Wikilivres frwikibooks https://fr.wikibooks.org/wiki/Accueil MediaWiki 1.47.0-wmf.22 first-letter Média Spécial Discussion Utilisateur Discussion utilisateur Wikilivres Discussion Wikilivres Fichier Discussion fichier MediaWiki Discussion MediaWiki Modèle Discussion modèle Aide Discussion aide Catégorie Discussion catégorie Transwiki Discussion Transwiki Wikijunior Discussion Wikijunior TimedText TimedText talk Module Discussion module Event Event talk Liste de mnémoniques 0 12821 773599 772810 2026-09-29T19:23:21Z ~2026-52347-17 124637 773599 wikitext text/x-wiki Cette page contient une '''liste de [[w:mnémotechnique|mnémotechniques]]''', c’est-à-dire différentes constructions qui facilitent la mémorisation. Par exemple : afin de retenir beaucoup plus facilement les sept péchés capitaux, une phrase mnémotechnique possible offrant une image plus visuelle regroupant une partie ou la totalité d'un péché : Par goût, Colette envie l'orgue luxueux d'Avarice (Paresse, gourmandise, colère, envie, orgueil, luxure, avarice) == Atmosphère == === Structure verticale === L’atmosphère terrestre présente une structure verticale en couches basée sur l’évolution de la température. On distingue la Troposphère (siège des phénomènes météorologiques), la Stratosphère, la Mésosphère et la Thermosphère (et l'exosphère). '''T'''out '''S'''ur '''M'''a '''T'''ête '''Trop''' de '''Str'''ess et de '''Més'''aventures '''Ter'''rifient à l''''Ex'''trême == Mathématiques == === Les 126 premières décimales du nombre π (pi) === Le nombre de lettres de chaque mot de ce poème correspond à une décimale de [[w:Pi|Pi]]. Un mot de dix lettres correspond au chiffre 0. {| |- align="center" | ''Que'' || || ''j'' || ''<nowiki>’</nowiki>'' || ''aime'' || ''à'' || ''faire'' || ''apprendre'' || ''un'' || ''nombre'' || ''utile'' || ''aux'' || ''sages'' || ''!'' |- align="center" ! 3 !! , !! 1 !! !! 4 !! 1 !! 5 !! 9 !! 2 !! 6 !! 5 !! 3 !! 5 |} {| |- align="center" | ''Immortel'' || ''Archimède'' || '','' || ''artiste'' || ''ingénieur'' || '','' |- align="center" ! 8 !! 9 !! !! 7 !! 9 |} {| |- align="center" | ''Qui'' || ''de'' || ''ton'' || ''jugement'' || ''peut'' || ''priser'' || ''la'' || ''valeur'' || ''?'' |- align="center" ! 3 !! 2 !! 3 !! 8 !! 4 !! 6 !! 2 !! 6 |} {| |- align="center" | ''Pour'' || ''moi'' || '','' || ''ton'' || ''problème'' || ''eut'' || ''de'' || ''pareils'' || ''avantages'' || ''...'' |- align="center" ! 4 !! 3 !! !!3!! 8 !! 3 !! 2 !! 7 !! 9 |} {| |- align="center" | ''Jadis'' || '','' || ''mystérieux'' || , || ''un'' || ''problème'' || ''bloquait'' |- align="center" ! 5 !! !! 0 !! !! 2 !! 8 !! 8 |} {| |- align="center" | ''Tout'' || ''l'' || ''<nowiki>’</nowiki>'' || ''admirable'' || ''procédé'' || '','' || ''l'' || ''<nowiki>’</nowiki>'' || ''œuvre'' || ''grandiose'' |- align="center" ! 4 !! 1 !! !! 9 !! 7 !! !! 1 !! !! 6 !! 9 |} {| |- align="center" | ''Que'' || ''Pythagore'' || ''découvrit'' || ''aux'' || ''anciens'' || ''Grecs'' ||''.'' |- align="center" ! 3 !! 9 !! 9 !! 3 !! 7 !! 5 |} {| |- align="center" | ''Ô'' || ''quadrature'' || ''!'' || ''Vieux'' || ''tourment'' || ''du'' || ''philosophe'' || ''...'' |- align="center" ! 1 !! 0 !! !! 5 !! 8 !! 2 !! 0 |} {| |- align="center" | ''Insoluble'' || ''rondeur'' || '','' || ''trop'' || ''longtemps'' || ''vous'' || ''avez'' |- align="center" ! 9 !! 7 !! !! 4 !! 9 !! 4 !! 4 |} {| |- align="center" | ''Défié'' || ''Pythagore'' || ''et'' || ''ses'' || ''imitateurs'' || ''.'' |- align="center" ! 5 !! 9 !! 2 !! 3 !! 0 |} {| |- align="center" | ''Comment'' || ''intégrer'' || ''l'' || ''<nowiki>’</nowiki>'' || ''espace'' || ''plan'' || ''circulaire'' || ''?'' |- align="center" ! 7 !! 8 !! 1 !! !! 6 !! 4 !! 0 |} {| |- align="center" | ''Former'' || ''un'' || ''triangle'' || ''auquel'' || ''il'' || ''équivaudra'' || ''?'' |- align="center" ! 6 !! 2 !! 8 !! 6 !! 2 !! 0 |} {| |- align="center" | ''Nouvelle'' || ''invention'' || '':'' || ''Archimède'' || ''inscrira'' |- align="center" ! 8 !! 9 !! !! 9 !! 8 |} {| |- align="center" | ''Dedans'' || ''un'' || ''hexagone'' || '';'' || ''appréciera'' || ''son'' || ''aire'' |- align="center" ! 6 !! 2 !! 8 !! !! 0 !! 3 !! 4 |} {| |- align="center" |''Fonction'' || ''du'' || ''rayon'' || ''.'' || ''Pas'' || ''trop'' || ''ne'' || ''s'' || ''<nowiki>’</nowiki>'' || ''y'' || ''tiendra'' |- align="center" ! 8 !! 2 !! 5 !! !! 3 !! 4 !!2 !! 1 !! !! 1 !! 7 |} {| |- align="center" |''Dédoublera'' || ''chaque'' || ''élément'' || ''antérieur'' |- align="center" ! 0 !! 6 !! 7 !! 9 |} {| |- align="center" |''Toujours'' || ''de'' || ''l'' || ''<nowiki>’</nowiki>'' || ''orbe'' || ''calculé'''e'''''¹ || ''approchera'' |- align="center" ! 8 !! 2 !! 1 !! !! 4 !! 8 !! 0 |} {| |- align="center" |''Définira'' || ''limite'' || '';'' || ''enfin'' || '','' || ''l'' || ''<nowiki>’</nowiki>'' || ''arc'' || '','' || ''le'' || ''limiteur'' |- align="center" ! 8 !! 6 !! !! 5 !! !! 1 !! !! 3 !! !! 2 !! 8 |} {| |- align="center" |''De'' || ''cet'' || ''inquiétant'' || ''cercle'' || '','' || ''ennemi'' || ''trop'' || ''rebelle'' |- align="center" ! 2 !! 3 !! 0 !! 6 !! !! 6 !! 4 !! 7 |} {| |- align="center" |''Professeur'', || ''enseignez'' || ''son'' || ''problème'' || ''avec'' || ''zèle'' || ''!'' |- align="center" ! 0 !! 9 !! 3 !! 8 !! 4 !! 4 |} ¹ Le mot orbe est du masculin mais ce ne fut pas toujours le cas, ceci induit à présent une faute d’accord à « ''calculée'' » que l’on peut remplacer par « ''escompté'' » pour conserver le bon nombre de lettres. === Premières décimales de l’inverse du nombre π : 1/π === La valeur de '''1/π = 0,3183098''' se retient sous la forme d’une phrase historique faisant référence aux trois glorieuses : {{Citation|« Les 3 journées de 1830 ont renversé 89 [la Révolution de 1789] »}}. Le score de la finale de la coupe du monde de football 98 a fait '''un surpris''' (1 sur pi), côté Brésil : '''0''', '''3''' (c’est le feu ! = '''18''' = '''''Cher''''' payé ?) ; '''3-0''' ('''''Gard'''''ez en souvenir) '''98''' === Trigonométrie === Le principe est de ne retenir que la première lettre ou la première syllabe des mots-clés de chaque définition ou théorème : ==== Définitions ==== * « Cosinus = côté Adjacent sur l'Hypoténuse » * « Sinus = côté Opposé sur l'Hypoténuse » * « Tangente = côté Opposé sur côté Adjacent » Une "phrase" permet de se rappeler ces trois définitions à la fois : '''cah soh toa''' pour « ''casse-toi'' » : '''C'''osinus = '''A'''djacent sur '''H'''ypoténuse ; '''S'''inus = '''O'''pposé sur '''H'''ypoténuse ; '''T'''angente = '''O'''pposé sur '''A'''djacent. Certains préfèrent '''soh cah toa'''. On peut aussi ressortir les dénominateurs de chaque fraction (afin de ne pas mélanger numérateurs et dénominateurs dans ces égalités) en apprenant les sons : '''SO-CA-TO, H-H-A''' (HHA étant les dénominateurs : '''S'''in ='''O'''pp /''H''yp , '''C'''os = '''A'''dj/''H''yp, '''T'''an='''O'''pp/''A''dj) <br /> D'autres méthodes consistent à associer un "mot" facile à retenir à chacune des trois définitions:<br /> - Cosadi - Sinopi - Tanopad <br /> - cosadjip - sinopip - tangopaj <br /> - CAHier - SOHo - TOAst (ou COCA) ==== Théorèmes ==== * « sin (a+b) = sin a cos b + cos a sin b » devient « ''sico cosi'' » * « cos (a+b) = cos a cos b - sin a sin b » devient « ''coco sisi'' » (ou « ''coco MOINS sisi'' ou « ''coco ISsi'' » pour retenir le signe) * À noter que la formule « ''sico cosi / coco moins sisi'' » ou « ''Coco si méchant, si, Coco, si'' » permet également d’apprendre les formules de factorisation suivantes : sin p + sin q = 2 sin [(p+q)/2] •cos [(p-q)/2] sin p - sin q = 2 cos [(p+q)/2] •sin [(p-q)/2] cos p + cos q = 2 cos [(p+q)/2] •cos [(p-q)/2] cos p - cos q = -2 sin [(p+q)/2] •sin [(p-q)/2] Avec p = A + B et q = A - B '''Cosinus est menteur et raciste''' ('''CO'''s comme '''CO'''n) en effet cos (a+b) donne (cos a cos b) - (sin a sin b). Cosinus est donc menteur puisque le signe de l’addition (positive) est négatif. Cosinus est raciste puisque on obtient (cos a cos b) d’une part et (sin a sin b) d’autre part : les cosinus et les sinus ne se mélangent pas. '''co'''sinus est un '''co'''pain '''co'''n (copain pour le sens et con pour le signe): cos(a'''+'''b)= cos(a)cos(b) '''-''' sin(a)sin(b) : les cosinus restent ensemble, mais le signe change. '''s'''inus est une '''s'''alade '''s'''ympa (salade pour le sens et sympa pour le signe): sin (a'''+'''b)=sin(a)cos(b) '''+''' sin(b)cos(a) : sin et cos se mélangent mais le signe reste le même On trouve également : '''opip adjip opadj''' : sinus ('''op'''posé sur '''hyp'''oténuse), cosinus ('''adj'''acent sur '''hyp'''oténuse), tangente ('''op'''posé sur '''adj'''acent). La phrase prononcée rapidement d’un seul coup est très facile à mémoriser. De même que '''SOH CAH TOA''': '''S'''inus= '''O'''pposé sur '''H'''ypoténuse '''C'''osinus= '''A'''djacent sur '''H'''ypoténuse '''T'''angente= '''O'''pposé sur '''A'''djacent On peut lui substituer la formule plus percutante : '''CAH SOH TOA''' (à prononcer Casse toi ! ) === Dates et constantes === Le [[w:code chiffres-sons|code chiffres-sons]] est une méthode qui permet de se souvenir de dates ou de valeurs numériques en formant des phrases. === Formules de géométrie === * Circonférence d’un cercle : 2 pi R (2 pierres) ** La circonférence est toute fière d’être égale à 2 pi R * Aire d’un disque: pi R<sup>2</sup> (« pierre carrée » ou « pierre deux ») ** Le cercle est tout joyeux d’être égal à pi R<sup>2</sup> (prononcer « pi R deux ») * « Le volume de la sphère, est quoi qu’on y puisse faire, 4/3 pi R<sup>3</sup>, fut-elle de bois. » ([[w:fr:Marcel Pagnol|Marcel Pagnol]]) Le volume d'une sphère, qu'elle soit de pierre, qu'elle soit de bois est égal aux 4/3 de pi R3 * Le volume d'une pizza (d'un camembert, ou de n'importe quel objet semblable) de rayon 'z' et de hauteur 'a' est égale à '''Pi.(z.z).a''' (la formule correspond à son nom) soit V = π.z<sup>2</sup>.a === Analyse vectorielle === [[File:DRG chart fr.svg|thumb|right|300px|Diagramme des principales relations entre opérateurs de calcul vectoriel.]] * Opérateurs s'annulant: '''DiR'''i'''G'''é (décrivant les flèches centrales sur le diagramme à droite) ** '''DiR'''i: <math>\mathrm{div}(\overrightarrow{\mathrm{rot}})=0</math> ** '''R'''i'''G''': <math>\overrightarrow{\mathrm{rot}}(\overrightarrow{\mathrm{grad}})=\vec{0}</math> * Autres formules (flèches reliant div et grad sur le diagramme à droite): ** <math>\Delta = \mathrm{div}(\overrightarrow{\mathrm{grad}})</math> ** <math>\overrightarrow{\mathrm{grad}}(\mathrm{div})= \overrightarrow{\mathrm{rot}}(\overrightarrow{\mathrm{rot}})+\vec{\Delta}</math> === Ordre des opérations === En algèbre, les opérations simples : <code>(</code>&nbsp;<code>)</code>, <code>+</code>, <code>-</code>, <code>&times;</code> et <code>&divide;</code>, sont évaluées selon un certain ordre : '''PEMDAS''' pour « '''p'''arenthèses, '''e'''xposant, '''m'''ultiplication, '''d'''ivision, '''a'''ddition et '''s'''oustraction ». Pour plus de détails sur l'application de ce mnémonique, voir [[:w:fr:Ordre des opérations|Ordre des opérations]]. === Double distributivité === Retenir le mot « '''PIED''' » qui donne les termes à regrouper lorsque l’on développe : '''P'''remiers, '''I'''ntérieurs, '''E'''xtérieurs, '''D'''erniers. === Constante e<ref name="villemin.gerard">http://villemin.gerard.free.fr/Wwwgvmm/MnemoTe/Phrase.htm</ref> === {| border="0" cellpadding="0" cellspacing="1" |align="center"|Tu | &nbsp; |align="center"|aideras | &nbsp; |align="center"|à | &nbsp; |align="center"|rappeler | &nbsp; |align="center"|ta | &nbsp; |align="center"|quantité | &nbsp; |align="center"|à | &nbsp; |align="center"|beaucoup | &nbsp; |align="center"|de | &nbsp; |align="center"|docteurs | &nbsp; |align="center"|amis. |- |align="center"|2 | ,&nbsp; |align="center"|7 | &nbsp; |align="center"|1 | &nbsp; |align="center"|8 | &nbsp; | align="center" |2 | &nbsp; |align="center"|8 | &nbsp; |align="center"|1 | &nbsp; |align="center"|8 | &nbsp; |align="center"|2 | &nbsp; |align="center"|8 | &nbsp; |align="center"|4 |} === Nombre d'or<ref name="villemin.gerard"/> === {| border="0" cellpadding="0" cellspacing="1" |align="center"|Ô | &nbsp; |align="center"|nombre | &nbsp; |align="center"|d' | &nbsp; |align="center"|élégance | &nbsp; |align="center"|! | &nbsp; |align="center"|Toi, | &nbsp; |align="center"|toi, | &nbsp; |align="center"|grandiose, | &nbsp; |align="center"|étonnant : | &nbsp; |align="center"|''le nombre d'or''. |- |align="center"|1 | ,&nbsp; |align="center"|6 | &nbsp; |align="center"|1 | &nbsp; |align="center"|8 | &nbsp; |align="center"|0 | &nbsp; |align="center"|3 | &nbsp; |align="center"|3 | &nbsp; |align="center"|9 | &nbsp; |align="center"|8 | &nbsp; |align="center"| &nbsp; |} (! pour 0) === Statistiques === * [[w:Règle 68-95-99.7|Règle 68-95-99.7]] : la proportion des échantillons entre [-σ, +σ], [-2σ, +2σ], [-3σ, +3σ] pour une distribution gaussienne centrée. * Erreurs de première espèce et deuxième espèce. ** Se rappeler la fable d’Ésope dans laquelle un enfant [[wikt:crier au loup|crie au loup]] (hypothèse nulle <math>H_0</math>: « il n'y a aucun loup »). **# D'abord, les villageois pensent qu'il y a un loup alors qu'il n'y en a aucun (erreur de première espèce). **# Puis, les villageois pensent qu'il n'y a aucun loup alors qu'il y en a un (erreur de seconde espèce). ** Il y a une barre dans '''P'''ositif (faux positif : erreur de type '''I''') et deux barres dans '''N'''égatif (faux négatif : erreur de type '''II'''). == Sciences == === Astronomie === ==== Ordre des planètes du Système solaire ==== Il existe toute une série de termes mnémotechniques pour se souvenir de l'ordre des planètes à l’intérieur du [[w:système solaire|Système solaire]]. La première lettre de chaque mot de cette phrase correspond à la première lettre de chaque [[w:planète|planète]], de la plus rapprochée à la plus éloignée du Soleil. L'[[w:apostrophe|apostrophe]] ou la [[w:virgule|virgule]] peut représenter la [[w:ceinture d'astéroïdes|ceinture d'astéroïdes]] entre [[w:Mars (planète)|Mars]] et [[w:Jupiter|Jupiter]]. Voici l’ordre des planètes du Système solaire : Mercure, Vénus, Terre, Mars, Jupiter, Saturne, Uranus, Neptune. ''À NOTER que selon la [[w:Définition des planètes de l'UAI|nouvelle définition]] de l’[[w:Union astronomique internationale|Union astronomique internationale]] d’août [[w:2006|2006]], [[w:Pluton (planète naine)|Pluton]] n’est plus considérée comme une [[w:planète|planète]] mais comme une planète naine ([[w:(134340) Pluton|(134340) Pluton]])'' (de même que [[w:(1) Cérès|(1) Cérès]], [[w:(136199) Éris|(136199) Éris]], [[w:(136108) Haumea|(136108) Haumea]] et [[w:(136472) Makemake|(136472) Makemake]]), <br/> '''''Ordre des planètes du Système solaire : '''Mercure, Vénus, Terre, Mars, Jupiter, Saturne, Uranus, Neptune.'' On emploie par exemple les phrases suivantes : *'''''M'''ême '''V'''ieux '''T'''ruc '''M'''ais '''J''''en '''S'''ais '''U'''n '''N'''ouveau.'' *'''''M'''a '''V'''ieille '''T'''ante '''M'''arie a '''J'''eté '''S'''amedi '''U'''n '''N'''avet.'' *'''''M'''a '''V'''ieille '''T'''rompette '''M'''e '''J'''oue '''S'''on '''U'''ltime '''N'''octurne.'' *'''''M'''a '''V'''oiture '''T'''e '''M'''ène '''J'''oyeusement '''S'''ur '''U'''ne '''N'''ationale.'' *'''''M'''arie, '''V'''iendras-'''T'''u '''M'''anger '''J'''eudi '''S'''ur '''U'''ne '''N'''appe ?'' *'''''M'''angez '''V'''os '''T'''artes, '''M'''ais '''J'''uste '''S'''ur '''U'''ne '''N'''appe .'' *'''''M'''e '''V'''oici '''T'''oute '''M'''ignonne''',''' '''J'''e '''S'''uis '''U'''ne '''N'''ébuleuse.'' *'''''M'''e '''V'''oici '''T'''oute '''M'''odifiée''',''' '''J'''e '''S'''uis '''U'''ne '''N'''ouveauté.'' *'''''M'''e '''V'''oilà '''T'''out '''M'''ouillé''',''' '''J''''ai '''S'''uivi '''U'''n '''N'''uage.'' *'''''M'''e '''V'''oilà '''T'''oute '''M'''ouillée''',''' '''J'''e '''S'''uis '''U'''ne '''N'''ymphomane.'' *'''''M'''on '''V'''ieux, '''T'''u '''M''''as '''J'''eté '''S'''ur '''U'''ne '''N'''avette.'' *'''''M'''on '''V'''ioloncelle '''T'''ombe, '''M'''ais '''J'''e '''S'''auve '''U'''ne '''N'''ote. *'''''M'''aman '''V'''ole '''T'''ous '''M'''es '''J'''ouets, '''S'''auf '''U'''n '''N'''ounours !'' *'''''M'''e '''V'''oici, '''T'''onton '''M'''arcel, '''J'''e '''S'''uis '''U'''n '''N'''ageur.'' *'''''M'''a '''V'''ille '''T'''hionville '''M'''ontre '''J'''oyeusement '''S'''on '''U'''nivers '''N'''octurne.'' *'''''M'''on '''V'''élo '''T'''e '''M'''ènera ''' J'''usque '''S'''ur '''U'''n '''N'''uage.'' *'''''M'''on '''V'''élo '''T'''ourne '''M'''al, ''' J''''en '''S'''ouhaite '''U'''n '''N'''ouveau.'' *'''''M'''onsieur, '''V'''ous '''T'''ravaillez '''M'''al ; - ''' J'''e '''S'''uis '''U'''n '''N'''ovice.'' *'''''M'''al '''V'''êtu '''T'''oi '''M'''ême, '''J'''e '''S'''uis '''U'''n '''N'''udiste'' *'''''M'''on '''V'''ieux '''T'''outou '''M'''édor '''J'''oue '''S'''ur '''U'''n '''N'''uage'' *'''''M'''a '''V'''erge '''T'''e '''M'''ènera '''J'''usque '''S'''ur '''U'''n '''N'''uage'' *'''''M'''ais '''V'''ous '''T'''ombez '''M'''al, '''J''''ai '''S'''auté '''U'''ne '''N'''aine'' * '''''M'''essieurs!''' V'''otre '''T'''rahison '''M'''<nowiki/><nowiki>'écœure: </nowiki>'''J'''ouer''' S'''ur '''U'''ne '''N'''omenclature!'' (au sujet de la disparition de Pluton de la liste) *'''''S'''ors (pour Soleil) -'''M'''oi '''V'''ite '''T'''a '''M'''armite '''J'''aune '''S'''ur '''U'''ne '''N'''appe.'' *'''''M'''arquez '''V'''otre '''T'''emps '''M'''esuré '''J'''uste '''S'''ous '''U'''ne '''N'''anoseconde.'' '''Et pour les nostalgiques de Pluton...''' * '''''M'''anon '''V'''iendras '''T'''u '''M'''anger '''J'''eudi '''S'''ur '''U'''ne '''N'''appe '''P'''ropre.'' *'''''M'''ercure '''V'''eut '''T'''aquiner '''M'''ars, '''J'''e '''S'''uis '''U'''ne '''N'''ouvelle '''P'''lanète.'' *'''''M'''ademoiselle, '''V'''ous '''T'''ravaillez '''M'''al, '''J'''e '''S'''uis '''U'''n '''N'''ouveau '''P'''rofesseur'' *''Le '''M'''onde '''V'''oit '''T'''ourner du '''M'''atin '''J'''usqu'au '''S'''oir '''U'''niquement '''N'''euf '''P'''lanètes''. *'''''M'''on '''V'''ieux, '''T'''u '''M'''e '''J'''ettes '''S'''ur '''U'''ne '''N'''ouvelle '''P'''lanète.'' *'''''M'''onsieur '''V'''euillez '''T'''ournez '''M'''a '''J'''upe '''S'''ans '''U'''ne '''N'''aïve '''P'''udeur.'' *'''''M'''e '''V'''oici, '''T'''oute '''M'''ignonne, '''J'''e '''S'''uis '''U'''ne '''N'''ouvelle '''P'''lanète. *'''''M'''e '''V'''oici, '''T'''onton '''M'''arcel, '''J'''e '''S'''uis '''U'''n '''N'''ageur '''P'''rofessionnel. *'''''M'''e '''V'''oici, '''T'''out '''M'''ouillé, '''J'''e '''S'''uis '''U'''n '''N'''ageur '''P'''ressé. *'''''M'''e '''V'''oici, '''T'''out '''M'''ouillé, '''J''''ai '''S'''uivi '''U'''n '''N'''uage '''P'''luvieux. *'''''M'''ais '''V'''iendras-'''T'''u '''M'''anger, '''J'''ulie, '''S'''ur '''U'''ne '''N'''appe '''P'''ropre. *'''''M'''on '''V'''ieux '''T'''héâtre '''M'''e '''J'''oue '''S'''ouvent '''U'''ne '''N'''ouvelle '''P'''ièce. *'''''M'''on '''V'''ieux, '''T'''u '''M''''as '''J'''eté '''S'''ur '''U'''ne '''N'''ouvelle '''P'''lanète. *'''''S'''ors (pour Soleil) -'''M'''oi '''V'''ite '''T'''a '''M'''armite '''J'''aune '''S'''ur '''U'''ne '''N'''appe '''P'''ropre.'' *'''''M'''onsieur '''V'''ous '''T'''irez '''M'''al '''J'''e '''S'''uis '''U'''n '''N'''ovice '''P'''itoyable. * '''''Mé'''lanie, '''V'''ous '''T'''ombez '''Ma'''l, '''J'''e '''S'''uis '''U'''n '''N'''avet '''P'''ourri.'' *'''''M'''on '''V'''aisseau '''T'''e '''M'''ènera '''J'''eudi '''S'''ur '''U'''ne '''N'''ouvelle '''P'''lanète. *'''''M'''a '''V'''ieille '''T'''ante '''M'''arge '''J'''oue '''S'''ur '''U'''n '''N'''ouveau '''P'''iano. *'''''M'''aman '''V'''ole '''T'''ous '''M'''es '''J'''ouets, '''S'''auf '''U'''n '''N'''ounours '''P'''ourri !'' *'''''M'''arin '''V'''aleureux, '''T'''u '''M'''ourras '''J'''eune '''S'''ur '''U'''n '''N'''avire '''P'''erdu !'' *'''''M'''on '''V'''élo '''T'''ourne '''M'''al '''J'''e '''S'''uis '''U'''n '''N'''ouveau '''P'''iéton. *'''''M'''erci '''V'''ous '''T'''ous '''M'''aintenant '''J'''e '''S'''ais '''U'''nir '''N'''euf '''P'''lanètes. *'''''M'''élanie '''V'''ous '''T'''ombez '''M'''al '''J'''e '''S'''uis '''U'''n '''N'''avet '''P'''ourri. *'''''M'''es '''V'''ieilles '''T'''antes '''M'''angeaient '''J'''adis '''S'''ur '''U'''ne '''N'''appe '''P'''ercée.'' *'''''M'''ets '''V'''ite '''T'''on '''M'''aillot '''J'''e '''S'''uis '''U'''n '''N'''udiste '''P'''oilu. * '''''M'''on '''V'''ieux '''T'''acot '''M'''´a '''J'''eté '''S'''ur '''U'''n '''N'''oble '''P'''''assant. *'''''M'''ange '''V'''ite '''T'''on '''M'''ars '''J''' 'en '''S'''ors '''U'''n '''N'''ouveau '''P'''aquet. *'''''MÈR'''E, '''V'''iens '''Ter'''miner '''M'''a '''JUP'''e, '''SA''' cout'''UR'''e '''NE''' tient '''PLU'''s.'' * '''''M'''aman, '''V'''oudrais-'''T'''u '''M''''emmener '''J'''ouer '''S'''ur '''U'''ne '''N'''ouvelle '''P'''lanète ?'' Suite à un concours qui s’est déroulé au Québec, la formule suivante a été retenue : *'''''M'''angez '''V'''os '''T'''artes, '''M'''ais '''J'''uste '''S'''ur '''U'''ne '''N'''appe !'' Il existe aussi cette formule (la plus ancienne mnémonique connue en astronomie) qui se retient facilement, grâce à ses trois mots de trois syllabes : *''Merveter, Marjusa, Uneplu'' ('''Mer'''cure, '''Vé'''nus, '''Ter'''re, '''Mar'''s, '''Ju'''piter, '''Sa'''turne, '''U'''ranus, '''Nep'''tune, '''Plu'''ton) Une variante<ref>Formule tirée de l’un des tomes du [https://fr.m.wikipedia.org/wiki/Manuel_des_Castors_Juniors ''Manuel des Castors Juniors'']</ref> de celle-ci : * ''Mervé'', ''Termaju'', ''Saturneplu'' ('''Mer'''cure, '''Vé'''nus, '''Ter'''re, '''Ma'''rs, '''Ju'''piter, '''Sat'''urne, '''Ur'''anus, '''Ne'''ptune, '''Plu'''ton) Qui existe aussi sous cette forme : * ''Mervé, Termaju, Satur n'est plus'' Et celle-ci qui inclut le Soleil : *'''''S'''alut ! '''Me''' '''v'''ois-'''t'''u ? '''M'''oi '''j'''e '''s'''uis '''u'''ne '''n'''ouvelle '''pl'''anète !'' '''Planète ayant un système d'anneaux''' * '''J'''e '''S'''uis '''U'''ne '''N'''ouille (Jupiter, Saturne, Uranus, Neptune) ==== Ordre des quatre lunes principales de Jupiter ==== '''I'''l '''e'''st '''g'''rand, '''C'''harles ! * [[w:Io|Io]], [[w:Europe|Europe]], [[w:Ganymède_(lune)|Ganymède]], [[w:Callisto_(lune)|Callisto]] ==== Croissant de Lune ==== Le '''p'''remier croissant et le '''d'''ernier croissant peuvent être reconnus en les assimilant aux sens du p et du d. En effet, en « ajoutant » au croissant de lune un bâton, on obtient un p ou un d selon le croissant. Cette méthode marche uniquement dans l'[[w:Hémisphère (géographie)|hémisphère]] [[w:nord|nord]], dans l’hémisphère sud il faudra considérer que la Lune ment. Une méthode plus simpliste consistait autrefois à lire le croissant de lune directement. Quand il formait un '''C''' la lune incitait à penser qu'elle était '''C'''roissante . Or dans ce cas là elle est décroissante. Et quand elle formait un '''D''' (en supposant l’ajout de la barre droite nécessaire) elle incitait à penser qu’elle était '''D'''écroissante. Or dans ce cas là elle est croissante. Il en est venu l’expression populaire : ''Il est menteur comme la lune''. Cependant, dans ce cas la Lune ne ment que dans l'hémisphère Nord : C correspond bien à la Lune croissante et D à la Lune décroissante. Ces méthodes ne sont pas valables entre les tropiques, où le sens de ''lecture'' varie selon les saisons. ==== [[w:type spectral|Types spectraux]] [[w:étoile|stellaires]] ==== Les différents [[w:type spectral|types spectraux]], du plus chaud au plus froid, sont : O, B, A, F, G, K, M. '''''O'''h, '''b'''e '''a''' '''f'''ine '''g'''irl/'''g'''uy, '''k'''iss '''m'''e !'' '''''O'''verseas '''b'''roadcast: '''a''' '''f'''lash! [[w:Godzilla|'''G'''odzilla]] '''k'''ills [[w:Mothra|'''M'''othra]] !'' === Physique === ==== Électromagnétique ==== Énergie électrique stockée dans un condensateur&nbsp;: <math>E= (1/2) C U^2</math> "l'''e''' '''demi''' '''cu'''l '''carré'''" ==== Les sept unités fondamentales==== Pour: ''seconde, ampère, candela, kilogramme, mètre, kelvin, mole&nbsp;'': <br> Sac km km <br> Je <u>'''s'''ais q</u>u<u>'''a'''n</u>d <u>'''c'''a</u>c<u>'''k'''i</u> <u>'''m'''et</u> <u>'''k'''el</u> <u>'''m'''o</u>t ! : (je) ''Sec-Am-Ca-Ki-Mè-Kel-Mo'' <br> <u>Ce con</u> d'<U>Ampère</U>, <u>qu'en d</u>it <u>qui l'au</u>ra!, <u>mettr</u>a <u>quel vin</u> au <u>môl</u>e ?: ''Sec<s>onde</s>'' d' ''ampère'', ''cand<s>ela</s>'' ''kilo<s>gramme</s>''ra, ''mètr<s>e</s>''a ''kelvin'' au ''moles'' "Secondes molles, quand des lacs-îlots [[wikt:grammer|grammant]] [[wikt:pairer|pairent]], Maître Kelvin !" (qui se prononce comme : "seconde, mole, candela, kilogramme, ampère, mètre, kelvin") * ==== Ordre des couleurs de [[w:Résistance (composant)#Repérage et valeurs normalisées|résistance électrique]] ==== ('''N'''oir, '''M'''arron, '''R'''ouge, '''O'''range, '''J'''aune, '''V'''ert, '''B'''leu, '''Vio'''let, '''G'''ris, '''B'''lanc) '''''N'''e '''M'''ange '''R'''ien '''O'''u '''J'''e '''V'''ais '''B'''leuir '''V'''iolemment (ton) '''G'''ros '''B'''laze.'' '''''N'''e '''M'''angez '''R'''ien '''O'''u '''J'''e '''V'''ous '''B'''rule '''V'''otre '''G'''rosse '''B'''arbe.'' '''''N'''e '''M'''angez '''R'''ien '''O'''u '''J'''eûnez, '''V'''oilà '''B'''ien '''V'''otre '''G'''rande '''B'''êtise.'' '''''N'''e '''M'''angez '''R'''ien '''O'''u '''J'''e '''V'''ous '''B'''rise '''V'''otre '''G'''rosse '''B'''outeille.'' '''N'''e '''M'''angez '''R'''ien '''O'''u '''J'''e '''V'''ous '''B'''ats '''V'''iolemment '''G'''ros '''B'''êta '''''N'''adine '''M'''e '''R'''épondit''' O'''ui, '''J'''e '''V'''eux '''B'''ien '''V'''otre '''G'''rosse '''B'''iroute'' '''''N'''oir, '''M'''arron, les couleurs de l'arc en ciel (sauf l'indigo), '''G'''ris, '''B'''lanc.'' Version québécoise utilisant la lettre '''B''' pour Brun au lieu de Marron : '''''N'''otre '''B'''ar '''R'''estera '''O'''uvert '''J'''eudi et '''V'''endredi. '''B'''ière et '''V'''in '''G'''ratuit, '''B'''ienvenue.'' '''''N'''otre '''B'''ar '''R'''estera '''O'''uvert '''J'''eudi et '''V'''endredi. '''B'''ien'''V'''enue '''G'''ros '''B'''uveur.'' ==== Ordre des couleurs du [[w:Couleur#Le spectre lumineux|spectre visible]] ==== Les sept couleurs du spectre visible ou de l'arc-en-ciel (dans l'ordre des fréquences croissantes : '''R'''ouge - '''O'''range - '''J'''aune - '''V'''ert - '''B'''leu - '''I'''ndigo - '''V'''iolet) peuvent se retenir grâce à la phrase suivante : La '''ROU'''sse '''OR'''ienta le '''J'''uge '''VER'''s le '''BL'''azer de l''''INDI'''enne '''VIOL'''ée. Dans l'ordre inverse (soit de la plus petite à la la plus grande longueur d'onde) elles peuvent se retenir grâce au mot '''VIBUJOR''', en remplaçant le '''U''' par un '''V''' ('''vert''' comme '''Hu'''lk). '''V'''iolet - '''I'''ndigo - '''B'''leu - '''V'''ert - '''J'''aune - '''O'''range - '''R'''ouge Remarque : en se figurant le drapeau français '''bleu'''-'''blanc'''-'''rouge''', on peut retrouver l’ordre des longueurs d’onde, en assimilant le bleu à l’ultraviolet, le blanc au visible, et le rouge à l’infra-rouge : '''ultraviolet'''-'''visible'''-'''infra-rouge'''. ==== Longueur d'onde des couleurs ==== Le mot rouge est plus long que le mot bleu (5 vs 4), sa longueur d'onde est plus longue également. ==== Couleurs en peinture et rayonnements lumineux ==== Les peintres utilisent les trois couleurs fondamentales '''Cyan Magenta et Jaune''', chacune absorbant une seule des trois couleurs fondamentales de la lumière (Rouge Vert et Bleu). Notre œil ne reconnaît la couleur que par la lumière identifiée par chacune des 3 familles de cônes de l'œil respectivement sensibles aux rayonnements '''Rouge Vert et Bleu'''. Cette phrase permet aux peintres et aux physiciens d'identifier un équivalent des deux couleurs de rayonnement lumineux identifiées par les cônes de l'œil pour chacune des couleurs fondamentales de la peinture. '''C'''ette '''B'''onne '''V'''ieille<br /> '''M'''ijote des '''R'''aviolis "'''B'''uitoni"<br /> '''<nowiki>J'</nowiki>'''en '''R'''é'''V'''ais La couleur '''C'''yan de la peinture correspond ainsi à la réception des rayonnements lumineux '''B'''leu et '''V'''ert. Le '''M'''agenta, pour sa part correspond aux rayonnements lumineux '''R'''ouge et '''B'''leu. Quant à la couleur '''J'''aune, elle renvoie vers l'œil les rayonnements lumineux '''R'''ouge et '''V'''ert. ==== Constantes ==== * vitesse de la lumière<ref name="villemin.gerard" /> : :{| style="text-align: center;" |Ah,||messagère||admirable,||lumière||éclatante,||je||sais||votre||célérité|| |- |La||constante||lumineuse||restera||désormais||là||dans||votre||cervelle|| |- |2||9||9||7||9||2||4||5||8||m/s |} * définition formelle d'une seconde (périodes de la radiation correspondant à une transition entre les deux sous-niveaux hyperfins du césium 133) : :{| style="text-align: center;" |« Pharaonne,||j'||affirmais||là,||honore||mal||l'||aimable||seconde||0 ! » |- |9||1||9||2||6||3||1||7||7||0 |} === Chimie === '''Priorité des groupes caractéristiques en nomenclature''' Pour nommer une molécule composée de plusieurs groupes caractéristiques, on utilise l'ordre suivant : Acide carboxylique - anhydride d'acide - ester - halogénure d'acyle - amide - nitrile - aldéhyde - cétone - alcool - amine - alcyne - alcène - éther-oxyde - dérivé halogéné - alcane Pour se rappeler de l'ordre : '''Ac'''e '''an'''nule '''Ester''' ! '''Halo ami'''? '''Ni'''e '''al'''ors '''Cé'''cile '''alcool'''isée, '''Am'''élie '''ascene''' à N'''eoxi''' et '''De'''lp'''h'''ine un '''alcane''' ==== Radicaux alkyles ==== Pour se rappeler l’ordre des 3 premiers groupement alcanes : * Il ai'''mait''' '''êt'''re '''pro'''pre. (Oralement, "Il ai'''Mét Éth Prop''' ") Pour se rappeler l’ordre des 4 premiers groupement alcanes : * ('''M'''éthane, '''É'''thane, '''P'''ropane, '''B'''utane) * '''M'''aman '''Et''' '''P'''apa '''B'''ébé * '''M'''aman '''Et''' '''P'''apa '''But'''inent. * '''M'''alin qui '''É'''tudie '''P'''our le '''B'''ac. * '''M'''ieux '''É'''tudier '''P'''our le '''B'''ac. * '''M'''on '''É'''cole '''P'''eut '''B'''rûler. * '''M'''on '''É'''lève '''P'''isse '''B'''ien * '''M'''organe '''E'''st '''P'''as '''B'''elle. * '''Me'''s '''é'''lèves '''p'''arlent '''b'''eaucoup. * '''M'''ets '''t'''es '''Prop'''res '''But'''s ! (Oralement, "Mét Éth Prop But") Pour se rappeler l’ordre des 5 premiers groupement alcanes : * ('''M'''éthane, '''É'''thane, '''P'''ropane, '''B'''utane, '''P'''entane) * '''M'''aman '''E'''st '''P'''artie '''B'''ébé '''P'''leure * '''M'''amie '''E'''st '''P'''artie '''B'''oire une '''P'''inte Pour se rappeler l’ordre des 6 premiers groupement alcanes : * ('''M'''éthane, '''É'''thane, '''P'''ropane, '''B'''utane, '''P'''entane, '''H'''exane) * '''M'''aurice '''E'''st '''P'''as '''B'''eau '''P'''our '''H'''élène. * '''M'''amie '''E'''t '''P'''api '''B'''atifolent '''P'''endant l''''H'''iver. * '''M'''aman '''E'''t '''P'''apa '''B'''oivent '''P'''endant '''H'''alloween * '''M'''amie '''E'''st '''P'''artie '''B'''oire une '''P'''inte de '''H'''eineken * '''M'''et '''E'''th '''P'''rop '''B'''ut '''P'''ent '''H'''ex Pour les plus vulgaires : * '''M'''audite '''É'''paisse ! '''P'''ourquoi '''B'''aiser '''P'''our l' '''H'''iver ! ==== [[w:Tableau périodique des éléments|Tableau périodique des éléments]] ==== Il est à noter que la plupart des moyens mnémotechniques concernant les éléments ont été créés par des [[w:étudiant|étudiant]]s, d’où le [[w:vocabulaire|vocabulaire]] parfois amusant des maximes. ===== [[w:Éléments de la période 2|Période 2]] ===== '''Pour : Li'''thium, '''Bé'''ryllium, '''B'''ore, '''C'''arbone, '''N'''itrogène (Azote), '''O'''xygène, '''F'''luor, '''Né'''on.'' * «La '''Li''''''Bé'''llule '''B'''leue, d’une '''C'''aresse, '''N'''oit dans l’'''O'''nde la '''F'''leur de '''Né'''nuphare. » * « '''Li'''thus et '''Be'''rénice '''B'''oivent, '''C'''haque '''N'''uit, '''O''' '''F'''rais de '''Né'''ron » * « '''Li'''verpool, '''Be'''rceau des '''B'''eatles, '''C'''onnait '''N'''aturellement ces '''O'''librius '''F'''ous et '''Né'''vrosés » * « '''Li'''bérez '''Be'''n '''B'''arkans, '''C'''élèbre '''N'''arrateur, '''O'''u '''F'''usillez '''Né'''ron » * « '''Li''' '''Be''' le '''B'''on '''C'''anard du '''N'''ord '''O'''uest de la '''F'''rance '''Ne'''ogauchiste » * « '''Li'''li '''Be'''sa '''B'''ien '''C'''ouchée '''N'''ue '''O''' '''F'''lanc de '''Né'''ron » * « '''Li'''li '''Be'''se '''B'''ien '''C'''hez '''N'''otre '''O'''ncle '''F'''umeur de '''Ne'''squik » * « '''Li'''li '''Be'''se '''B'''ien '''C'''onfortablement '''N'''otre '''O'''ncle '''F'''rançois '''Ne'''stor » * « '''Li'''mace '''Be'''te '''B'''ouffa '''C'''inq '''N'''ouveaux '''O'''ignons '''F'''raîchement '''Né'''s » * « '''Li'''li '''Be'''rça '''B'''ébé '''C'''hez '''N'''otre '''O'''ncle '''F'''ernand '''N'''estor * « '''Li'''li '''B'''ecta '''B'''ien '''C'''hez '''N'''otre '''O'''ncle '''F'''erdinand '''N'''estor » * « '''Li'''li '''Bé'''cha '''B'''ien '''C'''hez '''N'''otre '''O'''ncle '''F'''rançois-(ou '''F'''erdinand-)'''Ne'''stor »<br /> * « '''Li'''li '''Bé'''se '''B'''ien '''C'''hez '''N'''otre '''O'''ncle '''F'''rançois-(ou '''F'''erdinand-)'''Ne'''stor »<br /> * « '''LiBe'''rté '''B'''afouée '''C'''ontre '''N'''otre '''O'''rganisation '''F'''édérale '''Né'''ogaulliste (ou '''Né'''otrotskiste) » * « le '''Li''' t de '''BE''' '''B''' é a '''C'''assé le '''N'''ez de l' '''O'''ncle '''F'''urieux '''Né'''on » * « '''Li'''vrez '''Bê'''tement '''B'''ataille '''C'''ar '''N'''ous, '''O'''fficiers '''F'''rançais, '''Né'''gocions » * « '''L'i'''magination '''Be'''lliqueuse '''B'''aissa '''C'''ar '''N'''otre '''O'''rdre '''F'''ut '''Ne'''t » * « '''Li'''re '''Be'''aucoup '''B'''alzac '''C'''ar '''N'''otre '''O'''rthographe '''F'''ait '''Né'''gligé » * « '''Li'''ste de '''Be'''lles '''B'''outeilles de '''C'''ognac '''N'''ous '''O'''nt '''F'''outus '''Ne'''rveux » * « '''Li'''li '''Be'''cote '''B'''ien '''C'''omme '''Ni'''cole '''O''' '''F'''ond '''N'e'''st ce pas » * « '''Li'''bérez '''Be'''rnard '''B'''ossu '''C'''ontre '''N'''ouvel '''O'''tage '''F'''éminin. Signé '''Ne'''on » * « '''LiBe'''rté de '''B'''oire '''C'''ar '''N'''ous '''O'''n '''F'''oire '''N'''os '''e'''xams » * « '''Li'''bérez '''Be'''n '''B'''arka '''C'''ar '''N'''ous, '''O'''fficiers '''F'''rançais, '''Né'''gocions » * « '''Li'''li et '''Be'''rnard '''B'''aisent '''C'''omme '''N'''ous '''O'''n '''F'''ait '''Ne'''spa » ===== [[w:Éléments de la période 3|Période 3]] ===== ''Pour : '''S'''odium, '''M'''a'''g'''nésium, '''Al'''uminium, '''Si'''licium, '''P'''hosphore, '''S'''oufre, '''C'''h'''l'''ore, '''Ar'''gon.'' * « '''S'''uzanne '''M'''an'''g'''ea '''Al'''lègrement '''Si'''x '''P'''russiens '''S'''ans '''Cl'''aquer '''A'''p'''r'''ès. » * « '''S'''uzanne '''M'''an'''g'''ea '''Al'''lègrement '''Si'''x '''P'''oulets '''S'''ans '''Cl'''aquer des '''Ar'''ticulations. » * « '''S'''uzanne '''M'''an'''g'''ea '''Al'''lègrement '''Si'''x '''P'''oulets (ou '''P'''erdrix) '''S'''ans '''Cl'''aquer d' '''Ar'''gent. » Le sodium est représenté par '''Na'''. Alors Napoléon remplace Suzanne pour retrouver le symbole : * « '''Na'''poléon '''M'''an'''g'''ea '''Al'''lègrement '''Si'''x '''P'''oulets '''S'''ans '''Cl'''aquer d''''Ar'''gent » — ou « sans claquer '''A'''p'''r'''ès », « d''''Ar'''gon », « d''''Ar'''tère », « (d')'''Ar'''tiche » ou « sans claquer les '''Ar'''ticulations » pour éviter la confusion avec l'élément argent, noté '''Ag'''. * « '''Na'''poléon '''M'''an'''g'''ea '''Al'''lègrement '''Si'''x '''P'''russiens '''S'''ans '''Cl'''ore l’'''Ar'''mistice. » * « '''Na'''guère '''M'''onsei'''g'''neur '''Al'''louche '''Si''' '''P'''ervers '''S'''uça '''Cl'''aire '''Ar'''demment. » * « '''Na'''poléon '''M'''an'''g'''eait '''Al'''lègrement '''Si'''x '''P'''oulets '''S'''ans '''Cl'''amser '''A'''p'''r'''ès. » * « '''Na'''poléon '''M'''a'''g'''nera '''À''' '''l'''<nowiki/>'est '''Si''' '''P'''ossible '''S'''a '''C'''o'''l'''onne '''A'''rmée. » *« '''Na'''billa '''M'''an'''g'''e (h)'''Al'''lal '''Si''' '''P'''atrick '''S'''ébastien '''Cl'''ash '''Ar'''thur. » ===== [[w:Éléments de la période 4|Période 4]] ===== ''Pour : '''K'''allium (Potassium), '''Ca'''lcium, '''Sc'''andium, '''Ti'''tane, '''V'''anadium, '''C'''h'''r'''ome, '''M'''a'''n'''ganèse, '''Fe'''r, '''Co'''balt, '''Ni'''ckel, '''Cu'''ivre, '''Z'''i'''n'''c, '''Ga'''llium, '''Ge'''rmanium, '''A'''r'''s'''enic, '''Sé'''lénium, '''Br'''ome, '''Kr'''ypton.'' * « '''K'''arl '''Ca'''pitaine '''Sc'''andinave '''Ti'''ra sa '''V'''erge '''Cr'''asseuse et '''M'''i'''n'''uscule, '''Fé'''conda le '''Co'''n de '''Ni'''cole, et le '''Cu'''l de ses '''Z'''e'''n'''nemies, '''Ga'''rdant '''Ge'''néreusement '''As'''sez de '''Se'''mence pour ce '''Br'''ave '''K'''h'''r'''ouchtchev. » * « '''K'''évin '''Ca'''pture un '''Sc'''arabée '''Ti'''mide dans le '''V'''agin '''Cr'''éatif de '''M'''o'''n'''ique, '''Fé''' (fait) '''Co'''mme '''Ni'''cole dans le '''Cu'''l en '''Zinc''' de '''Ga'''spard de '''Ge'''rmanie, puis '''As'''pire '''Sé'''bastien dans la '''Br'''aguette du '''Kr'''aken » * « '''K'''hrouchtchev '''Ca'''ressa '''Sc'''iemment '''Ti'''to. '''V'''orochev '''Cr'''ia '''M'''ag'''n'''anime : "'''Fé''' pas le '''Co'''n '''Ni'''kita, ton '''Cu'''l en '''Z'''i'''n'''c '''Ga'''lvanisé te '''Gè'''ne '''AsSe'''z pour '''Br'''anler des '''Kr'''evettes. » * « '''K'''épler '''Ca'''lculait des '''Sc'''alaires '''Ti'''tanesques, '''V'''oyant '''Cr'''o-'''M'''ag'''n'''on '''Fé'''sant le '''Co'''n '''Ni'''ché sur le '''Cu'''l d'un '''Z'''ébulo'''n''', '''Ga'''gnant '''Gé'''néralement '''AsSe'''z de '''B'''iè'''r'''es '''Kr'''onenbourg. » * « '''K''' '''Ca''' (cacas) '''Sc'''iés de '''Ti'''ti '''V'''olant et '''Cr'''os '''M'''i'''n'''et qui '''F'''ont ('''Fe''') des '''Co'''nneries ont '''Ni'''qué le '''Cu'''l à '''Z'''a'''n'''zibar d'un '''Ga'''rs '''Gé'''nial '''As'''sis '''Se'''rrant une '''B'''onne ('''Br''') '''Kr'''o. » * « '''K'''hrouchtchev '''Ca'''ressa '''Sc'''andaleusement '''Ti'''tov. '''Van'''ia '''Cr'''ia '''M'''ag'''n'''animement "'''F'''ais pas le '''Co'''n Nikita, la Cuisine en '''Z'''i'''n'''c de la '''Ga'''re de '''Ge'''nève '''As''' Ses '''Br'''iques '''Cr'''euses » (ou '''K'''hrouchtchev '''Ca'''ssa le '''SC'''ooter à '''TI'''tov) * « '''K'''hrouchtchev '''Ca'''ressa '''Sc'''andaleusement la '''Ti'''gnasse de '''V'''anadia, '''Cr'''oyant '''M'''a'''n'''ifestement '''Fe'''re '''Co'''cu '''Ni'''colaiev, le '''Cu'''ré de '''Z'''a'''n'''zibar '''Ga'''gna '''Ge'''nève '''As'''sez '''Se'''crètement avec Son '''Br'''éviaire '''Kr'''ipté. » * « '''K'''arl '''Ca'''valier '''Sc'''andinave '''Ti'''ra '''V'''engeance '''C'''r'''u'''elle '''M'''a'''n'''iant le '''Fe'''r '''Co'''ntre le '''Ni'''kel. Le '''Cu'''l de '''Z'''e'''n'''obie '''Ga'''rnit de '''Ge'''ranium '''As'''pire la '''Se'''ve '''Br'''ûlante du '''Kr'''atère (cratère/Krypton). » * « '''K'''onrad '''Ca'''pitaine '''Sc'''andinave '''Ti'''ra sa '''V'''erge '''Cr'''asseuse et '''M'''i'''n'''uscule, '''Fe'''rmant le '''Co'''n de '''Ni'''cole, le '''Cu'''l de '''Zn'''obie, et '''Ga'''rdant '''Ge'''néreusement l''''As'''permique '''Se'''mence du '''Br'''ave '''K'''e'''r'''mit. » * « '''K'''a'''Ca''' '''Sc'''quatte avec '''Ti'''ti la '''V'''oiture de '''Cr'''os '''M'''i'''n'''et. '''Fe'''rnand '''Co'''nduit sa mi'''Ni''' '''COOPER''' en '''Z'''i'''g'''za'''Ga'''nt, '''Ge'''néralement '''As'''sis en se '''Se'''rvant une '''B'''ière '''Kr'''onembourg. » * « '''K'''hrouchtchev '''Ca'''ressa '''Sc'''rupuleusement le '''Ti'''tanesque et '''V'''elue '''Cr'''ane du '''M'''o'''n'''de avec '''Fe'''rmeté. '''Co'''ntre l'ennemie, '''Ni'''kita '''C'''a'''u'''sa la '''Z'''iza'''n'''ie, il en'''Ga-Ge'''a l''''As'''sault '''S'''talinien. '''Br'''avo '''K'''h'''r'''ouchtchev. » * « '''K'''af'''Ca''' (Kafka) '''Sc'''ruta, '''Ti'''mide, '''V'''era '''Cr'''uz '''M'''o'''n'''trant ses '''Fe'''sses, '''Co'''mme la '''Ni'''mphe (nymphe) '''Cu'''pide '''Z'''é'''n'''a. '''Ga'''llien et '''Ge'''rard, '''As'''ssis, '''Se''' '''Br'''assaient de la '''Kr'''onenbourg. » * « '''K'''orrigan '''Ca'''pitaine '''Sc'''andinave '''Ti'''rant sa '''V'''erge '''Cr'''asseuse et '''M'''i'''n'''uscule ('''Mn''') '''Fe'''rma le '''Co'''n de '''Ni'''cole et le '''Cu'''l de '''Z'''é'''n'''obie ('''Zn''') '''Ga'''rdant '''Gé'''néreusement l’'''As'''permatique '''Se'''mence d’un '''Br'''un '''Kr'''omatique (chromatique).» *« '''K'''évin '''Ca'''sse '''Sc'''iemment sa '''Ti'''relire et '''V'''ient '''Cr'''ier : "'''M'''ama'''n''', fait ('''Fe''') '''Co'''mme '''Ni'''cole, '''Cu'''isine !". '''Z'''hi'''n'''g lui dit : "dé'''GaGe''', '''AsSe'''z '''Br'''aillé '''Kr'''étin". * « '''K'''arine '''Ca'''lcula que '''Sc'''ientifiquement '''Ti'''tillé, '''V'''incent '''Cr'''ame '''M'''o'''n''' '''F'''outr'''e''' '''Co'''mme '''Ni'''colas '''Cu'''pide '''Z'''i'''n'''zin '''Ga'''lleux '''Ge'''sticulant '''As'''ymétriquement et '''Se''' '''Br'''ulant à la '''Kr'''yptonite. » * « '''K'''ptain '''Ca'''ca '''Sc'''andinave '''Ti'''re sa '''V'''erge '''Cr'''asseuse et '''M'''i'''n'''uscule (Mn) des '''Fe'''sses de '''Co'''rine '''Ni'''çoise, '''Cu'''ltivée et '''Z'''e'''n''' (Zn), '''Ga'''lamment '''Ge'''néreuse, '''As'''sez '''Se'''xy et '''Br'''anlant '''K'''a'''r'''im (Kr). » * « '''K'''évin '''Ca'''tapulta '''Sc'''iemment '''Ti'''bère le '''V'''erreux, le '''Cr'''étin, le '''M'''écha'''n'''t, '''Fe'''roce, '''Co'''rrompu. Ha'''Ni'''bal, '''Cu'''i'''Z'''a'''n'''t, '''Ga'''ve '''Ge'''ntillement d''''As'''pirine '''Se'''c '''Br'''utus le '''Kr'''asseux. » * « '''K'''arine '''Ca'''ressa '''S'''e'''c''' '''Ti'''mothée '''V'''ers sa '''Cr'''oupe '''M'''ais '''n'''e '''Fé'''(fait) '''Co'''uille '''Ni''' '''Cu'''l. '''Z'''ho'''n'''g '''Ga'''gna '''Ge'''ntiment '''A s'''e '''Br'''anler '''Kr'''asseusement. » * « '''K'''oalas de '''Ca'''nberra, '''S'''’é'''c'''ria-'''T'''-'''i'''l, je '''V'''eux '''Cr'''oire '''M'''o'''n''' '''F'''r'''è'''re '''Co'''mplètement ! Ils '''Ni'''chent, '''C'''op'''u'''lent en '''Z'''o'''n'''ages '''Ga'''lamment '''Gé'''rés, '''As'''sistés '''Se'''ulement de '''Br'''ouillons '''K(r)'''yptés. (variante : de '''Br'''aves '''K'''angou'''r'''ous)» * '''K'''hrouchtchev, '''Ca'''lant son '''Sc'''rotum '''Ti'''tanesque '''V'''ers la '''Cr'''oupe '''M'''ag'''n'''ifique des '''Fe'''sses de '''Co'''ssiga, '''Ni'''qua ses '''Cu'''isses dé'''Z'''i'''n'''guées: '''Ga'''lipettes '''Gê'''nantes, '''As'''sez '''Se'''xy pour '''Br'''anler '''Kr'''ouchtchev. * '''K'''rouchtchev, '''Ca'''libre '''Sc'''rotal '''Ti'''tanesque, '''V'''a '''Cr'''euser '''M'''o'''n''' '''Fe'''ssier '''Co'''quin. '''Ni'''quant '''Cu'''pidement '''Z'''i'''n'''oviev, '''Ga'''garine '''Gè'''re '''As'''sez '''Se'''s '''Br'''asseries '''Kr'''onenbourg. * '''K'''rouchtchev '''Ca'''resse '''Sc'''rotalement '''Ti'''to. «'''V'''oilà», '''Cr'''ie '''M'''arc (Mn) '''Fe'''uillée, «'''Co'''mment '''Ni'''kita '''Cu'''lbute!» «'''Z'''i'''n'''zin!» '''Ga'''léjea '''Gé'''rard, «'''As'''sez '''Se'''xy! '''Br'''avo, '''Kr'''ouchtchev!» * '''K'''rouchtchev '''Ca'''usa '''Sc'''andale. '''Ti'''to, '''V'''erge '''Cr'''amoisie, '''M''''e'''nFe'''rre '''Co'''chonnement les '''Ni'''bards et les '''Cu'''isses. '''Z'''é'''n'''obie '''Ga'''ve '''Gé'''rard, '''As'''pergeant '''Se'''s '''Br'''asseries '''Kr'''onenbourg. ===== [[w:Éléments de la période 5|Période 5]] ===== ''Pour : '''R'''u'''b'''idium, '''S'''t'''r'''ontium, '''Y'''ttrium, '''Z'''i'''r'''conium, '''N'''io'''b'''ium, '''Mo'''lybdène, '''T'''e'''c'''hnétium, '''Ru'''thénium, '''Rh'''odium, '''P'''alla'''d'''ium, '''A'''r'''g'''ent, '''C'''a'''d'''mium, '''In'''dium, '''S'''ta'''n'''num (Étain), '''S'''ti'''b'''ium (Antimoine), '''Te'''llure, '''I'''ode, '''Xé'''non.'' * « '''R'''o'''b'''in '''S'''u'''r''' '''Y'''vette a le '''Z'''èb'''r'''e '''N'''o'''b'''le de '''Mo'''nsieur '''T'''u'''c''' '''Ru'''. '''R'''o'''h'''an '''P'''ru'''d'''emment '''Ag'''é '''C'''é'''d'''a '''In'''évitablement '''S'''a'''n'''s '''S'''u'''b'''ir '''Te'''s '''I'''dées '''Xé'''nophobes. » (variante : '''R'''o'''b'''in '''S'''o'''r'''t '''Y'''von, le '''Z'''èb'''r'''e '''N'''o'''b'''le, dans '''Mo'''n '''T'''a'''c'''ot '''R'''o'''u'''illé) * «'''R'''o'''b'''ert '''S'''enio'''r''' est un '''Y'''éti du '''Z'''aï'''r'''e ou un '''N'''o'''b'''lio de '''Mo'''dène. Le '''T'''e'''c'''hnicien '''Ru'''dement bourré au '''Rh'''um '''P'''é'''d'''ale '''Ag'''ilement des '''C'''ou'''d'''es, il '''I'''nsulte '''S'''ai'''n'''t '''S'''e'''b'''astien, un '''Te'''rrien '''I'''diot et '''Xé'''nophobe. » * « '''R'''u'''b'''y, '''S'''o'''r'''te de '''Y'''éti '''Z'''aï'''r'''ois qu’un '''N'''o'''b'''liau de '''Mo'''dène, '''T'''e'''c'''hniquement '''Ru'''iné, '''R'''ac'''h'''ète au '''P'''ala'''d'''in avec l’'''A'''r'''g'''ent des '''C'''a'''d'''eaux '''In'''digènes '''S'''a'''n'''s '''S'''u'''b'''ir '''Te'''s '''I'''res '''Xé'''nophobes. » * « Le '''R'''a'''b'''bin '''S'''o'''r'''t son '''Y'''acht, le '''Z'''èb'''r'''e, pendant que '''N'''a'''b'''il, le '''Mo'''ldave '''T'''ur'''c''' '''Ru'''dement bourré au '''Rh'''um '''P'''é'''d'''ale '''Ag'''ilement des '''C'''ou'''d'''es, '''In'''diquant à '''S'''o'''n''' ami '''S'''é'''b'''astien la '''Te'''rre '''I'''mbibée de '''Xé'''rès. » * « '''R'''o'''b'''in '''S'''′'''r'''approche du '''Y'''éti sur un '''Z'''èb'''r'''e, '''No'''nobstant le '''Mo'''rse '''Tc'''hèque en '''Ru'''t et le '''Rh'''inocéros '''P'''é'''d'''é '''Ag'''ressif et '''C'''an'''d'''ide ; '''In'''capable de '''Sn'''iffer du '''S'''a'''b'''le et de la '''Te'''rre en '''I'''mitant '''Xé'''na. » * «'''R'''o'''b'''ert '''S'''enio'''r''', un '''Y'''éti du '''Z'''aï'''r'''e, '''N'''o'''b'''le et '''Mo'''rose, '''T'''ri'''c'''otait '''Ru'''e du '''Rh'''um et, '''P'''en'''d'''ant l′'''Ag'''enouillement du '''C'''i'''d''', '''In'''sulta '''Sn'''obes et '''Sb'''ires '''Te'''rrorisés à l′'''I'''rruption d′un '''Xé'''nophobe. » ===== [[w:Éléments de la période 6|Période 6]] ===== ''Pour : '''C'''é'''s'''ium, '''Ba'''ryum, '''La'''nthane, '''H'''a'''f'''nium, '''Ta'''ntale, '''W'''olfram (Tungstène), '''R'''h'''é'''nium, '''Os'''mium, '''Ir'''idium, '''P'''la'''t'''ine, '''Au'''rum (Or), '''H'''ydrar'''g'''irum (Mercure), '''T'''ha'''l'''lium, '''P'''lom'''b''', '''Bi'''smuth, '''Po'''lonium, '''A'''s'''t'''ate, '''R'''ado'''n'''.'' (La ou Lu selon la classification) * « '''C'''é'''s'''ar '''Ba'''lade '''La''' '''H'''i'''f'''i de '''Ta'''ta dans le '''W'''agon et '''Re'''garde '''Os'''si '''Ir'''ma. '''P'''e'''t'''er '''Au''' '''H'''an'''g'''ar, un '''T'''e'''l''' '''P'''ro'''b'''lème '''Bi'''en '''Po'''sé '''At'''tend '''R'''épo'''n'''se. » (variante : et '''Re'''garde '''Os'''ciller '''Ir'''ma) * « '''C'''é'''s'''ar '''Ba'''isa '''La'''ngoureusement l''''H'''orri'''f'''iante '''Ta'''ntouse dans les '''W'''C ('''Ré'''pugnants), '''Ré'''pétant les '''Os'''cillations '''Ir'''resistibles du '''P'''é'''t'''ard d''''Au'''rélien ; Mercure('''Hg''') lui '''T'''ai'''l'''la dans le '''P'''lom'''b''' une '''Bi'''te '''Po'''ilue pour lui '''A'''s'''t'''iquer les '''R'''ei'''n'''s. » * « '''C'''a'''s'''imir et '''Ba'''stien '''La'''ncent des '''H'''yper'''f'''réquences qui '''Ta'''pent sur un '''W'''agon '''Re'''mpli d''''Os''' '''Ir'''radiés, qui '''P'''é'''t'''a à l''''Au'''be '''H'''y'''g'''iénique, '''T'''é'''l'''éportant un '''P'''lom'''b'''ier '''Bi'''zarre '''Po'''lonais '''At'''taché à la '''R'''ei'''n'''e. » ===== [[w:Éléments de la période 7|Période 7]] ===== Pour : '''Fr'''ancium, '''Ra'''dium, '''Ac'''tinium, '''R'''uther'''f'''ordium, '''D'''u'''b'''nium, '''S'''eabor'''g'''ium, '''B'''o'''h'''rium, '''H'''a'''s'''sium, '''M'''ei'''t'''nérium, '''D'''arm'''s'''tadtium, '''R'''oent'''g'''enium, '''C'''oper'''n'''icium * « Les '''Fr'''ancais '''Ra'''lent '''Ac'''tivement depuis que '''R'''a'''f'''farin a '''D'''ou'''b'''lé '''S'''é'''g'''olène, é'''B'''a'''h'''ie par son '''H'''i'''s'''toire '''M'''ue'''t'''te sur la '''D'''i'''s'''tribution '''R'''é'''g'''ionale de la '''C'''o'''n'''nerie. » * « '''Fr'''anck '''Ra'''te '''Ac'''tuellement le '''R'''on'''f'''lement '''D'''é'''b'''ile du '''S'''i'''g'''nal '''B'''o'''h'''émien à l''''H'''i'''s'''toire '''M'''y'''t'''hique... » ===== [[w:Lanthanides|Lanthanides]] ===== ''Pour : ('''La'''nthane), '''Cé'''rium, '''Pr'''aséodyme, '''N'''éo'''d'''yme, '''P'''ro'''m'''ethium, '''S'''a'''m'''arium, '''Eu'''ropium, '''G'''a'''d'''olinium, '''T'''er'''b'''ium, '''Dy'''sprosium, '''Ho'''lmium, '''Er'''bium, '''T'''hulliu'''m''', '''Y'''tter'''b'''ium, '''Lu'''técium'' * « '''Cé'''dric, '''Pr'''ophète '''N'''éan'''d'''ertalien, '''P'''ro'''m'''et la '''S'''a'''m'''ba. '''Eu'''gène, '''G'''ran'''d''' '''T'''rou'''b'''le '''Dy'''namique des '''Ho'''mmes '''Er'''rants, '''T'''o'''m'''be sur l'h'''Yb'''ride '''Lu'''ne. » * « La '''Ce'''llule du '''Pr'''ofesseur est à '''N'''otre-'''d'''ame de '''P'''ana'''m'''e, '''S'''o'''m'''met de l' '''Eu'''rope, '''G'''ran'''d'''e et '''T'''rès''' b'''elle, où '''Dy'''onisos et '''Ho'''mère '''Er'''raient sans '''T'''u'''m'''ulte. '''Y'''a'''b'''on '''Lu'''tèce! » * « '''Ce'''cile, qui '''Pr'''atiquait le '''N'''u'''d'''isme, '''P'''ro'''m'''ettait à la '''S'''a'''m'''aritaine '''Eu'''phorique un '''G'''o'''d'''emichet avec un '''T'''u'''b'''e de '''Dy'''namite, '''Ho'''chet '''Er'''otique et '''T'''u'''m'''éfiant, s'''Y'''m'''b'''ole de '''Lu'''xure. » * « '''Ce'''sar se '''Pr'''omène avec '''N'''a'''d'''ine et '''P'''a'''m'''ina, en '''S'''e'''m'''ant les '''Eu'''nuques qui '''G'''ar'''d'''aient le '''T'''éné'''b'''reux '''Dy'''lan dans un cac'''Ho'''t car il '''Er'''rait près de la '''T'''o'''m'''be d''''Yb'''-'''Lu'''" * « '''Ce''' '''P'''a'''r'''adis que '''N'''ous '''d'''onna ('''Nd''') '''P'''ro'''m'''éthée, '''S'''e'''m'''blable à l''''Eu'''rope, nous '''G'''ar'''d'''e des '''T'''erri'''b'''les '''Dy'''sputes à l''''Ho'''rizon. Nous '''Er'''igerons une '''T'''o'''m'''be et '''Y''' '''b'''annirons '''Lu'''cifer » ===== [[w:Actinides|Actinides]] ===== ''Pour : ('''Ac'''tinium), '''Th'''orium, '''Pr'''otactinium, '''U'''ranium, '''N'''e'''p'''tunium, '''P'''l'''u'''tonium, '''Am'''ericium, '''C'''uriu'''m''', '''B'''er'''k'''élium, '''C'''ali'''f'''ornium, '''E'''in'''s'''teinium, '''F'''er'''m'''ium, '''M'''en'''d'''élénium, '''No'''bélium, '''L'''aw'''r'''encium.'' * « '''Th'''éo '''Pa'''rle '''U'''niversellement mais ''' N' '''ex'''p'''rime '''P'''l'''u'''s l''''Am'''ertume '''C'''o'''m'''mune. '''B'''roo'''k''' '''C'''on'''f'''ie l''''Es'''poir de '''F'''or'''m'''er un '''M'''on'''d'''e '''No'''uveau et '''L'''ib'''r'''e. » * « L''''Ac'''tivation''' Th'''ermique des '''Pa'''tates à l''''U'''ranium du '''N'''é'''p'''al en '''Pu'''rée '''Am'''ène, '''C'''o'''m'''me à '''B'''ang'''k'''ok, le '''C'''on'''f'''ort '''Es'''thétique d'une '''F'''a'''m'''ine un '''M'''i'''d'''i de '''No'''ël au '''L'''ibé'''r'''ia. (ou en bord de '''Lw'''oire selon les classifications) » * « '''Th'''or '''Pa'''rtit '''U'''ne '''N'''uit '''p'''our '''P'''l'''u'''ton, '''Am'''oureux de '''C'''a'''m'''ille. '''B'''er'''k'''eley, '''C'''ali'''f'''ornia '''Es'''perait '''F'''u'''m'''er '''M'''a '''d'''ouce et '''No'''ble '''L'''au'''r'''a.» ===== [[w:Alcalin|Alcalin]]s Groupe 1 ===== ''Pour : ('''H'''ydrogène, non alcalin), '''Li'''thium, '''Na'''trium (Sodium), '''K'''allium (Potassium), '''R'''u'''b'''idium, '''C'''é'''s'''ium, '''Fr'''ancium.'' * « ('''H'''eureux) dans le '''Li'''t de '''Na'''tacha, [[w:Khrouchtchev|'''K'''hrouchtchev]] '''R'''a'''b'''aissait '''C'''on'''s'''tamment son '''Fr'''oc. » * « '''L'''’'''i'''nter'''Na'''tionale '''K'''ommuniste '''R'''e'''b'''ute les '''C'''apitali'''s'''tes '''Fr'''ançais. » * « '''Li'''li '''N’a''' '''K''' '''R'''e'''b'''outonner '''C'''e'''s''' '''Fr'''ocs ('''Fr'''usques). » ===== [[w:Alcalino-terreux|Alcalino-terreux]] Groupe 2 ===== ''Pour : '''Bé'''ryllium, '''M'''a'''g'''nésium, '''Ca'''lcium, '''S'''t'''r'''ontium, '''Ba'''ryum, '''Ra'''dium.'' * « '''Bé'''bel(mondo) '''M'''an'''g'''eait du '''Ca'''ssoulet '''S'''u'''r''' un '''Ba'''teau '''Ra'''pide. » * « '''Bé'''bert '''M'''an'''g'''ea du '''Ca'''nard '''S'''u'''r''' un '''Ba'''teau-'''Ra'''dar. » * « '''Bé'''ta '''M'''an'''g'''ea du '''Ca'''ca '''S'''u'''r''' le '''Ba'''r de '''Ra'''bat (Maroc). » * « '''Bé'''atrice '''M'''an'''g'''ea une '''Ca'''rotte en '''S'''i'''r'''otant un '''Ba'''nana-split '''Ra'''vissant. » ===== Groupe 13 ===== ''Pour '''B'''ore, '''Al'''uminium, '''Ga'''llium, '''In'''dium, '''T'''ha'''l'''lium.'' *"'''B'''oris '''Al'''lait '''Ga'''mbader '''In''' '''T'''ou'''l'''ouse" ===== [[w:Cristallogène|Cristallogène]]s Groupe 14 ===== ''Pour : '''C'''arbone, '''S'''ilicium, '''Ge'''rmanium, '''S'''ta'''n'''num (Étain), '''P'''lom'''b'''.'' * « '''C'''es '''S'''imples '''Ge'''stes '''S'''eraie'''n'''t '''P'''ro'''b'''lématiques'''. »''' * « '''C''' 'est '''Si''' '''Gê'''nant '''S'''a'''n'''s '''P'''u'''b'''is. » ===== [[w:Pnictogène|Pnictogène]]s Groupe 15 ===== ''Pour : '''N'''itrogène (Azote), '''P'''hosphore, '''A'''r'''s'''enic, '''S'''ti'''b'''ium (Antimoine), '''Bi'''smuth.'' * « '''N'''e '''P'''as '''As'''tiquer '''S'''e'''b''' et sa '''Bi'''te. » * « '''N'''e '''P'''as '''As'''tiquer '''S'''o'''b'''rement le '''Bi'''zuth. » * « '''N'''e '''P'''as '''As'''tiquer le'''S b'''outs de '''Bi'''te. » * « '''N'''e '''PAs''' '''S'''a'''b'''rer Byzance('''Bi'''). » * " '''N'''e '''P'''as '''As'''soir '''S'''a'''b'''rina '''Bi'''zarrement" ===== [[w:Chalcogène|Chalcogène]]s Groupe 16 ===== ''Pour : '''O'''xygène, '''S'''oufre, '''Sé'''lénium, '''Te'''llure, '''Po'''lonium.'' * « '''O'''live '''S'''uce le '''Se'''xe '''Te'''ndu de '''Po'''peye. » * « '''O'''hh '''S'''uce moi le '''Se'''xe et les '''Te'''sticules '''Po'''ilus. » * « '''O'''scar '''S'''uce '''Se'''s '''Te'''sticules '''Po'''ilus. » * « '''O'''rgasme '''S'''ur le '''Se'''duisant '''Te'''odore '''Po'''ilu. » * « '''OS''' '''Se'''dimentaire '''Te'''rriblement '''Po'''li. » * « '''O'''h '''S'''acré '''Se'''igneur aux '''Te'''sticules '''Po'''lyèdriques. » * « '''O'''h '''S'''eigneur '''Sé''' (c'est) '''Te'''llement '''Po'''urri. » ===== [[w:Halogène|Halogène]]s Groupe 17 ===== ''Pour : '''F'''luor, '''C'''h'''l'''ore, '''Br'''ome, '''I'''ode, '''A'''s'''t'''ate.'' * « '''F'''ootball '''Cl'''ub de '''Br'''èles '''I'''ncapables d''''At'''taquer. » * « '''F'''ranck et '''Cl'''aude '''Br'''outent '''I'''rène '''A''' '''t'''able. » * « Une '''F'''issure '''Cl'''aviculaire '''Br'''isa tout '''I'''ntérêt d''''At'''taquer. » * « '''F'''outez '''Cl'''aire, qui '''Br'''anle '''I'''saac, car elle '''At'''tend. » * « '''F'''antastique, '''Cl'''aire '''Br'''anche '''I'''nstinctivement l''''At'''tache. » * « '''F'''erdinand '''Cl'''aque '''Br'''utalement '''I'''rène '''A''' '''t'''erre. » * « Les '''F'''ameuses '''Cl'''ochettes des '''Br'''ebis d''''I'''talie '''At'''tirent. » * « Le '''F'''ranc '''Cl'''ovis '''Br'''oie d''''I'''nnombrables '''At'''omes. » * « '''F'''élicie '''Cl'''aqua '''Br'''ian, '''I'''nnocent '''At'''tardé. » * « '''F'''olle '''Cl'''ara '''Br'''ave l''''I'''nvincible '''At'''hena. » ===== [[w:Gaz noble|Gaz noble]]s Groupe 18 ===== ''Pour : '''Hé'''lium, '''Né'''on, '''Ar'''gon, '''Kr'''ypton, '''Xé'''non, '''R'''ado'''n'''.'' * « '''He'''rcule '''Né'''gligea d’'''Ar'''racher le '''K'''o'''r'''sage de '''Xé'''na et '''R'''o'''n'''fla. » * « '''Hé''','''Né'''ron, '''Ar'''rête de '''Kr'''âner, '''Xé'''nophobe '''R'''i'''n'''gard ! » ===== [[w:Métalloïde|Métalloïde]]s ===== ''Pour : '''B'''ore, '''Si'''licium, '''Ge'''rmanium, Arsenic '''As''', Antimoine '''Sb''', '''Te'''llure et '''Po'''lonium'' *« '''B'''ob '''Si'''ffle son '''Ge'''t '''As'''sis avec '''S'''é'''b''' devant la '''Té'''lé '''Po'''lonaise. » ==== Couples acide/base ==== L’a'''c'''i'''d'''e '''c'''è'''d'''e un ou plusieurs protons tandis que la b'''a'''se c'''a'''pte un ou plusieurs protons. ==== Couples oxydant/réducteur ==== « Les électrons sont du côté de l'Occident. » (phonétiquement ''l’oxydant'') On peut également retenir que : **Ox Fixe, Red Cède (L'oxydant fixe des électrons, le réducteur en cède) ** l’oxyd'''ant''' est méch'''ant''' (il prend donc des électrons) ; ** le réduct'''eur''' a bon c'''œur''' (il donne donc des électrons). **L'oxydANT gagnANT, réductEUR donnEUR **Cap sur l'occident ! (L'oxydant '''cap'''te les électrons) **Notons aussi que l'oXydant aXepte (accepte) les électrons. Phrase qui marche à la fois pour les couples Acide/Base et Oxydant/Réducteur : L'Apéro gagne toujours ! ( A[cide] perd (des protons), O[xydant] gagne (des électrons) ). '''<nowiki/>''' ==== Ordre de priorité des groupements radicaux dans la nomenclature==== '''<nowiki/>''' '''A'''bruti '''H'''ans '''est''' l' '''ami de''' '''Nitr'''o! '''Al'''lez '''c'''hantons, L''''alcool''' '''am'''ené '''i'''ci '''e'''st '''t'''rès '''t'''errible Acide carboxylique, Halogénure, Ester, Amide, Nitrile, Aldéhyde, Cétone, Alcool, Amine, Imine, Ether, Thiol, Thioléter (pour ces deux derniers se reporter à la longueur). '''A Carbalo''' '''Ester''' '''a mit''' du '''Nitrile Aldéhyde''', '''s'étonne''' '''Alcolaminimine'''. '''Et tertio''', du '''thioleter'''. "L'''oïc''' '''est''' '''l’ami de Dalton":''' acide carboxylique (-oïque), ester, amide, aldéhyde, cétone. (ne pas confondre l'aldéhyde et l'alcool- voir la longueur des mots: c'est le plus long qui gagne). '''<u>Règle de Cahn, Ingold et Prelog</u>''' <u>''pour '''I '''> '''Br''' > '''Cl''' > '''S''' > '''F '''> '''O''' > '''N''' > '''C''' > '''H'''''</u> ** « '''Ib'''ra '''Cl'''ame '''S'''a '''F'''oi '''O''' '''N'''ouveau '''C'''avani '''H'''éroïque. » === Thermodynamique === ==== Loi des gaz parfaits ==== '''pV''' = '''nRT''' '''p''' = pression en pascals ; '''V''' = volume en mètres cubes ; '''n''' = quantité de matière en mols ; '''R''' = constante des gaz parfaits. R = 8,3 J.K-1.mol-1 ; '''T''' = température en Kelvins '''P'''ascal '''v'''oulut '''n'''ous '''r'''endre '''t'''héiste (référence au pari de Pascal) '''P'''a'''v'''a'''n'''e'''r'''ai'''t''' (sans les voyelles) '''pV''' = '''nRT''' n’est pas pété, énervé (ptnrv) '''P'''rocès-'''v'''erbal ; '''n'''ous '''r'''end '''t'''riste '''P'''uissance de '''V'''itesse = '''n'''otion de '''R'''apidité '''T'''errestre - Pour les joueurs de jeu de rôle uniquement ! Les PV d'un Pokemon est égale au Niveau fois sa RésisTance <br> ==== Différentielle de l’enthalpie ==== dH = TdS + VdP '''d'''îners '''H'''onorables = '''T'''artes '''d'''e '''S'''aison + '''V'''ins '''d'''u '''P'''ays (dH=TdS + VdP) '''d'''ouces '''H'''armonies = '''T'''oniques '''d'''e '''S'''olfège + '''V'''ibrations '''d'''e '''P'''iano (dH=TdS + VdP) '''d'''écouvertes '''H'''éroïques = '''T'''résors '''d'''e '''S'''able + '''V'''oyages '''d'''e '''P'''irates (dH=TdS + VdP) '''d'''anses '''H'''ispaniques = '''T'''angos '''d'''e '''S'''eville + '''V'''alses '''d'''e '''P'''ampelune (dH=TdS + VdP) '''d'''épart '''H'''éroïque = '''T'''oujours '''d'''u '''S'''tyle + '''V'''itesse '''d'''e '''P'''ointe (dH=TdS + VdP) '''d'''estination des '''H'''istoriens = '''T'''raversant '''d'''es '''S'''iècles + '''V'''oyageant '''d'''ans le '''P'''assé (dH=TdS + VdP) ==== Différentielle de l’enthalpie libre ==== dG = VdP-SdT '''V'''iande '''d'''e '''P'''orc '''-''' '''S'''el '''d'''e '''T'''able (VdP-SdT) '''V'''ends '''d'''u '''P'''ain sans (-) '''S'''ortir '''d'''e '''T'''on '''G'''îte (VdP - SdT = dG) ==== Différentielle de l’énergie interne (sans variation de quantité de matière) ==== dU=TdS-PdV '''T'''u '''d'''ois '''S'''avoir mais '''P'''as '''d'''e'''V'''iner (TdS-PdV) '''T'''out '''d'''e '''S'''uite '''Moins''' de '''P'''oints '''d'''e '''V'''ie '''T'''éter '''D'''u '''S'''el '''P'''endant '''D'''eux (ou '''D'''ix) '''V'''endredis. '''T'''rou '''d'''ans le '''S'''lip et '''P'''antalon '''d'''ans le '''V'''ent '''<nowiki>d'</nowiki>'''après '''U'''lysse = '''T'''outes '''d'''es '''S'''irènes mais '''P'''as '''d'''es '''V'''ampires <br /> ==== Différentielle de l’énergie interne (avec variation de quantité de matière) ==== dU=TdS-PdV+µdn '''T'''rop '''d'''e '''S'''avoir mais '''P'''as '''d'''<nowiki/>'en'''V'''ie c'est être '''nu''' '''d'''ans la '''n'''uit === Géologie === '''Les ères géologiques, du Quaternaire au Primaire (permettant de retenir les datations approximatives 7x60 + 3x40 Ma)''' '''Cénozoïque''' 60 (Quaternaire + Tertiaire) '''Crétacé''' 120 '''Jurassique''' 180 '''Trias''' 240 '''Permien''' 300 '''Carbonifère''' 360 '''Dévonien''' 420 '''Silurien''' 460 '''Ordovicien''' 500 '''Cambrien''' 540 '''C'''ite '''C'''e '''J'''oli '''T'''ruc '''P'''our '''C'''onnaître '''D'''es '''S'''iècles '''O'''rdonnés '''C'''orrectement ==== Niveaux de l'échelle chronologique géologique ==== '''Éo'''le '''ér'''adiqua les '''pe'''upliers '''ép'''uisés par l''''âge'''. * (éon, ère, période, époque, âge) ==== Les six périodes géologiques de l’ère primaire ==== ;Cambrien, Ordovicien, Silurien, Dévonien, Carbonifère, Permien. * '''''Cambr'''onne, l’'''ord'''urier,''' s’il eû'''t été '''dévo'''t, n’eût point '''carboni'''sé son '''pèr'''e'' * '''''Cambr'''onne '''ordo'''nna '''sil'''ence et '''dévo'''uement à ses '''car'''abiniers '''perm'''issionnaires'' * '''''Cambr'''onne '''aur'''ait, '''s'il eût''' été '''dévo'''t, '''carboni'''sé son '''pèr'''e'' * '''c-or-si-dé-ca-pé''' = Corps si décapés. * ''Le '''ca-or-sil-dé-ca-pe''' ='' Le Cahors, il décape. ==== Les trois périodes géologiques de l’ère secondaire ==== ;Trias, Jurassique, Crétacé. * '''T'''rois '''j'''ours '''c'''hacune. ==== Les cinq périodes géologiques de l’ère tertiaire ==== ;Paléocène, Éocène, Oligocène, Miocène, Pliocène. * '''Pâl'''e '''Et o'''bscène '''Au lit''', '''Mio''' se '''Plie au'''x scènes (de l'amour) ==== Stalactites et stalagmites ==== ''Les stalac'''t'''ites '''t'''ombent, les stalag'''m'''ites '''m'''ontent.'' ==== Géophysique ==== Formule pour la [http://fr.wikipedia.org/wiki/Anomalie_de_Bouguer correction gravitationnelle de Bouguer]: 2*π*h*ρ*G (G=constante gravitationnelle ρ=Masse volumique/Densité) "deux pies hachent Roger" 2 π h ρ G (ρ = "Rho", lettre grecque) ==== [[w:Échelle de Mohs|Échelle de Mohs]] ==== "'''T'''a '''G'''rosse '''C'''oncierge '''F'''olle d''''A'''mour '''O'''se '''Q'''uémander '''T'''es '''C'''aresses '''D'''ivines" "'''T'''oi '''G'''rand '''C'''hevalier, '''F'''uis '''A'''vec '''O'''rdre '''Q'''uand '''T'''on '''C'''œur '''D'''éfaille" "'''T'''rès '''G'''rand '''C'''hemin de '''F'''er '''A'''pache. '''O'''h ! '''Q'''uel '''T'''emps '''C'''e '''D'''imanche !" "'''T'''on '''G'''igolo '''C'''onte '''F'''leurette '''A''' '''(H)O'''rtense, '''Q'''ui '''T'''e '''C'''ocufie '''D'''iablement !" "'''T'''on '''G'''rand '''C'''ul '''F'''endu '''A''' une '''O'''uverture '''Q'''ue '''T'''u '''C'''aches '''D'''écemment" "'''T'''on '''G'''ros '''C'''ochon '''F'''ait '''A'''ïe '''O'''uille '''Q'''uand '''T'''u '''C'''ognes '''D'''essus" ([[w:Talc|'''T'''alc]], [[w:Gypse|'''G'''ypse]], [[w:Calcite|'''C'''alcite]], [[w:Fluorite|'''F'''luorite]], [[w:Apatite|'''A'''patite]], [[w:Orthose|'''O'''rthose]], [[w:Quartz (minéral)|'''Q'''uartz]], [[w:Topaze|'''T'''opaze]], [[w:Corindon|'''C'''orindon]], [[w:Diamant|'''D'''iamant]]) === Botanique === ==== Distinguer les hêtres des charmes ==== Le '''charme''' d''''Adam''' est d''''être''' à '''poil'''. ou encore: "Être à poils charme Adam" La feuille du charme a des dents (charme d’Adam) et la feuille du hêtre a des poils (être à poil). ==== Distinguer les principales espèces de pin ==== Les aiguilles du pin '''blanc''' sont groupées par '''5'''. '''Blanc''' a '''5''' lettres. Le pin '''rouge''' a des aiguilles groupées par '''2'''. Le mot '''rouge''' a '''2''' syllabes (s'il est suivit d'un mot commençant par une consonne en versification). Les aiguilles du pin '''noir''' sont en groupes de '''2'''. Dans le mot '''noir''', il y a '''2''' voyelles. ==== Distinguer les sapins des épicéas ==== Les sapins ('''''A'''bies'') ont des cônes '''a'''scendants, les épicéas ('''''P'''icea'') ont des cônes '''p'''endants. ==== Distinguer les cèdres ==== Le cèdre de l’'''A'''tlas a les pointes des branches '''a'''scendantes, le cèdre de l’Himalaya (''Cedrus '''d'''eodara'') '''d'''escendantes, le cèdre du '''L'''iban horizonta'''l'''es. ==== Distinguer les platanes des érables ==== pl'''A'''t'''A'''ne : feuilles '''A'''lternes '''É'''rable : feuilles oppos'''É'''es ==== Distinguer un Catalpa d’un Paulownia ==== P'''a'''ulowni'''a''' : deux feuilles par nœud (2 fois le a dans le nom) C'''a'''t'''a'''lp'''a''' : trois feuilles par nœud (3 a dans son nom) ==== Distinguer les feuilles de trèfle ==== Les feuilles du trèfle blanc ont de petites dents autour, celles du trèfle rouge ont des poils autour. Dents blanches, poils rouges (et non dents rouges, poils blancs !) ==== Distinguer les feuilles de trèfles de celles des luzernes ==== Les luzernes (''Medicago'') ont des pointes (= aiguilles, les médecins font des injections) au bout des folioles. ==== Distinguer les vesces des gesses ==== gesses ('''''L'''athyrus'') : l'alignement des points d'insertion des filets des étamines forme un angle droit avec le tube des étamines → L vesces ('''''V'''icia'') : il est oblique par rapport au tube ; on retrouve ce côté oblique dans la lettre V ==== Distinguer les knauties des scabieuses ==== '''k'''nautie : 4 ('''k'''atr’) pétales dans chaque fleur de l’inflorescence '''s'''cabieuse : 5 ('''s'''inq) pétales par fleur de l’inflorescence et des '''s'''oies sur le réceptacle ==== Distinguer les plantules de céréales dans un champ ==== BOAS : le '''b'''lé étant plus riche a des oreillettes, des poils et une ligule l’'''o'''rge a des oreillettes et une ligule l’'''a'''voine a une ligule le '''s'''eigle étant plus pauvre, n’a plus rien === Zoologie === ==== Ordre des cétacés ==== « '''C'est assez''', dit la '''baleine''', al'''ors que''' j'ai le '''dos fin''' je me '''cache à l'eau''' **baleine, orque, dauphin, cachalot, mais la liste est très incomplète. ==== Ordre des tatous ==== Les tatous font partie de l’ordre des ''Édentés'' car : "T’as tout sauf les dents !" === Biologie === ==== L'ordre hiérarchique de la classification de [[w:Taxinomie|taxinomie]] ==== Des Rats Essayent de Courir là Où Finissent les Grands Espaces (Raccourcis).<br /> DoRs EnCOre, la Famille GÈRe.<br /> Reste En Classe Ou Fais Grandes Études.<br /> Reste En Contact, Odile, Fais Gaffe, Émile ! (inspiré de la Cité de la peur, où Odile est attachée de presse et Émile tueur)<br /> Domaine, Règne, Embranchement, Classe, Ordre, Famille, Genre, Espèce, (Race). RECOFGE: Règne, Embranchement, Classe, Ordre, Famille, Genre, Espèce ==== Les [[w:bases azotées|bases azotées]] de l’ADN ==== '''À''' '''T'''on '''G'''rand '''C'''œur. '''A'''h '''T'''a '''G'''ueule '''C'''rétin '''À''' '''T'''able '''G'''rand '''C'''hef ('''ATGC''' : [[w:adénine|adénine]], [[w:thymine|thymine]], [[w:guanine|guanine]], [[w:cytosine|cytosine]]) ==== Intron/Exon ==== '''Int'''ron = '''Int'''rus ou '''int'''rusif, c'est la partie de nucléotide d'un gène qui est excisé de l'ARN lors de l'épissage, à l'inverse des '''exons.''' '''<nowiki/>''' ==== La séquence nucléotidique des télomères humains ==== '''T'''ous '''t'''es '''a'''mis se '''g'''avent de '''g'''énial '''g'''uarana. (TTAGGG) ==== Les différentes phases de la [[mitose]] ==== **le Prophète Athée (Pro Met A T) ** Je te '''ProMets''' de l''''Ana'''l au '''Telo''' ** '''ProMets''' à '''Anna''' de '''Tél'''éphoner ** '''P'''etit '''M'''ammifère '''À''' '''T'''éton ** '''P'''etit '''M'''atin '''A'''uprès de '''T'''oi ** '''P'''etit '''M'''artien '''A'''ttaque la '''T'''erre ** '''P'''etite '''M'''émé '''A''' '''T'''éléphoné ** '''P'''apa '''M'''aman '''A'''mour '''T'''oujours ** '''P'''our '''M'''on '''A'''mi '''Th'''omas ** '''P'''our '''M'''on '''A'''mour '''T'''oujours ** '''P'''our '''M'''on '''A'''nus '''T'''roué ** '''P'''etite '''M'''ademoiselle '''A'''ge '''T'''endre ** Promettante : '''Pro'''/'''met'''t/'''an'''/'''te''' ** '''PROMETANATELO''' ** ou ProMéthée est AnaTello (Se rappeler de la phrase Prométhée est un intello) ** '''P'''apa '''M'''ange '''A''' '''T'''able ** '''P'''ro des '''M''' '''A''' '''T'''hs ** '''P'''rof de '''M''' '''A''' '''T'''hs ** '''P'''ierre '''M'''angea des '''A'''nanas '''T'''ransgéniques ** '''P'''ouvoir '''M'''asculin '''A'''vant '''T'''out ** '''P'''aris-'''M'''arseille '''A''' '''T'''rotinette ** '''P'''our '''M'''émoriser : '''A'''voir '''T'''ravaillé ** '''P'''our '''M'''ieux '''A'''pprendre'''T'''out ** '''P'''ays les '''M'''oins '''avancés''' ** Le '''Pro'''f '''Met''' l' '''Âne''' devant la '''Tél'''é ('''P'''rophase, '''M'''étaphase, '''A'''naphase, '''T'''élophase) ** '''P'''auline '''M'''arche '''à''' la '''T'''équila ** TAMPI (à lire à l'envers) ** c'est PRoMEtteur An(un) inTello ** Papa Mange un Abricot Trop sucré (avec le s de sucré pour la synthèse qui suit la mitose G1 --> S --> G2) ==== Les différentes phases de la PROPHASE ==== '''Le''' '''Zi'''zi du '''Pachy'''derme a des '''Di'''mensions '''Dia'''boliques. (Leptotène, Zygotène, Pachytène, Diplotène, et Diacinèse) ou Letzplin (lepto/zygo) protége (pachy) didier (diplo/diacinèse) ou Le Zip à Didier ou Le zizi n'a pas de diarrhée ou Le zizi poilu du doyen ou Le zizi du pachyderme et du diplodocus sont différents ou Les Zizis Peuvent Devenir Durs ! ou '''Pré'''férer '''Le''' '''Zi'''zi du '''Pachy'''derme à celui du '''Diplo'''docus '''Dia'''bétique Pour préleptotène, leptotène, zygotène, pachytène, diplotène, diacinèse ==== Les acides aminés dits essentiels : ==== ''on compte neuf acides aminés essentiels : le tryptophane, la lysine, la méthionine, la phénylalanine, la thréonine, la valine, la leucine, l'isoleucine et l'histidine'' Le (LEU) trou (THR) de l'hystérique (HIS) Lyse (LYS) fait (PHE) tripper (TRY) valentin (VAL) mais (MET) ilose (ILE) pas ! '''''Le''' '''très''' '''ly'''rique '''Tri'''stan '''fait''' '''va'''chement '''m'''archer '''Ys'''eult, quelle '''Hist'''oire !'' ou encore : Hystérique, le très lyrique Tristan fait vachement méditer Iseult en Argentine (His)Leu-Thr-Lys-Trp-Phe-Val-Met-Iso(Arg): Histidine et Arginine seulement essentiels chez les enfants. ('''Le'''ucine, '''Thré'''onine, '''Ly'''sine, '''Try'''ptophane, '''Phé'''nylalanine, '''Va'''line, '''M'''éthionine, '''Is'''oleucine, '''Hist'''idine) Met le dans la valise, il fait trop d'histoire avec l'argent/en argentine. le cours d’'''hist'''oire, '''il''' '''le''' '''lit''' '''mais''' '''fait''' '''tres''' '''trivial''' ('''Hist'''idine; '''Ile''': Isoleucine, '''Leu'''cine, '''Ly'''sine, '''Mé'''thionine, '''Phé'''nylalanine '''Thré'''onine,'''Try'''ptophane,, '''Va'''line) Dans une '''V'''(aline)'''I'''(soleucine)'''L'''(eucine), il y a des '''H'''(ystidine)'''L'''(ysine)'''M'''(ethionine) et des '''P'''(hénilalanine)'''T'''(hréonine)'''T'''(ryptophane) (Dans une ville, il y a des HLM et des PTT) ''ils le valent trop trop mes félicitations'' '''ile''' '''leu''' '''val''' '''thr'''''op'' '''tr'''''o'''''p''' '''met''' '''phe''' '''lys''' ''itations'' ''Va te le mettre, Phillipe'' '''VA'''l '''TH'''r '''LE'''u '''MET''' '''TR'''p '''PH'''e '''ILE''' '''LY'''s pe '''''Va''' '''tri'''poter '''Lys'''e mais ('''met''') fait ('''phe''') '''le''' '''tr'''ès '''iso'''lément'' ''val thr lys met phe (fait) leu trp ile (iso-leucine)'' Plus simple et plus concret que tous les autres moyens mnémotechniques: VTT MILLPH (prononcé VTT MILF) et ainsi vous obtiendrez : Valine, Thréonine, Tryptophane, Méthionine, Isoleucine, Leucine, Lysine, Phénylalanine, Histidine. ==== Les acides aminés dits apolaire (Proline polaire/apolaire comprise) ==== Valérie promet à la triste Iseult le phénix et la Glycine. (val) (Pro/Met)(Ala)(Trp) (Ile) (Leu) (Phe) (Gly) Glycine dévale à la pelle, il le promet trop. ==== Le [[w:cycle de Krebs|cycle de Krebs]] ==== **''Si le '''citr'''on '''iso'''<nowiki>le l'</nowiki>'''acéto'''ne, le '''succi'''nct '''succès''' '''fumera''' '''m'''oins '''haut''''' ('''citr'''ate, '''iso'''citrate, alph'''acét'''oglutarate, '''succ'''inyl CoA, '''succ'''inate, '''fumara'''te, '''ma'''late, '''o'''xaloacétate) ** Avec les initiales : "C'est ici ce samedi soir : fumette, mal-à-la-tête, oubliette." ou encore : ** ''La '''C''' '''I''' '''A''' '''su'''specte un '''su'''spect qui '''fum'''e des '''Mal'''boros '''ox'''ydées.'' ** '''O'''h '''C'''atastrophe ! '''I'''l '''Os'''e '''Ac'''tiver '''Sa''' '''Su'''per '''F'''orce '''M'''agique ==== Le [[w:Cycle de Calvin|Cycle de Calvin]] ==== **"Les '''ri'''mes '''intermédiaires''' aux '''fo'''rmes '''diffo'''rmes de '''PGAL''' '''ri'''ment." ('''ri'''bulose phosphate, '''intermédiaire''' instable qui se scinde en deux 3-'''pho'''sphoglycérate, 1,3-'''dipho'''sphoglycérate, phosphoglycéraldéhyde ('''PGAL'''), dont l'un quitte le cycle et cinq sont utilisés pour reformer le '''ri'''bulose phosphate.) ==== Les Aldohexoses ==== '''Allo'''ns, '''altr'''uiste '''gl'''acer la '''mann'''e, '''Gul'''liver '''i'''ra '''gal'''érer au '''tall'''us ('''Allo'''se; '''altr'''ose; '''gl'''ucose; '''mann'''ose, '''Gu'''lose '''i'''dose '''ga'''lactose '''ta'''lose) ==== Les protéines intervenant dans les jonctions cellulaires ==== (Attention que ces phrases ne fonctionnent pleinement que si l'on connaît <i>déjà</i> les protéines intervenant, mais que l'on a du mal à retenir lesquelles font quoi.) - Jonction Adherens : '''Vin'''t le '''cad'''avre '''é'''quipé d''''a'''rmes '''α''' qui '''plaqu'''a le '''glo'''ussant '''ca'''valier. -> '''Vin'''culine, '''cad'''hérine-'''E''', '''a'''ctine, '''α'''-actinine, '''plak'''o'''glo'''bine, '''ca'''ténine. - Jonction de contact focal : '''Vin'''t la '''paix''' '''intégr'''ale; les '''a'''rmes '''α''' en '''ta'''s. -> '''Vin'''culine, '''pax'''iline, '''intégr'''ines, '''a'''ctine, '''α'''-actinine, '''ta'''line. - Desmosome : Tout ce qui '''colle''', plus la '''kératine'''. -> Desmo'''coll'''ine, desmo'''glé'''ine, desmo'''plak'''ine, '''plak'''oglobine, '''plak'''ophiline, '''kératine'''. - Jonction Gap (de communication) : Elle induit une '''connexion'''. -> '''Connex'''ines. - Hémidesmosomes : La '''p'''yramide de '''Khé'''ops '''d'''étruit '''intégr'''alement '''la mi'''en'''ne'''. -> '''P'''lectine, '''ké'''ratine 5 et 14, '''d'''ystonine, '''intégr'''ine α6β4, '''laminine''' 332. - Jonction tight, ou étanche, qui comporte des "'''kissing''' points" et dont le complexe crée une "'''zonula occludens'''" : '''Embrasser''' '''Claudine''' crée une '''occlu'''sion '''acti'''ve. -> Claudine, occludine, actine, ZO-1. ==== Les protéines des filaments intermédiaires ==== Elles diffèrent en fonction du tissu où elles se trouvent. Attention que les moyens proposés ici servent plus à retrouver la fonction d'une protéine déjà connue qu'à retenir le nom en lui-même. - Épithéliums : Kératines. Facile, il suffit de réfléchir un instant pour s'apercevoir que l'épithélium est bourré de kératines (couche cornée, desmosomes, ...). - Tissu '''C'''onjonctif : '''V'''imentines. On retient "'''CV'''". - Tissu '''M'''usculaire : '''D'''esmines. On retient "'''MD'''", une abréviation fréquente en anglais pour qualifier un Docteur en Médecine (Medicinæ doctor). - Tissu Nerveux proprement dit : Protéines des neurofilaments. Elles n'ont donc pas de nom propre, leur nom est leur fonction : des '''protéines''' dans les '''filaments''' intermédiaires des '''neuro'''nes. - Tissu Nerveux "de soutien" (tissu glial, donc) : Protéines fibrillaires acides gliales. Elles n'ont pas de nom propre, le nom est la fonction : Des '''protéines''' qui génèrent des '''filaments''' ('''fibrillaires''', donc) appartenant au tissu '''glial'''. La seule chose à retenir est qu'elles sont acides. - Noyaux : Lamines. On peut retenir qu'elles forment la '''lamina''' nucléaire, ou encore que pour arriver au noyau d'une cellule il faut la "maltraiter", et pourquoi pas la '''laminer'''. ==Technologie== ===Électronique=== ====Code couleur des résistances==== Code couleur à retenir : Noir, Marron, Rouge, Orange, Jaune, Vert, Bleu, Violet, Gris, Blanc * Ne Mangez Rien Ou Je Vous Battrai Violemment Gros Béta. * Ne Mangez Rien Ou Je Vous Brûle Votre Grosse Barbe. * Ne Mangez Rien Ou Jeunez Voilà Bien Votre Grande Bêtise. === Informatique === ==== RJ45 croisé ==== Broches 361782'''45'''. ==== Modèle OSI ==== Le modèle OSI divise les fonctionnalités nécessaires à la communication en sept couches : *# '''P'''hysique, *# '''L'''iaison, *# '''R'''éseau, *# '''T'''ransport, *# '''S'''ession, *# '''P'''résentation, *# '''A'''pplication. ** Il faut être deux pour avoir une liaison. ** Le 4*4 est un transport. "Félicie, OSI" *#Séduit par son '''PHYSIQUE''' *#et n'ayant aucune '''LIAISON''', *#je l'ai contactée sur un '''RÉSEAU''' social. *#Arrivé chez elle en '''TRANSPORT''' en commun, *#suivi une '''SESSION''' de va-et-vient, *#sans aucune forme de '''PRÉSENTATION''', *#j'y ai mis toute mon '''APPLICATION'''. Le lendemain, elle me recontactait... Les mots des phrases suivantes ont des initiales identiques à celles des couches, dans l'ordre ci-dessus ( P L R T S P A ) : *#'''P'''artout '''L'''e '''R'''oi '''T'''rouve '''S'''a '''P'''lace '''A'''ssise *# '''P'''our '''L'''e '''R'''éseau '''T'''out '''S'''e '''P'''asse '''A'''utomatiquement *# '''P'''ar '''L'''à, '''R'''aisonnons '''T'''ransport '''S'''ans '''P'''résenter l''''A'''pplication *# ''Pour les amateurs du jeu d'échecs :'' '''P'''rends '''L'''a '''R'''eine '''T'''out '''S'''era '''P'''lus '''A'''gréable *# '''P'''etit '''L'''apin '''R'''ose '''T'''rouvé à la '''S.P.A.''' *# '''P'''our '''L'''e '''R'''epas '''T'''out '''S'''era '''P'''rêt '''À''' 7 heures (7 couches) *# '''P'''our '''L'''e '''R'''éseau '''T'''u '''S'''eras '''P'''as '''A'''ugmenté *# '''P'''our '''L'''a '''R'''oute, '''T'''u '''S'''uis '''P'''ierre-'''A'''lain ! *# '''P'''our '''L'''a''' R'''etenir '''T'''oujours '''S'''e '''P'''arler '''A'''vant ! Les mots des phrases suivantes ont des initiales identiques à celles des couches, dans l'ordre inverse ( A P S T R L P ) : *# '''A'''près '''P'''lusieurs '''S'''emaines, '''T'''out '''R'''espire '''L'''a '''P'''aix ==== Classe d'adresse IP ==== En binaire, compter le nombre de 1 avant le premier 0. * A : 0 -> 127 (+ 127) <code>0xxxxxxx</code> * B : 128 -> 191 (+ 63) <code>10xxxxxx</code> * C : 192 -> 223 (+ 31) <code>110xxxxx</code> == Grammaire et orthographe == ===<u>Les principaux mots interrogatifs</u>=== Ce moyen mnémotechnique est très utile pour les coups de téléphone où l’on doit demander des renseignements. Il faut dresser rapidement la liste des mots interrogatifs sur un papier et être sûr que l’on a des réponses à toutes les questions. '''C’est cucu, c’est occupé !''' *'''C'''ombien ? *'''Q'''uoi ? *'''Q'''ui ? *'''C'''omment ? *'''O'''ù ? *'''Q'''uand ? *'''P'''ourquoi ? === [[w:Conjonction de coordination|Conjonctions de coordination]] === ''Mais où est donc Ornicar ?'' (Mais, Ou, Et, Donc, Or, Ni, Car) Mais cette méthode est pédagogiquement discutable, car elle entretient la confusion entre ''et'' (conjonction) et ''est'' (verbe ''être'' à la troisième personne du singulier), ainsi qu'entre ''ou'' (conjonction) et ''où'' (adverbe ou pronom relatif). Attention, ''donc'' n’est plus une conjonction de coordination, mais bien un verbe conjugué pour ''est'' et un adverbe de coordination pour ''où'' ! On peut aussi l’apprendre de cette manière afin de sortir le OU et ne pas induire de confusion dans l’esprit Mais ! Et donc Ornicar (mais, et, donc, or, ni, car) en jouant sur la sonorité de la surprise Au Québec, on dit aussi: ''Mais où est donc Carnior ?'' ===<u>Les principales prépositions</u>=== *''Adam part pour Anvers avec cent sous sûrs, entre derrière chez Decontre'' :(À, Dans, Par, Pour, En, Vers, Avec, Sans, Sous, Sur, Entre, Derrière, Chez, De, Contre) *''Adam part pour envers avec deux cents sous chez Parmisur. '' :(À, Dans, Par, Pour, En, Vers, Avec, De, Sans, Sous, Chez, Parmi, Sur) *''Adam part pour Anvers avec deux cents sous.'' *"Adam part pour Anvers avec deux cents sous chez Sur." :( À, Dans, Par, Pour, En, Vers, Avec, De, Sans, Sous, Chez, Sur) *''Adam part pour Anvers avec cent sous de chez surdurand.'' *"(À, Dans, Par, Pour, En, Vers, Avec, Sans, Sous, De, Chez, Sur, Durant) *''Adam Surché part pour Anvers avec deux-cents sous'' *"(À, Dans, Sur, Chez, Par, Pour, En, Vers, Avec, Sans, Sous) *’’ Adeudans part pour Sur sans sous chez Devant-derrière avec Avant-après-contre’’ ===<u>Les pronoms relatifs</u>=== 3 culs domptent ouvertement monsieur lequel,Duquel,Auquel... ''<nowiki>Qui que quoi dont où lequel duquel auquel…'</nowiki>'' ===<u>Les déterminants possessifs</u>=== Au pluriel: ''Mais c'était nos voleurs !'' (mes, ses, tes, nos, vos, leurs) ===<u>Orthographe</u>=== * Mou'''r'''ir ne prend qu’un “ r ” car on ne meurt qu’une fois. * Nou'''rr'''ir prend deux “ r ” car on se nourrit plusieurs fois. * Cou'''r'''ir ne prend qu’un “ r ”car on manque d’air en courant,<br /> mais quand on a'''rr'''ive on prend tout l’air qu’on peut. * L’hironde'''ll'''e prend deux “ l ” car elle vole avec ses deux ailes. * La v'''i'''e'''i'''lle ne peut marcher qu’avec ses deux bâtons. * A'''pp'''uyer prend deux « p » car on s’appuie mieux sur deux pattes. * Un ba'''l'''ai prend un seul “ l ” car il n’y a qu’un manche. * Un ba'''ll'''et prend deux “ l ” car pour danser il faut deux jambes. * Toujour'''s''', toujours un “ s ” et à jamai'''s''', ne jamais l’oublier. * J’a'''p'''erçois sur une jambe mais j’a'''pp'''arais sur les deux. * Quand je mets deux "p" à apercevoir, j'aperçois une faute. * Je n’a'''p'''erçois qu’un '''p''' à a'''p'''ercevoir (ou je m’a'''p'''erçois qu’a'''p'''ercevoir ne prend qu’un '''p'''). * Enve'''l'''oppe ne prend qu’un “ l ” car on ne met qu’une lettre dans une enveloppe. En revanche pour un vélo on a deux '''p'''neus : dé''velo'''''pp'''er, en''velo'''''pp'''er, etc. * Cuiss'''eau''' de v'''eau'''. * Sate'''ll'''ite prend 2 '''L''' car c’est plus pratique pour voler. (et un seul '''t''' car il ne tourne qu’autour d’une seule '''T'''erre) * Évide'''mm'''ent prend deux '''m''' comme dans '''Papa/Maman''' (à noter : tous les adjectifs qui se terminent par "ent", comme "évident", prennent 2 "m" ensuite, comme "évidemment"). * Je me souviens d’une corde en rappel : On se souvient '''DE''' quelque chose, mais on se rappelle quelque chose. * Un pa'''r'''esseux cou'''r'''onné ca'''r'''essait une ca'''r'''otte avec un air intéressé : liste de mots qui ne prennent qu’un '''r'''. * Co'''ll'''ine a deux colonnes (2 ” l ”) et colo'''nn'''e a deux collines (2 ” n ”). * Dé'''velopp'''er je fais du vélo avec mes deux pieds pour pédaler. * Échapper prend deux "P" car on s'échappe mieux avec deux pieds. * Culo'''tt'''e prend deux '''T''' car il y a deux jambes pour une culotte * Un professeur a un seul '''F'''ront et deux '''S'''ourcils, donc un seul F, mais deux S * Philippe : je marche (2p) mais ne vole pas (1l) * On parle le flaman'''D''' dans les Flan'''D'''res. Le flaman'''T''' rose est un oiseau de grande '''T'''aille. * L’am'''a'''nde pousse sur un '''a'''rbre ; l’am'''e'''nde sur un '''e'''ssuie-glace. *Guè'''r'''e signifie "pas beaucoup", donc un seul r. Il faut au moins deux adversaires pour faire la gue'''rr'''e, donc 2 R. * Une P'''ê'''che (melba...) / P'''ê'''cher (du poisson) / P'''é'''cher (commettre une offense) / un P'''é'''ché (originel...) : Dans la p'''ê'''che en rivière, le '''^''' représente l’hameçon et la p'''ê'''che (fruit) représente le flotteur de la canne à p'''ê'''che). Quand on confesse au prêtre un p'''é'''ché, on fait profil bas (accent aigu sur le '''é'''). * Tous les membres de la famille ont un accent grave, sauf pépé et mémé : père, mère, nièce… * M devant Mbappé (M devant M, B et P) * Reg versus Erg : ** Un Reg est un désert de Roches, de pieRRes ** L’ERg est un désERt de dunes ===<u>Mots avec accent circonflexe</u>=== * Une t'''a'''che c'est suffisamment sale pour ne pas avoir besoin d'en rajouter (d'accent circonflexe) * Le chapeau de c'''i'''me est tombé dans l’ab'''î'''me. Et celui du bo'''i'''teux dans la bo'''î'''te ! * On dit chapeau ! pour la '''tâche''' accomplie et non pas chapeau ! pour la '''tache''' sur le vêtement. * Un chien ou un chat marche sur deux paires de pa'''tt'''es. Par contre, on fait cuire des p'''ât'''es dans une casserole qu'on couvre avec le chapeau du â. * "Traîner ses guêtres", c'est flâner. <u>Pour les anglophones</u>, il suffit souvent de comparer le mot anglais de même racine que le mot français sur lequel on a un doute pour l'accent circonflexe. Si ce mot anglais contient un S, le mot français équivalent contient souvent un accent circonflexe. Exemples : * Ancêtre / Ancestor * Apôtre / Apostle * Arrêt / Arrest * Bâtard / Bastard * Bête / Beast * Boîte / Box * Château / Castle *Cloître / Cloister * Côte (anatomie, rivage, pente, culinaire) / Coast (rivage) * Coût / Cost * Crête / Crest (vague, cimier, huppe…) * Dégoût / Disgust * Épitre / Epistle * Fête, Festif (fr) / Feast (eng) * Guêpe / Wasp (eng) tous deux venant de vespa (latin) * Forêt / Forest * Hâtif / Hasty * Hôpital / Hospital * Hôte, hôtesse / Host, hostess * Hâte / Haste * Honnête / Honest * Huître / Oyster * Île / Island * Intérêt / Interest * Maître / Master * Mât / Mast (bateau) * Paître / To pasture * Pâtisserie, Pâte / Pastry / Pasta (ital.) * Plâtre / Plaster * Quête / Quest * Rôtir / To roast * Tâche (travail et non salissure) / Task * Tempête / Tempest ===<u>Pluriel</u>=== *Pluriel en OUX au lieu de OUS ::Un '''hibou''' moche comme un '''pou''' ::Avait pour '''joujou''' sur ses '''genoux''' ::Un '''caillou''' aussi '''chou''' qu’un '''bijou'''. Variante : ::Viens mon '''chou''', mon '''bijou''' ::Viens sur mes '''genoux''' ::Avec des '''joujoux''' et des '''cailloux''' ::Pour éloigner ces vilains '''hiboux''' pleins de '''poux''' Variante : ::Viens mon '''chou''', mon '''joujou''', mon '''bijou''' ::Sur mes '''genoux''' ::Jeter des '''cailloux''' ::À ces vieux '''hiboux''', pleins de '''poux''' Variante :<blockquote>Viens mon '''chou''', sur mes '''genoux''' avec tes '''joujoux''' et tes '''bijoux'''</blockquote><blockquote>Pour jeter des '''cailloux''' sur les vilains '''hiboux''' pleins de '''poux'''.</blockquote> Variante : Répéter plusieurs fois très vite : Hi-ge-jou-bi-ca-chou-pou. Vous avez ainsi les premières syllabes des 7 noms qui se terminent en "oux" au pluriel. 2e variante: '''J'''e '''P'''eux '''B'''oire '''C'''omme '''C'''es '''G'''ros '''H'''ommes. * Les noms terminés en « -al » font leur pluriel en « -aux » (sauf ''aval, bal, cal, carnaval, chacal, choral, festival, mistral, naval, pal, récital, régal''… qui font leur pluriel en « s ») : ::Dans mon pays '''natal''' ::Où les gens sont pourtant '''joviaux''' ::Eut lieu, c’était '''fatal''', un combat '''naval''', ::Heureusement, ce fut le combat '''final''' ::Parce qu’il faisait '''glacial'''. == [[w:Grammaire|Langues étrangères]] == Ces langues nous sont étrangères, d’où l’importance de trouver des moyens mnémotechniques === [[w:Allemand|Allemand]] === ==== Liste des particules verbales non détachables ==== ''J’ai mis Cerbère en enfer'' : ge-, miss-, zer-, be-, er-, ent-, emp-, ver- ''Cerbère gémit en enfer'' : zer-, be-, er-, ge-, miss-, ent-, emp-, ver- ''Miss Verzer bégaie en panthère'' : miss-, ver-, zer-, be-, ge-, emp-, ent-, er- ==== Genre des mots ==== Les mots (de plus d'une syllabe) se terminant en -e, -ei, -ie, -heit, -keit, -tion, -ung sont féminins. <br /> Il existe bien sûr des exceptions : der Däne, das Genie, der Ursprung, der Hochsprung... === [[w:Anglais|Anglais]] === ==== Mots contraires ou confondables ==== * Left: gauche / '''R'''ight: d'''r'''oite ** avec la''' main gauche''', on peut former un '''L''' en tenant les doigts en haut et le pouce en avant. C’est le '''L''' de '''L'''eft. ** dans l’alphabet le '''L''' est à '''gauche''' ('''L'''eft) et le '''R''' est à '''droite''' ('''R'''ight) : **:A B C D E F G H I J K '''L''' M N O P Q '''R''' S T U V W X Y Z ** Copy'''right''' veut dire '''droit''' d'auteur. ** Quand on est a'''droit''', c’est bien (= '''right''' en anglais) * Odd (3 lettres) : impair / Even (4 lettres) : pair ** Tuesday : mardi / Thu'''r'''sday : jeudi *** Thu'''r'''sday est le quat'''r'''ième jour de la semaine, il a donc un '''r''' ('''quatrième''' lettre) *** En classant les mots dans l’ordre lexicographique : ****jeudi (Thursday) est avant mardi (Tuesday), ****Thursday (jeudi) est avant Tuesday (mardi). *** Je'''u'''di et Th'''u'''rsday ont tous les deux la lettre '''u''' en troisième position. *** étymologiquement : Thursday = jour de '''Thor''', et jeudi = jour de '''Jupiter''' (Jovis die). Thor (mythologie nordique) et Jupiter (mythologie romaine) sont tous les deux ''dieu du tonnerre''. Même chose pour l'étymologie de Tuesday (jour de '''Tyr''') et de mardi (jour de '''Mars'''), tous les deux étant ''dieu de la guerre''. Mais il est plus difficile de retrouver Odin dans Tuesday. ***TUEsday sonne comme two-sday two étant égal au nombre 2 et mardi est le deuxième jour de la semaine. === [[w:Espagnol|Espagnol]] === ==== [[w:Consonne|Consonnes]] doublées ==== Les seules consonnes que l’on peut trouver à l’écrit en double sont celles du mot CaRoLiNa. On peut remarquer que le "[[w:LL|ll]]" est une consonne à part entière. Attention ! Ne pas confondre N et Ñ ==== <u>Subjonctif</u> ==== ===== verbe Savoir (saber) ===== si tu '''sé '''ton présent mais que tu ne '''sepa '''ton subjonctif ce n'est pas grave! === [[w:Japonais|Japonais]] === {{article détaillé|Japonais/Hiragana/Leçon 1}} === [[w:Latin|Latin]] === ==== Ordre des six cas principaux du latin ==== '''No'''us '''Vo'''us '''Ac'''hetons '''Gé'''néralement '''D'''es '''Ab'''ricots '''No'''minatif, '''Vo'''catif, '''Ac'''cusatif, '''Gé'''nitif, '''D'''atif, '''Ab'''latif === [[w:Néerlandais|Néerlandais]] === ==== Liste des particules verbales non détachables ==== ''begeherontverer' : be-, ge-, her-, ont-, ver-, er-'' BEnoit et Gerard ONT HERité du VERgER ==== Conjugaison de l’[[w:imparfait|imparfait]] ==== On forme l’[[w:imparfait|imparfait]] avec un '''t''' si le radical (Verbe -EN) du verbe se termine par F, K, P, S, T, CH.<br> Retenez : '''F'''ran'''K'''lin '''p'''rend '''s'''on '''t'''hé '''ch'''aud. <br> Si le radical se termine par une autre lettre, on forme l’imparfait avec un '''d'''. Exemples : <br> - pakken (''prendre'') : pak'''k'''-en > hij pak'''t'''e (''il prenait'')<br> - ruilen (''échanger'') : rui'''l'''-en > hij ruil'''d'''e (''il échangeait'') === [[w:Russe|Russe]]=== ==== Verbes à voyelle alternante ы/о dans le thème ==== '''К'''арл '''Р'''о'''М'''а'''Н'''о'''В''' крыть « couvrir » - рыть « creuser » - мыть « laver » - ныть « gémir; faire mal » - выть « hurler » Se fléchissent tous sur le modèle : * infinitif : мыть (accent stable au passé: м'ыла) * conjugaison : мóю, мóешь... мóют Contrairement à ст'ыть, ст'ыну « refroidir » ; слыть, слывý « être réputé... » == Littérature == === Auteurs français du {{XVIIe siècle}} === ''Sur une racine de la bruyère, une corneille boit l’eau de la fontaine Molière'' ([[w:Jean Racine|Racine]], [[w:Jean de La Bruyère|Jean de La Bruyère]], [[w:Pierre Corneille|Pierre Corneille]], [[w:Nicolas Boileau|Nicolas Boileau]], [[w:Jean de La Fontaine|Jean de La Fontaine]], [[w:Molière|Molière]]) Variante : La Corneille perchée sur la Racine de La Bruyère, Boileau de La Fontaine Molière ''(Remarque : La fontaine Molière est une fontaine à Paris)'' == Théâtre == Face à la scène, le côté '''j'''ardin et le côté '''c'''our sont du côté de chaque initiale de '''J'''ésus '''C'''hrist, de '''J'''ules '''C'''ésar , de '''J'''acques '''C'''artier ou de '''J'''acques '''C'''hirac (J.C. : jardin à gauche, cour à droite) Face au public, c’est l’inverse, et le côté '''cour''' est le côté du [[w:cœur|cœur]], à gauche. == Musique == '''Ah ! Lala !''' * Se souvenir de cette interjection pour faire correspondre les notes musicales latines (do, ré, mi fa...) avec les anglo-saxonnes (C, D, E, F...) '''A''' correspond à '''la''', il n'y a plus qu'à suivre B=si, C=do, D=ré, E=mi, F=fa, G=sol. '''TS MS DSS''' *''Nom des degrés'': '''t'''onique, '''s'''us-tonique, '''m'''édiante, '''s'''ous-dominante, '''d'''ominante, '''s'''us-dominante, '''s'''ensible '''Sa mère la racaille ! Saleté de fumier !''' *''Ordre des bémols'' : '''S'''i '''m'''i '''l'''a '''r'''é '''s'''ol '''d'''o '''f'''a '''Six mille laquais repus songent au dodo, fatigués''' *''Ordre des bémols'' : '''Si''' '''mi''' '''la''' '''ré''' '''so'''l '''do''' '''fa''' '''Facteur, donne au soldat réjoui la missive''' *''Ordre des dièses'' : '''Fa''' '''do''' '''sol''' '''ré''' '''la''' '''mi''' '''si''' '''Dommage, la mine est cassée Do Majeur --> La mineur''' *"Gamme relative" de Do Majeur '''Il Doit Posséder Les Modes En Lui''' Ionien, Dorien, Phrygien, Lydien, Mixolydien, Éolien, Locrien == Géographie == === Points cardinaux === ==== Où est l’est ? ==== *Visualiser Strasbourg et Brest. Strasbourg est à l'est, Brest est à l'ouest * Penser au mot '''O'''rang'''E''', sur une carte, l'Ouest est à gauche et l'Est à droite. * Écrire "'''où est''' l''''est'''" --> ouest à gauche et est à droite (en considérant le nord en haut bien entendu) * L’ouest est à gauche, l’est à droite (si le nord est au-dessus). * Penser que si on regarde la France, à gauche c'est l' ''eau'' comme dans '''O'''uest et à droite c'est l' ''étranger'' comme dans '''E'''st. * Penser qu'en France, on parle des "pays de l'est" (à droite sur la carte) et en parlant de la conquête de l'ouest on pense à l'Amérique (à gauche sur la carte) * Penser à : Ouest, le suffixe "est" se trouve à droite, tout comme l’est. Ce qui signifie "ouest" à gauche et "est" à droite. * Écrire ONE (1 en anglais) : Ouest-Nord-Est * Penser au mot 'OiE': l’Ouest est à gauche comme le O et l’Est est à droite comme le E (si le Nord est en haut) * Dans le mot ouest il y a un "u" comme dans gauche. Dans le mot est il n'y a pas de "u" comme dans droite. * Retenir le mot NESO en tournant dans le sens des aiguilles d'une montre, car l'inverse donne la nausée (NOSE). ==== Le soleil se couche à l’est ou à l’ouest ? ==== * Penser qu’en France, on voit de beaux couchers de soleil sur nos côtes atlantiques, à l’ouest. * Penser aussi au pays du soleil levant, le Japon, qui est bien à l’est du continent * Ou encore : Le Soleil se l'''è'''ve à l’'''e'''st et se c'''ou'''che à l’'''ou'''est === Pays limitrophes de la France === Aime '''I''S''A''B''E''L''A''' (Aimer pour la lettre '''M''') '''M'''onaco, '''I'''talie, '''S'''uisse, '''A'''llemagne, '''B'''elgique, '''E'''spagne, '''L'''uxembourg, '''A'''ndorre. ''MAL BAISÉ'' '''M'''onaco, '''A'''ndorre, '''L'''uxembourg, '''B'''elgique, '''A'''llemagne, '''I'''talie, '''S'''uisse, '''E'''spagne. ''AIMABLES'' '''A'''llemagne, '''I'''talie, '''M'''onaco, '''A'''ndorre, '''B'''elgique, '''L'''uxembourg, '''E'''spagne, '''S'''uisse Avec l’océan Atlantique, la Manche et la Méditerranée en plus : '' '''O'''h '''MA''' '''MER'''veilleuse '''BALISE''' '' '''O'''h = '''O'''céan Atlantique '''MA'''='''MA'''nche '''MER'''= '''MER'''Méditerranée '''BALISE'''= '''B'''elgique '''A'''llemagne '''L'''uxembourg '''I'''talie '''S'''uisse '''E'''spagne PS cette liste est valable seulement pour la France Métropolitaine car le pays avec lequel la France a la plus longue frontière est le ... Brésil ! (car la Guyane est un département français) === Grands lacs de l'Amérique du Nord === ''SMHEOL'' (d'ouest en est) '''S'''upérieur, '''M'''ichigan, '''H'''uron, '''E'''rié, '''O'''ntario (et St '''L'''aurent) ''HOLMES (élémentaire !)'' '''H'''uron, '''O'''ntario, St '''L'''aurent, '''M'''ichigan, '''E'''rié, '''S'''upérieur. Une autre méthode, souvent enseignée dans les cours de géographie, fait appel au mot anglais ''foyers'' de la manière suivante : ''HOMES'' '''H'''uron, '''O'''ntario, '''M'''ichigan, '''E'''rié, '''S'''upérieur === Les 5 arrondissements de New-York (Boroughs) === Vous n'arrivez pas à vous souvenir des 5 arrondissements de la grande ville de New-York? En sachant qu'il est incontournable d'aller se promener dans les grandes avenues et rues sans s'arrêter dans un stand BBQ et y manger les bons hot-dogs d'un sympathique New-yorkais. Il faut dire: '''Si Man BBQ''' (Staten Island, Manhattan, Brooklyn, Bronx, Queen). Bon appétit, bonne visite!. === Pays baltes === Vous confondez les pays baltes sur la carte ? C'est tout simple, ils sont placés par ordre alphabétique du nord au sud... [[w:Estonie|Estonie]], [[w:Lettonie|Lettonie]], [[w:Lituanie|Lituanie]] * Cela fonctionne aussi avec les appellations anglo-saxonnes : Estonia, Latvia, Lithuania et aussi avec les noms locaux : Eesti, Latvija, Lietuva. * Pour les capitales de ces pays : Estonie [[w:Tallinn|Tallinn]], Lettonie [[w:Riga|Riga]] et Lituanie [[w:Vilnius|Vilnius]] '''T'''rafic '''R'''outier '''V'''olumineux === Les tropiques === Les tropiques du Cancer et du Capricorne sont classés du nord au sud par ordre alphabétique. Le capricorne coule (en bas) car il a plus de lettres, il est plus lourd. L'antarctique aussi : l'arctique flotte. ou tropique du caNcer : N represente le Nord. ou Capricorne sonne comme "Cap Horn" donc au Sud === Les pays d'Amérique Centrale === *Du nord au sud : [[w:Bélize|Bélize]], [[w:Guatemala|Guatemala]], [[w:Honduras|Honduras]], [[w:Salvador|Salvador]], [[w:Nicaragua|Nicaragua]], [[w:Costa Rica|Costa Rica]], [[w:Panama|Panama]]. BGHSNCP soit: '''B'''eau '''G'''arçon '''H'''abitant '''S'''alvador '''N'''ettoie et '''C'''i'''r'''e les '''P'''lanchers ou Belle Guatemalaise Habitant Salvador, Nage sur la Côte du Panama. === Fleuves de Russie === D'ouest en est, les initiales des cinq principaux fleuves de [[w:Russie|Russie]] forment le mot "VOILA" : [[w:Volga|Volga]], [[w:Ob|Ob]], [[w:Ienisseï|Ienisseï]], [[w:Léna|Léna]], [[w:Amour (fleuve)|Amour]]. L'Ob, le Ienissei et la Léna sont les trois plus grands cours d'eau de Sibérie. === Pays du Moyen-Orient === Le Qatar est une presQu'île dans la péninsule arabiQue. Le Qatar peut être vu comme comme une Crête de CoQ juchée sur l'Arabie saoudite et s'ouvrant sur le golfe arabo-persiQue. === Pays d'Asie Centrale (en -stan) === * Du Nord au Sud et de l'Ouest à l'Est '''Kaz'''akhstan - '''Ou'''zbékistan - '''Ki'''rghizistan - '''Tu'''rkménistan - '''Ta'''djikistan - '''Af'''ghanistan - '''Pa'''kistan Kaz Ou Ki Tu Ta Af Pa Kazouki, tu taffes pas ? === Principales villes traversées par la Loire === * De l´Atlantique au Mont Gerbier de Jonc '''Na'''thalie '''an'''goisse '''to'''ujours les '''bl'''ondes '''or'''iginaires de '''Nevers''', elles '''ro'''ugissent '''sa'''ns '''pu'''deur. Nantes Angers Tours Blois Orléans Nevers Roanne Saint-Étienne Le Puy en Velay == Histoire == === Préhistoire === {{loupe|#Les périodes géologiques de l’ère primaire|# Les périodes géologiques de l’ère secondaire}} ==== Évolution des [[w:Homininae|homininés]] ==== Les '''Austral'''iens '''habil'''es eurent une '''érec'''tion, quand ils aperçurent, dans le '''néan'''t, des '''sapins''' gigantesques, <br /> ce qui donne, par ordre d'apparition<br /> [[w:Australopithèque|Australopithèque]], [[w:Homo habilis|Homo habilis]], [[w:Homo erectus|Homo erectus]], [[w:Homme de Néanderthal|Homme de Néanderthal]] et [[w:Homo Sapiens|Homo Sapiens]]. === Les 7 Merveilles du monde antique === "'''Mostapha''' ! '''J’attends''' la '''copie''' !" Variante: "'''Mostapha''' ! '''J’attends''' ta '''coloscopie''' !" ('''Mau'''solée d’Halicarnasse, '''Sta'''tue de Zeus à Olympie, '''Pha'''re d’Alexandrie, '''Ja'''rdins suspendus de Babylone, '''Tem'''ple d'Artémis à Éphèse, '''Co'''losse de Rhodes, '''Py'''ramides d’Égypte) === Les 7 rois de Rome === ''Ronutuann' tarsertar'' (qu'on retient mieux en imaginant le paresseux boucher Ronu : "Ronu, tuant tard, sert tard") ('''Ro'''mulus, '''Nu'''ma Pompilius, '''Tu'''llus Hostilius, '''An'''cus Martius, '''Tar'''quin l’Ancien, '''Ser'''vius Tullius, '''Tar'''quin le Superbe) === Les 11 [[w:Liste des empereurs romains|premiers empereurs romains]], dans l’ordre de leur règne === ''AuTiCaClauNéGalOViVesTiDo'' ('''Au'''guste, '''Ti'''bère, '''Ca'''ligula, '''Clau'''de, '''Né'''ron, '''Gal'''ba, '''O'''thon, '''Vi'''tellus, '''Ves'''pasien, '''Ti'''tus, '''Do'''mitien) Et les six suivants : ''NeTraHadAnMarCo'' (Nerva, Trajan, Hadrien, Antonin, Marc-Aurèle, Commode) Cesautica Clonegalo Vivestido CESar, AUguste, TIbere, CAligula CLAUde, NEron, GALba, Othon VItellus, VESpasien, TItus, Domitien === Les traités napoléoniens, dans l’ordre de leur signature === '''''CAV''''' (penser à une ''cave'') : ''Cambalu, Apresti, Viparis'' ('''Cam'''po Formio, '''Bâ'''le, '''Lu'''néville, '''A'''miens, '''Pres'''bourg, '''Ti'''lsit, '''Vi'''enne, '''Paris''') === Les présidents de la troisième République française === ''Thimagré Carcafauloufa Poindemidoudoule'' ('''Thi'''ers, '''Ma'''c-Mahon, '''Gré'''vy, '''Car'''not, '''Ca'''simir-Perier, '''Fau'''re, '''Lou'''bet, '''Fa'''llières, '''Poin'''caré, '''De'''schanel, '''Mi'''llerand, '''Dou'''mergue, '''Dou'''mer, '''Le'''brun) OU ce petit poème : Tire Mon Glaive Car Casse-Pierre Fort Loup Faillit Point Dèche Mille Dômes D'où Merle Brun === Les présidents de la cinquième République française === '''D'''es '''P'''illards '''G'''ouvernent, '''M'''ais '''C'''hacun '''S'''ubit '''H'''élas la Macronie '''D'''ur '''P'''armesan '''G'''orgonzola '''M'''ozzarella '''Ch'''auds '''S'''ervis. '''D'''ouce '''P'''atrie '''G'''auloise où '''M'''iaulent les '''Ch'''ats '''S'''iamois '''H'''eureux. <math>\Longrightarrow</math>De Gaulle, Pompidou, Giscard d'Estaing, Mitterrand, Chirac, Sarkozy, Hollande. '''D'''ouce '''P'''atrie '''G'''auloise où '''M'''iaulent les '''Ch'''ats '''S'''iamois '''H'''eureux et '''M'''alades. <math>\Longrightarrow</math>De Gaulle, Pompidou, Giscard d'Estaing, Mitterrand, Chirac, Sarkozy, Hollande, Macron. - Le sauveur de la France, Charles '''de Gaulle''', s’orthographie avec deux L. On peut retenir que de Gaulle a deux L, comme les deux barres de la croix de Lorraine, symbole de la France libre. On retient que la Gaule n’a qu’un L comme le L unique dans Celtes. Car "les Gaulois" est le nom que Jules César donne aux Celtes. === Les présidents américains à partir de Roosevelt === '''R'''udy '''T'''ente '''E'''n '''K'''araté '''J'''e '''N'''ique '''F'''abienne '''C'''omme '''R'''udy '''B'''ouche '''C'''ontre '''B'''ouche '''O'''utré '''T'''errifié. '''R'''oosevelt '''T'''rouva '''E'''léonore en '''K'''imono, '''J'''ames '''N'''e '''F'''ilma '''C'''arrément '''R'''ien, '''B'''rave '''C'''améraman '''B'''ouché et '''T'''êtu ! <math>\Longrightarrow</math>Roosevelt, Truman, Eisenhower, Kennedy, Johnson, Nixon, Ford, Carter, Reagan, Bush, Clinton, Bush, Obama, Trump. === Les dirigeants de l'URSS et de la Russie === '''L'''aissant '''S'''on '''K'''imono '''B'''leu '''À''' '''T'''rois '''G'''amins, '''E'''lle '''P'''ut '''M'''aintenir '''P'''outine. L = Lénine, S = Staline, K = Khrouchtchev B = Brejnev, À = Andropov, T = Tchernenko, G = Gorbatchev.....la "virgule" marque la chute du communisme, et E = Eltsine, P = Poutine, M = Medvedev, P = Poutine == Médecine == === Plan des muscles complexus === 1. Muscle semi-épineux de la tête * Sème tranquillement 156 graines dans un carré de terre pour 71 arbres épineux. (Le semi-épineux a pour origine les processus transverses de Th1 à TH5/Th6 et C4 à C7 et se termine sur les processus épineux de C7 ) th1) 2. Muscle longicissimus du cou *Louons tranquillement une sainte tu (la) sauteras. (Le muscle longicissimus du cou a pour origine les processus transverses de Th1 à Th5 et se termine sur les tubercules post de C3 à C7) === Les os du carpe === *''SSPP - TTCC'' (Initiales) * ''Sca-Lu-Py-Pi T-T-Go-Oc'' (Phonétique) <math>\Longrightarrow</math>('''Sca'''phoïde, (Semi-'''Lu'''naire)'''lu'''natum* , '''Py'''ramidal, '''Pi'''siforme - '''T'''rapèze, '''T'''rapézoïde, '''C'''apitatum ''', '''os '''C'''rochu ''')''' NB : dans la nouvelle nomenclature ce n'est plus le semi-lunaire mais le LUNATUM *On peut le voir sous un autre angle : ** PI - TRI - LU - SCA *: (pisciforme) (triquetrum) (lunatum) (scaphoide) ** HA - CA - TRI - TRA *: (hamatum) (capitatum) (trapézoide) (trapèze) Ou encore prendre les consonnes de ces 2 mots : *'''P'''é'''T'''a'''L'''e'''S''' : '''P'''isiforme - '''T'''riquetrum - '''L'''unatum - '''S'''caphoïde * a'''TT'''a'''CH'''e : '''T'''rapèze - '''T'''rapézoïde - '''C'''apitatum - '''H'''amatum *Trouvé par un étudiant : * ** '''S'''a'''L'''e '''T'''e'''P'''u, '''<nowiki>T'</nowiki>'''é'''T'''ais à '''CH'''ier. ** '''S'''uce '''l'''a '''t'''rique '''P'''atrick, '''t'''u '''t'''ireras '''Ch'''arlotte ** Le '''S'''carabée à '''L'''unettes '''T'''rie ses '''P'''ièces, '''T'''out '''T'''as est un '''C'''apital ('''h''')Amassé" ** '''S'''a'''L'''u'''T''' '''P'''ierre, '''T'''<nowiki/>'é'''T'''ais '''C'''haud '''H'''ier. === Les muscles épicondyliens médiaux (ex-épitrochléens) du membre supérieur === ''Grand Papa cuve et ronfle'' <math>\Longrightarrow</math>('''Grand pa'''lmaire, Petit '''pa'''lmaire, '''Cu'''bitus antérieur, '''Ron'''d pronateur, '''Flé'''chisseur commun superficiel) Une autre phrase est proposée "Grand Papa, Petit Papa, fléchit rondement le cul en avant" <u>Avec la nouvelle nomenclature</u> : ''Paulo Fuck Les Filles Sans Défense Faisant Un CAprice'' ''==> rond '''P'''ronateur, '''F'''léchisseur radial du carpe, '''L'''ong palmaire, '''F'''léchisseur '''S'''uperficiel des '''D'''oigts, '''Fl'''échisseur '''U'''lnaire du '''Ca'''rpe'' === Les muscles épicondyliens latéraux (ex-épicondyliens) du membre supérieur === <math>\Longrightarrow</math>'''2'''ème '''Ra'''dial, '''Ext'''enseur '''commun''', '''ext'''enseur '''propre''' '''du 5'''ème doigt, '''Court Su'''pinateur, '''Cu'''bital '''Post'''érieur, '''Anconé''' Deux rats excommuniés, expropriés du 5e ont cousu (court supinateur) le cul de la postière en cône. <u>Avec la nouvelle nomenclature</u> : ''Charlie Rêve d'Explorer Des Etoiles, 5 Etoiles Uniques Au Sanctuaire'' ''==>'' Court extenseur Radial du carpe, Extenseur commun des Doigts, Extenseur du 5ème doigt, Extenseur Ulnaire du carpe, Anconé, Supinateur === Les 12 paires de nerfs crâniens === ==== Ancienne nomenclature ==== *'''''O'''h '''O'''scar, '''m'''a '''p'''etite '''t'''héière '''m'''e '''f'''ait '''à''' '''g'''rand '''p'''eine '''s'''ix '''g'''rogs'' *'''''O'''h '''O'''scar, '''m'''a '''p'''etite '''t'''hérèse '''m'''e '''f'''ait '''à''' '''g'''rand '''p'''eine '''s'''ix '''g'''osses'' <math>\Longrightarrow</math>'''O'''lfactifs, '''O'''ptiques, '''M'''oteur oculaire commun, '''p'''athétiques, '''T'''rijumeau, '''M'''oteur oculaire externe, '''F'''aciaux, '''A'''uditifs, '''G'''losso-pharyngiens, '''P'''neumogastriques, '''S'''pinaux, '''G'''rand hypoglosse. * Nouvelle nomenclature *'''''OL'''ivia '''OPT'''<nowiki>e pour l'</nowiki>'''OC'''éan c'est '''TRO'''p '''TRI'''<nowiki>ste d'</nowiki>'''A'''ller '''FA'''ire des '''V'''isites '''G'''avantes quand les '''VAGUES''' '''A'''<nowiki>pportent l'</nowiki>'''HYP'''nose.'' *'''O'''h '''O'''h ! '''O'''scar ! '''T'''a '''T'''héière '''A''' '''F'''ait '''V'''ingt '''G'''rands '''V'''erres '''A''' '''H'''ector. *'' '''Ol'''ivier '''Op'''oil '''Ocul''' '''Troqu'''a '''Tri'''stement '''A'''vec '''Fa'''nny '''V'''ingt '''Gloss Par'''fums '''Va'''nille '''Accessoire'''<nowiki> d'</nowiki>'''Hy'''dratation.'' *'''''Ol'''é '''O'''<nowiki>scar d'</nowiki>'''Occ'''ident ! '''Tr'''availle ton '''Tri'''ceps, tes '''Abd'''o et tes '''F'''esses au '''WC'''. '''Gl'''isse '''vague'''ment ton '''accessoire''' et '''hip''' !'' *'''''O'''yez, '''O'''yez ! '''O'''bstinée '''T'''ortue '''T'''enace '''A''' '''F'''inalement '''V'''aincu, '''G'''rand '''V'''antard '''A''' '''H'''onte.'' *'''''O'''yé! '''O'''yé! '''O'''bstinée '''T'''ortue '''T'''enace '''A''' '''F'''inalement '''V'''aincu (la) '''G'''rande '''V'''ague '''À''' '''H'''awaii''. *'' '''Ol'''af '''Opt'''a '''Occ'''asionellement pour le '''Tro'''quet '''T'''andis qu' '''Abd'''el '''Fa'''isait '''V'''alser '''G'''rand'''-P'''ère '''Vague'''ment '''A'''utour de l' '''Hippo'''campe. '' *'''''O'''n '''O'''ccasion '''O'''livier '''T'''ries '''T'''o '''A'''nally '''F'''uck '''V'''arious '''G'''uys, '''V'''aginas '''A'''re '''H'''istory''. *'''''Ol'''a! '''Op'''hélie '''O cul Tro'''p '''Tri'''pant '''A Fa'''it '''Co'''quettement '''Glo'''usser '''Va'''lentin '''A''' l'<nowiki/>'''Hypo'''drome.'' <math>\Longrightarrow</math>'''O'''lfactif, '''O'''ptique, '''O'''cculomoteur, '''T'''rochléaire, '''T'''rijumeau, '''A'''bducens, '''F'''acial, '''V'''estibulo-Cochléaire ''ou'' '''C'''ochléo-vestibulaire, '''G'''losso-Pharyngien, '''V'''ague, '''A'''ccessoire, '''H'''ypoglosse. ==== Sensitif ou moteur ==== - Un dernier pour savoir la '''composante de chaque nerfs''' : Mots commençant par un '''S''' = sensitif, '''M''' = moteur, '''B''' = les deux (both). Ensuite les noms communs et les adjectifs sont parasympathiques (Money, brother, big, boobs). *'''''S'''ome '''S'''ay '''M'''oney '''M'''atters, '''B'''ut '''M'''y '''B'''rother '''S'''ays : '''B'''ig '''B'''oobs '''M'''atter '''M'''ost.'' ex: Boobs = 10e nerf (Vague), B = sensitif et moteur, nom commun = parasympathique. Ceci correspond aux caractéristiques du nerf vague ! - Une autre plus rigolote et moins décente : *'''''S'''eb '''S'''uces '''M'''oi '''M'''es '''D'''eux '''M'''amelons '''D'''e '''S'''ilicone '''D'''é-'''D'''é '''M'''e '''M'''anque'' '''S'''ahara '''S'''ablonneux (et) '''M'''er '''M'''orte, '''D'''eux '''M'''ondes '''D'''e '''S'''ilence (et) '''D'''éserts '''D'''e '''M'''ouvants '''M'''irages '''S''' = sensitif, '''M''' = moteur, '''D'''= les deux. Ainsi le 1{{er}} nerf crânien est sensitif. Le 9{{e}} et le 10{{e}} sont à la fois sensitifs et moteurs, etc. === Les 15 collatérales de l’artère maxillaire === '''''T'''on '''m'''épris '''p'''eut '''a'''mener '''m'''a '''t'''empête '''p'''etite '''b'''iche '''t'''ant aimée. '''Un''' '''p'''etit '''c'''âlin '''p'''eut '''p'''ardonner'' <math>\Longrightarrow</math>('''T'''ympanique, '''M'''éningée moyenne, '''P'''etite méningée, '''A'''lvéolaire inférieure, '''M'''asseterine, '''T'''emporale profonde postérieure, '''P'''térygoïdienne, '''B'''uccale, '''T'''emporale profonde antérieure, '''A'''lvéolaire supérieure, '''In'''fra-orbitaire, '''P'''alatine descendante, du '''C'''anal ptérygoïdien, '''P'''térygo-palatine, '''P'''haryngienne) (N.B. Non! l'artère pharyngienne est une branche de la carotide externe!) les 15 branches dans l'ordre: un '''T'''ic '''MENING'''é '''PE'''ut '''DE'''venir '''MA'''léfique, '''T'''andis qu'un '''BU'''bon '''TE'''rriblement '''AL'''gique '''P'''eu'''T''' être '''SOU'''lagé '''VI'''te '''PA'''r une '''PT'''yaline '''SP'''écifique '''( T'''ympanique, '''MENINGE'''é moyenne, '''PE'''tite méningée, '''DE'''ntaire inférieure, '''MA'''ssétérine, '''T'''emporale profonde moyenne, '''BU'''ccale, '''TE'''mporale profonde antérieure, '''AL'''véolaire, '''PT'''érygoïdienne, '''SOU'''s orbitaire, '''VI'''dienne, '''PA'''latine descendante, '''PT'''érygopalatine, '''SP'''hénopalatine.) === Les branches de l'artère axillaire === '''TH'''éodore '''a''' '''m'''angé '''s'''on '''c'''a'''c'''a <math>\Longrightarrow</math>'''TH'''oracique supérieure, '''A'''cromiothoracique, '''M'''ammaire Interne, '''S'''capulaire et les deux '''C'''irconflexes Cette artère se trouve dans la région de l'aisselle et pas ailleurs. === Branche de l'artère carotide externe : === '''''T'''ous '''L'''es '''F'''rançais '''O'''nt '''A'''pplaudi le '''P'''résident '''M'''onsieur '''T'''hiers''. <math>\Longrightarrow</math>('''T'''hyroïdienne supérieure, '''L'''inguale, '''F'''aciale, '''O'''ccipitale, '''A'''uriculaire postérieure, '''P'''haryngienne ascendante, '''M'''axillaire interne, '''T'''emporale superficielle): === Collatérales de la carotide externe === '''''T'''ire '''l'''a '''f'''icelle, '''p'''ortier ! '''O'''uvre '''à''' '''t'''on '''m'''aître '''r'''apidement'' <math>\Longrightarrow</math>('''T'''hyroïdienne supérieure, '''L'''inguale, '''F'''aciale, '''P'''haryngienne ascendante, '''O'''ccipitale, '''A'''uriculaire postérieure, '''T'''emporale superficielle, '''M'''axillaire, '''R'''ameau parotidien) '''T'''ou'''s''' '''l'''es '''F'''rançais '''a'''cclament '''O'''bama '''p'''résident <math>\Longrightarrow</math>('''T'''hyroïdienne '''s'''upérieure, '''L'''inguale, '''F'''aciale, '''A'''uriculaire postérieure, '''O'''ccipitale, '''P'''haryngienne ascendante) '''S'''ome '''a'''ngry '''l'''ady '''f'''igured '''o'''ut '''p'''ost '''m'''enopausal '''s'''yndrom. <math>\Longrightarrow</math>('''S'''uperior thyroidal, '''A'''scending pharyngeal, '''L'''ingual, '''F'''acial, '''O'''ccipital, '''P'''osterior auricular, '''M'''axillary, '''S'''uperficial temporal) Ce dernier, bien qu'en anglais, a l'avantage d'indiquer les artères dans l'ordre ascendant. '''T'''u '''P'''eux '''L'''a '''F'''ourrer '''O'''u l'''A''' '''M'''anger '''T'''oute. <math>\Longrightarrow</math>('''T'''hyroïdienne supérieure, '''P'''haryngée ascendante, '''L'''inguale, '''F'''aciale, '''O'''ccipitale, '''A'''uriculaire postérieure, '''M'''axillaire, '''T'''emporale superficielle) Ce dernier est une variante québécoise à caractère sexuel qui a également l'avantage d'indiquer les artères dans l'ordre ascendant. === Les collatérales de l’artère ophtalmique === '''''R'''emets '''l'''es '''c'''apotes '''s'''ans '''n'''ous '''f'''aire '''p'''<nowiki>erdre l'</nowiki>'''é'''rection'' <math>\Longrightarrow</math>(Centrale de la '''R'''étine, '''L'''acrymales, '''C'''iliaires, '''S'''upra-orbitaire, '''N'''asales, '''F'''rontales, '''P'''alpébrales, '''E'''htmoïdales antérieures et postérieures) === Les rameaux du plexus lombaire === '''Il''' '''hyp'''notise '''il'''lico l''''igu'''ane '''gé'''ant et '''fé'''roce et lui '''c'''oupe '''l'''ittéralement '''la''' '''cuisse''' qui '''fai'''sait '''ob'''struction '''car''' elle '''l'omb'''rageait. <math>\Longrightarrow</math>('''il'''io-'''hyp'''ogastrique; '''il'''io-'''ingu'''inal; '''gé'''nito-'''fé'''moral; '''c'''utané '''l'''atéral de '''la''' '''cuisse'''; '''fé'''moral; '''ob'''turateur; du muscle '''car'''ré des '''lombes''') === Les rameaux du plexus sacré === '''Si''' un '''gl'''acier '''sup'''er '''inf'''idèle est '''honteux''' d’avoir '''per'''foré le '''rect'''um et '''élev'''é '''l’anus''' d’un '''cu'''isinier '''po'''urtant '''c'''onsentant, un '''curé''' '''fe'''ra un '''ju'''gement '''im'''partial en '''oub'''liant l’'''in'''acceptable. <math>\Longrightarrow</math>('''sci'''atique; '''gl'''utéal '''sup'''érieur et '''inf'''érieur; '''honteux'''; '''pir'''iforme; '''rect'''al supérieur ; '''élév'''ateur de '''l’anus'''; '''cu'''tané '''po'''stérieur de la '''c'''uisse; '''carré''' '''fé'''moral et '''ju'''meau '''in'''férieur; '''ob'''turateur '''in'''terne) === Les muscles du grand trochanter === Mon '''g'''ars, '''troqu'''ons: Le '''Petit''' '''Pierre''' et '''les jumeaux''' '''moyen'''nant '''fesses''' à '''obtur'''er. <math>\Longrightarrow</math>('''G'''rand '''Troch'''anter: '''petit''' fessier; '''pir'''iforme; '''jumeaux''' supérieur et inférieur; '''moyen fess'''ier; '''obtur'''ateurs internes et externes) === Les muscles de la patte d'oie === *SA GRA - Tte ("ça gratte") *# Sartorius (ex-Couturier) *# Gracile *# Tendineux **CGT **Sartre est grat et tendre **ça gratte === Les ménisques du genou === '''''CI'''TR'''OE'''N'' (Le ménisque en forme de '''C''' est le ménisque '''I'''nterne ; le ménisque en forme de '''O''' est le ménisque '''E'''xterne) === Les obturateurs pelvi-trochantériens === Être '''ex-empt''' d''''im-pôt'''s (L'obturateur '''ex'''terne s'insère à la face '''ant'''érieure de l'os coxal, l'obturateur '''in'''terne s'insère à la face '''po'''stérieure de l'os coxal) == Mythologie == === Les 3 Grâces === '''Aglaé''' offre une u'''sine''' à Na'''thalie''' (variante : Aglaé offre Rosine à Nathalie) ** Aglaé, Euphrosine et Thalie === Les 9 Muses === Voici l'astuce des étudiants en grec à l'école pour retenir les neuf muses : '''''Cl'''ame, '''Eu'''gène, '''ta''' '''mél'''odie, '''terr'''ible '''air''' '''pol'''onais, o'''ura'''gan '''cal'''culé'' <math>\Longrightarrow</math>('''Cl'''io, '''Eu'''terpe, '''Tha'''lie, '''Mel'''pomène, '''Ter'''psichore, '''Ér'''ato, '''Pol'''ymnie, '''Ura'''nie, '''Cal'''liope) Calliope porte une couronne d’or, Clio une couronne de laurier, Érato une couronne de myrtes et de roses, Euterpe une couronne de fleurs, Melpomène une couronne de pampre de vigne, Polymnie une couronne de perles, Terpsichore une couronne de guirlandes, Thalie une couronne de lierre, et Uranie une couronne d'étoiles === Les dieux grecs === ''Hazah Phadhadah'' <math>\Longrightarrow</math>('''H'''éra, '''A'''phrodite, '''Z'''eus, '''A'''pollon, '''H'''éphaïstos, '''P'''oséidon, '''H'''ermès, '''A'''rtémis, '''D'''ionysos, '''H'''adès, '''A'''théna, '''D'''éméter, '''A'''rès, '''H'''estia) Notons que la plupart des dieux grecs commencent par la lettre "A" ou "H". {| class="wikitable" |- | Hestia || arrêta || d'aimer || Zeus<small>:</small> || possédée || <small>par</small> Dionysos<small>,</small> || <small>elle</small> erra || <small>dans</small> Athènes<small>,</small> || affolée<small>,</small> || <small>et fit</small> l'apologie || <small>de l'</small>art || effarant || d'Hermes || et d'Hadès |- | Hestia || Arès || Demeter || Zeus || Poséidon || Dionysos || Héra || Athéna || Aphrodite || Apollon || Artémis || Héphaïstos || Hermes || Hades |} === Les dieux romains === '''''J'''eune '''v'''euve '''j'''oyeuse '''c'''herche '''v'''ieux '''b'''aron '''m'''ême '''m'''alade '''a'''fin '''d'''e '''v'''ivre '''m'''ieux'' '''p'''oint <math>\Longrightarrow</math>('''J'''unon, '''V'''énus, '''J'''upiter, '''C'''érès, '''V'''ulcain, '''B'''acchus, '''M'''ercure, '''M'''inerve, '''A'''pollon, '''D'''iane, '''V'''esta, '''M'''ars, '''P'''luton) == Religion == === Les dimanches avant Pâques === Les petits protestants alsaciens (et allemands aussi, sans doute) apprenaient jadis le nom des dimanches qui précédaient Pâques grâce à la phrase : « '''I'''n '''R'''echter '''O'''rdnung '''L'''ehre '''J'''esu '''P'''assion », ce qui signifie : « Apprends dans le bon ordre la passion de Jésus ». On peut aussi dire : « '''I'''n '''R'''ektors '''O'''fen '''L'''iegen '''J'''unge '''P'''almen », ce qui veut dire : « Dans le poêle du recteur se trouvent de jeunes palmes (allusion à rameaux) ». Et ils retrouvaient : '''I'''nvocavit, '''R'''eminiscere, '''O'''culi, '''L'''aetare, '''J'''udica et '''P'''almarum (Palmsonntag - dimanche des Rameaux). === Péchés capitaux === Les initiales des [[w:sept péchés capitaux|sept péchés capitaux]] sont rassemblés dans le mot « Pô glacé ». ('''p'''aresse, '''o'''rgueil, '''g'''ourmandise, '''l'''uxure, '''a'''varice, '''c'''olère et '''e'''nvie) ** Autre expression pour retenir les 7 péchés capitaux : " CE GALOP ". (Colère, Envie, Gourmandise, Avarice, Luxure, Orgueil, Paresse) ** L' '''ENV''' ie '''EN V'''eut, lorsqu'on lui demande de travailler, la '''P'''aresse se '''P'''ousse, l' '''O'''rgueil se pense plus haut ('''O''') que les autres, la '''G'''ourmandise mange du '''G'''ateau et du '''G'''ras, la '''L'''uxure va dans un hot-'''L''', l' '''A'''varice en '''A''', la '''C'''olère '''C'''rie. **Ou encore une phrase: '''L'''es '''G'''rands '''E'''sprits '''O'''bligent '''C'''ertainement '''A''' '''P'''enser (luxure, gourmandise, envie, orgueil, colère, avarice, paresse) (entendu cité par Jacques Lacarrière lors d'une interview sur France-Culture)' ' **Une phrase courte et très facile à mémoriser, car elle ne fait pas appel qu'aux initiales qui demanderaient encore beaucoup d'efforts pour les identifier. Ici, l'utilisation de mots qui agissent immédiatement sur la divulgation des 7 péchés: ''''<nowiki>Par goût, Colette envie l'orgue luxueux d'Avarice'</nowiki>''' ('''Par'''esse, '''gou'''rmandise, '''colè'''re, '''envie''', '''orgue'''il, '''lux'''ure, '''avarice''') === Épîtres de Paul === Rococo Galéphicol ThèThè TimTim TiPhilHé ('''Ro'''mains, 1 '''Co'''rinthiens, 2 '''Co'''rinthiens, '''Gal'''ates, '''Éph'''esiens, '''Phi'''lippiens, '''Col'''ossiens, 1 '''The'''ssaloniciens, 2 '''The'''ssaloniciens, 1 '''Tim'''othée, 2 '''Tim'''othée, '''Ti'''te, '''Phil'''émon, '''Hé'''breux) === Apôtres de Jésus === '''S'''ouvent '''a'''bsent, '''J'''ean '''J'''aures '''p'''erdait '''b'''êtement '''t'''oute '''m'''onnaie le '''j'''our '''J''' de '''s'''on '''j'''eûne. '''S'''imon, '''A'''ndré, '''J'''acques, '''J'''ean, '''P'''hilippe, '''B'''arthélémy, '''T'''homas, '''M'''atthieu, '''J'''acques, '''J'''ude, '''S'''imon, '''J'''udas. '''Si JaJa Ma embarté Juju, J'enfile To Pierre''' '''Si'''mon, '''Ja'''cques, '''Ja'''cques, '''Ma'''tthieu, '''An'''dré, '''Barthé'''lémy, '''Ju'''de, '''Ju'''das, '''Jean''', '''Phil'''ippe, '''Tho'''mas, '''Pierre'''. === '''Vertus Cardinales''' === '''P'''rudence, '''J'''ustice, '''F'''orce et '''T'''empérance se retient avec : " '''P'''our '''J'''ésus, '''F'''ais '''T'''out ! ", les premières lettres des mots rappellent les quatre vertus cardinales. === Les sept sacrements catholiques === ''BECOROM'' : # Baptême # Eucharistie # Confirmation # Onction des malades # Réconciliation # Ordination # Mariage === Les sept dons de l'Esprit Saint === ''P C DS FCC (paie ces déesses fichier central des chèques)'' # Sagesse # Discernement # Conseil # Force # Connaissance # Crainte du Seigneur # Piété == Navigation == === Marine === ==== Bâbord/Tribord ==== '''''Bâ'''bord c’est g'''a'''uche, t'''r'''ibord, c’est d'''r'''oite.'' (si on regarde vers la partie avant du bateau) On peut aussi le retenir avec le mot batterie (que l’on prononce généralement « BaTri »), on a Ba à gauche (comme bâbord) et Tri à droite (comme tribord) OU plus simple avec "BaTeau". {| class="wikitable" | Bâ | Tri |- | Bâbord | Tribord |- | Gauche | Droite |} Variante : la seconde lettre de b'''â'''bord est la même que la seconde lettre de g'''a'''uche et la seconde lettre de t'''r'''ibord est la même que la seconde lettre de d'''r'''oite. Variante : Babo<s>rd ga</s>uche = Babouche. On ne retrouve qu'un A dans bAbord et gAuche et un I dans trIbord et droIte. ==== Couleur et signalisation bâbord et tribord ==== Couleur des feux de navigation d'un bateau: {| | Bâbord | '''R'''ouge |- | Tribord | '''V'''ert |} Lu de gauche à droite cela fait '''RV''' ou le prénom '''Hervé'''. ''Un marin emporte toujours Un Tricot Vert et Deux Bas Si Rouges'' = chiffres '''impairs''', '''Tri'''bord, '''Cô'''ne, '''Vert''', et chiffres '''pairs''', '''Bâ'''bord, '''Cy'''lindre, '''Rouge'''. Ou encore : en entrant au port, on trouve les balises COniques VERTES à TRIbord, et les balise CYlindrique ROUGES à BAbord. En [[w:aviron|aviron]], '''T.G.V''' à savoir '''T'''ribord-'''G'''auche-'''Vert''' car le rameur est dos à l'embarcation et donc tribord se situe à sa gauche. ==== Compartimentage ==== Le compartimentage est la méthode employée pour assurer la sécurité d'un navire contre les voies d'eau. Il consiste à diviser l'espace en compartiments étanches en-dessous de la ligne de flottaison. Il résulte de ces nombreux cloisonnements une difficulté à localiser, notamment sur les gros bâtiments, tel ou tel lieu précis (cabine, soute, etc.). Afin de régler cette difficulté se pratique un référencement des locaux selon une numérotation en quatres chiffres/lettres : la tranche (de la proue vers la poupe), le pont (de la surface vers le fond à partir du pont principal 0 situé immédiatement au-dessus de la ligne de flottaison), le rang (sous-section de tranche) et le bord (local dans un rang donné). Ex. : A216 signifie que le local se trouve dans la tranche alpha, au niveau du deuxième pont inférieur (ou faux pont), au premier rang, premier local à bâbord en partant de la ligne médiane (ou de la coursive centrale) du navire. La mémorisation de l'ordre des bords s'effctue avec la phrase mnémotechnique suivante : "j'aime les femmes en slip", le nombre de lettres de ces mots donnant la suite 1-5-3 (impairs sur tribord) 6-2-4 (pairs sur bâbord). ==== Nœuds ==== La phrase « ''Le serpent sort du trou, tourne autour de l'arbre, et rentre dans le trou'' » permet de se rappeler de la méthode pour faire un [[w:nœud de chaise|nœud de chaise]]. === Aviation === Chez les pilotes d’avions utilisant le système [[w:Precision_Approach_Path_Indicator|Vasi]] pour trouver l’altitude correcte à l’atterrissage en [[w:vol à vue|vol à vue]], des panneaux rouges et blancs à côté de la piste leur fournissent de précieuses indications qui ont abouti à cette comptine : :« ''White over white, you're high as a kite'' :''Red over white, you're right'' :''Red over red, you're dead'' » (Blanc sur blanc : trop haut, rouge sur blanc : correct, rouge sur rouge : trop bas). Pour récolter toutes les informations nécessaires pour compléter leur feuille de route, les pilotes aguerris utilisent la phrase : '''''R'''''etranchez '''v'''otre '''d'''érive, '''c'''ela '''v'''ous '''d'''onne '''c'''haque '''m'''esure '''d'''u '''c'''ap '''c'''ompas. Route vraie - X (dérive) / Cap vrai - Déclinaison / Cap magnétique - déviation / Cap compas Pour le décollage : CC PP VV TT (ou 3T) Compas, Conservateur de cap (ou gyro compas), Phares, Pompe, Volets, Verrière, [[w:Transpondeur|Transpondeur]], Top, (Talons au sol). Cela dépend bien sûr du type d'avion. Pour l’observateur au sol et face à l’avion, contrôleur, mécanicien de piste, le rouge est à droite et le vert est à gauche. Très pratique la nuit, on ne voit rien d’autre que les feux. Moyen mnémotechnique : Quand on se sert du vin à boire, on a le "rouge" dans la main droite et le "verre" dans la main gauche. Ou plus facile à retenir : Comme en politique, le rouge est toujours à gauche ! == Vie quotidienne == La vie quotidienne regorge de moyens mnémotechniques plus ou moins utiles. === Droite et Gauche === Se souvenir de sa main habile (droitier ou gaucher) Utiliser les initiales en majuscules (G et D) : l'arrondi est du côté correspondant (à Gauche pour G), (à droite pour D). En anglais, pour Left et Right (Gauche et Droite). On peut faire un L avec la main gauche, avec le pouce et l'index et non avec la main droite. D'où Left=gauche et right=droite. === Mois courts et mois longs === En mettant ses poings fermés côte à côte, les bosses des [[w:phalange|phalange]]s peuvent correspondre aux mois de 31 jours du [[w:calendrier|calendrier]] et les creux entre chacune aux mois de 30 jours ou moins. Et sans compter la jonction entre les mains comme un creux. On peut aussi le faire avec une seule main (c'est mieux pour les enfants, car ça permet de suivre le décompte des mois avec un doigt de l'autre main...) : on commence sur le premier sommet pour janvier, on s'arrête sur le dernier sommet pour juillet et, pour les mois suivants, on repart en arrière en comptant de nouveau le sommet (ou bien, on recommence au sommet initial, pour bien marquer les 2 mois de 31 jours). Attention ! Juillet-Aout ont 31 Jours mais Décembre-Janvier aussi !! === Heure d’été, heure d’hiver === En été on avance d’une heure, car "'''é'''té" et "'''a'''vance" commencent par une voyelle. En été le soleil qui passe à travers les volets nous réveille tôt car on dort une heure en moins. En hiver on recule d’une heure, car "'''h'''iver" et "'''r'''ecule" commencent par une consonne. En hiver on hiberne, donc on dort une heure en plus. Le changement d’heure se faisant en avril (!) et en octobre : * OCTOBRE finit par RE donc on REcule * ''AVRIL commence par AV donc on AVance'' Hélas..... cette information est affichée sur de très nombreux sites.. alors que le changement annoncé en AVRIL.. est en réalité réalisé le dernier dimanche de MARS ! Comme le changement a lieu en MARS et OCTOBRE, et qu'en général on ne peut pas (ou ne doit pas) faire reculer une aiguille sur une montre analogique : * MARS étant plus court (4 lettres), on avance de 1 heure, * OCTOBRE étant plus long (7 lettres), on avance de 23 heures (ou 11 heures pour les montres et horloges analogiques sans date). Pour les anglophones : Spring Forward, Fall Back (Spring étant le Printemps et Fall l'Automne)... === Retrouver de tête le nom du jour de la semaine quelle que soit la date donnée === {{pas clair}} Par convention, on associe les chiffres aux lettres suivantes : <pre> 0 = S, Z 1 = T, D 2 = N, Gn 3 = M 4 = R 5 = L, Y, ill 6 = CH, J, Ge 7 = K, Qu, Gu 8 = F, Ph, V 9 = P, B </pre> ==== N°1 - liens entre jours et lettres : ==== Lundi est le premier jour de la semaine . Donc '''Lundi = 1''' mardi = 2 ... ==== N°2 - liens entre mois et lettres ==== ===== a) correspondances pour année normale ===== : ** Janvier Février Mars... deviennent "'''S'''a'''M''' '''M'''e '''J'''e'''T'''e'''R'''a a'''G'''e'''N'''ou'''iLL'''é '''S'''on '''M'''a'''iLL'''ot" '''S''' = Janvier ; '''M''' = Février ; '''M''' = Mars '''J''' = Avril ; '''T''' = Mai ; '''R''' = Juin '''g'''= Juillet ; '''n'''= Août ; '''L'''= Septembre '''s'''= Octobre ; '''m'''= Novembre ; '''L'''= Décembre ===== b) correspondances pour année bissextile ===== "'''G'''i'''N'''o '''M'''e '''J'''e'''T'''e'''R'''a ..." '''G''' = Janvier ; '''N''' = Février ; etc ===== N°3 - facteur en fonction du siècle ===== ====== a) Avant le 4 octobre 1582, enlever 7 au siècle (''' -7''' ) ====== Année 670 : siècle 6 '''-7''' = 0 Année 1100 : siècle 11 '''-7''' = 4 Et le résultat on le transforme : 4 devient 0 , 3 devient 1 , 5 devient 6 , 2 reste 2 et inversement. Moyen mnémotechnique (suivant la convention) : RuSé MaTou :: 4-0 3-1 NoNNe LouChe :: 2-2 5-6 ====== b) À compter du 4 Octobre 1582 ====== soit le '''4''' - '''10''' - '''1582''' , c'est à dire le jour où le '''R'''oi '''T'''hé'''S'''ée '''T'''é'''L'''é'''PH'''o'''N'''a , on enlève 4 et non 7 , autant de multiple possible : **Année 1800 : siècle 18 - ( '''4'''x4 ) = 2 **Année 2000 : siècle 20 - ( '''4'''x5 ) = 0 La transformation donne 0-6 1-4 2-2 3-0 {| class="wikitable" |- | 0 || 1 || 2 || 3 |- | '''6''' || '''4''' || '''2'''|| '''0''' |- | '''CH'''è... || ...'''r'''e || '''N'''iai... || '''se''' |- | 0-6 || 4-1 || 2-2 || 0-3 |} ==== Calcul pour le 26 septembre 1955 ==== Il y a plusieurs opérations à réaliser en se conformant aux règles citées . **26 Sept 1955 règle 2a :: septembre = L = ''5'' **26+''5'' = 31 règle 3b ** 31-(7x4) = '''''3''''' **55 - (7x4) = 55-28= 27 **27 + (27/4) = 27+6 = 33 **33 - (7x4 ) = 33-28= '''''5''''' ** '''''5 + 3 ''''' =''''' 8''''' comme il y a 7 jours dans la semaine : *''''' 8-7 '''''= '''1''' le 1 correspond à '''lundi''' donc le 26 septembre 1955 était un '''lundi''', toute la journée !!! ==== Sinon pour l'année cours, passée ou à venir, ==== le moyen le plus simple et le plus rapide est de diviser l'année en trimestres . Pour chaque mois, on cherche le quantième du premier dimanche par exemple . On fait une phrase par trimestre et pour trouver la correspondance on rajoute 7 + de 1 à 6 . Exemple, pour 2012, {| class="wikitable" |- ! Janvier !! Février !! Mars |- | '''1''' || '''5''' || '''4''' |- | '''D'''e || '''<nowiki>L'</nowiki>''' || ai'''R''' |} Donc, le premier dimanche de Janvier 2012 est le 1er janvier . Pour aller à mon Rendez vous du 3 je rajoute 2. ** Selon ma convention déjà vue , lundi=1 mardi=2 mercredi=3 jeudi=4 vendredi=5 samedi=6 et dimanche=7 . Alors 2 correspond à mardi donc le 3 Janvier 2012 est mardi pour aller au 18 janvier 2012 , une semaine ayant 7 jours, même sous le règne actuel, je retire autant de semaine complète que possible . Donc 18 - (2x7 ) = 18 - 14 = 4 . Surprise, le 18 janvier 2012 sera un mercredi . Soit parce que j'ai rajouté 3 jours au dimanche, soit parce que j'ai décidé une fois pour toutes que le dimanche est le premier jour de la semaine, donc le mardi le 2ème etc ... ** dans ce cas, dimanche=1 mardi=2 mercredi=4 jeudi=5 vendredi=6 samedi=7 dimanche=8-7=1 C'est selon sa préférence intellectuelle . Je vous laisse continuer pour février et les autres trimestres. {| class="wikitable" |- ! janvier !! février !! mars !! avril !! mai !! juin !! juillet !! aout !! sept !! oct !! nov !! déc |- | 1 || 5 || 4 || 1 || 6 || 3 || 1 || 5 || 2 || 7 || 4 || 2 |- | D || l || r || t || ch || m || d || l || n || k || r || g |- | de || l' || air || tu || chô || me || dans || la || nuit || qui || rè || gne |} === Valeur d'un Euro en [[w:Franc français|Francs français]] === Selon le même principe que pour les décimales de ''π'' : {| border="0" cellpadding="0" cellspacing="1" |align="center"|''Chacun'' |&nbsp; |align="center"|''saura'' |&nbsp; |align="center"|''enfin'' |&nbsp; |align="center"|''convertir'' |&nbsp; |align="center"|''notre'' |&nbsp; |align="center"|''monnaie'' |- !align="center"|6 !align="center"|, !align="center"|5 | !align="center"|5 | !align="center"|9 | !align="center"|5 | !align="center"|7 |} === Morse === Le code morse est facilement mémorisable à l’aide des codes courts et longs remplacés par des syllabes. Le code long (-) remplacé par une syllabe en "O". Le code court (.) remplacé par une des autres voyelles. Ex : A = .- = Au/tO (une syllabe en A pour le . et une syllabe en O pour le -) La liste complète est [[w:Alphabet Morse#Tableau Mn.C3.A9motechnique|Ici]] === Les vins === ==== AOC de la côte de Nuits ==== Un mnémonique permettant de se rappeler des [[wikipedia:AOC|AOC]] communales de la [[wikipedia:Côte de Nuits|Côte de Nuits]], et dans l'ordre géographique en plus, par Paul Brunet, auteur du livre ''Le vin et les vins au restaurant'' : ''Messieurs, faites gaffe, mon chat vous voit noir'' (Marsannay, Fixin, Gevrey-Chambertin, Morey-Saint-Denis, Chambolle-Musigny, Vougeot, Vosne-Romanée, Nuits-Saint-Georges). ==== Nom des bouteilles de vin ==== Ce moyen mnémotechnique permet de mémoriser les principales tailles de [[w:bouteille de vin|bouteilles]] dans l'ordre croissant de contenance : * Car de bon matin je remarquais mal sa banalité naturelle (quart, demi, bouteille, magnum, jéroboam, réhoboam, mathusalem, salmanazar, balthazar, nabuchodonosor). Autre phrase mnémo, plus complète : * PICARD FIT : DE BON MATIN, JE REMARQUE SA BANALITÉ, SA MATIERE SI PAUVRE. Pour se rappeler tous les contenants de vin ou de champagne : * PIccolo, QUARt, FIllette, DEmi-bouteille, Bouteille, MAgnum, Jeroboam, REhoboam, Mathusalem, SAlmanazar, Balthazar, Nabuchodonosor, SAlomon, Melchisédech, Souverain, Primat. === <u>Dresser une table</u> === Pour se souvenir d'où mettre la fourchette et le couteau : Four'''<u>ch</u>'''ette à gau'''<u>ch</u>'''e, couteau à droite. ou encore : A, B, '''C''', '''D''' ... '''C'''outeau à '''D'''roite. E, '''F''', '''G''', H ... '''F'''ourchette à '''G'''auche == Cinéma, Bande dessinée... == === Dupond et Dupont === Pour différencier les deux [[w:Dupond et Dupont|dupondt]] de la bande dessinée [[w:Les Aventures de Tintin et Milou|Les Aventures de Tintin et Milou]], celui à la moustache tombante comme un D est Dupond, celui à la moustache pointue comme les barres du T est Dupont. === Les 7 nains === '''A''' '''J'''ouer '''P'''resque '''S'''eul '''T'''u '''D'''eviens '''G'''rincheux * Atchoum, Joyeux, Prof, Simplet, Timide, Dormeur, Grincheux : les 7 nains dans Blanche Neige... === Les Simpson === Pour différencier les deux sœurs de Marge, on observe les cheveux. Patty n'a pas de raie au centre et Selma a les cheveux découpés en deux blocs par une raie ou on regarde les boucles d'oreilles qui sont différentes Sinon, regarder les boucles d'oreilles de Patty, elles sont triangulaires (P comme Pythagore). == Sport == === Escalade === ''Pour la prochaine longueur je reste en bas, donc je me vache au plus bas.'' <br> :En escalade, permet de savoir sur quel point d'assurage se vacher lors du relais '''réversible''' uniquement. == Voir aussi == === Article connexe === * [[w:Code chiffres-sons|Code chiffres-sons]] === Liens externes === * [https://jeretiens.net -JeRetiens.net- Libre recueil ayant pour objectif de rassembler tous les trucs et astuces mnémotechniques pour retenir et apprendre plus facilement.] * [http://www.finallyover.com/categorie-1079667.html Méthodes thématiques de mémorisation] * [http://www.echolalie.org/wiki/index.php?ListeMnemotechnique Liste mnémotechnique] * [http://trucsmaths.free.fr/Pi.htm#poeme Le nombre pi] * [http://www.francaisfacile.com/exercices/exercice-francais-2/exercice-francais-75628.php francaisfacile.com] === Références === <references /> [[Catégorie:minilivres]] 6x91oztcearztowjycq2ndwmcq453h5 Fonctionnement d'un ordinateur 0 65764 773575 772939 2026-09-29T14:27:50Z Mewtow 31375 /* Liens divers */ 773575 wikitext text/x-wiki {{Page de garde|image=Personal computer, exploded 6.svg|description= Dans ce cours, vous allez apprendre quels sont les composants d'un ordinateur et comment ceux-ci fonctionnent. Ce cours commencera par des choses simples, comme le binaire, pour arriver progressivement jusqu'au fonctionnement des derniers processeurs, en passant par plein de choses passionnantes comme l'assembleur, les mémoires caches, etc. Ce cours est accessible à n'importe qui, sans prérequis, mais se veut cependant assez complet et riche en informations. |avancement=Terminé |cdu= * {{CDU item|6/68/681|681.3/681.31}} |versions= {{version imprimable|page=Fonctionnement d'un ordinateur/Version imprimable 2}} {{version PDF}} }} __NOTOC__ : '''L'auteur du livre tient à remercier vivement Dominus Carnufex et Vayel, qui se sont chargés de la relecture et de la correction orthographique d'une ancienne version de ce cours. Merci à eux pour le travail titanesque qui a été fourni.''' {{/Sommaire}} ==Liens vers ressources externes== ===Sur wikilivres=== * [[Les cartes graphiques|Les cartes graphiques]], un livre du même auteur qui aborde spécifiquement l'architecture des cartes vidéo. * [[Monter_un_PC|Monter un PC]], pour une approche bien plus pratique et utile. * [[Les systèmes d'exploitation|Les systèmes d'exploitation]], un cours qui explique l'interaction entre systèmes d'exploitation et matériel. Le sujet (les systèmes d'exploitation) est si lié au matériel informatique qu'il peut être vu comme un prolongement du présent cours, ou tout du moins comme un très bon complément. * [[Électronique numérique : logique|Électronique numérique : logique]], un cours d'électronique numérique, disponible sur Wikilivre. Un excellent complément pour les premiers chapitres du cours. ===Liens divers=== *[http://bitsavers.informatik.uni-stuttgart.de/ Bitsavers] : archive des documentations techniques de la plupart du matériel ancien. Tout y est, que ce soit les tout premiers ''mainframes'' de la taille d'une pièce d'appartement aux CPU/GPU des années 2000. * Si te d'information sur le jeu d'instruction et les processeurs, PA-RISC : [https://www.openpa.net/ Open PA-RISC]. * [http://users.ece.cmu.edu/~koopman/stack_computers/index.html Stack Computers: the new wave] : un livre sur les architectures à pile. * [https://homes.cs.washington.edu/~levy/capabook/ Capability-Based Computer Systems] : un livre sur les architectures à capacités. * [http://www.analogmuseum.org/english/ Museum of analog computing]. Ce site en anglais parle d'un sujet qui n'a pas été abordé dans ce livre : les calculateurs analogiques. * [https://www.icsa.inf.ed.ac.uk/research/groups/hase/models/ Des simulateurs pour des architectures réelles ou fictives.] {{AutoCat}} [[Catégorie:Informatique]] [[Catégorie:Électronique]] {{Nouveau livre|}} qy2mqcdr7dh3o21bnpb2kg6mb133qpt Fonctionnement d'un ordinateur/Le renommage de registres 0 65844 773616 773235 2026-09-29T20:50:17Z Mewtow 31375 773616 wikitext text/x-wiki Pour améliorer l'exécution dans le désordre, les concepteurs de processeurs ont étudié des méthodes pour éliminer la grosse majorité des dépendances de données lors de l’exécution. Dans ce que j'ai dit précédemment, j'ai évoqué trois types de dépendances de données. Les dépendances RAW (''Read After Write'') sont des dépendances contre lesquelles on ne peut rien faire : ce sont de « vraies » dépendances de données. Elles imposent un certain ordre d’exécution de nos instructions. Mais les dépendances WAW (''write after write'') et WAR (''write after read'') sont de fausses dépendances, nées du fait qu'un emplacement mémoire est réutilisé, pour stocker des données différentes à des instants différents. Bien évidemment, l’imagination débridée des concepteurs de processeur a trouvé une solution pour supprimer ces dépendances : le '''renommage de registres'''. Avant toute chose, précisons que ce chapitre abordera uniquement les techniques compatibles avec les exceptions précises. En clair, seulement les techniques utilisées sur les processeurs modernes. Il existe deux autres techniques de renommage de registre utilisées sur les processeurs sans exceptions précises : l'algorithme de Tomasulo et le ''scoreboarding''. Contrairement à ce que vous avez pu lire ailleurs, il y a une forme de renommage de registre dans le ''scoreboarding'', mais nous verrons cela dans quelques chapitres. Toujours est-il que ces deux techniques historiques étaient utilisées sur d'anciens ordinateurs, qui n'implémentaient pas la prédiction de branchement. Leurs techniques de renommage de registres étaient particulières, aussi nous les verrons dans un chapitre à part. ==Le renommage de registres : généralités== Les dépendances WAR et WAW sont souvent opposées aux dépendances vraies (true dependency), à savoir les dépendances RAW. Les dépendances WAR et WAW viennent du fait qu'un même registre nommé est réutilisé plusieurs fois pour des données différentes. Un même nom de registre identifie une donnée différente à des instants différents du programme, ce qui force à exécuter les instructions qui utilisent ce registre dans l'ordre. D'où le fait que les dépendances WAR et WAW sont souvent appelées des dépendances de nom (''naming dependency''). Si on change l'ordre de deux instructions ayant une dépendance de données WAW ou WAR, on peut se retrouver dans une situation où les deux instructions veulent stocker des données différentes en même temps dans le même registre, ce qui n'est pas possible. Mais elles n'existeraient pas si on utilisait un registre pour chaque donnée, qui est écrit une fois, lu une ou plusieurs fois, mais jamais écrasé. Un même nom de registre correspond alors à une donnée. Une solution simple vient alors à l'esprit : conserver chaque donnée dans son propre registre et choisir le registre adéquat à l'utilisation. Un registre architectural correspond alors à plusieurs registres, chacun contenant une donnée bien précise. L'idée est qu'au lieu d'avoir un registre qui contient des données différentes à des instants différents, on a autant de registres que de données, ce qui améliore les possibilités de réorganisation des instructions. Il faut ainsi faire la distinction entre : * '''registres architecturaux''', définis par le jeu d'instructions ; * '''registres physiques''', physiquement présents dans l'ordinateur ; * '''registres virtuels''' utilisés pour le renommage de registre mais invisibles pour le programmeur. Les registres physiques regroupent l'ensemble des registres, à savoir les registres architecturaux et virtuels. Pour illustrer l'idée, prenons l'exemple suivant, où un registre architectural nommé R6 est utilisé pour stocker trois données consécutives. Il mémorise d'abord le nombre 255, puis le nombre 2567763, puis zéro. On suppose que ces trois valeurs sont indépendantes, dans le sens où elles sont utilisées par des instructions sans dépendances RAW. En théorie, on pourrait exécuter ces instructions séparément, mais ce n'est pas possible. Le fait est que l'on doit d'abord faire les calculs avec l'opérande 255, puis ceux avec l'opérande 2567763, puis ceux avec l'opérande zéro. La raison est que pour que le calcul démarre, il faut que l'opérande soit disponible. Et l’usage d'un seul registre pour stocker des opérandes différentes à des temps différents limite les possibilités d’exécution en parallèle. Avec le renommage de registres, ces trois données sont enregistrées dans des registres physiques séparés, dès qu'elles sont disponibles. Le processeur garde évidemment trace du fait que ces trois registres physiques correspondent au registre architectural R6. Si les trois valeurs n'ont pas de dépendances entre elles, les instructions liées peuvent être exécutées dans le désordre et s’exécuter en même temps. Ce qui est le cas dans le schéma suivant, où certaines instructions sont exécutées en avance, ce qui réserve les registres physiques en avance. [[File:Renommage de registres - principe.png|centre|vignette|upright=2|Exemple où un registre architectural est utilisé pour contenir trois données successives.]] : Pour les connaisseurs, le renommage de registres réécrit le programme exécuté dans une représentation appelée SSA, utilisée par les compilateurs lors de la compilation. Et cette réécriture se fait un peu de la même manière avec un compilateur. Là où le compilateur change le nom des variables pour passer en forme SSA, le processeur change les noms de registres pour obtenir de l'assembleur SSA interne au processeur. ===La durée de vie des registres virtuels=== La plupart des processeurs disposent d'un banc de registre physique unique, qui regroupe registres physiques et virtuels. Mais il existe quelques processeurs qui font autrement. Ils ont un banc de registre pour les registres architecturaux, et les registres virtuels sont placés ailleurs dans le processeur, typiquement dans le tampon de ré-ordonnancement (ROB) ou le ''scheduler''. Pour simplifier, considérons qu'ils sont dans un banc de registre spécialisé qui regroupe les registres virtuels. C'est un peu faux en soi, mais faisons comme si. Dans le reste de cette section, nous allons partir du principe que les registres virtuels et architecturaux sont séparés pour simplifier les explications, nous verrons les autres formes de renommage de registre plus tard. Les registres virtuels ont une certaine durée de vie. On veut dire par là qu'une donnée écrite dans un registre virtuel y reste durant un certain temps, mais pas indéfiniment. Un registre virtuel est utilisé par une instruction en cours d'exécution dans le pipeline. Il nait lors du renommage de registre et meurt une fois l'instruction terminée. En clair, un registre virtuel dure durant toutes les étapes du pipeline qui suivent le renommage de registres. Une fois que l'instruction quitte le pipeline, qu'elle sort du ROB, le registre virtuel est inutile et doit laisser la place au registre architectural non-renommé. Le résultat de l'instruction doit être transféré dans le registre architectural adéquat, le registre de destination de l'instruction. Si les registres virtuels et architecturaux sont séparés, il faut copier la donnée des registres virtuels vers les registres architecturaux. Utiliser un banc de registre unique résout le problème, mais n'allons pas trop vite, nous verrons cela en détail dans la suite. Toujours est-il qu'un registre virtuel est libéré quand l'instruction associée quitte le ROB. Il est théoriquement possible de libérer un registre virtuel en avance, si on est certain qu'aucune instruction n'ira lire ce registre. Pour cela, le mieux est d'attribuer un compteur de lectures pour chaque registre. À noter que pour maintenir des exceptions précises, on est obligé d'attendre que la dernière instruction qui lit le registre ait validé. Le jeu n'en vaut clairement pas la chandelle. Le seul intérêt d'une telle optimisation est économiser des registres virtuels, d'avoir un banc de registres virtuels plus petits, mais cela se fait au prix de l'ajout de circuits qui consomment tout autant, si ce n'est plus de circuits, pour un résultat en termes de performances limité, voire nul. Après avoir vu la mort des registres virtuels, voyons leur naissance. Le renommage de registre a lieu après le décodage, donc juste avant le passage dans le ''scoreboard'', la fenêtre d’instruction, la file d'instruction ou toute autre structure dédiée à l'émission. En clair : les registres virtuels sont attribués juste avant émission et ne sont utiles qu'après. Les instructions susceptibles d'utiliser un registre virtuel sont donc les instructions émises ou prêtes à l'être, mais pas encore terminées. Les instructions en question sont soit en attente dans la fenêtre d’instruction, soit en cours d'exécution dans le chemin de données, soit en attente dans le ROB. Ces dernières attendent que les instructions précédentes se terminent. Il faut noter que toutes les instructions émises ou en passe de l'être ont été ajoutées dans le ROB juste après le renommage. Même les instructions en attente dans la fenêtre d'instruction sont dans le ROB. Pour résumer, le ROB garde la trace de ces instructions prêtes à être émises ou déjà émises. ===Le nombre idéal de registres virtuels=== Mine de rien, le contenu de la section précédente nous donne une seconde borne maximale sur le nombre de registres virtuels utiles. Supposons que chaque instruction fournit un résultat, stocké dans un registre virtuel rien que pour lui. Le nombre maximal d'instructions chargées dans le pipeline après émission est égal au nombre d'entrée dans le ROB. Il peut y avoir moins d'instructions, ce qui fait que des entrées du ROB sont inutilisées, mais supposons que nous soyons dans le meilleur des cas. Dans ce cas, on doit avoir un registre virtuel par instruction, ce qui fait au maximum un registre virtuel par entrée du ROB. Rien ne sert d'avoir plus de registres virtuels que d'entrées dans le ROB, il n'y aura pas assez d’instructions dans le pipeline pour tous les utiliser. Après avoir vu une borne maximale, voyons une limite minimale. Non pas qu'il faille absolument plus de registres virtuels que cette limite, simplement qu'il est préférable d'en avoir que cette limite. Partons du principe que les instructions pouvant utiliser un registre virtuel sont celles qui sont soit déjà émises, soit en attente de l'être. Si on néglige les instructions en attente dans le ROB, alors les instructions émises sont dans les ALUs. Le nombre d'instruction est donc égal à la somme de : la taille du ''scheduler'' (instructions en attente), du nombre d'unités de calcul (instruction en cours d'exécution), unités d'accès mémoire inclues. Mieux vaut ne pas passer sous la somme taille du ''scheduler'' + nombre d'unités de calcul. Un bon compromis est d'avoir un nombre de registre virtuel compris entre ces deux bornes. Le nombre réel de registre virtuels est très souvent inférieur au nombre d'entrées du ROB, car toutes les instructions ne fournissent pas de résultat à enregistrer dans les registres. C'est le cas pour les instructions de branchement, par exemple, ou les écritures en mémoire RAM. Par contre, il vaut mieux avoir plus de registres que d'entrées dans le ''scheduler''. La majorité es processeurs respectent ces deux limites basse et hautes, avec un nombre de registres réels entre les deux. Les quelques rares exceptions étaient des processeurs qui implémentaient le renommage de registre pour la première fois, et où ce genre de détails n'étaient pas bien compris. Par exemple, on peut citer le PowerPC 604, qui avait 20 registres virtuels, alors que le ROB avait seulement 16 entrées. Les 4 registres virtuels en trop n'étaient pas utilisés. Le processeur qui a immédiatement suivi, le PowerPC 604, n'a pas fait cette erreur et a réduit le nombre de registres virtuels à seulement 16. Un autre exemple est le MIPS R10000, avec son ROB à 32 entrées, son ''scheduler'' a 48 entrées et ses 64 registres virtuels. Le processeur suivant, le R12000, corrigea partiellement le problème en augmentant le ROB à 48 entrées, ce qui était insuffisant, mais bienvenu. ===Le renommage de registre total et partiel=== De nombreux processeurs ont des registres architecturaux séparés pour les nombres flottants et entiers. Dans ce cas, leur renommage est indépendant : les registres flottants ont leur unité de renommage dédiée, séparée de celle pour les registres entiers. A ce propos, quelques rares processeurs ne renomment que que les registres flottants, ou que les registres entiers ! Pour donner un exemple, le processeur Nx586 ne renommait que les registres entiers, pour les instructions entières. Un autre exemple est celui de l'IBM System/360 Model 91, sur lequel les registres flottants étaient renommés, mais pas les registres entiers. Sur les CPU x86, lorsque le renommage de registre a été introduit, il ne concernait que les registres flottants. Ce choix s'explique par l'organisation en pile de registres liée au jeu d'instruction x87. Elle limitait grandement le parallélisme d'instruction, le renommage permettait de fortement limiter la casse. [[File:Zen microarchitecture.svg|centre|vignette|upright=2|Microarchitecture Zen 1 des CPU d'AMD.]] Le renommage de registre peut être total ou partiel. Avec le renommage total, toutes les instructions voient leurs registres renommés. Il s'agit de la méthode la plus utilisée à ce jour, par simplicité de conception. Mais des processeurs assez anciens utilisaient un renommage partiel, qui ne s’appliquaient qu'à certains types d'instruction bien précis. Par exemple, on pourrait citer les processeurs Power1, Power2 et PowerPC 601. Sur le premier, seuls les registres flottants étaient renommés, et seulement pour les instructions de lecture flottante. La raison est que le processeur n'a qu'une seule FPU, ce qui limite l'efficacité de l'exécution dans le désordre sur celle-ci, et fait que renommer les registres ne sert à rien. Le processeur Power 2 dispose lui de plusieurs FPU et le renommage de registres touche aussi les instructions flottantes arithmétiques, c'est un renommage total. Les processeur qui utilisaient le renommage partiel étaient des processeurs assez anciens, qui faisaient avec un budget en transistors limité. De plus, la technique n'était pas très bien maitrisée, et était encore balbutiante. La technique a pourtant été proposée dès 1970 dans divers articles académiques, et raffinée pendant les années 70. Mais le budget en transistors du renommage de registre a fait qu'elle n'a pas été utilisée avant que la loi de Moore fasse son œuvre. ==Les différentes implémentations du renommage de registres== Il existe plusieurs manières différentes d'implémenter le renommage de registre, que nous allons voir dans cette section. Mais avant toute chose, parlons du réseau de contournement. Pour simplifier les explications, appelons ''instruction productrice'' l'instruction qui fournit un résultat, et instruction consommatrice celle qui l'utilise comme opérande. Si une instruction consommatrice est chargée dans le pipeline quelques cycles après l'instruction productrice, les deux sont dans le pipeline en même temps. Dans ce cas, on pourrait penser que c'est le réseau de contournement qui gérerait le transfert du résultat de l'instruction productrice à l’instruction consommatrice. Et effectivement, c'est souvent le cas. Mais les registres virtuels sont pris en compte dans le système de contournement. Si le résultat est écrit dans un registre virtuel, il peut aussi être lu dans ce registre virtuel. Lire un résultat dans les registres virtuels permet d'implémenter une forme de contournement. Tout cela pour dire qu'il y a un lien entre contournement et renommage de registres, les deux doivent être conçu de manière à communiquer entre eux. Typiquement, il y a toujours un réseau de contournement pour connecter la sortie d'une ALU aux entrées des autres. Ce dernier gère le cas où un résultat d’instruction est réutilisé comme opérande au cycle suivant. Mais pour réutiliser un résultat deux cycles après ou plus tard, c'est le système de renommage de registres qui s'en charge. Ceci étant dit, nous allons étudier les implémentations principales du renommage de registre. Pour simplifier, il existe deux manières d'implémenter le renommage de registre. La première utilise deux bancs de registres : un pour les registres architecturaux, un autre pour les registres virtuels. Une autre implémentation regroupe registres virtuels et architecturaux dans un seul banc de registre. Mais d'autres implémentations font totalement autrement, en réutilisant les stations de réservation ou le tampon de ré-ordonnancement. Dans ce qui suit, nous allons nous concentrer sur les principales : le renommage à banc de registre physique, le renommage dans le ROB, le renommage à registres virtuels. Nous allons laisser de côté le renommage dans les stations de réservation pour une raison très simple : elle n'est pas compatible avec les exceptions précises. Nous la verrons dans un chapitre à part, portant sur le ''scoreboarding'' et l'algorithme de Tomasulo. ===Le renommage à banc de registres physiques=== Les processeurs modernes utilisent un seul banc de registres pour les registres architecturaux et virtuels, appelé '''banc de registres physiques''' (''physical register file''). Le tampon de réordonnancement et le ''scheduler'' contiennent des numéros de registres virtuels, des pointeurs vers les registres. Il y a toujours un réseau de contournement pour connecter la sortie d'une ALU aux entrées des autres, qui gère le cas où la sortie de l'ALU est utilisé comme opérande au cycle suivant. Mais pour réutiliser un résultat deux cycles après ou plus tard, c'est le banc de registres physiques qui s'en charge. Les opérandes viennent donc soit du banc de registres physique, soit du réseau de contournement. [[File:Renommage à banc de registres physiques.png|centre|vignette|upright=2|Renommage à banc de registres physiques.]] Avec ce système, un registre physique peut être dans quatre états. * Le premier état est celui d'un ''registre disponible'', près à servir de registre de destination. Par disponible, on veut dire que ce registre peut être réservé par l'unité de renommage, mais qu'il n'a pas encore été réservé. Ce n'est ni un registre virtuel, ni un registre architectural, juste un registre inutilisé. * Le second état est l'''état réservé'', celui d'un registre virtuel qui attend qu'une instruction écrive son résultat dedans. L'état réservé réserve un registre en écriture, mais interdit les lectures dedans. * Le troisième état est celui d'un registre virtuel dans lequel une instruction a écrit son résultat, mais l'instruction n'a pas encore quitté le ROB. Le registre est alors appelé un ''registre écrit''. * Enfin, le quatrième est celui d'un ''registre architectural'', qui contient une donnée valide, dans le sens où il n'est associé à aucune instruction dans le ROB. Un registre passe normalement par ces quatre états dans l'ordre disponible, virtuel réservé, virtuel écrit, architectural. Une fois que l'instruction attribuée quitte le ROB, le registre virtuel devient un registre architectural. Cependant, cela suppose que l'instruction quitte le ROB normalement, ce qui n'est pas le cas suite à une mauvaise prédiction de branchement ou autre. Dans ce cas, il repasse immédiatement à l'état disponible. L'unité de renommage des registre mémorise l'état de chaque registre pour savoir dans quel état il est. Avec ce système, les données ne sont pas déplacées, ce qui a un avantage en termes de performance, de consommation énergétique et de simplification des circuits du processeur. Une fois enregistrées dans un registre, les données ne se déplacent plus. Avec un banc de registre virtuel séparé, elles sont recopiées d'un banc de registre virtuel vers un banc de registre architectural. Et les autres techniques que nous allons voir ont le même problème. Un autre avantage est que les opérandes proviennent toutes du même endroit : le banc de registre unique. Avec un banc de registre séparés, les opérandes peuvent provenir soit des registres architecturaux, soit des registres virtuels. Les opérandes peuvent donc provenir du banc de registre architectural, mais aussi du banc de registre renommés. La conséquence est que la gestion des interconnexions est beaucoup plus compliquée, notamment quand on veut implémenter le contournement. Pas de problèmes de ce genre avec un banc de registre unique. ===Le renommage dans le tampon de réordonnancement=== Il est possible de faire le renommage dans le tampon de réordonnancement (ROB, pour ''ReOrder Buffer'')). Cela veut dire que les résultats des instructions sont mémorisés dans le tampon de réordonnancement. Les entrées du ROB se voient ajouter un champ pour mémoriser le résultat d'une instruction, et ce champ sert de registre virtuel. Les entrées du ROB deviennent ainsi adressables, elle ont un numéro, qui sert de numéro/nom de registre virtuel. Avec cette technique, les registres architecturaux sont séparés des registres virtuels inclus dans le ROB. Les registres architecturaux sont regroupés dans un banc de registres spécialisé, appelé le '''''retirement register file'''''. Le ''scheduler'' mémorise soit un nom de registre architectural, soit l'adresse de l'entrée du ROB qui contient le résultat voulu. Quand une instruction a tous ses opérandes de prêts, ceux-ci sont lus depuis le ROB ou les registres architecturaux. Pour cela, le ROB mémorise l'état de chaque entrée, de chaque registre virtuel : vide, réservée pour un résultat, écrite avec un résultat. [[File:Renommage dans le tampon de réordonnancement.png|centre|vignette|upright=2|Renommage dans le tampon de réordonnancement.]] Un défaut est que cela complexifie l'implémentation des interconnexions par rapport à un banc de registre physique. Il y a toujours un réseau de contournement pour réutiliser un résultat un cycle plus tard. Mais pour réutiliser un résultat deux cycles après ou plus tard, c'est le ROB qui s'en charge. Les opérandes peuvent être lues depuis trois sources : le ROB, le banc de registre architectural, et le réseau de contournement. Soit une source de plus qu'avec la technique précédente, ce qui complexifie les multiplexeurs de contournement. Et cela a un effet sur la latence des opérations, le temps de traversée de ces multiplexeurs n'est pas gratuit, sans compter le temps mis pour les signaux de commande pour les configurer. Le renommage de registre est aussi plus compliqué. Au lieu de simplement remplacer un numéro de registre architectural par un numéro de registre physique, on doit faire la différence entre numéro de registre et adresse dans le ROB, pour savoir où lire les opérandes. Sans quoi ne sait pas configurer les multiplexeurs et choisir la bonne source pour les opérandes. Un autre défaut est que les registres virtuels doivent être copiés dans les registres architecturaux quand une instruction quitte le ROB. La copie se fait ici du ROB vers le banc de registre architectural. Et copier la donnée a un cout en énergie que l'usage d'un banc de registre unique n'a pas. Un dernier défaut est que le nombre de registres virtuel est égal au nombre d'entrées dans le ROB. Or, on a vu plus haut que c'est un peu du gâchis, car beaucoup d'instructions ne produisent aucun résultat. Le hardware ajouté pour les entrées est donc sous-utilisé, il ne sert que si l'instruction fournit un résultat, mais ne sert à rien sinon. ===Le renommage avec un tampon de renommage=== Le dernier défaut évoqué dit que beaucoup d'entrées du ROB sont inutilisées et que les registres virtuels associés sont gâchés. Pour éviter cela, il est possible de sortir les résultats d'instruction du ROB et de les placer dans une mémoire FIFO complémentaire du ROB, appelée le '''tampon de renommage'''. Pour le dire autrement, le ROB amélioré est scindé en deux, avec le ROB proprement dit d'un côté, et un pseudo-ROB pour le renommage de registres et le contournement. Pour information, cette technique de renommage était utilisée dans d'anciens processeurs commerciaux, comme les Pentium Pro, le Pentium II, ou encore le Pentium III, ainsi que dans le Core 2 Duo. La technique est souvent expliquée en décrivant le tampon de renommage comme un banc de registre séparé pour les registres virtuels, appelé le '''banc de registres renommés''' (''rename register file''). Il est séparé du banc de registres architecturaux, avec lequel il communique. La raison à cela est que le tampon de renommage est adressable alors que le ROB ne l'est pas. Il faut dire que le tampon de renommage a tout d'un banc de registre : il contient les registres virtuels et seulement ceux-ci, on peut l'adresser, lire des opérandes dedans, écrire des résultats dedans, etc. Par contre, il y a une différence avec un banc de registre normal : il est traité comme une mémoire FIFO. Nous avons déjà vu comment implémenter une FIFO avec un banc de registre et quelques registres, aussi je ne fais pas de rappels sur ce point. S'il s'agissait d'un véritable banc de registre isolé, sans rien de plus, le ROB et le ''scheduler'' contiendraient des numéros de registres virtuels, qui adressent directement le banc de registre renommé. Une telle implémentation est possible, mais aucun processeur commercial n'a utilisé une telle implémentation. À la place, le banc de registre est en réalité une mémoire FIFO, dont les entrées sont adressables, avec de plus un système de cache utilisé pour faire la correspondance entre nom de registre architectural et nom de registre virtuel. Nous détaillerons ce dernier point dans la section qui explique comment fonctionne l'unité de renommage. Une fois que l'instruction attribuée quitte le ROB, le registre virtuel est libéré, à savoir qu'il repasse en état disponible. C'est à ce moment qu'à lieu la copie de la donnée dans le registre architectural adéquat. Il faut noter que le registre virtuel n'est pas effacé, il contient toujours l'ancienne donnée. Mais ce n'est pas un problème. S'il est réservé par une instruction, elle écrira dedans, ce qui écrasera cette donnée. Et de manière générale, il est impossible de lire cette donnée, que ce soit si le registre est disponible ou réservé. [[File:Renommage à banc de registres renommés.png|centre|vignette|upright=2|Renommage à banc de registres renommés.]] La technique partage tous les défauts du renommage dans le ROB. Le réseau de contournement est plus compliqué car les opérandes peuvent venir de trois sources : les deux bancs de registres et le réseau de contournement. De plus, les registres virtuels doivent être copiés dans les registres architecturaux, avec tout ce que cela implique. Déjà, déplacer des données implique un cout en énergie et en consommation d'électricité, qu'il vaut mieux éviter. De plus, il faut ajouter un port de lecture sur le banc de registre renommés, pour copier un registre sans nuire aux performances. Le banc de registres physiques n'a pas à être modifié : le port d'écriture existant suffit pour la copie, vu qu'on n'écrit dedans que pour copier des résultats d'instructions validées/terminées. Par contre, le cout en transistors est plus faible qu'avec le renommage dans le ROB, vu que le banc de registre a moins de registres virtuels que le ROB. La technique n'impose pas d'avoir autant de registres virtuels que d'entrées dans le ROB, ce qui permet d'en réduire le nombre. Par contre, comparé à l'usage d'un banc de registres unique, le cout en transistors est plus élevé. La différence se fait surtout au niveau des ports de lecture/écriture du banc de registres. La raison est que l'on doit ajouter un port de lecture pour copier les résultats dans les registres architecturaux. Du moins, dans le cas le plus simple. C'est le cas sur un processeur qui permet de compléter l'exécution d'une instruction par cycle. Mais certains processeurs peuvent terminer l'exécution de plusieurs instructions par cycle. C'est notamment le cas des processeurs dits superscalaires, qui sont capables de charger, exécuter et terminer plusieurs instructions par cycle. Ils auront droit à leur chapitre dédié, mais passons. Toujours est-il que si plusieurs instructions peuvent se terminer en même temps, il faut ajouter autant de ports de lecture sur le banc de registre pour copier leurs résultats. ===Le renommage physique-virtuel=== Les méthodes mentionnées au-dessus ont un léger problème : beaucoup de registres physiques sont gâchés, car attribués à une instruction dès l'étage de renommage et libérés lorsque on est certain qu'aucune instruction ne lira le registre physique attribué. Et parfois, les registres sont alloués trop tôt, alors qu'ils auraient pu rester libres durant encore quelques cycles. C'est notamment le cas quand l'instruction renommée attend un opérande dans le ''scheduler'', ou quand le résultat est en cours de calcul dans l'unité de calcul. Ces situations ont toutes la même origine : le renommage a lieu tôt dans le pipeline, pour garder les dépendances entre instructions. Mais dans les faits, rien n'oblige à utiliser les registres architecturaux pour conserver les dépendances. On peut tout simplement attribuer un tag à chaque résultat d'instruction, tag qui ne correspond pas à un registre architectural. Et ce tag sera alloué à un registre architectural le plus tard possible, quand l'instruction fournira son résultat. Ce genre de méthodes a été formalisée avec ce qu'on appelle la technique du '''banc de registres physiques-virtuels''' (physical-virtual register file). Cette méthode demande d'ajouter une seconde table de correspondance, qui fait le lien entre le tag et le registre physique. De plus, la table d’alias de registres doit être modifiée : elle ne doit pas seulement faire la correspondance entre le nom de registre et le tag, mais aussi avec le registre physique s'il est déjà attribué. Ainsi, lors du renommage en sortie du décodeur, on peut renommer l'instruction avec les registres physiques si ceux-ci sont connus lors du renommage, et renommer avec des tags dans le cas contraire. Il faut noter que cette méthode a un léger problème : quand une instruction termine et que le résultat doit se voir attribuer un tag, il se peut parfaitement qu'il n'y ait plus de registre physique de libre. Les solutions pour régler ce problème sont assez complexes, aussi je n'en parlerai pas ici. ==L’unité de renommage== Pour commencer, sachez qu'il existe deux méthodes pour implémenter l'unité de renommage. La première utilise une unité à part, séparées, qui contient de nombreuses mémoires caches/FIFO pour stocker des informations nécessaires pour le renommage de registres. La seconde mémorise les informations de renommage dans le ROB ou le tampon de renommage, voir ailleurs. Les deux types d'unités de renommage sont assez différentes. Pour les désigner, je vais parler d''''implémentation par ''tag''''' et d''''implémentation associative'''. De plus, les deux types d'unités ne sont pas utilisées sur les mêmes implémentations. Par exemple, avec un banc de registre physique, il est naturel d'utiliser une implémentation par ''tag'', l'autre implémentation n'est pas pratique. Aussi, tous les processeurs avec un banc de registre physique utilisent une unité de renommage pat ''tag''. Mais pour le renommage dans le ROB, c'est l'inverse : les deux implémentations sont possibles, mais il est préférable d'utiliser une implémentation associative. Pour simplifier les explications, je vais commencer par décrire le premier type, avec un banc de registre physique. {|class="wikitable" |- ! ! Implémentation par ''tag'' ! Implémentation associative |- ! Banc de registre physique | Seule implémentation possible | |- ! Renommage dans le ROB | Possible, certains processeurs utilisent la technique | Possible, certains processeurs utilisent la technique |- ! Renommage dans un tampon de renommage | Possible, tous les processeurs utilisent la technique | Possible, aucun processeur connu |} ===Les unités de renommage par ''tag''=== Les registres architecturaux sont identifiés par des noms de registre, tout comme les registres physiques. Les noms de registre des registres physiques sont appelés des '''tags'''. Les registres physiques sont bien plus nombreux que les registres architecturaux, sans quoi le renommage de registre n'a aucun intérêt. La conséquence est que les numéros de registres physiques sont plus grands que les numéros de registres architecturaux. Le renommage de registres remplace les noms/numéros de registres architecturaux par des numéros de registres physiques, par des ''tags''. D'où le terme de ''renommage'' de registre. Ce remplacement est effectué dans un étage supplémentaire du pipeline, intercalé entre le décodage et l'émission. [[File:Renommage de registres.png|centre|vignette|upright=2|Renommage de registres.]] Le remplacement se fait cependant différemment pour le registre de destination et les registres d'opérandes. Le registre de destination est associé à un registre virtuel disponible. L'allocation du registre de destination prend un registre disponible et le place en état réservé. Une nouvelle correspondance entre registre architectural et virtuel est alors crée. Mais pour les opérandes, c'est autre chose. Les opérandes sont soit dans un registre architectural, soit dans un registre virtuel en état écrit. Les noms de registres architecturaux pour les opérandes doivent être remplacé par le nom de registre adéquat, déjà attribué. Une sacrée différence : on attribue un registre virtuel pour le résultat, les opérandes ont déjà un registre virtuel attribué. Un autre point est que l'unité de renommage ne fait pas que modifier les registres opérande/de destination. Elle gère aussi la disponibilité des opérandes. Plus haut, on a dit qu'un registre virtuel pouvait être dans quatre états. Soit il est disponible, soit il est réservé, soit il est écrit, soit la donnée est dans un registre architectural. L'unité de renommage est au courant de l'état de chaque registre. Les quatre états possibles sont utilisés pour diverses raisons. Et il y a deux manières pour mémoriser la correspondance entre un registre physique et un registre architectural. La première est d'utiliser un circuit à part, qui fait partie de l'unité de renommage, l'autre est d'intégrer les correspondances dans le ROB ou toute autre structure dédiée. Pr exemple, on peut ajouter la correspondance dans le ROB, dans le ''scheduler'', éventuellement dans le banc de registres renommés ! Dans ce qui suit, nous allons parler du cas où on utilise une mémoire à part, partie intégrante de l'unité de renommage de registre. Nous verrons l'intégration dans le ROB après, de même que la relation avec les quatre techniques précédentes. ===Renommer le registre de destination : la liste de disponibilité=== Renommer un registre de destination revient à lui attribuer un registre virtuel inutilisé. Pour cela, certaines techniques de renommage de registres mémorisent la liste des registres vides/disponibles dans une petite mémoire : la '''liste de disponibilités''' (''free list''). L'implémentation de la liste de disponibilité varie grandement d'un processeur à l'autre. Avec certaines méthodes de renommage de registre, qui impliquent un ROB, on peut même s'en passer totalement. Dans sa version la plus simple, elle contient un bit pour chaque registre, qui indique s'il est disponible ou non. Le bit en question est mis à jour quand une instruction entre/quitte le tampon de réordonnancement avec ce registre comme opérande. Lorsqu'un registre est attribué, il quitte la liste de disponibilités. Lorsque son instruction quitte le ROB, le bit de disponibilité est mis à jour. Une version plus évoluée utilise une mémoire FIFO qui contient des noms de registres. Le renommage du registre de destination utilise cette FIFO pour sortir le numéro de registre virtuel adéquat. Dans la suite, nous partirons du principe que c'est cette méthode qui est utilisée. Il faut noter que si le renommage est fait dans le ROB, la liste de disponibilité est inutile. La raison est que le ROB est déjà une mémoire FIFO, comme la liste de disponibilité. De plus, les registres virtuels sont dans le ROB. Attribuer un registre virtuel consiste simplement à mobiliser une entrée vide du ROB, en enfilant l'instruction dedans. Le ROB sait quelle est la prochaine entrée à allouer à une instruction émise, du fait de son caractère FIFO. ===La table de correspondances de registres=== Le renommage du registre de destination attribue un registre virtuel pour un résultat d'instruction. Reste qu'il faut maintenir cette attribution tant que l'instruction ne s'est pas terminée. Pendant toute la durée de vie de l'instruction, il faut se souvenir que tel registre virtuel correspond à tel résultat d'instruction, mais aussi à tel registre architectural. En effet, les instructions suivantes vont lire ce résultat pour l'utiliser comme opérande. Elle encoderont ce résultat/opérande avec le registre architectural censé contenir l'opérande. Le renommage de registre devra alors remplacer les registres opérande par le registre virtuel adéquat, qui contient l'opérande. Le renommage des registres opérande est le rôle de la '''table d’alias de registres''' (''register alias table''), une mémoire qui contient le registre virtuel associé à chaque registre architectural. Elle mémorise précisément une table de correspondance entre registre architectural et registre virtuel/physique. La table d'alias contient une correspondance par registre architectural, qui change au gré du renommage des instruction. De plus, elle contient un bit qui indique si le registre a été renommé ou non. S'il n'a pas été renommé, alors l'opérande est disponible dans les registres architecturaux, pas dans un registre virtuel. C'est très utile sur les processeurs avec un banc de registre séparés pour les registres architecturaux. Cela permet de savoir où lire les opérandes. La correspondance en question est mise à jour quand une instruction est émise, et quand elle termine. Premièrement, elle est mise à jour à chaque fois qu'un registre de destination est renommé. En clair, la table d’alias de registres est mise à jour à chaque lecture dans la table de disponibilité. Le registre virtuel choisi dans la liste de disponibilités est attribué au registre architectural de destination du résultat. Il suffira de réutiliser cette correspondance par la suite. Deuxièmement, elle est mise à jour quand une instruction termine, quand elle quitte le ROB. Le ROB envoie alors le numéro du registre virtuel qui contenait le résultat enregistré dans les registres architecturaux. Le numéro est alors enregistré dans la table de disponibilité. De plus, la correspondance associée dans la table d'alias est effacée. [[File:Renommage de registres - circuits.png|centre|vignette|upright=2|Unité de renommage de registres.]] Il existe deux façons pour implémenter la table d'alias. La plus ancienne consiste à utiliser une mémoire associative dont le tag contient le nom du registre architectural et la donnée le nom du registre physique. Sur les processeurs plus récents, on utilise une mémoire RAM, dont les adresses correspondent aux noms de registres architecturaux, et dont le contenu d'une adresse correspond au nom du registre physique associé. On n'a alors qu'une seule correspondance entre registre physique et registre architectural, mais cela ne pose pas de problème si on renomme les instructions dans l'ordre d'émission (ce qui est toujours fait). Notons que la table l'alias doit avoir deux ports de lecture : un pour chaque opérande. Et cela vaut peu importe son implémentation : le cache comme la RAM doivent avoir deux ports. ==L'interaction entre renommage de registres et autres optimisations== L'unité de renommage de registre ne fait pas que du renommage de registre, mais joue aussi un rôle dans l'exécution dans le désordre, et prend en charge des rôles annexes à son rôle principal. Par exemple, elle est impliquée pour corriger les mauvaises prédiction de branchement, les exceptions matérielle ou toute situation qui demande de vider le pipeline. En dehors de ces situations, un registre passe normalement par ces quatre état dans l'ordre disponible, réservé, écrit, architectural. Mais ce n'est pas le cas lors d'une mauvaise prédiction de branchement ou autre. Dans ce cas, tous les registres passent immédiatement à l'état disponible, sauf les registres architecturaux. ===La récupération après une prédiction invalide=== Quand une exception ou une mauvaise prédiction de branchement a lieu, les registres virtuels contiennent des données potentiellement invalides, contrairement aux registres architecturaux. En cas de mauvaise prédiction de branchement, la table d’alias de registres est partiellement vidée. Par vidée, on veut dire qu'on élimine les correspondances avec les registres virtuels invalidés. De plus, on doit remettre la table d’alias de registres et la table de disponibilités dans l'état antérieur au chargement de l'instruction qui a déclenché la mauvaise prédiction de branchement ou l'exception matérielle. Et cela peut se faire de différentes manières. La première solution s'applique au renommage dans le ROB. Il suffit de stocker dans le tampon de réordonnancement ce qui a été modifié dans l'unité de renommage de registres par l'instruction correspondante. Ainsi, lorsqu'une instruction sera prête à valider, et qu'une exception ou mauvaise prédiction de branchement aura eu lieu, les modifications effectuées dans l'unité de renommage de registres seront annulées les unes après les autres. Une autre solution consiste à garder un historique des changements fait dans la table d'alias. Lorsqu'une mauvais prédiction est détectée, le processeur traverse l'historique et annule les changements faits un par un. Le tout est assez lent, vu que la traversée se fait un renommage à la fois. Une optimisation utilise une copie valide de la table d’alias de registres dans une mémoire à part, pour la restaurer au besoin. Si jamais le processeur détecte un branchement, la table d’alias de registres est sauvegardée dans une mémoire intégrée au processeur. On peut utiliser plusieurs mémoires de sauvegarde de ce type, pour gérer une succession de branchements. ===La gestion des opérandes disponibles : "lecture avant émission" et "lecture après émission"=== Passons maintenant à un détail d'implémentation de l'exécution dans le désordre. La '''lecture après émission''' utilise des fenêtres d'instruction proprement dit, alors que la '''lecture avant émission''' utilise des stations de réservation. Rappelons que la différence est que les premières émettent les instruction puis lisent les registres, alors que la seconde lit les opérandes depuis les registres juste après le renommage de registre, pour les stocker dans le ''scheduler''. La différence est donc que les étages sont répartis différemment. Avec la "lecture avant émission", l'étage de lecture des opérandes est placé entre l'étage de renommage de registres et l'étage d'émission. Avec la "lecture après émission", l'étage de lecture des registres est situé après l'étage d'émission/''select/wakeup''. Les deux méthodes de lecture avant ou après émission montrent une grande différence pour ce qui est de déterminer la disponibilité des opérandes. Pour la lecture après émission, le renommage de registre n'est pas impliqué. Mais avec la lecture avant émission, les opérandes sont lues dans les registres entre le renommage des registres et l'entrée dans la station de réservation. Ce qui implique qu'on sait quelles sont les opérandes disponibles lors du renommage de registres. Pour cela, l'unité de renommage de registre contient, pour chaque registre virtuel, un bit ''ready'' qui indique que le registre renommé contient une opérande est disponible. S'il est à 0, l'instruction est placée dans le ''scheduler'', et attend que ses opérandes soient disponibles. S'il est à 1, les opérandes sont soit lues dans le registre et placées dans le ''scheduler'', soit lues au moment d'exécuter l'instruction. L'ensemble de ces bits est en plus des bits de disponibilité de la station de réservation, dans l'implémentation la plus simple. Les deux sont alors mis à jour en même temps. Une autre solution regroupe les bits de disponibilité dans une structure matérielle appelée la '''table de disponibilité''', qui est consultée à la fois par les stations de réservation et l'unité de renommage de registres. L'avantage de cette solution est que les signaux de réveil sont envoyés à une seule structure matérielle, pas plus. De plus, il n'y a pas de duplication des bits de disponibilité. Non pas que quelques bits fassent une grosse différence, mais tout est bon à prendre. Notons qu'avec un banc de registres physique, le bit de disponibilité se déduit des quatre états que peut prendre un registre physique. L'unité de renommage de registre doit sait déjà quelles sont les opérandes indisponibles, celles qui ont déjà été calculées, et celles enregistrées dans un registre architectural. Notons qu'un registre virtuel, une fois attribué, peut être en état réservé ou écrit. Seul l'état écrit correspond à une opérande disponible, l'unité de renommage doit donc pouvoir faire la différence. Pour savoir si un registre virtuel contient une donnée valide, la table d’alias de registres lui associe un bit de validité qui est mis à jour lors de l'écriture du résultat dans le registre virtuel correspondant. Elle doit aussi mémoriser quels registres architecturaux ont une donnée valide. Rappelons que le processeur sait qu'une opérande est disponible parce qu'un signal de réveil est généré dans le pipeline, pour dire que telle opérande est disponible. Le signal transmet l'opérande avec le numéro de registre (virtuel ici). Le numéro de registre transmis est alors comparé avec tous les numéros de registre des opérandes, dans le ''scheduler'' et/ou les stations de réservation. Il est possible qu'une instruction soit dans l'étape de renommage alors que le signal de ''réveil'' est envoyé. Si rien n'est fait, l'instruction sera insérée dans le ''scheduler'' avec une opérande indisponible, alors qu'elle l'est. Elle restera alors indéfiniment dans le ''scheduler'', vu que le signal de ''réveil'' n'est généré qu'une seule fois. Pour éviter cela, le signal de ''réveil'' doit aussi être envoyé aux instructions dans l'unité de renommage de registre. Une solution pour éviter cela est d'enregistrer directement les noms de registres renommés dans le ''scheduler'', dès la sortie de l'unité de renommage. Les noms de registres sautent un étage de pipeline, donc. La comparaison avec les signaux de réveil se fait alors dans le ''scheduler'', pas besoin de rajouter un comparateur dans l'étage de lecture des registres. Une autre solution est d'utiliser une table de disponibilité unique. Les signaux de réveil ne sont alors pas perdus. ==Les optimisations liées au renommage de registres== Le renommage de registre permet d'implémenter certaines optimisations annexes, qu'on ne croirait pas reliées au renommage de registre au premier abord. Par exemple, saviez-vous que le renommage de registre permet d'exécuter certaines instructions directement dans l'unité de renommage ? De nombreuses optimisations éliminent certaines instructions, en les remplaçant par des renommages de registres. Il existe plusieurs optimisations de ce genre, qui portent les noms barbabres d'élimination des MOV, de calcul trivial, et de remplacement d'idiomes. ===L'élimination des MOV=== La première optimisation de ce genre élimine les instructions de copie d'un registre dans un autre (les MOV) ou d’échange entre deux registres (XCHG). Ce qui explique pourquoi l'optimisation en question porte le nom d''''élimination des MOV''' (''MOV elimination''), sous-entendu, des MOV inter-registres. L'élimination des MOV est une technique implémenté sur les processeurs à banc de registre physique. En clair, il faut qu'il y ait un seul banc de registre. C'est important, car c'est la seule méthode qui fait que les registres virtuels n'ont pas à être copiés dans les registres architecturaux, ce qui facilite grandement l'implémentation d’une technique visant à éliminer des copies de registres. L'idée est qu'après une copie, le contenu des deux registres source et destination est identique tant qu'aucun des deux registres ne subit d'écriture. On peut alors utiliser un seul registre physique pour la valeur mémorisée, toute lecture des deux registres lisant celui-ci. Lors d'une écriture dans un de ces deux registres, le renommage attribuera un nouveau registre physique pour la nouvelle valeur écrite. : Formellement, il s'agit d'une optimisation de type '''''copy-on-write'''''. ===Le remplacement d'idiomes=== Le même genre d'optimisation peut être effectué avec des instructions inutiles, dont le résultat vaut zéro. En effet, il existe de nombreuses méthodes pour mettre un registre à zéro. Faire un XOR entre le registre et lui-même, le soustraire à lui-même ou le multiplier par zéro sont quelques exemples. Et de tels idiomes sont utilisés par les compilateurs, au lieu d'un simple MOV 0 -> registre, qui copie un 0 dans le registre. La raison est que les instructions MOV sont assez longues, vu qu'elles doivent intégrer une constante immédiate. Le renommage de registres peut être utilisé pour éliminer ces opérations et les remplacer par une mise à zéro du registre. L'optimisation en question porte le nom de '''remplacement d'idiomes'''. Elle est implémentée depuis les processeurs Pentium de microarchitecture P6, et leurs équivalents AMD. Un autre avantage de cette optimisation est que cela casse de fausses chaines de dépendances. Par exemple, une opération "reg XOR reg" faire croire au processeur qu'il y a une dépendance de donnée entre cette instruction, et les instructions précédente qui écrivent dans le registre. Le XOR est donc exécuté après ces instructions faussement dépendantes, alors que la mise à zéro du registre pourrait se faire en parallèle en utilisant un registre virtuel séparé. Les techniques précédentes permettent d'éliminer ces fausses dépendances. ===Les optimisations de calculs triviaux=== Il existe aussi des opérations dont le résultat est une des opérandes. On pourrait citer comme exemples les décalages par 0, les additions et soustractions avec 0, la multiplication par 1, et bien d'autres. En utilisant intelligemment le renommage de registres, ces calculs ne sont pas effectués. Les techniques qui permettent cela sont des techniques dites de '''calcul trivial''' (trivial computation). La détection des calculs simplifiables demande de comparer les opérandes avec 0 ou 1, via un paquets de comparateurs regroupés dans une unité de détection des calculs triviaux. Leur simplification se fait dans la table de renommage de registres, le registre de destination de l'instruction simplifiée étant renommé pour pointer sur l'opérande/résultat. Si le résultat est nul, on considère que la correspondance est invalide et on met le registre physique à une valeur invalide, similaire au pointeur NULL du C. Si un calcul lit un registre physique invalide, celui-ci est automatiquement simplifié par l'unité de renommage, l'autre opérande étant alors attribué automatiquement comme registre de destination du résultat dans la table de renommage. Mais cette technique a tendance à modifier la latence des instructions, qui est réduite après simplification. Cela pose problème au niveau des circuits d'émission et du planificateur, qui n'aiment pas les latences variables, comme on l'a vu il y a quelques chapitres. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=L'exécution dans le désordre | prevText=L'exécution dans le désordre | next=Le scoreboarding et l'algorithme de Tomasulo | nextText=Le scoreboarding et l'algorithme de Tomasulo }} </noinclude> epyteifju9jqm2x109tk8zsjghckdnt 773617 773616 2026-09-29T20:51:35Z Mewtow 31375 773617 wikitext text/x-wiki Pour améliorer l'exécution dans le désordre, les concepteurs de processeurs ont étudié des méthodes pour éliminer la grosse majorité des dépendances de données lors de l’exécution. Dans ce que j'ai dit précédemment, j'ai évoqué trois types de dépendances de données. Les dépendances RAW (''Read After Write'') sont des dépendances contre lesquelles on ne peut rien faire : ce sont de « vraies » dépendances de données. Elles imposent un certain ordre d’exécution de nos instructions. Mais les dépendances WAW (''write after write'') et WAR (''write after read'') sont de fausses dépendances, nées du fait qu'un emplacement mémoire est réutilisé, pour stocker des données différentes à des instants différents. Bien évidemment, l’imagination débridée des concepteurs de processeur a trouvé une solution pour supprimer ces dépendances : le '''renommage de registres'''. Avant toute chose, précisons que ce chapitre abordera uniquement les techniques compatibles avec les exceptions précises. En clair, seulement les techniques utilisées sur les processeurs modernes. Il existe deux autres techniques de renommage de registre utilisées sur les processeurs sans exceptions précises : l'algorithme de Tomasulo et le ''scoreboarding''. Contrairement à ce que vous avez pu lire ailleurs, il y a une forme de renommage de registre dans le ''scoreboarding'', mais nous verrons cela dans quelques chapitres. Toujours est-il que ces deux techniques historiques étaient utilisées sur d'anciens ordinateurs, qui n'implémentaient pas la prédiction de branchement. Leurs techniques de renommage de registres étaient particulières, aussi nous les verrons dans un chapitre à part. ==Le renommage de registres : généralités== Les dépendances WAR et WAW sont souvent opposées aux dépendances vraies (true dependency), à savoir les dépendances RAW. Les dépendances WAR et WAW viennent du fait qu'un même registre nommé est réutilisé plusieurs fois pour des données différentes. Un même nom de registre identifie une donnée différente à des instants différents du programme, ce qui force à exécuter les instructions qui utilisent ce registre dans l'ordre. D'où le fait que les dépendances WAR et WAW sont souvent appelées des dépendances de nom (''naming dependency''). Si on change l'ordre de deux instructions ayant une dépendance de données WAW ou WAR, on peut se retrouver dans une situation où les deux instructions veulent stocker des données différentes en même temps dans le même registre, ce qui n'est pas possible. Mais elles n'existeraient pas si on utilisait un registre pour chaque donnée, qui est écrit une fois, lu une ou plusieurs fois, mais jamais écrasé. Un même nom de registre correspond alors à une donnée. Une solution simple vient alors à l'esprit : conserver chaque donnée dans son propre registre et choisir le registre adéquat à l'utilisation. Un registre architectural correspond alors à plusieurs registres, chacun contenant une donnée bien précise. L'idée est qu'au lieu d'avoir un registre qui contient des données différentes à des instants différents, on a autant de registres que de données, ce qui améliore les possibilités de réorganisation des instructions. Il faut ainsi faire la distinction entre : * '''registres architecturaux''', définis par le jeu d'instructions ; * '''registres physiques''', physiquement présents dans l'ordinateur ; * '''registres virtuels''' utilisés pour le renommage de registre mais invisibles pour le programmeur. Les registres physiques regroupent l'ensemble des registres, à savoir les registres architecturaux et virtuels. Pour illustrer l'idée, prenons l'exemple suivant, où un registre architectural nommé R6 est utilisé pour stocker trois données consécutives. Il mémorise d'abord le nombre 255, puis le nombre 2567763, puis zéro. On suppose que ces trois valeurs sont indépendantes, dans le sens où elles sont utilisées par des instructions sans dépendances RAW. En théorie, on pourrait exécuter ces instructions séparément, mais ce n'est pas possible. Le fait est que l'on doit d'abord faire les calculs avec l'opérande 255, puis ceux avec l'opérande 2567763, puis ceux avec l'opérande zéro. La raison est que pour que le calcul démarre, il faut que l'opérande soit disponible. Et l’usage d'un seul registre pour stocker des opérandes différentes à des temps différents limite les possibilités d’exécution en parallèle. Avec le renommage de registres, ces trois données sont enregistrées dans des registres physiques séparés, dès qu'elles sont disponibles. Le processeur garde évidemment trace du fait que ces trois registres physiques correspondent au registre architectural R6. Si les trois valeurs n'ont pas de dépendances entre elles, les instructions liées peuvent être exécutées dans le désordre et s’exécuter en même temps. Ce qui est le cas dans le schéma suivant, où certaines instructions sont exécutées en avance, ce qui réserve les registres physiques en avance. [[File:Renommage de registres - principe.png|centre|vignette|upright=2|Exemple où un registre architectural est utilisé pour contenir trois données successives.]] : Pour les connaisseurs, le renommage de registres réécrit le programme exécuté dans une représentation appelée SSA, utilisée par les compilateurs lors de la compilation. Et cette réécriture se fait un peu de la même manière avec un compilateur. Là où le compilateur change le nom des variables pour passer en forme SSA, le processeur change les noms de registres pour obtenir de l'assembleur SSA interne au processeur. ===La durée de vie des registres virtuels=== La plupart des processeurs disposent d'un banc de registre physique unique, qui regroupe registres physiques et virtuels. Mais il existe quelques processeurs qui font autrement. Ils ont un banc de registre pour les registres architecturaux, et les registres virtuels sont placés ailleurs dans le processeur, typiquement dans le tampon de ré-ordonnancement (ROB) ou le ''scheduler''. Pour simplifier, considérons qu'ils sont dans un banc de registre spécialisé qui regroupe les registres virtuels. C'est un peu faux en soi, mais faisons comme si. Dans le reste de cette section, nous allons partir du principe que les registres virtuels et architecturaux sont séparés pour simplifier les explications, nous verrons les autres formes de renommage de registre plus tard. Les registres virtuels ont une certaine durée de vie. On veut dire par là qu'une donnée écrite dans un registre virtuel y reste durant un certain temps, mais pas indéfiniment. Un registre virtuel est utilisé par une instruction en cours d'exécution dans le pipeline. Il nait lors du renommage de registre et meurt une fois l'instruction terminée. En clair, un registre virtuel dure durant toutes les étapes du pipeline qui suivent le renommage de registres. Une fois que l'instruction quitte le pipeline, qu'elle sort du ROB, le registre virtuel est inutile et doit laisser la place au registre architectural non-renommé. Le résultat de l'instruction doit être transféré dans le registre architectural adéquat, le registre de destination de l'instruction. Si les registres virtuels et architecturaux sont séparés, il faut copier la donnée des registres virtuels vers les registres architecturaux. Utiliser un banc de registre unique résout le problème, mais n'allons pas trop vite, nous verrons cela en détail dans la suite. Toujours est-il qu'un registre virtuel est libéré quand l'instruction associée quitte le ROB. Il est théoriquement possible de libérer un registre virtuel en avance, si on est certain qu'aucune instruction n'ira lire ce registre. Pour cela, le mieux est d'attribuer un compteur de lectures pour chaque registre. À noter que pour maintenir des exceptions précises, on est obligé d'attendre que la dernière instruction qui lit le registre ait validé. Le jeu n'en vaut clairement pas la chandelle. Le seul intérêt d'une telle optimisation est économiser des registres virtuels, d'avoir un banc de registres virtuels plus petits, mais cela se fait au prix de l'ajout de circuits qui consomment tout autant, si ce n'est plus de circuits, pour un résultat en termes de performances limité, voire nul. Après avoir vu la mort des registres virtuels, voyons leur naissance. Le renommage de registre a lieu après le décodage, donc juste avant le passage dans le ''scoreboard'', le ''scheduler'', la file d'instruction ou toute autre structure dédiée à l'émission. En clair : les registres virtuels sont attribués juste avant émission et ne sont utiles qu'après. Les instructions susceptibles d'utiliser un registre virtuel sont donc les instructions émises ou prêtes à l'être, mais pas encore terminées. Les instructions en question sont soit en attente dans le ''scheduler'', soit en cours d'exécution dans le chemin de données, soit en attente dans le ROB. Ces dernières attendent que les instructions précédentes se terminent. Il faut noter que toutes les instructions émises ou en passe de l'être ont été ajoutées dans le ROB juste après le renommage. Même les instructions en attente dans le ''scheduler'' sont dans le ROB. Pour résumer, le ROB garde la trace de ces instructions prêtes à être émises ou déjà émises. ===Le nombre idéal de registres virtuels=== Mine de rien, le contenu de la section précédente nous donne une seconde borne maximale sur le nombre de registres virtuels utiles. Supposons que chaque instruction fournit un résultat, stocké dans un registre virtuel rien que pour lui. Le nombre maximal d'instructions chargées dans le pipeline après émission est égal au nombre d'entrée dans le ROB. Il peut y avoir moins d'instructions, ce qui fait que des entrées du ROB sont inutilisées, mais supposons que nous soyons dans le meilleur des cas. Dans ce cas, on doit avoir un registre virtuel par instruction, ce qui fait au maximum un registre virtuel par entrée du ROB. Rien ne sert d'avoir plus de registres virtuels que d'entrées dans le ROB, il n'y aura pas assez d’instructions dans le pipeline pour tous les utiliser. Après avoir vu une borne maximale, voyons une limite minimale. Non pas qu'il faille absolument plus de registres virtuels que cette limite, simplement qu'il est préférable d'en avoir que cette limite. Partons du principe que les instructions pouvant utiliser un registre virtuel sont celles qui sont soit déjà émises, soit en attente de l'être. Si on néglige les instructions en attente dans le ROB, alors les instructions émises sont dans les ALUs. Le nombre d'instruction est donc égal à la somme de : la taille du ''scheduler'' (instructions en attente), du nombre d'unités de calcul (instruction en cours d'exécution), unités d'accès mémoire inclues. Mieux vaut ne pas passer sous la somme taille du ''scheduler'' + nombre d'unités de calcul. Un bon compromis est d'avoir un nombre de registre virtuel compris entre ces deux bornes. Le nombre réel de registre virtuels est très souvent inférieur au nombre d'entrées du ROB, car toutes les instructions ne fournissent pas de résultat à enregistrer dans les registres. C'est le cas pour les instructions de branchement, par exemple, ou les écritures en mémoire RAM. Par contre, il vaut mieux avoir plus de registres que d'entrées dans le ''scheduler''. La majorité es processeurs respectent ces deux limites basse et hautes, avec un nombre de registres réels entre les deux. Les quelques rares exceptions étaient des processeurs qui implémentaient le renommage de registre pour la première fois, et où ce genre de détails n'étaient pas bien compris. Par exemple, on peut citer le PowerPC 604, qui avait 20 registres virtuels, alors que le ROB avait seulement 16 entrées. Les 4 registres virtuels en trop n'étaient pas utilisés. Le processeur qui a immédiatement suivi, le PowerPC 604, n'a pas fait cette erreur et a réduit le nombre de registres virtuels à seulement 16. Un autre exemple est le MIPS R10000, avec son ROB à 32 entrées, son ''scheduler'' a 48 entrées et ses 64 registres virtuels. Le processeur suivant, le R12000, corrigea partiellement le problème en augmentant le ROB à 48 entrées, ce qui était insuffisant, mais bienvenu. ===Le renommage de registre total et partiel=== De nombreux processeurs ont des registres architecturaux séparés pour les nombres flottants et entiers. Dans ce cas, leur renommage est indépendant : les registres flottants ont leur unité de renommage dédiée, séparée de celle pour les registres entiers. A ce propos, quelques rares processeurs ne renomment que que les registres flottants, ou que les registres entiers ! Pour donner un exemple, le processeur Nx586 ne renommait que les registres entiers, pour les instructions entières. Un autre exemple est celui de l'IBM System/360 Model 91, sur lequel les registres flottants étaient renommés, mais pas les registres entiers. Sur les CPU x86, lorsque le renommage de registre a été introduit, il ne concernait que les registres flottants. Ce choix s'explique par l'organisation en pile de registres liée au jeu d'instruction x87. Elle limitait grandement le parallélisme d'instruction, le renommage permettait de fortement limiter la casse. [[File:Zen microarchitecture.svg|centre|vignette|upright=2|Microarchitecture Zen 1 des CPU d'AMD.]] Le renommage de registre peut être total ou partiel. Avec le renommage total, toutes les instructions voient leurs registres renommés. Il s'agit de la méthode la plus utilisée à ce jour, par simplicité de conception. Mais des processeurs assez anciens utilisaient un renommage partiel, qui ne s’appliquaient qu'à certains types d'instruction bien précis. Par exemple, on pourrait citer les processeurs Power1, Power2 et PowerPC 601. Sur le premier, seuls les registres flottants étaient renommés, et seulement pour les instructions de lecture flottante. La raison est que le processeur n'a qu'une seule FPU, ce qui limite l'efficacité de l'exécution dans le désordre sur celle-ci, et fait que renommer les registres ne sert à rien. Le processeur Power 2 dispose lui de plusieurs FPU et le renommage de registres touche aussi les instructions flottantes arithmétiques, c'est un renommage total. Les processeur qui utilisaient le renommage partiel étaient des processeurs assez anciens, qui faisaient avec un budget en transistors limité. De plus, la technique n'était pas très bien maitrisée, et était encore balbutiante. La technique a pourtant été proposée dès 1970 dans divers articles académiques, et raffinée pendant les années 70. Mais le budget en transistors du renommage de registre a fait qu'elle n'a pas été utilisée avant que la loi de Moore fasse son œuvre. ==Les différentes implémentations du renommage de registres== Il existe plusieurs manières différentes d'implémenter le renommage de registre, que nous allons voir dans cette section. Mais avant toute chose, parlons du réseau de contournement. Pour simplifier les explications, appelons ''instruction productrice'' l'instruction qui fournit un résultat, et instruction consommatrice celle qui l'utilise comme opérande. Si une instruction consommatrice est chargée dans le pipeline quelques cycles après l'instruction productrice, les deux sont dans le pipeline en même temps. Dans ce cas, on pourrait penser que c'est le réseau de contournement qui gérerait le transfert du résultat de l'instruction productrice à l’instruction consommatrice. Et effectivement, c'est souvent le cas. Mais les registres virtuels sont pris en compte dans le système de contournement. Si le résultat est écrit dans un registre virtuel, il peut aussi être lu dans ce registre virtuel. Lire un résultat dans les registres virtuels permet d'implémenter une forme de contournement. Tout cela pour dire qu'il y a un lien entre contournement et renommage de registres, les deux doivent être conçu de manière à communiquer entre eux. Typiquement, il y a toujours un réseau de contournement pour connecter la sortie d'une ALU aux entrées des autres. Ce dernier gère le cas où un résultat d’instruction est réutilisé comme opérande au cycle suivant. Mais pour réutiliser un résultat deux cycles après ou plus tard, c'est le système de renommage de registres qui s'en charge. Ceci étant dit, nous allons étudier les implémentations principales du renommage de registre. Pour simplifier, il existe deux manières d'implémenter le renommage de registre. La première utilise deux bancs de registres : un pour les registres architecturaux, un autre pour les registres virtuels. Une autre implémentation regroupe registres virtuels et architecturaux dans un seul banc de registre. Mais d'autres implémentations font totalement autrement, en réutilisant les stations de réservation ou le tampon de ré-ordonnancement. Dans ce qui suit, nous allons nous concentrer sur les principales : le renommage à banc de registre physique, le renommage dans le ROB, le renommage à registres virtuels. Nous allons laisser de côté le renommage dans les stations de réservation pour une raison très simple : elle n'est pas compatible avec les exceptions précises. Nous la verrons dans un chapitre à part, portant sur le ''scoreboarding'' et l'algorithme de Tomasulo. ===Le renommage à banc de registres physiques=== Les processeurs modernes utilisent un seul banc de registres pour les registres architecturaux et virtuels, appelé '''banc de registres physiques''' (''physical register file''). Le tampon de réordonnancement et le ''scheduler'' contiennent des numéros de registres virtuels, des pointeurs vers les registres. Il y a toujours un réseau de contournement pour connecter la sortie d'une ALU aux entrées des autres, qui gère le cas où la sortie de l'ALU est utilisé comme opérande au cycle suivant. Mais pour réutiliser un résultat deux cycles après ou plus tard, c'est le banc de registres physiques qui s'en charge. Les opérandes viennent donc soit du banc de registres physique, soit du réseau de contournement. [[File:Renommage à banc de registres physiques.png|centre|vignette|upright=2|Renommage à banc de registres physiques.]] Avec ce système, un registre physique peut être dans quatre états. * Le premier état est celui d'un ''registre disponible'', près à servir de registre de destination. Par disponible, on veut dire que ce registre peut être réservé par l'unité de renommage, mais qu'il n'a pas encore été réservé. Ce n'est ni un registre virtuel, ni un registre architectural, juste un registre inutilisé. * Le second état est l'''état réservé'', celui d'un registre virtuel qui attend qu'une instruction écrive son résultat dedans. L'état réservé réserve un registre en écriture, mais interdit les lectures dedans. * Le troisième état est celui d'un registre virtuel dans lequel une instruction a écrit son résultat, mais l'instruction n'a pas encore quitté le ROB. Le registre est alors appelé un ''registre écrit''. * Enfin, le quatrième est celui d'un ''registre architectural'', qui contient une donnée valide, dans le sens où il n'est associé à aucune instruction dans le ROB. Un registre passe normalement par ces quatre états dans l'ordre disponible, virtuel réservé, virtuel écrit, architectural. Une fois que l'instruction attribuée quitte le ROB, le registre virtuel devient un registre architectural. Cependant, cela suppose que l'instruction quitte le ROB normalement, ce qui n'est pas le cas suite à une mauvaise prédiction de branchement ou autre. Dans ce cas, il repasse immédiatement à l'état disponible. L'unité de renommage des registre mémorise l'état de chaque registre pour savoir dans quel état il est. Avec ce système, les données ne sont pas déplacées, ce qui a un avantage en termes de performance, de consommation énergétique et de simplification des circuits du processeur. Une fois enregistrées dans un registre, les données ne se déplacent plus. Avec un banc de registre virtuel séparé, elles sont recopiées d'un banc de registre virtuel vers un banc de registre architectural. Et les autres techniques que nous allons voir ont le même problème. Un autre avantage est que les opérandes proviennent toutes du même endroit : le banc de registre unique. Avec un banc de registre séparés, les opérandes peuvent provenir soit des registres architecturaux, soit des registres virtuels. Les opérandes peuvent donc provenir du banc de registre architectural, mais aussi du banc de registre renommés. La conséquence est que la gestion des interconnexions est beaucoup plus compliquée, notamment quand on veut implémenter le contournement. Pas de problèmes de ce genre avec un banc de registre unique. ===Le renommage dans le tampon de réordonnancement=== Il est possible de faire le renommage dans le tampon de réordonnancement (ROB, pour ''ReOrder Buffer'')). Cela veut dire que les résultats des instructions sont mémorisés dans le tampon de réordonnancement. Les entrées du ROB se voient ajouter un champ pour mémoriser le résultat d'une instruction, et ce champ sert de registre virtuel. Les entrées du ROB deviennent ainsi adressables, elle ont un numéro, qui sert de numéro/nom de registre virtuel. Avec cette technique, les registres architecturaux sont séparés des registres virtuels inclus dans le ROB. Les registres architecturaux sont regroupés dans un banc de registres spécialisé, appelé le '''''retirement register file'''''. Le ''scheduler'' mémorise soit un nom de registre architectural, soit l'adresse de l'entrée du ROB qui contient le résultat voulu. Quand une instruction a tous ses opérandes de prêts, ceux-ci sont lus depuis le ROB ou les registres architecturaux. Pour cela, le ROB mémorise l'état de chaque entrée, de chaque registre virtuel : vide, réservée pour un résultat, écrite avec un résultat. [[File:Renommage dans le tampon de réordonnancement.png|centre|vignette|upright=2|Renommage dans le tampon de réordonnancement.]] Un défaut est que cela complexifie l'implémentation des interconnexions par rapport à un banc de registre physique. Il y a toujours un réseau de contournement pour réutiliser un résultat un cycle plus tard. Mais pour réutiliser un résultat deux cycles après ou plus tard, c'est le ROB qui s'en charge. Les opérandes peuvent être lues depuis trois sources : le ROB, le banc de registre architectural, et le réseau de contournement. Soit une source de plus qu'avec la technique précédente, ce qui complexifie les multiplexeurs de contournement. Et cela a un effet sur la latence des opérations, le temps de traversée de ces multiplexeurs n'est pas gratuit, sans compter le temps mis pour les signaux de commande pour les configurer. Le renommage de registre est aussi plus compliqué. Au lieu de simplement remplacer un numéro de registre architectural par un numéro de registre physique, on doit faire la différence entre numéro de registre et adresse dans le ROB, pour savoir où lire les opérandes. Sans quoi ne sait pas configurer les multiplexeurs et choisir la bonne source pour les opérandes. Un autre défaut est que les registres virtuels doivent être copiés dans les registres architecturaux quand une instruction quitte le ROB. La copie se fait ici du ROB vers le banc de registre architectural. Et copier la donnée a un cout en énergie que l'usage d'un banc de registre unique n'a pas. Un dernier défaut est que le nombre de registres virtuel est égal au nombre d'entrées dans le ROB. Or, on a vu plus haut que c'est un peu du gâchis, car beaucoup d'instructions ne produisent aucun résultat. Le hardware ajouté pour les entrées est donc sous-utilisé, il ne sert que si l'instruction fournit un résultat, mais ne sert à rien sinon. ===Le renommage avec un tampon de renommage=== Le dernier défaut évoqué dit que beaucoup d'entrées du ROB sont inutilisées et que les registres virtuels associés sont gâchés. Pour éviter cela, il est possible de sortir les résultats d'instruction du ROB et de les placer dans une mémoire FIFO complémentaire du ROB, appelée le '''tampon de renommage'''. Pour le dire autrement, le ROB amélioré est scindé en deux, avec le ROB proprement dit d'un côté, et un pseudo-ROB pour le renommage de registres et le contournement. Pour information, cette technique de renommage était utilisée dans d'anciens processeurs commerciaux, comme les Pentium Pro, le Pentium II, ou encore le Pentium III, ainsi que dans le Core 2 Duo. La technique est souvent expliquée en décrivant le tampon de renommage comme un banc de registre séparé pour les registres virtuels, appelé le '''banc de registres renommés''' (''rename register file''). Il est séparé du banc de registres architecturaux, avec lequel il communique. La raison à cela est que le tampon de renommage est adressable alors que le ROB ne l'est pas. Il faut dire que le tampon de renommage a tout d'un banc de registre : il contient les registres virtuels et seulement ceux-ci, on peut l'adresser, lire des opérandes dedans, écrire des résultats dedans, etc. Par contre, il y a une différence avec un banc de registre normal : il est traité comme une mémoire FIFO. Nous avons déjà vu comment implémenter une FIFO avec un banc de registre et quelques registres, aussi je ne fais pas de rappels sur ce point. S'il s'agissait d'un véritable banc de registre isolé, sans rien de plus, le ROB et le ''scheduler'' contiendraient des numéros de registres virtuels, qui adressent directement le banc de registre renommé. Une telle implémentation est possible, mais aucun processeur commercial n'a utilisé une telle implémentation. À la place, le banc de registre est en réalité une mémoire FIFO, dont les entrées sont adressables, avec de plus un système de cache utilisé pour faire la correspondance entre nom de registre architectural et nom de registre virtuel. Nous détaillerons ce dernier point dans la section qui explique comment fonctionne l'unité de renommage. Une fois que l'instruction attribuée quitte le ROB, le registre virtuel est libéré, à savoir qu'il repasse en état disponible. C'est à ce moment qu'à lieu la copie de la donnée dans le registre architectural adéquat. Il faut noter que le registre virtuel n'est pas effacé, il contient toujours l'ancienne donnée. Mais ce n'est pas un problème. S'il est réservé par une instruction, elle écrira dedans, ce qui écrasera cette donnée. Et de manière générale, il est impossible de lire cette donnée, que ce soit si le registre est disponible ou réservé. [[File:Renommage à banc de registres renommés.png|centre|vignette|upright=2|Renommage à banc de registres renommés.]] La technique partage tous les défauts du renommage dans le ROB. Le réseau de contournement est plus compliqué car les opérandes peuvent venir de trois sources : les deux bancs de registres et le réseau de contournement. De plus, les registres virtuels doivent être copiés dans les registres architecturaux, avec tout ce que cela implique. Déjà, déplacer des données implique un cout en énergie et en consommation d'électricité, qu'il vaut mieux éviter. De plus, il faut ajouter un port de lecture sur le banc de registre renommés, pour copier un registre sans nuire aux performances. Le banc de registres physiques n'a pas à être modifié : le port d'écriture existant suffit pour la copie, vu qu'on n'écrit dedans que pour copier des résultats d'instructions validées/terminées. Par contre, le cout en transistors est plus faible qu'avec le renommage dans le ROB, vu que le banc de registre a moins de registres virtuels que le ROB. La technique n'impose pas d'avoir autant de registres virtuels que d'entrées dans le ROB, ce qui permet d'en réduire le nombre. Par contre, comparé à l'usage d'un banc de registres unique, le cout en transistors est plus élevé. La différence se fait surtout au niveau des ports de lecture/écriture du banc de registres. La raison est que l'on doit ajouter un port de lecture pour copier les résultats dans les registres architecturaux. Du moins, dans le cas le plus simple. C'est le cas sur un processeur qui permet de compléter l'exécution d'une instruction par cycle. Mais certains processeurs peuvent terminer l'exécution de plusieurs instructions par cycle. C'est notamment le cas des processeurs dits superscalaires, qui sont capables de charger, exécuter et terminer plusieurs instructions par cycle. Ils auront droit à leur chapitre dédié, mais passons. Toujours est-il que si plusieurs instructions peuvent se terminer en même temps, il faut ajouter autant de ports de lecture sur le banc de registre pour copier leurs résultats. ===Le renommage physique-virtuel=== Les méthodes mentionnées au-dessus ont un léger problème : beaucoup de registres physiques sont gâchés, car attribués à une instruction dès l'étage de renommage et libérés lorsque on est certain qu'aucune instruction ne lira le registre physique attribué. Et parfois, les registres sont alloués trop tôt, alors qu'ils auraient pu rester libres durant encore quelques cycles. C'est notamment le cas quand l'instruction renommée attend un opérande dans le ''scheduler'', ou quand le résultat est en cours de calcul dans l'unité de calcul. Ces situations ont toutes la même origine : le renommage a lieu tôt dans le pipeline, pour garder les dépendances entre instructions. Mais dans les faits, rien n'oblige à utiliser les registres architecturaux pour conserver les dépendances. On peut tout simplement attribuer un tag à chaque résultat d'instruction, tag qui ne correspond pas à un registre architectural. Et ce tag sera alloué à un registre architectural le plus tard possible, quand l'instruction fournira son résultat. Ce genre de méthodes a été formalisée avec ce qu'on appelle la technique du '''banc de registres physiques-virtuels''' (physical-virtual register file). Cette méthode demande d'ajouter une seconde table de correspondance, qui fait le lien entre le tag et le registre physique. De plus, la table d’alias de registres doit être modifiée : elle ne doit pas seulement faire la correspondance entre le nom de registre et le tag, mais aussi avec le registre physique s'il est déjà attribué. Ainsi, lors du renommage en sortie du décodeur, on peut renommer l'instruction avec les registres physiques si ceux-ci sont connus lors du renommage, et renommer avec des tags dans le cas contraire. Il faut noter que cette méthode a un léger problème : quand une instruction termine et que le résultat doit se voir attribuer un tag, il se peut parfaitement qu'il n'y ait plus de registre physique de libre. Les solutions pour régler ce problème sont assez complexes, aussi je n'en parlerai pas ici. ==L’unité de renommage== Pour commencer, sachez qu'il existe deux méthodes pour implémenter l'unité de renommage. La première utilise une unité à part, séparées, qui contient de nombreuses mémoires caches/FIFO pour stocker des informations nécessaires pour le renommage de registres. La seconde mémorise les informations de renommage dans le ROB ou le tampon de renommage, voir ailleurs. Les deux types d'unités de renommage sont assez différentes. Pour les désigner, je vais parler d''''implémentation par ''tag''''' et d''''implémentation associative'''. De plus, les deux types d'unités ne sont pas utilisées sur les mêmes implémentations. Par exemple, avec un banc de registre physique, il est naturel d'utiliser une implémentation par ''tag'', l'autre implémentation n'est pas pratique. Aussi, tous les processeurs avec un banc de registre physique utilisent une unité de renommage pat ''tag''. Mais pour le renommage dans le ROB, c'est l'inverse : les deux implémentations sont possibles, mais il est préférable d'utiliser une implémentation associative. Pour simplifier les explications, je vais commencer par décrire le premier type, avec un banc de registre physique. {|class="wikitable" |- ! ! Implémentation par ''tag'' ! Implémentation associative |- ! Banc de registre physique | Seule implémentation possible | |- ! Renommage dans le ROB | Possible, certains processeurs utilisent la technique | Possible, certains processeurs utilisent la technique |- ! Renommage dans un tampon de renommage | Possible, tous les processeurs utilisent la technique | Possible, aucun processeur connu |} ===Les unités de renommage par ''tag''=== Les registres architecturaux sont identifiés par des noms de registre, tout comme les registres physiques. Les noms de registre des registres physiques sont appelés des '''tags'''. Les registres physiques sont bien plus nombreux que les registres architecturaux, sans quoi le renommage de registre n'a aucun intérêt. La conséquence est que les numéros de registres physiques sont plus grands que les numéros de registres architecturaux. Le renommage de registres remplace les noms/numéros de registres architecturaux par des numéros de registres physiques, par des ''tags''. D'où le terme de ''renommage'' de registre. Ce remplacement est effectué dans un étage supplémentaire du pipeline, intercalé entre le décodage et l'émission. [[File:Renommage de registres.png|centre|vignette|upright=2|Renommage de registres.]] Le remplacement se fait cependant différemment pour le registre de destination et les registres d'opérandes. Le registre de destination est associé à un registre virtuel disponible. L'allocation du registre de destination prend un registre disponible et le place en état réservé. Une nouvelle correspondance entre registre architectural et virtuel est alors crée. Mais pour les opérandes, c'est autre chose. Les opérandes sont soit dans un registre architectural, soit dans un registre virtuel en état écrit. Les noms de registres architecturaux pour les opérandes doivent être remplacé par le nom de registre adéquat, déjà attribué. Une sacrée différence : on attribue un registre virtuel pour le résultat, les opérandes ont déjà un registre virtuel attribué. Un autre point est que l'unité de renommage ne fait pas que modifier les registres opérande/de destination. Elle gère aussi la disponibilité des opérandes. Plus haut, on a dit qu'un registre virtuel pouvait être dans quatre états. Soit il est disponible, soit il est réservé, soit il est écrit, soit la donnée est dans un registre architectural. L'unité de renommage est au courant de l'état de chaque registre. Les quatre états possibles sont utilisés pour diverses raisons. Et il y a deux manières pour mémoriser la correspondance entre un registre physique et un registre architectural. La première est d'utiliser un circuit à part, qui fait partie de l'unité de renommage, l'autre est d'intégrer les correspondances dans le ROB ou toute autre structure dédiée. Pr exemple, on peut ajouter la correspondance dans le ROB, dans le ''scheduler'', éventuellement dans le banc de registres renommés ! Dans ce qui suit, nous allons parler du cas où on utilise une mémoire à part, partie intégrante de l'unité de renommage de registre. Nous verrons l'intégration dans le ROB après, de même que la relation avec les quatre techniques précédentes. ===Renommer le registre de destination : la liste de disponibilité=== Renommer un registre de destination revient à lui attribuer un registre virtuel inutilisé. Pour cela, certaines techniques de renommage de registres mémorisent la liste des registres vides/disponibles dans une petite mémoire : la '''liste de disponibilités''' (''free list''). L'implémentation de la liste de disponibilité varie grandement d'un processeur à l'autre. Avec certaines méthodes de renommage de registre, qui impliquent un ROB, on peut même s'en passer totalement. Dans sa version la plus simple, elle contient un bit pour chaque registre, qui indique s'il est disponible ou non. Le bit en question est mis à jour quand une instruction entre/quitte le tampon de réordonnancement avec ce registre comme opérande. Lorsqu'un registre est attribué, il quitte la liste de disponibilités. Lorsque son instruction quitte le ROB, le bit de disponibilité est mis à jour. Une version plus évoluée utilise une mémoire FIFO qui contient des noms de registres. Le renommage du registre de destination utilise cette FIFO pour sortir le numéro de registre virtuel adéquat. Dans la suite, nous partirons du principe que c'est cette méthode qui est utilisée. Il faut noter que si le renommage est fait dans le ROB, la liste de disponibilité est inutile. La raison est que le ROB est déjà une mémoire FIFO, comme la liste de disponibilité. De plus, les registres virtuels sont dans le ROB. Attribuer un registre virtuel consiste simplement à mobiliser une entrée vide du ROB, en enfilant l'instruction dedans. Le ROB sait quelle est la prochaine entrée à allouer à une instruction émise, du fait de son caractère FIFO. ===La table de correspondances de registres=== Le renommage du registre de destination attribue un registre virtuel pour un résultat d'instruction. Reste qu'il faut maintenir cette attribution tant que l'instruction ne s'est pas terminée. Pendant toute la durée de vie de l'instruction, il faut se souvenir que tel registre virtuel correspond à tel résultat d'instruction, mais aussi à tel registre architectural. En effet, les instructions suivantes vont lire ce résultat pour l'utiliser comme opérande. Elle encoderont ce résultat/opérande avec le registre architectural censé contenir l'opérande. Le renommage de registre devra alors remplacer les registres opérande par le registre virtuel adéquat, qui contient l'opérande. Le renommage des registres opérande est le rôle de la '''table d’alias de registres''' (''register alias table''), une mémoire qui contient le registre virtuel associé à chaque registre architectural. Elle mémorise précisément une table de correspondance entre registre architectural et registre virtuel/physique. La table d'alias contient une correspondance par registre architectural, qui change au gré du renommage des instruction. De plus, elle contient un bit qui indique si le registre a été renommé ou non. S'il n'a pas été renommé, alors l'opérande est disponible dans les registres architecturaux, pas dans un registre virtuel. C'est très utile sur les processeurs avec un banc de registre séparés pour les registres architecturaux. Cela permet de savoir où lire les opérandes. La correspondance en question est mise à jour quand une instruction est émise, et quand elle termine. Premièrement, elle est mise à jour à chaque fois qu'un registre de destination est renommé. En clair, la table d’alias de registres est mise à jour à chaque lecture dans la table de disponibilité. Le registre virtuel choisi dans la liste de disponibilités est attribué au registre architectural de destination du résultat. Il suffira de réutiliser cette correspondance par la suite. Deuxièmement, elle est mise à jour quand une instruction termine, quand elle quitte le ROB. Le ROB envoie alors le numéro du registre virtuel qui contenait le résultat enregistré dans les registres architecturaux. Le numéro est alors enregistré dans la table de disponibilité. De plus, la correspondance associée dans la table d'alias est effacée. [[File:Renommage de registres - circuits.png|centre|vignette|upright=2|Unité de renommage de registres.]] Il existe deux façons pour implémenter la table d'alias. La plus ancienne consiste à utiliser une mémoire associative dont le tag contient le nom du registre architectural et la donnée le nom du registre physique. Sur les processeurs plus récents, on utilise une mémoire RAM, dont les adresses correspondent aux noms de registres architecturaux, et dont le contenu d'une adresse correspond au nom du registre physique associé. On n'a alors qu'une seule correspondance entre registre physique et registre architectural, mais cela ne pose pas de problème si on renomme les instructions dans l'ordre d'émission (ce qui est toujours fait). Notons que la table l'alias doit avoir deux ports de lecture : un pour chaque opérande. Et cela vaut peu importe son implémentation : le cache comme la RAM doivent avoir deux ports. ==L'interaction entre renommage de registres et autres optimisations== L'unité de renommage de registre ne fait pas que du renommage de registre, mais joue aussi un rôle dans l'exécution dans le désordre, et prend en charge des rôles annexes à son rôle principal. Par exemple, elle est impliquée pour corriger les mauvaises prédiction de branchement, les exceptions matérielle ou toute situation qui demande de vider le pipeline. En dehors de ces situations, un registre passe normalement par ces quatre état dans l'ordre disponible, réservé, écrit, architectural. Mais ce n'est pas le cas lors d'une mauvaise prédiction de branchement ou autre. Dans ce cas, tous les registres passent immédiatement à l'état disponible, sauf les registres architecturaux. ===La récupération après une prédiction invalide=== Quand une exception ou une mauvaise prédiction de branchement a lieu, les registres virtuels contiennent des données potentiellement invalides, contrairement aux registres architecturaux. En cas de mauvaise prédiction de branchement, la table d’alias de registres est partiellement vidée. Par vidée, on veut dire qu'on élimine les correspondances avec les registres virtuels invalidés. De plus, on doit remettre la table d’alias de registres et la table de disponibilités dans l'état antérieur au chargement de l'instruction qui a déclenché la mauvaise prédiction de branchement ou l'exception matérielle. Et cela peut se faire de différentes manières. La première solution s'applique au renommage dans le ROB. Il suffit de stocker dans le tampon de réordonnancement ce qui a été modifié dans l'unité de renommage de registres par l'instruction correspondante. Ainsi, lorsqu'une instruction sera prête à valider, et qu'une exception ou mauvaise prédiction de branchement aura eu lieu, les modifications effectuées dans l'unité de renommage de registres seront annulées les unes après les autres. Une autre solution consiste à garder un historique des changements fait dans la table d'alias. Lorsqu'une mauvais prédiction est détectée, le processeur traverse l'historique et annule les changements faits un par un. Le tout est assez lent, vu que la traversée se fait un renommage à la fois. Une optimisation utilise une copie valide de la table d’alias de registres dans une mémoire à part, pour la restaurer au besoin. Si jamais le processeur détecte un branchement, la table d’alias de registres est sauvegardée dans une mémoire intégrée au processeur. On peut utiliser plusieurs mémoires de sauvegarde de ce type, pour gérer une succession de branchements. ===La gestion des opérandes disponibles : "lecture avant émission" et "lecture après émission"=== Passons maintenant à un détail d'implémentation de l'exécution dans le désordre. La '''lecture après émission''' utilise des le ''schedulers'' basiques, alors que la '''lecture avant émission''' utilise des stations de réservation. Rappelons que la différence est que les premières émettent les instruction puis lisent les registres, alors que la seconde lit les opérandes depuis les registres juste après le renommage de registre, pour les stocker dans le ''scheduler''. La différence est donc que les étages sont répartis différemment. Avec la "lecture avant émission", l'étage de lecture des opérandes est placé entre l'étage de renommage de registres et l'étage d'émission. Avec la "lecture après émission", l'étage de lecture des registres est situé après l'étage d'émission/''select/wakeup''. Les deux méthodes de lecture avant ou après émission montrent une grande différence pour ce qui est de déterminer la disponibilité des opérandes. Pour la lecture après émission, le renommage de registre n'est pas impliqué. Mais avec la lecture avant émission, les opérandes sont lues dans les registres entre le renommage des registres et l'entrée dans la station de réservation. Ce qui implique qu'on sait quelles sont les opérandes disponibles lors du renommage de registres. Pour cela, l'unité de renommage de registre contient, pour chaque registre virtuel, un bit ''ready'' qui indique que le registre renommé contient une opérande est disponible. S'il est à 0, l'instruction est placée dans le ''scheduler'', et attend que ses opérandes soient disponibles. S'il est à 1, les opérandes sont soit lues dans le registre et placées dans le ''scheduler'', soit lues au moment d'exécuter l'instruction. L'ensemble de ces bits est en plus des bits de disponibilité de la station de réservation, dans l'implémentation la plus simple. Les deux sont alors mis à jour en même temps. Une autre solution regroupe les bits de disponibilité dans une structure matérielle appelée la '''table de disponibilité''', qui est consultée à la fois par les stations de réservation et l'unité de renommage de registres. L'avantage de cette solution est que les signaux de réveil sont envoyés à une seule structure matérielle, pas plus. De plus, il n'y a pas de duplication des bits de disponibilité. Non pas que quelques bits fassent une grosse différence, mais tout est bon à prendre. Notons qu'avec un banc de registres physique, le bit de disponibilité se déduit des quatre états que peut prendre un registre physique. L'unité de renommage de registre doit sait déjà quelles sont les opérandes indisponibles, celles qui ont déjà été calculées, et celles enregistrées dans un registre architectural. Notons qu'un registre virtuel, une fois attribué, peut être en état réservé ou écrit. Seul l'état écrit correspond à une opérande disponible, l'unité de renommage doit donc pouvoir faire la différence. Pour savoir si un registre virtuel contient une donnée valide, la table d’alias de registres lui associe un bit de validité qui est mis à jour lors de l'écriture du résultat dans le registre virtuel correspondant. Elle doit aussi mémoriser quels registres architecturaux ont une donnée valide. Rappelons que le processeur sait qu'une opérande est disponible parce qu'un signal de réveil est généré dans le pipeline, pour dire que telle opérande est disponible. Le signal transmet l'opérande avec le numéro de registre (virtuel ici). Le numéro de registre transmis est alors comparé avec tous les numéros de registre des opérandes, dans le ''scheduler'' et/ou les stations de réservation. Il est possible qu'une instruction soit dans l'étape de renommage alors que le signal de ''réveil'' est envoyé. Si rien n'est fait, l'instruction sera insérée dans le ''scheduler'' avec une opérande indisponible, alors qu'elle l'est. Elle restera alors indéfiniment dans le ''scheduler'', vu que le signal de ''réveil'' n'est généré qu'une seule fois. Pour éviter cela, le signal de ''réveil'' doit aussi être envoyé aux instructions dans l'unité de renommage de registre. Une solution pour éviter cela est d'enregistrer directement les noms de registres renommés dans le ''scheduler'', dès la sortie de l'unité de renommage. Les noms de registres sautent un étage de pipeline, donc. La comparaison avec les signaux de réveil se fait alors dans le ''scheduler'', pas besoin de rajouter un comparateur dans l'étage de lecture des registres. Une autre solution est d'utiliser une table de disponibilité unique. Les signaux de réveil ne sont alors pas perdus. ==Les optimisations liées au renommage de registres== Le renommage de registre permet d'implémenter certaines optimisations annexes, qu'on ne croirait pas reliées au renommage de registre au premier abord. Par exemple, saviez-vous que le renommage de registre permet d'exécuter certaines instructions directement dans l'unité de renommage ? De nombreuses optimisations éliminent certaines instructions, en les remplaçant par des renommages de registres. Il existe plusieurs optimisations de ce genre, qui portent les noms barbabres d'élimination des MOV, de calcul trivial, et de remplacement d'idiomes. ===L'élimination des MOV=== La première optimisation de ce genre élimine les instructions de copie d'un registre dans un autre (les MOV) ou d’échange entre deux registres (XCHG). Ce qui explique pourquoi l'optimisation en question porte le nom d''''élimination des MOV''' (''MOV elimination''), sous-entendu, des MOV inter-registres. L'élimination des MOV est une technique implémenté sur les processeurs à banc de registre physique. En clair, il faut qu'il y ait un seul banc de registre. C'est important, car c'est la seule méthode qui fait que les registres virtuels n'ont pas à être copiés dans les registres architecturaux, ce qui facilite grandement l'implémentation d’une technique visant à éliminer des copies de registres. L'idée est qu'après une copie, le contenu des deux registres source et destination est identique tant qu'aucun des deux registres ne subit d'écriture. On peut alors utiliser un seul registre physique pour la valeur mémorisée, toute lecture des deux registres lisant celui-ci. Lors d'une écriture dans un de ces deux registres, le renommage attribuera un nouveau registre physique pour la nouvelle valeur écrite. : Formellement, il s'agit d'une optimisation de type '''''copy-on-write'''''. ===Le remplacement d'idiomes=== Le même genre d'optimisation peut être effectué avec des instructions inutiles, dont le résultat vaut zéro. En effet, il existe de nombreuses méthodes pour mettre un registre à zéro. Faire un XOR entre le registre et lui-même, le soustraire à lui-même ou le multiplier par zéro sont quelques exemples. Et de tels idiomes sont utilisés par les compilateurs, au lieu d'un simple MOV 0 -> registre, qui copie un 0 dans le registre. La raison est que les instructions MOV sont assez longues, vu qu'elles doivent intégrer une constante immédiate. Le renommage de registres peut être utilisé pour éliminer ces opérations et les remplacer par une mise à zéro du registre. L'optimisation en question porte le nom de '''remplacement d'idiomes'''. Elle est implémentée depuis les processeurs Pentium de microarchitecture P6, et leurs équivalents AMD. Un autre avantage de cette optimisation est que cela casse de fausses chaines de dépendances. Par exemple, une opération "reg XOR reg" faire croire au processeur qu'il y a une dépendance de donnée entre cette instruction, et les instructions précédente qui écrivent dans le registre. Le XOR est donc exécuté après ces instructions faussement dépendantes, alors que la mise à zéro du registre pourrait se faire en parallèle en utilisant un registre virtuel séparé. Les techniques précédentes permettent d'éliminer ces fausses dépendances. ===Les optimisations de calculs triviaux=== Il existe aussi des opérations dont le résultat est une des opérandes. On pourrait citer comme exemples les décalages par 0, les additions et soustractions avec 0, la multiplication par 1, et bien d'autres. En utilisant intelligemment le renommage de registres, ces calculs ne sont pas effectués. Les techniques qui permettent cela sont des techniques dites de '''calcul trivial''' (trivial computation). La détection des calculs simplifiables demande de comparer les opérandes avec 0 ou 1, via un paquets de comparateurs regroupés dans une unité de détection des calculs triviaux. Leur simplification se fait dans la table de renommage de registres, le registre de destination de l'instruction simplifiée étant renommé pour pointer sur l'opérande/résultat. Si le résultat est nul, on considère que la correspondance est invalide et on met le registre physique à une valeur invalide, similaire au pointeur NULL du C. Si un calcul lit un registre physique invalide, celui-ci est automatiquement simplifié par l'unité de renommage, l'autre opérande étant alors attribué automatiquement comme registre de destination du résultat dans la table de renommage. Mais cette technique a tendance à modifier la latence des instructions, qui est réduite après simplification. Cela pose problème au niveau des circuits d'émission et du planificateur, qui n'aiment pas les latences variables, comme on l'a vu il y a quelques chapitres. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=L'exécution dans le désordre | prevText=L'exécution dans le désordre | next=Le scoreboarding et l'algorithme de Tomasulo | nextText=Le scoreboarding et l'algorithme de Tomasulo }} </noinclude> mxible06p47eydjyqnrjxk26yk1gu9f 773681 773617 2026-09-29T23:12:45Z Mewtow 31375 /* Le renommage de registre total et partiel */ 773681 wikitext text/x-wiki Pour améliorer l'exécution dans le désordre, les concepteurs de processeurs ont étudié des méthodes pour éliminer la grosse majorité des dépendances de données lors de l’exécution. Dans ce que j'ai dit précédemment, j'ai évoqué trois types de dépendances de données. Les dépendances RAW (''Read After Write'') sont des dépendances contre lesquelles on ne peut rien faire : ce sont de « vraies » dépendances de données. Elles imposent un certain ordre d’exécution de nos instructions. Mais les dépendances WAW (''write after write'') et WAR (''write after read'') sont de fausses dépendances, nées du fait qu'un emplacement mémoire est réutilisé, pour stocker des données différentes à des instants différents. Bien évidemment, l’imagination débridée des concepteurs de processeur a trouvé une solution pour supprimer ces dépendances : le '''renommage de registres'''. Avant toute chose, précisons que ce chapitre abordera uniquement les techniques compatibles avec les exceptions précises. En clair, seulement les techniques utilisées sur les processeurs modernes. Il existe deux autres techniques de renommage de registre utilisées sur les processeurs sans exceptions précises : l'algorithme de Tomasulo et le ''scoreboarding''. Contrairement à ce que vous avez pu lire ailleurs, il y a une forme de renommage de registre dans le ''scoreboarding'', mais nous verrons cela dans quelques chapitres. Toujours est-il que ces deux techniques historiques étaient utilisées sur d'anciens ordinateurs, qui n'implémentaient pas la prédiction de branchement. Leurs techniques de renommage de registres étaient particulières, aussi nous les verrons dans un chapitre à part. ==Le renommage de registres : généralités== Les dépendances WAR et WAW sont souvent opposées aux dépendances vraies (true dependency), à savoir les dépendances RAW. Les dépendances WAR et WAW viennent du fait qu'un même registre nommé est réutilisé plusieurs fois pour des données différentes. Un même nom de registre identifie une donnée différente à des instants différents du programme, ce qui force à exécuter les instructions qui utilisent ce registre dans l'ordre. D'où le fait que les dépendances WAR et WAW sont souvent appelées des dépendances de nom (''naming dependency''). Si on change l'ordre de deux instructions ayant une dépendance de données WAW ou WAR, on peut se retrouver dans une situation où les deux instructions veulent stocker des données différentes en même temps dans le même registre, ce qui n'est pas possible. Mais elles n'existeraient pas si on utilisait un registre pour chaque donnée, qui est écrit une fois, lu une ou plusieurs fois, mais jamais écrasé. Un même nom de registre correspond alors à une donnée. Une solution simple vient alors à l'esprit : conserver chaque donnée dans son propre registre et choisir le registre adéquat à l'utilisation. Un registre architectural correspond alors à plusieurs registres, chacun contenant une donnée bien précise. L'idée est qu'au lieu d'avoir un registre qui contient des données différentes à des instants différents, on a autant de registres que de données, ce qui améliore les possibilités de réorganisation des instructions. Il faut ainsi faire la distinction entre : * '''registres architecturaux''', définis par le jeu d'instructions ; * '''registres physiques''', physiquement présents dans l'ordinateur ; * '''registres virtuels''' utilisés pour le renommage de registre mais invisibles pour le programmeur. Les registres physiques regroupent l'ensemble des registres, à savoir les registres architecturaux et virtuels. Pour illustrer l'idée, prenons l'exemple suivant, où un registre architectural nommé R6 est utilisé pour stocker trois données consécutives. Il mémorise d'abord le nombre 255, puis le nombre 2567763, puis zéro. On suppose que ces trois valeurs sont indépendantes, dans le sens où elles sont utilisées par des instructions sans dépendances RAW. En théorie, on pourrait exécuter ces instructions séparément, mais ce n'est pas possible. Le fait est que l'on doit d'abord faire les calculs avec l'opérande 255, puis ceux avec l'opérande 2567763, puis ceux avec l'opérande zéro. La raison est que pour que le calcul démarre, il faut que l'opérande soit disponible. Et l’usage d'un seul registre pour stocker des opérandes différentes à des temps différents limite les possibilités d’exécution en parallèle. Avec le renommage de registres, ces trois données sont enregistrées dans des registres physiques séparés, dès qu'elles sont disponibles. Le processeur garde évidemment trace du fait que ces trois registres physiques correspondent au registre architectural R6. Si les trois valeurs n'ont pas de dépendances entre elles, les instructions liées peuvent être exécutées dans le désordre et s’exécuter en même temps. Ce qui est le cas dans le schéma suivant, où certaines instructions sont exécutées en avance, ce qui réserve les registres physiques en avance. [[File:Renommage de registres - principe.png|centre|vignette|upright=2|Exemple où un registre architectural est utilisé pour contenir trois données successives.]] : Pour les connaisseurs, le renommage de registres réécrit le programme exécuté dans une représentation appelée SSA, utilisée par les compilateurs lors de la compilation. Et cette réécriture se fait un peu de la même manière avec un compilateur. Là où le compilateur change le nom des variables pour passer en forme SSA, le processeur change les noms de registres pour obtenir de l'assembleur SSA interne au processeur. ===La durée de vie des registres virtuels=== La plupart des processeurs disposent d'un banc de registre physique unique, qui regroupe registres physiques et virtuels. Mais il existe quelques processeurs qui font autrement. Ils ont un banc de registre pour les registres architecturaux, et les registres virtuels sont placés ailleurs dans le processeur, typiquement dans le tampon de ré-ordonnancement (ROB) ou le ''scheduler''. Pour simplifier, considérons qu'ils sont dans un banc de registre spécialisé qui regroupe les registres virtuels. C'est un peu faux en soi, mais faisons comme si. Dans le reste de cette section, nous allons partir du principe que les registres virtuels et architecturaux sont séparés pour simplifier les explications, nous verrons les autres formes de renommage de registre plus tard. Les registres virtuels ont une certaine durée de vie. On veut dire par là qu'une donnée écrite dans un registre virtuel y reste durant un certain temps, mais pas indéfiniment. Un registre virtuel est utilisé par une instruction en cours d'exécution dans le pipeline. Il nait lors du renommage de registre et meurt une fois l'instruction terminée. En clair, un registre virtuel dure durant toutes les étapes du pipeline qui suivent le renommage de registres. Une fois que l'instruction quitte le pipeline, qu'elle sort du ROB, le registre virtuel est inutile et doit laisser la place au registre architectural non-renommé. Le résultat de l'instruction doit être transféré dans le registre architectural adéquat, le registre de destination de l'instruction. Si les registres virtuels et architecturaux sont séparés, il faut copier la donnée des registres virtuels vers les registres architecturaux. Utiliser un banc de registre unique résout le problème, mais n'allons pas trop vite, nous verrons cela en détail dans la suite. Toujours est-il qu'un registre virtuel est libéré quand l'instruction associée quitte le ROB. Il est théoriquement possible de libérer un registre virtuel en avance, si on est certain qu'aucune instruction n'ira lire ce registre. Pour cela, le mieux est d'attribuer un compteur de lectures pour chaque registre. À noter que pour maintenir des exceptions précises, on est obligé d'attendre que la dernière instruction qui lit le registre ait validé. Le jeu n'en vaut clairement pas la chandelle. Le seul intérêt d'une telle optimisation est économiser des registres virtuels, d'avoir un banc de registres virtuels plus petits, mais cela se fait au prix de l'ajout de circuits qui consomment tout autant, si ce n'est plus de circuits, pour un résultat en termes de performances limité, voire nul. Après avoir vu la mort des registres virtuels, voyons leur naissance. Le renommage de registre a lieu après le décodage, donc juste avant le passage dans le ''scoreboard'', le ''scheduler'', la file d'instruction ou toute autre structure dédiée à l'émission. En clair : les registres virtuels sont attribués juste avant émission et ne sont utiles qu'après. Les instructions susceptibles d'utiliser un registre virtuel sont donc les instructions émises ou prêtes à l'être, mais pas encore terminées. Les instructions en question sont soit en attente dans le ''scheduler'', soit en cours d'exécution dans le chemin de données, soit en attente dans le ROB. Ces dernières attendent que les instructions précédentes se terminent. Il faut noter que toutes les instructions émises ou en passe de l'être ont été ajoutées dans le ROB juste après le renommage. Même les instructions en attente dans le ''scheduler'' sont dans le ROB. Pour résumer, le ROB garde la trace de ces instructions prêtes à être émises ou déjà émises. ===Le nombre idéal de registres virtuels=== Mine de rien, le contenu de la section précédente nous donne une seconde borne maximale sur le nombre de registres virtuels utiles. Supposons que chaque instruction fournit un résultat, stocké dans un registre virtuel rien que pour lui. Le nombre maximal d'instructions chargées dans le pipeline après émission est égal au nombre d'entrée dans le ROB. Il peut y avoir moins d'instructions, ce qui fait que des entrées du ROB sont inutilisées, mais supposons que nous soyons dans le meilleur des cas. Dans ce cas, on doit avoir un registre virtuel par instruction, ce qui fait au maximum un registre virtuel par entrée du ROB. Rien ne sert d'avoir plus de registres virtuels que d'entrées dans le ROB, il n'y aura pas assez d’instructions dans le pipeline pour tous les utiliser. Après avoir vu une borne maximale, voyons une limite minimale. Non pas qu'il faille absolument plus de registres virtuels que cette limite, simplement qu'il est préférable d'en avoir que cette limite. Partons du principe que les instructions pouvant utiliser un registre virtuel sont celles qui sont soit déjà émises, soit en attente de l'être. Si on néglige les instructions en attente dans le ROB, alors les instructions émises sont dans les ALUs. Le nombre d'instruction est donc égal à la somme de : la taille du ''scheduler'' (instructions en attente), du nombre d'unités de calcul (instruction en cours d'exécution), unités d'accès mémoire inclues. Mieux vaut ne pas passer sous la somme taille du ''scheduler'' + nombre d'unités de calcul. Un bon compromis est d'avoir un nombre de registre virtuel compris entre ces deux bornes. Le nombre réel de registre virtuels est très souvent inférieur au nombre d'entrées du ROB, car toutes les instructions ne fournissent pas de résultat à enregistrer dans les registres. C'est le cas pour les instructions de branchement, par exemple, ou les écritures en mémoire RAM. Par contre, il vaut mieux avoir plus de registres que d'entrées dans le ''scheduler''. La majorité es processeurs respectent ces deux limites basse et hautes, avec un nombre de registres réels entre les deux. Les quelques rares exceptions étaient des processeurs qui implémentaient le renommage de registre pour la première fois, et où ce genre de détails n'étaient pas bien compris. Par exemple, on peut citer le PowerPC 604, qui avait 20 registres virtuels, alors que le ROB avait seulement 16 entrées. Les 4 registres virtuels en trop n'étaient pas utilisés. Le processeur qui a immédiatement suivi, le PowerPC 604, n'a pas fait cette erreur et a réduit le nombre de registres virtuels à seulement 16. Un autre exemple est le MIPS R10000, avec son ROB à 32 entrées, son ''scheduler'' a 48 entrées et ses 64 registres virtuels. Le processeur suivant, le R12000, corrigea partiellement le problème en augmentant le ROB à 48 entrées, ce qui était insuffisant, mais bienvenu. ===Le renommage des registres flottants et entiers=== De nombreux processeurs ont des registres architecturaux séparés pour les nombres flottants et entiers. Mais cela n'implique pas que le renommage de registre le soit. Les deux possibilités existent : une unité de renommage de registre partagée, ou au contraire deux unités de renommage séparées. Intel a tendance à utiliser la premireè solution sur ses processeurs aute performance, alors qu'AMD utilise la seconde solution. [[File:Zen microarchitecture.svg|centre|vignette|upright=2|Microarchitecture Zen 1 des CPU d'AMD.]] A ce propos, quelques rares processeurs ne renomment que que les registres flottants, ou que les registres entiers ! Pour donner un exemple, le processeur Nx586 ne renommait que les registres entiers, pour les instructions entières. Un autre exemple est celui de l'IBM System/360 Model 91, sur lequel les registres flottants étaient renommés, mais pas les registres entiers. Sur les CPU x86, lorsque le renommage de registre a été introduit, il ne concernait que les registres flottants. Ce choix s'explique par l'organisation en pile de registres liée au jeu d'instruction x87. Elle limitait grandement le parallélisme d'instruction, le renommage permettait de fortement limiter la casse. ===Le renommage de registre total et partiel=== Le renommage de registre peut être total ou partiel. Avec le '''renommage total''', toutes les instructions voient leurs registres renommés. Il s'agit de la méthode la plus utilisée à ce jour, par simplicité de conception. Mais des processeurs assez anciens utilisaient un '''renommage partiel''', qui ne s’appliquaient qu'à certains types d'instruction bien précis. Par exemple, on pourrait citer les processeurs Power1, Power2 et PowerPC 601. Sur le premier, les registres flottants étaient renommés seulement pour les instructions de lecture flottante. La raison est que le processeur n'a qu'une seule FPU, ce qui limite l'efficacité de l'exécution dans le désordre sur celle-ci, et fait que renommer les registres ne sert à rien. Le processeur Power 2 dispose lui de plusieurs FPU et le renommage de registres touche aussi les instructions flottantes arithmétiques, c'est un renommage total. Les processeur qui utilisaient le renommage partiel étaient des processeurs assez anciens, qui faisaient avec un budget en transistors limité. De plus, la technique n'était pas très bien maitrisée, et était encore balbutiante. La technique a pourtant été proposée dès 1970 dans divers articles académiques, et raffinée pendant les années 70. Mais le budget en transistors du renommage de registre a fait qu'elle n'a pas été utilisée avant que la loi de Moore fasse son œuvre. ==Les différentes implémentations du renommage de registres== Il existe plusieurs manières différentes d'implémenter le renommage de registre, que nous allons voir dans cette section. Mais avant toute chose, parlons du réseau de contournement. Pour simplifier les explications, appelons ''instruction productrice'' l'instruction qui fournit un résultat, et instruction consommatrice celle qui l'utilise comme opérande. Si une instruction consommatrice est chargée dans le pipeline quelques cycles après l'instruction productrice, les deux sont dans le pipeline en même temps. Dans ce cas, on pourrait penser que c'est le réseau de contournement qui gérerait le transfert du résultat de l'instruction productrice à l’instruction consommatrice. Et effectivement, c'est souvent le cas. Mais les registres virtuels sont pris en compte dans le système de contournement. Si le résultat est écrit dans un registre virtuel, il peut aussi être lu dans ce registre virtuel. Lire un résultat dans les registres virtuels permet d'implémenter une forme de contournement. Tout cela pour dire qu'il y a un lien entre contournement et renommage de registres, les deux doivent être conçu de manière à communiquer entre eux. Typiquement, il y a toujours un réseau de contournement pour connecter la sortie d'une ALU aux entrées des autres. Ce dernier gère le cas où un résultat d’instruction est réutilisé comme opérande au cycle suivant. Mais pour réutiliser un résultat deux cycles après ou plus tard, c'est le système de renommage de registres qui s'en charge. Ceci étant dit, nous allons étudier les implémentations principales du renommage de registre. Pour simplifier, il existe deux manières d'implémenter le renommage de registre. La première utilise deux bancs de registres : un pour les registres architecturaux, un autre pour les registres virtuels. Une autre implémentation regroupe registres virtuels et architecturaux dans un seul banc de registre. Mais d'autres implémentations font totalement autrement, en réutilisant les stations de réservation ou le tampon de ré-ordonnancement. Dans ce qui suit, nous allons nous concentrer sur les principales : le renommage à banc de registre physique, le renommage dans le ROB, le renommage à registres virtuels. Nous allons laisser de côté le renommage dans les stations de réservation pour une raison très simple : elle n'est pas compatible avec les exceptions précises. Nous la verrons dans un chapitre à part, portant sur le ''scoreboarding'' et l'algorithme de Tomasulo. ===Le renommage à banc de registres physiques=== Les processeurs modernes utilisent un seul banc de registres pour les registres architecturaux et virtuels, appelé '''banc de registres physiques''' (''physical register file''). Le tampon de réordonnancement et le ''scheduler'' contiennent des numéros de registres virtuels, des pointeurs vers les registres. Il y a toujours un réseau de contournement pour connecter la sortie d'une ALU aux entrées des autres, qui gère le cas où la sortie de l'ALU est utilisé comme opérande au cycle suivant. Mais pour réutiliser un résultat deux cycles après ou plus tard, c'est le banc de registres physiques qui s'en charge. Les opérandes viennent donc soit du banc de registres physique, soit du réseau de contournement. [[File:Renommage à banc de registres physiques.png|centre|vignette|upright=2|Renommage à banc de registres physiques.]] Avec ce système, un registre physique peut être dans quatre états. * Le premier état est celui d'un ''registre disponible'', près à servir de registre de destination. Par disponible, on veut dire que ce registre peut être réservé par l'unité de renommage, mais qu'il n'a pas encore été réservé. Ce n'est ni un registre virtuel, ni un registre architectural, juste un registre inutilisé. * Le second état est l'''état réservé'', celui d'un registre virtuel qui attend qu'une instruction écrive son résultat dedans. L'état réservé réserve un registre en écriture, mais interdit les lectures dedans. * Le troisième état est celui d'un registre virtuel dans lequel une instruction a écrit son résultat, mais l'instruction n'a pas encore quitté le ROB. Le registre est alors appelé un ''registre écrit''. * Enfin, le quatrième est celui d'un ''registre architectural'', qui contient une donnée valide, dans le sens où il n'est associé à aucune instruction dans le ROB. Un registre passe normalement par ces quatre états dans l'ordre disponible, virtuel réservé, virtuel écrit, architectural. Une fois que l'instruction attribuée quitte le ROB, le registre virtuel devient un registre architectural. Cependant, cela suppose que l'instruction quitte le ROB normalement, ce qui n'est pas le cas suite à une mauvaise prédiction de branchement ou autre. Dans ce cas, il repasse immédiatement à l'état disponible. L'unité de renommage des registre mémorise l'état de chaque registre pour savoir dans quel état il est. Avec ce système, les données ne sont pas déplacées, ce qui a un avantage en termes de performance, de consommation énergétique et de simplification des circuits du processeur. Une fois enregistrées dans un registre, les données ne se déplacent plus. Avec un banc de registre virtuel séparé, elles sont recopiées d'un banc de registre virtuel vers un banc de registre architectural. Et les autres techniques que nous allons voir ont le même problème. Un autre avantage est que les opérandes proviennent toutes du même endroit : le banc de registre unique. Avec un banc de registre séparés, les opérandes peuvent provenir soit des registres architecturaux, soit des registres virtuels. Les opérandes peuvent donc provenir du banc de registre architectural, mais aussi du banc de registre renommés. La conséquence est que la gestion des interconnexions est beaucoup plus compliquée, notamment quand on veut implémenter le contournement. Pas de problèmes de ce genre avec un banc de registre unique. ===Le renommage dans le tampon de réordonnancement=== Il est possible de faire le renommage dans le tampon de réordonnancement (ROB, pour ''ReOrder Buffer'')). Cela veut dire que les résultats des instructions sont mémorisés dans le tampon de réordonnancement. Les entrées du ROB se voient ajouter un champ pour mémoriser le résultat d'une instruction, et ce champ sert de registre virtuel. Les entrées du ROB deviennent ainsi adressables, elle ont un numéro, qui sert de numéro/nom de registre virtuel. Avec cette technique, les registres architecturaux sont séparés des registres virtuels inclus dans le ROB. Les registres architecturaux sont regroupés dans un banc de registres spécialisé, appelé le '''''retirement register file'''''. Le ''scheduler'' mémorise soit un nom de registre architectural, soit l'adresse de l'entrée du ROB qui contient le résultat voulu. Quand une instruction a tous ses opérandes de prêts, ceux-ci sont lus depuis le ROB ou les registres architecturaux. Pour cela, le ROB mémorise l'état de chaque entrée, de chaque registre virtuel : vide, réservée pour un résultat, écrite avec un résultat. [[File:Renommage dans le tampon de réordonnancement.png|centre|vignette|upright=2|Renommage dans le tampon de réordonnancement.]] Un défaut est que cela complexifie l'implémentation des interconnexions par rapport à un banc de registre physique. Il y a toujours un réseau de contournement pour réutiliser un résultat un cycle plus tard. Mais pour réutiliser un résultat deux cycles après ou plus tard, c'est le ROB qui s'en charge. Les opérandes peuvent être lues depuis trois sources : le ROB, le banc de registre architectural, et le réseau de contournement. Soit une source de plus qu'avec la technique précédente, ce qui complexifie les multiplexeurs de contournement. Et cela a un effet sur la latence des opérations, le temps de traversée de ces multiplexeurs n'est pas gratuit, sans compter le temps mis pour les signaux de commande pour les configurer. Le renommage de registre est aussi plus compliqué. Au lieu de simplement remplacer un numéro de registre architectural par un numéro de registre physique, on doit faire la différence entre numéro de registre et adresse dans le ROB, pour savoir où lire les opérandes. Sans quoi ne sait pas configurer les multiplexeurs et choisir la bonne source pour les opérandes. Un autre défaut est que les registres virtuels doivent être copiés dans les registres architecturaux quand une instruction quitte le ROB. La copie se fait ici du ROB vers le banc de registre architectural. Et copier la donnée a un cout en énergie que l'usage d'un banc de registre unique n'a pas. Un dernier défaut est que le nombre de registres virtuel est égal au nombre d'entrées dans le ROB. Or, on a vu plus haut que c'est un peu du gâchis, car beaucoup d'instructions ne produisent aucun résultat. Le hardware ajouté pour les entrées est donc sous-utilisé, il ne sert que si l'instruction fournit un résultat, mais ne sert à rien sinon. ===Le renommage avec un tampon de renommage=== Le dernier défaut évoqué dit que beaucoup d'entrées du ROB sont inutilisées et que les registres virtuels associés sont gâchés. Pour éviter cela, il est possible de sortir les résultats d'instruction du ROB et de les placer dans une mémoire FIFO complémentaire du ROB, appelée le '''tampon de renommage'''. Pour le dire autrement, le ROB amélioré est scindé en deux, avec le ROB proprement dit d'un côté, et un pseudo-ROB pour le renommage de registres et le contournement. Pour information, cette technique de renommage était utilisée dans d'anciens processeurs commerciaux, comme les Pentium Pro, le Pentium II, ou encore le Pentium III, ainsi que dans le Core 2 Duo. La technique est souvent expliquée en décrivant le tampon de renommage comme un banc de registre séparé pour les registres virtuels, appelé le '''banc de registres renommés''' (''rename register file''). Il est séparé du banc de registres architecturaux, avec lequel il communique. La raison à cela est que le tampon de renommage est adressable alors que le ROB ne l'est pas. Il faut dire que le tampon de renommage a tout d'un banc de registre : il contient les registres virtuels et seulement ceux-ci, on peut l'adresser, lire des opérandes dedans, écrire des résultats dedans, etc. Par contre, il y a une différence avec un banc de registre normal : il est traité comme une mémoire FIFO. Nous avons déjà vu comment implémenter une FIFO avec un banc de registre et quelques registres, aussi je ne fais pas de rappels sur ce point. S'il s'agissait d'un véritable banc de registre isolé, sans rien de plus, le ROB et le ''scheduler'' contiendraient des numéros de registres virtuels, qui adressent directement le banc de registre renommé. Une telle implémentation est possible, mais aucun processeur commercial n'a utilisé une telle implémentation. À la place, le banc de registre est en réalité une mémoire FIFO, dont les entrées sont adressables, avec de plus un système de cache utilisé pour faire la correspondance entre nom de registre architectural et nom de registre virtuel. Nous détaillerons ce dernier point dans la section qui explique comment fonctionne l'unité de renommage. Une fois que l'instruction attribuée quitte le ROB, le registre virtuel est libéré, à savoir qu'il repasse en état disponible. C'est à ce moment qu'à lieu la copie de la donnée dans le registre architectural adéquat. Il faut noter que le registre virtuel n'est pas effacé, il contient toujours l'ancienne donnée. Mais ce n'est pas un problème. S'il est réservé par une instruction, elle écrira dedans, ce qui écrasera cette donnée. Et de manière générale, il est impossible de lire cette donnée, que ce soit si le registre est disponible ou réservé. [[File:Renommage à banc de registres renommés.png|centre|vignette|upright=2|Renommage à banc de registres renommés.]] La technique partage tous les défauts du renommage dans le ROB. Le réseau de contournement est plus compliqué car les opérandes peuvent venir de trois sources : les deux bancs de registres et le réseau de contournement. De plus, les registres virtuels doivent être copiés dans les registres architecturaux, avec tout ce que cela implique. Déjà, déplacer des données implique un cout en énergie et en consommation d'électricité, qu'il vaut mieux éviter. De plus, il faut ajouter un port de lecture sur le banc de registre renommés, pour copier un registre sans nuire aux performances. Le banc de registres physiques n'a pas à être modifié : le port d'écriture existant suffit pour la copie, vu qu'on n'écrit dedans que pour copier des résultats d'instructions validées/terminées. Par contre, le cout en transistors est plus faible qu'avec le renommage dans le ROB, vu que le banc de registre a moins de registres virtuels que le ROB. La technique n'impose pas d'avoir autant de registres virtuels que d'entrées dans le ROB, ce qui permet d'en réduire le nombre. Par contre, comparé à l'usage d'un banc de registres unique, le cout en transistors est plus élevé. La différence se fait surtout au niveau des ports de lecture/écriture du banc de registres. La raison est que l'on doit ajouter un port de lecture pour copier les résultats dans les registres architecturaux. Du moins, dans le cas le plus simple. C'est le cas sur un processeur qui permet de compléter l'exécution d'une instruction par cycle. Mais certains processeurs peuvent terminer l'exécution de plusieurs instructions par cycle. C'est notamment le cas des processeurs dits superscalaires, qui sont capables de charger, exécuter et terminer plusieurs instructions par cycle. Ils auront droit à leur chapitre dédié, mais passons. Toujours est-il que si plusieurs instructions peuvent se terminer en même temps, il faut ajouter autant de ports de lecture sur le banc de registre pour copier leurs résultats. ===Le renommage physique-virtuel=== Les méthodes mentionnées au-dessus ont un léger problème : beaucoup de registres physiques sont gâchés, car attribués à une instruction dès l'étage de renommage et libérés lorsque on est certain qu'aucune instruction ne lira le registre physique attribué. Et parfois, les registres sont alloués trop tôt, alors qu'ils auraient pu rester libres durant encore quelques cycles. C'est notamment le cas quand l'instruction renommée attend un opérande dans le ''scheduler'', ou quand le résultat est en cours de calcul dans l'unité de calcul. Ces situations ont toutes la même origine : le renommage a lieu tôt dans le pipeline, pour garder les dépendances entre instructions. Mais dans les faits, rien n'oblige à utiliser les registres architecturaux pour conserver les dépendances. On peut tout simplement attribuer un tag à chaque résultat d'instruction, tag qui ne correspond pas à un registre architectural. Et ce tag sera alloué à un registre architectural le plus tard possible, quand l'instruction fournira son résultat. Ce genre de méthodes a été formalisée avec ce qu'on appelle la technique du '''banc de registres physiques-virtuels''' (physical-virtual register file). Cette méthode demande d'ajouter une seconde table de correspondance, qui fait le lien entre le tag et le registre physique. De plus, la table d’alias de registres doit être modifiée : elle ne doit pas seulement faire la correspondance entre le nom de registre et le tag, mais aussi avec le registre physique s'il est déjà attribué. Ainsi, lors du renommage en sortie du décodeur, on peut renommer l'instruction avec les registres physiques si ceux-ci sont connus lors du renommage, et renommer avec des tags dans le cas contraire. Il faut noter que cette méthode a un léger problème : quand une instruction termine et que le résultat doit se voir attribuer un tag, il se peut parfaitement qu'il n'y ait plus de registre physique de libre. Les solutions pour régler ce problème sont assez complexes, aussi je n'en parlerai pas ici. ==L’unité de renommage== Pour commencer, sachez qu'il existe deux méthodes pour implémenter l'unité de renommage. La première utilise une unité à part, séparées, qui contient de nombreuses mémoires caches/FIFO pour stocker des informations nécessaires pour le renommage de registres. La seconde mémorise les informations de renommage dans le ROB ou le tampon de renommage, voir ailleurs. Les deux types d'unités de renommage sont assez différentes. Pour les désigner, je vais parler d''''implémentation par ''tag''''' et d''''implémentation associative'''. De plus, les deux types d'unités ne sont pas utilisées sur les mêmes implémentations. Par exemple, avec un banc de registre physique, il est naturel d'utiliser une implémentation par ''tag'', l'autre implémentation n'est pas pratique. Aussi, tous les processeurs avec un banc de registre physique utilisent une unité de renommage pat ''tag''. Mais pour le renommage dans le ROB, c'est l'inverse : les deux implémentations sont possibles, mais il est préférable d'utiliser une implémentation associative. Pour simplifier les explications, je vais commencer par décrire le premier type, avec un banc de registre physique. {|class="wikitable" |- ! ! Implémentation par ''tag'' ! Implémentation associative |- ! Banc de registre physique | Seule implémentation possible | |- ! Renommage dans le ROB | Possible, certains processeurs utilisent la technique | Possible, certains processeurs utilisent la technique |- ! Renommage dans un tampon de renommage | Possible, tous les processeurs utilisent la technique | Possible, aucun processeur connu |} ===Les unités de renommage par ''tag''=== Les registres architecturaux sont identifiés par des noms de registre, tout comme les registres physiques. Les noms de registre des registres physiques sont appelés des '''tags'''. Les registres physiques sont bien plus nombreux que les registres architecturaux, sans quoi le renommage de registre n'a aucun intérêt. La conséquence est que les numéros de registres physiques sont plus grands que les numéros de registres architecturaux. Le renommage de registres remplace les noms/numéros de registres architecturaux par des numéros de registres physiques, par des ''tags''. D'où le terme de ''renommage'' de registre. Ce remplacement est effectué dans un étage supplémentaire du pipeline, intercalé entre le décodage et l'émission. [[File:Renommage de registres.png|centre|vignette|upright=2|Renommage de registres.]] Le remplacement se fait cependant différemment pour le registre de destination et les registres d'opérandes. Le registre de destination est associé à un registre virtuel disponible. L'allocation du registre de destination prend un registre disponible et le place en état réservé. Une nouvelle correspondance entre registre architectural et virtuel est alors crée. Mais pour les opérandes, c'est autre chose. Les opérandes sont soit dans un registre architectural, soit dans un registre virtuel en état écrit. Les noms de registres architecturaux pour les opérandes doivent être remplacé par le nom de registre adéquat, déjà attribué. Une sacrée différence : on attribue un registre virtuel pour le résultat, les opérandes ont déjà un registre virtuel attribué. Un autre point est que l'unité de renommage ne fait pas que modifier les registres opérande/de destination. Elle gère aussi la disponibilité des opérandes. Plus haut, on a dit qu'un registre virtuel pouvait être dans quatre états. Soit il est disponible, soit il est réservé, soit il est écrit, soit la donnée est dans un registre architectural. L'unité de renommage est au courant de l'état de chaque registre. Les quatre états possibles sont utilisés pour diverses raisons. Et il y a deux manières pour mémoriser la correspondance entre un registre physique et un registre architectural. La première est d'utiliser un circuit à part, qui fait partie de l'unité de renommage, l'autre est d'intégrer les correspondances dans le ROB ou toute autre structure dédiée. Pr exemple, on peut ajouter la correspondance dans le ROB, dans le ''scheduler'', éventuellement dans le banc de registres renommés ! Dans ce qui suit, nous allons parler du cas où on utilise une mémoire à part, partie intégrante de l'unité de renommage de registre. Nous verrons l'intégration dans le ROB après, de même que la relation avec les quatre techniques précédentes. ===Renommer le registre de destination : la liste de disponibilité=== Renommer un registre de destination revient à lui attribuer un registre virtuel inutilisé. Pour cela, certaines techniques de renommage de registres mémorisent la liste des registres vides/disponibles dans une petite mémoire : la '''liste de disponibilités''' (''free list''). L'implémentation de la liste de disponibilité varie grandement d'un processeur à l'autre. Avec certaines méthodes de renommage de registre, qui impliquent un ROB, on peut même s'en passer totalement. Dans sa version la plus simple, elle contient un bit pour chaque registre, qui indique s'il est disponible ou non. Le bit en question est mis à jour quand une instruction entre/quitte le tampon de réordonnancement avec ce registre comme opérande. Lorsqu'un registre est attribué, il quitte la liste de disponibilités. Lorsque son instruction quitte le ROB, le bit de disponibilité est mis à jour. Une version plus évoluée utilise une mémoire FIFO qui contient des noms de registres. Le renommage du registre de destination utilise cette FIFO pour sortir le numéro de registre virtuel adéquat. Dans la suite, nous partirons du principe que c'est cette méthode qui est utilisée. Il faut noter que si le renommage est fait dans le ROB, la liste de disponibilité est inutile. La raison est que le ROB est déjà une mémoire FIFO, comme la liste de disponibilité. De plus, les registres virtuels sont dans le ROB. Attribuer un registre virtuel consiste simplement à mobiliser une entrée vide du ROB, en enfilant l'instruction dedans. Le ROB sait quelle est la prochaine entrée à allouer à une instruction émise, du fait de son caractère FIFO. ===La table de correspondances de registres=== Le renommage du registre de destination attribue un registre virtuel pour un résultat d'instruction. Reste qu'il faut maintenir cette attribution tant que l'instruction ne s'est pas terminée. Pendant toute la durée de vie de l'instruction, il faut se souvenir que tel registre virtuel correspond à tel résultat d'instruction, mais aussi à tel registre architectural. En effet, les instructions suivantes vont lire ce résultat pour l'utiliser comme opérande. Elle encoderont ce résultat/opérande avec le registre architectural censé contenir l'opérande. Le renommage de registre devra alors remplacer les registres opérande par le registre virtuel adéquat, qui contient l'opérande. Le renommage des registres opérande est le rôle de la '''table d’alias de registres''' (''register alias table''), une mémoire qui contient le registre virtuel associé à chaque registre architectural. Elle mémorise précisément une table de correspondance entre registre architectural et registre virtuel/physique. La table d'alias contient une correspondance par registre architectural, qui change au gré du renommage des instruction. De plus, elle contient un bit qui indique si le registre a été renommé ou non. S'il n'a pas été renommé, alors l'opérande est disponible dans les registres architecturaux, pas dans un registre virtuel. C'est très utile sur les processeurs avec un banc de registre séparés pour les registres architecturaux. Cela permet de savoir où lire les opérandes. La correspondance en question est mise à jour quand une instruction est émise, et quand elle termine. Premièrement, elle est mise à jour à chaque fois qu'un registre de destination est renommé. En clair, la table d’alias de registres est mise à jour à chaque lecture dans la table de disponibilité. Le registre virtuel choisi dans la liste de disponibilités est attribué au registre architectural de destination du résultat. Il suffira de réutiliser cette correspondance par la suite. Deuxièmement, elle est mise à jour quand une instruction termine, quand elle quitte le ROB. Le ROB envoie alors le numéro du registre virtuel qui contenait le résultat enregistré dans les registres architecturaux. Le numéro est alors enregistré dans la table de disponibilité. De plus, la correspondance associée dans la table d'alias est effacée. [[File:Renommage de registres - circuits.png|centre|vignette|upright=2|Unité de renommage de registres.]] Il existe deux façons pour implémenter la table d'alias. La plus ancienne consiste à utiliser une mémoire associative dont le tag contient le nom du registre architectural et la donnée le nom du registre physique. Sur les processeurs plus récents, on utilise une mémoire RAM, dont les adresses correspondent aux noms de registres architecturaux, et dont le contenu d'une adresse correspond au nom du registre physique associé. On n'a alors qu'une seule correspondance entre registre physique et registre architectural, mais cela ne pose pas de problème si on renomme les instructions dans l'ordre d'émission (ce qui est toujours fait). Notons que la table l'alias doit avoir deux ports de lecture : un pour chaque opérande. Et cela vaut peu importe son implémentation : le cache comme la RAM doivent avoir deux ports. ==L'interaction entre renommage de registres et autres optimisations== L'unité de renommage de registre ne fait pas que du renommage de registre, mais joue aussi un rôle dans l'exécution dans le désordre, et prend en charge des rôles annexes à son rôle principal. Par exemple, elle est impliquée pour corriger les mauvaises prédiction de branchement, les exceptions matérielle ou toute situation qui demande de vider le pipeline. En dehors de ces situations, un registre passe normalement par ces quatre état dans l'ordre disponible, réservé, écrit, architectural. Mais ce n'est pas le cas lors d'une mauvaise prédiction de branchement ou autre. Dans ce cas, tous les registres passent immédiatement à l'état disponible, sauf les registres architecturaux. ===La récupération après une prédiction invalide=== Quand une exception ou une mauvaise prédiction de branchement a lieu, les registres virtuels contiennent des données potentiellement invalides, contrairement aux registres architecturaux. En cas de mauvaise prédiction de branchement, la table d’alias de registres est partiellement vidée. Par vidée, on veut dire qu'on élimine les correspondances avec les registres virtuels invalidés. De plus, on doit remettre la table d’alias de registres et la table de disponibilités dans l'état antérieur au chargement de l'instruction qui a déclenché la mauvaise prédiction de branchement ou l'exception matérielle. Et cela peut se faire de différentes manières. La première solution s'applique au renommage dans le ROB. Il suffit de stocker dans le tampon de réordonnancement ce qui a été modifié dans l'unité de renommage de registres par l'instruction correspondante. Ainsi, lorsqu'une instruction sera prête à valider, et qu'une exception ou mauvaise prédiction de branchement aura eu lieu, les modifications effectuées dans l'unité de renommage de registres seront annulées les unes après les autres. Une autre solution consiste à garder un historique des changements fait dans la table d'alias. Lorsqu'une mauvais prédiction est détectée, le processeur traverse l'historique et annule les changements faits un par un. Le tout est assez lent, vu que la traversée se fait un renommage à la fois. Une optimisation utilise une copie valide de la table d’alias de registres dans une mémoire à part, pour la restaurer au besoin. Si jamais le processeur détecte un branchement, la table d’alias de registres est sauvegardée dans une mémoire intégrée au processeur. On peut utiliser plusieurs mémoires de sauvegarde de ce type, pour gérer une succession de branchements. ===La gestion des opérandes disponibles : "lecture avant émission" et "lecture après émission"=== Passons maintenant à un détail d'implémentation de l'exécution dans le désordre. La '''lecture après émission''' utilise des le ''schedulers'' basiques, alors que la '''lecture avant émission''' utilise des stations de réservation. Rappelons que la différence est que les premières émettent les instruction puis lisent les registres, alors que la seconde lit les opérandes depuis les registres juste après le renommage de registre, pour les stocker dans le ''scheduler''. La différence est donc que les étages sont répartis différemment. Avec la "lecture avant émission", l'étage de lecture des opérandes est placé entre l'étage de renommage de registres et l'étage d'émission. Avec la "lecture après émission", l'étage de lecture des registres est situé après l'étage d'émission/''select/wakeup''. Les deux méthodes de lecture avant ou après émission montrent une grande différence pour ce qui est de déterminer la disponibilité des opérandes. Pour la lecture après émission, le renommage de registre n'est pas impliqué. Mais avec la lecture avant émission, les opérandes sont lues dans les registres entre le renommage des registres et l'entrée dans la station de réservation. Ce qui implique qu'on sait quelles sont les opérandes disponibles lors du renommage de registres. Pour cela, l'unité de renommage de registre contient, pour chaque registre virtuel, un bit ''ready'' qui indique que le registre renommé contient une opérande est disponible. S'il est à 0, l'instruction est placée dans le ''scheduler'', et attend que ses opérandes soient disponibles. S'il est à 1, les opérandes sont soit lues dans le registre et placées dans le ''scheduler'', soit lues au moment d'exécuter l'instruction. L'ensemble de ces bits est en plus des bits de disponibilité de la station de réservation, dans l'implémentation la plus simple. Les deux sont alors mis à jour en même temps. Une autre solution regroupe les bits de disponibilité dans une structure matérielle appelée la '''table de disponibilité''', qui est consultée à la fois par les stations de réservation et l'unité de renommage de registres. L'avantage de cette solution est que les signaux de réveil sont envoyés à une seule structure matérielle, pas plus. De plus, il n'y a pas de duplication des bits de disponibilité. Non pas que quelques bits fassent une grosse différence, mais tout est bon à prendre. Notons qu'avec un banc de registres physique, le bit de disponibilité se déduit des quatre états que peut prendre un registre physique. L'unité de renommage de registre doit sait déjà quelles sont les opérandes indisponibles, celles qui ont déjà été calculées, et celles enregistrées dans un registre architectural. Notons qu'un registre virtuel, une fois attribué, peut être en état réservé ou écrit. Seul l'état écrit correspond à une opérande disponible, l'unité de renommage doit donc pouvoir faire la différence. Pour savoir si un registre virtuel contient une donnée valide, la table d’alias de registres lui associe un bit de validité qui est mis à jour lors de l'écriture du résultat dans le registre virtuel correspondant. Elle doit aussi mémoriser quels registres architecturaux ont une donnée valide. Rappelons que le processeur sait qu'une opérande est disponible parce qu'un signal de réveil est généré dans le pipeline, pour dire que telle opérande est disponible. Le signal transmet l'opérande avec le numéro de registre (virtuel ici). Le numéro de registre transmis est alors comparé avec tous les numéros de registre des opérandes, dans le ''scheduler'' et/ou les stations de réservation. Il est possible qu'une instruction soit dans l'étape de renommage alors que le signal de ''réveil'' est envoyé. Si rien n'est fait, l'instruction sera insérée dans le ''scheduler'' avec une opérande indisponible, alors qu'elle l'est. Elle restera alors indéfiniment dans le ''scheduler'', vu que le signal de ''réveil'' n'est généré qu'une seule fois. Pour éviter cela, le signal de ''réveil'' doit aussi être envoyé aux instructions dans l'unité de renommage de registre. Une solution pour éviter cela est d'enregistrer directement les noms de registres renommés dans le ''scheduler'', dès la sortie de l'unité de renommage. Les noms de registres sautent un étage de pipeline, donc. La comparaison avec les signaux de réveil se fait alors dans le ''scheduler'', pas besoin de rajouter un comparateur dans l'étage de lecture des registres. Une autre solution est d'utiliser une table de disponibilité unique. Les signaux de réveil ne sont alors pas perdus. ==Les optimisations liées au renommage de registres== Le renommage de registre permet d'implémenter certaines optimisations annexes, qu'on ne croirait pas reliées au renommage de registre au premier abord. Par exemple, saviez-vous que le renommage de registre permet d'exécuter certaines instructions directement dans l'unité de renommage ? De nombreuses optimisations éliminent certaines instructions, en les remplaçant par des renommages de registres. Il existe plusieurs optimisations de ce genre, qui portent les noms barbabres d'élimination des MOV, de calcul trivial, et de remplacement d'idiomes. ===L'élimination des MOV=== La première optimisation de ce genre élimine les instructions de copie d'un registre dans un autre (les MOV) ou d’échange entre deux registres (XCHG). Ce qui explique pourquoi l'optimisation en question porte le nom d''''élimination des MOV''' (''MOV elimination''), sous-entendu, des MOV inter-registres. L'élimination des MOV est une technique implémenté sur les processeurs à banc de registre physique. En clair, il faut qu'il y ait un seul banc de registre. C'est important, car c'est la seule méthode qui fait que les registres virtuels n'ont pas à être copiés dans les registres architecturaux, ce qui facilite grandement l'implémentation d’une technique visant à éliminer des copies de registres. L'idée est qu'après une copie, le contenu des deux registres source et destination est identique tant qu'aucun des deux registres ne subit d'écriture. On peut alors utiliser un seul registre physique pour la valeur mémorisée, toute lecture des deux registres lisant celui-ci. Lors d'une écriture dans un de ces deux registres, le renommage attribuera un nouveau registre physique pour la nouvelle valeur écrite. : Formellement, il s'agit d'une optimisation de type '''''copy-on-write'''''. ===Le remplacement d'idiomes=== Le même genre d'optimisation peut être effectué avec des instructions inutiles, dont le résultat vaut zéro. En effet, il existe de nombreuses méthodes pour mettre un registre à zéro. Faire un XOR entre le registre et lui-même, le soustraire à lui-même ou le multiplier par zéro sont quelques exemples. Et de tels idiomes sont utilisés par les compilateurs, au lieu d'un simple MOV 0 -> registre, qui copie un 0 dans le registre. La raison est que les instructions MOV sont assez longues, vu qu'elles doivent intégrer une constante immédiate. Le renommage de registres peut être utilisé pour éliminer ces opérations et les remplacer par une mise à zéro du registre. L'optimisation en question porte le nom de '''remplacement d'idiomes'''. Elle est implémentée depuis les processeurs Pentium de microarchitecture P6, et leurs équivalents AMD. Un autre avantage de cette optimisation est que cela casse de fausses chaines de dépendances. Par exemple, une opération "reg XOR reg" faire croire au processeur qu'il y a une dépendance de donnée entre cette instruction, et les instructions précédente qui écrivent dans le registre. Le XOR est donc exécuté après ces instructions faussement dépendantes, alors que la mise à zéro du registre pourrait se faire en parallèle en utilisant un registre virtuel séparé. Les techniques précédentes permettent d'éliminer ces fausses dépendances. ===Les optimisations de calculs triviaux=== Il existe aussi des opérations dont le résultat est une des opérandes. On pourrait citer comme exemples les décalages par 0, les additions et soustractions avec 0, la multiplication par 1, et bien d'autres. En utilisant intelligemment le renommage de registres, ces calculs ne sont pas effectués. Les techniques qui permettent cela sont des techniques dites de '''calcul trivial''' (trivial computation). La détection des calculs simplifiables demande de comparer les opérandes avec 0 ou 1, via un paquets de comparateurs regroupés dans une unité de détection des calculs triviaux. Leur simplification se fait dans la table de renommage de registres, le registre de destination de l'instruction simplifiée étant renommé pour pointer sur l'opérande/résultat. Si le résultat est nul, on considère que la correspondance est invalide et on met le registre physique à une valeur invalide, similaire au pointeur NULL du C. Si un calcul lit un registre physique invalide, celui-ci est automatiquement simplifié par l'unité de renommage, l'autre opérande étant alors attribué automatiquement comme registre de destination du résultat dans la table de renommage. Mais cette technique a tendance à modifier la latence des instructions, qui est réduite après simplification. Cela pose problème au niveau des circuits d'émission et du planificateur, qui n'aiment pas les latences variables, comme on l'a vu il y a quelques chapitres. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=L'exécution dans le désordre | prevText=L'exécution dans le désordre | next=Le scoreboarding et l'algorithme de Tomasulo | nextText=Le scoreboarding et l'algorithme de Tomasulo }} </noinclude> impbwt4h6di2eosmrb0g4ksrwj12d52 773682 773681 2026-09-29T23:13:55Z Mewtow 31375 /* Le renommage des registres flottants et entiers */ 773682 wikitext text/x-wiki Pour améliorer l'exécution dans le désordre, les concepteurs de processeurs ont étudié des méthodes pour éliminer la grosse majorité des dépendances de données lors de l’exécution. Dans ce que j'ai dit précédemment, j'ai évoqué trois types de dépendances de données. Les dépendances RAW (''Read After Write'') sont des dépendances contre lesquelles on ne peut rien faire : ce sont de « vraies » dépendances de données. Elles imposent un certain ordre d’exécution de nos instructions. Mais les dépendances WAW (''write after write'') et WAR (''write after read'') sont de fausses dépendances, nées du fait qu'un emplacement mémoire est réutilisé, pour stocker des données différentes à des instants différents. Bien évidemment, l’imagination débridée des concepteurs de processeur a trouvé une solution pour supprimer ces dépendances : le '''renommage de registres'''. Avant toute chose, précisons que ce chapitre abordera uniquement les techniques compatibles avec les exceptions précises. En clair, seulement les techniques utilisées sur les processeurs modernes. Il existe deux autres techniques de renommage de registre utilisées sur les processeurs sans exceptions précises : l'algorithme de Tomasulo et le ''scoreboarding''. Contrairement à ce que vous avez pu lire ailleurs, il y a une forme de renommage de registre dans le ''scoreboarding'', mais nous verrons cela dans quelques chapitres. Toujours est-il que ces deux techniques historiques étaient utilisées sur d'anciens ordinateurs, qui n'implémentaient pas la prédiction de branchement. Leurs techniques de renommage de registres étaient particulières, aussi nous les verrons dans un chapitre à part. ==Le renommage de registres : généralités== Les dépendances WAR et WAW sont souvent opposées aux dépendances vraies (true dependency), à savoir les dépendances RAW. Les dépendances WAR et WAW viennent du fait qu'un même registre nommé est réutilisé plusieurs fois pour des données différentes. Un même nom de registre identifie une donnée différente à des instants différents du programme, ce qui force à exécuter les instructions qui utilisent ce registre dans l'ordre. D'où le fait que les dépendances WAR et WAW sont souvent appelées des dépendances de nom (''naming dependency''). Si on change l'ordre de deux instructions ayant une dépendance de données WAW ou WAR, on peut se retrouver dans une situation où les deux instructions veulent stocker des données différentes en même temps dans le même registre, ce qui n'est pas possible. Mais elles n'existeraient pas si on utilisait un registre pour chaque donnée, qui est écrit une fois, lu une ou plusieurs fois, mais jamais écrasé. Un même nom de registre correspond alors à une donnée. Une solution simple vient alors à l'esprit : conserver chaque donnée dans son propre registre et choisir le registre adéquat à l'utilisation. Un registre architectural correspond alors à plusieurs registres, chacun contenant une donnée bien précise. L'idée est qu'au lieu d'avoir un registre qui contient des données différentes à des instants différents, on a autant de registres que de données, ce qui améliore les possibilités de réorganisation des instructions. Il faut ainsi faire la distinction entre : * '''registres architecturaux''', définis par le jeu d'instructions ; * '''registres physiques''', physiquement présents dans l'ordinateur ; * '''registres virtuels''' utilisés pour le renommage de registre mais invisibles pour le programmeur. Les registres physiques regroupent l'ensemble des registres, à savoir les registres architecturaux et virtuels. Pour illustrer l'idée, prenons l'exemple suivant, où un registre architectural nommé R6 est utilisé pour stocker trois données consécutives. Il mémorise d'abord le nombre 255, puis le nombre 2567763, puis zéro. On suppose que ces trois valeurs sont indépendantes, dans le sens où elles sont utilisées par des instructions sans dépendances RAW. En théorie, on pourrait exécuter ces instructions séparément, mais ce n'est pas possible. Le fait est que l'on doit d'abord faire les calculs avec l'opérande 255, puis ceux avec l'opérande 2567763, puis ceux avec l'opérande zéro. La raison est que pour que le calcul démarre, il faut que l'opérande soit disponible. Et l’usage d'un seul registre pour stocker des opérandes différentes à des temps différents limite les possibilités d’exécution en parallèle. Avec le renommage de registres, ces trois données sont enregistrées dans des registres physiques séparés, dès qu'elles sont disponibles. Le processeur garde évidemment trace du fait que ces trois registres physiques correspondent au registre architectural R6. Si les trois valeurs n'ont pas de dépendances entre elles, les instructions liées peuvent être exécutées dans le désordre et s’exécuter en même temps. Ce qui est le cas dans le schéma suivant, où certaines instructions sont exécutées en avance, ce qui réserve les registres physiques en avance. [[File:Renommage de registres - principe.png|centre|vignette|upright=2|Exemple où un registre architectural est utilisé pour contenir trois données successives.]] : Pour les connaisseurs, le renommage de registres réécrit le programme exécuté dans une représentation appelée SSA, utilisée par les compilateurs lors de la compilation. Et cette réécriture se fait un peu de la même manière avec un compilateur. Là où le compilateur change le nom des variables pour passer en forme SSA, le processeur change les noms de registres pour obtenir de l'assembleur SSA interne au processeur. ===La durée de vie des registres virtuels=== La plupart des processeurs disposent d'un banc de registre physique unique, qui regroupe registres physiques et virtuels. Mais il existe quelques processeurs qui font autrement. Ils ont un banc de registre pour les registres architecturaux, et les registres virtuels sont placés ailleurs dans le processeur, typiquement dans le tampon de ré-ordonnancement (ROB) ou le ''scheduler''. Pour simplifier, considérons qu'ils sont dans un banc de registre spécialisé qui regroupe les registres virtuels. C'est un peu faux en soi, mais faisons comme si. Dans le reste de cette section, nous allons partir du principe que les registres virtuels et architecturaux sont séparés pour simplifier les explications, nous verrons les autres formes de renommage de registre plus tard. Les registres virtuels ont une certaine durée de vie. On veut dire par là qu'une donnée écrite dans un registre virtuel y reste durant un certain temps, mais pas indéfiniment. Un registre virtuel est utilisé par une instruction en cours d'exécution dans le pipeline. Il nait lors du renommage de registre et meurt une fois l'instruction terminée. En clair, un registre virtuel dure durant toutes les étapes du pipeline qui suivent le renommage de registres. Une fois que l'instruction quitte le pipeline, qu'elle sort du ROB, le registre virtuel est inutile et doit laisser la place au registre architectural non-renommé. Le résultat de l'instruction doit être transféré dans le registre architectural adéquat, le registre de destination de l'instruction. Si les registres virtuels et architecturaux sont séparés, il faut copier la donnée des registres virtuels vers les registres architecturaux. Utiliser un banc de registre unique résout le problème, mais n'allons pas trop vite, nous verrons cela en détail dans la suite. Toujours est-il qu'un registre virtuel est libéré quand l'instruction associée quitte le ROB. Il est théoriquement possible de libérer un registre virtuel en avance, si on est certain qu'aucune instruction n'ira lire ce registre. Pour cela, le mieux est d'attribuer un compteur de lectures pour chaque registre. À noter que pour maintenir des exceptions précises, on est obligé d'attendre que la dernière instruction qui lit le registre ait validé. Le jeu n'en vaut clairement pas la chandelle. Le seul intérêt d'une telle optimisation est économiser des registres virtuels, d'avoir un banc de registres virtuels plus petits, mais cela se fait au prix de l'ajout de circuits qui consomment tout autant, si ce n'est plus de circuits, pour un résultat en termes de performances limité, voire nul. Après avoir vu la mort des registres virtuels, voyons leur naissance. Le renommage de registre a lieu après le décodage, donc juste avant le passage dans le ''scoreboard'', le ''scheduler'', la file d'instruction ou toute autre structure dédiée à l'émission. En clair : les registres virtuels sont attribués juste avant émission et ne sont utiles qu'après. Les instructions susceptibles d'utiliser un registre virtuel sont donc les instructions émises ou prêtes à l'être, mais pas encore terminées. Les instructions en question sont soit en attente dans le ''scheduler'', soit en cours d'exécution dans le chemin de données, soit en attente dans le ROB. Ces dernières attendent que les instructions précédentes se terminent. Il faut noter que toutes les instructions émises ou en passe de l'être ont été ajoutées dans le ROB juste après le renommage. Même les instructions en attente dans le ''scheduler'' sont dans le ROB. Pour résumer, le ROB garde la trace de ces instructions prêtes à être émises ou déjà émises. ===Le nombre idéal de registres virtuels=== Mine de rien, le contenu de la section précédente nous donne une seconde borne maximale sur le nombre de registres virtuels utiles. Supposons que chaque instruction fournit un résultat, stocké dans un registre virtuel rien que pour lui. Le nombre maximal d'instructions chargées dans le pipeline après émission est égal au nombre d'entrée dans le ROB. Il peut y avoir moins d'instructions, ce qui fait que des entrées du ROB sont inutilisées, mais supposons que nous soyons dans le meilleur des cas. Dans ce cas, on doit avoir un registre virtuel par instruction, ce qui fait au maximum un registre virtuel par entrée du ROB. Rien ne sert d'avoir plus de registres virtuels que d'entrées dans le ROB, il n'y aura pas assez d’instructions dans le pipeline pour tous les utiliser. Après avoir vu une borne maximale, voyons une limite minimale. Non pas qu'il faille absolument plus de registres virtuels que cette limite, simplement qu'il est préférable d'en avoir que cette limite. Partons du principe que les instructions pouvant utiliser un registre virtuel sont celles qui sont soit déjà émises, soit en attente de l'être. Si on néglige les instructions en attente dans le ROB, alors les instructions émises sont dans les ALUs. Le nombre d'instruction est donc égal à la somme de : la taille du ''scheduler'' (instructions en attente), du nombre d'unités de calcul (instruction en cours d'exécution), unités d'accès mémoire inclues. Mieux vaut ne pas passer sous la somme taille du ''scheduler'' + nombre d'unités de calcul. Un bon compromis est d'avoir un nombre de registre virtuel compris entre ces deux bornes. Le nombre réel de registre virtuels est très souvent inférieur au nombre d'entrées du ROB, car toutes les instructions ne fournissent pas de résultat à enregistrer dans les registres. C'est le cas pour les instructions de branchement, par exemple, ou les écritures en mémoire RAM. Par contre, il vaut mieux avoir plus de registres que d'entrées dans le ''scheduler''. La majorité es processeurs respectent ces deux limites basse et hautes, avec un nombre de registres réels entre les deux. Les quelques rares exceptions étaient des processeurs qui implémentaient le renommage de registre pour la première fois, et où ce genre de détails n'étaient pas bien compris. Par exemple, on peut citer le PowerPC 604, qui avait 20 registres virtuels, alors que le ROB avait seulement 16 entrées. Les 4 registres virtuels en trop n'étaient pas utilisés. Le processeur qui a immédiatement suivi, le PowerPC 604, n'a pas fait cette erreur et a réduit le nombre de registres virtuels à seulement 16. Un autre exemple est le MIPS R10000, avec son ROB à 32 entrées, son ''scheduler'' a 48 entrées et ses 64 registres virtuels. Le processeur suivant, le R12000, corrigea partiellement le problème en augmentant le ROB à 48 entrées, ce qui était insuffisant, mais bienvenu. ===Le renommage des registres flottants et entiers=== De nombreux processeurs ont des registres architecturaux séparés pour les nombres flottants et entiers. Mais cela n'implique pas que le renommage de registre le soit. Les deux possibilités existent : une unité de renommage de registre partagée, ou au contraire deux unités de renommage séparées. Intel a tendance à utiliser la premireè solution sur ses processeurs aute performance, alors qu'AMD utilise la seconde solution. [[File:Zen microarchitecture.svg|centre|vignette|upright=2|Microarchitecture Zen 1 des CPU d'AMD.]] A ce propos, quelques rares processeurs ne renomment que que les registres flottants, ou que les registres entiers ! Pour donner un exemple, le processeur Nx586 ne renommait que les registres entiers, pour les instructions entières. L'IBM System/360 Model 91, quant à lui, faisait l'inverse. Les registres flottants étaient renommés, mais pas les registres entiers. Sur les CPU x86, lorsque le renommage de registre a été introduit, il ne concernait que les registres flottants. Ce choix s'explique par l'organisation en pile de registres liée au jeu d'instruction x87, qui limitait grandement le parallélisme d'instruction. Le renommage permettait de fortement limiter la casse, sans compter qu'il permettait d'utiliser des noms de registre explicites à l'intèrieur du processeur. ===Le renommage de registre total et partiel=== Le renommage de registre peut être total ou partiel. Avec le '''renommage total''', toutes les instructions voient leurs registres renommés. Il s'agit de la méthode la plus utilisée à ce jour, par simplicité de conception. Mais des processeurs assez anciens utilisaient un '''renommage partiel''', qui ne s’appliquaient qu'à certains types d'instruction bien précis. Par exemple, on pourrait citer les processeurs Power1, Power2 et PowerPC 601. Sur le premier, les registres flottants étaient renommés seulement pour les instructions de lecture flottante. La raison est que le processeur n'a qu'une seule FPU, ce qui limite l'efficacité de l'exécution dans le désordre sur celle-ci, et fait que renommer les registres ne sert à rien. Le processeur Power 2 dispose lui de plusieurs FPU et le renommage de registres touche aussi les instructions flottantes arithmétiques, c'est un renommage total. Les processeur qui utilisaient le renommage partiel étaient des processeurs assez anciens, qui faisaient avec un budget en transistors limité. De plus, la technique n'était pas très bien maitrisée, et était encore balbutiante. La technique a pourtant été proposée dès 1970 dans divers articles académiques, et raffinée pendant les années 70. Mais le budget en transistors du renommage de registre a fait qu'elle n'a pas été utilisée avant que la loi de Moore fasse son œuvre. ==Les différentes implémentations du renommage de registres== Il existe plusieurs manières différentes d'implémenter le renommage de registre, que nous allons voir dans cette section. Mais avant toute chose, parlons du réseau de contournement. Pour simplifier les explications, appelons ''instruction productrice'' l'instruction qui fournit un résultat, et instruction consommatrice celle qui l'utilise comme opérande. Si une instruction consommatrice est chargée dans le pipeline quelques cycles après l'instruction productrice, les deux sont dans le pipeline en même temps. Dans ce cas, on pourrait penser que c'est le réseau de contournement qui gérerait le transfert du résultat de l'instruction productrice à l’instruction consommatrice. Et effectivement, c'est souvent le cas. Mais les registres virtuels sont pris en compte dans le système de contournement. Si le résultat est écrit dans un registre virtuel, il peut aussi être lu dans ce registre virtuel. Lire un résultat dans les registres virtuels permet d'implémenter une forme de contournement. Tout cela pour dire qu'il y a un lien entre contournement et renommage de registres, les deux doivent être conçu de manière à communiquer entre eux. Typiquement, il y a toujours un réseau de contournement pour connecter la sortie d'une ALU aux entrées des autres. Ce dernier gère le cas où un résultat d’instruction est réutilisé comme opérande au cycle suivant. Mais pour réutiliser un résultat deux cycles après ou plus tard, c'est le système de renommage de registres qui s'en charge. Ceci étant dit, nous allons étudier les implémentations principales du renommage de registre. Pour simplifier, il existe deux manières d'implémenter le renommage de registre. La première utilise deux bancs de registres : un pour les registres architecturaux, un autre pour les registres virtuels. Une autre implémentation regroupe registres virtuels et architecturaux dans un seul banc de registre. Mais d'autres implémentations font totalement autrement, en réutilisant les stations de réservation ou le tampon de ré-ordonnancement. Dans ce qui suit, nous allons nous concentrer sur les principales : le renommage à banc de registre physique, le renommage dans le ROB, le renommage à registres virtuels. Nous allons laisser de côté le renommage dans les stations de réservation pour une raison très simple : elle n'est pas compatible avec les exceptions précises. Nous la verrons dans un chapitre à part, portant sur le ''scoreboarding'' et l'algorithme de Tomasulo. ===Le renommage à banc de registres physiques=== Les processeurs modernes utilisent un seul banc de registres pour les registres architecturaux et virtuels, appelé '''banc de registres physiques''' (''physical register file''). Le tampon de réordonnancement et le ''scheduler'' contiennent des numéros de registres virtuels, des pointeurs vers les registres. Il y a toujours un réseau de contournement pour connecter la sortie d'une ALU aux entrées des autres, qui gère le cas où la sortie de l'ALU est utilisé comme opérande au cycle suivant. Mais pour réutiliser un résultat deux cycles après ou plus tard, c'est le banc de registres physiques qui s'en charge. Les opérandes viennent donc soit du banc de registres physique, soit du réseau de contournement. [[File:Renommage à banc de registres physiques.png|centre|vignette|upright=2|Renommage à banc de registres physiques.]] Avec ce système, un registre physique peut être dans quatre états. * Le premier état est celui d'un ''registre disponible'', près à servir de registre de destination. Par disponible, on veut dire que ce registre peut être réservé par l'unité de renommage, mais qu'il n'a pas encore été réservé. Ce n'est ni un registre virtuel, ni un registre architectural, juste un registre inutilisé. * Le second état est l'''état réservé'', celui d'un registre virtuel qui attend qu'une instruction écrive son résultat dedans. L'état réservé réserve un registre en écriture, mais interdit les lectures dedans. * Le troisième état est celui d'un registre virtuel dans lequel une instruction a écrit son résultat, mais l'instruction n'a pas encore quitté le ROB. Le registre est alors appelé un ''registre écrit''. * Enfin, le quatrième est celui d'un ''registre architectural'', qui contient une donnée valide, dans le sens où il n'est associé à aucune instruction dans le ROB. Un registre passe normalement par ces quatre états dans l'ordre disponible, virtuel réservé, virtuel écrit, architectural. Une fois que l'instruction attribuée quitte le ROB, le registre virtuel devient un registre architectural. Cependant, cela suppose que l'instruction quitte le ROB normalement, ce qui n'est pas le cas suite à une mauvaise prédiction de branchement ou autre. Dans ce cas, il repasse immédiatement à l'état disponible. L'unité de renommage des registre mémorise l'état de chaque registre pour savoir dans quel état il est. Avec ce système, les données ne sont pas déplacées, ce qui a un avantage en termes de performance, de consommation énergétique et de simplification des circuits du processeur. Une fois enregistrées dans un registre, les données ne se déplacent plus. Avec un banc de registre virtuel séparé, elles sont recopiées d'un banc de registre virtuel vers un banc de registre architectural. Et les autres techniques que nous allons voir ont le même problème. Un autre avantage est que les opérandes proviennent toutes du même endroit : le banc de registre unique. Avec un banc de registre séparés, les opérandes peuvent provenir soit des registres architecturaux, soit des registres virtuels. Les opérandes peuvent donc provenir du banc de registre architectural, mais aussi du banc de registre renommés. La conséquence est que la gestion des interconnexions est beaucoup plus compliquée, notamment quand on veut implémenter le contournement. Pas de problèmes de ce genre avec un banc de registre unique. ===Le renommage dans le tampon de réordonnancement=== Il est possible de faire le renommage dans le tampon de réordonnancement (ROB, pour ''ReOrder Buffer'')). Cela veut dire que les résultats des instructions sont mémorisés dans le tampon de réordonnancement. Les entrées du ROB se voient ajouter un champ pour mémoriser le résultat d'une instruction, et ce champ sert de registre virtuel. Les entrées du ROB deviennent ainsi adressables, elle ont un numéro, qui sert de numéro/nom de registre virtuel. Avec cette technique, les registres architecturaux sont séparés des registres virtuels inclus dans le ROB. Les registres architecturaux sont regroupés dans un banc de registres spécialisé, appelé le '''''retirement register file'''''. Le ''scheduler'' mémorise soit un nom de registre architectural, soit l'adresse de l'entrée du ROB qui contient le résultat voulu. Quand une instruction a tous ses opérandes de prêts, ceux-ci sont lus depuis le ROB ou les registres architecturaux. Pour cela, le ROB mémorise l'état de chaque entrée, de chaque registre virtuel : vide, réservée pour un résultat, écrite avec un résultat. [[File:Renommage dans le tampon de réordonnancement.png|centre|vignette|upright=2|Renommage dans le tampon de réordonnancement.]] Un défaut est que cela complexifie l'implémentation des interconnexions par rapport à un banc de registre physique. Il y a toujours un réseau de contournement pour réutiliser un résultat un cycle plus tard. Mais pour réutiliser un résultat deux cycles après ou plus tard, c'est le ROB qui s'en charge. Les opérandes peuvent être lues depuis trois sources : le ROB, le banc de registre architectural, et le réseau de contournement. Soit une source de plus qu'avec la technique précédente, ce qui complexifie les multiplexeurs de contournement. Et cela a un effet sur la latence des opérations, le temps de traversée de ces multiplexeurs n'est pas gratuit, sans compter le temps mis pour les signaux de commande pour les configurer. Le renommage de registre est aussi plus compliqué. Au lieu de simplement remplacer un numéro de registre architectural par un numéro de registre physique, on doit faire la différence entre numéro de registre et adresse dans le ROB, pour savoir où lire les opérandes. Sans quoi ne sait pas configurer les multiplexeurs et choisir la bonne source pour les opérandes. Un autre défaut est que les registres virtuels doivent être copiés dans les registres architecturaux quand une instruction quitte le ROB. La copie se fait ici du ROB vers le banc de registre architectural. Et copier la donnée a un cout en énergie que l'usage d'un banc de registre unique n'a pas. Un dernier défaut est que le nombre de registres virtuel est égal au nombre d'entrées dans le ROB. Or, on a vu plus haut que c'est un peu du gâchis, car beaucoup d'instructions ne produisent aucun résultat. Le hardware ajouté pour les entrées est donc sous-utilisé, il ne sert que si l'instruction fournit un résultat, mais ne sert à rien sinon. ===Le renommage avec un tampon de renommage=== Le dernier défaut évoqué dit que beaucoup d'entrées du ROB sont inutilisées et que les registres virtuels associés sont gâchés. Pour éviter cela, il est possible de sortir les résultats d'instruction du ROB et de les placer dans une mémoire FIFO complémentaire du ROB, appelée le '''tampon de renommage'''. Pour le dire autrement, le ROB amélioré est scindé en deux, avec le ROB proprement dit d'un côté, et un pseudo-ROB pour le renommage de registres et le contournement. Pour information, cette technique de renommage était utilisée dans d'anciens processeurs commerciaux, comme les Pentium Pro, le Pentium II, ou encore le Pentium III, ainsi que dans le Core 2 Duo. La technique est souvent expliquée en décrivant le tampon de renommage comme un banc de registre séparé pour les registres virtuels, appelé le '''banc de registres renommés''' (''rename register file''). Il est séparé du banc de registres architecturaux, avec lequel il communique. La raison à cela est que le tampon de renommage est adressable alors que le ROB ne l'est pas. Il faut dire que le tampon de renommage a tout d'un banc de registre : il contient les registres virtuels et seulement ceux-ci, on peut l'adresser, lire des opérandes dedans, écrire des résultats dedans, etc. Par contre, il y a une différence avec un banc de registre normal : il est traité comme une mémoire FIFO. Nous avons déjà vu comment implémenter une FIFO avec un banc de registre et quelques registres, aussi je ne fais pas de rappels sur ce point. S'il s'agissait d'un véritable banc de registre isolé, sans rien de plus, le ROB et le ''scheduler'' contiendraient des numéros de registres virtuels, qui adressent directement le banc de registre renommé. Une telle implémentation est possible, mais aucun processeur commercial n'a utilisé une telle implémentation. À la place, le banc de registre est en réalité une mémoire FIFO, dont les entrées sont adressables, avec de plus un système de cache utilisé pour faire la correspondance entre nom de registre architectural et nom de registre virtuel. Nous détaillerons ce dernier point dans la section qui explique comment fonctionne l'unité de renommage. Une fois que l'instruction attribuée quitte le ROB, le registre virtuel est libéré, à savoir qu'il repasse en état disponible. C'est à ce moment qu'à lieu la copie de la donnée dans le registre architectural adéquat. Il faut noter que le registre virtuel n'est pas effacé, il contient toujours l'ancienne donnée. Mais ce n'est pas un problème. S'il est réservé par une instruction, elle écrira dedans, ce qui écrasera cette donnée. Et de manière générale, il est impossible de lire cette donnée, que ce soit si le registre est disponible ou réservé. [[File:Renommage à banc de registres renommés.png|centre|vignette|upright=2|Renommage à banc de registres renommés.]] La technique partage tous les défauts du renommage dans le ROB. Le réseau de contournement est plus compliqué car les opérandes peuvent venir de trois sources : les deux bancs de registres et le réseau de contournement. De plus, les registres virtuels doivent être copiés dans les registres architecturaux, avec tout ce que cela implique. Déjà, déplacer des données implique un cout en énergie et en consommation d'électricité, qu'il vaut mieux éviter. De plus, il faut ajouter un port de lecture sur le banc de registre renommés, pour copier un registre sans nuire aux performances. Le banc de registres physiques n'a pas à être modifié : le port d'écriture existant suffit pour la copie, vu qu'on n'écrit dedans que pour copier des résultats d'instructions validées/terminées. Par contre, le cout en transistors est plus faible qu'avec le renommage dans le ROB, vu que le banc de registre a moins de registres virtuels que le ROB. La technique n'impose pas d'avoir autant de registres virtuels que d'entrées dans le ROB, ce qui permet d'en réduire le nombre. Par contre, comparé à l'usage d'un banc de registres unique, le cout en transistors est plus élevé. La différence se fait surtout au niveau des ports de lecture/écriture du banc de registres. La raison est que l'on doit ajouter un port de lecture pour copier les résultats dans les registres architecturaux. Du moins, dans le cas le plus simple. C'est le cas sur un processeur qui permet de compléter l'exécution d'une instruction par cycle. Mais certains processeurs peuvent terminer l'exécution de plusieurs instructions par cycle. C'est notamment le cas des processeurs dits superscalaires, qui sont capables de charger, exécuter et terminer plusieurs instructions par cycle. Ils auront droit à leur chapitre dédié, mais passons. Toujours est-il que si plusieurs instructions peuvent se terminer en même temps, il faut ajouter autant de ports de lecture sur le banc de registre pour copier leurs résultats. ===Le renommage physique-virtuel=== Les méthodes mentionnées au-dessus ont un léger problème : beaucoup de registres physiques sont gâchés, car attribués à une instruction dès l'étage de renommage et libérés lorsque on est certain qu'aucune instruction ne lira le registre physique attribué. Et parfois, les registres sont alloués trop tôt, alors qu'ils auraient pu rester libres durant encore quelques cycles. C'est notamment le cas quand l'instruction renommée attend un opérande dans le ''scheduler'', ou quand le résultat est en cours de calcul dans l'unité de calcul. Ces situations ont toutes la même origine : le renommage a lieu tôt dans le pipeline, pour garder les dépendances entre instructions. Mais dans les faits, rien n'oblige à utiliser les registres architecturaux pour conserver les dépendances. On peut tout simplement attribuer un tag à chaque résultat d'instruction, tag qui ne correspond pas à un registre architectural. Et ce tag sera alloué à un registre architectural le plus tard possible, quand l'instruction fournira son résultat. Ce genre de méthodes a été formalisée avec ce qu'on appelle la technique du '''banc de registres physiques-virtuels''' (physical-virtual register file). Cette méthode demande d'ajouter une seconde table de correspondance, qui fait le lien entre le tag et le registre physique. De plus, la table d’alias de registres doit être modifiée : elle ne doit pas seulement faire la correspondance entre le nom de registre et le tag, mais aussi avec le registre physique s'il est déjà attribué. Ainsi, lors du renommage en sortie du décodeur, on peut renommer l'instruction avec les registres physiques si ceux-ci sont connus lors du renommage, et renommer avec des tags dans le cas contraire. Il faut noter que cette méthode a un léger problème : quand une instruction termine et que le résultat doit se voir attribuer un tag, il se peut parfaitement qu'il n'y ait plus de registre physique de libre. Les solutions pour régler ce problème sont assez complexes, aussi je n'en parlerai pas ici. ==L’unité de renommage== Pour commencer, sachez qu'il existe deux méthodes pour implémenter l'unité de renommage. La première utilise une unité à part, séparées, qui contient de nombreuses mémoires caches/FIFO pour stocker des informations nécessaires pour le renommage de registres. La seconde mémorise les informations de renommage dans le ROB ou le tampon de renommage, voir ailleurs. Les deux types d'unités de renommage sont assez différentes. Pour les désigner, je vais parler d''''implémentation par ''tag''''' et d''''implémentation associative'''. De plus, les deux types d'unités ne sont pas utilisées sur les mêmes implémentations. Par exemple, avec un banc de registre physique, il est naturel d'utiliser une implémentation par ''tag'', l'autre implémentation n'est pas pratique. Aussi, tous les processeurs avec un banc de registre physique utilisent une unité de renommage pat ''tag''. Mais pour le renommage dans le ROB, c'est l'inverse : les deux implémentations sont possibles, mais il est préférable d'utiliser une implémentation associative. Pour simplifier les explications, je vais commencer par décrire le premier type, avec un banc de registre physique. {|class="wikitable" |- ! ! Implémentation par ''tag'' ! Implémentation associative |- ! Banc de registre physique | Seule implémentation possible | |- ! Renommage dans le ROB | Possible, certains processeurs utilisent la technique | Possible, certains processeurs utilisent la technique |- ! Renommage dans un tampon de renommage | Possible, tous les processeurs utilisent la technique | Possible, aucun processeur connu |} ===Les unités de renommage par ''tag''=== Les registres architecturaux sont identifiés par des noms de registre, tout comme les registres physiques. Les noms de registre des registres physiques sont appelés des '''tags'''. Les registres physiques sont bien plus nombreux que les registres architecturaux, sans quoi le renommage de registre n'a aucun intérêt. La conséquence est que les numéros de registres physiques sont plus grands que les numéros de registres architecturaux. Le renommage de registres remplace les noms/numéros de registres architecturaux par des numéros de registres physiques, par des ''tags''. D'où le terme de ''renommage'' de registre. Ce remplacement est effectué dans un étage supplémentaire du pipeline, intercalé entre le décodage et l'émission. [[File:Renommage de registres.png|centre|vignette|upright=2|Renommage de registres.]] Le remplacement se fait cependant différemment pour le registre de destination et les registres d'opérandes. Le registre de destination est associé à un registre virtuel disponible. L'allocation du registre de destination prend un registre disponible et le place en état réservé. Une nouvelle correspondance entre registre architectural et virtuel est alors crée. Mais pour les opérandes, c'est autre chose. Les opérandes sont soit dans un registre architectural, soit dans un registre virtuel en état écrit. Les noms de registres architecturaux pour les opérandes doivent être remplacé par le nom de registre adéquat, déjà attribué. Une sacrée différence : on attribue un registre virtuel pour le résultat, les opérandes ont déjà un registre virtuel attribué. Un autre point est que l'unité de renommage ne fait pas que modifier les registres opérande/de destination. Elle gère aussi la disponibilité des opérandes. Plus haut, on a dit qu'un registre virtuel pouvait être dans quatre états. Soit il est disponible, soit il est réservé, soit il est écrit, soit la donnée est dans un registre architectural. L'unité de renommage est au courant de l'état de chaque registre. Les quatre états possibles sont utilisés pour diverses raisons. Et il y a deux manières pour mémoriser la correspondance entre un registre physique et un registre architectural. La première est d'utiliser un circuit à part, qui fait partie de l'unité de renommage, l'autre est d'intégrer les correspondances dans le ROB ou toute autre structure dédiée. Pr exemple, on peut ajouter la correspondance dans le ROB, dans le ''scheduler'', éventuellement dans le banc de registres renommés ! Dans ce qui suit, nous allons parler du cas où on utilise une mémoire à part, partie intégrante de l'unité de renommage de registre. Nous verrons l'intégration dans le ROB après, de même que la relation avec les quatre techniques précédentes. ===Renommer le registre de destination : la liste de disponibilité=== Renommer un registre de destination revient à lui attribuer un registre virtuel inutilisé. Pour cela, certaines techniques de renommage de registres mémorisent la liste des registres vides/disponibles dans une petite mémoire : la '''liste de disponibilités''' (''free list''). L'implémentation de la liste de disponibilité varie grandement d'un processeur à l'autre. Avec certaines méthodes de renommage de registre, qui impliquent un ROB, on peut même s'en passer totalement. Dans sa version la plus simple, elle contient un bit pour chaque registre, qui indique s'il est disponible ou non. Le bit en question est mis à jour quand une instruction entre/quitte le tampon de réordonnancement avec ce registre comme opérande. Lorsqu'un registre est attribué, il quitte la liste de disponibilités. Lorsque son instruction quitte le ROB, le bit de disponibilité est mis à jour. Une version plus évoluée utilise une mémoire FIFO qui contient des noms de registres. Le renommage du registre de destination utilise cette FIFO pour sortir le numéro de registre virtuel adéquat. Dans la suite, nous partirons du principe que c'est cette méthode qui est utilisée. Il faut noter que si le renommage est fait dans le ROB, la liste de disponibilité est inutile. La raison est que le ROB est déjà une mémoire FIFO, comme la liste de disponibilité. De plus, les registres virtuels sont dans le ROB. Attribuer un registre virtuel consiste simplement à mobiliser une entrée vide du ROB, en enfilant l'instruction dedans. Le ROB sait quelle est la prochaine entrée à allouer à une instruction émise, du fait de son caractère FIFO. ===La table de correspondances de registres=== Le renommage du registre de destination attribue un registre virtuel pour un résultat d'instruction. Reste qu'il faut maintenir cette attribution tant que l'instruction ne s'est pas terminée. Pendant toute la durée de vie de l'instruction, il faut se souvenir que tel registre virtuel correspond à tel résultat d'instruction, mais aussi à tel registre architectural. En effet, les instructions suivantes vont lire ce résultat pour l'utiliser comme opérande. Elle encoderont ce résultat/opérande avec le registre architectural censé contenir l'opérande. Le renommage de registre devra alors remplacer les registres opérande par le registre virtuel adéquat, qui contient l'opérande. Le renommage des registres opérande est le rôle de la '''table d’alias de registres''' (''register alias table''), une mémoire qui contient le registre virtuel associé à chaque registre architectural. Elle mémorise précisément une table de correspondance entre registre architectural et registre virtuel/physique. La table d'alias contient une correspondance par registre architectural, qui change au gré du renommage des instruction. De plus, elle contient un bit qui indique si le registre a été renommé ou non. S'il n'a pas été renommé, alors l'opérande est disponible dans les registres architecturaux, pas dans un registre virtuel. C'est très utile sur les processeurs avec un banc de registre séparés pour les registres architecturaux. Cela permet de savoir où lire les opérandes. La correspondance en question est mise à jour quand une instruction est émise, et quand elle termine. Premièrement, elle est mise à jour à chaque fois qu'un registre de destination est renommé. En clair, la table d’alias de registres est mise à jour à chaque lecture dans la table de disponibilité. Le registre virtuel choisi dans la liste de disponibilités est attribué au registre architectural de destination du résultat. Il suffira de réutiliser cette correspondance par la suite. Deuxièmement, elle est mise à jour quand une instruction termine, quand elle quitte le ROB. Le ROB envoie alors le numéro du registre virtuel qui contenait le résultat enregistré dans les registres architecturaux. Le numéro est alors enregistré dans la table de disponibilité. De plus, la correspondance associée dans la table d'alias est effacée. [[File:Renommage de registres - circuits.png|centre|vignette|upright=2|Unité de renommage de registres.]] Il existe deux façons pour implémenter la table d'alias. La plus ancienne consiste à utiliser une mémoire associative dont le tag contient le nom du registre architectural et la donnée le nom du registre physique. Sur les processeurs plus récents, on utilise une mémoire RAM, dont les adresses correspondent aux noms de registres architecturaux, et dont le contenu d'une adresse correspond au nom du registre physique associé. On n'a alors qu'une seule correspondance entre registre physique et registre architectural, mais cela ne pose pas de problème si on renomme les instructions dans l'ordre d'émission (ce qui est toujours fait). Notons que la table l'alias doit avoir deux ports de lecture : un pour chaque opérande. Et cela vaut peu importe son implémentation : le cache comme la RAM doivent avoir deux ports. ==L'interaction entre renommage de registres et autres optimisations== L'unité de renommage de registre ne fait pas que du renommage de registre, mais joue aussi un rôle dans l'exécution dans le désordre, et prend en charge des rôles annexes à son rôle principal. Par exemple, elle est impliquée pour corriger les mauvaises prédiction de branchement, les exceptions matérielle ou toute situation qui demande de vider le pipeline. En dehors de ces situations, un registre passe normalement par ces quatre état dans l'ordre disponible, réservé, écrit, architectural. Mais ce n'est pas le cas lors d'une mauvaise prédiction de branchement ou autre. Dans ce cas, tous les registres passent immédiatement à l'état disponible, sauf les registres architecturaux. ===La récupération après une prédiction invalide=== Quand une exception ou une mauvaise prédiction de branchement a lieu, les registres virtuels contiennent des données potentiellement invalides, contrairement aux registres architecturaux. En cas de mauvaise prédiction de branchement, la table d’alias de registres est partiellement vidée. Par vidée, on veut dire qu'on élimine les correspondances avec les registres virtuels invalidés. De plus, on doit remettre la table d’alias de registres et la table de disponibilités dans l'état antérieur au chargement de l'instruction qui a déclenché la mauvaise prédiction de branchement ou l'exception matérielle. Et cela peut se faire de différentes manières. La première solution s'applique au renommage dans le ROB. Il suffit de stocker dans le tampon de réordonnancement ce qui a été modifié dans l'unité de renommage de registres par l'instruction correspondante. Ainsi, lorsqu'une instruction sera prête à valider, et qu'une exception ou mauvaise prédiction de branchement aura eu lieu, les modifications effectuées dans l'unité de renommage de registres seront annulées les unes après les autres. Une autre solution consiste à garder un historique des changements fait dans la table d'alias. Lorsqu'une mauvais prédiction est détectée, le processeur traverse l'historique et annule les changements faits un par un. Le tout est assez lent, vu que la traversée se fait un renommage à la fois. Une optimisation utilise une copie valide de la table d’alias de registres dans une mémoire à part, pour la restaurer au besoin. Si jamais le processeur détecte un branchement, la table d’alias de registres est sauvegardée dans une mémoire intégrée au processeur. On peut utiliser plusieurs mémoires de sauvegarde de ce type, pour gérer une succession de branchements. ===La gestion des opérandes disponibles : "lecture avant émission" et "lecture après émission"=== Passons maintenant à un détail d'implémentation de l'exécution dans le désordre. La '''lecture après émission''' utilise des le ''schedulers'' basiques, alors que la '''lecture avant émission''' utilise des stations de réservation. Rappelons que la différence est que les premières émettent les instruction puis lisent les registres, alors que la seconde lit les opérandes depuis les registres juste après le renommage de registre, pour les stocker dans le ''scheduler''. La différence est donc que les étages sont répartis différemment. Avec la "lecture avant émission", l'étage de lecture des opérandes est placé entre l'étage de renommage de registres et l'étage d'émission. Avec la "lecture après émission", l'étage de lecture des registres est situé après l'étage d'émission/''select/wakeup''. Les deux méthodes de lecture avant ou après émission montrent une grande différence pour ce qui est de déterminer la disponibilité des opérandes. Pour la lecture après émission, le renommage de registre n'est pas impliqué. Mais avec la lecture avant émission, les opérandes sont lues dans les registres entre le renommage des registres et l'entrée dans la station de réservation. Ce qui implique qu'on sait quelles sont les opérandes disponibles lors du renommage de registres. Pour cela, l'unité de renommage de registre contient, pour chaque registre virtuel, un bit ''ready'' qui indique que le registre renommé contient une opérande est disponible. S'il est à 0, l'instruction est placée dans le ''scheduler'', et attend que ses opérandes soient disponibles. S'il est à 1, les opérandes sont soit lues dans le registre et placées dans le ''scheduler'', soit lues au moment d'exécuter l'instruction. L'ensemble de ces bits est en plus des bits de disponibilité de la station de réservation, dans l'implémentation la plus simple. Les deux sont alors mis à jour en même temps. Une autre solution regroupe les bits de disponibilité dans une structure matérielle appelée la '''table de disponibilité''', qui est consultée à la fois par les stations de réservation et l'unité de renommage de registres. L'avantage de cette solution est que les signaux de réveil sont envoyés à une seule structure matérielle, pas plus. De plus, il n'y a pas de duplication des bits de disponibilité. Non pas que quelques bits fassent une grosse différence, mais tout est bon à prendre. Notons qu'avec un banc de registres physique, le bit de disponibilité se déduit des quatre états que peut prendre un registre physique. L'unité de renommage de registre doit sait déjà quelles sont les opérandes indisponibles, celles qui ont déjà été calculées, et celles enregistrées dans un registre architectural. Notons qu'un registre virtuel, une fois attribué, peut être en état réservé ou écrit. Seul l'état écrit correspond à une opérande disponible, l'unité de renommage doit donc pouvoir faire la différence. Pour savoir si un registre virtuel contient une donnée valide, la table d’alias de registres lui associe un bit de validité qui est mis à jour lors de l'écriture du résultat dans le registre virtuel correspondant. Elle doit aussi mémoriser quels registres architecturaux ont une donnée valide. Rappelons que le processeur sait qu'une opérande est disponible parce qu'un signal de réveil est généré dans le pipeline, pour dire que telle opérande est disponible. Le signal transmet l'opérande avec le numéro de registre (virtuel ici). Le numéro de registre transmis est alors comparé avec tous les numéros de registre des opérandes, dans le ''scheduler'' et/ou les stations de réservation. Il est possible qu'une instruction soit dans l'étape de renommage alors que le signal de ''réveil'' est envoyé. Si rien n'est fait, l'instruction sera insérée dans le ''scheduler'' avec une opérande indisponible, alors qu'elle l'est. Elle restera alors indéfiniment dans le ''scheduler'', vu que le signal de ''réveil'' n'est généré qu'une seule fois. Pour éviter cela, le signal de ''réveil'' doit aussi être envoyé aux instructions dans l'unité de renommage de registre. Une solution pour éviter cela est d'enregistrer directement les noms de registres renommés dans le ''scheduler'', dès la sortie de l'unité de renommage. Les noms de registres sautent un étage de pipeline, donc. La comparaison avec les signaux de réveil se fait alors dans le ''scheduler'', pas besoin de rajouter un comparateur dans l'étage de lecture des registres. Une autre solution est d'utiliser une table de disponibilité unique. Les signaux de réveil ne sont alors pas perdus. ==Les optimisations liées au renommage de registres== Le renommage de registre permet d'implémenter certaines optimisations annexes, qu'on ne croirait pas reliées au renommage de registre au premier abord. Par exemple, saviez-vous que le renommage de registre permet d'exécuter certaines instructions directement dans l'unité de renommage ? De nombreuses optimisations éliminent certaines instructions, en les remplaçant par des renommages de registres. Il existe plusieurs optimisations de ce genre, qui portent les noms barbabres d'élimination des MOV, de calcul trivial, et de remplacement d'idiomes. ===L'élimination des MOV=== La première optimisation de ce genre élimine les instructions de copie d'un registre dans un autre (les MOV) ou d’échange entre deux registres (XCHG). Ce qui explique pourquoi l'optimisation en question porte le nom d''''élimination des MOV''' (''MOV elimination''), sous-entendu, des MOV inter-registres. L'élimination des MOV est une technique implémenté sur les processeurs à banc de registre physique. En clair, il faut qu'il y ait un seul banc de registre. C'est important, car c'est la seule méthode qui fait que les registres virtuels n'ont pas à être copiés dans les registres architecturaux, ce qui facilite grandement l'implémentation d’une technique visant à éliminer des copies de registres. L'idée est qu'après une copie, le contenu des deux registres source et destination est identique tant qu'aucun des deux registres ne subit d'écriture. On peut alors utiliser un seul registre physique pour la valeur mémorisée, toute lecture des deux registres lisant celui-ci. Lors d'une écriture dans un de ces deux registres, le renommage attribuera un nouveau registre physique pour la nouvelle valeur écrite. : Formellement, il s'agit d'une optimisation de type '''''copy-on-write'''''. ===Le remplacement d'idiomes=== Le même genre d'optimisation peut être effectué avec des instructions inutiles, dont le résultat vaut zéro. En effet, il existe de nombreuses méthodes pour mettre un registre à zéro. Faire un XOR entre le registre et lui-même, le soustraire à lui-même ou le multiplier par zéro sont quelques exemples. Et de tels idiomes sont utilisés par les compilateurs, au lieu d'un simple MOV 0 -> registre, qui copie un 0 dans le registre. La raison est que les instructions MOV sont assez longues, vu qu'elles doivent intégrer une constante immédiate. Le renommage de registres peut être utilisé pour éliminer ces opérations et les remplacer par une mise à zéro du registre. L'optimisation en question porte le nom de '''remplacement d'idiomes'''. Elle est implémentée depuis les processeurs Pentium de microarchitecture P6, et leurs équivalents AMD. Un autre avantage de cette optimisation est que cela casse de fausses chaines de dépendances. Par exemple, une opération "reg XOR reg" faire croire au processeur qu'il y a une dépendance de donnée entre cette instruction, et les instructions précédente qui écrivent dans le registre. Le XOR est donc exécuté après ces instructions faussement dépendantes, alors que la mise à zéro du registre pourrait se faire en parallèle en utilisant un registre virtuel séparé. Les techniques précédentes permettent d'éliminer ces fausses dépendances. ===Les optimisations de calculs triviaux=== Il existe aussi des opérations dont le résultat est une des opérandes. On pourrait citer comme exemples les décalages par 0, les additions et soustractions avec 0, la multiplication par 1, et bien d'autres. En utilisant intelligemment le renommage de registres, ces calculs ne sont pas effectués. Les techniques qui permettent cela sont des techniques dites de '''calcul trivial''' (trivial computation). La détection des calculs simplifiables demande de comparer les opérandes avec 0 ou 1, via un paquets de comparateurs regroupés dans une unité de détection des calculs triviaux. Leur simplification se fait dans la table de renommage de registres, le registre de destination de l'instruction simplifiée étant renommé pour pointer sur l'opérande/résultat. Si le résultat est nul, on considère que la correspondance est invalide et on met le registre physique à une valeur invalide, similaire au pointeur NULL du C. Si un calcul lit un registre physique invalide, celui-ci est automatiquement simplifié par l'unité de renommage, l'autre opérande étant alors attribué automatiquement comme registre de destination du résultat dans la table de renommage. Mais cette technique a tendance à modifier la latence des instructions, qui est réduite après simplification. Cela pose problème au niveau des circuits d'émission et du planificateur, qui n'aiment pas les latences variables, comme on l'a vu il y a quelques chapitres. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=L'exécution dans le désordre | prevText=L'exécution dans le désordre | next=Le scoreboarding et l'algorithme de Tomasulo | nextText=Le scoreboarding et l'algorithme de Tomasulo }} </noinclude> 52rhcjqwc0gjzt47mf2ewsg54r9ynxx Fonctionnement d'un ordinateur/La désambiguïsation mémoire 0 65845 773632 773412 2026-09-29T21:09:02Z Mewtow 31375 /* La modèle de consistance des processeurs x86 */ 773632 wikitext text/x-wiki Dans les chapitres précédents, nous avons vu la mal-nommée exécution dans le désordre dans les chapitres précédents, qui devrait plutôt s'appeler l'émission dans le désordre. Elle modifie l'ordre des instructions pour gagner en efficacité, mais cela n'est valable que pour les instructions travaillant sur des registres ! Nous n'avons pas parlé de l'exécution dans le désordre des accès mémoire, car ils sont un peu à part. Et pour comprendre pourquoi, nous allons dédier ce chapitre à la gestion des accès mémoire dans le pipeline. ==L’émission des accès mémoire== Avant de poursuivre, faisons un rappel rapide. Il faut distinguer deux types de dépendances de données : les dépendances de registres (deux instructions manipulent le même registre), alors que l'unité mémoire gère les dépendances d'adresse (deux instructions manipulent la même adresse). La différence registre-adresse fait que la gestion des dépendances est totalement différente. ===L'''aliasing'' mémoire et les dépendances mémoire=== Pour rappel, deux instructions ont une dépendance d'adresse si elles écrivent ou lisent la même adresse mémoire, ce qui interdit de changer leur ordre. Des instructions mémoires qui lisent/écrivent des adresses différentes sont indépendantes. Lorsque deux instructions mémoire lisent/écrivent à la même adresse, on parle d''''aliasing mémoire'''. Détecter les cas d'aliasing mémoire est primordial pour gérer la désambiguïsation mémoire, et cela demande de comparer des adresses. Formellement, l'aliasing mémoire n'est ni plus moins que l'application des dépendances de données aux instructions mémoire. Et comme les autres dépendances de données, il existe plusieurs types d'aliasing mémoire : RAR, RAW, WAR et WAW. Les dépendances RAR ne posent aucun problème, les lectures peuvent changer d'ordre sans aucun problème, tant qu'il n'y a pas d'écritures entre les deux. Par contre, les autres dépendances imposent trois contraintes. * Les dépendances RAW imposent que les lectures ne doivent pas s'exécuter avant une écriture à la même adresse. * Les dépendances WAR imposent que l'on ne peut pas déplacer une écriture avant une lecture à la même adresse. * Enfin, les dépendances WAW font que l'ordre des écritures doit être celui du programme : impossible de changer l'ordre de deux écritures. Les trois contraintes peuvent s'implémenter de plusieurs manières différentes. Comme pour les dépendances de données normales, seules les dépendances RAW sont de vraies dépendances de données. Les deux autres dépendances viennent du fait que l'on utilise la même adresse pour stocker des valeurs différentes. S'il existe des techniques similaires au renommage de registre permettent de les faire disparaitre, elles sont très limitées. ===La désambiguïsation mémoire=== Diverses optimisations permettent d'émettre des accès mémoire dans le désordre, exactement comme l’exécution dans le désordre le fait pour les autres instructions. Elles utilisent pour cela des fenêtres d'instruction spécialisées dans les accès mémoire. Il faut vraiment insister sur le fait que l'exécution dans le désordre proprement dite ne se préoccupe pas des micro-opérations mémoire. Pour faire la distinction, on parle de '''désambiguïsation mémoire''' (''memory disambiguation'') pour parler de l'exécution dans le désordre des accès mémoire. Le but de la désambiguïsation mémoire est d'exécuter les lectures le plus tôt possible. La raison est que la donnée lue est utilisée par d'autres instructions, dépendantes de la lecture. Elles sont donc à la tête d'une chaine de dépendances de données qui peut bloquer le pipeline si elle n'est pas résolue très tôt. Dès qu'une lecture peut être lancée, elle accède directement au cache de données. Par contre, si l'aliasing ne le permet pas (écriture à la même adresse pas encore effectuée) ou que l'adresse à lire n'a pas encore été calculée, la lecture attend son tour. Le problème est que la désambiguïsation mémoire demande de comparer des adresses, pour détecter les dépendances d'adresse. Et cela pose de sérieuses contraintes pour son implémentation. En comparaison, l'exécution dans le désordre normale compare des registres, ce qui est beaucoup plus simple. Les registres utilisés par une instruction sont directement encodés dans l'instruction elle-même, ce qui fait qu'on peut détecter les dépendances de registre à l'émission, voire au décodage. Et elles peuvent même être éliminées par le renommage de registre pour les dépendances WAW et WAR. Par contre, les adresses sont des opérandes d'instruction, elles ne sont pas encodées dans l'instruction elle-même. Il y a certes d'exception de l'adressage absolu, mais elle est minoritaire. Avec l'adressage indirect ou indicé, les adresses sont soit lues depuis les registres, soit calculées par une unité de calcul. Les adresses ne sont donc connues qu'une fois que l'instruction a attendu suffisamment de temps dans la fenêtre d'instruction. ===Le calcul anticipé des adresses mémoire=== La désambiguïsation mémoire fonctionne d'autant mieux que les adresses à lire/écrire sont connues le plus tôt possible. Pour cela, il est possible de séparer les accès à la mémoire en deux micro-instructions : une pour le calcul d'adresse et l'autre pour les accès mémoire. Cela permet de calculer les adresses dès que possibles, et donc de vérifier à l'avance si l'adresse calculée a des dépendances avec celles des autres instructions. La détection des dépendances est ainsi anticipée de quelques cycles, permettant un accès anticipé sûr des accès mémoire. On parle de '''calcul anticipé des dépendances'''. Une implémentation possible effectue les calculs d'adresse dans les unités de calcul entière. L'ALU entière et l'unité mémoire sont alors dans deux avals séparés, en parallèle. La micro-opération de calcul d'adresse s'exécute dans une ALU, et son résultat est envoyé à l'unité mémoire. Pour cela, l'adresse calculée est envoyée à l'unité mémoire via un système de contournement dédié, qui relie les sorties des ALU entières à l'unité mémoire. Une solution alternative utilise un aval unique qui s'occupe à la fois des micro-opérations entières et des micro-opérations mémoire. L'aval a alors deux étages en série, un pour l'unité de calcul, suivi par l'étage d'accès mémoire. Le pipeline RISC classique était dans ce cas, pour rappel. Cette solution permet d'avoir un pipeline dit de longueur fixe, à savoir que toutes les instructions font le même nombre de cycles d'horloge. De plus, elle garantit que les instructions mémoire sont décodées en une seule micro-opération. En clair, il y a un seul aval pour toutes les instructions. Mais elle vient avec un défaut majeur : de nombreuses instructions n'utilisent pas l'unité mémoire, mais doivent quand même traverser l'étage associé, qui passe un cycle à ne rien faire. ==L’émission dans l'ordre des accès mémoire== Avant toute chose, faisons quelques rappels sur l'exécution dans le désordre. Les micro-opérations renommées sont mises en attente avant que les conditions pour leur émission soient remplies. La mise en attente peut se faire soit dans une file de micro-opération, soit dans une fenêtre d'instruction. Une file de micro-opération est une mémoire FIFO qui garde les micro-opération dans leur ordre d'émission, l'ordre du programme. Les micro-opérations sont donc émises dans l'ordre du programme, il n'y a pas d'émission dans le désordre. Par contre, les fenêtres d'instructions peuvent émettre les micro-opérations dans le désordre, dans un ordre différent de celui du programme. Dans les deux cas, les écritures sont retardées via une file d'écriture, qu'on a vu il y a quelques chapitres et sur laquelle on fera des rappels. ===La file de µops mémoire=== Avec l''''émission dans l'ordre des accès mémoire''', le processeur émet les accès mémoire dans l'ordre du programme. Cela implique que l'unité mémoire n'a pas de fenêtre d'instruction, ni de station de réservation associée. À la place, les micro-opérations mémoire sont placées dans une file de micro-opération dédiée, appelée la '''file de µops mémoire'''. Par contre, pour les unités de calcul, le processeur utilise des fenêtres d'instruction. Autant les accès mémoire se font dans l'ordre, autant les instructions arithmétiques/logiques/branchements/autres sont exécutées dans le désordre. En clair, le processeur peut supporter l'exécution dans le désordre, sauf pour les micro-opérations mémoire. [[File:Processeur avec émission dans l'ordre des accès mémoire.png|centre|vignette|upright=2|Processeur avec émission dans l'ordre des accès mémoire]] : Nous avons volontairement omis le cas où le processeur n'a pas d'exécution dans le désordre, où il y a une file de micro-opération unique. Mais c'est globalement la même chose, car une file de micro-opération unifiée émet toutes les instructions dans l'ordre. La file de µops mémoire est une mémoire FIFO, qui contient plusieurs entrées, chaque entrée pouvant accueillir une µops mémoire. Une entrée contient plusieurs champs : un qui précise si l'opération est une lecture ou une écriture, un pour l'adresse mémoire à lire/écrire, un autre pour la donnée à écrire (qui est vide pour une lecture), un autre pour le registre de destination des lectures. Les deux derniers champs sont souvent fusionnés en un seul, qui est interprété différemment selon que l'instruction est une lecture ou une écriture. Elle contient aussi des bits de validité, qui indique si l'adresse ou la donnée sont disponibles, ou si le champ associé est vide. [[File:Load Store Queue unifiée.png|centre|vignette|upright=2.5|File de µops mémoire.]] L'unité mémoire ne permet que de faire un accès mémoire à la fois. Du moins, elle a un port sur lequel on envoie la micro-opération émise, que ce soit une écriture ou une lecture. Vu de l'extérieur, il faut attendre qu'un accès mémoire soit terminé pour lancer le suivant. Avant d'émettre une micro-opération mémoire, la file de micro-opération (son ''scoreboard'') vérifie si l'unité d'accès mémoire est libre ou non. Si elle est occupée, un accès mémoire est en cours, et on ne peut pas émettre de micro-opération mémoire. Une fois l'accès mémoire terminé, la mémoire ou le cache envoient un signal pour indiquer que l'accès est fini, et c'est au tour d'une nouvelle micro-opération mémoire. [[File:Unité de gestion des accès mémoires dans l’ordre.png|centre|vignette|upright=2.0|Unité de gestion des accès mémoires dans l’ordre]] Mais il s'agit là du comportement vu de l'extérieur de l'unité mémoire. En réalité, l'unité mémoire utilise quelques optimisations en interne qui permettent d'exécuter dans le désordre les micro-opérations mémoire. ===La file d'écriture : une FIFO de mise en attente des écritures=== Afin de supporter les exceptions précises, les écritures doivent respecter deux contraintes : s'exécuter dans le tout dernier étage du pipeline, s'exécuter dans l'ordre du programme. Pour cela, les écritures sont mises en attente tant que les instructions précédentes ne sont pas terminées. Les écritures dans le cache sont mises en attente dans une mémoire FIFO, appelée la '''file d'écriture''', ou encore la ''Write Queue''. Nous en avions déjà parlé dans le chapitre sur le pipeline, dans la section sur les exceptions précises. Mais quelques rappels ne feront pas de mal. L'écriture est insérée dans la file d'écriture lorsqu'elle est émise, elle en sort à l'étage de ''Writeback'' si tout se passe bien. Si une exception est détectée, l'étage de ''Writeback'' vide la file d'écriture, ce qui annule les écritures mises en attente, faites à tort. De plus, la file d'écriture est une mémoire FIFO, qui mémorise les écritures dans l'ordre du programme. En effet, les écritures sont ajoutées dans la file d'écriture lorsqu'elles sont émises, et elles sont émises dans l'ordre du programme. [[File:Store Queue sur un pipeline fixe.png|centre|vignette|upright=2|Write Queue sur un pipeline fixe]] La file d'écriture garantit que les écritures sont dans l'ordre du programme. Et cette propriété élimine totalement les dépendances WAW. Le fait que les écritures se font à la fin du pipeline élimine quant à elle les dépendances WAR. Il ne reste plus qu'à gérer les dépendances RAW, celles où une lecture lit une donnée écrite par une autre instruction. Une telle situation survient, car les écritures sont mises en attente pendant un certain temps, la donnée écrite peut être lue pendant ce laps de temps. La lecture ne peut pas lire la donnée dans le cache, car la donnée à lire n'y est pas encore enregistrée. Le cas est rare, car il demande de lire une donnée qu'on vient d'écrire, mais il existe. Il se manifeste surtout sur les processeurs avec peu de registre, où des données doivent régulièrement être déplacées temporairement en mémoire RAM. Pour éviter cela, une solution consiste mettre en attente les lectures si une écriture est en attente. Les lectures sont maintenues dans la file de µops tant que la file d'écriture n'est pas vide. La file de µops mémoire est suivie d'un circuit de détection des dépendances, un '''''scoreboard'' mémoire''' qui est assez simple. L'unité mémoire fournit un bit qui indique si la file d'écriture est vide ou non, ainsi qu'un second bit qui indique qu'elle est vide. Les deux ne sont pas compliqués à générer, ils font partie intégrante de l'interface de toute mémoire FIFO digne de ce nom. Le ''scoreboard'' mémoire utilise ces deux bits pour savoir s'il peut émettre une micro-opération mémoire. Il n'émet pas de lecture tant que la file d'écriture n'est pas vide. Il peut par contre émettre des écritures tant qu'elle n'est pas pleine. Une meilleure solution serait d'interdire les lectures, mais seulement en cas de dépendance mémoire détectée. Et c'est là qu'intervient la technique du '''''load bypassing'''''. Elle autorise une lecture, si elle n'a aucune dépendance avec les écritures mises en attente dans la file d'écriture. Elle doit être mise en attente dans le cas contraire. Pour l'implémenter, il faut comparer l'adresse à lire avec toutes les adresses dans la file d'écriture. La lecture est exécutée immédiatement si aucune correspondance n'est trouvée, mais elle est mise en attente dans le cas contraire. Pour cela, la file d'écriture est modifiée et devient un mélange entre FIFO et mémoire associative. L'adresse à lire est envoyée à la file d'écriture, et celle-ci vérifie si une écriture est en attente à cette adresse. Si c'est le cas, c'est un succès de ''Write Queue'' : la lecture doit être bloquée. Sinon, c'est un défaut de ''Write Queue'', la lecture accède au cache, là où se trouve la donnée à lire. Dans le chapitre sur le contournement, nous avons parlé d'une forme de contournement qui corrige ce problème. Les lectures peuvent lire la donnée depuis la file d'écriture si besoin, ce qui renvoie la donnée adéquate. Pour cela, les lectures consultent à la fois le cache et la file d'écriture, comme dit plus haut. L'adresse à lire est envoyée à la file d'écriture, et celle-ci vérifie si une écriture est en attente à cette adresse. Si c'est le cas, c'est un succès de ''Write Queue'', et celle-ci envoie alors la donnée associée à l'étage d'accès mémoire. Sinon, la lecture accède au cache, là où se trouve la donnée à lire. La solution porte le nom de ''Store to load Forwarding'', ou encore de '''réacheminement écriture-vers-lecture'''. [[File:Store to load forwarding sur un pipeline simple.png|centre|vignette|upright=2|Store to load forwarding sur un pipeline simple]] La lecture est mise en attente dans l'unité mémoire, vu que c'est elle qui fait les comparaisons d'adresse. Du point de vue extérieur, le ''scoreboard'' mémoire ne voit pas s’il y a eu succès dans la file d'écriture ou non. Il voit juste que l'unité mémoire est occupée et ne peut pas accepter de nouvelle lecture. Elle reste occupée durant quelques cycles, en cas de défaut de ''Write Queue'', le temps de faire la lecture dans le cache. Par contre, en cas de succès de ''Write Queue'', elle reste occupée tant que la lecture n'a pas donné de résultat, ce qui inclue le temps de mise en attente. Les processeurs haute performance implémentent tous le ''Store to load Forwarding'', mais quelques processeurs basse performance ne le font pas. Ils se contentent du ''load bypassing'', qui offre des performances correctes pour un cout en matériel bien plus modeste. Pour donner un exemple, la micro-architecture Jaguar d'AMD était dans ce cas. Elle a été utilisée sur les consoles de jeu de 8ème génération, comme la Xbox One et la Playstation 4. Les processeurs haute performance préférent utiliser plus de circuits pour implémenter le ''Store to load Forwarding'', mais l'implémentation n'est souvent pas complète. En effet, l'implémentation est souvent simple et ne prend en compte que des lectures/écritures à des adresses identiques, sans compter que la taille des données doit aussi être identique. Une écriture d'un entier de 32 bit sera contournée et envoyée à une lecture de 32 bits à la même adresse. Mais la lecture lit seulement 16 bits sur les 32 écrits, le contournement peut ne pas marcher. Concrètement, ce cas précis fonctionnera. Mais le cas inverse, avec une lecture lisant plusieurs écritures de taille plus petite, ne marchera pas sur tous les processeurs. Ne parlons pas du cas où les données écrites sont à cheval sur deux lignes de cache. ===Le contournement des adresses mémoire avec une file de µops=== Il faut noter qu'au moment où les instructions LOAD et STORE sont émises, leur adresse n'est pas forcément connue. Sauf en cas d'adressage absolu, mais mettons ce cas particulier de côté, il est assez rare en pratique. Les micro-opérations mémoire sont donc insérées dans la file de µops, mais l'adresse est souvent disponible plus tard. Il faut donc modifier le chemin de données pour que l'adresse soit envoyée à la file de µops mémoire. Pour simplifier, étudions le cas d'un processeur où les instructions LOAD/STORE ne gèrent que l'adressage indirect à registre, à savoir que l'adresse est lue dans un registre. Les calculs d'adresse sont réalisés par une instruction de calcul séparée de l'instruction LOAD/STORE. Tout calcul d'adresse a lieu dans les unités de calcul entière, les micro-opérations mémoire ne font pas de calcul d'adresse. Au minimum, il doit y avoir une connexion entre le banc de registre et la file de µops mémoire. Il faut alors attendre que les adresses soient enregistrées dans les registres pour être envoyées à la file de µops mémoire. Cependant, il est possible de profiter du réseau de contournement. L'idée est que l'adresse est accessible avant via le réseau de contournement, avant même d'être enregistrée dans les registres L'idée est que l'adresse est envoyée à l'unité mémoire dès qu'elle sort des unités de calcul. Le gain en performance étant important, tous les processeurs modernes ajoutent un système de contournement qui envoie les adresses à la file de µops mémoire. L'ALU entière calcule l'adresse finale, l'envoie à la file de µops mémoire. [[File:Contournement pour la file de µops mémoire.png|centre|vignette|upright=2|Contournement pour la file de µops mémoire]] Maintenant, les instructions LOAD/STORE avec un mode d'adressage indicé, ce qui signifie que l'instruction fait un calcul d'adresse et l'accès mémoire proprement dit. Une solution basique utilise une micro-opération séparée pour le calcul d'adresse et l'accès mémoire. Le calcul d'adresse envoie son résultat à la file de µops mémoire, sans l'enregistrer dans les registres, via contournement. Sans optimisation particulière, les calculs d'adresse sont réalisés par les ALU entières, le processeur n'est pas modifié et reste le même que celui du schéma précédent. Mais une autre solution utilise des ALU spécialisées dans les calculs d'adresse, appelées des ''Adress Generation Unit'', abrévié AGU. L'avantage est que cela simplifie grandement le réseau de contournement : seules les AGU sont connectées à la file de µops mémoire. Un autre avantage est lié à l'adressage de la destination. En utilisant des opérations entières usuelles, il faudrait préciser que le résultat est à destination de la file de µops mémoire, pour configurer le réseau de contournement. Avec des AGU, les calculs d'adresse sont des micro-opérations différentes des additions et soustraction, elles sont envoyées au AGU spécifiquement, pas besoin de préciser la destination. [[File:File de µops mémoire avec calcul d'adresse via AGU.png|centre|vignette|upright=2|File de µops mémoire avec calcul d'adresse via AGU]] Lors de l'émission, la micro-opération mémoire est insérée dans la file de µops mémoire, l'opération de calcul d'adresse est émise dans la fenêtre d'instruction. Et les deux sont exécutés différemment. En effet, un calcul d'adresse est une opération arithmétique, qui est gérée par le système d'exécution dans le désordre. Elle peut s'exécuter dès que ses opérandes sont disponibles. À l'inverse de l'accès mémoire, qui lui doit se faire dans l'ordre du programme. Les adresses sont donc calculées en avance, puis insérées dans la file de µops mémoire. La µops de calcul d'adresse précise où enregistrer son résultat, le résultat est enregistré dans la bonne entrée de la file de µops mémoire. Les techniques précédentes décodent une instruction LOAD/STORE en deux micro-opérations. Mais il est possible de la décoder en une seule. Le calcul d'adresse est alors réalisé dans l'unité mémoire. Les opérandes du calcul d'adresse sont lues depuis les registres lorsque l'instruction quitte la file de µops mémoire, du moins pour les opérandes qui n'ont pas été contournées. Là, elles sont envoyées à l'unité mémoire, qui fait le calcul d'adresse. Dans les faits, aucun processeur commercial moderne n'utilise cette technique. [[File:File de µops mémoire avec calcul d'adresse dans l'unité mémoire.png|centre|vignette|upright=2|File de µops mémoire avec calcul d'adresse dans l'unité mémoire]] ===L'optimisation du pseudo-contournement des opérandes mémoire=== Les processeurs modernes implémentent une optimisation concernant les accès mémoire. Cette optimisation a été décrite par Agner Fog dans ses manuels d'optimisation, sous le terme de '''''Mirroring memory operand'''''. Il a documenté son apparition sur les processeurs Zen 2 d'AMD, puis son évolution sur les processeurs Zen 4 et 5. L'optimisation est bizarrement absente de la microarchitecture Zen 3. Elle se manifeste dans une condition très précise : plusieurs instructions proches accèdent à la même adresse. Les deux instructions ne sont pas forcément consécutives, il peut y avoir une dizaine ou centaine d'instructions entre les deux. Une telle situation survient souvent sur les CPU CISC, et notamment sur les CPU x86, car ils ont peu de registres. les compilateurs font donc beaucoup d'échanges entre pile d'appel et registres, ce qui fait que des données écrites dans la pile sont souvent relue quelques instructions plus tard. Dans ce cas, la donnée lue/écrite est mémorisée dans un registre interne au processeur et peut être accédée très rapidement. Par exemple, imaginons plusieurs lectures proches à la même adresse, sans écriture entre elles. Dans ce cas, le processeur ne fera qu'une seule lecture en mémoire RAM, les lectures ultérieures liront la donnée depuis le registre interne. Comme autre exemple, imaginons une écriture suivie plus tard par une lecture à la même adresse. Dans ce cas, la donnée sera écrite dans un registre interne, en plus d'être propagée dans le cache ou la RAM, et la lecture ultérieure lira directement le registre interne. Le gain en performance est alors conséquent, comparé à du simple ''store-to-load forwarding''. Il faut noter que la technique marche aussi pour les opérations ''load-op'', pas seulement pour les instructions d'accès mémoire. Par exemple, prenons une écriture en RAM, suivies quelques instructions plus tard par une opération ''load-op'' à la même adresse. L'écriture écrit à une adresse, qui est lue par l'instruction ''load-op''. L'optimisation s'applique : l'instruction ''load-op'' lira l'opérande mémoire depuis un registre interne du processeur, qui contient une copie de la donnée écrite. Sur les processeurs Zen 2, l'optimisation marchait aussi pour les instructions PSUH et POP, qui lisaient/écrivaient dans la pile d'appel. Mais cette possibilité a été retirée sur les processeurs Zen 5. La technique détecte que deux instructions accèdent à la même adresse sous certaines conditions bien précises. L'optimisation ne marche que pour les modes d'adressages indicés et indirect, avec ou sans décalages, mais pas en mode absolu ou relatifs. Il faut préciser que l'optimisation ne marche que pour les registres généraux, pas les registres flottants. Les registres doivent être précisés de la même manière dans toutes les instructions. Par exemple, le processeur ne reconnait pas que l'addition des deux registres RCX + RAX est la même que RAX + RCX. Sur les CPU Zen 2 et 4, elle ne marchait que pour des opérandes de 32 et 64 bits, mais les processeurs Zen 5 gèrent des données de 8 et 16 bits aussi. Les décalages étaient limités à 8 bits sur le Zen 2, mais n'a plus de limites sur les Zen 4 et 5. ==Le ''Load Ordering, Store Ordering''== Intuitivement, on dit qu'exécuter des µops mémoire dans le désordre demande de remplacer la file de µops mémoire par une fenêtre d'instruction. Et si c'est en effet une solution intéressante, nous n'allons pas la voir toute de suite. Nous allons étudier le cas où cette file deµops mémoire est scindée en deux : une file pour les lectures et une autre pour les écritures. ===Les files de µops LOAD et STORE=== Dans le chapitre sur l'exécution dans le désordre, nous avons vu deux possibilités pour implémenter l'exécution dans le désordre. La première utilise une fenêtre d'instruction ou une station de réservation, l'autre utilise plusieurs files de µops séparées. Et cette technique peut parfaitement s'utiliser pour les micro-opérations mémoire. Les micro-opérations mémoire sont réparties dans deux files de µops mémoire séparées, chacun émettant des micro-opérations indépendamment de l'autre. Mais comment répartir les micro-opérations mémoire dans deux files, simplement et sans que cela pose des problèmes de dépendances de données ? La réponse à ces contraintes est toute simple : on utilise une file de µops spécialisée pour les lectures, et une autre pour les écritures. Les cours d'architecture des ordinateurs nomment souvent ces deux files en utilisant les termes de ''file de STORE'' (''store queue'') et de ''file de LOAD'' (''load queue''). Dans ce qui suit, nous parlerons de '''file de µops LOAD''' et de '''file de µops STORE''', pour bien préciser qu'il s'agit de file de µops. La file de STORE ne doit pas être confondue avec la file d'écriture, qui est appelée ''write queue'' en anglais. Les termes ''store queue'' et ''write queue'' désignent deux choses différentes, mais il y a un risque de confusion pour qui n'est pas assez attentif. D'autant plus que la méthode que nous allons voir a une file d'écriture en plus des deux files de µops mémoire. En effet, la file d'écriture ne mémorise pas des micro-opérations, juste des écritures déjà émises et en attente. Une entrée dans la file d'écriture contient une adresse et la donnée à écrire. Alors que dans la file de µops STORE, il se peut que l'adresse ou la donnée soient manquantes, car pas encore disponibles. De plus, la file d'écriture met en attente des écritures tant que les instructions précédentes ne sont pas terminées, alors que la file de µops STORE met en attente les micro-opérations avant leur émission. La première attend le feu vert de l'étage de ''Writeback'', l'autre attend le feu vert de l'étage de ''schedule'', d'un ''scoreboard'' amélioré. Les deux files sont chacune connectées à l'unité mémoire, via un port dédié. L'unité mémoire a donc un port pour les lectures, et un port pour les écritures. Le port d'écriture est relié à la file d'écriture, le port de lecture est directement relié au cache de données. il faut noter qu'une unité mémoire à deux ports n'est pas si bizarre que cela. En effet, le cache de données a lui aussi deux ports, dans la majorité des cas, avec un port de lecture et un port d'écriture. [[File:Load Ordering, Store Ordering.jpg|centre|vignette|upright=2|Exécution dans le désordre des lectures.]] Le fait de séparer lectures et écriture a de nombreux avantages. Le premier est qu'une file de µops mémoire unique gâche des transistors. Une écriture a besoin de mémoriser une adresse et une donnée, avec les bits de validité pour les deux. Une lecture n'a besoin que d'une adresse et du bit de validité associé. Avec une file de µops unique, chaque entrée de la file est suffisamment large pour contenir une écriture. Si elle ne contient qu'une lecture, elle est trop large, ce qui sous-utilise les circuits de la file. Avec des files de lecture/écriture séparées, on n'a pas ce problème, chaque file contient juste ce qu'il faut. Il y a donc une économie de transistors. Cependant, le système est moins flexible. Par exemple, prenons une file de µops mémoire unique, de 16 entrées. Elle peut mémoriser indifféremment 16 lectures, 16 écritures, ou n'importe quel mix d'écriture et de lectures tant qu'il se limite à 16 µops. Avec des files séparées, ce n'est plus le cas. Prenons par exemple le cas avec une file de µops LOAD de 10 éléments et une file de µops STORE de même capacité : impossible d'avoir 16 écritures en attente. Cependant, ce désavantage est quelque peu compensé par l'économie de transistor mentionnée précédemment, qui est réinvestie pour agrandir les files de µops. Typiquement, on agrandit la file de µops LOAD, car les lectures sont plus fréquentes que les écritures dans la majorité des programmes. En ayant une file de µops LOAD assez conséquente, le désavantage est fortement atténué, voire disparait. ===La gestion des dépendances avec des files de µops mémoire séparées=== L'usage de ces deux files de µops mémoire porte le nom de '''''Load Ordering, Store Ordering'''''. Il est intéressant de comparer cette technique avec la précédente, qui utilisait une file de µops mémoire séparée. Avec deux files séparées, les lectures s'exécutent dans l'ordre, les écritures s'exécutent dans l'ordre, mais les lectures peuvent passer avant/après les écritures et réciproquement, tant que l'aliasing le permet. Les écritures peuvent prendre de l'avance sur les lectures, ou réciproquement. Et cette avance est très utile si elle permet d'exécuter des lectures en avance. En comparaison, avec une file de µops unique, ni écritures ni lectures ne peuvent prendre de l'avance. Les performances sont donc améliorées, bien que de peu. Néanmoins, l'avance des lectures est limitée. Prenons le cas où une lecture doit être mise en attente, car son adresse n'est pas disponible. Avec une file de µops mémoire unique, la lecture bloque toutes les micro-opérations qui suivent. Avec deux files séparées, elle bloque uniquement les lectures, pas les écritures. Les écritures qui suivent la lecture peuvent s'exécuter. Le cas avec une écriture en attente est un peu différent. Une écriture en attente bloquera les écritures suivantes. Mais elle bloquera aussi les lectures postérieures : du point de vue de ces lectures, une écriture précédente a une adresse inconnue, on ne sait pas s'il y a dépendance mémoire avec et on suppose que oui dans le doute. En clair, l'avance des lectures n'a lieu que si les adresses des écritures précédentes sont connues, déjà calculées, sans quoi on ne peut pas détecter les dépendances mémoire. Le fait que les écritures peuvent être émises en avance fait que la détection des dépendances RAW est différent. L'idée générale reste cependant la même. Lors de l'émission, une lecture doit vérifier ses dépendances avec les écritures antérieures, une écriture doit vérifier ses dépendances avec les lectures ultérieures. Avec une file de µops unique, on est certain que les écritures antérieures sont dans la file d'écriture, dans l'unité mémoire. Et lorsqu'on émet une écriture, on est certain que les lectures ultérieures seront émises après. Avec deux files séparées, ce n'est pas forcément le cas. Si les lectures ont pris de l'avance, une écriture précédente peut être en attente dans la file de µops STORE, alors qu'une lecture ultérieure a été émise. Ce qui complique la détection des dépendances RAW d'adresse. Les détecter demande non seulement de vérifier la file d'écriture, mais aussi la file de µops STORE. Dans ce qui suit, on suppose que l'unité mémoire incorpore une file d'écriture, ce qui est toujours le cas en pratique. Le fait que les écritures se font dans l'ordre élimine les dépendances WAW et WAR. On suppose aussi que l'unité mémoire implémente le ''réacheminement écriture-vers-lecture'' (''store-to-load forwarding''). Ainsi, si une lecture est émise dans l'unité mémoire, les dépendances RAW avec les écritures déjà émises ne sont pas un problème. Par contre, il faut gérer les dépendances avec les écritures en attente dans la file de µops STORE, dont certaines sont antérieures à la lecture dans l'ordre du programme. Pour cela, il n'y a pas le choix : pour chaque lecture, on vérifie dans la file de µops STORE si elle a une dépendance avec une écriture antérieure. La gestion des dépendances RAW est donc gérée partiellement dans l'unité mémoire et la file de µops STORE. Pour l'implémenter, il faut comparer l'adresse à lire avec toutes les adresses dans la file de µops STORE. En cas de ''match'', la lecture est bloquée dans la file de lecture. Mais s'il n'y a aucune correspondance, alors la lecture peut s'exécuter. Pour cela, la file de µops STORE est un mélange entre FIFO et mémoire associative. Il faut préciser que la comparaison ne prend en compte que les écritures situées avant la lecture, dans l'ordre du programme. Les deux files de µops doivent donc mémoriser des informations sur l'ordre d'émission. De plus, il arrive que des écritures soient dans la file d'écriture, mais que leur adresse n'ait pas encore été calculée. Dans ce cas, il y a potentiellement dépendance avec la lecture si l'adresse se révèle être la même une fois calculée : on considère que les adresses inconnues sont des correspondances/''match''. La file de lecture met des lectures en attente, soit car elle attend ses opérandes, soit car elle attend que les lectures précédentes soient terminées, soit car l'aliasing ne lui permet pas. Elle a cependant un défaut : celui de forcer les lectures à s’exécuter dans l'ordre, ce qui est une contrainte inutile. Mais l'avantage est que l'implémentation est très simple. Une file de micro-opération est bien plus simple à implémenter qu'une fenêtre d'instruction. ==Le ''Partial Ordering'' : la ''Load/Store Queue''== Avec la technique précédente, les lectures s'exécutent dans l'ordre, à savoir que l'on ne peut pas déplacer une lecture avant ou après une autre. Et cette limitation a des conséquences sur la performance de l'exécution dans le désordre. Des lectures sont mises en attente, parce qu'une lecture précédente l'est, alors qu'elles auraient pu s’exécuter avant. Et ce retard sur les lectures se répercute sur les instructions lecture-dépendantes, donc sur le reste du pipeline. Pour éviter cela, la technique du ''Partial Ordering'' permet aux lectures de s'exécuter dans le désordre tant que les conditions d'aliasing sont respectées. ===La ''Load/Store Queue''=== La technique s'implémente en remplaçant les files de µops mémoire par une fenêtre d'instruction spécialisée dans les µops mémoire. Elle est souvent appelée la '''''Load/Store Queue''''', qui est concrètement une station de réservation spécialisée dans les micro-opérations mémoire. En tout cas, nous utiliserons beaucoup l'abréviation LSQ pour parler de la ''Load/Store Queue''. [[File:Processeur avec émission dans le désordre des accès mémoire.png|centre|vignette|upright=2|Processeur avec émission dans le désordre des accès mémoire]] Une entrée de la ''Load/Store Queue'' contient plusieurs champs : un qui précise si l'opération est une lecture ou une écriture, un pour l'adresse mémoire à lire/écrire, un autre pour la donnée à écrire (qui est vide pour une lecture), un autre pour le registre de destination des lectures (inutile pour les écritures). Les deux derniers champs sont souvent fusionnés en un seul, qui est interprété différemment selon que l'instruction est une lecture ou une écriture. [[File:Load Store Queue unifiée.png|centre|vignette|upright=2.5|''Load/Store Queue''.]] Lorsqu'une micro-opération mémoire est émise, après renommage de registres, elle est insérée dans la ''Load/Store Queue''. Si l'adresse à lire/écrire est disponible, elle est immédiatement lue depuis les registres, idem pour une éventuelle donnée à écrire. Sinon, la micro-opération attend dans la LSQ que son adresse soit calculée par l'ALU entière. Pour gérer ce cas, elle contient des bits de validité pour chaque champ qui indiquent si l'adresse d'accès est connue, et si la donnée à écrire est disponible pour une écriture. Il faut noter que tout ce qui a été dit plus haut à propos du contournement des adresses vaut aussi avec une ''Load/Store Queue'', à un détail près. Pour détecter les dépendances, la LSQ doit comparer les adresses à lire/écrire, ce qui fait qu'elles doivent avoir été calculées avant d'entrer dans la LSQ. En clair, il n'est pas possible de faire les calculs d'adresse dans l'unité mémoire, juste avant d’accéder au cache. Les unités de calcul d'adresse sont réalisés dans une ALU entière ou une AGU spécialisée. Lorsqu'une instruction mémoire est émise, elle est décodée en deux micro-opérations : une pour le calcul d'adresse, une autre pour l'accès mémoire proprement dit. Le calcul d'adresse est réalisé soit dans une ALU entière, soit dans une AGU spécialisée. L'accès mémoire attend dans la ''Load/Store Queue'' que l'adresse soit calculée. Une fois l'adresse calculée, elle est envoyée à la ''Load/Store Queue'' et est enregistrée dans l'entrée adéquate. Reste qu'il faut envoyer l'adresse des ALU à la LSQ. Pour cela, on réutilise le réseau de contournement du processeur. L'implémentation la plus simple effectue les calculs d'adresse dans les ALU entières. La sortie de toutes les ALU entière est reliée à la LSQ. [[File:Load-Store Queue.png|centre|vignette|upright=2|Load-Store Queue]] Les processeurs modernes préfèrent utiliser des unités de calcul d'adresse dédiées, afin de simplifier le réseau de contournement. [[File:ALU et LSQ.png|centre|vignette|upright=1.5|ALU et LSQ]] En pratique, les LSQ proprement dites sont peu efficaces, pour un budget en transistor donné. La raison est qu'une entrée de la LSQ doit mémoriser indifféremment lectures et écritures. Et elle contient pour cela plusieurs champs : l'adresse à lire/écrire, le registre pour la donnée à lire/écrire, et un champ pour la donnée à écrire. Or, pour une lecture, le dernier champ, pour la donnée à écrire, est inutile. Sachant que les lectures sont beaucoup plus nombreuses que les écritures, ce champ sera gaché pour la majorité des instructiosn, et les transistors associés le seront aussi. Une solution pour cela est d'utiliser une file séparée pour les lectures et écritures. ===La détection des dépendances mémoire=== La ''Load/Store Queue'' est couplée à un système de détection des dépendances mémoire, qui détermine quelles instructions peuvent s'exécuter sans problème. Et ce système de détection des dépendances est bien différent de celui d'une station de réservation normale. Les ''Load/Store Queue'' comparent non pas des noms de registres, mais des adresses/opérandes. Chaque micro-opération en attente compare son adresse avec celle de toutes les micro-opérations précédentes. Ou presque, la comparaison ne doit tenir compte que des écritures, et de celles situées avant dans l'ordre du programme. La ''Load/Store Queue'' doit donc mémoriser les instructions dans l'ordre du programme, tout en faisant des comparaisons d'adresse. Ça en fait une sorte hybride entre mémoire associative et mémoire FIFO. Nous avions vu dans le chapitre "L'exécution dans le désordre" qu'il y a plusieurs manières pour implémenter une station de réservation : avec une mémoire associative, avec préplanification, avec des matrices de dépendances. Le problème est qu'on ne peut pas utiliser une mémoire associative pour la LSQ, qui utilise des comparateurs pour comparer les noms de registres/adresses. En effet, la détection des dépendances mémoire demande de faire beaucoup de comparaisons : chaque adresse est comparé à toutes les autres. Et les adresses faisant facilement 32 à 64 bits, les comparateurs sont bien plus imposants que ceux qui comparent des noms de registres de 5-10 bits. Le cout en matériel serait trop élevé, de même que le temps de calcul des dépendances. À la place, on utilise des matrices de dépendances. La détection des dépendances mémoire utilise précisément deux matrices de ce type : une matrice de disponibilité, et une matrice de dépendance. Ces matrices forment une espèce de tableau carré, organisé en lignes et en colonnes. L'instruction dans la énième entrée se voit attribuer la énième ligne et la énième colonne. À l'intersection d'une ligne et d'une colonne, on trouve un bit qui indique si l'instruction de la ligne et celle de la colonne ont une dépendance. La '''matrice de disponibilité''' permet de bloquer l'exécution des lectures/écritures tant qu'une instruction précédente n'a pas calculé son adresse, tant qu'on ne peut pas vérifier les dépendances. Lorsqu'une instruction est ajoutée dans le LSB, elle met tous les bits de la colonne attribuée à 1 si l'adresse à lire/écrire est inconnue, puis les met à 0 une fois l'adresse calculée. Une instruction ne peut pas démarrer si, sur la ligne qui lui est attribuée, se trouve un 1. Plus précisément, si on trouve un 1 pour les instructions plus anciennes, ce qui fait qu'une partie de la matrice est ignorée. Les bits notés X dans le tableau suivant sont ignorés, car ils précisent la disponibilité des opérandes d'un opérande ultérieure, ce qui est inutile. En clair, les calculs d'adresse modifient les colonnes, et on vérifie les lignes pour autoriser l'exécution. {|class="wikitable" |- ! Instructions mémoire dans la LSB, triées de la plus ancienne à la plus jeune ! 0 !! 1 !! 2 !! 3 !! 4 !! 5 !! 6 |- ! 0 | 1 || X || X || X || X || X || X |- ! 1 | 0 || 0 || X || X || X || X || X |- ! 2 | 0 || 1 || 0 || X || X || X || X |- ! 3 | 0 || 1 || 1 || 1 || X || X || X |- ! 4 | 0 || 0 || 0 || 0 || 1 || X || X |- ! 5 | 0 || 0 || 1 || 0 || 0 || 1 || X |- ! 6 | 1 || 1 || 1 || 1 || 1 || 1 || 0 |} Les '''matrices de dépendances''' fonctionnent sur le même principe, mais déterminent les dépendances mémoire. Lorsque le processeur a calculé une adresse, il la compare avec les adresses à lire/écrire déjà dans la LSB. Il met alors à jour les bits de la colonne de la matrice de dépendance : le bit à l'intersection d'une ligne et d'une colonne est mis à 0 si les deux instructions n'ont pas de dépendances, à 1 si elles en ont une. Une instruction mémoire est exécutée si tous les bits de sa ligne sont à 0. Là encore, on ne tient compte que des bits pour les instructions plus anciennes, la matrice a encore une fois une forme triangulaire, comme pour la matrice de disponibilité. Une optimisation scinde la ''Load/Store Queue'' en deux structures, aux rôles légèrement différents. La première gère la disponibilité des opérandes, la seconde gère seulement les dépendances mémoire. La première est une station de réservation où les instructions sont mises en attente tant que leurs opérandes ne sont pas prêts. La seconde met en attente des micro-opérations dont les opérandes sont prêts, mais qui doivent attendre pour une autre raison : dépendance mémoire, cache occupé, etc. L'avantage est qu'on remplace une grosse station de réservation par deux plus petites, mais l'intérêt est surtout relié au système de détection des dépendances. Sans cette optimisation, on a deux matrices énormes reliées à une ''Load/Store Queue'' unique. Avec la séparation, la matrice de disponibilité est reliée uniquement à la première station de réservation, alors que la matrice de dépendance est reliée uniquement à l'autre. Les deux matrices sont donc plus petites, car reliées à deux stations de réservation mémoire plus petites. ==L'exécution spéculative des accès mémoires== Pour rappel, le but de la désambiguïsation mémoire est d'exécuter les lectures le plus tôt possible. Les données lues sont en effet, le départ d'une série d'instructions dépendantes, généralement des instructions arithmétiques, mais parfois d'autres lectures. Quand on manipule des structures de données, il n'est pas rare qu'une lecture lise un pointeur-adresse utilisé par une autre lecture. Les techniques de désambiguïsation mémoire que nous avons vu précédemment sont dites conservatrices, à savoir qu'elles ne changent pas l'ordre de deux instructions mémoire si elles ont une dépendance d'adresse. Elles exécutent une lecture le plus tôt possible, mais seulement si on sait que celle-ci n'aliase pas d'écritures précédentes. Et cela demande de connaitre les adresses des écritures précédentes dans l'ordre du programme. Si une lecture est précédée par une ou plusieurs écritures, les adresses à écrire doivent être connues. Il se peut en effet qu’une écriture dont on ne connait pas l'adresse aliase la lecture. La garantie est liée à la présence de la file de µops mémoire ou la file de µops STORE. Si une seule écriture a une adresse inconnue, elle reste dans la file de µops mémoire et bloque l'émission de toutes les autres micro-opérations mémoire, lecture comme écriture. Mais il existe des techniques dites spéculatives, qui modifient l'ordre des accès mémoire sans se soucier de leurs dépendances. Elles émettent les lectures dès que leurs opérandes sont prêts, sans se préoccuper de l'aliasing avec une écriture précédente. Pour éviter tout problème, le processeur vérifie si aucune dépendance mémoire n'est violée et corrige le tir dès qu'une violation est détectée. Le processeur vérifie s'il a fait une erreur de prédiction, en vérifiant les adresses à écrire ou lire. En cas d'erreur, le processeur fait comme lors d'une prédiction de branchement ratée : il remet le pipeline en ordre et ré-exécute les accès mémoire dans le bon ordre. Il s'agit d'un cas particulier d’'''exécution spéculative''', au même titre que la prédiction de branchement. Toutes les techniques de ce genre exécutent des lectures dans le désordre. L'avantage est que cela permet d'exécuter les lectures en avance. Vu que la donnée lue est l'opérande d'autres instructions, les exécuter en avance fait prendre de l'avance à un paquet d'instructions. Mais il faut comparer cet avantage au risque de mauvaise prédiction. Et aussi bizarre que cela puisse paraître, cela donne de bons résultats. Il faut dire que les situations où une lecture relit une donnée tout juste écrite sont rares : même pas 2 à 3 % des lectures. Les dépendances mémoire sont donc très rares, les cas d'aliasing sont vraiment limités. En termes de cout en transistors, le hardware qui vérifie les dépendances mémoire reste globalement le même à peu de choses près, il est juste déplacé dans le pipeline et adapté à sa nouvelle fonction. ===La file de lectures=== La première technique que nous allons voir reprend la technique du ''Load Ordering, Store Ordering'', avec ses deux files de µops de lecture et d'écriture. Elle exécute les lectures sans se préoccuper des dépendances avec les écritures. Mais le processeur vérifie qu'aucune violation de dépendance n'a eu lieu après un certain temps. Une violation de dépendance peut avoir lieu pour n'importe quelle instruction précédant la lecture dans l'ordre du programme. En clair, le processeur doit conserver les lectures spéculatives tant que les instructions précédentes ne sont pas terminées. Pour cela, il faut ajouter une nouvelle file d'attente, qui mémorise les lectures terminées. Nous l’appellerons la file de vérification des lectures, ou encore la '''file de lectures'''. Elle fonctionne sur le même principe que la file d'écriture et les deux font partie de l'unité mémoire. Les deux visent à remettre les lectures/écritures dans l'ordre du programme, afin que les instructions suivant une lecture/écriture fautive soient annulées. Les lectures sont insérées dans la file de lecture à l'émission, quand elles quittent la file de µops mémoire/LSQ, ce qui est la même chose avec les écritures pour la file d'écriture. Une différence très importante est que les écritures sont retardées alors que les lectures s'exécutent immédiatement. D'ailleurs, la file de lecture ne sert pas pour le contournement : les données lues sont immédiatement envoyées au chemin de données, pas besoin de les contourner ultérieurement. Alors que la file d'écriture est utilisée pour le contournement en cas de dépendances RAW. Les lectures sortent de la file µops LOAD dès que leurs adresses sont calculées, sans tenir compte des dépendances mémoires. Elles sont alors ajoutées à la file de lectures et s'exécutent immédiatement, de manière spéculative. Pour vérifier qu'il n'y a pas d'erreur de spéculation, le processeur conserve l'adresse de la lecture effectuée dans la file de lectures. Les lectures quittent la file de lecture quand toutes les instructions précédentes dans l'ordre du programme sont terminées, à savoir tant quand elles ont quitté le tampon de réordonnancement/ROB. Notons que la file de vérification des lectures contient les lectures dans l'ordre du programme. En effet, les lectures sont accumulées en sortant de la file de µops LOAD, où elles sont triées dans l'ordre du programme. Et cela permet de gérer les erreurs de prédiction parfaitement, en annulant les instructions suivant une erreur de prédiction. [[File:Spéculation avec une file de lecture.jpg|centre|vignette|upright=2.5|Spéculation avec une file de lecture.]] Reste à détecter les erreurs de prédiction, ce qui peut être fait avec deux méthodes. Avec la première, les violations de dépendances mémoire sont faites à chaque écriture. Précisément, la détection a lieu quand une écriture est sur le point de quitter la file d'écriture. L'unité mémoire récupère alors l'adresse d'écriture et la compare avec toutes les lectures dans la file de vérification des lectures. Si aucune correspondance n'est trouvé, c'est que les lectures spéculatives n'ont accédé à l'adresse d'écriture. Mais s’il y a correspondance, c'est qu'une lecture a lu l'adresse avant qu'elle soit écrite. Pour cela, la file de vérification des lectures est un mélange entre FIFO et cache/mémoire associative. La vérification fait cependant gaffe à ne prendre en compte que les lectures situées après l'écriture dans l'ordre du programme (seulement ces instructions sont capables de générer une dépendance RAW). Avec la seconde méthode, les violations de dépendance mémoire sont détectées au moment où la lecture quitte à la file de lectures et le ROB. Mais cela demande que la donnée lue soit recopiée dans la file de lecture. Quand la lecture quitte la file de lecture et le ROB, la lecture est ré-exécutée et la donnée relue. Le processeur compare alors la donnée lue à ce moment avec la donnée mémorisée dans la file de lecture. Si la donnée est différente, alors il y a eu erreur de violation de dépendance mémoire. Évidemment, relire une donnée n'est pas gratuit. Il est possible de limiter son impact en performance en dédiant un port de lecture sur le cache rien que pour ça. Mais le cout en circuit est comparable à l'usage d'une FIFO associative de la technique précédente. Mais quoi qu'il en soit, le cache doit permettre des lectures en un seul cycle, sans quoi la méthode ne marche pas vraiment. ===La prédiction de dépendances mémoires=== Certains processeurs essayent de prédire si deux accès mémoires sont dépendants : ils incorporent une unité qui va fonctionner comme une unité de prédiction de branchement, à la différence qu'elle prédit les dépendances mémoires. Si cette unité prédit que deux accès mémoires sont indépendants, le processeur les exécute dans le désordre, et les exécute dans l'ordre du programme dans le cas contraire. Il faut prendre en compte les erreurs de prédiction, ce qui est fait comme pour les mauvaises prédictions de branchement : on vide le pipeline. Beaucoup de techniques de prédiction des dépendances mémoire ont été inventées et en faire une revue exhaustive serait long et fastidieux. On pourrait citer les ensembles colorés (''color sets''), et bien d'autres techniques. Mais nous n'allons parler que des techniques les plus élémentaires. Quoi qu’il en soit, la recherche sur le sujet est assez riche, comme toujours quand il s'agit d'architecture des ordinateurs. On peut améliorer cette technique en mémorisant les instructions qui ont causé une mauvaise prédiction de dépendance mémoire. La prochaine fois qu'on exécute ces instructions, on sait qu'il y a de grandes chances qu'il se produise une erreur de prédiction, ce qui pousse à ne pas les exécuter de manière spéculative. On peut pour cela réutiliser les techniques de prédiction de branchement, tels des compteurs à saturations, mis à jour en cas d'erreurs de prédiction de dépendances mémoire. Dans tous les cas, on trouve un cache, équivalent au ''branch target buffer'', qui mémorise les instructions fautives (leur ''Program Counter''), avec d'autres informations comme les adresses des instructions dépendantes. La première classe de techniques du genre consiste à mémoriser les lectures qui ont causé une violation de dépendance, tandis que l'autre ne mémorise que les écritures. Cette dernière est l'approche utilisée par le '''cache de barrières d’écriture''' (store barrier cache). Enfin, nous allons conclure avec une dernière technique : celle des '''ensembles d’écritures''' (store sets). Cette technique est capable de gérer le cas où une lecture dépend de plusieurs écritures : le processeur mémorise l'ensemble des écritures avec lesquelles la lecture a déjà eu une dépendance. Cet ensemble d'écritures associées à une lecture est appelé tout simplement un ensemble d’écritures, et reçoit un identifiant (un nombre) par le processeur. Cette technique demande d'utiliser deux tables : * une qui assigne un identifiant d’ensemble d’écritures à l'instruction en cours ; * une autre qui mémorise les ensembles d’écritures sous la forme d'une liste chainée : le début de la liste correspond à l'écriture la plus ancienne de l’ensemble. Cela permet d'obtenir l'écriture la plus ancienne dans cet ensemble d’écritures directement. Quand le processeur détecte une violation de dépendance entre une lecture et une écriture, elle ajoute l'écriture dans l’ensemble d’écritures adéquat. Le déroulement d'une lecture demande d'accéder à la première table pour récupérer l'identifiant de l’ensemble d’écritures, et l'utiliser pour adresser la seconde table. S'il y a dépendance, cet accès renvoie l'écriture fautive en cas de dépendance. Quand une écriture est envoyée à l'unité mémoire, celle-ci va accéder à la table de correspondances de la même manière qu'une lecture, et va récupérer l'identifiant de l’ensemble d’écritures auquel elle appartient, identifiant qui est utilisé pour vérifier s'il y a une écriture en cours d’exécution. Si c'est le cas, cela signifie que l'écriture en cours d’exécution doit s’exécuter avant l'écriture qui a consulté la table : cette dernière est mise en attente. ==La prédiction d'adresse et de valeur== D'autres techniques de prédiction mémoire plus élaborées que les précédentes existent. Il s'agit de la prédiction d'adresse et de la prédiction de valeur. Leur nom trahit ce qu'elles font. La première technique tente de prédire l'adresse d'une lecture/écriture, alors que la seconde tente carrément de prédire quelle sera la donnée lue. Il y a bien de la recherche académique sur le sujet, mais il s'agit de techniques assez osées, dont on voit mal comment elles pourraient fonctionner. L'efficacité de cette technique a été étudiée grâce à des simulateurs. Suivant les études ou les programmes, on trouve des résultats qui varient pas mal. Dans certains cas, la performance baisse un peu, et dans d'autres, on peut avoir des gains de plus de 10% ! Mais dans des cas normaux, on trouve des gains de 4-5% environ. Ce qui est tout de même pas mal à l'heure actuelle. Cependant, en Janvier 2025, à l'heure où j'écris ces lignes, il a été découvert la première utilisation de ces deux techniques dans un processeur commercial. La découverte fait suite à la publication de deux vulnérabilités matérielles sur les CPU Apple M2 et M4 et quelques CPU ARM, qui font justement usage de ces deux techniques. Les deux vulnérabilités, appelées SLAP et FLOP, sont assez similaires aux attaques Spectre et Meltdown, sauf qu'elles attaquent non pas la prédiction de branchement, mais la prédiction d'adresse et de valeur du CPU. ===La prédiction d'adresse=== La prédiction d'adresse tente de prédire l'adresse d'une lecture à l'avance, ce qui permet de lancer les lectures en avance. Si la prédiction est correcte, on gagne quelques cycles qui permet aux unités de calcul de faire leurs calculs plus en avance, sans compter que les mécanismes de désambiguïsation mémoire fonctionnent plus efficacement. Si jamais cette adresse est connue plus tôt, on détecte les dépendances plus rapidement et on peut agir en conséquence. Des variantes de ces unités de prédiction d'adresse sont utilisées pour précharger des données depuis le cache de donnée. Et leur efficacité est assez bonne, voire excellente dans certains cas. La différence est que la prédiction d'adresse est utilisée pour prédire les adresses à lire depuis le cache vers les registres, ce qui est le sujet de cette sous-partie. La prédiction d'adresse est réalisée par une sorte de cache, qui associe à chaque instruction la prochaine adresse à lire. Nous appellerons ce cache la '''table de prédiction d'adresse'''. Pour faire l'association instruction <-> adresse lue/écrite, le tag du cache utilise l'adresse de l'instruction (le ''program Counter''), alors que la ligne de cache associée contient l'adresse prédite. Son contenu est utilisé pour faire une prédiction. Lorsqu'une lecture est émise, la table est consultée pour récupérer en avance l'adresse à lire, avant que celle-ci soit calculée par l'ALU. La lecture est alors exécutée en avance, avant que la vraie adresse soit connue, en utilisant l'adresse prédite. Reste qu'il faut des circuits autour de cette table de prédiction d'adresse, pour déterminer si la prédiction est correcte, ainsi que pour remplir cette table avec une adresse prédite. Pour cela, il y a un circuit de prédiction d'adresse dédié. Il récupère les instructions qui quittent le ROB ou la file des lectures mémoire, afin de vérifier les lectures qui viennent de se terminer/''commit'' et qui quittent le pipeline. Il peut contenir une '''table d'apprentissage''', qui mémorise des informations nécessaires pour faire des prédictions d'adresse. Par exemple, un historique des dernières adresses lues pour les lectures les plus récentes, ou un historique des adresses des lectures. La table est aussi utilisée pour déterminer si les prédictions effectuées étaient correctes ou non. Pour cela, il est possible de réutiliser les techniques vues dans le chapitre sur la prédiction de branchement, notamment des compteurs à saturation. Pour la prédiction de branchement et les autres formes de prédiction mémoire, les table d'apprentissage et pour les instructions/adresses sont fusionnées en une seule. Mais ici, il est nécessaire de les séparer pour une raison assez particulière : éliminer la pollution du cache dans la table de prédiction d'adresse. On ne peut pas allouer une ligne de cache pour chaque nouvelle instruction de lecture exécutée. Seule une minorité des lectures profitent de la prédiction d'adresse. Il est nécessaire de filtrer les lectures pour ne conserver que celles qui profitent de la prédiction d'adresse, ce qui est possible plus facilement en séparant la table d'apprentissage et les compteurs à saturation de la table de prédiction d'adresse. Une première méthode consiste à prédire que la lecture lit toujours la même adresse, ce qui lui vaut le nom de '''prédiction d'adresse constante'''. On pourrait se demander pourquoi une telle situation surviendrait. La raison est qu'il arrive que les compilateurs n'arrivent pas à gérer les accès mémoires efficacement. Dans certaines situations un peu compliquées impliquant des pointeurs ou des références, divers phénomènes complexes d'''aliasing'' des pointeurs peuvent générer des relectures intempestives de données en mémoire. Cela peut aussi arriver lorsqu'on compile du code qui provient de plusieurs librairies, ou quand du code lit régulièrement des constantes en mémoire ROM. La prédiction d'adresse constante ajoute un circuit qui analyse les dernières lectures, une fois qu'elles quittent le ROB, qu'elles ''commit''. Si, pour une instruction de lecture, l'adresse lue est toujours la même, alors l'instruction est ajoutée dans la table de prédiction d'adresse. Vu que les instructions qui accèdent toujours à la même adresse sont rares, il est préférable d'initialiser les compteurs à saturation de façon à ce qu'ils disent que toute nouvelle instruction change d'adresse. Il s'agit d'une méthode simple mais peu efficace, car cette situation est rare. Une autre méthode détecte les accès en enjambées, là encore quand les lectures quittent le ROB. Nous l’appellerons la '''prédiction d'adresse en enjambées'''. De tels accès surviennent régulièrement quand on accède des tableaux ou d'autres structures de données semblables, ce qui rend la technique très intéressante. Implémenter cette technique est facile : il suffit d'ajouter un circuit qui détecte les accès en enjambées, au lieu de celui qui détecte les accès constants. À chaque fois qu'une lecture entraine un succès de cache dans la table de prédiction d'adresse, l'enjambée est ajoutée à l'adresse contenue dans la table de prédiction d'adresse, l'ancienne adresse prédite est remplacée par celle avec l'enjambée d'ajoutée. Sur les Apple M2-M4, la prédiction d'adresse gére aussi bien les adresses constantes que les accès en enjambée. Le brevet qui décrit l'implémentation de l'unité de prédiction d'adresse et de valeur est potentiellement le suivant : [https://patents.google.com/patent/US11829763B2/en Early load execution via constant address and stride prediction]. En théorie, il est possible de faire mieux en repérant des accès mémoires qui se répètent de façon régulière et cyclique, même s'ils n'ont aucune enjambée. Ce genre d'accès se trouve assez souvent lorsque l'on manipule des listes chainées ou des structures de données assez irrégulières comme des arbres, des graphes, etc. Mais il n'y a pas encore de CPU qui implémente de telle optimisation. ===La prédiction de valeur : prédire la donnée lue=== Les techniques de '''prédiction de valeur''' (''Value Prediction'') consistent à prédire quelle est la donnée qui sera lue par une instruction de lecture. Oui, vous avez bien lu : le processeur est capable de parier sur la valeur qui sera chargée depuis la mémoire, de prédire si cette valeur vaut 0, 1, 1024, etc. Une fois son pari fait, il exécute les instructions du programme avec la valeur qu'il a pariée de façon spéculative. Si le pari est correct, le CPU continue l’exécution. Sinon, il est obligé de vider le pipeline et de recommencer avec la bonne valeur. Au premier abord, cette technique semble franchement mal partie tellement les chances de se tromper sont tellement énormes ! Mais le fait est que, dans certains cas, il est possible de spéculer correctement. Là encore, les techniques les plus simples fonctionnent dans deux cas. Le premier est celui où une donnée est relue à l'identique à chaque fois que la lecture est exécutée. Le second est celui où la donnée est incrémentée/décrémentée d'une constante qui est toujours la même d'une exécution de la lecture à l'autre. Une sorte d'enjambée constante, mais pour les données. Nous allons nous concentrer sur le premier cas, celui où une donnée est relue plusieurs fois sans être modifiée entre temps. L'idée de base est qu'une instruction de lecture qui s'exécute plusieurs fois de suite à la même adresse renvoie la même valeur à chaque fois. C'est parfaitement possible s’il n'y a eu aucune écriture à cette adresse entre-temps, d'où le fait qu'il faille surveiller si les prédictions constantes sont correctes. On peut se demander quelles sont les raisons qui font qu'une instruction de lecture renvoie la même valeur à chaque fois. Après tout, autant lire une seule fois la donnée et la garder dans un registre une bonne fois pour toutes ! Mais dans la réalité, on fait face à quelques limites, qui seront détaillées dans la liste suivante. La première est que le manque de registre fait que certaines données sont conservées en RAM et sont relues fréquemment. Cela arrive quand on stocke des constantes en mémoire. Par exemple, sur les processeurs x86, les constantes flottantes ne peuvent pas être intégrées dans nos instructions via le mode d'adressage immédiat. À la place, on les stocke en mémoire et on les charge dans les registres à chaque fois qu'on en a besoin. L'implémentation est similaire à la prédiction d'adresse, si ce n'est que c'est la donnée lue qui est prédite. Là encore, on a une '''table de prédiction de donnée lue''', consultée lorsqu'une lecture est émise. La table de prédiction de la donnée lue est une mémoire cache qui associe le ''Program Counter'' de la lecture à la donnée prédite, éventuellement couplé à des compteurs à saturation. Elle est consultée à chaque fois qu'une lecture est émise, la donnée adéquate est récupérée lors d'un succès de cache. On trouve aussi un circuit qui insère ou retire des instructions de la table de prédiction de donnée lue. Elle détecte les lectures prédictibles, couplé à une table d’apprentissage, et quelques circuits annexes liés au ROB ou aux files de lectures. Elle contient au minimum des compteurs à saturations, associés chacun à une instruction (son ''program counter'' pour être précis). ==La désambiguïsation mémoire a des effets de bord== La désambiguïsation mémoire a une caractéristique que l'exécution dans le désordre simple n'a pas : elle a des effets qui débordent sur la mémoire. Il est possible de savoir si un processeur fait de la désambiguïsation mémoire en regardant le bus mémoire. On s’aperçoit alors que les lectures se font dans un ordre différent de celui du programme. À l'opposé, l'exécution dans le désordre n'a pas d'effets observables de ce genre. Elle améliore la performance, elle modifie les durées observables des instructions, mais cela se limite à des questions de ''timings''. Le seul moyen de savoir si un processeur fait de l'exécution dans le désordre est de mesurer les latences/durées de chaque instruction. Mais aucun état observable au-delà des ''timings'' n'est modifié. Pas avec la désambiguïsation mémoire. ===La consistance mémoire=== Le fait que la désambiguïsation mémoire ait des effets observables ne pose aucun problème avec un seul processeur, ca elle est conçue pour. Par contre, les techniques de désambiguïsation mémoire peuvent poser des problèmes avec plusieurs processeurs. Il arrive que des programmes partagent une même portion de mémoire, et lisent/écrivent dedans. Avec plusieurs processeurs, chaque processeur effectue la désambiguïsation mémoire dans son coin sans se préoccuper des autres. Les opérations d'écriture peuvent être mises dans le désordre du point de vue des autres processeurs, et les lectures effectuées par les autres processeurs peuvent alors renvoyer de vielles données. Un exemple classique est celui de deux cœurs qui partagent le même cache ou la même mémoire, mais qui utilisent chacun une file d'écriture (''store buffer''). Imaginons que le premier cœur effectue une écriture, puis une lecture, à des adresses différentes. L'écriture est retardée grâce au tampon d'écriture, alors que la lecture lit directement le cache. Pour le premier processeur, l'écriture s'est réalisée avant la lecture, car pour lui, la fin de l'écriture signifie écrire dans le tampon d'écriture. Mais pour le second cœur, l'ordre s'est inversé : il voit la lecture dans le cache, puis l'écriture dans le cache. La raison est qu'il n'a pas connaissance du contenu du tampon d'écriture de l'autre cœur. Un autre exemple : les techniques de prédiction d'adresse et de valeur posent des problèmes avec les dépendances RAW. Elles permettent à une instruction mémoire de s'exécuter avant une autre, malgré la présence d'une dépendance RAW entre les deux. L'ordre entre les deux instructions change, alors que les autres processeurs ne devraient pas le voir. Et dans les faits, les processeurs qui incorporent ces techniques ont des modèles de consistance mémoire qui ne permettent pas ces optimisations en cas de dépendances RAW. Les deux techniques doivent idéalement être désactivées pour les instructions mémoire qui ont des dépendances RAW. Les programmeurs doivent tenir compte de ce genre de situations, dans des cas assez rares et liés à la programmation bas niveau. Pour cela, ils doivent savoir comment le processeur réorganise les accès mémoire. Concrètement, chaque processeur définit un '''modèle de consistance mémoire''' qui indique quelles optimisations sont activées et non. Il s'agit d'une sorte de contrat entre le logiciel et le matériel : les programmeurs savent comment le processeur va réorganiser les lectures et écritures et peuvent coder leurs programmes en fonction. L'implémentation du système de consistance mémoire dépend grandement de l'architecture, mais des modèles ont été standardisés afin de permettre aux programmeurs de savoir où placer les barrières mémoires. Il s'agit de vrais standards, formalisés, parfois mathématiquement, que des chercheurs étudient sur un plan mathématique et algorithmique. Le modèle préféré des programmeurs est la '''consistance séquentielle''', où les différents processeurs effectuent des accès mémoire dans l'ordre du programme et les accès mémoire simultanés sont interdits. La première contrainte interdit l'usage de mécanismes de désambiguïsation mémoire, la seconde interdit l'usage de caches non-bloquants. La consistance séquentielle a donc un cout en performance assez important, ce qui fait que les processeurs modernes n'utilisent pas la consistance séquentielle. Un modèle plus flexible est le '''''total store ordering''''', qui autorise la présence d'une file d'écriture et l'usage de caches non-bloquants pour les lectures (interdit d'avoir plusieurs écritures simultanées). C'est plus ou moins celui utilisé par les processeurs x86, comme on le verra plus bas. Il existe des modèles de consistance mémoire plus relâchés, appelés des '''modèles de consistance faible''', qui autorisent diverses optimisations de spéculation mémoire, la combinaison d'écriture (fusionner deux écritures à la même adresse en une seule), etc. Ils sont supportés sur les architectures ARM et POWER. ===Les barrières mémoire=== Le changement d'ordre des lectures et écritures peut poser occasionnellement des problèmes avec la programmation pour les architectures multi-processeur ou multicœurs. Il existe des morceaux de code qui ne marchent que si la consistance séquentielle est respectée et il faut faire en sorte qu'ils marchent sur des processeurs avec un modèle de consistance mémoire différent. Pour cela, les processeurs incorporent des instructions appelées '''barrières mémoires''' ou '''''Fences'''''. Elles forcent le processeur à terminer tous les accès mémoire qui précédent dans l'ordre du programme. Certains processeurs possèdent une barrière mémoire pour les lectures et une autre pour les écritures. D'autres processeurs ajoutent des barrières mémoires dédiées à des cas particuliers. Elles permettent de forcer les accès à des données partagées à dérouler correctement. [[File:Fences.png|centre|vignette|upright=2|Fences.]] Leur implémentation est assez simple : elles empêchent l'émission de toute nouvelle instruction mémoire, tant qu'une condition précise n'est pas réunie. Par exemple, la barrière mémoire pour les écritures attend que la file d'écriture soit vidée avant de démarrer le moindre accès mémoire. Un compilateur peut placer les barrières mémoires au bon endroit, avec un peu d'aide du programmeur. Certains langages de programmation permettent d'indiquer au compilateur qu'une donnée doit toujours être lue depuis la mémoire RAM, via le mot-clé volatile. C'est très utile pour préciser que cette donnée est potentiellement partagée par plusieurs processeurs ou manipulable par des périphériques. Les compilateurs peuvent placer des barrières mémoires lors des lectures ou écritures sur ces variables, mais ce n'est pas une obligation. Il arrive aussi que le programmeur doive manipuler explicitement des barrières mémoires. Utiliser l'assembleur est alors une possibilité, mais qui est rarement exploitée, pour des raisons de portabilité. Pour limiter la casse, certains systèmes d'exploitations ou compilateurs peuvent aussi fournir des barrières mémoires explicites, encapsulées dans des bibliothèques ou cachées dans certaines fonctions. ===La modèle de consistance des processeurs x86=== Après avoir vu la théorie, passons maintenant à la pratique. Dans cette partie, on va voir les modèles de consistances utilisés sur les processeurs x86, ceux qu'on retrouve dans les PC actuels. Le modèle de consistance des processeurs x86 a varié au cours de l'existence de l'architecture : un vulgaire 486DX n'a pas le même modèle de consistance qu'un Core 2 duo, par exemple. Ils ont évolués au cours du temps, avec l'arrivée de nouvelles optimisations. De plus, leur formalisation a été progressive, et s'est faite au fur et à mesure. En général, les modèles de consistance des processeurs x86 ont toujours étés assez restrictifs, si on les compare aux autres processeurs. Il s'agit de modèles de type ''total store ordering'' (TSO), au moins dans les grandes lignes. Ils permettent donc d'effectuer certaines lectures en avance, soit parce que les lectures se font à des adresses différentes, soit par utilisation de réacheminement écriture vers lecture. Les possibilités d'exécution en avance des lectures varient suivant le processeur, elles deviennent de plus en plus performantes avec le temps. Le premier modèle de consistance est apparu sur les premiers processeurs x86 et est resté en place sur tous les processeurs de marque Pentium. Les processeurs de l'époque n'incorporaient pas beaucoup d'optimisations, le budget en transistor n'était pas assez conséquent pour ça, la mémoire n'était pas assez lente. Le modèle TSO de l'époque n'autorisaient que peu de lectures anticipées. Une lecture ne peut être exécutée en avance que sous les conditions suivantes : * les écritures contournées se font dans la mémoire cache ; * la lecture doit se faire dans la mémoire RAM ; * les écritures se font à une adresse différente de la lecture ; * aucune transaction avec un périphérique ne doit être en cours. A partir du Pentium 4, les choses changent. Le Pentium 4 est en effet le premier processeur à implémenter des techniques permettant d’exécuter plusieurs processus en parallèle, dont l'Hyperthreading. En conséquence, le modèle de consistance a dû être assoupli pour éviter de perdre bêtement en performance. Il s'agit d'un vrai modèle de type TSO, la majeure partie des contraintes sur les lectures anticipées sont réduites au minimum. Il y a aussi des contraintes supplémentaires pour les instructions dites atomiques, ainsi que pour les instructions qui accèdent aux périphériques ou aux entrées-sorties. Une optimisation séparée du TSO est que les écritures en mémoire peuvent changer d'ordre dans un cas exceptionnel : les écritures effectuées par les instructions de copie mémoire comme REPMOVSD, REPSCACB, ainsi que les instructions SSE MOVNTI, MOVNTQ, MOVNTDQ, MOVNTPS, MOVNTPD. Les écritures effectuées dans ces instructions peuvent se faire dans un désordre complet (ou presque). Lors du passage au 64 bits, le modèle mémoire des processeurs x86 de l'époque a été formalisé dans un papier d'Intel appelé [https://www.cs.cmu.edu/~410-f10/doc/Intel_Reordering_318147.pdf Intel® 64 Architecture Memory Ordering White Paper], mis à jour en 2008 suite à quelques problèmes techniques. La formalisation du modèle a été d'une grande aide aux programmeurs, qui devaient se débrouiller avec des documentations qui ne formalisaient pas de modèle de consistance précis. Le document décrit un modèle de consistance mémoire portant le nom barbare de ''total lock order + causal consistency” (TLO+CC)'', qui admet plus d'optimisations que le modèle TSO. Mais la description était en réalité légèrement différente du modèle mémoire réellement implémenté sur les processeurs existants, qui utilisaient du TSO, sauf en de rares occasions. Les concepteurs de processeur font souvent cela, à savoir définir un modèle de consistance plus laxiste que réellement implémenté, pour des questions de comptabilité. Ainsi, si les futurs processeurs de la marque implémentent un modèle plus laxiste, les programmes déjà codés continuent de fonctionner. Le modèle décrit dans la documentation laisse de la marge pour le futur. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les implémentations modernes de l'OOO | prevText=Les implémentations modernes de l'OOO | next=Le parallélisme mémoire | nextText=Le parallélisme mémoire }} </noinclude> qrhbxsqsk46owgvadt9foxji5hkdjdc 773633 773632 2026-09-29T21:11:00Z Mewtow 31375 Remplacement fenêtre instruction par shceduler 773633 wikitext text/x-wiki Dans les chapitres précédents, nous avons vu la mal-nommée exécution dans le désordre dans les chapitres précédents, qui devrait plutôt s'appeler l'émission dans le désordre. Elle modifie l'ordre des instructions pour gagner en efficacité, mais cela n'est valable que pour les instructions travaillant sur des registres ! Nous n'avons pas parlé de l'exécution dans le désordre des accès mémoire, car ils sont un peu à part. Et pour comprendre pourquoi, nous allons dédier ce chapitre à la gestion des accès mémoire dans le pipeline. ==L’émission des accès mémoire== Avant de poursuivre, faisons un rappel rapide. Il faut distinguer deux types de dépendances de données : les dépendances de registres (deux instructions manipulent le même registre), alors que l'unité mémoire gère les dépendances d'adresse (deux instructions manipulent la même adresse). La différence registre-adresse fait que la gestion des dépendances est totalement différente. ===L'''aliasing'' mémoire et les dépendances mémoire=== Pour rappel, deux instructions ont une dépendance d'adresse si elles écrivent ou lisent la même adresse mémoire, ce qui interdit de changer leur ordre. Des instructions mémoires qui lisent/écrivent des adresses différentes sont indépendantes. Lorsque deux instructions mémoire lisent/écrivent à la même adresse, on parle d''''aliasing mémoire'''. Détecter les cas d'aliasing mémoire est primordial pour gérer la désambiguïsation mémoire, et cela demande de comparer des adresses. Formellement, l'aliasing mémoire n'est ni plus moins que l'application des dépendances de données aux instructions mémoire. Et comme les autres dépendances de données, il existe plusieurs types d'aliasing mémoire : RAR, RAW, WAR et WAW. Les dépendances RAR ne posent aucun problème, les lectures peuvent changer d'ordre sans aucun problème, tant qu'il n'y a pas d'écritures entre les deux. Par contre, les autres dépendances imposent trois contraintes. * Les dépendances RAW imposent que les lectures ne doivent pas s'exécuter avant une écriture à la même adresse. * Les dépendances WAR imposent que l'on ne peut pas déplacer une écriture avant une lecture à la même adresse. * Enfin, les dépendances WAW font que l'ordre des écritures doit être celui du programme : impossible de changer l'ordre de deux écritures. Les trois contraintes peuvent s'implémenter de plusieurs manières différentes. Comme pour les dépendances de données normales, seules les dépendances RAW sont de vraies dépendances de données. Les deux autres dépendances viennent du fait que l'on utilise la même adresse pour stocker des valeurs différentes. S'il existe des techniques similaires au renommage de registre permettent de les faire disparaitre, elles sont très limitées. ===La désambiguïsation mémoire=== Diverses optimisations permettent d'émettre des accès mémoire dans le désordre, exactement comme l’exécution dans le désordre le fait pour les autres instructions. Elles utilisent pour cela des ''schedulers'' spécialisées dans les accès mémoire. Il faut vraiment insister sur le fait que l'exécution dans le désordre proprement dite ne se préoccupe pas des micro-opérations mémoire. Pour faire la distinction, on parle de '''désambiguïsation mémoire''' (''memory disambiguation'') pour parler de l'exécution dans le désordre des accès mémoire. Le but de la désambiguïsation mémoire est d'exécuter les lectures le plus tôt possible. La raison est que la donnée lue est utilisée par d'autres instructions, dépendantes de la lecture. Elles sont donc à la tête d'une chaine de dépendances de données qui peut bloquer le pipeline si elle n'est pas résolue très tôt. Dès qu'une lecture peut être lancée, elle accède directement au cache de données. Par contre, si l'aliasing ne le permet pas (écriture à la même adresse pas encore effectuée) ou que l'adresse à lire n'a pas encore été calculée, la lecture attend son tour. Le problème est que la désambiguïsation mémoire demande de comparer des adresses, pour détecter les dépendances d'adresse. Et cela pose de sérieuses contraintes pour son implémentation. En comparaison, l'exécution dans le désordre normale compare des registres, ce qui est beaucoup plus simple. Les registres utilisés par une instruction sont directement encodés dans l'instruction elle-même, ce qui fait qu'on peut détecter les dépendances de registre à l'émission, voire au décodage. Et elles peuvent même être éliminées par le renommage de registre pour les dépendances WAW et WAR. Par contre, les adresses sont des opérandes d'instruction, elles ne sont pas encodées dans l'instruction elle-même. Il y a certes d'exception de l'adressage absolu, mais elle est minoritaire. Avec l'adressage indirect ou indicé, les adresses sont soit lues depuis les registres, soit calculées par une unité de calcul. Les adresses ne sont donc connues qu'une fois que l'instruction a attendu suffisamment de temps dans le ''scheduler''. ===Le calcul anticipé des adresses mémoire=== La désambiguïsation mémoire fonctionne d'autant mieux que les adresses à lire/écrire sont connues le plus tôt possible. Pour cela, il est possible de séparer les accès à la mémoire en deux micro-instructions : une pour le calcul d'adresse et l'autre pour les accès mémoire. Cela permet de calculer les adresses dès que possibles, et donc de vérifier à l'avance si l'adresse calculée a des dépendances avec celles des autres instructions. La détection des dépendances est ainsi anticipée de quelques cycles, permettant un accès anticipé sûr des accès mémoire. On parle de '''calcul anticipé des dépendances'''. Une implémentation possible effectue les calculs d'adresse dans les unités de calcul entière. L'ALU entière et l'unité mémoire sont alors dans deux avals séparés, en parallèle. La micro-opération de calcul d'adresse s'exécute dans une ALU, et son résultat est envoyé à l'unité mémoire. Pour cela, l'adresse calculée est envoyée à l'unité mémoire via un système de contournement dédié, qui relie les sorties des ALU entières à l'unité mémoire. Une solution alternative utilise un aval unique qui s'occupe à la fois des micro-opérations entières et des micro-opérations mémoire. L'aval a alors deux étages en série, un pour l'unité de calcul, suivi par l'étage d'accès mémoire. Le pipeline RISC classique était dans ce cas, pour rappel. Cette solution permet d'avoir un pipeline dit de longueur fixe, à savoir que toutes les instructions font le même nombre de cycles d'horloge. De plus, elle garantit que les instructions mémoire sont décodées en une seule micro-opération. En clair, il y a un seul aval pour toutes les instructions. Mais elle vient avec un défaut majeur : de nombreuses instructions n'utilisent pas l'unité mémoire, mais doivent quand même traverser l'étage associé, qui passe un cycle à ne rien faire. ==L’émission dans l'ordre des accès mémoire== Avant toute chose, faisons quelques rappels sur l'exécution dans le désordre. Les micro-opérations renommées sont mises en attente avant que les conditions pour leur émission soient remplies. La mise en attente peut se faire soit dans une file de micro-opération, soit dans un ''scheduler''. Une file de micro-opération est une mémoire FIFO qui garde les micro-opération dans leur ordre d'émission, l'ordre du programme. Les micro-opérations sont donc émises dans l'ordre du programme, il n'y a pas d'émission dans le désordre. Par contre, les ''schedulers''s peuvent émettre les micro-opérations dans le désordre, dans un ordre différent de celui du programme. Dans les deux cas, les écritures sont retardées via une file d'écriture, qu'on a vu il y a quelques chapitres et sur laquelle on fera des rappels. ===La file de µops mémoire=== Avec l''''émission dans l'ordre des accès mémoire''', le processeur émet les accès mémoire dans l'ordre du programme. Cela implique que l'unité mémoire n'a pas de ''scheduler'', ni de station de réservation associée. À la place, les micro-opérations mémoire sont placées dans une file de micro-opération dédiée, appelée la '''file de µops mémoire'''. Par contre, pour les unités de calcul, le processeur utilise des ''schedulers''. Autant les accès mémoire se font dans l'ordre, autant les instructions arithmétiques/logiques/branchements/autres sont exécutées dans le désordre. En clair, le processeur peut supporter l'exécution dans le désordre, sauf pour les micro-opérations mémoire. [[File:Processeur avec émission dans l'ordre des accès mémoire.png|centre|vignette|upright=2|Processeur avec émission dans l'ordre des accès mémoire]] : Nous avons volontairement omis le cas où le processeur n'a pas d'exécution dans le désordre, où il y a une file de micro-opération unique. Mais c'est globalement la même chose, car une file de micro-opération unifiée émet toutes les instructions dans l'ordre. La file de µops mémoire est une mémoire FIFO, qui contient plusieurs entrées, chaque entrée pouvant accueillir une µops mémoire. Une entrée contient plusieurs champs : un qui précise si l'opération est une lecture ou une écriture, un pour l'adresse mémoire à lire/écrire, un autre pour la donnée à écrire (qui est vide pour une lecture), un autre pour le registre de destination des lectures. Les deux derniers champs sont souvent fusionnés en un seul, qui est interprété différemment selon que l'instruction est une lecture ou une écriture. Elle contient aussi des bits de validité, qui indique si l'adresse ou la donnée sont disponibles, ou si le champ associé est vide. [[File:Load Store Queue unifiée.png|centre|vignette|upright=2.5|File de µops mémoire.]] L'unité mémoire ne permet que de faire un accès mémoire à la fois. Du moins, elle a un port sur lequel on envoie la micro-opération émise, que ce soit une écriture ou une lecture. Vu de l'extérieur, il faut attendre qu'un accès mémoire soit terminé pour lancer le suivant. Avant d'émettre une micro-opération mémoire, la file de micro-opération (son ''scoreboard'') vérifie si l'unité d'accès mémoire est libre ou non. Si elle est occupée, un accès mémoire est en cours, et on ne peut pas émettre de micro-opération mémoire. Une fois l'accès mémoire terminé, la mémoire ou le cache envoient un signal pour indiquer que l'accès est fini, et c'est au tour d'une nouvelle micro-opération mémoire. [[File:Unité de gestion des accès mémoires dans l’ordre.png|centre|vignette|upright=2.0|Unité de gestion des accès mémoires dans l’ordre]] Mais il s'agit là du comportement vu de l'extérieur de l'unité mémoire. En réalité, l'unité mémoire utilise quelques optimisations en interne qui permettent d'exécuter dans le désordre les micro-opérations mémoire. ===La file d'écriture : une FIFO de mise en attente des écritures=== Afin de supporter les exceptions précises, les écritures doivent respecter deux contraintes : s'exécuter dans le tout dernier étage du pipeline, s'exécuter dans l'ordre du programme. Pour cela, les écritures sont mises en attente tant que les instructions précédentes ne sont pas terminées. Les écritures dans le cache sont mises en attente dans une mémoire FIFO, appelée la '''file d'écriture''', ou encore la ''Write Queue''. Nous en avions déjà parlé dans le chapitre sur le pipeline, dans la section sur les exceptions précises. Mais quelques rappels ne feront pas de mal. L'écriture est insérée dans la file d'écriture lorsqu'elle est émise, elle en sort à l'étage de ''Writeback'' si tout se passe bien. Si une exception est détectée, l'étage de ''Writeback'' vide la file d'écriture, ce qui annule les écritures mises en attente, faites à tort. De plus, la file d'écriture est une mémoire FIFO, qui mémorise les écritures dans l'ordre du programme. En effet, les écritures sont ajoutées dans la file d'écriture lorsqu'elles sont émises, et elles sont émises dans l'ordre du programme. [[File:Store Queue sur un pipeline fixe.png|centre|vignette|upright=2|Write Queue sur un pipeline fixe]] La file d'écriture garantit que les écritures sont dans l'ordre du programme. Et cette propriété élimine totalement les dépendances WAW. Le fait que les écritures se font à la fin du pipeline élimine quant à elle les dépendances WAR. Il ne reste plus qu'à gérer les dépendances RAW, celles où une lecture lit une donnée écrite par une autre instruction. Une telle situation survient, car les écritures sont mises en attente pendant un certain temps, la donnée écrite peut être lue pendant ce laps de temps. La lecture ne peut pas lire la donnée dans le cache, car la donnée à lire n'y est pas encore enregistrée. Le cas est rare, car il demande de lire une donnée qu'on vient d'écrire, mais il existe. Il se manifeste surtout sur les processeurs avec peu de registre, où des données doivent régulièrement être déplacées temporairement en mémoire RAM. Pour éviter cela, une solution consiste mettre en attente les lectures si une écriture est en attente. Les lectures sont maintenues dans la file de µops tant que la file d'écriture n'est pas vide. La file de µops mémoire est suivie d'un circuit de détection des dépendances, un '''''scoreboard'' mémoire''' qui est assez simple. L'unité mémoire fournit un bit qui indique si la file d'écriture est vide ou non, ainsi qu'un second bit qui indique qu'elle est vide. Les deux ne sont pas compliqués à générer, ils font partie intégrante de l'interface de toute mémoire FIFO digne de ce nom. Le ''scoreboard'' mémoire utilise ces deux bits pour savoir s'il peut émettre une micro-opération mémoire. Il n'émet pas de lecture tant que la file d'écriture n'est pas vide. Il peut par contre émettre des écritures tant qu'elle n'est pas pleine. Une meilleure solution serait d'interdire les lectures, mais seulement en cas de dépendance mémoire détectée. Et c'est là qu'intervient la technique du '''''load bypassing'''''. Elle autorise une lecture, si elle n'a aucune dépendance avec les écritures mises en attente dans la file d'écriture. Elle doit être mise en attente dans le cas contraire. Pour l'implémenter, il faut comparer l'adresse à lire avec toutes les adresses dans la file d'écriture. La lecture est exécutée immédiatement si aucune correspondance n'est trouvée, mais elle est mise en attente dans le cas contraire. Pour cela, la file d'écriture est modifiée et devient un mélange entre FIFO et mémoire associative. L'adresse à lire est envoyée à la file d'écriture, et celle-ci vérifie si une écriture est en attente à cette adresse. Si c'est le cas, c'est un succès de ''Write Queue'' : la lecture doit être bloquée. Sinon, c'est un défaut de ''Write Queue'', la lecture accède au cache, là où se trouve la donnée à lire. Dans le chapitre sur le contournement, nous avons parlé d'une forme de contournement qui corrige ce problème. Les lectures peuvent lire la donnée depuis la file d'écriture si besoin, ce qui renvoie la donnée adéquate. Pour cela, les lectures consultent à la fois le cache et la file d'écriture, comme dit plus haut. L'adresse à lire est envoyée à la file d'écriture, et celle-ci vérifie si une écriture est en attente à cette adresse. Si c'est le cas, c'est un succès de ''Write Queue'', et celle-ci envoie alors la donnée associée à l'étage d'accès mémoire. Sinon, la lecture accède au cache, là où se trouve la donnée à lire. La solution porte le nom de ''Store to load Forwarding'', ou encore de '''réacheminement écriture-vers-lecture'''. [[File:Store to load forwarding sur un pipeline simple.png|centre|vignette|upright=2|Store to load forwarding sur un pipeline simple]] La lecture est mise en attente dans l'unité mémoire, vu que c'est elle qui fait les comparaisons d'adresse. Du point de vue extérieur, le ''scoreboard'' mémoire ne voit pas s’il y a eu succès dans la file d'écriture ou non. Il voit juste que l'unité mémoire est occupée et ne peut pas accepter de nouvelle lecture. Elle reste occupée durant quelques cycles, en cas de défaut de ''Write Queue'', le temps de faire la lecture dans le cache. Par contre, en cas de succès de ''Write Queue'', elle reste occupée tant que la lecture n'a pas donné de résultat, ce qui inclue le temps de mise en attente. Les processeurs haute performance implémentent tous le ''Store to load Forwarding'', mais quelques processeurs basse performance ne le font pas. Ils se contentent du ''load bypassing'', qui offre des performances correctes pour un cout en matériel bien plus modeste. Pour donner un exemple, la micro-architecture Jaguar d'AMD était dans ce cas. Elle a été utilisée sur les consoles de jeu de 8ème génération, comme la Xbox One et la Playstation 4. Les processeurs haute performance préférent utiliser plus de circuits pour implémenter le ''Store to load Forwarding'', mais l'implémentation n'est souvent pas complète. En effet, l'implémentation est souvent simple et ne prend en compte que des lectures/écritures à des adresses identiques, sans compter que la taille des données doit aussi être identique. Une écriture d'un entier de 32 bit sera contournée et envoyée à une lecture de 32 bits à la même adresse. Mais la lecture lit seulement 16 bits sur les 32 écrits, le contournement peut ne pas marcher. Concrètement, ce cas précis fonctionnera. Mais le cas inverse, avec une lecture lisant plusieurs écritures de taille plus petite, ne marchera pas sur tous les processeurs. Ne parlons pas du cas où les données écrites sont à cheval sur deux lignes de cache. ===Le contournement des adresses mémoire avec une file de µops=== Il faut noter qu'au moment où les instructions LOAD et STORE sont émises, leur adresse n'est pas forcément connue. Sauf en cas d'adressage absolu, mais mettons ce cas particulier de côté, il est assez rare en pratique. Les micro-opérations mémoire sont donc insérées dans la file de µops, mais l'adresse est souvent disponible plus tard. Il faut donc modifier le chemin de données pour que l'adresse soit envoyée à la file de µops mémoire. Pour simplifier, étudions le cas d'un processeur où les instructions LOAD/STORE ne gèrent que l'adressage indirect à registre, à savoir que l'adresse est lue dans un registre. Les calculs d'adresse sont réalisés par une instruction de calcul séparée de l'instruction LOAD/STORE. Tout calcul d'adresse a lieu dans les unités de calcul entière, les micro-opérations mémoire ne font pas de calcul d'adresse. Au minimum, il doit y avoir une connexion entre le banc de registre et la file de µops mémoire. Il faut alors attendre que les adresses soient enregistrées dans les registres pour être envoyées à la file de µops mémoire. Cependant, il est possible de profiter du réseau de contournement. L'idée est que l'adresse est accessible avant via le réseau de contournement, avant même d'être enregistrée dans les registres L'idée est que l'adresse est envoyée à l'unité mémoire dès qu'elle sort des unités de calcul. Le gain en performance étant important, tous les processeurs modernes ajoutent un système de contournement qui envoie les adresses à la file de µops mémoire. L'ALU entière calcule l'adresse finale, l'envoie à la file de µops mémoire. [[File:Contournement pour la file de µops mémoire.png|centre|vignette|upright=2|Contournement pour la file de µops mémoire]] Maintenant, les instructions LOAD/STORE avec un mode d'adressage indicé, ce qui signifie que l'instruction fait un calcul d'adresse et l'accès mémoire proprement dit. Une solution basique utilise une micro-opération séparée pour le calcul d'adresse et l'accès mémoire. Le calcul d'adresse envoie son résultat à la file de µops mémoire, sans l'enregistrer dans les registres, via contournement. Sans optimisation particulière, les calculs d'adresse sont réalisés par les ALU entières, le processeur n'est pas modifié et reste le même que celui du schéma précédent. Mais une autre solution utilise des ALU spécialisées dans les calculs d'adresse, appelées des ''Adress Generation Unit'', abrévié AGU. L'avantage est que cela simplifie grandement le réseau de contournement : seules les AGU sont connectées à la file de µops mémoire. Un autre avantage est lié à l'adressage de la destination. En utilisant des opérations entières usuelles, il faudrait préciser que le résultat est à destination de la file de µops mémoire, pour configurer le réseau de contournement. Avec des AGU, les calculs d'adresse sont des micro-opérations différentes des additions et soustraction, elles sont envoyées au AGU spécifiquement, pas besoin de préciser la destination. [[File:File de µops mémoire avec calcul d'adresse via AGU.png|centre|vignette|upright=2|File de µops mémoire avec calcul d'adresse via AGU]] Lors de l'émission, la micro-opération mémoire est insérée dans la file de µops mémoire, l'opération de calcul d'adresse est émise dans le ''scheduler''. Et les deux sont exécutés différemment. En effet, un calcul d'adresse est une opération arithmétique, qui est gérée par le système d'exécution dans le désordre. Elle peut s'exécuter dès que ses opérandes sont disponibles. À l'inverse de l'accès mémoire, qui lui doit se faire dans l'ordre du programme. Les adresses sont donc calculées en avance, puis insérées dans la file de µops mémoire. La µops de calcul d'adresse précise où enregistrer son résultat, le résultat est enregistré dans la bonne entrée de la file de µops mémoire. Les techniques précédentes décodent une instruction LOAD/STORE en deux micro-opérations. Mais il est possible de la décoder en une seule. Le calcul d'adresse est alors réalisé dans l'unité mémoire. Les opérandes du calcul d'adresse sont lues depuis les registres lorsque l'instruction quitte la file de µops mémoire, du moins pour les opérandes qui n'ont pas été contournées. Là, elles sont envoyées à l'unité mémoire, qui fait le calcul d'adresse. Dans les faits, aucun processeur commercial moderne n'utilise cette technique. [[File:File de µops mémoire avec calcul d'adresse dans l'unité mémoire.png|centre|vignette|upright=2|File de µops mémoire avec calcul d'adresse dans l'unité mémoire]] ===L'optimisation du pseudo-contournement des opérandes mémoire=== Les processeurs modernes implémentent une optimisation concernant les accès mémoire. Cette optimisation a été décrite par Agner Fog dans ses manuels d'optimisation, sous le terme de '''''Mirroring memory operand'''''. Il a documenté son apparition sur les processeurs Zen 2 d'AMD, puis son évolution sur les processeurs Zen 4 et 5. L'optimisation est bizarrement absente de la microarchitecture Zen 3. Elle se manifeste dans une condition très précise : plusieurs instructions proches accèdent à la même adresse. Les deux instructions ne sont pas forcément consécutives, il peut y avoir une dizaine ou centaine d'instructions entre les deux. Une telle situation survient souvent sur les CPU CISC, et notamment sur les CPU x86, car ils ont peu de registres. les compilateurs font donc beaucoup d'échanges entre pile d'appel et registres, ce qui fait que des données écrites dans la pile sont souvent relue quelques instructions plus tard. Dans ce cas, la donnée lue/écrite est mémorisée dans un registre interne au processeur et peut être accédée très rapidement. Par exemple, imaginons plusieurs lectures proches à la même adresse, sans écriture entre elles. Dans ce cas, le processeur ne fera qu'une seule lecture en mémoire RAM, les lectures ultérieures liront la donnée depuis le registre interne. Comme autre exemple, imaginons une écriture suivie plus tard par une lecture à la même adresse. Dans ce cas, la donnée sera écrite dans un registre interne, en plus d'être propagée dans le cache ou la RAM, et la lecture ultérieure lira directement le registre interne. Le gain en performance est alors conséquent, comparé à du simple ''store-to-load forwarding''. Il faut noter que la technique marche aussi pour les opérations ''load-op'', pas seulement pour les instructions d'accès mémoire. Par exemple, prenons une écriture en RAM, suivies quelques instructions plus tard par une opération ''load-op'' à la même adresse. L'écriture écrit à une adresse, qui est lue par l'instruction ''load-op''. L'optimisation s'applique : l'instruction ''load-op'' lira l'opérande mémoire depuis un registre interne du processeur, qui contient une copie de la donnée écrite. Sur les processeurs Zen 2, l'optimisation marchait aussi pour les instructions PSUH et POP, qui lisaient/écrivaient dans la pile d'appel. Mais cette possibilité a été retirée sur les processeurs Zen 5. La technique détecte que deux instructions accèdent à la même adresse sous certaines conditions bien précises. L'optimisation ne marche que pour les modes d'adressages indicés et indirect, avec ou sans décalages, mais pas en mode absolu ou relatifs. Il faut préciser que l'optimisation ne marche que pour les registres généraux, pas les registres flottants. Les registres doivent être précisés de la même manière dans toutes les instructions. Par exemple, le processeur ne reconnait pas que l'addition des deux registres RCX + RAX est la même que RAX + RCX. Sur les CPU Zen 2 et 4, elle ne marchait que pour des opérandes de 32 et 64 bits, mais les processeurs Zen 5 gèrent des données de 8 et 16 bits aussi. Les décalages étaient limités à 8 bits sur le Zen 2, mais n'a plus de limites sur les Zen 4 et 5. ==Le ''Load Ordering, Store Ordering''== Intuitivement, on dit qu'exécuter des µops mémoire dans le désordre demande de remplacer la file de µops mémoire par un ''scheduler''. Et si c'est en effet une solution intéressante, nous n'allons pas la voir toute de suite. Nous allons étudier le cas où cette file deµops mémoire est scindée en deux : une file pour les lectures et une autre pour les écritures. ===Les files de µops LOAD et STORE=== Dans le chapitre sur l'exécution dans le désordre, nous avons vu deux possibilités pour implémenter l'exécution dans le désordre. La première utilise un ''scheduler'' ou une station de réservation, l'autre utilise plusieurs files de µops séparées. Et cette technique peut parfaitement s'utiliser pour les micro-opérations mémoire. Les micro-opérations mémoire sont réparties dans deux files de µops mémoire séparées, chacun émettant des micro-opérations indépendamment de l'autre. Mais comment répartir les micro-opérations mémoire dans deux files, simplement et sans que cela pose des problèmes de dépendances de données ? La réponse à ces contraintes est toute simple : on utilise une file de µops spécialisée pour les lectures, et une autre pour les écritures. Les cours d'architecture des ordinateurs nomment souvent ces deux files en utilisant les termes de ''file de STORE'' (''store queue'') et de ''file de LOAD'' (''load queue''). Dans ce qui suit, nous parlerons de '''file de µops LOAD''' et de '''file de µops STORE''', pour bien préciser qu'il s'agit de file de µops. La file de STORE ne doit pas être confondue avec la file d'écriture, qui est appelée ''write queue'' en anglais. Les termes ''store queue'' et ''write queue'' désignent deux choses différentes, mais il y a un risque de confusion pour qui n'est pas assez attentif. D'autant plus que la méthode que nous allons voir a une file d'écriture en plus des deux files de µops mémoire. En effet, la file d'écriture ne mémorise pas des micro-opérations, juste des écritures déjà émises et en attente. Une entrée dans la file d'écriture contient une adresse et la donnée à écrire. Alors que dans la file de µops STORE, il se peut que l'adresse ou la donnée soient manquantes, car pas encore disponibles. De plus, la file d'écriture met en attente des écritures tant que les instructions précédentes ne sont pas terminées, alors que la file de µops STORE met en attente les micro-opérations avant leur émission. La première attend le feu vert de l'étage de ''Writeback'', l'autre attend le feu vert de l'étage de ''schedule'', d'un ''scoreboard'' amélioré. Les deux files sont chacune connectées à l'unité mémoire, via un port dédié. L'unité mémoire a donc un port pour les lectures, et un port pour les écritures. Le port d'écriture est relié à la file d'écriture, le port de lecture est directement relié au cache de données. il faut noter qu'une unité mémoire à deux ports n'est pas si bizarre que cela. En effet, le cache de données a lui aussi deux ports, dans la majorité des cas, avec un port de lecture et un port d'écriture. [[File:Load Ordering, Store Ordering.jpg|centre|vignette|upright=2|Exécution dans le désordre des lectures.]] Le fait de séparer lectures et écriture a de nombreux avantages. Le premier est qu'une file de µops mémoire unique gâche des transistors. Une écriture a besoin de mémoriser une adresse et une donnée, avec les bits de validité pour les deux. Une lecture n'a besoin que d'une adresse et du bit de validité associé. Avec une file de µops unique, chaque entrée de la file est suffisamment large pour contenir une écriture. Si elle ne contient qu'une lecture, elle est trop large, ce qui sous-utilise les circuits de la file. Avec des files de lecture/écriture séparées, on n'a pas ce problème, chaque file contient juste ce qu'il faut. Il y a donc une économie de transistors. Cependant, le système est moins flexible. Par exemple, prenons une file de µops mémoire unique, de 16 entrées. Elle peut mémoriser indifféremment 16 lectures, 16 écritures, ou n'importe quel mix d'écriture et de lectures tant qu'il se limite à 16 µops. Avec des files séparées, ce n'est plus le cas. Prenons par exemple le cas avec une file de µops LOAD de 10 éléments et une file de µops STORE de même capacité : impossible d'avoir 16 écritures en attente. Cependant, ce désavantage est quelque peu compensé par l'économie de transistor mentionnée précédemment, qui est réinvestie pour agrandir les files de µops. Typiquement, on agrandit la file de µops LOAD, car les lectures sont plus fréquentes que les écritures dans la majorité des programmes. En ayant une file de µops LOAD assez conséquente, le désavantage est fortement atténué, voire disparait. ===La gestion des dépendances avec des files de µops mémoire séparées=== L'usage de ces deux files de µops mémoire porte le nom de '''''Load Ordering, Store Ordering'''''. Il est intéressant de comparer cette technique avec la précédente, qui utilisait une file de µops mémoire séparée. Avec deux files séparées, les lectures s'exécutent dans l'ordre, les écritures s'exécutent dans l'ordre, mais les lectures peuvent passer avant/après les écritures et réciproquement, tant que l'aliasing le permet. Les écritures peuvent prendre de l'avance sur les lectures, ou réciproquement. Et cette avance est très utile si elle permet d'exécuter des lectures en avance. En comparaison, avec une file de µops unique, ni écritures ni lectures ne peuvent prendre de l'avance. Les performances sont donc améliorées, bien que de peu. Néanmoins, l'avance des lectures est limitée. Prenons le cas où une lecture doit être mise en attente, car son adresse n'est pas disponible. Avec une file de µops mémoire unique, la lecture bloque toutes les micro-opérations qui suivent. Avec deux files séparées, elle bloque uniquement les lectures, pas les écritures. Les écritures qui suivent la lecture peuvent s'exécuter. Le cas avec une écriture en attente est un peu différent. Une écriture en attente bloquera les écritures suivantes. Mais elle bloquera aussi les lectures postérieures : du point de vue de ces lectures, une écriture précédente a une adresse inconnue, on ne sait pas s'il y a dépendance mémoire avec et on suppose que oui dans le doute. En clair, l'avance des lectures n'a lieu que si les adresses des écritures précédentes sont connues, déjà calculées, sans quoi on ne peut pas détecter les dépendances mémoire. Le fait que les écritures peuvent être émises en avance fait que la détection des dépendances RAW est différent. L'idée générale reste cependant la même. Lors de l'émission, une lecture doit vérifier ses dépendances avec les écritures antérieures, une écriture doit vérifier ses dépendances avec les lectures ultérieures. Avec une file de µops unique, on est certain que les écritures antérieures sont dans la file d'écriture, dans l'unité mémoire. Et lorsqu'on émet une écriture, on est certain que les lectures ultérieures seront émises après. Avec deux files séparées, ce n'est pas forcément le cas. Si les lectures ont pris de l'avance, une écriture précédente peut être en attente dans la file de µops STORE, alors qu'une lecture ultérieure a été émise. Ce qui complique la détection des dépendances RAW d'adresse. Les détecter demande non seulement de vérifier la file d'écriture, mais aussi la file de µops STORE. Dans ce qui suit, on suppose que l'unité mémoire incorpore une file d'écriture, ce qui est toujours le cas en pratique. Le fait que les écritures se font dans l'ordre élimine les dépendances WAW et WAR. On suppose aussi que l'unité mémoire implémente le ''réacheminement écriture-vers-lecture'' (''store-to-load forwarding''). Ainsi, si une lecture est émise dans l'unité mémoire, les dépendances RAW avec les écritures déjà émises ne sont pas un problème. Par contre, il faut gérer les dépendances avec les écritures en attente dans la file de µops STORE, dont certaines sont antérieures à la lecture dans l'ordre du programme. Pour cela, il n'y a pas le choix : pour chaque lecture, on vérifie dans la file de µops STORE si elle a une dépendance avec une écriture antérieure. La gestion des dépendances RAW est donc gérée partiellement dans l'unité mémoire et la file de µops STORE. Pour l'implémenter, il faut comparer l'adresse à lire avec toutes les adresses dans la file de µops STORE. En cas de ''match'', la lecture est bloquée dans la file de lecture. Mais s'il n'y a aucune correspondance, alors la lecture peut s'exécuter. Pour cela, la file de µops STORE est un mélange entre FIFO et mémoire associative. Il faut préciser que la comparaison ne prend en compte que les écritures situées avant la lecture, dans l'ordre du programme. Les deux files de µops doivent donc mémoriser des informations sur l'ordre d'émission. De plus, il arrive que des écritures soient dans la file d'écriture, mais que leur adresse n'ait pas encore été calculée. Dans ce cas, il y a potentiellement dépendance avec la lecture si l'adresse se révèle être la même une fois calculée : on considère que les adresses inconnues sont des correspondances/''match''. La file de lecture met des lectures en attente, soit car elle attend ses opérandes, soit car elle attend que les lectures précédentes soient terminées, soit car l'aliasing ne lui permet pas. Elle a cependant un défaut : celui de forcer les lectures à s’exécuter dans l'ordre, ce qui est une contrainte inutile. Mais l'avantage est que l'implémentation est très simple. Une file de micro-opération est bien plus simple à implémenter qu'un ''scheduler''. ==Le ''Partial Ordering'' : la ''Load/Store Queue''== Avec la technique précédente, les lectures s'exécutent dans l'ordre, à savoir que l'on ne peut pas déplacer une lecture avant ou après une autre. Et cette limitation a des conséquences sur la performance de l'exécution dans le désordre. Des lectures sont mises en attente, parce qu'une lecture précédente l'est, alors qu'elles auraient pu s’exécuter avant. Et ce retard sur les lectures se répercute sur les instructions lecture-dépendantes, donc sur le reste du pipeline. Pour éviter cela, la technique du ''Partial Ordering'' permet aux lectures de s'exécuter dans le désordre tant que les conditions d'aliasing sont respectées. ===La ''Load/Store Queue''=== La technique s'implémente en remplaçant les files de µops mémoire par un ''scheduler'' spécialisée dans les µops mémoire. Elle est souvent appelée la '''''Load/Store Queue''''', qui est concrètement une station de réservation spécialisée dans les micro-opérations mémoire. En tout cas, nous utiliserons beaucoup l'abréviation LSQ pour parler de la ''Load/Store Queue''. [[File:Processeur avec émission dans le désordre des accès mémoire.png|centre|vignette|upright=2|Processeur avec émission dans le désordre des accès mémoire]] Une entrée de la ''Load/Store Queue'' contient plusieurs champs : un qui précise si l'opération est une lecture ou une écriture, un pour l'adresse mémoire à lire/écrire, un autre pour la donnée à écrire (qui est vide pour une lecture), un autre pour le registre de destination des lectures (inutile pour les écritures). Les deux derniers champs sont souvent fusionnés en un seul, qui est interprété différemment selon que l'instruction est une lecture ou une écriture. [[File:Load Store Queue unifiée.png|centre|vignette|upright=2.5|''Load/Store Queue''.]] Lorsqu'une micro-opération mémoire est émise, après renommage de registres, elle est insérée dans la ''Load/Store Queue''. Si l'adresse à lire/écrire est disponible, elle est immédiatement lue depuis les registres, idem pour une éventuelle donnée à écrire. Sinon, la micro-opération attend dans la LSQ que son adresse soit calculée par l'ALU entière. Pour gérer ce cas, elle contient des bits de validité pour chaque champ qui indiquent si l'adresse d'accès est connue, et si la donnée à écrire est disponible pour une écriture. Il faut noter que tout ce qui a été dit plus haut à propos du contournement des adresses vaut aussi avec une ''Load/Store Queue'', à un détail près. Pour détecter les dépendances, la LSQ doit comparer les adresses à lire/écrire, ce qui fait qu'elles doivent avoir été calculées avant d'entrer dans la LSQ. En clair, il n'est pas possible de faire les calculs d'adresse dans l'unité mémoire, juste avant d’accéder au cache. Les unités de calcul d'adresse sont réalisés dans une ALU entière ou une AGU spécialisée. Lorsqu'une instruction mémoire est émise, elle est décodée en deux micro-opérations : une pour le calcul d'adresse, une autre pour l'accès mémoire proprement dit. Le calcul d'adresse est réalisé soit dans une ALU entière, soit dans une AGU spécialisée. L'accès mémoire attend dans la ''Load/Store Queue'' que l'adresse soit calculée. Une fois l'adresse calculée, elle est envoyée à la ''Load/Store Queue'' et est enregistrée dans l'entrée adéquate. Reste qu'il faut envoyer l'adresse des ALU à la LSQ. Pour cela, on réutilise le réseau de contournement du processeur. L'implémentation la plus simple effectue les calculs d'adresse dans les ALU entières. La sortie de toutes les ALU entière est reliée à la LSQ. [[File:Load-Store Queue.png|centre|vignette|upright=2|Load-Store Queue]] Les processeurs modernes préfèrent utiliser des unités de calcul d'adresse dédiées, afin de simplifier le réseau de contournement. [[File:ALU et LSQ.png|centre|vignette|upright=1.5|ALU et LSQ]] En pratique, les LSQ proprement dites sont peu efficaces, pour un budget en transistor donné. La raison est qu'une entrée de la LSQ doit mémoriser indifféremment lectures et écritures. Et elle contient pour cela plusieurs champs : l'adresse à lire/écrire, le registre pour la donnée à lire/écrire, et un champ pour la donnée à écrire. Or, pour une lecture, le dernier champ, pour la donnée à écrire, est inutile. Sachant que les lectures sont beaucoup plus nombreuses que les écritures, ce champ sera gaché pour la majorité des instructiosn, et les transistors associés le seront aussi. Une solution pour cela est d'utiliser une file séparée pour les lectures et écritures. ===La détection des dépendances mémoire=== La ''Load/Store Queue'' est couplée à un système de détection des dépendances mémoire, qui détermine quelles instructions peuvent s'exécuter sans problème. Et ce système de détection des dépendances est bien différent de celui d'une station de réservation normale. Les ''Load/Store Queue'' comparent non pas des noms de registres, mais des adresses/opérandes. Chaque micro-opération en attente compare son adresse avec celle de toutes les micro-opérations précédentes. Ou presque, la comparaison ne doit tenir compte que des écritures, et de celles situées avant dans l'ordre du programme. La ''Load/Store Queue'' doit donc mémoriser les instructions dans l'ordre du programme, tout en faisant des comparaisons d'adresse. Ça en fait une sorte hybride entre mémoire associative et mémoire FIFO. Nous avions vu dans le chapitre "L'exécution dans le désordre" qu'il y a plusieurs manières pour implémenter une station de réservation : avec une mémoire associative, avec préplanification, avec des matrices de dépendances. Le problème est qu'on ne peut pas utiliser une mémoire associative pour la LSQ, qui utilise des comparateurs pour comparer les noms de registres/adresses. En effet, la détection des dépendances mémoire demande de faire beaucoup de comparaisons : chaque adresse est comparé à toutes les autres. Et les adresses faisant facilement 32 à 64 bits, les comparateurs sont bien plus imposants que ceux qui comparent des noms de registres de 5-10 bits. Le cout en matériel serait trop élevé, de même que le temps de calcul des dépendances. À la place, on utilise des matrices de dépendances. La détection des dépendances mémoire utilise précisément deux matrices de ce type : une matrice de disponibilité, et une matrice de dépendance. Ces matrices forment une espèce de tableau carré, organisé en lignes et en colonnes. L'instruction dans la énième entrée se voit attribuer la énième ligne et la énième colonne. À l'intersection d'une ligne et d'une colonne, on trouve un bit qui indique si l'instruction de la ligne et celle de la colonne ont une dépendance. La '''matrice de disponibilité''' permet de bloquer l'exécution des lectures/écritures tant qu'une instruction précédente n'a pas calculé son adresse, tant qu'on ne peut pas vérifier les dépendances. Lorsqu'une instruction est ajoutée dans le LSB, elle met tous les bits de la colonne attribuée à 1 si l'adresse à lire/écrire est inconnue, puis les met à 0 une fois l'adresse calculée. Une instruction ne peut pas démarrer si, sur la ligne qui lui est attribuée, se trouve un 1. Plus précisément, si on trouve un 1 pour les instructions plus anciennes, ce qui fait qu'une partie de la matrice est ignorée. Les bits notés X dans le tableau suivant sont ignorés, car ils précisent la disponibilité des opérandes d'un opérande ultérieure, ce qui est inutile. En clair, les calculs d'adresse modifient les colonnes, et on vérifie les lignes pour autoriser l'exécution. {|class="wikitable" |- ! Instructions mémoire dans la LSB, triées de la plus ancienne à la plus jeune ! 0 !! 1 !! 2 !! 3 !! 4 !! 5 !! 6 |- ! 0 | 1 || X || X || X || X || X || X |- ! 1 | 0 || 0 || X || X || X || X || X |- ! 2 | 0 || 1 || 0 || X || X || X || X |- ! 3 | 0 || 1 || 1 || 1 || X || X || X |- ! 4 | 0 || 0 || 0 || 0 || 1 || X || X |- ! 5 | 0 || 0 || 1 || 0 || 0 || 1 || X |- ! 6 | 1 || 1 || 1 || 1 || 1 || 1 || 0 |} Les '''matrices de dépendances''' fonctionnent sur le même principe, mais déterminent les dépendances mémoire. Lorsque le processeur a calculé une adresse, il la compare avec les adresses à lire/écrire déjà dans la LSB. Il met alors à jour les bits de la colonne de la matrice de dépendance : le bit à l'intersection d'une ligne et d'une colonne est mis à 0 si les deux instructions n'ont pas de dépendances, à 1 si elles en ont une. Une instruction mémoire est exécutée si tous les bits de sa ligne sont à 0. Là encore, on ne tient compte que des bits pour les instructions plus anciennes, la matrice a encore une fois une forme triangulaire, comme pour la matrice de disponibilité. Une optimisation scinde la ''Load/Store Queue'' en deux structures, aux rôles légèrement différents. La première gère la disponibilité des opérandes, la seconde gère seulement les dépendances mémoire. La première est une station de réservation où les instructions sont mises en attente tant que leurs opérandes ne sont pas prêts. La seconde met en attente des micro-opérations dont les opérandes sont prêts, mais qui doivent attendre pour une autre raison : dépendance mémoire, cache occupé, etc. L'avantage est qu'on remplace une grosse station de réservation par deux plus petites, mais l'intérêt est surtout relié au système de détection des dépendances. Sans cette optimisation, on a deux matrices énormes reliées à une ''Load/Store Queue'' unique. Avec la séparation, la matrice de disponibilité est reliée uniquement à la première station de réservation, alors que la matrice de dépendance est reliée uniquement à l'autre. Les deux matrices sont donc plus petites, car reliées à deux stations de réservation mémoire plus petites. ==L'exécution spéculative des accès mémoires== Pour rappel, le but de la désambiguïsation mémoire est d'exécuter les lectures le plus tôt possible. Les données lues sont en effet, le départ d'une série d'instructions dépendantes, généralement des instructions arithmétiques, mais parfois d'autres lectures. Quand on manipule des structures de données, il n'est pas rare qu'une lecture lise un pointeur-adresse utilisé par une autre lecture. Les techniques de désambiguïsation mémoire que nous avons vu précédemment sont dites conservatrices, à savoir qu'elles ne changent pas l'ordre de deux instructions mémoire si elles ont une dépendance d'adresse. Elles exécutent une lecture le plus tôt possible, mais seulement si on sait que celle-ci n'aliase pas d'écritures précédentes. Et cela demande de connaitre les adresses des écritures précédentes dans l'ordre du programme. Si une lecture est précédée par une ou plusieurs écritures, les adresses à écrire doivent être connues. Il se peut en effet qu’une écriture dont on ne connait pas l'adresse aliase la lecture. La garantie est liée à la présence de la file de µops mémoire ou la file de µops STORE. Si une seule écriture a une adresse inconnue, elle reste dans la file de µops mémoire et bloque l'émission de toutes les autres micro-opérations mémoire, lecture comme écriture. Mais il existe des techniques dites spéculatives, qui modifient l'ordre des accès mémoire sans se soucier de leurs dépendances. Elles émettent les lectures dès que leurs opérandes sont prêts, sans se préoccuper de l'aliasing avec une écriture précédente. Pour éviter tout problème, le processeur vérifie si aucune dépendance mémoire n'est violée et corrige le tir dès qu'une violation est détectée. Le processeur vérifie s'il a fait une erreur de prédiction, en vérifiant les adresses à écrire ou lire. En cas d'erreur, le processeur fait comme lors d'une prédiction de branchement ratée : il remet le pipeline en ordre et ré-exécute les accès mémoire dans le bon ordre. Il s'agit d'un cas particulier d’'''exécution spéculative''', au même titre que la prédiction de branchement. Toutes les techniques de ce genre exécutent des lectures dans le désordre. L'avantage est que cela permet d'exécuter les lectures en avance. Vu que la donnée lue est l'opérande d'autres instructions, les exécuter en avance fait prendre de l'avance à un paquet d'instructions. Mais il faut comparer cet avantage au risque de mauvaise prédiction. Et aussi bizarre que cela puisse paraître, cela donne de bons résultats. Il faut dire que les situations où une lecture relit une donnée tout juste écrite sont rares : même pas 2 à 3 % des lectures. Les dépendances mémoire sont donc très rares, les cas d'aliasing sont vraiment limités. En termes de cout en transistors, le hardware qui vérifie les dépendances mémoire reste globalement le même à peu de choses près, il est juste déplacé dans le pipeline et adapté à sa nouvelle fonction. ===La file de lectures=== La première technique que nous allons voir reprend la technique du ''Load Ordering, Store Ordering'', avec ses deux files de µops de lecture et d'écriture. Elle exécute les lectures sans se préoccuper des dépendances avec les écritures. Mais le processeur vérifie qu'aucune violation de dépendance n'a eu lieu après un certain temps. Une violation de dépendance peut avoir lieu pour n'importe quelle instruction précédant la lecture dans l'ordre du programme. En clair, le processeur doit conserver les lectures spéculatives tant que les instructions précédentes ne sont pas terminées. Pour cela, il faut ajouter une nouvelle file d'attente, qui mémorise les lectures terminées. Nous l’appellerons la file de vérification des lectures, ou encore la '''file de lectures'''. Elle fonctionne sur le même principe que la file d'écriture et les deux font partie de l'unité mémoire. Les deux visent à remettre les lectures/écritures dans l'ordre du programme, afin que les instructions suivant une lecture/écriture fautive soient annulées. Les lectures sont insérées dans la file de lecture à l'émission, quand elles quittent la file de µops mémoire/LSQ, ce qui est la même chose avec les écritures pour la file d'écriture. Une différence très importante est que les écritures sont retardées alors que les lectures s'exécutent immédiatement. D'ailleurs, la file de lecture ne sert pas pour le contournement : les données lues sont immédiatement envoyées au chemin de données, pas besoin de les contourner ultérieurement. Alors que la file d'écriture est utilisée pour le contournement en cas de dépendances RAW. Les lectures sortent de la file µops LOAD dès que leurs adresses sont calculées, sans tenir compte des dépendances mémoires. Elles sont alors ajoutées à la file de lectures et s'exécutent immédiatement, de manière spéculative. Pour vérifier qu'il n'y a pas d'erreur de spéculation, le processeur conserve l'adresse de la lecture effectuée dans la file de lectures. Les lectures quittent la file de lecture quand toutes les instructions précédentes dans l'ordre du programme sont terminées, à savoir tant quand elles ont quitté le tampon de réordonnancement/ROB. Notons que la file de vérification des lectures contient les lectures dans l'ordre du programme. En effet, les lectures sont accumulées en sortant de la file de µops LOAD, où elles sont triées dans l'ordre du programme. Et cela permet de gérer les erreurs de prédiction parfaitement, en annulant les instructions suivant une erreur de prédiction. [[File:Spéculation avec une file de lecture.jpg|centre|vignette|upright=2.5|Spéculation avec une file de lecture.]] Reste à détecter les erreurs de prédiction, ce qui peut être fait avec deux méthodes. Avec la première, les violations de dépendances mémoire sont faites à chaque écriture. Précisément, la détection a lieu quand une écriture est sur le point de quitter la file d'écriture. L'unité mémoire récupère alors l'adresse d'écriture et la compare avec toutes les lectures dans la file de vérification des lectures. Si aucune correspondance n'est trouvé, c'est que les lectures spéculatives n'ont accédé à l'adresse d'écriture. Mais s’il y a correspondance, c'est qu'une lecture a lu l'adresse avant qu'elle soit écrite. Pour cela, la file de vérification des lectures est un mélange entre FIFO et cache/mémoire associative. La vérification fait cependant gaffe à ne prendre en compte que les lectures situées après l'écriture dans l'ordre du programme (seulement ces instructions sont capables de générer une dépendance RAW). Avec la seconde méthode, les violations de dépendance mémoire sont détectées au moment où la lecture quitte à la file de lectures et le ROB. Mais cela demande que la donnée lue soit recopiée dans la file de lecture. Quand la lecture quitte la file de lecture et le ROB, la lecture est ré-exécutée et la donnée relue. Le processeur compare alors la donnée lue à ce moment avec la donnée mémorisée dans la file de lecture. Si la donnée est différente, alors il y a eu erreur de violation de dépendance mémoire. Évidemment, relire une donnée n'est pas gratuit. Il est possible de limiter son impact en performance en dédiant un port de lecture sur le cache rien que pour ça. Mais le cout en circuit est comparable à l'usage d'une FIFO associative de la technique précédente. Mais quoi qu'il en soit, le cache doit permettre des lectures en un seul cycle, sans quoi la méthode ne marche pas vraiment. ===La prédiction de dépendances mémoires=== Certains processeurs essayent de prédire si deux accès mémoires sont dépendants : ils incorporent une unité qui va fonctionner comme une unité de prédiction de branchement, à la différence qu'elle prédit les dépendances mémoires. Si cette unité prédit que deux accès mémoires sont indépendants, le processeur les exécute dans le désordre, et les exécute dans l'ordre du programme dans le cas contraire. Il faut prendre en compte les erreurs de prédiction, ce qui est fait comme pour les mauvaises prédictions de branchement : on vide le pipeline. Beaucoup de techniques de prédiction des dépendances mémoire ont été inventées et en faire une revue exhaustive serait long et fastidieux. On pourrait citer les ensembles colorés (''color sets''), et bien d'autres techniques. Mais nous n'allons parler que des techniques les plus élémentaires. Quoi qu’il en soit, la recherche sur le sujet est assez riche, comme toujours quand il s'agit d'architecture des ordinateurs. On peut améliorer cette technique en mémorisant les instructions qui ont causé une mauvaise prédiction de dépendance mémoire. La prochaine fois qu'on exécute ces instructions, on sait qu'il y a de grandes chances qu'il se produise une erreur de prédiction, ce qui pousse à ne pas les exécuter de manière spéculative. On peut pour cela réutiliser les techniques de prédiction de branchement, tels des compteurs à saturations, mis à jour en cas d'erreurs de prédiction de dépendances mémoire. Dans tous les cas, on trouve un cache, équivalent au ''branch target buffer'', qui mémorise les instructions fautives (leur ''Program Counter''), avec d'autres informations comme les adresses des instructions dépendantes. La première classe de techniques du genre consiste à mémoriser les lectures qui ont causé une violation de dépendance, tandis que l'autre ne mémorise que les écritures. Cette dernière est l'approche utilisée par le '''cache de barrières d’écriture''' (store barrier cache). Enfin, nous allons conclure avec une dernière technique : celle des '''ensembles d’écritures''' (store sets). Cette technique est capable de gérer le cas où une lecture dépend de plusieurs écritures : le processeur mémorise l'ensemble des écritures avec lesquelles la lecture a déjà eu une dépendance. Cet ensemble d'écritures associées à une lecture est appelé tout simplement un ensemble d’écritures, et reçoit un identifiant (un nombre) par le processeur. Cette technique demande d'utiliser deux tables : * une qui assigne un identifiant d’ensemble d’écritures à l'instruction en cours ; * une autre qui mémorise les ensembles d’écritures sous la forme d'une liste chainée : le début de la liste correspond à l'écriture la plus ancienne de l’ensemble. Cela permet d'obtenir l'écriture la plus ancienne dans cet ensemble d’écritures directement. Quand le processeur détecte une violation de dépendance entre une lecture et une écriture, elle ajoute l'écriture dans l’ensemble d’écritures adéquat. Le déroulement d'une lecture demande d'accéder à la première table pour récupérer l'identifiant de l’ensemble d’écritures, et l'utiliser pour adresser la seconde table. S'il y a dépendance, cet accès renvoie l'écriture fautive en cas de dépendance. Quand une écriture est envoyée à l'unité mémoire, celle-ci va accéder à la table de correspondances de la même manière qu'une lecture, et va récupérer l'identifiant de l’ensemble d’écritures auquel elle appartient, identifiant qui est utilisé pour vérifier s'il y a une écriture en cours d’exécution. Si c'est le cas, cela signifie que l'écriture en cours d’exécution doit s’exécuter avant l'écriture qui a consulté la table : cette dernière est mise en attente. ==La prédiction d'adresse et de valeur== D'autres techniques de prédiction mémoire plus élaborées que les précédentes existent. Il s'agit de la prédiction d'adresse et de la prédiction de valeur. Leur nom trahit ce qu'elles font. La première technique tente de prédire l'adresse d'une lecture/écriture, alors que la seconde tente carrément de prédire quelle sera la donnée lue. Il y a bien de la recherche académique sur le sujet, mais il s'agit de techniques assez osées, dont on voit mal comment elles pourraient fonctionner. L'efficacité de cette technique a été étudiée grâce à des simulateurs. Suivant les études ou les programmes, on trouve des résultats qui varient pas mal. Dans certains cas, la performance baisse un peu, et dans d'autres, on peut avoir des gains de plus de 10% ! Mais dans des cas normaux, on trouve des gains de 4-5% environ. Ce qui est tout de même pas mal à l'heure actuelle. Cependant, en Janvier 2025, à l'heure où j'écris ces lignes, il a été découvert la première utilisation de ces deux techniques dans un processeur commercial. La découverte fait suite à la publication de deux vulnérabilités matérielles sur les CPU Apple M2 et M4 et quelques CPU ARM, qui font justement usage de ces deux techniques. Les deux vulnérabilités, appelées SLAP et FLOP, sont assez similaires aux attaques Spectre et Meltdown, sauf qu'elles attaquent non pas la prédiction de branchement, mais la prédiction d'adresse et de valeur du CPU. ===La prédiction d'adresse=== La prédiction d'adresse tente de prédire l'adresse d'une lecture à l'avance, ce qui permet de lancer les lectures en avance. Si la prédiction est correcte, on gagne quelques cycles qui permet aux unités de calcul de faire leurs calculs plus en avance, sans compter que les mécanismes de désambiguïsation mémoire fonctionnent plus efficacement. Si jamais cette adresse est connue plus tôt, on détecte les dépendances plus rapidement et on peut agir en conséquence. Des variantes de ces unités de prédiction d'adresse sont utilisées pour précharger des données depuis le cache de donnée. Et leur efficacité est assez bonne, voire excellente dans certains cas. La différence est que la prédiction d'adresse est utilisée pour prédire les adresses à lire depuis le cache vers les registres, ce qui est le sujet de cette sous-partie. La prédiction d'adresse est réalisée par une sorte de cache, qui associe à chaque instruction la prochaine adresse à lire. Nous appellerons ce cache la '''table de prédiction d'adresse'''. Pour faire l'association instruction <-> adresse lue/écrite, le tag du cache utilise l'adresse de l'instruction (le ''program Counter''), alors que la ligne de cache associée contient l'adresse prédite. Son contenu est utilisé pour faire une prédiction. Lorsqu'une lecture est émise, la table est consultée pour récupérer en avance l'adresse à lire, avant que celle-ci soit calculée par l'ALU. La lecture est alors exécutée en avance, avant que la vraie adresse soit connue, en utilisant l'adresse prédite. Reste qu'il faut des circuits autour de cette table de prédiction d'adresse, pour déterminer si la prédiction est correcte, ainsi que pour remplir cette table avec une adresse prédite. Pour cela, il y a un circuit de prédiction d'adresse dédié. Il récupère les instructions qui quittent le ROB ou la file des lectures mémoire, afin de vérifier les lectures qui viennent de se terminer/''commit'' et qui quittent le pipeline. Il peut contenir une '''table d'apprentissage''', qui mémorise des informations nécessaires pour faire des prédictions d'adresse. Par exemple, un historique des dernières adresses lues pour les lectures les plus récentes, ou un historique des adresses des lectures. La table est aussi utilisée pour déterminer si les prédictions effectuées étaient correctes ou non. Pour cela, il est possible de réutiliser les techniques vues dans le chapitre sur la prédiction de branchement, notamment des compteurs à saturation. Pour la prédiction de branchement et les autres formes de prédiction mémoire, les table d'apprentissage et pour les instructions/adresses sont fusionnées en une seule. Mais ici, il est nécessaire de les séparer pour une raison assez particulière : éliminer la pollution du cache dans la table de prédiction d'adresse. On ne peut pas allouer une ligne de cache pour chaque nouvelle instruction de lecture exécutée. Seule une minorité des lectures profitent de la prédiction d'adresse. Il est nécessaire de filtrer les lectures pour ne conserver que celles qui profitent de la prédiction d'adresse, ce qui est possible plus facilement en séparant la table d'apprentissage et les compteurs à saturation de la table de prédiction d'adresse. Une première méthode consiste à prédire que la lecture lit toujours la même adresse, ce qui lui vaut le nom de '''prédiction d'adresse constante'''. On pourrait se demander pourquoi une telle situation surviendrait. La raison est qu'il arrive que les compilateurs n'arrivent pas à gérer les accès mémoires efficacement. Dans certaines situations un peu compliquées impliquant des pointeurs ou des références, divers phénomènes complexes d'''aliasing'' des pointeurs peuvent générer des relectures intempestives de données en mémoire. Cela peut aussi arriver lorsqu'on compile du code qui provient de plusieurs librairies, ou quand du code lit régulièrement des constantes en mémoire ROM. La prédiction d'adresse constante ajoute un circuit qui analyse les dernières lectures, une fois qu'elles quittent le ROB, qu'elles ''commit''. Si, pour une instruction de lecture, l'adresse lue est toujours la même, alors l'instruction est ajoutée dans la table de prédiction d'adresse. Vu que les instructions qui accèdent toujours à la même adresse sont rares, il est préférable d'initialiser les compteurs à saturation de façon à ce qu'ils disent que toute nouvelle instruction change d'adresse. Il s'agit d'une méthode simple mais peu efficace, car cette situation est rare. Une autre méthode détecte les accès en enjambées, là encore quand les lectures quittent le ROB. Nous l’appellerons la '''prédiction d'adresse en enjambées'''. De tels accès surviennent régulièrement quand on accède des tableaux ou d'autres structures de données semblables, ce qui rend la technique très intéressante. Implémenter cette technique est facile : il suffit d'ajouter un circuit qui détecte les accès en enjambées, au lieu de celui qui détecte les accès constants. À chaque fois qu'une lecture entraine un succès de cache dans la table de prédiction d'adresse, l'enjambée est ajoutée à l'adresse contenue dans la table de prédiction d'adresse, l'ancienne adresse prédite est remplacée par celle avec l'enjambée d'ajoutée. Sur les Apple M2-M4, la prédiction d'adresse gére aussi bien les adresses constantes que les accès en enjambée. Le brevet qui décrit l'implémentation de l'unité de prédiction d'adresse et de valeur est potentiellement le suivant : [https://patents.google.com/patent/US11829763B2/en Early load execution via constant address and stride prediction]. En théorie, il est possible de faire mieux en repérant des accès mémoires qui se répètent de façon régulière et cyclique, même s'ils n'ont aucune enjambée. Ce genre d'accès se trouve assez souvent lorsque l'on manipule des listes chainées ou des structures de données assez irrégulières comme des arbres, des graphes, etc. Mais il n'y a pas encore de CPU qui implémente de telle optimisation. ===La prédiction de valeur : prédire la donnée lue=== Les techniques de '''prédiction de valeur''' (''Value Prediction'') consistent à prédire quelle est la donnée qui sera lue par une instruction de lecture. Oui, vous avez bien lu : le processeur est capable de parier sur la valeur qui sera chargée depuis la mémoire, de prédire si cette valeur vaut 0, 1, 1024, etc. Une fois son pari fait, il exécute les instructions du programme avec la valeur qu'il a pariée de façon spéculative. Si le pari est correct, le CPU continue l’exécution. Sinon, il est obligé de vider le pipeline et de recommencer avec la bonne valeur. Au premier abord, cette technique semble franchement mal partie tellement les chances de se tromper sont tellement énormes ! Mais le fait est que, dans certains cas, il est possible de spéculer correctement. Là encore, les techniques les plus simples fonctionnent dans deux cas. Le premier est celui où une donnée est relue à l'identique à chaque fois que la lecture est exécutée. Le second est celui où la donnée est incrémentée/décrémentée d'une constante qui est toujours la même d'une exécution de la lecture à l'autre. Une sorte d'enjambée constante, mais pour les données. Nous allons nous concentrer sur le premier cas, celui où une donnée est relue plusieurs fois sans être modifiée entre temps. L'idée de base est qu'une instruction de lecture qui s'exécute plusieurs fois de suite à la même adresse renvoie la même valeur à chaque fois. C'est parfaitement possible s’il n'y a eu aucune écriture à cette adresse entre-temps, d'où le fait qu'il faille surveiller si les prédictions constantes sont correctes. On peut se demander quelles sont les raisons qui font qu'une instruction de lecture renvoie la même valeur à chaque fois. Après tout, autant lire une seule fois la donnée et la garder dans un registre une bonne fois pour toutes ! Mais dans la réalité, on fait face à quelques limites, qui seront détaillées dans la liste suivante. La première est que le manque de registre fait que certaines données sont conservées en RAM et sont relues fréquemment. Cela arrive quand on stocke des constantes en mémoire. Par exemple, sur les processeurs x86, les constantes flottantes ne peuvent pas être intégrées dans nos instructions via le mode d'adressage immédiat. À la place, on les stocke en mémoire et on les charge dans les registres à chaque fois qu'on en a besoin. L'implémentation est similaire à la prédiction d'adresse, si ce n'est que c'est la donnée lue qui est prédite. Là encore, on a une '''table de prédiction de donnée lue''', consultée lorsqu'une lecture est émise. La table de prédiction de la donnée lue est une mémoire cache qui associe le ''Program Counter'' de la lecture à la donnée prédite, éventuellement couplé à des compteurs à saturation. Elle est consultée à chaque fois qu'une lecture est émise, la donnée adéquate est récupérée lors d'un succès de cache. On trouve aussi un circuit qui insère ou retire des instructions de la table de prédiction de donnée lue. Elle détecte les lectures prédictibles, couplé à une table d’apprentissage, et quelques circuits annexes liés au ROB ou aux files de lectures. Elle contient au minimum des compteurs à saturations, associés chacun à une instruction (son ''program counter'' pour être précis). ==La désambiguïsation mémoire a des effets de bord== La désambiguïsation mémoire a une caractéristique que l'exécution dans le désordre simple n'a pas : elle a des effets qui débordent sur la mémoire. Il est possible de savoir si un processeur fait de la désambiguïsation mémoire en regardant le bus mémoire. On s’aperçoit alors que les lectures se font dans un ordre différent de celui du programme. À l'opposé, l'exécution dans le désordre n'a pas d'effets observables de ce genre. Elle améliore la performance, elle modifie les durées observables des instructions, mais cela se limite à des questions de ''timings''. Le seul moyen de savoir si un processeur fait de l'exécution dans le désordre est de mesurer les latences/durées de chaque instruction. Mais aucun état observable au-delà des ''timings'' n'est modifié. Pas avec la désambiguïsation mémoire. ===La consistance mémoire=== Le fait que la désambiguïsation mémoire ait des effets observables ne pose aucun problème avec un seul processeur, ca elle est conçue pour. Par contre, les techniques de désambiguïsation mémoire peuvent poser des problèmes avec plusieurs processeurs. Il arrive que des programmes partagent une même portion de mémoire, et lisent/écrivent dedans. Avec plusieurs processeurs, chaque processeur effectue la désambiguïsation mémoire dans son coin sans se préoccuper des autres. Les opérations d'écriture peuvent être mises dans le désordre du point de vue des autres processeurs, et les lectures effectuées par les autres processeurs peuvent alors renvoyer de vielles données. Un exemple classique est celui de deux cœurs qui partagent le même cache ou la même mémoire, mais qui utilisent chacun une file d'écriture (''store buffer''). Imaginons que le premier cœur effectue une écriture, puis une lecture, à des adresses différentes. L'écriture est retardée grâce au tampon d'écriture, alors que la lecture lit directement le cache. Pour le premier processeur, l'écriture s'est réalisée avant la lecture, car pour lui, la fin de l'écriture signifie écrire dans le tampon d'écriture. Mais pour le second cœur, l'ordre s'est inversé : il voit la lecture dans le cache, puis l'écriture dans le cache. La raison est qu'il n'a pas connaissance du contenu du tampon d'écriture de l'autre cœur. Un autre exemple : les techniques de prédiction d'adresse et de valeur posent des problèmes avec les dépendances RAW. Elles permettent à une instruction mémoire de s'exécuter avant une autre, malgré la présence d'une dépendance RAW entre les deux. L'ordre entre les deux instructions change, alors que les autres processeurs ne devraient pas le voir. Et dans les faits, les processeurs qui incorporent ces techniques ont des modèles de consistance mémoire qui ne permettent pas ces optimisations en cas de dépendances RAW. Les deux techniques doivent idéalement être désactivées pour les instructions mémoire qui ont des dépendances RAW. Les programmeurs doivent tenir compte de ce genre de situations, dans des cas assez rares et liés à la programmation bas niveau. Pour cela, ils doivent savoir comment le processeur réorganise les accès mémoire. Concrètement, chaque processeur définit un '''modèle de consistance mémoire''' qui indique quelles optimisations sont activées et non. Il s'agit d'une sorte de contrat entre le logiciel et le matériel : les programmeurs savent comment le processeur va réorganiser les lectures et écritures et peuvent coder leurs programmes en fonction. L'implémentation du système de consistance mémoire dépend grandement de l'architecture, mais des modèles ont été standardisés afin de permettre aux programmeurs de savoir où placer les barrières mémoires. Il s'agit de vrais standards, formalisés, parfois mathématiquement, que des chercheurs étudient sur un plan mathématique et algorithmique. Le modèle préféré des programmeurs est la '''consistance séquentielle''', où les différents processeurs effectuent des accès mémoire dans l'ordre du programme et les accès mémoire simultanés sont interdits. La première contrainte interdit l'usage de mécanismes de désambiguïsation mémoire, la seconde interdit l'usage de caches non-bloquants. La consistance séquentielle a donc un cout en performance assez important, ce qui fait que les processeurs modernes n'utilisent pas la consistance séquentielle. Un modèle plus flexible est le '''''total store ordering''''', qui autorise la présence d'une file d'écriture et l'usage de caches non-bloquants pour les lectures (interdit d'avoir plusieurs écritures simultanées). C'est plus ou moins celui utilisé par les processeurs x86, comme on le verra plus bas. Il existe des modèles de consistance mémoire plus relâchés, appelés des '''modèles de consistance faible''', qui autorisent diverses optimisations de spéculation mémoire, la combinaison d'écriture (fusionner deux écritures à la même adresse en une seule), etc. Ils sont supportés sur les architectures ARM et POWER. ===Les barrières mémoire=== Le changement d'ordre des lectures et écritures peut poser occasionnellement des problèmes avec la programmation pour les architectures multi-processeur ou multicœurs. Il existe des morceaux de code qui ne marchent que si la consistance séquentielle est respectée et il faut faire en sorte qu'ils marchent sur des processeurs avec un modèle de consistance mémoire différent. Pour cela, les processeurs incorporent des instructions appelées '''barrières mémoires''' ou '''''Fences'''''. Elles forcent le processeur à terminer tous les accès mémoire qui précédent dans l'ordre du programme. Certains processeurs possèdent une barrière mémoire pour les lectures et une autre pour les écritures. D'autres processeurs ajoutent des barrières mémoires dédiées à des cas particuliers. Elles permettent de forcer les accès à des données partagées à dérouler correctement. [[File:Fences.png|centre|vignette|upright=2|Fences.]] Leur implémentation est assez simple : elles empêchent l'émission de toute nouvelle instruction mémoire, tant qu'une condition précise n'est pas réunie. Par exemple, la barrière mémoire pour les écritures attend que la file d'écriture soit vidée avant de démarrer le moindre accès mémoire. Un compilateur peut placer les barrières mémoires au bon endroit, avec un peu d'aide du programmeur. Certains langages de programmation permettent d'indiquer au compilateur qu'une donnée doit toujours être lue depuis la mémoire RAM, via le mot-clé volatile. C'est très utile pour préciser que cette donnée est potentiellement partagée par plusieurs processeurs ou manipulable par des périphériques. Les compilateurs peuvent placer des barrières mémoires lors des lectures ou écritures sur ces variables, mais ce n'est pas une obligation. Il arrive aussi que le programmeur doive manipuler explicitement des barrières mémoires. Utiliser l'assembleur est alors une possibilité, mais qui est rarement exploitée, pour des raisons de portabilité. Pour limiter la casse, certains systèmes d'exploitations ou compilateurs peuvent aussi fournir des barrières mémoires explicites, encapsulées dans des bibliothèques ou cachées dans certaines fonctions. ===La modèle de consistance des processeurs x86=== Après avoir vu la théorie, passons maintenant à la pratique. Dans cette partie, on va voir les modèles de consistances utilisés sur les processeurs x86, ceux qu'on retrouve dans les PC actuels. Le modèle de consistance des processeurs x86 a varié au cours de l'existence de l'architecture : un vulgaire 486DX n'a pas le même modèle de consistance qu'un Core 2 duo, par exemple. Ils ont évolués au cours du temps, avec l'arrivée de nouvelles optimisations. De plus, leur formalisation a été progressive, et s'est faite au fur et à mesure. En général, les modèles de consistance des processeurs x86 ont toujours étés assez restrictifs, si on les compare aux autres processeurs. Il s'agit de modèles de type ''total store ordering'' (TSO), au moins dans les grandes lignes. Ils permettent donc d'effectuer certaines lectures en avance, soit parce que les lectures se font à des adresses différentes, soit par utilisation de réacheminement écriture vers lecture. Les possibilités d'exécution en avance des lectures varient suivant le processeur, elles deviennent de plus en plus performantes avec le temps. Le premier modèle de consistance est apparu sur les premiers processeurs x86 et est resté en place sur tous les processeurs de marque Pentium. Les processeurs de l'époque n'incorporaient pas beaucoup d'optimisations, le budget en transistor n'était pas assez conséquent pour ça, la mémoire n'était pas assez lente. Le modèle TSO de l'époque n'autorisaient que peu de lectures anticipées. Une lecture ne peut être exécutée en avance que sous les conditions suivantes : * les écritures contournées se font dans la mémoire cache ; * la lecture doit se faire dans la mémoire RAM ; * les écritures se font à une adresse différente de la lecture ; * aucune transaction avec un périphérique ne doit être en cours. A partir du Pentium 4, les choses changent. Le Pentium 4 est en effet le premier processeur à implémenter des techniques permettant d’exécuter plusieurs processus en parallèle, dont l'Hyperthreading. En conséquence, le modèle de consistance a dû être assoupli pour éviter de perdre bêtement en performance. Il s'agit d'un vrai modèle de type TSO, la majeure partie des contraintes sur les lectures anticipées sont réduites au minimum. Il y a aussi des contraintes supplémentaires pour les instructions dites atomiques, ainsi que pour les instructions qui accèdent aux périphériques ou aux entrées-sorties. Une optimisation séparée du TSO est que les écritures en mémoire peuvent changer d'ordre dans un cas exceptionnel : les écritures effectuées par les instructions de copie mémoire comme REPMOVSD, REPSCACB, ainsi que les instructions SSE MOVNTI, MOVNTQ, MOVNTDQ, MOVNTPS, MOVNTPD. Les écritures effectuées dans ces instructions peuvent se faire dans un désordre complet (ou presque). Lors du passage au 64 bits, le modèle mémoire des processeurs x86 de l'époque a été formalisé dans un papier d'Intel appelé [https://www.cs.cmu.edu/~410-f10/doc/Intel_Reordering_318147.pdf Intel® 64 Architecture Memory Ordering White Paper], mis à jour en 2008 suite à quelques problèmes techniques. La formalisation du modèle a été d'une grande aide aux programmeurs, qui devaient se débrouiller avec des documentations qui ne formalisaient pas de modèle de consistance précis. Le document décrit un modèle de consistance mémoire portant le nom barbare de ''total lock order + causal consistency” (TLO+CC)'', qui admet plus d'optimisations que le modèle TSO. Mais la description était en réalité légèrement différente du modèle mémoire réellement implémenté sur les processeurs existants, qui utilisaient du TSO, sauf en de rares occasions. Les concepteurs de processeur font souvent cela, à savoir définir un modèle de consistance plus laxiste que réellement implémenté, pour des questions de comptabilité. Ainsi, si les futurs processeurs de la marque implémentent un modèle plus laxiste, les programmes déjà codés continuent de fonctionner. Le modèle décrit dans la documentation laisse de la marge pour le futur. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les implémentations modernes de l'OOO | prevText=Les implémentations modernes de l'OOO | next=Le parallélisme mémoire | nextText=Le parallélisme mémoire }} </noinclude> pnbmkn87xw2w5l9tl09um4d5n22adzl 773663 773633 2026-09-29T22:18:43Z Mewtow 31375 /* La modèle de consistance des processeurs x86 */ 773663 wikitext text/x-wiki Dans les chapitres précédents, nous avons vu la mal-nommée exécution dans le désordre dans les chapitres précédents, qui devrait plutôt s'appeler l'émission dans le désordre. Elle modifie l'ordre des instructions pour gagner en efficacité, mais cela n'est valable que pour les instructions travaillant sur des registres ! Nous n'avons pas parlé de l'exécution dans le désordre des accès mémoire, car ils sont un peu à part. Et pour comprendre pourquoi, nous allons dédier ce chapitre à la gestion des accès mémoire dans le pipeline. ==L’émission des accès mémoire== Avant de poursuivre, faisons un rappel rapide. Il faut distinguer deux types de dépendances de données : les dépendances de registres (deux instructions manipulent le même registre), alors que l'unité mémoire gère les dépendances d'adresse (deux instructions manipulent la même adresse). La différence registre-adresse fait que la gestion des dépendances est totalement différente. ===L'''aliasing'' mémoire et les dépendances mémoire=== Pour rappel, deux instructions ont une dépendance d'adresse si elles écrivent ou lisent la même adresse mémoire, ce qui interdit de changer leur ordre. Des instructions mémoires qui lisent/écrivent des adresses différentes sont indépendantes. Lorsque deux instructions mémoire lisent/écrivent à la même adresse, on parle d''''aliasing mémoire'''. Détecter les cas d'aliasing mémoire est primordial pour gérer la désambiguïsation mémoire, et cela demande de comparer des adresses. Formellement, l'aliasing mémoire n'est ni plus moins que l'application des dépendances de données aux instructions mémoire. Et comme les autres dépendances de données, il existe plusieurs types d'aliasing mémoire : RAR, RAW, WAR et WAW. Les dépendances RAR ne posent aucun problème, les lectures peuvent changer d'ordre sans aucun problème, tant qu'il n'y a pas d'écritures entre les deux. Par contre, les autres dépendances imposent trois contraintes. * Les dépendances RAW imposent que les lectures ne doivent pas s'exécuter avant une écriture à la même adresse. * Les dépendances WAR imposent que l'on ne peut pas déplacer une écriture avant une lecture à la même adresse. * Enfin, les dépendances WAW font que l'ordre des écritures doit être celui du programme : impossible de changer l'ordre de deux écritures. Les trois contraintes peuvent s'implémenter de plusieurs manières différentes. Comme pour les dépendances de données normales, seules les dépendances RAW sont de vraies dépendances de données. Les deux autres dépendances viennent du fait que l'on utilise la même adresse pour stocker des valeurs différentes. S'il existe des techniques similaires au renommage de registre permettent de les faire disparaitre, elles sont très limitées. ===La désambiguïsation mémoire=== Diverses optimisations permettent d'émettre des accès mémoire dans le désordre, exactement comme l’exécution dans le désordre le fait pour les autres instructions. Elles utilisent pour cela des ''schedulers'' spécialisées dans les accès mémoire. Il faut vraiment insister sur le fait que l'exécution dans le désordre proprement dite ne se préoccupe pas des micro-opérations mémoire. Pour faire la distinction, on parle de '''désambiguïsation mémoire''' (''memory disambiguation'') pour parler de l'exécution dans le désordre des accès mémoire. Le but de la désambiguïsation mémoire est d'exécuter les lectures le plus tôt possible. La raison est que la donnée lue est utilisée par d'autres instructions, dépendantes de la lecture. Elles sont donc à la tête d'une chaine de dépendances de données qui peut bloquer le pipeline si elle n'est pas résolue très tôt. Dès qu'une lecture peut être lancée, elle accède directement au cache de données. Par contre, si l'aliasing ne le permet pas (écriture à la même adresse pas encore effectuée) ou que l'adresse à lire n'a pas encore été calculée, la lecture attend son tour. Le problème est que la désambiguïsation mémoire demande de comparer des adresses, pour détecter les dépendances d'adresse. Et cela pose de sérieuses contraintes pour son implémentation. En comparaison, l'exécution dans le désordre normale compare des registres, ce qui est beaucoup plus simple. Les registres utilisés par une instruction sont directement encodés dans l'instruction elle-même, ce qui fait qu'on peut détecter les dépendances de registre à l'émission, voire au décodage. Et elles peuvent même être éliminées par le renommage de registre pour les dépendances WAW et WAR. Par contre, les adresses sont des opérandes d'instruction, elles ne sont pas encodées dans l'instruction elle-même. Il y a certes d'exception de l'adressage absolu, mais elle est minoritaire. Avec l'adressage indirect ou indicé, les adresses sont soit lues depuis les registres, soit calculées par une unité de calcul. Les adresses ne sont donc connues qu'une fois que l'instruction a attendu suffisamment de temps dans le ''scheduler''. ===Le calcul anticipé des adresses mémoire=== La désambiguïsation mémoire fonctionne d'autant mieux que les adresses à lire/écrire sont connues le plus tôt possible. Pour cela, il est possible de séparer les accès à la mémoire en deux micro-instructions : une pour le calcul d'adresse et l'autre pour les accès mémoire. Cela permet de calculer les adresses dès que possibles, et donc de vérifier à l'avance si l'adresse calculée a des dépendances avec celles des autres instructions. La détection des dépendances est ainsi anticipée de quelques cycles, permettant un accès anticipé sûr des accès mémoire. On parle de '''calcul anticipé des dépendances'''. Une implémentation possible effectue les calculs d'adresse dans les unités de calcul entière. L'ALU entière et l'unité mémoire sont alors dans deux avals séparés, en parallèle. La micro-opération de calcul d'adresse s'exécute dans une ALU, et son résultat est envoyé à l'unité mémoire. Pour cela, l'adresse calculée est envoyée à l'unité mémoire via un système de contournement dédié, qui relie les sorties des ALU entières à l'unité mémoire. Une solution alternative utilise un aval unique qui s'occupe à la fois des micro-opérations entières et des micro-opérations mémoire. L'aval a alors deux étages en série, un pour l'unité de calcul, suivi par l'étage d'accès mémoire. Le pipeline RISC classique était dans ce cas, pour rappel. Cette solution permet d'avoir un pipeline dit de longueur fixe, à savoir que toutes les instructions font le même nombre de cycles d'horloge. De plus, elle garantit que les instructions mémoire sont décodées en une seule micro-opération. En clair, il y a un seul aval pour toutes les instructions. Mais elle vient avec un défaut majeur : de nombreuses instructions n'utilisent pas l'unité mémoire, mais doivent quand même traverser l'étage associé, qui passe un cycle à ne rien faire. ==L’émission dans l'ordre des accès mémoire== Avant toute chose, faisons quelques rappels sur l'exécution dans le désordre. Les micro-opérations renommées sont mises en attente avant que les conditions pour leur émission soient remplies. La mise en attente peut se faire soit dans une file de micro-opération, soit dans un ''scheduler''. Une file de micro-opération est une mémoire FIFO qui garde les micro-opération dans leur ordre d'émission, l'ordre du programme. Les micro-opérations sont donc émises dans l'ordre du programme, il n'y a pas d'émission dans le désordre. Par contre, les ''schedulers''s peuvent émettre les micro-opérations dans le désordre, dans un ordre différent de celui du programme. Dans les deux cas, les écritures sont retardées via une file d'écriture, qu'on a vu il y a quelques chapitres et sur laquelle on fera des rappels. ===La file de µops mémoire=== Avec l''''émission dans l'ordre des accès mémoire''', le processeur émet les accès mémoire dans l'ordre du programme. Cela implique que l'unité mémoire n'a pas de ''scheduler'', ni de station de réservation associée. À la place, les micro-opérations mémoire sont placées dans une file de micro-opération dédiée, appelée la '''file de µops mémoire'''. Par contre, pour les unités de calcul, le processeur utilise des ''schedulers''. Autant les accès mémoire se font dans l'ordre, autant les instructions arithmétiques/logiques/branchements/autres sont exécutées dans le désordre. En clair, le processeur peut supporter l'exécution dans le désordre, sauf pour les micro-opérations mémoire. [[File:Processeur avec émission dans l'ordre des accès mémoire.png|centre|vignette|upright=2|Processeur avec émission dans l'ordre des accès mémoire]] : Nous avons volontairement omis le cas où le processeur n'a pas d'exécution dans le désordre, où il y a une file de micro-opération unique. Mais c'est globalement la même chose, car une file de micro-opération unifiée émet toutes les instructions dans l'ordre. La file de µops mémoire est une mémoire FIFO, qui contient plusieurs entrées, chaque entrée pouvant accueillir une µops mémoire. Une entrée contient plusieurs champs : un qui précise si l'opération est une lecture ou une écriture, un pour l'adresse mémoire à lire/écrire, un autre pour la donnée à écrire (qui est vide pour une lecture), un autre pour le registre de destination des lectures. Les deux derniers champs sont souvent fusionnés en un seul, qui est interprété différemment selon que l'instruction est une lecture ou une écriture. Elle contient aussi des bits de validité, qui indique si l'adresse ou la donnée sont disponibles, ou si le champ associé est vide. [[File:Load Store Queue unifiée.png|centre|vignette|upright=2.5|File de µops mémoire.]] L'unité mémoire ne permet que de faire un accès mémoire à la fois. Du moins, elle a un port sur lequel on envoie la micro-opération émise, que ce soit une écriture ou une lecture. Vu de l'extérieur, il faut attendre qu'un accès mémoire soit terminé pour lancer le suivant. Avant d'émettre une micro-opération mémoire, la file de micro-opération (son ''scoreboard'') vérifie si l'unité d'accès mémoire est libre ou non. Si elle est occupée, un accès mémoire est en cours, et on ne peut pas émettre de micro-opération mémoire. Une fois l'accès mémoire terminé, la mémoire ou le cache envoient un signal pour indiquer que l'accès est fini, et c'est au tour d'une nouvelle micro-opération mémoire. [[File:Unité de gestion des accès mémoires dans l’ordre.png|centre|vignette|upright=2.0|Unité de gestion des accès mémoires dans l’ordre]] Mais il s'agit là du comportement vu de l'extérieur de l'unité mémoire. En réalité, l'unité mémoire utilise quelques optimisations en interne qui permettent d'exécuter dans le désordre les micro-opérations mémoire. ===La file d'écriture : une FIFO de mise en attente des écritures=== Afin de supporter les exceptions précises, les écritures doivent respecter deux contraintes : s'exécuter dans le tout dernier étage du pipeline, s'exécuter dans l'ordre du programme. Pour cela, les écritures sont mises en attente tant que les instructions précédentes ne sont pas terminées. Les écritures dans le cache sont mises en attente dans une mémoire FIFO, appelée la '''file d'écriture''', ou encore la ''Write Queue''. Nous en avions déjà parlé dans le chapitre sur le pipeline, dans la section sur les exceptions précises. Mais quelques rappels ne feront pas de mal. L'écriture est insérée dans la file d'écriture lorsqu'elle est émise, elle en sort à l'étage de ''Writeback'' si tout se passe bien. Si une exception est détectée, l'étage de ''Writeback'' vide la file d'écriture, ce qui annule les écritures mises en attente, faites à tort. De plus, la file d'écriture est une mémoire FIFO, qui mémorise les écritures dans l'ordre du programme. En effet, les écritures sont ajoutées dans la file d'écriture lorsqu'elles sont émises, et elles sont émises dans l'ordre du programme. [[File:Store Queue sur un pipeline fixe.png|centre|vignette|upright=2|Write Queue sur un pipeline fixe]] La file d'écriture garantit que les écritures sont dans l'ordre du programme. Et cette propriété élimine totalement les dépendances WAW. Le fait que les écritures se font à la fin du pipeline élimine quant à elle les dépendances WAR. Il ne reste plus qu'à gérer les dépendances RAW, celles où une lecture lit une donnée écrite par une autre instruction. Une telle situation survient, car les écritures sont mises en attente pendant un certain temps, la donnée écrite peut être lue pendant ce laps de temps. La lecture ne peut pas lire la donnée dans le cache, car la donnée à lire n'y est pas encore enregistrée. Le cas est rare, car il demande de lire une donnée qu'on vient d'écrire, mais il existe. Il se manifeste surtout sur les processeurs avec peu de registre, où des données doivent régulièrement être déplacées temporairement en mémoire RAM. Pour éviter cela, une solution consiste mettre en attente les lectures si une écriture est en attente. Les lectures sont maintenues dans la file de µops tant que la file d'écriture n'est pas vide. La file de µops mémoire est suivie d'un circuit de détection des dépendances, un '''''scoreboard'' mémoire''' qui est assez simple. L'unité mémoire fournit un bit qui indique si la file d'écriture est vide ou non, ainsi qu'un second bit qui indique qu'elle est vide. Les deux ne sont pas compliqués à générer, ils font partie intégrante de l'interface de toute mémoire FIFO digne de ce nom. Le ''scoreboard'' mémoire utilise ces deux bits pour savoir s'il peut émettre une micro-opération mémoire. Il n'émet pas de lecture tant que la file d'écriture n'est pas vide. Il peut par contre émettre des écritures tant qu'elle n'est pas pleine. Une meilleure solution serait d'interdire les lectures, mais seulement en cas de dépendance mémoire détectée. Et c'est là qu'intervient la technique du '''''load bypassing'''''. Elle autorise une lecture, si elle n'a aucune dépendance avec les écritures mises en attente dans la file d'écriture. Elle doit être mise en attente dans le cas contraire. Pour l'implémenter, il faut comparer l'adresse à lire avec toutes les adresses dans la file d'écriture. La lecture est exécutée immédiatement si aucune correspondance n'est trouvée, mais elle est mise en attente dans le cas contraire. Pour cela, la file d'écriture est modifiée et devient un mélange entre FIFO et mémoire associative. L'adresse à lire est envoyée à la file d'écriture, et celle-ci vérifie si une écriture est en attente à cette adresse. Si c'est le cas, c'est un succès de ''Write Queue'' : la lecture doit être bloquée. Sinon, c'est un défaut de ''Write Queue'', la lecture accède au cache, là où se trouve la donnée à lire. Dans le chapitre sur le contournement, nous avons parlé d'une forme de contournement qui corrige ce problème. Les lectures peuvent lire la donnée depuis la file d'écriture si besoin, ce qui renvoie la donnée adéquate. Pour cela, les lectures consultent à la fois le cache et la file d'écriture, comme dit plus haut. L'adresse à lire est envoyée à la file d'écriture, et celle-ci vérifie si une écriture est en attente à cette adresse. Si c'est le cas, c'est un succès de ''Write Queue'', et celle-ci envoie alors la donnée associée à l'étage d'accès mémoire. Sinon, la lecture accède au cache, là où se trouve la donnée à lire. La solution porte le nom de ''Store to load Forwarding'', ou encore de '''réacheminement écriture-vers-lecture'''. [[File:Store to load forwarding sur un pipeline simple.png|centre|vignette|upright=2|Store to load forwarding sur un pipeline simple]] La lecture est mise en attente dans l'unité mémoire, vu que c'est elle qui fait les comparaisons d'adresse. Du point de vue extérieur, le ''scoreboard'' mémoire ne voit pas s’il y a eu succès dans la file d'écriture ou non. Il voit juste que l'unité mémoire est occupée et ne peut pas accepter de nouvelle lecture. Elle reste occupée durant quelques cycles, en cas de défaut de ''Write Queue'', le temps de faire la lecture dans le cache. Par contre, en cas de succès de ''Write Queue'', elle reste occupée tant que la lecture n'a pas donné de résultat, ce qui inclue le temps de mise en attente. Les processeurs haute performance implémentent tous le ''Store to load Forwarding'', mais quelques processeurs basse performance ne le font pas. Ils se contentent du ''load bypassing'', qui offre des performances correctes pour un cout en matériel bien plus modeste. Pour donner un exemple, la micro-architecture Jaguar d'AMD était dans ce cas. Elle a été utilisée sur les consoles de jeu de 8ème génération, comme la Xbox One et la Playstation 4. Les processeurs haute performance préférent utiliser plus de circuits pour implémenter le ''Store to load Forwarding'', mais l'implémentation n'est souvent pas complète. En effet, l'implémentation est souvent simple et ne prend en compte que des lectures/écritures à des adresses identiques, sans compter que la taille des données doit aussi être identique. Une écriture d'un entier de 32 bit sera contournée et envoyée à une lecture de 32 bits à la même adresse. Mais la lecture lit seulement 16 bits sur les 32 écrits, le contournement peut ne pas marcher. Concrètement, ce cas précis fonctionnera. Mais le cas inverse, avec une lecture lisant plusieurs écritures de taille plus petite, ne marchera pas sur tous les processeurs. Ne parlons pas du cas où les données écrites sont à cheval sur deux lignes de cache. ===Le contournement des adresses mémoire avec une file de µops=== Il faut noter qu'au moment où les instructions LOAD et STORE sont émises, leur adresse n'est pas forcément connue. Sauf en cas d'adressage absolu, mais mettons ce cas particulier de côté, il est assez rare en pratique. Les micro-opérations mémoire sont donc insérées dans la file de µops, mais l'adresse est souvent disponible plus tard. Il faut donc modifier le chemin de données pour que l'adresse soit envoyée à la file de µops mémoire. Pour simplifier, étudions le cas d'un processeur où les instructions LOAD/STORE ne gèrent que l'adressage indirect à registre, à savoir que l'adresse est lue dans un registre. Les calculs d'adresse sont réalisés par une instruction de calcul séparée de l'instruction LOAD/STORE. Tout calcul d'adresse a lieu dans les unités de calcul entière, les micro-opérations mémoire ne font pas de calcul d'adresse. Au minimum, il doit y avoir une connexion entre le banc de registre et la file de µops mémoire. Il faut alors attendre que les adresses soient enregistrées dans les registres pour être envoyées à la file de µops mémoire. Cependant, il est possible de profiter du réseau de contournement. L'idée est que l'adresse est accessible avant via le réseau de contournement, avant même d'être enregistrée dans les registres L'idée est que l'adresse est envoyée à l'unité mémoire dès qu'elle sort des unités de calcul. Le gain en performance étant important, tous les processeurs modernes ajoutent un système de contournement qui envoie les adresses à la file de µops mémoire. L'ALU entière calcule l'adresse finale, l'envoie à la file de µops mémoire. [[File:Contournement pour la file de µops mémoire.png|centre|vignette|upright=2|Contournement pour la file de µops mémoire]] Maintenant, les instructions LOAD/STORE avec un mode d'adressage indicé, ce qui signifie que l'instruction fait un calcul d'adresse et l'accès mémoire proprement dit. Une solution basique utilise une micro-opération séparée pour le calcul d'adresse et l'accès mémoire. Le calcul d'adresse envoie son résultat à la file de µops mémoire, sans l'enregistrer dans les registres, via contournement. Sans optimisation particulière, les calculs d'adresse sont réalisés par les ALU entières, le processeur n'est pas modifié et reste le même que celui du schéma précédent. Mais une autre solution utilise des ALU spécialisées dans les calculs d'adresse, appelées des ''Adress Generation Unit'', abrévié AGU. L'avantage est que cela simplifie grandement le réseau de contournement : seules les AGU sont connectées à la file de µops mémoire. Un autre avantage est lié à l'adressage de la destination. En utilisant des opérations entières usuelles, il faudrait préciser que le résultat est à destination de la file de µops mémoire, pour configurer le réseau de contournement. Avec des AGU, les calculs d'adresse sont des micro-opérations différentes des additions et soustraction, elles sont envoyées au AGU spécifiquement, pas besoin de préciser la destination. [[File:File de µops mémoire avec calcul d'adresse via AGU.png|centre|vignette|upright=2|File de µops mémoire avec calcul d'adresse via AGU]] Lors de l'émission, la micro-opération mémoire est insérée dans la file de µops mémoire, l'opération de calcul d'adresse est émise dans le ''scheduler''. Et les deux sont exécutés différemment. En effet, un calcul d'adresse est une opération arithmétique, qui est gérée par le système d'exécution dans le désordre. Elle peut s'exécuter dès que ses opérandes sont disponibles. À l'inverse de l'accès mémoire, qui lui doit se faire dans l'ordre du programme. Les adresses sont donc calculées en avance, puis insérées dans la file de µops mémoire. La µops de calcul d'adresse précise où enregistrer son résultat, le résultat est enregistré dans la bonne entrée de la file de µops mémoire. Les techniques précédentes décodent une instruction LOAD/STORE en deux micro-opérations. Mais il est possible de la décoder en une seule. Le calcul d'adresse est alors réalisé dans l'unité mémoire. Les opérandes du calcul d'adresse sont lues depuis les registres lorsque l'instruction quitte la file de µops mémoire, du moins pour les opérandes qui n'ont pas été contournées. Là, elles sont envoyées à l'unité mémoire, qui fait le calcul d'adresse. Dans les faits, aucun processeur commercial moderne n'utilise cette technique. [[File:File de µops mémoire avec calcul d'adresse dans l'unité mémoire.png|centre|vignette|upright=2|File de µops mémoire avec calcul d'adresse dans l'unité mémoire]] ===L'optimisation du pseudo-contournement des opérandes mémoire=== Les processeurs modernes implémentent une optimisation concernant les accès mémoire. Cette optimisation a été décrite par Agner Fog dans ses manuels d'optimisation, sous le terme de '''''Mirroring memory operand'''''. Il a documenté son apparition sur les processeurs Zen 2 d'AMD, puis son évolution sur les processeurs Zen 4 et 5. L'optimisation est bizarrement absente de la microarchitecture Zen 3. Elle se manifeste dans une condition très précise : plusieurs instructions proches accèdent à la même adresse. Les deux instructions ne sont pas forcément consécutives, il peut y avoir une dizaine ou centaine d'instructions entre les deux. Une telle situation survient souvent sur les CPU CISC, et notamment sur les CPU x86, car ils ont peu de registres. les compilateurs font donc beaucoup d'échanges entre pile d'appel et registres, ce qui fait que des données écrites dans la pile sont souvent relue quelques instructions plus tard. Dans ce cas, la donnée lue/écrite est mémorisée dans un registre interne au processeur et peut être accédée très rapidement. Par exemple, imaginons plusieurs lectures proches à la même adresse, sans écriture entre elles. Dans ce cas, le processeur ne fera qu'une seule lecture en mémoire RAM, les lectures ultérieures liront la donnée depuis le registre interne. Comme autre exemple, imaginons une écriture suivie plus tard par une lecture à la même adresse. Dans ce cas, la donnée sera écrite dans un registre interne, en plus d'être propagée dans le cache ou la RAM, et la lecture ultérieure lira directement le registre interne. Le gain en performance est alors conséquent, comparé à du simple ''store-to-load forwarding''. Il faut noter que la technique marche aussi pour les opérations ''load-op'', pas seulement pour les instructions d'accès mémoire. Par exemple, prenons une écriture en RAM, suivies quelques instructions plus tard par une opération ''load-op'' à la même adresse. L'écriture écrit à une adresse, qui est lue par l'instruction ''load-op''. L'optimisation s'applique : l'instruction ''load-op'' lira l'opérande mémoire depuis un registre interne du processeur, qui contient une copie de la donnée écrite. Sur les processeurs Zen 2, l'optimisation marchait aussi pour les instructions PSUH et POP, qui lisaient/écrivaient dans la pile d'appel. Mais cette possibilité a été retirée sur les processeurs Zen 5. La technique détecte que deux instructions accèdent à la même adresse sous certaines conditions bien précises. L'optimisation ne marche que pour les modes d'adressages indicés et indirect, avec ou sans décalages, mais pas en mode absolu ou relatifs. Il faut préciser que l'optimisation ne marche que pour les registres généraux, pas les registres flottants. Les registres doivent être précisés de la même manière dans toutes les instructions. Par exemple, le processeur ne reconnait pas que l'addition des deux registres RCX + RAX est la même que RAX + RCX. Sur les CPU Zen 2 et 4, elle ne marchait que pour des opérandes de 32 et 64 bits, mais les processeurs Zen 5 gèrent des données de 8 et 16 bits aussi. Les décalages étaient limités à 8 bits sur le Zen 2, mais n'a plus de limites sur les Zen 4 et 5. ==Le ''Load Ordering, Store Ordering''== Intuitivement, on dit qu'exécuter des µops mémoire dans le désordre demande de remplacer la file de µops mémoire par un ''scheduler''. Et si c'est en effet une solution intéressante, nous n'allons pas la voir toute de suite. Nous allons étudier le cas où cette file deµops mémoire est scindée en deux : une file pour les lectures et une autre pour les écritures. ===Les files de µops LOAD et STORE=== Dans le chapitre sur l'exécution dans le désordre, nous avons vu deux possibilités pour implémenter l'exécution dans le désordre. La première utilise un ''scheduler'' ou une station de réservation, l'autre utilise plusieurs files de µops séparées. Et cette technique peut parfaitement s'utiliser pour les micro-opérations mémoire. Les micro-opérations mémoire sont réparties dans deux files de µops mémoire séparées, chacun émettant des micro-opérations indépendamment de l'autre. Mais comment répartir les micro-opérations mémoire dans deux files, simplement et sans que cela pose des problèmes de dépendances de données ? La réponse à ces contraintes est toute simple : on utilise une file de µops spécialisée pour les lectures, et une autre pour les écritures. Les cours d'architecture des ordinateurs nomment souvent ces deux files en utilisant les termes de ''file de STORE'' (''store queue'') et de ''file de LOAD'' (''load queue''). Dans ce qui suit, nous parlerons de '''file de µops LOAD''' et de '''file de µops STORE''', pour bien préciser qu'il s'agit de file de µops. La file de STORE ne doit pas être confondue avec la file d'écriture, qui est appelée ''write queue'' en anglais. Les termes ''store queue'' et ''write queue'' désignent deux choses différentes, mais il y a un risque de confusion pour qui n'est pas assez attentif. D'autant plus que la méthode que nous allons voir a une file d'écriture en plus des deux files de µops mémoire. En effet, la file d'écriture ne mémorise pas des micro-opérations, juste des écritures déjà émises et en attente. Une entrée dans la file d'écriture contient une adresse et la donnée à écrire. Alors que dans la file de µops STORE, il se peut que l'adresse ou la donnée soient manquantes, car pas encore disponibles. De plus, la file d'écriture met en attente des écritures tant que les instructions précédentes ne sont pas terminées, alors que la file de µops STORE met en attente les micro-opérations avant leur émission. La première attend le feu vert de l'étage de ''Writeback'', l'autre attend le feu vert de l'étage de ''schedule'', d'un ''scoreboard'' amélioré. Les deux files sont chacune connectées à l'unité mémoire, via un port dédié. L'unité mémoire a donc un port pour les lectures, et un port pour les écritures. Le port d'écriture est relié à la file d'écriture, le port de lecture est directement relié au cache de données. il faut noter qu'une unité mémoire à deux ports n'est pas si bizarre que cela. En effet, le cache de données a lui aussi deux ports, dans la majorité des cas, avec un port de lecture et un port d'écriture. [[File:Load Ordering, Store Ordering.jpg|centre|vignette|upright=2|Exécution dans le désordre des lectures.]] Le fait de séparer lectures et écriture a de nombreux avantages. Le premier est qu'une file de µops mémoire unique gâche des transistors. Une écriture a besoin de mémoriser une adresse et une donnée, avec les bits de validité pour les deux. Une lecture n'a besoin que d'une adresse et du bit de validité associé. Avec une file de µops unique, chaque entrée de la file est suffisamment large pour contenir une écriture. Si elle ne contient qu'une lecture, elle est trop large, ce qui sous-utilise les circuits de la file. Avec des files de lecture/écriture séparées, on n'a pas ce problème, chaque file contient juste ce qu'il faut. Il y a donc une économie de transistors. Cependant, le système est moins flexible. Par exemple, prenons une file de µops mémoire unique, de 16 entrées. Elle peut mémoriser indifféremment 16 lectures, 16 écritures, ou n'importe quel mix d'écriture et de lectures tant qu'il se limite à 16 µops. Avec des files séparées, ce n'est plus le cas. Prenons par exemple le cas avec une file de µops LOAD de 10 éléments et une file de µops STORE de même capacité : impossible d'avoir 16 écritures en attente. Cependant, ce désavantage est quelque peu compensé par l'économie de transistor mentionnée précédemment, qui est réinvestie pour agrandir les files de µops. Typiquement, on agrandit la file de µops LOAD, car les lectures sont plus fréquentes que les écritures dans la majorité des programmes. En ayant une file de µops LOAD assez conséquente, le désavantage est fortement atténué, voire disparait. ===La gestion des dépendances avec des files de µops mémoire séparées=== L'usage de ces deux files de µops mémoire porte le nom de '''''Load Ordering, Store Ordering'''''. Il est intéressant de comparer cette technique avec la précédente, qui utilisait une file de µops mémoire séparée. Avec deux files séparées, les lectures s'exécutent dans l'ordre, les écritures s'exécutent dans l'ordre, mais les lectures peuvent passer avant/après les écritures et réciproquement, tant que l'aliasing le permet. Les écritures peuvent prendre de l'avance sur les lectures, ou réciproquement. Et cette avance est très utile si elle permet d'exécuter des lectures en avance. En comparaison, avec une file de µops unique, ni écritures ni lectures ne peuvent prendre de l'avance. Les performances sont donc améliorées, bien que de peu. Néanmoins, l'avance des lectures est limitée. Prenons le cas où une lecture doit être mise en attente, car son adresse n'est pas disponible. Avec une file de µops mémoire unique, la lecture bloque toutes les micro-opérations qui suivent. Avec deux files séparées, elle bloque uniquement les lectures, pas les écritures. Les écritures qui suivent la lecture peuvent s'exécuter. Le cas avec une écriture en attente est un peu différent. Une écriture en attente bloquera les écritures suivantes. Mais elle bloquera aussi les lectures postérieures : du point de vue de ces lectures, une écriture précédente a une adresse inconnue, on ne sait pas s'il y a dépendance mémoire avec et on suppose que oui dans le doute. En clair, l'avance des lectures n'a lieu que si les adresses des écritures précédentes sont connues, déjà calculées, sans quoi on ne peut pas détecter les dépendances mémoire. Le fait que les écritures peuvent être émises en avance fait que la détection des dépendances RAW est différent. L'idée générale reste cependant la même. Lors de l'émission, une lecture doit vérifier ses dépendances avec les écritures antérieures, une écriture doit vérifier ses dépendances avec les lectures ultérieures. Avec une file de µops unique, on est certain que les écritures antérieures sont dans la file d'écriture, dans l'unité mémoire. Et lorsqu'on émet une écriture, on est certain que les lectures ultérieures seront émises après. Avec deux files séparées, ce n'est pas forcément le cas. Si les lectures ont pris de l'avance, une écriture précédente peut être en attente dans la file de µops STORE, alors qu'une lecture ultérieure a été émise. Ce qui complique la détection des dépendances RAW d'adresse. Les détecter demande non seulement de vérifier la file d'écriture, mais aussi la file de µops STORE. Dans ce qui suit, on suppose que l'unité mémoire incorpore une file d'écriture, ce qui est toujours le cas en pratique. Le fait que les écritures se font dans l'ordre élimine les dépendances WAW et WAR. On suppose aussi que l'unité mémoire implémente le ''réacheminement écriture-vers-lecture'' (''store-to-load forwarding''). Ainsi, si une lecture est émise dans l'unité mémoire, les dépendances RAW avec les écritures déjà émises ne sont pas un problème. Par contre, il faut gérer les dépendances avec les écritures en attente dans la file de µops STORE, dont certaines sont antérieures à la lecture dans l'ordre du programme. Pour cela, il n'y a pas le choix : pour chaque lecture, on vérifie dans la file de µops STORE si elle a une dépendance avec une écriture antérieure. La gestion des dépendances RAW est donc gérée partiellement dans l'unité mémoire et la file de µops STORE. Pour l'implémenter, il faut comparer l'adresse à lire avec toutes les adresses dans la file de µops STORE. En cas de ''match'', la lecture est bloquée dans la file de lecture. Mais s'il n'y a aucune correspondance, alors la lecture peut s'exécuter. Pour cela, la file de µops STORE est un mélange entre FIFO et mémoire associative. Il faut préciser que la comparaison ne prend en compte que les écritures situées avant la lecture, dans l'ordre du programme. Les deux files de µops doivent donc mémoriser des informations sur l'ordre d'émission. De plus, il arrive que des écritures soient dans la file d'écriture, mais que leur adresse n'ait pas encore été calculée. Dans ce cas, il y a potentiellement dépendance avec la lecture si l'adresse se révèle être la même une fois calculée : on considère que les adresses inconnues sont des correspondances/''match''. La file de lecture met des lectures en attente, soit car elle attend ses opérandes, soit car elle attend que les lectures précédentes soient terminées, soit car l'aliasing ne lui permet pas. Elle a cependant un défaut : celui de forcer les lectures à s’exécuter dans l'ordre, ce qui est une contrainte inutile. Mais l'avantage est que l'implémentation est très simple. Une file de micro-opération est bien plus simple à implémenter qu'un ''scheduler''. ==Le ''Partial Ordering'' : la ''Load/Store Queue''== Avec la technique précédente, les lectures s'exécutent dans l'ordre, à savoir que l'on ne peut pas déplacer une lecture avant ou après une autre. Et cette limitation a des conséquences sur la performance de l'exécution dans le désordre. Des lectures sont mises en attente, parce qu'une lecture précédente l'est, alors qu'elles auraient pu s’exécuter avant. Et ce retard sur les lectures se répercute sur les instructions lecture-dépendantes, donc sur le reste du pipeline. Pour éviter cela, la technique du ''Partial Ordering'' permet aux lectures de s'exécuter dans le désordre tant que les conditions d'aliasing sont respectées. ===La ''Load/Store Queue''=== La technique s'implémente en remplaçant les files de µops mémoire par un ''scheduler'' spécialisée dans les µops mémoire. Elle est souvent appelée la '''''Load/Store Queue''''', qui est concrètement une station de réservation spécialisée dans les micro-opérations mémoire. En tout cas, nous utiliserons beaucoup l'abréviation LSQ pour parler de la ''Load/Store Queue''. [[File:Processeur avec émission dans le désordre des accès mémoire.png|centre|vignette|upright=2|Processeur avec émission dans le désordre des accès mémoire]] Une entrée de la ''Load/Store Queue'' contient plusieurs champs : un qui précise si l'opération est une lecture ou une écriture, un pour l'adresse mémoire à lire/écrire, un autre pour la donnée à écrire (qui est vide pour une lecture), un autre pour le registre de destination des lectures (inutile pour les écritures). Les deux derniers champs sont souvent fusionnés en un seul, qui est interprété différemment selon que l'instruction est une lecture ou une écriture. [[File:Load Store Queue unifiée.png|centre|vignette|upright=2.5|''Load/Store Queue''.]] Lorsqu'une micro-opération mémoire est émise, après renommage de registres, elle est insérée dans la ''Load/Store Queue''. Si l'adresse à lire/écrire est disponible, elle est immédiatement lue depuis les registres, idem pour une éventuelle donnée à écrire. Sinon, la micro-opération attend dans la LSQ que son adresse soit calculée par l'ALU entière. Pour gérer ce cas, elle contient des bits de validité pour chaque champ qui indiquent si l'adresse d'accès est connue, et si la donnée à écrire est disponible pour une écriture. Il faut noter que tout ce qui a été dit plus haut à propos du contournement des adresses vaut aussi avec une ''Load/Store Queue'', à un détail près. Pour détecter les dépendances, la LSQ doit comparer les adresses à lire/écrire, ce qui fait qu'elles doivent avoir été calculées avant d'entrer dans la LSQ. En clair, il n'est pas possible de faire les calculs d'adresse dans l'unité mémoire, juste avant d’accéder au cache. Les unités de calcul d'adresse sont réalisés dans une ALU entière ou une AGU spécialisée. Lorsqu'une instruction mémoire est émise, elle est décodée en deux micro-opérations : une pour le calcul d'adresse, une autre pour l'accès mémoire proprement dit. Le calcul d'adresse est réalisé soit dans une ALU entière, soit dans une AGU spécialisée. L'accès mémoire attend dans la ''Load/Store Queue'' que l'adresse soit calculée. Une fois l'adresse calculée, elle est envoyée à la ''Load/Store Queue'' et est enregistrée dans l'entrée adéquate. Reste qu'il faut envoyer l'adresse des ALU à la LSQ. Pour cela, on réutilise le réseau de contournement du processeur. L'implémentation la plus simple effectue les calculs d'adresse dans les ALU entières. La sortie de toutes les ALU entière est reliée à la LSQ. [[File:Load-Store Queue.png|centre|vignette|upright=2|Load-Store Queue]] Les processeurs modernes préfèrent utiliser des unités de calcul d'adresse dédiées, afin de simplifier le réseau de contournement. [[File:ALU et LSQ.png|centre|vignette|upright=1.5|ALU et LSQ]] En pratique, les LSQ proprement dites sont peu efficaces, pour un budget en transistor donné. La raison est qu'une entrée de la LSQ doit mémoriser indifféremment lectures et écritures. Et elle contient pour cela plusieurs champs : l'adresse à lire/écrire, le registre pour la donnée à lire/écrire, et un champ pour la donnée à écrire. Or, pour une lecture, le dernier champ, pour la donnée à écrire, est inutile. Sachant que les lectures sont beaucoup plus nombreuses que les écritures, ce champ sera gaché pour la majorité des instructiosn, et les transistors associés le seront aussi. Une solution pour cela est d'utiliser une file séparée pour les lectures et écritures. ===La détection des dépendances mémoire=== La ''Load/Store Queue'' est couplée à un système de détection des dépendances mémoire, qui détermine quelles instructions peuvent s'exécuter sans problème. Et ce système de détection des dépendances est bien différent de celui d'une station de réservation normale. Les ''Load/Store Queue'' comparent non pas des noms de registres, mais des adresses/opérandes. Chaque micro-opération en attente compare son adresse avec celle de toutes les micro-opérations précédentes. Ou presque, la comparaison ne doit tenir compte que des écritures, et de celles situées avant dans l'ordre du programme. La ''Load/Store Queue'' doit donc mémoriser les instructions dans l'ordre du programme, tout en faisant des comparaisons d'adresse. Ça en fait une sorte hybride entre mémoire associative et mémoire FIFO. Nous avions vu dans le chapitre "L'exécution dans le désordre" qu'il y a plusieurs manières pour implémenter une station de réservation : avec une mémoire associative, avec préplanification, avec des matrices de dépendances. Le problème est qu'on ne peut pas utiliser une mémoire associative pour la LSQ, qui utilise des comparateurs pour comparer les noms de registres/adresses. En effet, la détection des dépendances mémoire demande de faire beaucoup de comparaisons : chaque adresse est comparé à toutes les autres. Et les adresses faisant facilement 32 à 64 bits, les comparateurs sont bien plus imposants que ceux qui comparent des noms de registres de 5-10 bits. Le cout en matériel serait trop élevé, de même que le temps de calcul des dépendances. À la place, on utilise des matrices de dépendances. La détection des dépendances mémoire utilise précisément deux matrices de ce type : une matrice de disponibilité, et une matrice de dépendance. Ces matrices forment une espèce de tableau carré, organisé en lignes et en colonnes. L'instruction dans la énième entrée se voit attribuer la énième ligne et la énième colonne. À l'intersection d'une ligne et d'une colonne, on trouve un bit qui indique si l'instruction de la ligne et celle de la colonne ont une dépendance. La '''matrice de disponibilité''' permet de bloquer l'exécution des lectures/écritures tant qu'une instruction précédente n'a pas calculé son adresse, tant qu'on ne peut pas vérifier les dépendances. Lorsqu'une instruction est ajoutée dans le LSB, elle met tous les bits de la colonne attribuée à 1 si l'adresse à lire/écrire est inconnue, puis les met à 0 une fois l'adresse calculée. Une instruction ne peut pas démarrer si, sur la ligne qui lui est attribuée, se trouve un 1. Plus précisément, si on trouve un 1 pour les instructions plus anciennes, ce qui fait qu'une partie de la matrice est ignorée. Les bits notés X dans le tableau suivant sont ignorés, car ils précisent la disponibilité des opérandes d'un opérande ultérieure, ce qui est inutile. En clair, les calculs d'adresse modifient les colonnes, et on vérifie les lignes pour autoriser l'exécution. {|class="wikitable" |- ! Instructions mémoire dans la LSB, triées de la plus ancienne à la plus jeune ! 0 !! 1 !! 2 !! 3 !! 4 !! 5 !! 6 |- ! 0 | 1 || X || X || X || X || X || X |- ! 1 | 0 || 0 || X || X || X || X || X |- ! 2 | 0 || 1 || 0 || X || X || X || X |- ! 3 | 0 || 1 || 1 || 1 || X || X || X |- ! 4 | 0 || 0 || 0 || 0 || 1 || X || X |- ! 5 | 0 || 0 || 1 || 0 || 0 || 1 || X |- ! 6 | 1 || 1 || 1 || 1 || 1 || 1 || 0 |} Les '''matrices de dépendances''' fonctionnent sur le même principe, mais déterminent les dépendances mémoire. Lorsque le processeur a calculé une adresse, il la compare avec les adresses à lire/écrire déjà dans la LSB. Il met alors à jour les bits de la colonne de la matrice de dépendance : le bit à l'intersection d'une ligne et d'une colonne est mis à 0 si les deux instructions n'ont pas de dépendances, à 1 si elles en ont une. Une instruction mémoire est exécutée si tous les bits de sa ligne sont à 0. Là encore, on ne tient compte que des bits pour les instructions plus anciennes, la matrice a encore une fois une forme triangulaire, comme pour la matrice de disponibilité. Une optimisation scinde la ''Load/Store Queue'' en deux structures, aux rôles légèrement différents. La première gère la disponibilité des opérandes, la seconde gère seulement les dépendances mémoire. La première est une station de réservation où les instructions sont mises en attente tant que leurs opérandes ne sont pas prêts. La seconde met en attente des micro-opérations dont les opérandes sont prêts, mais qui doivent attendre pour une autre raison : dépendance mémoire, cache occupé, etc. L'avantage est qu'on remplace une grosse station de réservation par deux plus petites, mais l'intérêt est surtout relié au système de détection des dépendances. Sans cette optimisation, on a deux matrices énormes reliées à une ''Load/Store Queue'' unique. Avec la séparation, la matrice de disponibilité est reliée uniquement à la première station de réservation, alors que la matrice de dépendance est reliée uniquement à l'autre. Les deux matrices sont donc plus petites, car reliées à deux stations de réservation mémoire plus petites. ==L'exécution spéculative des accès mémoires== Pour rappel, le but de la désambiguïsation mémoire est d'exécuter les lectures le plus tôt possible. Les données lues sont en effet, le départ d'une série d'instructions dépendantes, généralement des instructions arithmétiques, mais parfois d'autres lectures. Quand on manipule des structures de données, il n'est pas rare qu'une lecture lise un pointeur-adresse utilisé par une autre lecture. Les techniques de désambiguïsation mémoire que nous avons vu précédemment sont dites conservatrices, à savoir qu'elles ne changent pas l'ordre de deux instructions mémoire si elles ont une dépendance d'adresse. Elles exécutent une lecture le plus tôt possible, mais seulement si on sait que celle-ci n'aliase pas d'écritures précédentes. Et cela demande de connaitre les adresses des écritures précédentes dans l'ordre du programme. Si une lecture est précédée par une ou plusieurs écritures, les adresses à écrire doivent être connues. Il se peut en effet qu’une écriture dont on ne connait pas l'adresse aliase la lecture. La garantie est liée à la présence de la file de µops mémoire ou la file de µops STORE. Si une seule écriture a une adresse inconnue, elle reste dans la file de µops mémoire et bloque l'émission de toutes les autres micro-opérations mémoire, lecture comme écriture. Mais il existe des techniques dites spéculatives, qui modifient l'ordre des accès mémoire sans se soucier de leurs dépendances. Elles émettent les lectures dès que leurs opérandes sont prêts, sans se préoccuper de l'aliasing avec une écriture précédente. Pour éviter tout problème, le processeur vérifie si aucune dépendance mémoire n'est violée et corrige le tir dès qu'une violation est détectée. Le processeur vérifie s'il a fait une erreur de prédiction, en vérifiant les adresses à écrire ou lire. En cas d'erreur, le processeur fait comme lors d'une prédiction de branchement ratée : il remet le pipeline en ordre et ré-exécute les accès mémoire dans le bon ordre. Il s'agit d'un cas particulier d’'''exécution spéculative''', au même titre que la prédiction de branchement. Toutes les techniques de ce genre exécutent des lectures dans le désordre. L'avantage est que cela permet d'exécuter les lectures en avance. Vu que la donnée lue est l'opérande d'autres instructions, les exécuter en avance fait prendre de l'avance à un paquet d'instructions. Mais il faut comparer cet avantage au risque de mauvaise prédiction. Et aussi bizarre que cela puisse paraître, cela donne de bons résultats. Il faut dire que les situations où une lecture relit une donnée tout juste écrite sont rares : même pas 2 à 3 % des lectures. Les dépendances mémoire sont donc très rares, les cas d'aliasing sont vraiment limités. En termes de cout en transistors, le hardware qui vérifie les dépendances mémoire reste globalement le même à peu de choses près, il est juste déplacé dans le pipeline et adapté à sa nouvelle fonction. ===La file de lectures=== La première technique que nous allons voir reprend la technique du ''Load Ordering, Store Ordering'', avec ses deux files de µops de lecture et d'écriture. Elle exécute les lectures sans se préoccuper des dépendances avec les écritures. Mais le processeur vérifie qu'aucune violation de dépendance n'a eu lieu après un certain temps. Une violation de dépendance peut avoir lieu pour n'importe quelle instruction précédant la lecture dans l'ordre du programme. En clair, le processeur doit conserver les lectures spéculatives tant que les instructions précédentes ne sont pas terminées. Pour cela, il faut ajouter une nouvelle file d'attente, qui mémorise les lectures terminées. Nous l’appellerons la file de vérification des lectures, ou encore la '''file de lectures'''. Elle fonctionne sur le même principe que la file d'écriture et les deux font partie de l'unité mémoire. Les deux visent à remettre les lectures/écritures dans l'ordre du programme, afin que les instructions suivant une lecture/écriture fautive soient annulées. Les lectures sont insérées dans la file de lecture à l'émission, quand elles quittent la file de µops mémoire/LSQ, ce qui est la même chose avec les écritures pour la file d'écriture. Une différence très importante est que les écritures sont retardées alors que les lectures s'exécutent immédiatement. D'ailleurs, la file de lecture ne sert pas pour le contournement : les données lues sont immédiatement envoyées au chemin de données, pas besoin de les contourner ultérieurement. Alors que la file d'écriture est utilisée pour le contournement en cas de dépendances RAW. Les lectures sortent de la file µops LOAD dès que leurs adresses sont calculées, sans tenir compte des dépendances mémoires. Elles sont alors ajoutées à la file de lectures et s'exécutent immédiatement, de manière spéculative. Pour vérifier qu'il n'y a pas d'erreur de spéculation, le processeur conserve l'adresse de la lecture effectuée dans la file de lectures. Les lectures quittent la file de lecture quand toutes les instructions précédentes dans l'ordre du programme sont terminées, à savoir tant quand elles ont quitté le tampon de réordonnancement/ROB. Notons que la file de vérification des lectures contient les lectures dans l'ordre du programme. En effet, les lectures sont accumulées en sortant de la file de µops LOAD, où elles sont triées dans l'ordre du programme. Et cela permet de gérer les erreurs de prédiction parfaitement, en annulant les instructions suivant une erreur de prédiction. [[File:Spéculation avec une file de lecture.jpg|centre|vignette|upright=2.5|Spéculation avec une file de lecture.]] Reste à détecter les erreurs de prédiction, ce qui peut être fait avec deux méthodes. Avec la première, les violations de dépendances mémoire sont faites à chaque écriture. Précisément, la détection a lieu quand une écriture est sur le point de quitter la file d'écriture. L'unité mémoire récupère alors l'adresse d'écriture et la compare avec toutes les lectures dans la file de vérification des lectures. Si aucune correspondance n'est trouvé, c'est que les lectures spéculatives n'ont accédé à l'adresse d'écriture. Mais s’il y a correspondance, c'est qu'une lecture a lu l'adresse avant qu'elle soit écrite. Pour cela, la file de vérification des lectures est un mélange entre FIFO et cache/mémoire associative. La vérification fait cependant gaffe à ne prendre en compte que les lectures situées après l'écriture dans l'ordre du programme (seulement ces instructions sont capables de générer une dépendance RAW). Avec la seconde méthode, les violations de dépendance mémoire sont détectées au moment où la lecture quitte à la file de lectures et le ROB. Mais cela demande que la donnée lue soit recopiée dans la file de lecture. Quand la lecture quitte la file de lecture et le ROB, la lecture est ré-exécutée et la donnée relue. Le processeur compare alors la donnée lue à ce moment avec la donnée mémorisée dans la file de lecture. Si la donnée est différente, alors il y a eu erreur de violation de dépendance mémoire. Évidemment, relire une donnée n'est pas gratuit. Il est possible de limiter son impact en performance en dédiant un port de lecture sur le cache rien que pour ça. Mais le cout en circuit est comparable à l'usage d'une FIFO associative de la technique précédente. Mais quoi qu'il en soit, le cache doit permettre des lectures en un seul cycle, sans quoi la méthode ne marche pas vraiment. ===La prédiction de dépendances mémoires=== Certains processeurs essayent de prédire si deux accès mémoires sont dépendants : ils incorporent une unité qui va fonctionner comme une unité de prédiction de branchement, à la différence qu'elle prédit les dépendances mémoires. Si cette unité prédit que deux accès mémoires sont indépendants, le processeur les exécute dans le désordre, et les exécute dans l'ordre du programme dans le cas contraire. Il faut prendre en compte les erreurs de prédiction, ce qui est fait comme pour les mauvaises prédictions de branchement : on vide le pipeline. Beaucoup de techniques de prédiction des dépendances mémoire ont été inventées et en faire une revue exhaustive serait long et fastidieux. On pourrait citer les ensembles colorés (''color sets''), et bien d'autres techniques. Mais nous n'allons parler que des techniques les plus élémentaires. Quoi qu’il en soit, la recherche sur le sujet est assez riche, comme toujours quand il s'agit d'architecture des ordinateurs. On peut améliorer cette technique en mémorisant les instructions qui ont causé une mauvaise prédiction de dépendance mémoire. La prochaine fois qu'on exécute ces instructions, on sait qu'il y a de grandes chances qu'il se produise une erreur de prédiction, ce qui pousse à ne pas les exécuter de manière spéculative. On peut pour cela réutiliser les techniques de prédiction de branchement, tels des compteurs à saturations, mis à jour en cas d'erreurs de prédiction de dépendances mémoire. Dans tous les cas, on trouve un cache, équivalent au ''branch target buffer'', qui mémorise les instructions fautives (leur ''Program Counter''), avec d'autres informations comme les adresses des instructions dépendantes. La première classe de techniques du genre consiste à mémoriser les lectures qui ont causé une violation de dépendance, tandis que l'autre ne mémorise que les écritures. Cette dernière est l'approche utilisée par le '''cache de barrières d’écriture''' (store barrier cache). Enfin, nous allons conclure avec une dernière technique : celle des '''ensembles d’écritures''' (store sets). Cette technique est capable de gérer le cas où une lecture dépend de plusieurs écritures : le processeur mémorise l'ensemble des écritures avec lesquelles la lecture a déjà eu une dépendance. Cet ensemble d'écritures associées à une lecture est appelé tout simplement un ensemble d’écritures, et reçoit un identifiant (un nombre) par le processeur. Cette technique demande d'utiliser deux tables : * une qui assigne un identifiant d’ensemble d’écritures à l'instruction en cours ; * une autre qui mémorise les ensembles d’écritures sous la forme d'une liste chainée : le début de la liste correspond à l'écriture la plus ancienne de l’ensemble. Cela permet d'obtenir l'écriture la plus ancienne dans cet ensemble d’écritures directement. Quand le processeur détecte une violation de dépendance entre une lecture et une écriture, elle ajoute l'écriture dans l’ensemble d’écritures adéquat. Le déroulement d'une lecture demande d'accéder à la première table pour récupérer l'identifiant de l’ensemble d’écritures, et l'utiliser pour adresser la seconde table. S'il y a dépendance, cet accès renvoie l'écriture fautive en cas de dépendance. Quand une écriture est envoyée à l'unité mémoire, celle-ci va accéder à la table de correspondances de la même manière qu'une lecture, et va récupérer l'identifiant de l’ensemble d’écritures auquel elle appartient, identifiant qui est utilisé pour vérifier s'il y a une écriture en cours d’exécution. Si c'est le cas, cela signifie que l'écriture en cours d’exécution doit s’exécuter avant l'écriture qui a consulté la table : cette dernière est mise en attente. ==La prédiction d'adresse et de valeur== D'autres techniques de prédiction mémoire plus élaborées que les précédentes existent. Il s'agit de la prédiction d'adresse et de la prédiction de valeur. Leur nom trahit ce qu'elles font. La première technique tente de prédire l'adresse d'une lecture/écriture, alors que la seconde tente carrément de prédire quelle sera la donnée lue. Il y a bien de la recherche académique sur le sujet, mais il s'agit de techniques assez osées, dont on voit mal comment elles pourraient fonctionner. L'efficacité de cette technique a été étudiée grâce à des simulateurs. Suivant les études ou les programmes, on trouve des résultats qui varient pas mal. Dans certains cas, la performance baisse un peu, et dans d'autres, on peut avoir des gains de plus de 10% ! Mais dans des cas normaux, on trouve des gains de 4-5% environ. Ce qui est tout de même pas mal à l'heure actuelle. Cependant, en Janvier 2025, à l'heure où j'écris ces lignes, il a été découvert la première utilisation de ces deux techniques dans un processeur commercial. La découverte fait suite à la publication de deux vulnérabilités matérielles sur les CPU Apple M2 et M4 et quelques CPU ARM, qui font justement usage de ces deux techniques. Les deux vulnérabilités, appelées SLAP et FLOP, sont assez similaires aux attaques Spectre et Meltdown, sauf qu'elles attaquent non pas la prédiction de branchement, mais la prédiction d'adresse et de valeur du CPU. ===La prédiction d'adresse=== La prédiction d'adresse tente de prédire l'adresse d'une lecture à l'avance, ce qui permet de lancer les lectures en avance. Si la prédiction est correcte, on gagne quelques cycles qui permet aux unités de calcul de faire leurs calculs plus en avance, sans compter que les mécanismes de désambiguïsation mémoire fonctionnent plus efficacement. Si jamais cette adresse est connue plus tôt, on détecte les dépendances plus rapidement et on peut agir en conséquence. Des variantes de ces unités de prédiction d'adresse sont utilisées pour précharger des données depuis le cache de donnée. Et leur efficacité est assez bonne, voire excellente dans certains cas. La différence est que la prédiction d'adresse est utilisée pour prédire les adresses à lire depuis le cache vers les registres, ce qui est le sujet de cette sous-partie. La prédiction d'adresse est réalisée par une sorte de cache, qui associe à chaque instruction la prochaine adresse à lire. Nous appellerons ce cache la '''table de prédiction d'adresse'''. Pour faire l'association instruction <-> adresse lue/écrite, le tag du cache utilise l'adresse de l'instruction (le ''program Counter''), alors que la ligne de cache associée contient l'adresse prédite. Son contenu est utilisé pour faire une prédiction. Lorsqu'une lecture est émise, la table est consultée pour récupérer en avance l'adresse à lire, avant que celle-ci soit calculée par l'ALU. La lecture est alors exécutée en avance, avant que la vraie adresse soit connue, en utilisant l'adresse prédite. Reste qu'il faut des circuits autour de cette table de prédiction d'adresse, pour déterminer si la prédiction est correcte, ainsi que pour remplir cette table avec une adresse prédite. Pour cela, il y a un circuit de prédiction d'adresse dédié. Il récupère les instructions qui quittent le ROB ou la file des lectures mémoire, afin de vérifier les lectures qui viennent de se terminer/''commit'' et qui quittent le pipeline. Il peut contenir une '''table d'apprentissage''', qui mémorise des informations nécessaires pour faire des prédictions d'adresse. Par exemple, un historique des dernières adresses lues pour les lectures les plus récentes, ou un historique des adresses des lectures. La table est aussi utilisée pour déterminer si les prédictions effectuées étaient correctes ou non. Pour cela, il est possible de réutiliser les techniques vues dans le chapitre sur la prédiction de branchement, notamment des compteurs à saturation. Pour la prédiction de branchement et les autres formes de prédiction mémoire, les table d'apprentissage et pour les instructions/adresses sont fusionnées en une seule. Mais ici, il est nécessaire de les séparer pour une raison assez particulière : éliminer la pollution du cache dans la table de prédiction d'adresse. On ne peut pas allouer une ligne de cache pour chaque nouvelle instruction de lecture exécutée. Seule une minorité des lectures profitent de la prédiction d'adresse. Il est nécessaire de filtrer les lectures pour ne conserver que celles qui profitent de la prédiction d'adresse, ce qui est possible plus facilement en séparant la table d'apprentissage et les compteurs à saturation de la table de prédiction d'adresse. Une première méthode consiste à prédire que la lecture lit toujours la même adresse, ce qui lui vaut le nom de '''prédiction d'adresse constante'''. On pourrait se demander pourquoi une telle situation surviendrait. La raison est qu'il arrive que les compilateurs n'arrivent pas à gérer les accès mémoires efficacement. Dans certaines situations un peu compliquées impliquant des pointeurs ou des références, divers phénomènes complexes d'''aliasing'' des pointeurs peuvent générer des relectures intempestives de données en mémoire. Cela peut aussi arriver lorsqu'on compile du code qui provient de plusieurs librairies, ou quand du code lit régulièrement des constantes en mémoire ROM. La prédiction d'adresse constante ajoute un circuit qui analyse les dernières lectures, une fois qu'elles quittent le ROB, qu'elles ''commit''. Si, pour une instruction de lecture, l'adresse lue est toujours la même, alors l'instruction est ajoutée dans la table de prédiction d'adresse. Vu que les instructions qui accèdent toujours à la même adresse sont rares, il est préférable d'initialiser les compteurs à saturation de façon à ce qu'ils disent que toute nouvelle instruction change d'adresse. Il s'agit d'une méthode simple mais peu efficace, car cette situation est rare. Une autre méthode détecte les accès en enjambées, là encore quand les lectures quittent le ROB. Nous l’appellerons la '''prédiction d'adresse en enjambées'''. De tels accès surviennent régulièrement quand on accède des tableaux ou d'autres structures de données semblables, ce qui rend la technique très intéressante. Implémenter cette technique est facile : il suffit d'ajouter un circuit qui détecte les accès en enjambées, au lieu de celui qui détecte les accès constants. À chaque fois qu'une lecture entraine un succès de cache dans la table de prédiction d'adresse, l'enjambée est ajoutée à l'adresse contenue dans la table de prédiction d'adresse, l'ancienne adresse prédite est remplacée par celle avec l'enjambée d'ajoutée. Sur les Apple M2-M4, la prédiction d'adresse gére aussi bien les adresses constantes que les accès en enjambée. Le brevet qui décrit l'implémentation de l'unité de prédiction d'adresse et de valeur est potentiellement le suivant : [https://patents.google.com/patent/US11829763B2/en Early load execution via constant address and stride prediction]. En théorie, il est possible de faire mieux en repérant des accès mémoires qui se répètent de façon régulière et cyclique, même s'ils n'ont aucune enjambée. Ce genre d'accès se trouve assez souvent lorsque l'on manipule des listes chainées ou des structures de données assez irrégulières comme des arbres, des graphes, etc. Mais il n'y a pas encore de CPU qui implémente de telle optimisation. ===La prédiction de valeur : prédire la donnée lue=== Les techniques de '''prédiction de valeur''' (''Value Prediction'') consistent à prédire quelle est la donnée qui sera lue par une instruction de lecture. Oui, vous avez bien lu : le processeur est capable de parier sur la valeur qui sera chargée depuis la mémoire, de prédire si cette valeur vaut 0, 1, 1024, etc. Une fois son pari fait, il exécute les instructions du programme avec la valeur qu'il a pariée de façon spéculative. Si le pari est correct, le CPU continue l’exécution. Sinon, il est obligé de vider le pipeline et de recommencer avec la bonne valeur. Au premier abord, cette technique semble franchement mal partie tellement les chances de se tromper sont tellement énormes ! Mais le fait est que, dans certains cas, il est possible de spéculer correctement. Là encore, les techniques les plus simples fonctionnent dans deux cas. Le premier est celui où une donnée est relue à l'identique à chaque fois que la lecture est exécutée. Le second est celui où la donnée est incrémentée/décrémentée d'une constante qui est toujours la même d'une exécution de la lecture à l'autre. Une sorte d'enjambée constante, mais pour les données. Nous allons nous concentrer sur le premier cas, celui où une donnée est relue plusieurs fois sans être modifiée entre temps. L'idée de base est qu'une instruction de lecture qui s'exécute plusieurs fois de suite à la même adresse renvoie la même valeur à chaque fois. C'est parfaitement possible s’il n'y a eu aucune écriture à cette adresse entre-temps, d'où le fait qu'il faille surveiller si les prédictions constantes sont correctes. On peut se demander quelles sont les raisons qui font qu'une instruction de lecture renvoie la même valeur à chaque fois. Après tout, autant lire une seule fois la donnée et la garder dans un registre une bonne fois pour toutes ! Mais dans la réalité, on fait face à quelques limites, qui seront détaillées dans la liste suivante. La première est que le manque de registre fait que certaines données sont conservées en RAM et sont relues fréquemment. Cela arrive quand on stocke des constantes en mémoire. Par exemple, sur les processeurs x86, les constantes flottantes ne peuvent pas être intégrées dans nos instructions via le mode d'adressage immédiat. À la place, on les stocke en mémoire et on les charge dans les registres à chaque fois qu'on en a besoin. L'implémentation est similaire à la prédiction d'adresse, si ce n'est que c'est la donnée lue qui est prédite. Là encore, on a une '''table de prédiction de donnée lue''', consultée lorsqu'une lecture est émise. La table de prédiction de la donnée lue est une mémoire cache qui associe le ''Program Counter'' de la lecture à la donnée prédite, éventuellement couplé à des compteurs à saturation. Elle est consultée à chaque fois qu'une lecture est émise, la donnée adéquate est récupérée lors d'un succès de cache. On trouve aussi un circuit qui insère ou retire des instructions de la table de prédiction de donnée lue. Elle détecte les lectures prédictibles, couplé à une table d’apprentissage, et quelques circuits annexes liés au ROB ou aux files de lectures. Elle contient au minimum des compteurs à saturations, associés chacun à une instruction (son ''program counter'' pour être précis). ==La désambiguïsation mémoire a des effets de bord== La désambiguïsation mémoire a une caractéristique que l'exécution dans le désordre simple n'a pas : elle a des effets qui débordent sur la mémoire. Il est possible de savoir si un processeur fait de la désambiguïsation mémoire en regardant le bus mémoire. On s’aperçoit alors que les lectures se font dans un ordre différent de celui du programme. À l'opposé, l'exécution dans le désordre n'a pas d'effets observables de ce genre. Elle améliore la performance, elle modifie les durées observables des instructions, mais cela se limite à des questions de ''timings''. Le seul moyen de savoir si un processeur fait de l'exécution dans le désordre est de mesurer les latences/durées de chaque instruction. Mais aucun état observable au-delà des ''timings'' n'est modifié. Pas avec la désambiguïsation mémoire. ===La consistance mémoire=== Le fait que la désambiguïsation mémoire ait des effets observables ne pose aucun problème avec un seul processeur, ca elle est conçue pour. Par contre, les techniques de désambiguïsation mémoire peuvent poser des problèmes avec plusieurs processeurs. Il arrive que des programmes partagent une même portion de mémoire, et lisent/écrivent dedans. Avec plusieurs processeurs, chaque processeur effectue la désambiguïsation mémoire dans son coin sans se préoccuper des autres. Les opérations d'écriture peuvent être mises dans le désordre du point de vue des autres processeurs, et les lectures effectuées par les autres processeurs peuvent alors renvoyer de vielles données. Un exemple classique est celui de deux cœurs qui partagent le même cache ou la même mémoire, mais qui utilisent chacun une file d'écriture (''store buffer''). Imaginons que le premier cœur effectue une écriture, puis une lecture, à des adresses différentes. L'écriture est retardée grâce au tampon d'écriture, alors que la lecture lit directement le cache. Pour le premier processeur, l'écriture s'est réalisée avant la lecture, car pour lui, la fin de l'écriture signifie écrire dans le tampon d'écriture. Mais pour le second cœur, l'ordre s'est inversé : il voit la lecture dans le cache, puis l'écriture dans le cache. La raison est qu'il n'a pas connaissance du contenu du tampon d'écriture de l'autre cœur. Un autre exemple : les techniques de prédiction d'adresse et de valeur posent des problèmes avec les dépendances RAW. Elles permettent à une instruction mémoire de s'exécuter avant une autre, malgré la présence d'une dépendance RAW entre les deux. L'ordre entre les deux instructions change, alors que les autres processeurs ne devraient pas le voir. Et dans les faits, les processeurs qui incorporent ces techniques ont des modèles de consistance mémoire qui ne permettent pas ces optimisations en cas de dépendances RAW. Les deux techniques doivent idéalement être désactivées pour les instructions mémoire qui ont des dépendances RAW. Les programmeurs doivent tenir compte de ce genre de situations, dans des cas assez rares et liés à la programmation bas niveau. Pour cela, ils doivent savoir comment le processeur réorganise les accès mémoire. Concrètement, chaque processeur définit un '''modèle de consistance mémoire''' qui indique quelles optimisations sont activées et non. Il s'agit d'une sorte de contrat entre le logiciel et le matériel : les programmeurs savent comment le processeur va réorganiser les lectures et écritures et peuvent coder leurs programmes en fonction. L'implémentation du système de consistance mémoire dépend grandement de l'architecture, mais des modèles ont été standardisés afin de permettre aux programmeurs de savoir où placer les barrières mémoires. Il s'agit de vrais standards, formalisés, parfois mathématiquement, que des chercheurs étudient sur un plan mathématique et algorithmique. Le modèle préféré des programmeurs est la '''consistance séquentielle''', où les différents processeurs effectuent des accès mémoire dans l'ordre du programme et les accès mémoire simultanés sont interdits. La première contrainte interdit l'usage de mécanismes de désambiguïsation mémoire, la seconde interdit l'usage de caches non-bloquants. La consistance séquentielle a donc un cout en performance assez important, ce qui fait que les processeurs modernes n'utilisent pas la consistance séquentielle. Un modèle plus flexible est le '''''total store ordering''''', qui autorise la présence d'une file d'écriture et l'usage de caches non-bloquants pour les lectures (interdit d'avoir plusieurs écritures simultanées). C'est plus ou moins celui utilisé par les processeurs x86, comme on le verra plus bas. Il existe des modèles de consistance mémoire plus relâchés, appelés des '''modèles de consistance faible''', qui autorisent diverses optimisations de spéculation mémoire, la combinaison d'écriture (fusionner deux écritures à la même adresse en une seule), etc. Ils sont supportés sur les architectures ARM et POWER. ===Les barrières mémoire=== Le changement d'ordre des lectures et écritures peut poser occasionnellement des problèmes avec la programmation pour les architectures multi-processeur ou multicœurs. Il existe des morceaux de code qui ne marchent que si la consistance séquentielle est respectée et il faut faire en sorte qu'ils marchent sur des processeurs avec un modèle de consistance mémoire différent. Pour cela, les processeurs incorporent des instructions appelées '''barrières mémoires''' ou '''''Fences'''''. Elles forcent le processeur à terminer tous les accès mémoire qui précédent dans l'ordre du programme. Certains processeurs possèdent une barrière mémoire pour les lectures et une autre pour les écritures. D'autres processeurs ajoutent des barrières mémoires dédiées à des cas particuliers. Elles permettent de forcer les accès à des données partagées à dérouler correctement. [[File:Fences.png|centre|vignette|upright=2|Fences.]] Leur implémentation est assez simple : elles empêchent l'émission de toute nouvelle instruction mémoire, tant qu'une condition précise n'est pas réunie. Par exemple, la barrière mémoire pour les écritures attend que la file d'écriture soit vidée avant de démarrer le moindre accès mémoire. Un compilateur peut placer les barrières mémoires au bon endroit, avec un peu d'aide du programmeur. Certains langages de programmation permettent d'indiquer au compilateur qu'une donnée doit toujours être lue depuis la mémoire RAM, via le mot-clé volatile. C'est très utile pour préciser que cette donnée est potentiellement partagée par plusieurs processeurs ou manipulable par des périphériques. Les compilateurs peuvent placer des barrières mémoires lors des lectures ou écritures sur ces variables, mais ce n'est pas une obligation. Il arrive aussi que le programmeur doive manipuler explicitement des barrières mémoires. Utiliser l'assembleur est alors une possibilité, mais qui est rarement exploitée, pour des raisons de portabilité. Pour limiter la casse, certains systèmes d'exploitations ou compilateurs peuvent aussi fournir des barrières mémoires explicites, encapsulées dans des bibliothèques ou cachées dans certaines fonctions. ===La modèle de consistance des processeurs x86=== Après avoir vu la théorie, passons maintenant à la pratique. Dans cette partie, on va voir les modèles de consistances utilisés sur les processeurs x86, ceux qu'on retrouve dans les PC actuels. Le modèle de consistance des processeurs x86 a varié au cours de l'existence de l'architecture : un vulgaire 486DX n'a pas le même modèle de consistance qu'un Core 2 duo, par exemple. Ils ont évolués au cours du temps, avec l'arrivée de nouvelles optimisations. De plus, leur formalisation a été progressive, et s'est faite au fur et à mesure. En général, les modèles de consistance des processeurs x86 ont toujours étés assez restrictifs, si on les compare aux autres processeurs. Il s'agit de modèles de type ''total store ordering'' (TSO), au moins dans les grandes lignes. Ils permettent donc d'effectuer certaines lectures en avance, soit parce que les lectures se font à des adresses différentes, soit par utilisation de réacheminement écriture vers lecture. Les possibilités d'exécution en avance des lectures varient suivant le processeur, elles deviennent de plus en plus performantes avec le temps. Le premier modèle de consistance est apparu sur les premiers processeurs x86 et est resté en place sur tous les processeurs de marque Pentium. Les processeurs de l'époque n'incorporaient pas beaucoup d'optimisations, le budget en transistor n'était pas assez conséquent pour ça, la mémoire n'était pas assez lente. Le modèle TSO de l'époque n'autorisaient que peu de lectures anticipées. Une lecture ne peut être exécutée en avance que sous les conditions suivantes : * les écritures contournées se font dans la mémoire cache ; * la lecture doit se faire dans la mémoire RAM ; * les écritures se font à une adresse différente de la lecture ; * aucune transaction avec un périphérique ne doit être en cours. A partir du Pentium 4, les choses changent. Le Pentium 4 est en effet le premier processeur à implémenter des techniques permettant d’exécuter plusieurs processus en parallèle, dont l'Hyperthreading. En conséquence, le modèle de consistance a dû être assoupli pour éviter de perdre bêtement en performance. Il s'agit d'un vrai modèle de type TSO, la majeure partie des contraintes sur les lectures anticipées sont réduites au minimum. Il y a aussi des contraintes supplémentaires pour les instructions dites atomiques, ainsi que pour les instructions qui accèdent aux périphériques ou aux entrées-sorties. Une optimisation séparée du TSO est que les écritures en mémoire peuvent changer d'ordre dans un cas exceptionnel : les écritures effectuées par les instructions de copie mémoire comme REPMOVSD, REPSCACB, ainsi que les instructions SSE MOVNTI, MOVNTQ, MOVNTDQ, MOVNTPS, MOVNTPD. Les écritures effectuées dans ces instructions peuvent se faire dans un désordre complet (ou presque). Lors du passage au 64 bits, le modèle mémoire des processeurs x86 de l'époque a été formalisé dans un papier d'Intel appelé [https://www.cs.cmu.edu/~410-f10/doc/Intel_Reordering_318147.pdf Intel® 64 Architecture Memory Ordering White Paper], mis à jour en 2008 suite à quelques problèmes techniques. La formalisation du modèle a été d'une grande aide aux programmeurs, qui devaient se débrouiller avec des documentations qui ne formalisaient pas de modèle de consistance précis. Le document décrit un modèle de consistance mémoire portant le nom barbare de ''total lock order + causal consistency” (TLO+CC)'', qui admet plus d'optimisations que le modèle TSO. Mais la description était en réalité légèrement différente du modèle mémoire réellement implémenté sur les processeurs existants, qui utilisaient du TSO, sauf en de rares occasions. Les concepteurs de processeur font souvent cela, à savoir définir un modèle de consistance plus laxiste que réellement implémenté, pour des questions de comptabilité. Ainsi, si les futurs processeurs de la marque implémentent un modèle plus laxiste, les programmes déjà codés continuent de fonctionner. Le modèle décrit dans la documentation laisse de la marge pour le futur. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Le scoreboarding et l'algorithme de Tomasulo | prevText=Le scoreboarding et l'algorithme de Tomasulo | next=Le parallélisme mémoire | nextText=Le parallélisme mémoire }} </noinclude> fra67fnzel8y6fuczgowyao4lt39ntt Fonctionnement d'un ordinateur/L'exécution dans le désordre 0 65869 773586 773350 2026-09-29T17:13:46Z Mewtow 31375 773586 wikitext text/x-wiki Dans les chapitres précédents, nous avons parlé des techniques dites d''''émission dans l'ordre'''. L'idée est d’exécuter une nouvelle micro-opération à chaque cycle, dans des unités de calcul séparées. Les instructions sont émises consécutivement, mais les instructions s’exécutent en parallèle dans des unités de calcul séparées. Par contre, quand l'unité d'émission ne peut pas émettre une instruction, elle bloque tout le pipeline. Les instructions qui suivent sont elles aussi bloquées, elle doivent attendre leur tour, même si elles sont en capacité de s'exécuter. Les techniques d'exécution dans le désordre que nous allons voir dans ce chapitre corrigent ce point précis. Elles sont dites à '''émission dans le désordre'''. Elles se distinguent des précédentes sur un point précis : quand l'unité d'émission bloque l'émission d'une instruction, les instructions suivantes peuvent poursuivre. L'émission des instructions peut donc se faire dans le désordre, dans le sens où une instruction peut être émise alors qu'une instruction précédente ne l'est pas encore. L'avantage de l'émission dans le désordre est qu'une instruction s'exécute dès que ses opérandes sont disponibles. Par disponible, on veut dire présent soit dans le réseau de contournement, soit dans les registres. Le processeur détecte automatiquement quand les opérandes d'une instruction sont sont disponibles, et il l’exécute à ce moment là. Dès qu'une instruction a ses opérandes disponibles, elle est émise et exécutée. C'est là la seule contrainte : les dépendances WAR, WAW et autres sont gérées par un ROB ou toute autre technique d'exception précise, seules les dépendances RAW limitent l'exécution. Mais avant de poursuivre, quelques point niveaux terminologie : * L'émission dans le désordre est un terme parlant et assez précis. Malheureusement, la terminologie la plus utilisée par d''''exécution dans le désordre'''. Et nous utiliserons ce terme dans la suite du cours, histoire de ne pas trop dévier de la nomenclature habituelle. * Nous utiliserons parfois l'abréviation OOO pour parler d'exécution dans le désordre. L'abréviation est celle de ''Out Of Order Excution''. * Nous utiliserons aussi l'abréviation ''µop'' pour parler de micro-opération, ''µops'' au pluriels pour parler de plusieurs micro-opérations, ou des micro-opérations en général. L'exécution dans le désordre ne gére en effet que des µops, elle se situe après l'étape de décodage. Mais avant de poursuivre, précisons une chose importante : l'exécution dans le désordre traite les accès mémoire à part. La majorité des processeurs OOO assez anciens exécutent les accès mémoire dans l'ordre, seules les µops entières/flottantes/branchements sont exécutées dans le désordre. Les processeurs datant d'après les années 2010 sont capable d'exécuter les accès mémoire dans le désordre, mais l'implémentation en question est assez particulière. Un chapitre entier sera dédié à l'exécution dans le désordre des µops mémoire. Nous allons volontairement mettre de côté la gestion des accès mémoire dans ce chapitre. ==Les fenêtres d’instruction : généralités== [[File:File de micro-opération.png|vignette|upright=1|File de micro-opérations]] Pour décrire comment est implémentée l'émission dans le désordre, il faut commencer par parler des processeurs sans. Les processeurs sans exécution dans le désordre ont une unité d'émission qui bloque tout le pipeline dès qu'une µop ne peut pas être émise. Pour limiter l'impact de ce blocage, quelques rares processeurs incorporent une '''file de micro-opération''', une mémoire FIFO qui met en attente les µops. Vu que c'est une mémoire FIFO, les µops sont émises dans l'ordre, à savoir l'ordre d'ajout, dans l'ordre de décodage. Le schéma ci-dessous illustre une telle file d'attente couplée à un ''scoreboard''. Sur le principe, l'exécution dans le désordre améliore la file de µops sur un point : ce n'est plus une mémoire FIFO. De telles files de micro-opération permettent d'émettre des instructions dans le désordre, ce qui corrige le problème mentionné plus haut avec le ''scoreboard''. Si une instruction bloque le pipeline, les instructions suivantes peuvent être émises. Il existe dans les grandes lignes 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! Emission dans l'ordre ! Emission dans le désordre |- ! Une file de micro-opération | ''Scoreboard'' | Fenêtre d'instruction centralisée |- ! Plusieurs files de micro-opération | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | Fenêtre d'instruction décentralisée |} ===L'usage de plusieurs files d'instruction=== La première méthode évoluée d'OOO utilise plusieurs files de micro-opération. L'idée est qu'une fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement une file de micro-opération pour les opérations entières, une autre pour les opérations flottantes, une autre pour les accès mémoire. D'autres processeurs utilisent une file pour les accès mémoire et une autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. La présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que la technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si une dépendance bloque une FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans une autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer la disponibilité des registres. Quand un registre est lu ou écrit par une instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. La logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : une pour les instructions d'accès mémoire et une autre pour les autres instructions. Si jamais une instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de la lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'une est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est la file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. ===La fenêtre d'instruction centralisée=== Les processeurs OOO modernes utilisent une file d'attente modifiée, où les instructions sont insérées dans l'ordre, mais peuvent sortir dans le désordre, être émises dans le désordre. La file d'attente en question est appelée la '''fenêtre d'instruction'''. Les instructions décodées sont accumulées dans la fenêtre d'instruction, où elles attendent que leurs opérandes soient disponibles. La fenêtre d'instruction sert donc de file d'attente. A chaque cycle, l'unité d'émission consulte la fenêtre d'instruction pour voir quelles instructions peuvent s'exécuter, quelles instructions ont leur opérandes de disponibles. Elle choisit une instruction exécutable et l'envoie aux ALU. La fenêtre d'instruction doit spécialement être conçue pour, c'est une sorte de mémoire associative très complexe. [[File:OOO Issue.png|centre|vignette|upright=2.5|Exécution dans le désordre avec une fenêtre d'instruction]] Le cas le plus simple n'utilise qu'une seule fenêtre d'instruction. Avec elle, l'unité d'émission, détecte les dépendances et répartit les instructions sur les unités de calcul. Les instructions décodées sont ajoutées en parallèle dans la fenêtre d'instruction, et le ROB. La raison est que les instructions quittent la fenêtre d'instruction dans le désordre, l'ordre des instructions est perdu après l'unité de décodage/renommage de registre. Aussi, pour remplir le ROB, la seule opportunité est en sortie de l'unité de décodage. Dans le cas où une instruction est décodée en plusieurs micro-opérations, elles sont toutes insérées en même temps dans la fenêtre d'instruction et le ROB. [[File:Fenêtre d'instruction.png|centre|vignette|upright=2|Fenêtre d'instruction.]] Les micro-opérations mémoire sont à part des autres, pour diverses raisons. Une de ces raisons est que les dépendances de données sont classées en deux types : les dépendances de registre et les dépendances d'adresse. Et les deux sont fondamentalement différentes. Autant on peut détecter les dépendances de registre lors de l'émission, autant c'est plus compliqué avec les dépendances d'adresse. De plus, rappelons que si les lectures peuvent s'exécuter dans le désordre, les écritures doivent s'exécuter dans l'ordre, ou du moins en donner l'illusion. Pour cela, le processeur remet les écritures dans l'ordre avec une sorte de mini-ROB intégré à l'unité mémoire, appelée la file d'écriture. Elle complémente le ROB, qui lui ne gére que les écritures dans les registres, mais les deux collaborent. Les processeurs grand public anciens n'autorisaient pas d'exécution dans le désordre des accès mémoire. Pour cela, l'unité mémoire est précédée par une file de micro-opérations, pour forcer l'exécution dans l'ordre des accès mémoire. Les processeurs modernes ajoutent des techniques d'exécution dans le désordre des accès mémoire, mais nous les verrons dans un chapitre dédié. Dans les deux cas, les micro-opérations mémoire doivent être envoyées à l'unité mémoire dans l'ordre du programme, dans l'ordre de décodage. Dans ce chapitre, on suppose que l'unité mémoire est précédée d'une file de micro-opération mémoire dédiée, rien que pour elle. Elle est à part du reste. [[File:Processeur avec émission dans l'ordre des accès mémoire.png|centre|vignette|upright=2|Processeur avec émission dans l'ordre des accès mémoire]] ===Les fenêtres d'instruction décentralisées=== Une autre solution utilise plusieurs fenêtres d'instruction. Pour faire la différence avec l'usage d'une fenêtre d'instruction unique, nous allons parler de fenêtre d'instruction centralisée s'il n'y en a qu'une dans le processeur, de '''fenêtre d'instruction décentralisée''' s'il y en a plusieurs. Dans le cas général, chaque fenêtre d'instruction est associée à un type précis d'opération/instruction. La tendance moderne est d'utiliser une fenêtre d'instruction pour les instructions de calcul entières, une autre pour les flottantes. Il s'agit d'un choix simple et efficace, mais quelques processeurs font autrement, pour répondre à des contraintes très diverses. L'usage de fenêtres décentralisées simplifie la répartition des instructions sur les différentes unités de calcul. Par exemple, utiliser des fenêtres séparées pour les ALU et les FPU facilite la répartition des instructions de calcul sur les ALU. Une fenêtre centralisée demande de faire la différence entre instruction entière/flottante, puis de choisir sur quelle unité de calcul entière/flottante utiliser. Une fenêtre décentralisée fait les deux choix séparément : d'abord on envoie l'instruction dans la bonne fenêtre suivant si c'est une instruction flottante ou entière, et ensuite on gère la disponibilité des ALUs/opérandes. Et on peut adapter la même idée en séparant les unités d'accès mémoire des ALU entières, etc. Par contre, un défaut est que certaines fenêtres d'instruction peuvent être sous-utilisées. Par exemple, la station de réservation flottante est inutilisée si le programme n'exécute pas d'opérations flottantes. Ou encore, les fenêtres pour les accès mémoire peuvent être sous-utilisées, si le programme effectue peu d'accès mémoire relativement aux autres instructions. En fait, tout dépend de comment sont calibrées les fenêtres d'instruction et de la répartition des instructions dans le programme entre opérations entières, flottantes, mémoire. Par exemple, si un programma de deux fenêtres d'instructions identiques, une pour les calculs entiers et une autre pour les calculs flottants, elles ne seront utilisées à la perfection que si la moitié des instructions du programme fait des calculs flottants et l'autre des calculs entiers. Toute déviation par rapport à cette répartition idéale risque de laisser des entrées vides dans une fenêtre d’instruction. Un point important est que l'émission est découpée en deux étages avec des fenêtres d'instruction décentralisées. La première étape envoie l'instruction décodée vers la fenêtre d'instruction adéquate, la seconde gère l'émission proprement dit. La première est l'étage de ''dispatch'' qui envoie l'instruction dans la fenêtre d’instruction adéquate, selon que c'est une instruction flottante, entière, autre. La seconde est l'étage de ''scheduling'', qui gère la disponibilité des opérandes et des unités de calcul. En clair, on trie les instructions suivant leur type, suivant le type d'unité de calcul adéquate, puis on l'émet proprement dit. Faire ainsi a plusieurs avantages, avec cependant peu d'inconvénients. Lors de l'étape de ''dispatch'', l'instruction émise est ajoutée au tampon de réordonnancement, s'il existe. Sans cela, impossible de conserver l'ordre des instructions. Les instructions sont émises dans l'ordre au niveau de l'unité de ''dispatch'', pas au niveau de l'étage de ''scheduling''. Aussi, pour remplir le ROB, cela doit se faire au dernier moment où les instructions sont émises dans l'ordre, soit en sortie de l'unité de ''dispatch''. De plus, les micro-opérations mémoire sont traitées à part des autres, elles sont envoyées directement à l'unité mémoire. La gestion des calculs d'adresse est quelque peu complexe, mais ils peuvent être fait soit dans l'unité mémoire, soit dans les ALU entières, peu importe. Il y a aussi un système de contournement complexe entre ALU/FPU et unité mémoire, qui n'est pas représenté dans le schéma ci-dessous. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Il faut noter que quelques processeurs utilisent des méthodes intermédiaires entre les trois solutions précédentes. Par exemple, les processeurs AMD Zen utilisent une fenêtre d'instruction décentralisée un peu particulière. Les unités de calcul entières disposent d'une fenêtre d'instruction rien que pour elles, sur ce processeur. Les instructions flottantes sont quant à elles alimentées par une file de micro-opération, pas une fenêtre d'instruction ! La raison à ce choix est un compromis entre performance et cout en circuit. L'exécution dans le désordre est peu efficace sur les instructions flottantes, car les CPU n'ont que peu d'ALU flottantes séparées. Vu le cout en circuits d'une fenêtre d'instruction, les concepteurs du processeur ont préféré utiliser une file de micro-opération pour les opérations flottantes. ===Avantages et inconvénients de chaque implémentation=== Un processeur contient soit une fenêtre d'instruction unique, soit plusieurs fenêtres d'instruction séparées. Typiquement, les fenêtres d’instruction séparées sont spécialisées, dans le sens où on a une fenêtre pour les instructions flottantes, une autre pour les instructions entières, une autre pour les accès mémoire, etc. Pour résumer, on a le choix entre une grosse fenêtre généraliste et plusieurs fenêtres spécialisées, sauf que la fenêtre centralisée est lente et complexe, contrairement aux fenêtres spécialisées. Les deux méthodes ont des inconvénients et des avantages différents. Dans les grandes lignes, l'avantage des fenêtres décentralisées est qu'elles sont plus petites qu'une grosse fenêtre d'instruction. Cela simplifie la gestion du contournement et de la répartition des instructions sur les unités de calcul, comme on le verra dans quelques paragraphes. Elles sont donc moins complexes et plus rapides. L'autre avantage, c'est qu'il est possible de démarrer l'exécution de plusieurs instructions simultanément : une instruction par fenêtre décentralisée, contre une par fenêtre d'instruction. Mais les fenêtres décentralisées sont souvent sous-utilisées, partiellement remplies, contrairement aux fenêtres d'instruction. Il arrive qu'une fenêtre d'instruction soit remplie, alors que les autres sont vides. Par exemple, prenons un processeur avec une fenêtre d'instruction reliée à la FPU, et une autre reliée aux autres ALUs. Si le processeur n'exécute que des opérations flottantes, la fenêtre reliée à la FPU sera pleine, alors que l'autre sera vide. L'exécution des instructions dans le désordre est alors limitée par la petite taille de la fenêtre, qui ne peut plus accepter de nouvelle instruction flottante. Avec une fenêtre unique, on n'aurait pas eu ce problème : on aurait eu une énorme fenêtre d'instruction remplie d'instruction flottante, au lieu d'une petite fenêtre spécialisée. Il est maintenant temps de voir en quoi sont faites les fenêtres d’instruction, qu'elles soient centralisées ou décentralisées. Nous allons aussi voir quelle est la logique d'émission associée. ==L'implémentation d'une fenêtre d'instruction : généralités== Une fenêtre d'instruction est une mémoire qui mémorise des micro-opérations. Elle est cependant plus complexe qu'une mémoire RAM ou qu'une FIFO et ressemble un petit peu à une mémoire cache. Elle dispose d'un port d'écriture et d'un port de lecture, au minimum. Le port d'écriture permet à l'unité de décodage d'insérer une micro-opération dedans, d'ajouter la micro-opération qui vient d'être décodée. Si une instruction machine est décodée en plusieurs micro-opération, deux possibilités. La première est de les insérer un par un, ce qui fait qu'on peut se contenter d'un seul port d'écriture. L'autre possibilité est de les ajouter en même temps, ce qui demande plusieurs ports d'écriture. Le port de lecture sert à émettre une instruction. On part du principe que la fenêtre d'instruction ne peut émettre qu'une seule instruction à la fois, car les processeurs que nous avons vu précédemment sont de ce type. Mais nous verrons dans quelques chapitre qu'il existe des processeurs dits superscalaires, qui sont capables d'émettre plusieurs instructions par cycle. Dans ce cas, la fenêtre d'instruction a un seul port de lecture. Un processeur superscalaire, quant à lui, doit avoir un port de lecture par unité de calcul, ce qui fait beaucoup plus. ===Les entrées d'une fenêtre d’instruction=== Les fenêtres d'instruction sont composées d''''entrées''', des mots mémoire qui stockent une instruction. Une instruction réserve une entrée après son décodage et la libère dès qu'elle est envoyée aux unités de calcul. Une entrée contient l'opcode (les signaux de commande à envoyer à l'ALU), le registre de destination du résultat, les registres de chaque opérande, et éventuellement des signaux de commande en plus. De plus, chaque opérande est couplée à un bit de disponibilité, qui indique si elle est disponible. Quand un opérande est écrit dans les registres, le bit de présence correspondant est mis à jour. Enfin, chaque entrée possède un bit ''empty'' qui indique si elle est vide, cette information étant utile pour réserver des entrées. [[File:Entrée d'une station de réservation - sans les tags.png|centre|vignette|upright=3|Entrée d'une fenêtre d'instruction]] Nous verrons dans quelques chapitres que certaines fenêtres d'instruction sont capables de mémoriser les opérandes des instructions. De telles fenêtres d'instruction seront appelées, dans ce cours, des '''stations de réservation'''. Les entrées des stations de réservation sont assez semblables à celle des fenêtres d'instruction, à un détail près : les opérandes de l'instruction sont enregistrées directement dans des champs séparés. Il y a deux champs, un par opérande, pour stocker l'opérande elle-même, lue depuis les registres ou obtenue via le réseau de contournement. Notons que les champs pour les opérandes viennent en plus des champs pour les noms de registres, encore que les deux peuvent être fusionnés si on veut optimiser le tout. [[File:Entrée d'une station de réservation.png|centre|vignette|upright=3|Entrée d'une station de réservation.]] Précisons que la terminologie n'est pas très fiable. Les termes "fenêtre d'instruction" et "station de réservation" ne regroupent pas du tout la même chose d'un papier de recherche à l'autre, d'un bouquin à l'autre, d'un chercheur à l'autre, d'un ingénieur à l'autre, d'un professeur à l'autre. Le terme initial vient pourtant de l'article original sur l'algorithme de Tomasulo, où il désignait une fenêtre d'instruction associée à une unité de calcul précise. Mais le terme a ensuite été réutilisé, ce qui fait que certains processeurs avec plusieurs unités de calcul sont décrit comme ayant une unique station de réservation. En bref : c'est le bazar ! Mais nous en reparlerons dans le chapitre sur le renommage de registres, car c'est la place idéale pour les aborder. Toujours est-il que j'ai fait le choix de confondre les concepts de fenêtre d'instruction et de station de réservation avec les concepts de '''lecture avant émission''' et de '''lecture après émission'''. La différence entre les deux est que les registres sont lus après émission avec une fenêtre d'instruction, avant avec des stations de réservation. Dans le cas "avant émission", les opérandes sont mémorisées dans la station de réservation. Et cette différence a une influence sur le pipeline du processeur, le banc de registres et tout ce qui s'en suit. Un désavantage de la lecture avant émission est qu'il faut stocker les opérandes après lecture, ici dans les stations de réservation. Mais un avantage est que le banc de registre a besoin de moins de ports de lecture, car une bonne partie des opérandes sont fournies par le système de contournement. Nous verrons cela dans le détail dans le chapitre sur les processeurs superscalaires. Il a été proposé de fusionner le tampon de ré-ordonnancement avec la fenêtre d'instruction dans une structure unique. La méthode a notamment été utilisée sur les processeurs d'architecture K6 d'AMD. Le tout donnait une structure appelée le '''DRIS''' (''deferred scheduling register renaming instruction shelf''). La différence avec une fenêtre d’instruction normale est que les entrées sont libérée non pas quand l'instruction est exécutée/émise, mais quand elle termine son exécution et quitte le ROB. La fenêtre d'instruction doit alors incorporer des bits pour savoir si telle entrée a émis sont instruction ou non. ===La logique d'éveil et de sélection=== Dans le cas qui va suivre, on suppose que le processeur ne peut émettre qu'une instruction à la fois. Chaque cycle, une instruction est sélectionnée et est envoyée dans le chemin de données, soit à une ALU, soit à une unité d'accès mémoire. La sélection d'une instruction est effectuée par l'unité d'émission, qui est aussi appelée le '''''scheduler'''''. Elle gère la disponibilité des opérandes et la disponibilité des unités de calcul adéquate. Le choix de l'instruction émise doit être le plus pertinent possible, pour des raisons de performances. Pour le premier point, l'unité d'émission détermine quelles instructions sont candidates pour l'émission. Les ''instructions candidates'' sont celles dont tous les opérandes sont prêts. Le processeur contient un circuit qui détecte les instructions candidates : la '''logique d’éveil''' (''wake-up logic''). Une fois que la logique d'éveil a fait son travail, une instruction est choisie pour s’exécuter en fonction de la disponibilité des unités de calcul adéquates. Ce rôle est dévolu à un circuit qu'on appelle la '''logique de sélection''', ou ''select logic''. [[File:Fonctionnement complet de la logique d’émission.jpg|centre|vignette|upright=1.5|Fonctionnement complet de la logique d’émission.]] La logique de sélection doit gérer le fait que les unités de calcul du processeur ne sont pas toutes identiques. Déjà, un processeur a généralement des unités séparées pour les instructions entières et flottantes, des unités spécialisées dans les accès mémoire, parfois des unités spécialisées pour les branchements. Une instruction doit être attribuée à la bonne unité de calcul, on ne doit pas envoyer une instruction entière dans une unité de calcul flottante. De plus, parmi les unités de calcul entières, toutes ne sont pas identiques. Par exemple, il est fréquent d'avoir plusieurs unités de calcul spécialisées dans les opérations simples (additions, soustractions, opérations logiques) avec une unité pour les multiplications/divisions séparées, parfois une unité spécialisée pour les décalages/rotations, etc. Là encore, allouer la bonne instruction à la bonne ALU est complexe. Plus les unités de calcul sont hétérogènes, plus la logique de sélection est compliquée. Les logiques d'éveil comme de sélection sont assez complexes. Comme on le verra plus bas, la logique de sélection la plus simple, qui gère une seule unité de calcul, est basée sur un encodeur à priorité couplé à d'autres circuits. Et pour gérer plusieurs ALUs, il faut mettre des encodeurs en cascade. Le résultat est que même en prenant une logique de sélection simple, elle sera assez lente et gourmande en circuits. Aussi, la logique de sélection met souvent un cycle d'horloge entier pour faire son travail, elle a son propre étage de pipeline attribué. La logique d'éveil est dans le même cas, ce qui fait qu'émettre une micro-opération demande deux cycles d'horloge. Le défaut est que cela rajoute des cycles d'horloges entre la fenêtre d'instruction et l'ALU, ce qui complique la gestion du pipeline. Ces cycles de retard sont à prendre en compte au moment d'émettre les instructions, les ''scheduler'' doit en tenir compte pour des performances optimales. Sans tenir compte de ces cycles de retard, les instructions arrivent en retard de quelques cycles à l'ALU, cycles de retard durant lesquels l'ALU n'a pas fait de calcul et a été sous-utilisée, sans compter que le système de contournement n'est pas utilisé au mieux. Et le problème est encore plus important sur les processeur avec des stations de réservation, qui utilisent la "lecture après émission" : cela rajoute un cycle d'horloge en plus, un temps de retard en plus. ===La logique d'éveil : l'émission anticipée=== La logique d'éveil doit tenir compte du fait qu'il y a plusieurs étages entre l'émission et l'exécution sur une unité de calcul. Par exemple, un processeur a souvent entre un et à cinq étages entre la file d'attente et les unités de calcul. Il faut lire les registres, gérer le contournement, et cela peut prendre quelques cycles d'horloge. Sur le Pentium 4, on trouve 6 étages entre la fenêtre d’instruction et l'entrée de l'ALU. Si les micro-opérations sont émises quand les opérandes sont disponibles, il y aura un délai de quelques cycles avant qu'elles atteignent l'ALU. Alors qu'idéalement, on souhaiterait que la micro-opération atteigne l'ALU dès que ses opérandes sont disponibles, pour profiter des techniques de contournement. Pour cela, la logique d'éveil émet les instructions quelques cycles en avance pour qu'elles arrivent au bon moment. Il s'agit d'une technique d''''émission anticipée''', dont nous avions parlé dans le chapitre sur le contournement. : Il faut noter que le problème se pose plus avec des fenêtres d'instruction qu'avec des stations de réservation. Les premières ont un étage en plus entre émission et ALU, vu qu'il faut lire des registres après l'émission. L'émission anticipée demande d'émettre un signal d'éveil en avance de quelques cycles, pile au bon moment. Par exemples, si on a deux étages entre l'ALU et l'unité d'émission, le signal de réveil sera généré deux cycles avant que le résultat soit effectivement calculé. L'implémentation varie, mais deux solutions sont possibles. La première est de générer le signal d'éveil dans l'ALU, ce qui n'a de sens que pour les opérations comme les multiplications ou les divisions, qui prennent plusieurs cycles. Une autre technique génère le signal de réveil dans une structure centralisée, spécialisée dans la génération des signaux d'éveil. L'unité de composée d'un registre à décalage par registre. Imaginons qu'une instruction est émise, que cette instruction mette N cycles à s'exécuter, et qu'elle écrive dans un registre de destination. L'unité sélectionne alors le registre à décalage associé au registre de destination, et met le bit numéro N à 1. Le registre décalé d'un cran à chaque cycle. Quand le bit sortant est un 1, alors le signal de validité pour l'opérande est généré. L'émission anticipée marche bien si l'instruction a une durée fixe, connue à l'avance. Et autant c'est le cas pour les instructions arithmétiques et logiques, autant ce n'est pas le cas pour les accès mémoire. Les accès mémoire ont une latence variable : quelques cycles pour un succès de cache, plusieurs dizaines de cycles pour un défaut de cache L1, pas loin de la centaine pour un défaut de cache L2, etc. Et cela pose des problèmes pour l'émission anticipée. L'émission en avance pour les accès mémoire est purement spéculative : le processeur émet des instructions en supposant que la lecture entrainera un succès de cache, quitte à annuler l'instruction en cas de défaut de cache. Mais faire ainsi demande non seulement d'annuler les instructions émises en avance, mais aussi de ne pas retirer les instructions émises en avance de la fenêtre d'instruction. Elles sont émises, mais une copie de sauvegarde est conservée dans la fenêtre d'instruction. Si le processeur détecte un défaut de cache, il peut alors ré-exécuter l'instruction. S'il détecte un succès de cache, les instructions lecture-dépendante sont retirées de la fenêtre d'instruction, la copie de sauvegarde est devenue inutile et est donc jetée. ===La logique de sélection : âge ou position ?=== La logique de sélection est primordiale pour de bonnes performances. Il existe deux méthodes principales pour sélectionner l'instruction à exécuter. La première est la plus simple : elle se base sur lé numéro de l'entrée. En effet, une fenêtre d'instruction est avant tout une sorte de mémoire, un mix entre mémoire associative, mémoire RAM, et FIFO. Et chaque entrée a un numéro, une adresse mémoire. Nous parlerons de numéro dans ce qui suit, car ce sera plus simple, le terme d'adresse mémoire étant peut-être un peu exagéré dans le contexte des fenêtres d'instruction. Toujours est-il que la fenêtre d'instruction est adressable dans le sens où on peut lui envoyer le numéro de l'entrée voulue, et la fenêtre d’instruction renvoie le contenu de l'entrée sur son port de lecture. Et c'est ce que fait la logique de sélection : elle génère le numéro de l'entrée à lire. Le numéro est alors envoyé sur l'entrée d'adresse de la fenêtre d’instruction, et elle fournit la micro-opération associée sur son port de lecture, son '''port d'émission'''. La première méthode de sélection, donc. Elle est basée sur sur le numéro de l'entrée. Si plusieurs entrées sont éveillées, la logique de sélection prend celle avec le plus petit numéro. Elle porte le nom de '''sélection par position''', sous-entendu position dans la fenêtre d'instruction. Vous l'avez peut-être deviné, mais la logique de sélection est alors un encodeur à priorité. Le circuit de sélection ne se résume donc pas seulement à un encodeur à priorité, mais c'est le circuit central. L'avantage d'une telle méthode de sélection est qu'elle est simple à implémenter : un encodeur à priorité est un circuit connu, facile à implémenter. Mais on remarque un défaut : un encodeur est un circuit assez rapide, mais qui utilise beaucoup de transistors, beaucoup de portes logiques, surtout si on veut qu'il soit rapide. Ce qui explique que la logique de sélection ait son propre étage de pipeline rien que pour elle. La seconde méthode s'appelle la '''sélection par âge''', au nom assez transparent. L'idée est de privilégier l'émission de l'instruction la plus ancienne. Elle demande que la fenêtre d'instruction trie les micro-opérations par ordre d'insertion dans la fenêtre d'instruction, ce qui en fait une pseudo-FIFO. Le tri est partiel, car les instructions peuvent sortir de la fenêtre d’instruction à tout moment. Compacter la fenêtre d'instruction, à savoir regrouper toutes les entrées valides est une idée, mais elle est compliquée à implémenter. Aussi, elles préfèrent encoder des informations sur l'ordre d'émission dans chaque entrée. L'encodeur à priorité doit alors travailler non pas sur des nombres entiers liés à l'ordre d'insertion dans la pseudo-FIFO. Elle est encore plus gourmande en circuits que la méthode précédente. Les processeurs haute performance utilisent souvent des méthodes hybrides. Par exemple, les processeurs AMD de microarchitecture Bulldozer utilisaient une méthode intermédiaire. Ils utilisaient une fenêtre d'instruction couplée à un encodeur à priorité pour la sélection par position, mais complémentaient le tout avec une unité qui mémorisait l'instruction la plus ancienne dans la fenêtre d’instruction. Le mécanisme de sélection par âge était utilisé en priorité. Mais si l'instruction la plus ancienne n'était pas prête, le processeur basculait sur le mécanisme de sélection par position. ===La compaction des fenêtres d'instruction=== À chaque cycle, les instructions décodées sont ajoutées dans la fenêtre d'instruction, dans des entrées vides. Vu que les instructions quittent celle-ci dans le désordre, ces vides sont dispersés dans la fenêtre d'instruction, ce qui pose problème pour déterminer où placer les nouvelles instructions. La solution la plus triviale consiste à conserver une liste des vides, mise à jour à chaque insertion ou émission d'instruction. Une autre solution consiste à éliminer les vides en compactant la fenêtre d'instruction à chaque cycle d'horloge. Des circuits se chargent de détecter les vides et de regrouper les instructions en un unique bloc. Il faut signaler que certaines processeurs arrivent à se passer de cette étape de compactage, mais au prix de fenêtres d'instruction nettement plus complexes. Autre problème : quand il faut choisir quelle instruction émettre, il y a toujours plusieurs candidats. Si on choisit mal, des instructions restent en attente trop longtemps parce que d'autres instructions plus jeunes leur passent devant. Pour éviter cela, les instructions les plus vielles, les plus anciennes, sont prioritaires. Pour cela, on peut utiliser une FIFO un peu spéciale pour la fenêtre d'instruction. Si les ajouts d'instruction se font dans l'ordre, les instructions ne quittent pas forcément la fenêtre d'instruction dans l'ordre imposé par une FIFO : les instructions restent triées dans leur ordre d'ajout, même s'il y a des vides entre elles. Dans ces condition, il est préférable que le compactage conserve l'ordre FIFO des instructions. Dans ces conditions, l'instruction la plus ancienne est celle qui est située à l'adresse la plus faible : le circuit de sélection peut donc être fabriqué avec des encodeurs, et est relativement simple. ==Les fenêtres d'instruction basées sur une matrice de dépendances== L'implémentation la plus simple étend le fonctionnement d'un pipeline dynamique usuel. Rappelez-vous le chapitre sur les pipeline dynamiques. Nous avions vu que de tels pipelines émettaient une instruction par cycle, quitte à émettre des bulles de pipeline en cas de dépendance bloquante. Et il est possible d'améliorer leur unité d'émission pour qu'elle soit compatible avec l'exécution dans le désordre. ===Rappels sur le registre de réservation/disponibilité=== L'émission d'une instruction est gouvernée par un ''registre de réservation'' qui indique quels registres sont réservés par une instruction, et ceux qui sont libres. Un registre réservé est un registre qui sera écrit par une instruction en cours d'exécution, mais qui n'a pas encore écrit son résultat. Les instructions candidates doivent avoir leurs opérandes dans des registres libres. Sinon, c'est signe que leurs opérandes sont réservées en écriture, donc pas encore écrites, donc pas disponibles. Si une instruction candidate veut lire ce registre, c'est signe qu'il y a une dépendance RAW : elle veut lire un registre réservé, qui est destiné à être écrit par une instruction en vol. Si elle veut écrire, c'est signe qu'elle veut écrire dans un registre où une autre instruction veut écrire : c'est une dépendance WAW. Dans les deux cas, l'instruction n'est pas émise. Le registre de réservation encode les registres réservés comme suit : chaque bit est associé à un registre. Le bit numéro 0 est associé au registre numéro 0, le bit numéro 1 au registre numéro 1, etc. Là, En clair, les numéros de registres réservés sont encodés en représentation non pas binaire, mais en représentation ''one-hot'' (vue au premier chapitre). {|class="wikitable" |+ Registre de réservation |- ! Registre 7 !! Registre 6 !! Registre 5 !! Registre 4 !! Registre 3 !! Registre 2 !! Registre 1 !! Registre 0 |- | 0 || 0 || 1 || 0 || 0 || 1 || 0 || 0 |} Avant d'émettre une instruction, l'unité d'émission extrait les registres opérande/destination et les convertis dans la même représentation que le registre de réservation, à savoir en représentation ''one-hot''. Le circuit de traduction binaire vers ''one-hot'' est, pour rappel, un simple décodeur. Puis, on fait un OU logique entre les sorties des décodeurs. Le résultat est un masque qui indique quels registres sont lus par l'instruction, encodé en représentation ''one-hot''. Appelons-le le '''masque d'opérandes'''. Le masque est alors comparé au registre de réservation pour vérifier si l'instruction peut être émise. [[File:Unité d'émission simple, dans l'ordre.png|centre|vignette|upright=2|Unité d'émission simple, dans l'ordre]] Si l'émission est autorisée, le registres de réservation est là aussi mis à jour. Le registre de réservation est aussi mis à jour dès qu'une instruction enregistre son résultat dans les registres, ou alors dès qu'il est disponible pour le contournement. Le bit associé au registre repasse alors à 0 (ou à 1). Sans contournement, la mise à jour se fait alors à la toute fin de l'instruction, quand elle se termine, lors de la dernière étape d'enregistrement, à la fin de son pipeline. Avec, elle se fait quand l'instruction quitte l'unité de calcul. ===L'extension à l'exécution dans le désordre : l'éveil par matrice de bits=== La différence entre un pipeline dynamique et l'exécution dans le désordre est que l'on passe d'une instruction à émettre à plusieurs. Plusieurs instructions sont mises en attente dans une fenêtre d’instruction, et y attendent leur tour. L'idée est alors d'envoyer le registre de disponibilité à toutes les entrées, à toutes les instructions en attente. Ainsi, on sait quelles sont les instructions qui peuvent s'exécuter et celles qui ne le peuvent pas. L'implémentation est assez simple, elle ressemble beaucoup à l'implémentation d'un pipeline dynamique simple, si ce n'est que des circuits sont dupliqués. L'implémentation utilise des fenêtres d'instruction légèrement différentes de celles introduites plus haut. Elles n'utilisent notamment pas de bits de disponibilité, mais autre chose. Lorsqu'une instruction est ajoutée à la fenêtre d'instruction, le masque de disponibilité des opérandes est stocké dans la fenêtre d'instruction. A chaque cycle, le registre de disponibilité est envoyée à toutes les entrées, et est comparé avec tous les masques de disponibilité des opérandes. Si une comparaison renvoie un 1, alors l'instruction de l'entrée est une instruction candidate à l'émission. [[File:Unité d'émission dans le désordre basée sur un registre de disponibilité.png|centre|vignette|upright=2.5|Unité d'émission dans le désordre basée sur un registre de disponibilité]] L'ensemble est implémenté avec l'aide d'une '''matrice de bits''', où chaque ligne correspond à une entrée et chaque colonne à un registre. À chaque croisement entre une ligne et une colonne, on trouve un bit. Si le bit de la ligne n et de la colonne m est à 1, cela veut dire : l'instruction dans l'entrée n a besoin de lire le registre m. S’il est à 0, alors cela veut dire que l'instruction stockée dans la ligne n n'a pas besoin de la donnée dans le registre m. [[File:Planificateur à matrice de bits.jpg|centre|vignette|upright=2|Planificateur à matrice de bits.]] Lorsqu'une instruction réserve une entrée, elle initialise la ligne en fonction des registres qu'elle souhaite lire. Pour vérifier si une instruction a ses opérandes prêts, le processeur compare le registre de disponibilité à la ligne associée à l'instruction/entrée. A chaque intersection ligne-colonne, se trouve un comparateur de 1 bit, qui détecte si le registre est demandé et disponible. Les résultats de cette porte sont ensuite envoyés à une porte ET, qui fait le gros du travail. [[File:Logique de détection de la disponibilité d'une instruction.jpg|centre|vignette|upright=2|Logique de détection de la disponibilité d'une instruction.]] ==Les fenêtres d'instruction basées sur une mémoire associative== Les processeurs modernes utilisent une mémoire associative pour la fenêtre d'instruction. Les mémoires associatives ont été abordées il y a quelques chapitres, mais faisons quelques rappels. Les mémoires associatives servent à accélérer la recherche de données dans un ensemble. Or, une fenêtre d'instruction vérifie régulièrement si chaque entrée est prête. Il s'agit d'un processus de recherche d'une instruction qui respecte une condition bien précise dans la mémoire, ce qui fait que les mémoires associatives sont donc tout indiquées. Comme vous le savez, les signaux de commande d'une instruction sont propagés avec celle-ci dans le pipeline, le nom du registre de destination ne faisant pas exception. Le nom de registre est envoyé à la fenêtre d'instruction lors de l'écriture du résultat dans les registres. S'il y a correspondance, l'opérande est disponible et son bit de disponibilité est mis à 1. On peut adapter cette méthode pour tenir compte du contournement assez simplement. [[File:Détection des dépendances par propagation du registre de destination.png|centre|vignette|upright=2|Détection des dépendances par propagation du registre de destination.]] En conséquence, le circuit de détection des dépendances est constitué d'un grand nombre de comparateurs : un par champ « nom de registre » dans chaque entrée. La logique d'éveil/''wake up'' regroupe tous les comparateurs, la logique de sélection est un circuit situé en-dehors de la mémoire associative. Les entrées sont dans la mémoire associative elle-même. [[File:Gestion des bits de validité.png|centre|vignette|upright=2|Gestion des bits de validité.]] L'implémentation la plus simple est celle du schéma précédent, où on utilise une mémoire associative unique. Une version plus élaborée sépare la fenêtre d'instruction en deux parties : une mémoire qui mémorise les registres des opérandes, une autre mémoire pour le reste. La mémoire pour les registres opérandes est la mémoire associative proprement dite, c'est elle qui est associées aux comparateurs, à la logique de ''wake-up''/réveil, etc. Par contre, l'autre mémoire est une mémoire RAM simplifiée, qui mémorise les informations qui n'ont pas besoin des comparateurs. L'opcode de l'instruction est là-dedans, par exemple. ===Les optimisations de la consommation d'énergie : la désactivation des portions inutilisées=== Le problème avec des fenêtres d'instruction de ce type est leur forte consommation énergétique, ainsi que le grand nombre de portes logiques utilisées, qui deviennent prohibitif pour des fenêtres d'instruction un peu grosses. Pour résoudre ce problème, certains ont optimisé les comparateurs. D'autres ont tenté de profiter du fait que la majorité des bits dans les entrées sont composés de zéros. Bref, les optimisations purement matérielles sont légion. Une première solution est de désactiver les entrées qui sont inutilisées, vides, sans instruction. Pour cela, on fait précéder les comparateurs par un circuit qui les connecte ou déconnecte des lignes de bit. Le circuit est commandé par le bit ''empty'' qui indique si une entrée est vide ou non. L'avantage est que la consommation d'énergie de la fenêtre d'instruction devient alors proportionnelle au nombre d'entrées non-vides, et non au nombre d'entrées total. Du moins, en apparence, les entrées non-utilisées doivent quand même être alimentées pour fonctionner, mais l'activité de comparaison disparait dans les entrées vides. Il est possible d'étendre cette technique aux entrées dont les opérandes sont prêtes. Les gains sont généralement assez bons, avec une réduction de consommation variant entre 30 et 50%, avec une implémentation très simple et très économe en circuits. Une autre solution, assez simple à mettre en place, consiste à désactiver une partie de la fenêtre d'instruction sin elle est inutilisée. Pour cela, il faut segmenter la fenêtre d'instruction avec la technique du ''wire partitionning''. Pour rappel, une fenêtre d'instruction est une mémoire associative. Et comme toute mémoire associative, elle contient des fils, les lignes de bit, qui relient les entrées/sorties à toutes les cellules mémoire. Plus une ligne de bit est longue, plus elle consomme d'énergie et plus le temps de lecture/écriture est long. L'idée est de segmenter les lignes de bits en plaçant des répéteurs qui recopient la tension d'un segment au suivant. Les répéteurs sont des tampons trois-états, ce qui permet de déconnecter les portions inutilisées de la ligne de bit. Ce faisant, la fenêtre d'instruction est découpée en segments, qui peuvent être désactivés si besoin. Si il y a peu d'instructions chargées dans la fenêtre d'instruction, les portions inutilisées sont désactivées. La technique marche d'autan mieux si les instructions sont compactées au début de la fenêtre d'instruction. [[File:Wire partitionning.png|centre|vignette|upright=2|Wire partitionning]] Tout le problème est de savoir quelles portions désactiver. La technique est assez simple si la fenêtre d'instruction est compactée, à savoir si toutes les instructions sont régulièrement regroupées au début de la mémoire CAM. Mais même avec cette optimisation, la décision de désactiver une portion de la fenêtre d'instruction n'est pas à prendre à la légère. Il ne faut pas désactiver une portion contenant des instructions pouvant être émise sous peu. La décision dépend de paramètres variés : proportion d'entrée vides, quantité d'entrées récemment activées/désactivées récemment, présences d'entrées avec un ''match'' d'opérandes récent, etc. Il est important de préciser que les techniques en question fonctionnent aussi sur les autres types de fenêtre d'instruction, qui ne sont pas basées sur des mémoires associatives. Nous allons voir celles-ci dans la suite du chapitre, mais gardez à l'esprit que ces optimisations, à savoir désactiver les entrées vides/prêts et partitionner la fenêtre d'instruction, sont des optimisations générales qui marchent avec presque tout. ===L'ajout d'une FIFO pour les instructions déjà prêtes à l'émission=== D'autres techniques permettent de réduire aussi bien le cout en circuits que la consommation d'énergie de la fenêtre d'instruction. L'idée est d'utiliser une mémoire associative quand elle est réellement nécessaire, mais d'utiliser une fenêtre d'instruction "normale" dès que possible. La méthode la plus simple tient compte du fait que certaines instructions ont déjà toutes leurs opérandes de disponibles à l'émission, mais doivent quand même être mises en attente, parce que l'ALU adéquate est occupée, parce que des dépendances WAW/WAR sont encore là, ou pour tout autre raison. Dans ce cas, elles sont mises en attente non pas dans la fenêtre d'instruction, mais dans une mémoire FIFO toute simple. L'idée est qu'au lieu d'avoir une énorme mémoire associative pour la fenêtre d'instruction, on déplace quelques entrées dans une petite FIFO annexe. Le résultat est un gain en terme d'énergie et de circuits, au prix d'une perte de performance mineure. La perte de performance en question se manifeste si aucune instruction n'a ses opérandes de prêtes à l'émission : le programme n'utilise pas la FIFO et voit alors une fenêtre d'instruction plus petite. Une amélioration de cette technique tient compte du fait que certaines instructions sont dans un cas intermédiaire. Elles ont déjà une opérande de prête lors de l'émission, mais pas l'autre. Le nombre d'opérandes varie suivant l’instruction : certaines n'ont besoin que d'un seul opérande. De plus, il arrive qu'une opération tout juste décodée ait déjà un ou plusieurs de ses opérandes de prêts. Cette constatation permet d'éviter d'utiliser des comparateurs pour les opérandes déjà prêts. Par exemple, on peut parfaitement utiliser trois fenêtres d'instruction : * une pour les instructions dont tous les opérandes sont prêts, mais qui sont quand même mises en attente, sans comparateur ; * une pour les instructions dont un seul opérande manque, qui n'utilise qu'un comparateur par entrée ; * une pour les instructions dont deux opérandes manquent à l'appel, qui utilise deux comparateurs par entrée. C'est beaucoup plus économique que d'utiliser une seule grosse fenêtre d'instruction qui contiendrait autant d'entrées que les trois précédentes réunies, avec deux comparateurs par entrée. Certains sont même allés plus loin, et ont proposé de supprimer la fenêtre d'instruction avec deux opérandes par entrée. Les instructions dont deux opérandes sont inconnus au décodage sont stockées dans la fenêtre d'instruction pour instructions avec un comparateur par entrée. Un circuit de prédiction se charge alors de prédire l'opérande manquant, cette prédiction étant vérifiée plus loin dans le pipeline. Il serait cependant étonnant qu'une telle proposition ait donné lieu à la moindre implémentation réelle. ===Les optimisations de la consommation d'énergie avancées=== D'autres chercheurs ont conservé une fenêtre d'instruction unique, avec autant de comparateurs par entrée qu'il y a d'opérandes possibles par instruction. Simplement, le processus de détection des opérandes prêts est légèrement ralenti : on ne vérifie qu'un opérande par cycle. Pour vérifier les deux opérandes d'une entrée, on doit attendre deux cycles. Enfin, certains chercheurs ont proposé des fenêtres d'instruction segmentées. Les instructions circulent à chaque cycle d'un segment vers le suivant : en conséquence, certains segments conservent les instructions les plus anciennes, un autre les instructions les plus jeunes, etc. Seul le denier segment, celui qui contient les instructions les plus vielles, peut émettre une instruction : la détection des opérandes se fait seulement dans le dernier segment, qui contient les instructions les plus anciennes. On économise ainsi beaucoup de comparateurs. Certains chercheurs ont tenté de pipeliner l'étape de sélection des opérandes, ainsi que l'étage d'arbitrage. Mais en faisant cela, il faut plusieurs cycles pour détecter qu'une instruction a ses opérandes prêts, ce qui pose problème face à de nombreuses dépendances RAW. Pour éviter de trop perdre en performances, certains chercheurs ont décidé d'utiliser des techniques pour prédire quelles seront les instructions dont les opérandes seront bientôt prêts. Si détecter qu'une instruction est prête prend n cycles, le processeur devra tenter de prédire la future disponibilité des opérandes n cycles en avance pour obtenir des performances optimales. ===Remplacer la mémoire associative par une RAM=== Une autre optimisation possible est de remplacer la fenêtre d'instruction par une mémoire RAM, dont chaque mot mémoire correspondrait à une entrée. Une telle optimisation permet en théorie de se passer des comparateurs associés à chaque entrée, mais au prix de l'ajout de circuits annexes potentiellement couteux. La première de ces techniques, la '''recherche directe par étiquette''' (direct tag search) fut créée par Weiss et son collègue Smith. Ils cherchaient à améliorer l'algorithme de Tomasulo, un algorithme qu'on expliquera dans quelques chapitres. Rappelons que chaque instruction produit un résultat, qui devra être rapatrié dans une ou plusieurs entrées de la fenêtre d'instruction. L'optimisation de la recherche directe par étiquette fonctionne dans le cas où le résultat de l'instruction n'est utilisé que par une seule entrée, et pas plusieurs. Le principe est simple : chaque champ « opérande » d'une entrée est adressable via le nom de registre de cette opérande. Pour faire le lien entre entrée et nom de registre, la recherche directe par étiquette ajoute une table de correspondances matérielle, une mémoire RAM qui mémorise les adresses des champs « opérande » des entrées. Les adresses envoyées dans cette mémoire sont les noms de registres des résultats. Lors de l'émission, la table de correspondances est mise à jour. Les numéros des champs « opérande » réservés lors de l'émission sont mémorisés dans les mots mémoire qui correspondent aux deux registres sources. Toutefois, une petite vérification est faite lors de l'émission : si il y a déjà une correspondance dans la table pour un registre source, alors une autre instruction compte lire ce registre. Pour éviter d'écraser les données de l'instruction précédente dans la table de correspondances, l'émission de l'instruction est bloquée. [[File:Recherche directe par étiquette.png|centre|vignette|upright=2|Recherche directe par étiquette.]] ==Les fenêtres d’instruction avec préplanification== Avec la '''préplanification''' (''prescheduling''), la fenêtre d’instruction est composée de mémoires FIFO dans lesquelles les instructions sont triées dans l'ordre d'émission. Il n'y a pas de logique d’émission proprement dite, celle-ci se bornant à vérifier si l'instruction située au début de la FIFO peut s’exécuter. Par contre, le préplanificateur détecte les dépendances et en déduit où insérer les instructions dans le tampon d'émission, à l'endroit le plus adéquat. [[File:Préplanification.jpg|centre|vignette|upright=2|Préplanification.]] ===L'usage de FIFO multiples=== La technique de préplanification la plus simple utilise plusieurs FIFO. Quand une instruction a une dépendance avec une autre instruction, les deux sont placées dans la même FIFO. Pour cela, le préplanificateur détecte les chaines d'instructions dépendantes, et place les instructions dans la FIFO adéquate. A chaque cycle, l'unité d'émission lit une micro-opération dans chaque FIFO et vérifie si elle peut l'émettre. Si la micro-opération n'a pas ses opérandes disponibles, ou qu'une dépendance structurelle survient, alors la FIFO est bloquée. La micro-opération attend que la dépendance soit résolue, bloquant toutes les instructions précédentes. Mais les autres FIFO ne sont pas bloquées, laissant de la marge de manœuvre. [[File:Préplanification par FIFO multiples.png|centre|vignette|upright=1.5|Préplanification par FIFO multiples.]] ===La technique du tampon trié=== La technique du '''tampon trié''' trie les instructions selon le temps d'attente avant leur exécution. Les instructions qui sont censées s’exécuter bientôt sont insérées au tout début de la FIFO, tandis que les instructions qui s’exécuteront dans un long moment sont insérées vers la fin. Là encore, l'unité d'émission lit une micro-opération dans la FIFO, et détermine si elle peut être émise. Si une dépendance survient, l'émission est retardée, et la FIFO est bloquée. [[File:Préplanification par tampon trié.png|centre|vignette|upright=1.5|Préplanification par tampon trié.]] La technique a cependant quelques problèmes assez importants. Le premier problème est que la FIFO est bloquée lorsqu'une micro-opération ne peut être émise. Le second problème est que le temps avant exécution n'est pas toujours connu, notamment pour les instructions d'accès mémoire. Et cela se répercute sur les instructions dépendantes de celles-ci. Pour résoudre ce genre de problèmes, l'usage d'un pipeline à ''replay'' est possible, et est même l'une des meilleures solution possible, malgré ses défauts. L'idée est que les lecture sont pré-planifiées en supposant qu'elles font un succès de cache L1. Si la prédiction est fausse, la lecture est ré-exécutée plusieurs cycles plus tard, en supposant qu'elle fait un succès dans le cache L2, et ainsi de suite. Elle est alors ré-insérée dans la FIFO, elle est pré-planifiée une seconde fois. Il en est de même si une micro-opération ne peut pas être émise : il suffit de la réinsérer dans la FIFO au bon endroit, en attendant que ses dépendances soient résolus. Ainsi, l'instruction fautive ne bloque pas la fenêtre d’instruction, et retente sa chance autant de fois qu'il le faut. [[File:Préplanification par fenêtre d’instruction scorebarodée.png|centre|vignette|upright=1.5|Préplanification par fenêtre d’instruction scorebarodée.]] Une autre solution utilise deux fenêtres d’instruction : une FIFO gérée par la préplanification, et une vraie fenêtre d'instruction pour les instructions dont le temps d'attente ne peut pas être déterminé. Il est possible de mettre cette dernière avant la préplanification, afin de gérer les temps d'attente des instructions d'accès mémoire. Quand le temps d'attente d'une lecture devient connu, ses instructions dépendantes sont gérées avec préplanification. [[File:Préplanification avec fenêtre d’instruction.png|centre|vignette|upright=2.5|Préplanification avec fenêtre d’instruction.]] ===Les fenêtres d'instruction avec allocation temporelle statique=== L''''allocation temporelle statique''' correspond à une technique utilisée sur les processeurs Cuzco de l'entreprise Condor. La technique en question a été présenté en 2025, mais des idées similaires ont été présentées dans la littérature académique. Elle ressemble beaucoup aux techniques de pré-planification, avec cependant quelques différences. L'idée est simple : le processeur dispose de plusieurs fenêtres d'instruction, qui mettent en attente les micro-opérations. Lors de l'étape de renommage de registres, le processeur détermine dans combien de cycles d'horloge la micro-opération sera prête pour exécution. La micro-opération est alors mise en attente durant ce nombre de cycles, dans les fenêtres d'instruction, puis est émise une fois ce nombre de cycles écoulés. Ce faisant, les fenêtres d'instruction n'ont pas besoin de détecter la disponibilité des opérandes à chaque cycle, pour chaque micro-opération en attente. Le ''timing'' de l'émission des micro-opérations est décidé à l'avance. L'implémentation exacte n'est pas connue, mais plusieurs solutions sont imaginables. Par exemple, la fenêtre d'instruction peut simplement être composée de plusieurs mémoires de petite taille, chacune contenant les micro-opérations destinées à être exécutées dans N cycles, N étant différent pour chaque mémoire. Une autre solution, plus réaliste, utilise une fenêtre d'instruction dans laquelle la micro-opération est couplée à des champs pour les opérandes, et un champ compteur. Le champ compteur est initialisé avec le nombre de cycles à attendre, et est décrémenté à chaque cycle d'horloge. Quand il atteint zéro, la micro-opération est émise. Vous remarquerez que la méthode ne marche que si toutes les micro-opérations prennent un nombre fixe de cycles d'horloge. Et autant c'est le cas pour les micro-opérations arithmétiques ou logiques, autant les accès mémoire ne rentrent pas dans ce cadre. En théorie, on ne sait pas combien de temps prendra un accès mémoire. Et cette incertitude se répercute sur les instructions dépendantes d'un accès mémoire. Pour éviter cela, le processeur réutilise un pipeline à ''replay'' tel que vu dans le chapitre précédent. L'unité de renommage de registre suppose que tout accès mémoire fait un succès de cache L1, et décide des ''timings'' d'émission sous cette hypothèse. Si une lecture subit un défaut de cache, elle est ré-exécutée, de même que toutes les instructions dépendantes. Pour cela, le registre de destination de la lecture est marqué comme invalide, grâce à un bit spécifique attaché au registre. Toute instruction qui lit une opérande invalide est elle aussi ré-executée de zéro. Pour simplifier, l'unité d'émission ressemble à une unité d'émission dans l'ordre, avec un registre de disponibilité, qu'on aurait amélioré pour aller au-delà de la simple détection des dépendances d'instruction. Pour déterminer les ''timings'' d'émission, à savoir quand émettre une micro-opération, le processeur utilise une unité d'émission à deux étages. Le premier étage est appelé le ''register scoreboard'', le second étage est appelé la ''Time Ressource Matrix''. Les deux étages communiquent entre eux, comme on va le voir, et leurs noms donnent une idée de ce qu'ils font. Le premier étage gère les dépendances de registres, le second gère les dépendances structurelles. Le premier étage est un registre de disponibilité amélioré, qui gère les dépendances de registre. Cet étage sait quand tel registre sera écrit, et donc que l'opérande écrite dedans sera disponible à partir de tel cycle d'horloge. Il le sait car l'étage suivant l'aura prévenu, mais laissons cela de côté pour le moment. Quand une micro-opération rentre dans cet étage, il vérifie les dépendances avec les registres et les micro-opérations antérieures. Vu qu'il sait quand les registres seront disponibles, il peut déterminer quand l'instruction pourra s'exécuter. Par exemple, si une micro-opération lit les deux registres R7 et R15, qui sont disponibles respectivement dans 5 et 7 cycles, le premier étage sait que la micro-opération devra attendre 7 cycles. Mais tout cela ne suffit pas à déterminer quand émettre une micro-opération. En effet, il fait aussi gérer les dépendances structurelles, ce qui est le boulot du second étage. Le second étage utilise pour cela une ''Time Ressource Matrix'', qui mémorise l'occupation de diverses "ressources", pour les 256 cycles d'horloge à venir. Les ressources en question sont les ports de lecture/écriture du banc de registre, les ALUs utilisées, si la micro-opération utilise l'unité mémoire, etc. Le second étage prend en entrée une micro-opération, détermine quelles "ressources" elle utilise, puis regarde leur disponibilité. Elle détecte alors les dépendances structurelles et détermine alors quand peut s'exécuter la micro-opération. Elle peut retarder l'émission de quelques cycles, si une dépendance structurelle est détectée. Une fois sortie du second étage, on sait quand la micro-opération va être émise, à quel cycle précisément. Et vu que la durée de l'instruction est fixe, on sait quand cette micro-opération va se terminer, quand son résultat sera disponible. Cela permet de mettre à jour la ''Time Ressource Matrix'', pour préciser que le port d'écriture sera occupé à tel moment. De plus, cette information est transmise au premier étage, qui sait alors quand est enregistré le résultat dans le registre de destination. C'est comme cela que le premier étage sait quand un registre est disponible : le second étage le prévient, quand il émet une instruction ! La ''Time Ressource Matrix''mémorise l'occupation des "ressources" pour les 256 cycles d'horloge à venir. Cependant, elle ne vérifie pas les dépendances pour les 256 cycles suivants. Quand elle reçoit une micro-opération, elle teste les dépendances structurelles pour seulement les 8 prochains cycles maximum. Si la micro-opération ne peut pas être émise pendant ces 8 cycles, le pipeline est bloqué, un ''pipeline stall'' est émis. Pour être plus précis, vu que le processeur peut décoder 8 micro-opérations en même temps, cela permet de ne consulter que 64 cycles d'horloge sur les 256. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les premiers processeurs Intel | prevText=Les premiers processeurs Intel | next=Le renommage de registres | nextText=Le renommage de registres }} </noinclude> ktnm9vezdykaumlqnia4ka1sfsipg22 773587 773586 2026-09-29T17:28:57Z Mewtow 31375 /* Les fenêtres d’instruction : généralités */ 773587 wikitext text/x-wiki Dans les chapitres précédents, nous avons parlé des techniques dites d''''émission dans l'ordre'''. L'idée est d’exécuter une nouvelle micro-opération à chaque cycle, dans des unités de calcul séparées. Les instructions sont émises consécutivement, mais les instructions s’exécutent en parallèle dans des unités de calcul séparées. Par contre, quand l'unité d'émission ne peut pas émettre une instruction, elle bloque tout le pipeline. Les instructions qui suivent sont elles aussi bloquées, elle doivent attendre leur tour, même si elles sont en capacité de s'exécuter. Les techniques d'exécution dans le désordre que nous allons voir dans ce chapitre corrigent ce point précis. Elles sont dites à '''émission dans le désordre'''. Elles se distinguent des précédentes sur un point précis : quand l'unité d'émission bloque l'émission d'une instruction, les instructions suivantes peuvent poursuivre. L'émission des instructions peut donc se faire dans le désordre, dans le sens où une instruction peut être émise alors qu'une instruction précédente ne l'est pas encore. L'avantage de l'émission dans le désordre est qu'une instruction s'exécute dès que ses opérandes sont disponibles. Par disponible, on veut dire présent soit dans le réseau de contournement, soit dans les registres. Le processeur détecte automatiquement quand les opérandes d'une instruction sont sont disponibles, et il l’exécute à ce moment là. Dès qu'une instruction a ses opérandes disponibles, elle est émise et exécutée. C'est là la seule contrainte : les dépendances WAR, WAW et autres sont gérées par un ROB ou toute autre technique d'exception précise, seules les dépendances RAW limitent l'exécution. Mais avant de poursuivre, quelques point niveaux terminologie : * L'émission dans le désordre est un terme parlant et assez précis. Malheureusement, la terminologie la plus utilisée par d''''exécution dans le désordre'''. Et nous utiliserons ce terme dans la suite du cours, histoire de ne pas trop dévier de la nomenclature habituelle. * Nous utiliserons parfois l'abréviation OOO pour parler d'exécution dans le désordre. L'abréviation est celle de ''Out Of Order Excution''. * Nous utiliserons aussi l'abréviation ''µop'' pour parler de micro-opération, ''µops'' au pluriels pour parler de plusieurs micro-opérations, ou des micro-opérations en général. L'exécution dans le désordre ne gére en effet que des µops, elle se situe après l'étape de décodage. Mais avant de poursuivre, précisons une chose importante : l'exécution dans le désordre traite les accès mémoire à part. La majorité des processeurs OOO assez anciens exécutent les accès mémoire dans l'ordre, seules les µops entières/flottantes/branchements sont exécutées dans le désordre. Les processeurs datant d'après les années 2010 sont capable d'exécuter les accès mémoire dans le désordre, mais l'implémentation en question est assez particulière. Un chapitre entier sera dédié à l'exécution dans le désordre des µops mémoire. Nous allons volontairement mettre de côté la gestion des accès mémoire dans ce chapitre. ==Les fenêtres d’instruction : généralités== [[File:File de micro-opération.png|vignette|upright=1|File de micro-opérations]] Pour décrire comment est implémentée l'émission dans le désordre, il faut commencer par parler des processeurs sans. Les processeurs sans exécution dans le désordre ont une unité d'émission qui bloque tout le pipeline dès qu'une µop ne peut pas être émise. Pour limiter l'impact de ce blocage, quelques rares processeurs incorporent une '''file de micro-opération''', une mémoire FIFO qui met en attente les µops. Vu que c'est une mémoire FIFO, les µops sont émises dans l'ordre, à savoir l'ordre d'ajout, dans l'ordre de décodage. Le schéma ci-dessous illustre une telle file d'attente couplée à un ''scoreboard''. Sur le principe, l'exécution dans le désordre améliore la file de µops sur un point : ce n'est plus une mémoire FIFO. Les µops sont insérées dans l'ordre, mais peuvent sortir dans le désordre (être émises dans le désordre). La file de µops devient alors une '''fenêtre d'instruction''', terme traduit directement de l'anglais ''instruction Window''. Terme assez trompeur, car elles mettent en attente des µops, pas des instructions. Elles peuvent émettre des µops dans le désordre, ce qui fait que si une µop bloque le pipeline, les µops suivantes peuvent être émises. Si je commence le paragraphe précédent par "sur le principe", c'est car certaines techniques d'OOO utilisent des files de µops normales. Notez le pluriel ! Il existe dans les grandes lignes 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! File de µops améliorée |- ! Une seule "file de µops" | ''Scoreboard'' | Fenêtre d'instruction centralisée |- ! Plusieurs "file de µops" | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | Fenêtre d'instruction décentralisée |} ===La fenêtre d'instruction centralisée=== L'implémentation la plus simple de l'OOO utilise une unique '''fenêtre d'instruction'''. Les instructions décodées sont accumulées dans la fenêtre d'instruction, où elles attendent que leurs opérandes soient disponibles. La fenêtre d'instruction sert donc de file d'attente. Mais elle contient aussi une unité d'émission, qui détecte quelles µops sont prêtes à être émises. L'unité d'émission et la fenêtre d'instruction sont fusionnées ensemble, elles forment un seul circuit. Mais nous allons dire qu'elles sont conceptuellement séparées pour le moment. A chaque cycle, l'unité d'émission consulte la fenêtre d'instruction pour voir quelles µops peuvent s'exécuter, lesquelles ont leur opérandes de disponibles. La fenêtre d'instruction doit spécialement être conçue pour, c'est une sorte de mémoire associative très complexe, comme on le verra dans ce qui suit. [[File:OOO Issue.png|centre|vignette|upright=2.5|Exécution dans le désordre avec une fenêtre d'instruction]] Une fois qu'une µop sort du décodeur d'instructions, elle est ajoutée en parallèle dans la fenêtre d'instruction et le ROB. La raison est que les µops quittent la fenêtre d'instruction dans le désordre, et qu'elles doivent être remises en ordre par la suite. Le ROB s'occupe de cette remise en ordre, mais il a besoin de savoir dans quel ordre les µops sont censées être, et cet ordre est celui du décodage. Aussi, pour remplir le ROB, la seule opportunité est en sortie de l'unité de décodage. Dans le cas où une instruction est décodée en plusieurs micro-opérations, elles sont toutes insérées en même temps dans la fenêtre d'instruction et le ROB, en tenant compte de leur ordre. [[File:Fenêtre d'instruction.png|centre|vignette|upright=2|Fenêtre d'instruction.]] Les micro-opérations mémoire sont à part des autres, pour diverses raisons. Une de ces raisons est que les dépendances de données sont classées en deux types : les dépendances de registre et les dépendances d'adresse. Et les deux sont fondamentalement différentes. Autant on peut détecter les dépendances de registre lors de l'émission, autant c'est plus compliqué avec les dépendances d'adresse. De plus, rappelons que si les lectures peuvent s'exécuter dans le désordre, les écritures doivent s'exécuter dans l'ordre, ou du moins en donner l'illusion. Pour cela, le processeur remet les écritures dans l'ordre avec une sorte de mini-ROB intégré à l'unité mémoire, appelée la file d'écriture. Elle complémente le ROB, qui lui ne gère que les écritures dans les registres, mais les deux collaborent. La file d'écriture envoie une écriture à la mémoire RAM quand le ROB lui dit que c'est bon, les instructions précédentes sont terminées ''dans l'ordre du programme''. Les processeurs assez anciens n'autorisaient pas d'exécution dans le désordre des accès mémoire. Pour cela, la fenêtre d'instruction ne mémorise pas de µops mémoire. L'unité mémoire est précédée par une file de micro-opérations séparée, pour forcer l'exécution dans l'ordre des accès mémoire. Les processeurs modernes ajoutent des techniques d'exécution dans le désordre des accès mémoire, mais nous les verrons dans un chapitre dédié. Dans ce chapitre, on suppose que l'unité mémoire est précédée d'une file de micro-opération mémoire dédiée, rien que pour elle. [[File:Processeur avec émission dans l'ordre des accès mémoire.png|centre|vignette|upright=2|Processeur avec émission dans l'ordre des accès mémoire]] ===Les fenêtres d'instruction décentralisées=== Une autre solution utilise plusieurs fenêtres d'instruction. Pour faire la différence avec l'usage d'une fenêtre d'instruction unique, nous allons parler de fenêtre d'instruction centralisée s'il n'y en a qu'une dans le processeur, de '''fenêtre d'instruction décentralisée''' s'il y en a plusieurs. Dans le cas général, chaque fenêtre d'instruction est associée à un type précis d'opération/instruction. La tendance moderne est d'utiliser une fenêtre d'instruction pour les instructions de calcul entières, une autre pour les flottantes. Il s'agit d'un choix simple et efficace, mais quelques processeurs font autrement, pour répondre à des contraintes très diverses. L'usage de fenêtres décentralisées simplifie la répartition des instructions sur les différentes unités de calcul. Par exemple, utiliser des fenêtres séparées pour les ALU et les FPU facilite la répartition des instructions de calcul sur les ALU. Une fenêtre centralisée demande de faire la différence entre instruction entière/flottante, puis de choisir sur quelle unité de calcul entière/flottante utiliser. Une fenêtre décentralisée fait les deux choix séparément : d'abord on envoie l'instruction dans la bonne fenêtre suivant si c'est une instruction flottante ou entière, et ensuite on gère la disponibilité des ALUs/opérandes. Et on peut adapter la même idée en séparant les unités d'accès mémoire des ALU entières, etc. Par contre, un défaut est que certaines fenêtres d'instruction peuvent être sous-utilisées. Par exemple, la station de réservation flottante est inutilisée si le programme n'exécute pas d'opérations flottantes. Ou encore, les fenêtres pour les accès mémoire peuvent être sous-utilisées, si le programme effectue peu d'accès mémoire relativement aux autres instructions. En fait, tout dépend de comment sont calibrées les fenêtres d'instruction et de la répartition des instructions dans le programme entre opérations entières, flottantes, mémoire. Par exemple, si un programma de deux fenêtres d'instructions identiques, une pour les calculs entiers et une autre pour les calculs flottants, elles ne seront utilisées à la perfection que si la moitié des instructions du programme fait des calculs flottants et l'autre des calculs entiers. Toute déviation par rapport à cette répartition idéale risque de laisser des entrées vides dans une fenêtre d’instruction. Un point important est que l'émission est découpée en deux étages avec des fenêtres d'instruction décentralisées. La première étape envoie l'instruction décodée vers la fenêtre d'instruction adéquate, la seconde gère l'émission proprement dit. La première est l'étage de ''dispatch'' qui envoie l'instruction dans la fenêtre d’instruction adéquate, selon que c'est une instruction flottante, entière, autre. La seconde est l'étage de ''scheduling'', qui gère la disponibilité des opérandes et des unités de calcul. En clair, on trie les instructions suivant leur type, suivant le type d'unité de calcul adéquate, puis on l'émet proprement dit. Faire ainsi a plusieurs avantages, avec cependant peu d'inconvénients. Lors de l'étape de ''dispatch'', l'instruction émise est ajoutée au tampon de réordonnancement, s'il existe. Sans cela, impossible de conserver l'ordre des instructions. Les instructions sont émises dans l'ordre au niveau de l'unité de ''dispatch'', pas au niveau de l'étage de ''scheduling''. Aussi, pour remplir le ROB, cela doit se faire au dernier moment où les instructions sont émises dans l'ordre, soit en sortie de l'unité de ''dispatch''. De plus, les micro-opérations mémoire sont traitées à part des autres, elles sont envoyées directement à l'unité mémoire. La gestion des calculs d'adresse est quelque peu complexe, mais ils peuvent être fait soit dans l'unité mémoire, soit dans les ALU entières, peu importe. Il y a aussi un système de contournement complexe entre ALU/FPU et unité mémoire, qui n'est pas représenté dans le schéma ci-dessous. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Il faut noter que quelques processeurs utilisent des méthodes intermédiaires entre les trois solutions précédentes. Par exemple, les processeurs AMD Zen utilisent une fenêtre d'instruction décentralisée un peu particulière. Les unités de calcul entières disposent d'une fenêtre d'instruction rien que pour elles, sur ce processeur. Les instructions flottantes sont quant à elles alimentées par une file de micro-opération, pas une fenêtre d'instruction ! La raison à ce choix est un compromis entre performance et cout en circuit. L'exécution dans le désordre est peu efficace sur les instructions flottantes, car les CPU n'ont que peu d'ALU flottantes séparées. Vu le cout en circuits d'une fenêtre d'instruction, les concepteurs du processeur ont préféré utiliser une file de micro-opération pour les opérations flottantes. ===L'usage de plusieurs files d'instruction=== Une dernière méthode d'OOO utilise plusieurs files de micro-opération. L'idée est qu'une fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement une file de micro-opération pour les opérations entières, une autre pour les opérations flottantes, une autre pour les accès mémoire. D'autres processeurs utilisent une file pour les accès mémoire et une autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. La présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que la technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si une dépendance bloque une FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans une autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer la disponibilité des registres. Quand un registre est lu ou écrit par une instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. La logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : une pour les instructions d'accès mémoire et une autre pour les autres instructions. Si jamais une instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de la lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'une est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est la file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. ===Avantages et inconvénients de chaque implémentation=== Un processeur contient soit une fenêtre d'instruction unique, soit plusieurs fenêtres d'instruction séparées. Typiquement, les fenêtres d’instruction séparées sont spécialisées, dans le sens où on a une fenêtre pour les instructions flottantes, une autre pour les instructions entières, une autre pour les accès mémoire, etc. Pour résumer, on a le choix entre une grosse fenêtre généraliste et plusieurs fenêtres spécialisées, sauf que la fenêtre centralisée est lente et complexe, contrairement aux fenêtres spécialisées. Les deux méthodes ont des inconvénients et des avantages différents. Dans les grandes lignes, l'avantage des fenêtres décentralisées est qu'elles sont plus petites qu'une grosse fenêtre d'instruction. Cela simplifie la gestion du contournement et de la répartition des instructions sur les unités de calcul, comme on le verra dans quelques paragraphes. Elles sont donc moins complexes et plus rapides. L'autre avantage, c'est qu'il est possible de démarrer l'exécution de plusieurs instructions simultanément : une instruction par fenêtre décentralisée, contre une par fenêtre d'instruction. Mais les fenêtres décentralisées sont souvent sous-utilisées, partiellement remplies, contrairement aux fenêtres d'instruction. Il arrive qu'une fenêtre d'instruction soit remplie, alors que les autres sont vides. Par exemple, prenons un processeur avec une fenêtre d'instruction reliée à la FPU, et une autre reliée aux autres ALUs. Si le processeur n'exécute que des opérations flottantes, la fenêtre reliée à la FPU sera pleine, alors que l'autre sera vide. L'exécution des instructions dans le désordre est alors limitée par la petite taille de la fenêtre, qui ne peut plus accepter de nouvelle instruction flottante. Avec une fenêtre unique, on n'aurait pas eu ce problème : on aurait eu une énorme fenêtre d'instruction remplie d'instruction flottante, au lieu d'une petite fenêtre spécialisée. Il est maintenant temps de voir en quoi sont faites les fenêtres d’instruction, qu'elles soient centralisées ou décentralisées. Nous allons aussi voir quelle est la logique d'émission associée. ==L'implémentation d'une fenêtre d'instruction : généralités== Une fenêtre d'instruction est une mémoire qui mémorise des micro-opérations. Elle est cependant plus complexe qu'une mémoire RAM ou qu'une FIFO et ressemble un petit peu à une mémoire cache. Elle dispose d'un port d'écriture et d'un port de lecture, au minimum. Le port d'écriture permet à l'unité de décodage d'insérer une micro-opération dedans, d'ajouter la micro-opération qui vient d'être décodée. Si une instruction machine est décodée en plusieurs micro-opération, deux possibilités. La première est de les insérer un par un, ce qui fait qu'on peut se contenter d'un seul port d'écriture. L'autre possibilité est de les ajouter en même temps, ce qui demande plusieurs ports d'écriture. Le port de lecture sert à émettre une instruction. On part du principe que la fenêtre d'instruction ne peut émettre qu'une seule instruction à la fois, car les processeurs que nous avons vu précédemment sont de ce type. Mais nous verrons dans quelques chapitre qu'il existe des processeurs dits superscalaires, qui sont capables d'émettre plusieurs instructions par cycle. Dans ce cas, la fenêtre d'instruction a un seul port de lecture. Un processeur superscalaire, quant à lui, doit avoir un port de lecture par unité de calcul, ce qui fait beaucoup plus. ===Les entrées d'une fenêtre d’instruction=== Les fenêtres d'instruction sont composées d''''entrées''', des mots mémoire qui stockent une instruction. Une instruction réserve une entrée après son décodage et la libère dès qu'elle est envoyée aux unités de calcul. Une entrée contient l'opcode (les signaux de commande à envoyer à l'ALU), le registre de destination du résultat, les registres de chaque opérande, et éventuellement des signaux de commande en plus. De plus, chaque opérande est couplée à un bit de disponibilité, qui indique si elle est disponible. Quand un opérande est écrit dans les registres, le bit de présence correspondant est mis à jour. Enfin, chaque entrée possède un bit ''empty'' qui indique si elle est vide, cette information étant utile pour réserver des entrées. [[File:Entrée d'une station de réservation - sans les tags.png|centre|vignette|upright=3|Entrée d'une fenêtre d'instruction]] Nous verrons dans quelques chapitres que certaines fenêtres d'instruction sont capables de mémoriser les opérandes des instructions. De telles fenêtres d'instruction seront appelées, dans ce cours, des '''stations de réservation'''. Les entrées des stations de réservation sont assez semblables à celle des fenêtres d'instruction, à un détail près : les opérandes de l'instruction sont enregistrées directement dans des champs séparés. Il y a deux champs, un par opérande, pour stocker l'opérande elle-même, lue depuis les registres ou obtenue via le réseau de contournement. Notons que les champs pour les opérandes viennent en plus des champs pour les noms de registres, encore que les deux peuvent être fusionnés si on veut optimiser le tout. [[File:Entrée d'une station de réservation.png|centre|vignette|upright=3|Entrée d'une station de réservation.]] Précisons que la terminologie n'est pas très fiable. Les termes "fenêtre d'instruction" et "station de réservation" ne regroupent pas du tout la même chose d'un papier de recherche à l'autre, d'un bouquin à l'autre, d'un chercheur à l'autre, d'un ingénieur à l'autre, d'un professeur à l'autre. Le terme initial vient pourtant de l'article original sur l'algorithme de Tomasulo, où il désignait une fenêtre d'instruction associée à une unité de calcul précise. Mais le terme a ensuite été réutilisé, ce qui fait que certains processeurs avec plusieurs unités de calcul sont décrit comme ayant une unique station de réservation. En bref : c'est le bazar ! Mais nous en reparlerons dans le chapitre sur le renommage de registres, car c'est la place idéale pour les aborder. Toujours est-il que j'ai fait le choix de confondre les concepts de fenêtre d'instruction et de station de réservation avec les concepts de '''lecture avant émission''' et de '''lecture après émission'''. La différence entre les deux est que les registres sont lus après émission avec une fenêtre d'instruction, avant avec des stations de réservation. Dans le cas "avant émission", les opérandes sont mémorisées dans la station de réservation. Et cette différence a une influence sur le pipeline du processeur, le banc de registres et tout ce qui s'en suit. Un désavantage de la lecture avant émission est qu'il faut stocker les opérandes après lecture, ici dans les stations de réservation. Mais un avantage est que le banc de registre a besoin de moins de ports de lecture, car une bonne partie des opérandes sont fournies par le système de contournement. Nous verrons cela dans le détail dans le chapitre sur les processeurs superscalaires. Il a été proposé de fusionner le tampon de ré-ordonnancement avec la fenêtre d'instruction dans une structure unique. La méthode a notamment été utilisée sur les processeurs d'architecture K6 d'AMD. Le tout donnait une structure appelée le '''DRIS''' (''deferred scheduling register renaming instruction shelf''). La différence avec une fenêtre d’instruction normale est que les entrées sont libérée non pas quand l'instruction est exécutée/émise, mais quand elle termine son exécution et quitte le ROB. La fenêtre d'instruction doit alors incorporer des bits pour savoir si telle entrée a émis sont instruction ou non. ===La logique d'éveil et de sélection=== Dans le cas qui va suivre, on suppose que le processeur ne peut émettre qu'une instruction à la fois. Chaque cycle, une instruction est sélectionnée et est envoyée dans le chemin de données, soit à une ALU, soit à une unité d'accès mémoire. La sélection d'une instruction est effectuée par l'unité d'émission, qui est aussi appelée le '''''scheduler'''''. Elle gère la disponibilité des opérandes et la disponibilité des unités de calcul adéquate. Le choix de l'instruction émise doit être le plus pertinent possible, pour des raisons de performances. Pour le premier point, l'unité d'émission détermine quelles instructions sont candidates pour l'émission. Les ''instructions candidates'' sont celles dont tous les opérandes sont prêts. Le processeur contient un circuit qui détecte les instructions candidates : la '''logique d’éveil''' (''wake-up logic''). Une fois que la logique d'éveil a fait son travail, une instruction est choisie pour s’exécuter en fonction de la disponibilité des unités de calcul adéquates. Ce rôle est dévolu à un circuit qu'on appelle la '''logique de sélection''', ou ''select logic''. [[File:Fonctionnement complet de la logique d’émission.jpg|centre|vignette|upright=1.5|Fonctionnement complet de la logique d’émission.]] La logique de sélection doit gérer le fait que les unités de calcul du processeur ne sont pas toutes identiques. Déjà, un processeur a généralement des unités séparées pour les instructions entières et flottantes, des unités spécialisées dans les accès mémoire, parfois des unités spécialisées pour les branchements. Une instruction doit être attribuée à la bonne unité de calcul, on ne doit pas envoyer une instruction entière dans une unité de calcul flottante. De plus, parmi les unités de calcul entières, toutes ne sont pas identiques. Par exemple, il est fréquent d'avoir plusieurs unités de calcul spécialisées dans les opérations simples (additions, soustractions, opérations logiques) avec une unité pour les multiplications/divisions séparées, parfois une unité spécialisée pour les décalages/rotations, etc. Là encore, allouer la bonne instruction à la bonne ALU est complexe. Plus les unités de calcul sont hétérogènes, plus la logique de sélection est compliquée. Les logiques d'éveil comme de sélection sont assez complexes. Comme on le verra plus bas, la logique de sélection la plus simple, qui gère une seule unité de calcul, est basée sur un encodeur à priorité couplé à d'autres circuits. Et pour gérer plusieurs ALUs, il faut mettre des encodeurs en cascade. Le résultat est que même en prenant une logique de sélection simple, elle sera assez lente et gourmande en circuits. Aussi, la logique de sélection met souvent un cycle d'horloge entier pour faire son travail, elle a son propre étage de pipeline attribué. La logique d'éveil est dans le même cas, ce qui fait qu'émettre une micro-opération demande deux cycles d'horloge. Le défaut est que cela rajoute des cycles d'horloges entre la fenêtre d'instruction et l'ALU, ce qui complique la gestion du pipeline. Ces cycles de retard sont à prendre en compte au moment d'émettre les instructions, les ''scheduler'' doit en tenir compte pour des performances optimales. Sans tenir compte de ces cycles de retard, les instructions arrivent en retard de quelques cycles à l'ALU, cycles de retard durant lesquels l'ALU n'a pas fait de calcul et a été sous-utilisée, sans compter que le système de contournement n'est pas utilisé au mieux. Et le problème est encore plus important sur les processeur avec des stations de réservation, qui utilisent la "lecture après émission" : cela rajoute un cycle d'horloge en plus, un temps de retard en plus. ===La logique d'éveil : l'émission anticipée=== La logique d'éveil doit tenir compte du fait qu'il y a plusieurs étages entre l'émission et l'exécution sur une unité de calcul. Par exemple, un processeur a souvent entre un et à cinq étages entre la file d'attente et les unités de calcul. Il faut lire les registres, gérer le contournement, et cela peut prendre quelques cycles d'horloge. Sur le Pentium 4, on trouve 6 étages entre la fenêtre d’instruction et l'entrée de l'ALU. Si les micro-opérations sont émises quand les opérandes sont disponibles, il y aura un délai de quelques cycles avant qu'elles atteignent l'ALU. Alors qu'idéalement, on souhaiterait que la micro-opération atteigne l'ALU dès que ses opérandes sont disponibles, pour profiter des techniques de contournement. Pour cela, la logique d'éveil émet les instructions quelques cycles en avance pour qu'elles arrivent au bon moment. Il s'agit d'une technique d''''émission anticipée''', dont nous avions parlé dans le chapitre sur le contournement. : Il faut noter que le problème se pose plus avec des fenêtres d'instruction qu'avec des stations de réservation. Les premières ont un étage en plus entre émission et ALU, vu qu'il faut lire des registres après l'émission. L'émission anticipée demande d'émettre un signal d'éveil en avance de quelques cycles, pile au bon moment. Par exemples, si on a deux étages entre l'ALU et l'unité d'émission, le signal de réveil sera généré deux cycles avant que le résultat soit effectivement calculé. L'implémentation varie, mais deux solutions sont possibles. La première est de générer le signal d'éveil dans l'ALU, ce qui n'a de sens que pour les opérations comme les multiplications ou les divisions, qui prennent plusieurs cycles. Une autre technique génère le signal de réveil dans une structure centralisée, spécialisée dans la génération des signaux d'éveil. L'unité de composée d'un registre à décalage par registre. Imaginons qu'une instruction est émise, que cette instruction mette N cycles à s'exécuter, et qu'elle écrive dans un registre de destination. L'unité sélectionne alors le registre à décalage associé au registre de destination, et met le bit numéro N à 1. Le registre décalé d'un cran à chaque cycle. Quand le bit sortant est un 1, alors le signal de validité pour l'opérande est généré. L'émission anticipée marche bien si l'instruction a une durée fixe, connue à l'avance. Et autant c'est le cas pour les instructions arithmétiques et logiques, autant ce n'est pas le cas pour les accès mémoire. Les accès mémoire ont une latence variable : quelques cycles pour un succès de cache, plusieurs dizaines de cycles pour un défaut de cache L1, pas loin de la centaine pour un défaut de cache L2, etc. Et cela pose des problèmes pour l'émission anticipée. L'émission en avance pour les accès mémoire est purement spéculative : le processeur émet des instructions en supposant que la lecture entrainera un succès de cache, quitte à annuler l'instruction en cas de défaut de cache. Mais faire ainsi demande non seulement d'annuler les instructions émises en avance, mais aussi de ne pas retirer les instructions émises en avance de la fenêtre d'instruction. Elles sont émises, mais une copie de sauvegarde est conservée dans la fenêtre d'instruction. Si le processeur détecte un défaut de cache, il peut alors ré-exécuter l'instruction. S'il détecte un succès de cache, les instructions lecture-dépendante sont retirées de la fenêtre d'instruction, la copie de sauvegarde est devenue inutile et est donc jetée. ===La logique de sélection : âge ou position ?=== La logique de sélection est primordiale pour de bonnes performances. Il existe deux méthodes principales pour sélectionner l'instruction à exécuter. La première est la plus simple : elle se base sur lé numéro de l'entrée. En effet, une fenêtre d'instruction est avant tout une sorte de mémoire, un mix entre mémoire associative, mémoire RAM, et FIFO. Et chaque entrée a un numéro, une adresse mémoire. Nous parlerons de numéro dans ce qui suit, car ce sera plus simple, le terme d'adresse mémoire étant peut-être un peu exagéré dans le contexte des fenêtres d'instruction. Toujours est-il que la fenêtre d'instruction est adressable dans le sens où on peut lui envoyer le numéro de l'entrée voulue, et la fenêtre d’instruction renvoie le contenu de l'entrée sur son port de lecture. Et c'est ce que fait la logique de sélection : elle génère le numéro de l'entrée à lire. Le numéro est alors envoyé sur l'entrée d'adresse de la fenêtre d’instruction, et elle fournit la micro-opération associée sur son port de lecture, son '''port d'émission'''. La première méthode de sélection, donc. Elle est basée sur sur le numéro de l'entrée. Si plusieurs entrées sont éveillées, la logique de sélection prend celle avec le plus petit numéro. Elle porte le nom de '''sélection par position''', sous-entendu position dans la fenêtre d'instruction. Vous l'avez peut-être deviné, mais la logique de sélection est alors un encodeur à priorité. Le circuit de sélection ne se résume donc pas seulement à un encodeur à priorité, mais c'est le circuit central. L'avantage d'une telle méthode de sélection est qu'elle est simple à implémenter : un encodeur à priorité est un circuit connu, facile à implémenter. Mais on remarque un défaut : un encodeur est un circuit assez rapide, mais qui utilise beaucoup de transistors, beaucoup de portes logiques, surtout si on veut qu'il soit rapide. Ce qui explique que la logique de sélection ait son propre étage de pipeline rien que pour elle. La seconde méthode s'appelle la '''sélection par âge''', au nom assez transparent. L'idée est de privilégier l'émission de l'instruction la plus ancienne. Elle demande que la fenêtre d'instruction trie les micro-opérations par ordre d'insertion dans la fenêtre d'instruction, ce qui en fait une pseudo-FIFO. Le tri est partiel, car les instructions peuvent sortir de la fenêtre d’instruction à tout moment. Compacter la fenêtre d'instruction, à savoir regrouper toutes les entrées valides est une idée, mais elle est compliquée à implémenter. Aussi, elles préfèrent encoder des informations sur l'ordre d'émission dans chaque entrée. L'encodeur à priorité doit alors travailler non pas sur des nombres entiers liés à l'ordre d'insertion dans la pseudo-FIFO. Elle est encore plus gourmande en circuits que la méthode précédente. Les processeurs haute performance utilisent souvent des méthodes hybrides. Par exemple, les processeurs AMD de microarchitecture Bulldozer utilisaient une méthode intermédiaire. Ils utilisaient une fenêtre d'instruction couplée à un encodeur à priorité pour la sélection par position, mais complémentaient le tout avec une unité qui mémorisait l'instruction la plus ancienne dans la fenêtre d’instruction. Le mécanisme de sélection par âge était utilisé en priorité. Mais si l'instruction la plus ancienne n'était pas prête, le processeur basculait sur le mécanisme de sélection par position. ===La compaction des fenêtres d'instruction=== À chaque cycle, les instructions décodées sont ajoutées dans la fenêtre d'instruction, dans des entrées vides. Vu que les instructions quittent celle-ci dans le désordre, ces vides sont dispersés dans la fenêtre d'instruction, ce qui pose problème pour déterminer où placer les nouvelles instructions. La solution la plus triviale consiste à conserver une liste des vides, mise à jour à chaque insertion ou émission d'instruction. Une autre solution consiste à éliminer les vides en compactant la fenêtre d'instruction à chaque cycle d'horloge. Des circuits se chargent de détecter les vides et de regrouper les instructions en un unique bloc. Il faut signaler que certaines processeurs arrivent à se passer de cette étape de compactage, mais au prix de fenêtres d'instruction nettement plus complexes. Autre problème : quand il faut choisir quelle instruction émettre, il y a toujours plusieurs candidats. Si on choisit mal, des instructions restent en attente trop longtemps parce que d'autres instructions plus jeunes leur passent devant. Pour éviter cela, les instructions les plus vielles, les plus anciennes, sont prioritaires. Pour cela, on peut utiliser une FIFO un peu spéciale pour la fenêtre d'instruction. Si les ajouts d'instruction se font dans l'ordre, les instructions ne quittent pas forcément la fenêtre d'instruction dans l'ordre imposé par une FIFO : les instructions restent triées dans leur ordre d'ajout, même s'il y a des vides entre elles. Dans ces condition, il est préférable que le compactage conserve l'ordre FIFO des instructions. Dans ces conditions, l'instruction la plus ancienne est celle qui est située à l'adresse la plus faible : le circuit de sélection peut donc être fabriqué avec des encodeurs, et est relativement simple. ==Les fenêtres d'instruction basées sur une matrice de dépendances== L'implémentation la plus simple étend le fonctionnement d'un pipeline dynamique usuel. Rappelez-vous le chapitre sur les pipeline dynamiques. Nous avions vu que de tels pipelines émettaient une instruction par cycle, quitte à émettre des bulles de pipeline en cas de dépendance bloquante. Et il est possible d'améliorer leur unité d'émission pour qu'elle soit compatible avec l'exécution dans le désordre. ===Rappels sur le registre de réservation/disponibilité=== L'émission d'une instruction est gouvernée par un ''registre de réservation'' qui indique quels registres sont réservés par une instruction, et ceux qui sont libres. Un registre réservé est un registre qui sera écrit par une instruction en cours d'exécution, mais qui n'a pas encore écrit son résultat. Les instructions candidates doivent avoir leurs opérandes dans des registres libres. Sinon, c'est signe que leurs opérandes sont réservées en écriture, donc pas encore écrites, donc pas disponibles. Si une instruction candidate veut lire ce registre, c'est signe qu'il y a une dépendance RAW : elle veut lire un registre réservé, qui est destiné à être écrit par une instruction en vol. Si elle veut écrire, c'est signe qu'elle veut écrire dans un registre où une autre instruction veut écrire : c'est une dépendance WAW. Dans les deux cas, l'instruction n'est pas émise. Le registre de réservation encode les registres réservés comme suit : chaque bit est associé à un registre. Le bit numéro 0 est associé au registre numéro 0, le bit numéro 1 au registre numéro 1, etc. Là, En clair, les numéros de registres réservés sont encodés en représentation non pas binaire, mais en représentation ''one-hot'' (vue au premier chapitre). {|class="wikitable" |+ Registre de réservation |- ! Registre 7 !! Registre 6 !! Registre 5 !! Registre 4 !! Registre 3 !! Registre 2 !! Registre 1 !! Registre 0 |- | 0 || 0 || 1 || 0 || 0 || 1 || 0 || 0 |} Avant d'émettre une instruction, l'unité d'émission extrait les registres opérande/destination et les convertis dans la même représentation que le registre de réservation, à savoir en représentation ''one-hot''. Le circuit de traduction binaire vers ''one-hot'' est, pour rappel, un simple décodeur. Puis, on fait un OU logique entre les sorties des décodeurs. Le résultat est un masque qui indique quels registres sont lus par l'instruction, encodé en représentation ''one-hot''. Appelons-le le '''masque d'opérandes'''. Le masque est alors comparé au registre de réservation pour vérifier si l'instruction peut être émise. [[File:Unité d'émission simple, dans l'ordre.png|centre|vignette|upright=2|Unité d'émission simple, dans l'ordre]] Si l'émission est autorisée, le registres de réservation est là aussi mis à jour. Le registre de réservation est aussi mis à jour dès qu'une instruction enregistre son résultat dans les registres, ou alors dès qu'il est disponible pour le contournement. Le bit associé au registre repasse alors à 0 (ou à 1). Sans contournement, la mise à jour se fait alors à la toute fin de l'instruction, quand elle se termine, lors de la dernière étape d'enregistrement, à la fin de son pipeline. Avec, elle se fait quand l'instruction quitte l'unité de calcul. ===L'extension à l'exécution dans le désordre : l'éveil par matrice de bits=== La différence entre un pipeline dynamique et l'exécution dans le désordre est que l'on passe d'une instruction à émettre à plusieurs. Plusieurs instructions sont mises en attente dans une fenêtre d’instruction, et y attendent leur tour. L'idée est alors d'envoyer le registre de disponibilité à toutes les entrées, à toutes les instructions en attente. Ainsi, on sait quelles sont les instructions qui peuvent s'exécuter et celles qui ne le peuvent pas. L'implémentation est assez simple, elle ressemble beaucoup à l'implémentation d'un pipeline dynamique simple, si ce n'est que des circuits sont dupliqués. L'implémentation utilise des fenêtres d'instruction légèrement différentes de celles introduites plus haut. Elles n'utilisent notamment pas de bits de disponibilité, mais autre chose. Lorsqu'une instruction est ajoutée à la fenêtre d'instruction, le masque de disponibilité des opérandes est stocké dans la fenêtre d'instruction. A chaque cycle, le registre de disponibilité est envoyée à toutes les entrées, et est comparé avec tous les masques de disponibilité des opérandes. Si une comparaison renvoie un 1, alors l'instruction de l'entrée est une instruction candidate à l'émission. [[File:Unité d'émission dans le désordre basée sur un registre de disponibilité.png|centre|vignette|upright=2.5|Unité d'émission dans le désordre basée sur un registre de disponibilité]] L'ensemble est implémenté avec l'aide d'une '''matrice de bits''', où chaque ligne correspond à une entrée et chaque colonne à un registre. À chaque croisement entre une ligne et une colonne, on trouve un bit. Si le bit de la ligne n et de la colonne m est à 1, cela veut dire : l'instruction dans l'entrée n a besoin de lire le registre m. S’il est à 0, alors cela veut dire que l'instruction stockée dans la ligne n n'a pas besoin de la donnée dans le registre m. [[File:Planificateur à matrice de bits.jpg|centre|vignette|upright=2|Planificateur à matrice de bits.]] Lorsqu'une instruction réserve une entrée, elle initialise la ligne en fonction des registres qu'elle souhaite lire. Pour vérifier si une instruction a ses opérandes prêts, le processeur compare le registre de disponibilité à la ligne associée à l'instruction/entrée. A chaque intersection ligne-colonne, se trouve un comparateur de 1 bit, qui détecte si le registre est demandé et disponible. Les résultats de cette porte sont ensuite envoyés à une porte ET, qui fait le gros du travail. [[File:Logique de détection de la disponibilité d'une instruction.jpg|centre|vignette|upright=2|Logique de détection de la disponibilité d'une instruction.]] ==Les fenêtres d'instruction basées sur une mémoire associative== Les processeurs modernes utilisent une mémoire associative pour la fenêtre d'instruction. Les mémoires associatives ont été abordées il y a quelques chapitres, mais faisons quelques rappels. Les mémoires associatives servent à accélérer la recherche de données dans un ensemble. Or, une fenêtre d'instruction vérifie régulièrement si chaque entrée est prête. Il s'agit d'un processus de recherche d'une instruction qui respecte une condition bien précise dans la mémoire, ce qui fait que les mémoires associatives sont donc tout indiquées. Comme vous le savez, les signaux de commande d'une instruction sont propagés avec celle-ci dans le pipeline, le nom du registre de destination ne faisant pas exception. Le nom de registre est envoyé à la fenêtre d'instruction lors de l'écriture du résultat dans les registres. S'il y a correspondance, l'opérande est disponible et son bit de disponibilité est mis à 1. On peut adapter cette méthode pour tenir compte du contournement assez simplement. [[File:Détection des dépendances par propagation du registre de destination.png|centre|vignette|upright=2|Détection des dépendances par propagation du registre de destination.]] En conséquence, le circuit de détection des dépendances est constitué d'un grand nombre de comparateurs : un par champ « nom de registre » dans chaque entrée. La logique d'éveil/''wake up'' regroupe tous les comparateurs, la logique de sélection est un circuit situé en-dehors de la mémoire associative. Les entrées sont dans la mémoire associative elle-même. [[File:Gestion des bits de validité.png|centre|vignette|upright=2|Gestion des bits de validité.]] L'implémentation la plus simple est celle du schéma précédent, où on utilise une mémoire associative unique. Une version plus élaborée sépare la fenêtre d'instruction en deux parties : une mémoire qui mémorise les registres des opérandes, une autre mémoire pour le reste. La mémoire pour les registres opérandes est la mémoire associative proprement dite, c'est elle qui est associées aux comparateurs, à la logique de ''wake-up''/réveil, etc. Par contre, l'autre mémoire est une mémoire RAM simplifiée, qui mémorise les informations qui n'ont pas besoin des comparateurs. L'opcode de l'instruction est là-dedans, par exemple. ===Les optimisations de la consommation d'énergie : la désactivation des portions inutilisées=== Le problème avec des fenêtres d'instruction de ce type est leur forte consommation énergétique, ainsi que le grand nombre de portes logiques utilisées, qui deviennent prohibitif pour des fenêtres d'instruction un peu grosses. Pour résoudre ce problème, certains ont optimisé les comparateurs. D'autres ont tenté de profiter du fait que la majorité des bits dans les entrées sont composés de zéros. Bref, les optimisations purement matérielles sont légion. Une première solution est de désactiver les entrées qui sont inutilisées, vides, sans instruction. Pour cela, on fait précéder les comparateurs par un circuit qui les connecte ou déconnecte des lignes de bit. Le circuit est commandé par le bit ''empty'' qui indique si une entrée est vide ou non. L'avantage est que la consommation d'énergie de la fenêtre d'instruction devient alors proportionnelle au nombre d'entrées non-vides, et non au nombre d'entrées total. Du moins, en apparence, les entrées non-utilisées doivent quand même être alimentées pour fonctionner, mais l'activité de comparaison disparait dans les entrées vides. Il est possible d'étendre cette technique aux entrées dont les opérandes sont prêtes. Les gains sont généralement assez bons, avec une réduction de consommation variant entre 30 et 50%, avec une implémentation très simple et très économe en circuits. Une autre solution, assez simple à mettre en place, consiste à désactiver une partie de la fenêtre d'instruction sin elle est inutilisée. Pour cela, il faut segmenter la fenêtre d'instruction avec la technique du ''wire partitionning''. Pour rappel, une fenêtre d'instruction est une mémoire associative. Et comme toute mémoire associative, elle contient des fils, les lignes de bit, qui relient les entrées/sorties à toutes les cellules mémoire. Plus une ligne de bit est longue, plus elle consomme d'énergie et plus le temps de lecture/écriture est long. L'idée est de segmenter les lignes de bits en plaçant des répéteurs qui recopient la tension d'un segment au suivant. Les répéteurs sont des tampons trois-états, ce qui permet de déconnecter les portions inutilisées de la ligne de bit. Ce faisant, la fenêtre d'instruction est découpée en segments, qui peuvent être désactivés si besoin. Si il y a peu d'instructions chargées dans la fenêtre d'instruction, les portions inutilisées sont désactivées. La technique marche d'autan mieux si les instructions sont compactées au début de la fenêtre d'instruction. [[File:Wire partitionning.png|centre|vignette|upright=2|Wire partitionning]] Tout le problème est de savoir quelles portions désactiver. La technique est assez simple si la fenêtre d'instruction est compactée, à savoir si toutes les instructions sont régulièrement regroupées au début de la mémoire CAM. Mais même avec cette optimisation, la décision de désactiver une portion de la fenêtre d'instruction n'est pas à prendre à la légère. Il ne faut pas désactiver une portion contenant des instructions pouvant être émise sous peu. La décision dépend de paramètres variés : proportion d'entrée vides, quantité d'entrées récemment activées/désactivées récemment, présences d'entrées avec un ''match'' d'opérandes récent, etc. Il est important de préciser que les techniques en question fonctionnent aussi sur les autres types de fenêtre d'instruction, qui ne sont pas basées sur des mémoires associatives. Nous allons voir celles-ci dans la suite du chapitre, mais gardez à l'esprit que ces optimisations, à savoir désactiver les entrées vides/prêts et partitionner la fenêtre d'instruction, sont des optimisations générales qui marchent avec presque tout. ===L'ajout d'une FIFO pour les instructions déjà prêtes à l'émission=== D'autres techniques permettent de réduire aussi bien le cout en circuits que la consommation d'énergie de la fenêtre d'instruction. L'idée est d'utiliser une mémoire associative quand elle est réellement nécessaire, mais d'utiliser une fenêtre d'instruction "normale" dès que possible. La méthode la plus simple tient compte du fait que certaines instructions ont déjà toutes leurs opérandes de disponibles à l'émission, mais doivent quand même être mises en attente, parce que l'ALU adéquate est occupée, parce que des dépendances WAW/WAR sont encore là, ou pour tout autre raison. Dans ce cas, elles sont mises en attente non pas dans la fenêtre d'instruction, mais dans une mémoire FIFO toute simple. L'idée est qu'au lieu d'avoir une énorme mémoire associative pour la fenêtre d'instruction, on déplace quelques entrées dans une petite FIFO annexe. Le résultat est un gain en terme d'énergie et de circuits, au prix d'une perte de performance mineure. La perte de performance en question se manifeste si aucune instruction n'a ses opérandes de prêtes à l'émission : le programme n'utilise pas la FIFO et voit alors une fenêtre d'instruction plus petite. Une amélioration de cette technique tient compte du fait que certaines instructions sont dans un cas intermédiaire. Elles ont déjà une opérande de prête lors de l'émission, mais pas l'autre. Le nombre d'opérandes varie suivant l’instruction : certaines n'ont besoin que d'un seul opérande. De plus, il arrive qu'une opération tout juste décodée ait déjà un ou plusieurs de ses opérandes de prêts. Cette constatation permet d'éviter d'utiliser des comparateurs pour les opérandes déjà prêts. Par exemple, on peut parfaitement utiliser trois fenêtres d'instruction : * une pour les instructions dont tous les opérandes sont prêts, mais qui sont quand même mises en attente, sans comparateur ; * une pour les instructions dont un seul opérande manque, qui n'utilise qu'un comparateur par entrée ; * une pour les instructions dont deux opérandes manquent à l'appel, qui utilise deux comparateurs par entrée. C'est beaucoup plus économique que d'utiliser une seule grosse fenêtre d'instruction qui contiendrait autant d'entrées que les trois précédentes réunies, avec deux comparateurs par entrée. Certains sont même allés plus loin, et ont proposé de supprimer la fenêtre d'instruction avec deux opérandes par entrée. Les instructions dont deux opérandes sont inconnus au décodage sont stockées dans la fenêtre d'instruction pour instructions avec un comparateur par entrée. Un circuit de prédiction se charge alors de prédire l'opérande manquant, cette prédiction étant vérifiée plus loin dans le pipeline. Il serait cependant étonnant qu'une telle proposition ait donné lieu à la moindre implémentation réelle. ===Les optimisations de la consommation d'énergie avancées=== D'autres chercheurs ont conservé une fenêtre d'instruction unique, avec autant de comparateurs par entrée qu'il y a d'opérandes possibles par instruction. Simplement, le processus de détection des opérandes prêts est légèrement ralenti : on ne vérifie qu'un opérande par cycle. Pour vérifier les deux opérandes d'une entrée, on doit attendre deux cycles. Enfin, certains chercheurs ont proposé des fenêtres d'instruction segmentées. Les instructions circulent à chaque cycle d'un segment vers le suivant : en conséquence, certains segments conservent les instructions les plus anciennes, un autre les instructions les plus jeunes, etc. Seul le denier segment, celui qui contient les instructions les plus vielles, peut émettre une instruction : la détection des opérandes se fait seulement dans le dernier segment, qui contient les instructions les plus anciennes. On économise ainsi beaucoup de comparateurs. Certains chercheurs ont tenté de pipeliner l'étape de sélection des opérandes, ainsi que l'étage d'arbitrage. Mais en faisant cela, il faut plusieurs cycles pour détecter qu'une instruction a ses opérandes prêts, ce qui pose problème face à de nombreuses dépendances RAW. Pour éviter de trop perdre en performances, certains chercheurs ont décidé d'utiliser des techniques pour prédire quelles seront les instructions dont les opérandes seront bientôt prêts. Si détecter qu'une instruction est prête prend n cycles, le processeur devra tenter de prédire la future disponibilité des opérandes n cycles en avance pour obtenir des performances optimales. ===Remplacer la mémoire associative par une RAM=== Une autre optimisation possible est de remplacer la fenêtre d'instruction par une mémoire RAM, dont chaque mot mémoire correspondrait à une entrée. Une telle optimisation permet en théorie de se passer des comparateurs associés à chaque entrée, mais au prix de l'ajout de circuits annexes potentiellement couteux. La première de ces techniques, la '''recherche directe par étiquette''' (direct tag search) fut créée par Weiss et son collègue Smith. Ils cherchaient à améliorer l'algorithme de Tomasulo, un algorithme qu'on expliquera dans quelques chapitres. Rappelons que chaque instruction produit un résultat, qui devra être rapatrié dans une ou plusieurs entrées de la fenêtre d'instruction. L'optimisation de la recherche directe par étiquette fonctionne dans le cas où le résultat de l'instruction n'est utilisé que par une seule entrée, et pas plusieurs. Le principe est simple : chaque champ « opérande » d'une entrée est adressable via le nom de registre de cette opérande. Pour faire le lien entre entrée et nom de registre, la recherche directe par étiquette ajoute une table de correspondances matérielle, une mémoire RAM qui mémorise les adresses des champs « opérande » des entrées. Les adresses envoyées dans cette mémoire sont les noms de registres des résultats. Lors de l'émission, la table de correspondances est mise à jour. Les numéros des champs « opérande » réservés lors de l'émission sont mémorisés dans les mots mémoire qui correspondent aux deux registres sources. Toutefois, une petite vérification est faite lors de l'émission : si il y a déjà une correspondance dans la table pour un registre source, alors une autre instruction compte lire ce registre. Pour éviter d'écraser les données de l'instruction précédente dans la table de correspondances, l'émission de l'instruction est bloquée. [[File:Recherche directe par étiquette.png|centre|vignette|upright=2|Recherche directe par étiquette.]] ==Les fenêtres d’instruction avec préplanification== Avec la '''préplanification''' (''prescheduling''), la fenêtre d’instruction est composée de mémoires FIFO dans lesquelles les instructions sont triées dans l'ordre d'émission. Il n'y a pas de logique d’émission proprement dite, celle-ci se bornant à vérifier si l'instruction située au début de la FIFO peut s’exécuter. Par contre, le préplanificateur détecte les dépendances et en déduit où insérer les instructions dans le tampon d'émission, à l'endroit le plus adéquat. [[File:Préplanification.jpg|centre|vignette|upright=2|Préplanification.]] ===L'usage de FIFO multiples=== La technique de préplanification la plus simple utilise plusieurs FIFO. Quand une instruction a une dépendance avec une autre instruction, les deux sont placées dans la même FIFO. Pour cela, le préplanificateur détecte les chaines d'instructions dépendantes, et place les instructions dans la FIFO adéquate. A chaque cycle, l'unité d'émission lit une micro-opération dans chaque FIFO et vérifie si elle peut l'émettre. Si la micro-opération n'a pas ses opérandes disponibles, ou qu'une dépendance structurelle survient, alors la FIFO est bloquée. La micro-opération attend que la dépendance soit résolue, bloquant toutes les instructions précédentes. Mais les autres FIFO ne sont pas bloquées, laissant de la marge de manœuvre. [[File:Préplanification par FIFO multiples.png|centre|vignette|upright=1.5|Préplanification par FIFO multiples.]] ===La technique du tampon trié=== La technique du '''tampon trié''' trie les instructions selon le temps d'attente avant leur exécution. Les instructions qui sont censées s’exécuter bientôt sont insérées au tout début de la FIFO, tandis que les instructions qui s’exécuteront dans un long moment sont insérées vers la fin. Là encore, l'unité d'émission lit une micro-opération dans la FIFO, et détermine si elle peut être émise. Si une dépendance survient, l'émission est retardée, et la FIFO est bloquée. [[File:Préplanification par tampon trié.png|centre|vignette|upright=1.5|Préplanification par tampon trié.]] La technique a cependant quelques problèmes assez importants. Le premier problème est que la FIFO est bloquée lorsqu'une micro-opération ne peut être émise. Le second problème est que le temps avant exécution n'est pas toujours connu, notamment pour les instructions d'accès mémoire. Et cela se répercute sur les instructions dépendantes de celles-ci. Pour résoudre ce genre de problèmes, l'usage d'un pipeline à ''replay'' est possible, et est même l'une des meilleures solution possible, malgré ses défauts. L'idée est que les lecture sont pré-planifiées en supposant qu'elles font un succès de cache L1. Si la prédiction est fausse, la lecture est ré-exécutée plusieurs cycles plus tard, en supposant qu'elle fait un succès dans le cache L2, et ainsi de suite. Elle est alors ré-insérée dans la FIFO, elle est pré-planifiée une seconde fois. Il en est de même si une micro-opération ne peut pas être émise : il suffit de la réinsérer dans la FIFO au bon endroit, en attendant que ses dépendances soient résolus. Ainsi, l'instruction fautive ne bloque pas la fenêtre d’instruction, et retente sa chance autant de fois qu'il le faut. [[File:Préplanification par fenêtre d’instruction scorebarodée.png|centre|vignette|upright=1.5|Préplanification par fenêtre d’instruction scorebarodée.]] Une autre solution utilise deux fenêtres d’instruction : une FIFO gérée par la préplanification, et une vraie fenêtre d'instruction pour les instructions dont le temps d'attente ne peut pas être déterminé. Il est possible de mettre cette dernière avant la préplanification, afin de gérer les temps d'attente des instructions d'accès mémoire. Quand le temps d'attente d'une lecture devient connu, ses instructions dépendantes sont gérées avec préplanification. [[File:Préplanification avec fenêtre d’instruction.png|centre|vignette|upright=2.5|Préplanification avec fenêtre d’instruction.]] ===Les fenêtres d'instruction avec allocation temporelle statique=== L''''allocation temporelle statique''' correspond à une technique utilisée sur les processeurs Cuzco de l'entreprise Condor. La technique en question a été présenté en 2025, mais des idées similaires ont été présentées dans la littérature académique. Elle ressemble beaucoup aux techniques de pré-planification, avec cependant quelques différences. L'idée est simple : le processeur dispose de plusieurs fenêtres d'instruction, qui mettent en attente les micro-opérations. Lors de l'étape de renommage de registres, le processeur détermine dans combien de cycles d'horloge la micro-opération sera prête pour exécution. La micro-opération est alors mise en attente durant ce nombre de cycles, dans les fenêtres d'instruction, puis est émise une fois ce nombre de cycles écoulés. Ce faisant, les fenêtres d'instruction n'ont pas besoin de détecter la disponibilité des opérandes à chaque cycle, pour chaque micro-opération en attente. Le ''timing'' de l'émission des micro-opérations est décidé à l'avance. L'implémentation exacte n'est pas connue, mais plusieurs solutions sont imaginables. Par exemple, la fenêtre d'instruction peut simplement être composée de plusieurs mémoires de petite taille, chacune contenant les micro-opérations destinées à être exécutées dans N cycles, N étant différent pour chaque mémoire. Une autre solution, plus réaliste, utilise une fenêtre d'instruction dans laquelle la micro-opération est couplée à des champs pour les opérandes, et un champ compteur. Le champ compteur est initialisé avec le nombre de cycles à attendre, et est décrémenté à chaque cycle d'horloge. Quand il atteint zéro, la micro-opération est émise. Vous remarquerez que la méthode ne marche que si toutes les micro-opérations prennent un nombre fixe de cycles d'horloge. Et autant c'est le cas pour les micro-opérations arithmétiques ou logiques, autant les accès mémoire ne rentrent pas dans ce cadre. En théorie, on ne sait pas combien de temps prendra un accès mémoire. Et cette incertitude se répercute sur les instructions dépendantes d'un accès mémoire. Pour éviter cela, le processeur réutilise un pipeline à ''replay'' tel que vu dans le chapitre précédent. L'unité de renommage de registre suppose que tout accès mémoire fait un succès de cache L1, et décide des ''timings'' d'émission sous cette hypothèse. Si une lecture subit un défaut de cache, elle est ré-exécutée, de même que toutes les instructions dépendantes. Pour cela, le registre de destination de la lecture est marqué comme invalide, grâce à un bit spécifique attaché au registre. Toute instruction qui lit une opérande invalide est elle aussi ré-executée de zéro. Pour simplifier, l'unité d'émission ressemble à une unité d'émission dans l'ordre, avec un registre de disponibilité, qu'on aurait amélioré pour aller au-delà de la simple détection des dépendances d'instruction. Pour déterminer les ''timings'' d'émission, à savoir quand émettre une micro-opération, le processeur utilise une unité d'émission à deux étages. Le premier étage est appelé le ''register scoreboard'', le second étage est appelé la ''Time Ressource Matrix''. Les deux étages communiquent entre eux, comme on va le voir, et leurs noms donnent une idée de ce qu'ils font. Le premier étage gère les dépendances de registres, le second gère les dépendances structurelles. Le premier étage est un registre de disponibilité amélioré, qui gère les dépendances de registre. Cet étage sait quand tel registre sera écrit, et donc que l'opérande écrite dedans sera disponible à partir de tel cycle d'horloge. Il le sait car l'étage suivant l'aura prévenu, mais laissons cela de côté pour le moment. Quand une micro-opération rentre dans cet étage, il vérifie les dépendances avec les registres et les micro-opérations antérieures. Vu qu'il sait quand les registres seront disponibles, il peut déterminer quand l'instruction pourra s'exécuter. Par exemple, si une micro-opération lit les deux registres R7 et R15, qui sont disponibles respectivement dans 5 et 7 cycles, le premier étage sait que la micro-opération devra attendre 7 cycles. Mais tout cela ne suffit pas à déterminer quand émettre une micro-opération. En effet, il fait aussi gérer les dépendances structurelles, ce qui est le boulot du second étage. Le second étage utilise pour cela une ''Time Ressource Matrix'', qui mémorise l'occupation de diverses "ressources", pour les 256 cycles d'horloge à venir. Les ressources en question sont les ports de lecture/écriture du banc de registre, les ALUs utilisées, si la micro-opération utilise l'unité mémoire, etc. Le second étage prend en entrée une micro-opération, détermine quelles "ressources" elle utilise, puis regarde leur disponibilité. Elle détecte alors les dépendances structurelles et détermine alors quand peut s'exécuter la micro-opération. Elle peut retarder l'émission de quelques cycles, si une dépendance structurelle est détectée. Une fois sortie du second étage, on sait quand la micro-opération va être émise, à quel cycle précisément. Et vu que la durée de l'instruction est fixe, on sait quand cette micro-opération va se terminer, quand son résultat sera disponible. Cela permet de mettre à jour la ''Time Ressource Matrix'', pour préciser que le port d'écriture sera occupé à tel moment. De plus, cette information est transmise au premier étage, qui sait alors quand est enregistré le résultat dans le registre de destination. C'est comme cela que le premier étage sait quand un registre est disponible : le second étage le prévient, quand il émet une instruction ! La ''Time Ressource Matrix''mémorise l'occupation des "ressources" pour les 256 cycles d'horloge à venir. Cependant, elle ne vérifie pas les dépendances pour les 256 cycles suivants. Quand elle reçoit une micro-opération, elle teste les dépendances structurelles pour seulement les 8 prochains cycles maximum. Si la micro-opération ne peut pas être émise pendant ces 8 cycles, le pipeline est bloqué, un ''pipeline stall'' est émis. Pour être plus précis, vu que le processeur peut décoder 8 micro-opérations en même temps, cela permet de ne consulter que 64 cycles d'horloge sur les 256. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les premiers processeurs Intel | prevText=Les premiers processeurs Intel | next=Le renommage de registres | nextText=Le renommage de registres }} </noinclude> a0f54079hbolb5w1mf2dz8mwmh0z65u 773588 773587 2026-09-29T17:33:16Z Mewtow 31375 /* La fenêtre d'instruction centralisée */ 773588 wikitext text/x-wiki Dans les chapitres précédents, nous avons parlé des techniques dites d''''émission dans l'ordre'''. L'idée est d’exécuter une nouvelle micro-opération à chaque cycle, dans des unités de calcul séparées. Les instructions sont émises consécutivement, mais les instructions s’exécutent en parallèle dans des unités de calcul séparées. Par contre, quand l'unité d'émission ne peut pas émettre une instruction, elle bloque tout le pipeline. Les instructions qui suivent sont elles aussi bloquées, elle doivent attendre leur tour, même si elles sont en capacité de s'exécuter. Les techniques d'exécution dans le désordre que nous allons voir dans ce chapitre corrigent ce point précis. Elles sont dites à '''émission dans le désordre'''. Elles se distinguent des précédentes sur un point précis : quand l'unité d'émission bloque l'émission d'une instruction, les instructions suivantes peuvent poursuivre. L'émission des instructions peut donc se faire dans le désordre, dans le sens où une instruction peut être émise alors qu'une instruction précédente ne l'est pas encore. L'avantage de l'émission dans le désordre est qu'une instruction s'exécute dès que ses opérandes sont disponibles. Par disponible, on veut dire présent soit dans le réseau de contournement, soit dans les registres. Le processeur détecte automatiquement quand les opérandes d'une instruction sont sont disponibles, et il l’exécute à ce moment là. Dès qu'une instruction a ses opérandes disponibles, elle est émise et exécutée. C'est là la seule contrainte : les dépendances WAR, WAW et autres sont gérées par un ROB ou toute autre technique d'exception précise, seules les dépendances RAW limitent l'exécution. Mais avant de poursuivre, quelques point niveaux terminologie : * L'émission dans le désordre est un terme parlant et assez précis. Malheureusement, la terminologie la plus utilisée par d''''exécution dans le désordre'''. Et nous utiliserons ce terme dans la suite du cours, histoire de ne pas trop dévier de la nomenclature habituelle. * Nous utiliserons parfois l'abréviation OOO pour parler d'exécution dans le désordre. L'abréviation est celle de ''Out Of Order Excution''. * Nous utiliserons aussi l'abréviation ''µop'' pour parler de micro-opération, ''µops'' au pluriels pour parler de plusieurs micro-opérations, ou des micro-opérations en général. L'exécution dans le désordre ne gére en effet que des µops, elle se situe après l'étape de décodage. Mais avant de poursuivre, précisons une chose importante : l'exécution dans le désordre traite les accès mémoire à part. La majorité des processeurs OOO assez anciens exécutent les accès mémoire dans l'ordre, seules les µops entières/flottantes/branchements sont exécutées dans le désordre. Les processeurs datant d'après les années 2010 sont capable d'exécuter les accès mémoire dans le désordre, mais l'implémentation en question est assez particulière. Un chapitre entier sera dédié à l'exécution dans le désordre des µops mémoire. Nous allons volontairement mettre de côté la gestion des accès mémoire dans ce chapitre. ==Les fenêtres d’instruction : généralités== [[File:File de micro-opération.png|vignette|upright=1|File de micro-opérations]] Pour décrire comment est implémentée l'émission dans le désordre, il faut commencer par parler des processeurs sans. Les processeurs sans exécution dans le désordre ont une unité d'émission qui bloque tout le pipeline dès qu'une µop ne peut pas être émise. Pour limiter l'impact de ce blocage, quelques rares processeurs incorporent une '''file de micro-opération''', une mémoire FIFO qui met en attente les µops. Vu que c'est une mémoire FIFO, les µops sont émises dans l'ordre, à savoir l'ordre d'ajout, dans l'ordre de décodage. Le schéma ci-dessous illustre une telle file d'attente couplée à un ''scoreboard''. Sur le principe, l'exécution dans le désordre améliore la file de µops sur un point : ce n'est plus une mémoire FIFO. Les µops sont insérées dans l'ordre, mais peuvent sortir dans le désordre (être émises dans le désordre). La file de µops devient alors une '''fenêtre d'instruction''', terme traduit directement de l'anglais ''instruction Window''. Terme assez trompeur, car elles mettent en attente des µops, pas des instructions. Elles peuvent émettre des µops dans le désordre, ce qui fait que si une µop bloque le pipeline, les µops suivantes peuvent être émises. Si je commence le paragraphe précédent par "sur le principe", c'est car certaines techniques d'OOO utilisent des files de µops normales. Notez le pluriel ! Il existe dans les grandes lignes 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! File de µops améliorée |- ! Une seule "file de µops" | ''Scoreboard'' | Fenêtre d'instruction centralisée |- ! Plusieurs "file de µops" | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | Fenêtre d'instruction décentralisée |} ===La fenêtre d'instruction centralisée=== L'implémentation la plus simple de l'OOO utilise une unique '''fenêtre d'instruction'''. Les instructions décodées sont accumulées dans la fenêtre d'instruction, où elles attendent que leurs opérandes soient disponibles. La fenêtre d'instruction sert donc de file d'attente. Mais elle contient aussi une unité d'émission, qui détecte quelles µops sont prêtes à être émises. L'unité d'émission et la fenêtre d'instruction sont fusionnées ensemble, elles forment un seul circuit. Mais nous allons dire qu'elles sont conceptuellement séparées pour le moment. A chaque cycle, l'unité d'émission consulte la fenêtre d'instruction pour voir quelles µops peuvent s'exécuter, lesquelles ont leur opérandes de disponibles. La fenêtre d'instruction doit spécialement être conçue pour, c'est une sorte de mémoire associative très complexe, comme on le verra dans ce qui suit. [[File:OOO Issue.png|centre|vignette|upright=2.5|Exécution dans le désordre avec une fenêtre d'instruction]] Une fois qu'une µop sort du décodeur d'instructions, elle est ajoutée en parallèle dans la fenêtre d'instruction et le ROB. La raison est que les µops quittent la fenêtre d'instruction dans le désordre, et qu'elles doivent être remises en ordre par la suite. Le ROB s'occupe de cette remise en ordre, mais il a besoin de savoir dans quel ordre les µops sont censées être, et cet ordre est celui du décodage. Aussi, pour remplir le ROB, la seule opportunité est en sortie de l'unité de décodage. Dans le cas où une instruction est décodée en plusieurs micro-opérations, elles sont toutes insérées en même temps dans la fenêtre d'instruction et le ROB, en tenant compte de leur ordre. [[File:Fenêtre d'instruction.png|centre|vignette|upright=2|Fenêtre d'instruction.]] Les micro-opérations mémoire sont à part des autres, pour diverses raisons. Une de ces raisons est que les dépendances de données sont classées en deux types : les dépendances de registre et les dépendances d'adresse. Et les deux sont fondamentalement différentes. Autant on peut détecter les dépendances de registre lors de l'émission, autant c'est plus compliqué avec les dépendances d'adresse. De plus, rappelons que si les lectures peuvent s'exécuter dans le désordre, les écritures doivent s'exécuter dans l'ordre, ou du moins en donner l'illusion. Pour cela, le processeur remet les écritures dans l'ordre avec une sorte de mini-ROB intégré à l'unité mémoire, appelée la file d'écriture. Elle complémente le ROB, qui lui ne gère que les écritures dans les registres, mais les deux collaborent. La file d'écriture envoie une écriture à la mémoire RAM quand le ROB lui dit que c'est bon, les instructions précédentes sont terminées ''dans l'ordre du programme''. Les processeurs assez anciens n'autorisaient pas d'exécution dans le désordre des accès mémoire. Pour cela, la fenêtre d'instruction ne mémorise pas de µops mémoire. L'unité mémoire est précédée par une file de micro-opérations séparée, pour forcer l'exécution dans l'ordre des accès mémoire. [[File:Processeur avec émission dans l'ordre des accès mémoire.png|centre|vignette|upright=2|Processeur avec émission dans l'ordre des accès mémoire]] Les processeurs modernes ajoutent des techniques d'exécution dans le désordre des accès mémoire, mais nous les verrons dans un chapitre dédié. Elles permettent d'utiliser une fenêtre d'instruction unique, qui mémorise aussi les µops mémoire. Si elles sont mises en place, l'unité mémoire n'a pas besoin de file de µops séparée. L'idée est que les dépendances de registre sont traitées par la fenêtre d'instruction, mais que l'unité mémoire gére les dépendances d'adresse. Les dépendances d'adresse sont gérées par des techniques de ''désambiguation mémoire'', qui auront droit à un chapitre dédié. Dans ce chapitre, on suppose que l'unité mémoire est précédée d'une file de micro-opération mémoire dédiée, rien que pour elle. ===Les fenêtres d'instruction décentralisées=== Une autre solution utilise plusieurs fenêtres d'instruction. Pour faire la différence avec l'usage d'une fenêtre d'instruction unique, nous allons parler de fenêtre d'instruction centralisée s'il n'y en a qu'une dans le processeur, de '''fenêtre d'instruction décentralisée''' s'il y en a plusieurs. Dans le cas général, chaque fenêtre d'instruction est associée à un type précis d'opération/instruction. La tendance moderne est d'utiliser une fenêtre d'instruction pour les instructions de calcul entières, une autre pour les flottantes. Il s'agit d'un choix simple et efficace, mais quelques processeurs font autrement, pour répondre à des contraintes très diverses. L'usage de fenêtres décentralisées simplifie la répartition des instructions sur les différentes unités de calcul. Par exemple, utiliser des fenêtres séparées pour les ALU et les FPU facilite la répartition des instructions de calcul sur les ALU. Une fenêtre centralisée demande de faire la différence entre instruction entière/flottante, puis de choisir sur quelle unité de calcul entière/flottante utiliser. Une fenêtre décentralisée fait les deux choix séparément : d'abord on envoie l'instruction dans la bonne fenêtre suivant si c'est une instruction flottante ou entière, et ensuite on gère la disponibilité des ALUs/opérandes. Et on peut adapter la même idée en séparant les unités d'accès mémoire des ALU entières, etc. Par contre, un défaut est que certaines fenêtres d'instruction peuvent être sous-utilisées. Par exemple, la station de réservation flottante est inutilisée si le programme n'exécute pas d'opérations flottantes. Ou encore, les fenêtres pour les accès mémoire peuvent être sous-utilisées, si le programme effectue peu d'accès mémoire relativement aux autres instructions. En fait, tout dépend de comment sont calibrées les fenêtres d'instruction et de la répartition des instructions dans le programme entre opérations entières, flottantes, mémoire. Par exemple, si un programma de deux fenêtres d'instructions identiques, une pour les calculs entiers et une autre pour les calculs flottants, elles ne seront utilisées à la perfection que si la moitié des instructions du programme fait des calculs flottants et l'autre des calculs entiers. Toute déviation par rapport à cette répartition idéale risque de laisser des entrées vides dans une fenêtre d’instruction. Un point important est que l'émission est découpée en deux étages avec des fenêtres d'instruction décentralisées. La première étape envoie l'instruction décodée vers la fenêtre d'instruction adéquate, la seconde gère l'émission proprement dit. La première est l'étage de ''dispatch'' qui envoie l'instruction dans la fenêtre d’instruction adéquate, selon que c'est une instruction flottante, entière, autre. La seconde est l'étage de ''scheduling'', qui gère la disponibilité des opérandes et des unités de calcul. En clair, on trie les instructions suivant leur type, suivant le type d'unité de calcul adéquate, puis on l'émet proprement dit. Faire ainsi a plusieurs avantages, avec cependant peu d'inconvénients. Lors de l'étape de ''dispatch'', l'instruction émise est ajoutée au tampon de réordonnancement, s'il existe. Sans cela, impossible de conserver l'ordre des instructions. Les instructions sont émises dans l'ordre au niveau de l'unité de ''dispatch'', pas au niveau de l'étage de ''scheduling''. Aussi, pour remplir le ROB, cela doit se faire au dernier moment où les instructions sont émises dans l'ordre, soit en sortie de l'unité de ''dispatch''. De plus, les micro-opérations mémoire sont traitées à part des autres, elles sont envoyées directement à l'unité mémoire. La gestion des calculs d'adresse est quelque peu complexe, mais ils peuvent être fait soit dans l'unité mémoire, soit dans les ALU entières, peu importe. Il y a aussi un système de contournement complexe entre ALU/FPU et unité mémoire, qui n'est pas représenté dans le schéma ci-dessous. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Il faut noter que quelques processeurs utilisent des méthodes intermédiaires entre les trois solutions précédentes. Par exemple, les processeurs AMD Zen utilisent une fenêtre d'instruction décentralisée un peu particulière. Les unités de calcul entières disposent d'une fenêtre d'instruction rien que pour elles, sur ce processeur. Les instructions flottantes sont quant à elles alimentées par une file de micro-opération, pas une fenêtre d'instruction ! La raison à ce choix est un compromis entre performance et cout en circuit. L'exécution dans le désordre est peu efficace sur les instructions flottantes, car les CPU n'ont que peu d'ALU flottantes séparées. Vu le cout en circuits d'une fenêtre d'instruction, les concepteurs du processeur ont préféré utiliser une file de micro-opération pour les opérations flottantes. ===L'usage de plusieurs files d'instruction=== Une dernière méthode d'OOO utilise plusieurs files de micro-opération. L'idée est qu'une fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement une file de micro-opération pour les opérations entières, une autre pour les opérations flottantes, une autre pour les accès mémoire. D'autres processeurs utilisent une file pour les accès mémoire et une autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. La présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que la technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si une dépendance bloque une FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans une autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer la disponibilité des registres. Quand un registre est lu ou écrit par une instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. La logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : une pour les instructions d'accès mémoire et une autre pour les autres instructions. Si jamais une instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de la lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'une est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est la file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. ===Avantages et inconvénients de chaque implémentation=== Un processeur contient soit une fenêtre d'instruction unique, soit plusieurs fenêtres d'instruction séparées. Typiquement, les fenêtres d’instruction séparées sont spécialisées, dans le sens où on a une fenêtre pour les instructions flottantes, une autre pour les instructions entières, une autre pour les accès mémoire, etc. Pour résumer, on a le choix entre une grosse fenêtre généraliste et plusieurs fenêtres spécialisées, sauf que la fenêtre centralisée est lente et complexe, contrairement aux fenêtres spécialisées. Les deux méthodes ont des inconvénients et des avantages différents. Dans les grandes lignes, l'avantage des fenêtres décentralisées est qu'elles sont plus petites qu'une grosse fenêtre d'instruction. Cela simplifie la gestion du contournement et de la répartition des instructions sur les unités de calcul, comme on le verra dans quelques paragraphes. Elles sont donc moins complexes et plus rapides. L'autre avantage, c'est qu'il est possible de démarrer l'exécution de plusieurs instructions simultanément : une instruction par fenêtre décentralisée, contre une par fenêtre d'instruction. Mais les fenêtres décentralisées sont souvent sous-utilisées, partiellement remplies, contrairement aux fenêtres d'instruction. Il arrive qu'une fenêtre d'instruction soit remplie, alors que les autres sont vides. Par exemple, prenons un processeur avec une fenêtre d'instruction reliée à la FPU, et une autre reliée aux autres ALUs. Si le processeur n'exécute que des opérations flottantes, la fenêtre reliée à la FPU sera pleine, alors que l'autre sera vide. L'exécution des instructions dans le désordre est alors limitée par la petite taille de la fenêtre, qui ne peut plus accepter de nouvelle instruction flottante. Avec une fenêtre unique, on n'aurait pas eu ce problème : on aurait eu une énorme fenêtre d'instruction remplie d'instruction flottante, au lieu d'une petite fenêtre spécialisée. Il est maintenant temps de voir en quoi sont faites les fenêtres d’instruction, qu'elles soient centralisées ou décentralisées. Nous allons aussi voir quelle est la logique d'émission associée. ==L'implémentation d'une fenêtre d'instruction : généralités== Une fenêtre d'instruction est une mémoire qui mémorise des micro-opérations. Elle est cependant plus complexe qu'une mémoire RAM ou qu'une FIFO et ressemble un petit peu à une mémoire cache. Elle dispose d'un port d'écriture et d'un port de lecture, au minimum. Le port d'écriture permet à l'unité de décodage d'insérer une micro-opération dedans, d'ajouter la micro-opération qui vient d'être décodée. Si une instruction machine est décodée en plusieurs micro-opération, deux possibilités. La première est de les insérer un par un, ce qui fait qu'on peut se contenter d'un seul port d'écriture. L'autre possibilité est de les ajouter en même temps, ce qui demande plusieurs ports d'écriture. Le port de lecture sert à émettre une instruction. On part du principe que la fenêtre d'instruction ne peut émettre qu'une seule instruction à la fois, car les processeurs que nous avons vu précédemment sont de ce type. Mais nous verrons dans quelques chapitre qu'il existe des processeurs dits superscalaires, qui sont capables d'émettre plusieurs instructions par cycle. Dans ce cas, la fenêtre d'instruction a un seul port de lecture. Un processeur superscalaire, quant à lui, doit avoir un port de lecture par unité de calcul, ce qui fait beaucoup plus. ===Les entrées d'une fenêtre d’instruction=== Les fenêtres d'instruction sont composées d''''entrées''', des mots mémoire qui stockent une instruction. Une instruction réserve une entrée après son décodage et la libère dès qu'elle est envoyée aux unités de calcul. Une entrée contient l'opcode (les signaux de commande à envoyer à l'ALU), le registre de destination du résultat, les registres de chaque opérande, et éventuellement des signaux de commande en plus. De plus, chaque opérande est couplée à un bit de disponibilité, qui indique si elle est disponible. Quand un opérande est écrit dans les registres, le bit de présence correspondant est mis à jour. Enfin, chaque entrée possède un bit ''empty'' qui indique si elle est vide, cette information étant utile pour réserver des entrées. [[File:Entrée d'une station de réservation - sans les tags.png|centre|vignette|upright=3|Entrée d'une fenêtre d'instruction]] Nous verrons dans quelques chapitres que certaines fenêtres d'instruction sont capables de mémoriser les opérandes des instructions. De telles fenêtres d'instruction seront appelées, dans ce cours, des '''stations de réservation'''. Les entrées des stations de réservation sont assez semblables à celle des fenêtres d'instruction, à un détail près : les opérandes de l'instruction sont enregistrées directement dans des champs séparés. Il y a deux champs, un par opérande, pour stocker l'opérande elle-même, lue depuis les registres ou obtenue via le réseau de contournement. Notons que les champs pour les opérandes viennent en plus des champs pour les noms de registres, encore que les deux peuvent être fusionnés si on veut optimiser le tout. [[File:Entrée d'une station de réservation.png|centre|vignette|upright=3|Entrée d'une station de réservation.]] Précisons que la terminologie n'est pas très fiable. Les termes "fenêtre d'instruction" et "station de réservation" ne regroupent pas du tout la même chose d'un papier de recherche à l'autre, d'un bouquin à l'autre, d'un chercheur à l'autre, d'un ingénieur à l'autre, d'un professeur à l'autre. Le terme initial vient pourtant de l'article original sur l'algorithme de Tomasulo, où il désignait une fenêtre d'instruction associée à une unité de calcul précise. Mais le terme a ensuite été réutilisé, ce qui fait que certains processeurs avec plusieurs unités de calcul sont décrit comme ayant une unique station de réservation. En bref : c'est le bazar ! Mais nous en reparlerons dans le chapitre sur le renommage de registres, car c'est la place idéale pour les aborder. Toujours est-il que j'ai fait le choix de confondre les concepts de fenêtre d'instruction et de station de réservation avec les concepts de '''lecture avant émission''' et de '''lecture après émission'''. La différence entre les deux est que les registres sont lus après émission avec une fenêtre d'instruction, avant avec des stations de réservation. Dans le cas "avant émission", les opérandes sont mémorisées dans la station de réservation. Et cette différence a une influence sur le pipeline du processeur, le banc de registres et tout ce qui s'en suit. Un désavantage de la lecture avant émission est qu'il faut stocker les opérandes après lecture, ici dans les stations de réservation. Mais un avantage est que le banc de registre a besoin de moins de ports de lecture, car une bonne partie des opérandes sont fournies par le système de contournement. Nous verrons cela dans le détail dans le chapitre sur les processeurs superscalaires. Il a été proposé de fusionner le tampon de ré-ordonnancement avec la fenêtre d'instruction dans une structure unique. La méthode a notamment été utilisée sur les processeurs d'architecture K6 d'AMD. Le tout donnait une structure appelée le '''DRIS''' (''deferred scheduling register renaming instruction shelf''). La différence avec une fenêtre d’instruction normale est que les entrées sont libérée non pas quand l'instruction est exécutée/émise, mais quand elle termine son exécution et quitte le ROB. La fenêtre d'instruction doit alors incorporer des bits pour savoir si telle entrée a émis sont instruction ou non. ===La logique d'éveil et de sélection=== Dans le cas qui va suivre, on suppose que le processeur ne peut émettre qu'une instruction à la fois. Chaque cycle, une instruction est sélectionnée et est envoyée dans le chemin de données, soit à une ALU, soit à une unité d'accès mémoire. La sélection d'une instruction est effectuée par l'unité d'émission, qui est aussi appelée le '''''scheduler'''''. Elle gère la disponibilité des opérandes et la disponibilité des unités de calcul adéquate. Le choix de l'instruction émise doit être le plus pertinent possible, pour des raisons de performances. Pour le premier point, l'unité d'émission détermine quelles instructions sont candidates pour l'émission. Les ''instructions candidates'' sont celles dont tous les opérandes sont prêts. Le processeur contient un circuit qui détecte les instructions candidates : la '''logique d’éveil''' (''wake-up logic''). Une fois que la logique d'éveil a fait son travail, une instruction est choisie pour s’exécuter en fonction de la disponibilité des unités de calcul adéquates. Ce rôle est dévolu à un circuit qu'on appelle la '''logique de sélection''', ou ''select logic''. [[File:Fonctionnement complet de la logique d’émission.jpg|centre|vignette|upright=1.5|Fonctionnement complet de la logique d’émission.]] La logique de sélection doit gérer le fait que les unités de calcul du processeur ne sont pas toutes identiques. Déjà, un processeur a généralement des unités séparées pour les instructions entières et flottantes, des unités spécialisées dans les accès mémoire, parfois des unités spécialisées pour les branchements. Une instruction doit être attribuée à la bonne unité de calcul, on ne doit pas envoyer une instruction entière dans une unité de calcul flottante. De plus, parmi les unités de calcul entières, toutes ne sont pas identiques. Par exemple, il est fréquent d'avoir plusieurs unités de calcul spécialisées dans les opérations simples (additions, soustractions, opérations logiques) avec une unité pour les multiplications/divisions séparées, parfois une unité spécialisée pour les décalages/rotations, etc. Là encore, allouer la bonne instruction à la bonne ALU est complexe. Plus les unités de calcul sont hétérogènes, plus la logique de sélection est compliquée. Les logiques d'éveil comme de sélection sont assez complexes. Comme on le verra plus bas, la logique de sélection la plus simple, qui gère une seule unité de calcul, est basée sur un encodeur à priorité couplé à d'autres circuits. Et pour gérer plusieurs ALUs, il faut mettre des encodeurs en cascade. Le résultat est que même en prenant une logique de sélection simple, elle sera assez lente et gourmande en circuits. Aussi, la logique de sélection met souvent un cycle d'horloge entier pour faire son travail, elle a son propre étage de pipeline attribué. La logique d'éveil est dans le même cas, ce qui fait qu'émettre une micro-opération demande deux cycles d'horloge. Le défaut est que cela rajoute des cycles d'horloges entre la fenêtre d'instruction et l'ALU, ce qui complique la gestion du pipeline. Ces cycles de retard sont à prendre en compte au moment d'émettre les instructions, les ''scheduler'' doit en tenir compte pour des performances optimales. Sans tenir compte de ces cycles de retard, les instructions arrivent en retard de quelques cycles à l'ALU, cycles de retard durant lesquels l'ALU n'a pas fait de calcul et a été sous-utilisée, sans compter que le système de contournement n'est pas utilisé au mieux. Et le problème est encore plus important sur les processeur avec des stations de réservation, qui utilisent la "lecture après émission" : cela rajoute un cycle d'horloge en plus, un temps de retard en plus. ===La logique d'éveil : l'émission anticipée=== La logique d'éveil doit tenir compte du fait qu'il y a plusieurs étages entre l'émission et l'exécution sur une unité de calcul. Par exemple, un processeur a souvent entre un et à cinq étages entre la file d'attente et les unités de calcul. Il faut lire les registres, gérer le contournement, et cela peut prendre quelques cycles d'horloge. Sur le Pentium 4, on trouve 6 étages entre la fenêtre d’instruction et l'entrée de l'ALU. Si les micro-opérations sont émises quand les opérandes sont disponibles, il y aura un délai de quelques cycles avant qu'elles atteignent l'ALU. Alors qu'idéalement, on souhaiterait que la micro-opération atteigne l'ALU dès que ses opérandes sont disponibles, pour profiter des techniques de contournement. Pour cela, la logique d'éveil émet les instructions quelques cycles en avance pour qu'elles arrivent au bon moment. Il s'agit d'une technique d''''émission anticipée''', dont nous avions parlé dans le chapitre sur le contournement. : Il faut noter que le problème se pose plus avec des fenêtres d'instruction qu'avec des stations de réservation. Les premières ont un étage en plus entre émission et ALU, vu qu'il faut lire des registres après l'émission. L'émission anticipée demande d'émettre un signal d'éveil en avance de quelques cycles, pile au bon moment. Par exemples, si on a deux étages entre l'ALU et l'unité d'émission, le signal de réveil sera généré deux cycles avant que le résultat soit effectivement calculé. L'implémentation varie, mais deux solutions sont possibles. La première est de générer le signal d'éveil dans l'ALU, ce qui n'a de sens que pour les opérations comme les multiplications ou les divisions, qui prennent plusieurs cycles. Une autre technique génère le signal de réveil dans une structure centralisée, spécialisée dans la génération des signaux d'éveil. L'unité de composée d'un registre à décalage par registre. Imaginons qu'une instruction est émise, que cette instruction mette N cycles à s'exécuter, et qu'elle écrive dans un registre de destination. L'unité sélectionne alors le registre à décalage associé au registre de destination, et met le bit numéro N à 1. Le registre décalé d'un cran à chaque cycle. Quand le bit sortant est un 1, alors le signal de validité pour l'opérande est généré. L'émission anticipée marche bien si l'instruction a une durée fixe, connue à l'avance. Et autant c'est le cas pour les instructions arithmétiques et logiques, autant ce n'est pas le cas pour les accès mémoire. Les accès mémoire ont une latence variable : quelques cycles pour un succès de cache, plusieurs dizaines de cycles pour un défaut de cache L1, pas loin de la centaine pour un défaut de cache L2, etc. Et cela pose des problèmes pour l'émission anticipée. L'émission en avance pour les accès mémoire est purement spéculative : le processeur émet des instructions en supposant que la lecture entrainera un succès de cache, quitte à annuler l'instruction en cas de défaut de cache. Mais faire ainsi demande non seulement d'annuler les instructions émises en avance, mais aussi de ne pas retirer les instructions émises en avance de la fenêtre d'instruction. Elles sont émises, mais une copie de sauvegarde est conservée dans la fenêtre d'instruction. Si le processeur détecte un défaut de cache, il peut alors ré-exécuter l'instruction. S'il détecte un succès de cache, les instructions lecture-dépendante sont retirées de la fenêtre d'instruction, la copie de sauvegarde est devenue inutile et est donc jetée. ===La logique de sélection : âge ou position ?=== La logique de sélection est primordiale pour de bonnes performances. Il existe deux méthodes principales pour sélectionner l'instruction à exécuter. La première est la plus simple : elle se base sur lé numéro de l'entrée. En effet, une fenêtre d'instruction est avant tout une sorte de mémoire, un mix entre mémoire associative, mémoire RAM, et FIFO. Et chaque entrée a un numéro, une adresse mémoire. Nous parlerons de numéro dans ce qui suit, car ce sera plus simple, le terme d'adresse mémoire étant peut-être un peu exagéré dans le contexte des fenêtres d'instruction. Toujours est-il que la fenêtre d'instruction est adressable dans le sens où on peut lui envoyer le numéro de l'entrée voulue, et la fenêtre d’instruction renvoie le contenu de l'entrée sur son port de lecture. Et c'est ce que fait la logique de sélection : elle génère le numéro de l'entrée à lire. Le numéro est alors envoyé sur l'entrée d'adresse de la fenêtre d’instruction, et elle fournit la micro-opération associée sur son port de lecture, son '''port d'émission'''. La première méthode de sélection, donc. Elle est basée sur sur le numéro de l'entrée. Si plusieurs entrées sont éveillées, la logique de sélection prend celle avec le plus petit numéro. Elle porte le nom de '''sélection par position''', sous-entendu position dans la fenêtre d'instruction. Vous l'avez peut-être deviné, mais la logique de sélection est alors un encodeur à priorité. Le circuit de sélection ne se résume donc pas seulement à un encodeur à priorité, mais c'est le circuit central. L'avantage d'une telle méthode de sélection est qu'elle est simple à implémenter : un encodeur à priorité est un circuit connu, facile à implémenter. Mais on remarque un défaut : un encodeur est un circuit assez rapide, mais qui utilise beaucoup de transistors, beaucoup de portes logiques, surtout si on veut qu'il soit rapide. Ce qui explique que la logique de sélection ait son propre étage de pipeline rien que pour elle. La seconde méthode s'appelle la '''sélection par âge''', au nom assez transparent. L'idée est de privilégier l'émission de l'instruction la plus ancienne. Elle demande que la fenêtre d'instruction trie les micro-opérations par ordre d'insertion dans la fenêtre d'instruction, ce qui en fait une pseudo-FIFO. Le tri est partiel, car les instructions peuvent sortir de la fenêtre d’instruction à tout moment. Compacter la fenêtre d'instruction, à savoir regrouper toutes les entrées valides est une idée, mais elle est compliquée à implémenter. Aussi, elles préfèrent encoder des informations sur l'ordre d'émission dans chaque entrée. L'encodeur à priorité doit alors travailler non pas sur des nombres entiers liés à l'ordre d'insertion dans la pseudo-FIFO. Elle est encore plus gourmande en circuits que la méthode précédente. Les processeurs haute performance utilisent souvent des méthodes hybrides. Par exemple, les processeurs AMD de microarchitecture Bulldozer utilisaient une méthode intermédiaire. Ils utilisaient une fenêtre d'instruction couplée à un encodeur à priorité pour la sélection par position, mais complémentaient le tout avec une unité qui mémorisait l'instruction la plus ancienne dans la fenêtre d’instruction. Le mécanisme de sélection par âge était utilisé en priorité. Mais si l'instruction la plus ancienne n'était pas prête, le processeur basculait sur le mécanisme de sélection par position. ===La compaction des fenêtres d'instruction=== À chaque cycle, les instructions décodées sont ajoutées dans la fenêtre d'instruction, dans des entrées vides. Vu que les instructions quittent celle-ci dans le désordre, ces vides sont dispersés dans la fenêtre d'instruction, ce qui pose problème pour déterminer où placer les nouvelles instructions. La solution la plus triviale consiste à conserver une liste des vides, mise à jour à chaque insertion ou émission d'instruction. Une autre solution consiste à éliminer les vides en compactant la fenêtre d'instruction à chaque cycle d'horloge. Des circuits se chargent de détecter les vides et de regrouper les instructions en un unique bloc. Il faut signaler que certaines processeurs arrivent à se passer de cette étape de compactage, mais au prix de fenêtres d'instruction nettement plus complexes. Autre problème : quand il faut choisir quelle instruction émettre, il y a toujours plusieurs candidats. Si on choisit mal, des instructions restent en attente trop longtemps parce que d'autres instructions plus jeunes leur passent devant. Pour éviter cela, les instructions les plus vielles, les plus anciennes, sont prioritaires. Pour cela, on peut utiliser une FIFO un peu spéciale pour la fenêtre d'instruction. Si les ajouts d'instruction se font dans l'ordre, les instructions ne quittent pas forcément la fenêtre d'instruction dans l'ordre imposé par une FIFO : les instructions restent triées dans leur ordre d'ajout, même s'il y a des vides entre elles. Dans ces condition, il est préférable que le compactage conserve l'ordre FIFO des instructions. Dans ces conditions, l'instruction la plus ancienne est celle qui est située à l'adresse la plus faible : le circuit de sélection peut donc être fabriqué avec des encodeurs, et est relativement simple. ==Les fenêtres d'instruction basées sur une matrice de dépendances== L'implémentation la plus simple étend le fonctionnement d'un pipeline dynamique usuel. Rappelez-vous le chapitre sur les pipeline dynamiques. Nous avions vu que de tels pipelines émettaient une instruction par cycle, quitte à émettre des bulles de pipeline en cas de dépendance bloquante. Et il est possible d'améliorer leur unité d'émission pour qu'elle soit compatible avec l'exécution dans le désordre. ===Rappels sur le registre de réservation/disponibilité=== L'émission d'une instruction est gouvernée par un ''registre de réservation'' qui indique quels registres sont réservés par une instruction, et ceux qui sont libres. Un registre réservé est un registre qui sera écrit par une instruction en cours d'exécution, mais qui n'a pas encore écrit son résultat. Les instructions candidates doivent avoir leurs opérandes dans des registres libres. Sinon, c'est signe que leurs opérandes sont réservées en écriture, donc pas encore écrites, donc pas disponibles. Si une instruction candidate veut lire ce registre, c'est signe qu'il y a une dépendance RAW : elle veut lire un registre réservé, qui est destiné à être écrit par une instruction en vol. Si elle veut écrire, c'est signe qu'elle veut écrire dans un registre où une autre instruction veut écrire : c'est une dépendance WAW. Dans les deux cas, l'instruction n'est pas émise. Le registre de réservation encode les registres réservés comme suit : chaque bit est associé à un registre. Le bit numéro 0 est associé au registre numéro 0, le bit numéro 1 au registre numéro 1, etc. Là, En clair, les numéros de registres réservés sont encodés en représentation non pas binaire, mais en représentation ''one-hot'' (vue au premier chapitre). {|class="wikitable" |+ Registre de réservation |- ! Registre 7 !! Registre 6 !! Registre 5 !! Registre 4 !! Registre 3 !! Registre 2 !! Registre 1 !! Registre 0 |- | 0 || 0 || 1 || 0 || 0 || 1 || 0 || 0 |} Avant d'émettre une instruction, l'unité d'émission extrait les registres opérande/destination et les convertis dans la même représentation que le registre de réservation, à savoir en représentation ''one-hot''. Le circuit de traduction binaire vers ''one-hot'' est, pour rappel, un simple décodeur. Puis, on fait un OU logique entre les sorties des décodeurs. Le résultat est un masque qui indique quels registres sont lus par l'instruction, encodé en représentation ''one-hot''. Appelons-le le '''masque d'opérandes'''. Le masque est alors comparé au registre de réservation pour vérifier si l'instruction peut être émise. [[File:Unité d'émission simple, dans l'ordre.png|centre|vignette|upright=2|Unité d'émission simple, dans l'ordre]] Si l'émission est autorisée, le registres de réservation est là aussi mis à jour. Le registre de réservation est aussi mis à jour dès qu'une instruction enregistre son résultat dans les registres, ou alors dès qu'il est disponible pour le contournement. Le bit associé au registre repasse alors à 0 (ou à 1). Sans contournement, la mise à jour se fait alors à la toute fin de l'instruction, quand elle se termine, lors de la dernière étape d'enregistrement, à la fin de son pipeline. Avec, elle se fait quand l'instruction quitte l'unité de calcul. ===L'extension à l'exécution dans le désordre : l'éveil par matrice de bits=== La différence entre un pipeline dynamique et l'exécution dans le désordre est que l'on passe d'une instruction à émettre à plusieurs. Plusieurs instructions sont mises en attente dans une fenêtre d’instruction, et y attendent leur tour. L'idée est alors d'envoyer le registre de disponibilité à toutes les entrées, à toutes les instructions en attente. Ainsi, on sait quelles sont les instructions qui peuvent s'exécuter et celles qui ne le peuvent pas. L'implémentation est assez simple, elle ressemble beaucoup à l'implémentation d'un pipeline dynamique simple, si ce n'est que des circuits sont dupliqués. L'implémentation utilise des fenêtres d'instruction légèrement différentes de celles introduites plus haut. Elles n'utilisent notamment pas de bits de disponibilité, mais autre chose. Lorsqu'une instruction est ajoutée à la fenêtre d'instruction, le masque de disponibilité des opérandes est stocké dans la fenêtre d'instruction. A chaque cycle, le registre de disponibilité est envoyée à toutes les entrées, et est comparé avec tous les masques de disponibilité des opérandes. Si une comparaison renvoie un 1, alors l'instruction de l'entrée est une instruction candidate à l'émission. [[File:Unité d'émission dans le désordre basée sur un registre de disponibilité.png|centre|vignette|upright=2.5|Unité d'émission dans le désordre basée sur un registre de disponibilité]] L'ensemble est implémenté avec l'aide d'une '''matrice de bits''', où chaque ligne correspond à une entrée et chaque colonne à un registre. À chaque croisement entre une ligne et une colonne, on trouve un bit. Si le bit de la ligne n et de la colonne m est à 1, cela veut dire : l'instruction dans l'entrée n a besoin de lire le registre m. S’il est à 0, alors cela veut dire que l'instruction stockée dans la ligne n n'a pas besoin de la donnée dans le registre m. [[File:Planificateur à matrice de bits.jpg|centre|vignette|upright=2|Planificateur à matrice de bits.]] Lorsqu'une instruction réserve une entrée, elle initialise la ligne en fonction des registres qu'elle souhaite lire. Pour vérifier si une instruction a ses opérandes prêts, le processeur compare le registre de disponibilité à la ligne associée à l'instruction/entrée. A chaque intersection ligne-colonne, se trouve un comparateur de 1 bit, qui détecte si le registre est demandé et disponible. Les résultats de cette porte sont ensuite envoyés à une porte ET, qui fait le gros du travail. [[File:Logique de détection de la disponibilité d'une instruction.jpg|centre|vignette|upright=2|Logique de détection de la disponibilité d'une instruction.]] ==Les fenêtres d'instruction basées sur une mémoire associative== Les processeurs modernes utilisent une mémoire associative pour la fenêtre d'instruction. Les mémoires associatives ont été abordées il y a quelques chapitres, mais faisons quelques rappels. Les mémoires associatives servent à accélérer la recherche de données dans un ensemble. Or, une fenêtre d'instruction vérifie régulièrement si chaque entrée est prête. Il s'agit d'un processus de recherche d'une instruction qui respecte une condition bien précise dans la mémoire, ce qui fait que les mémoires associatives sont donc tout indiquées. Comme vous le savez, les signaux de commande d'une instruction sont propagés avec celle-ci dans le pipeline, le nom du registre de destination ne faisant pas exception. Le nom de registre est envoyé à la fenêtre d'instruction lors de l'écriture du résultat dans les registres. S'il y a correspondance, l'opérande est disponible et son bit de disponibilité est mis à 1. On peut adapter cette méthode pour tenir compte du contournement assez simplement. [[File:Détection des dépendances par propagation du registre de destination.png|centre|vignette|upright=2|Détection des dépendances par propagation du registre de destination.]] En conséquence, le circuit de détection des dépendances est constitué d'un grand nombre de comparateurs : un par champ « nom de registre » dans chaque entrée. La logique d'éveil/''wake up'' regroupe tous les comparateurs, la logique de sélection est un circuit situé en-dehors de la mémoire associative. Les entrées sont dans la mémoire associative elle-même. [[File:Gestion des bits de validité.png|centre|vignette|upright=2|Gestion des bits de validité.]] L'implémentation la plus simple est celle du schéma précédent, où on utilise une mémoire associative unique. Une version plus élaborée sépare la fenêtre d'instruction en deux parties : une mémoire qui mémorise les registres des opérandes, une autre mémoire pour le reste. La mémoire pour les registres opérandes est la mémoire associative proprement dite, c'est elle qui est associées aux comparateurs, à la logique de ''wake-up''/réveil, etc. Par contre, l'autre mémoire est une mémoire RAM simplifiée, qui mémorise les informations qui n'ont pas besoin des comparateurs. L'opcode de l'instruction est là-dedans, par exemple. ===Les optimisations de la consommation d'énergie : la désactivation des portions inutilisées=== Le problème avec des fenêtres d'instruction de ce type est leur forte consommation énergétique, ainsi que le grand nombre de portes logiques utilisées, qui deviennent prohibitif pour des fenêtres d'instruction un peu grosses. Pour résoudre ce problème, certains ont optimisé les comparateurs. D'autres ont tenté de profiter du fait que la majorité des bits dans les entrées sont composés de zéros. Bref, les optimisations purement matérielles sont légion. Une première solution est de désactiver les entrées qui sont inutilisées, vides, sans instruction. Pour cela, on fait précéder les comparateurs par un circuit qui les connecte ou déconnecte des lignes de bit. Le circuit est commandé par le bit ''empty'' qui indique si une entrée est vide ou non. L'avantage est que la consommation d'énergie de la fenêtre d'instruction devient alors proportionnelle au nombre d'entrées non-vides, et non au nombre d'entrées total. Du moins, en apparence, les entrées non-utilisées doivent quand même être alimentées pour fonctionner, mais l'activité de comparaison disparait dans les entrées vides. Il est possible d'étendre cette technique aux entrées dont les opérandes sont prêtes. Les gains sont généralement assez bons, avec une réduction de consommation variant entre 30 et 50%, avec une implémentation très simple et très économe en circuits. Une autre solution, assez simple à mettre en place, consiste à désactiver une partie de la fenêtre d'instruction sin elle est inutilisée. Pour cela, il faut segmenter la fenêtre d'instruction avec la technique du ''wire partitionning''. Pour rappel, une fenêtre d'instruction est une mémoire associative. Et comme toute mémoire associative, elle contient des fils, les lignes de bit, qui relient les entrées/sorties à toutes les cellules mémoire. Plus une ligne de bit est longue, plus elle consomme d'énergie et plus le temps de lecture/écriture est long. L'idée est de segmenter les lignes de bits en plaçant des répéteurs qui recopient la tension d'un segment au suivant. Les répéteurs sont des tampons trois-états, ce qui permet de déconnecter les portions inutilisées de la ligne de bit. Ce faisant, la fenêtre d'instruction est découpée en segments, qui peuvent être désactivés si besoin. Si il y a peu d'instructions chargées dans la fenêtre d'instruction, les portions inutilisées sont désactivées. La technique marche d'autan mieux si les instructions sont compactées au début de la fenêtre d'instruction. [[File:Wire partitionning.png|centre|vignette|upright=2|Wire partitionning]] Tout le problème est de savoir quelles portions désactiver. La technique est assez simple si la fenêtre d'instruction est compactée, à savoir si toutes les instructions sont régulièrement regroupées au début de la mémoire CAM. Mais même avec cette optimisation, la décision de désactiver une portion de la fenêtre d'instruction n'est pas à prendre à la légère. Il ne faut pas désactiver une portion contenant des instructions pouvant être émise sous peu. La décision dépend de paramètres variés : proportion d'entrée vides, quantité d'entrées récemment activées/désactivées récemment, présences d'entrées avec un ''match'' d'opérandes récent, etc. Il est important de préciser que les techniques en question fonctionnent aussi sur les autres types de fenêtre d'instruction, qui ne sont pas basées sur des mémoires associatives. Nous allons voir celles-ci dans la suite du chapitre, mais gardez à l'esprit que ces optimisations, à savoir désactiver les entrées vides/prêts et partitionner la fenêtre d'instruction, sont des optimisations générales qui marchent avec presque tout. ===L'ajout d'une FIFO pour les instructions déjà prêtes à l'émission=== D'autres techniques permettent de réduire aussi bien le cout en circuits que la consommation d'énergie de la fenêtre d'instruction. L'idée est d'utiliser une mémoire associative quand elle est réellement nécessaire, mais d'utiliser une fenêtre d'instruction "normale" dès que possible. La méthode la plus simple tient compte du fait que certaines instructions ont déjà toutes leurs opérandes de disponibles à l'émission, mais doivent quand même être mises en attente, parce que l'ALU adéquate est occupée, parce que des dépendances WAW/WAR sont encore là, ou pour tout autre raison. Dans ce cas, elles sont mises en attente non pas dans la fenêtre d'instruction, mais dans une mémoire FIFO toute simple. L'idée est qu'au lieu d'avoir une énorme mémoire associative pour la fenêtre d'instruction, on déplace quelques entrées dans une petite FIFO annexe. Le résultat est un gain en terme d'énergie et de circuits, au prix d'une perte de performance mineure. La perte de performance en question se manifeste si aucune instruction n'a ses opérandes de prêtes à l'émission : le programme n'utilise pas la FIFO et voit alors une fenêtre d'instruction plus petite. Une amélioration de cette technique tient compte du fait que certaines instructions sont dans un cas intermédiaire. Elles ont déjà une opérande de prête lors de l'émission, mais pas l'autre. Le nombre d'opérandes varie suivant l’instruction : certaines n'ont besoin que d'un seul opérande. De plus, il arrive qu'une opération tout juste décodée ait déjà un ou plusieurs de ses opérandes de prêts. Cette constatation permet d'éviter d'utiliser des comparateurs pour les opérandes déjà prêts. Par exemple, on peut parfaitement utiliser trois fenêtres d'instruction : * une pour les instructions dont tous les opérandes sont prêts, mais qui sont quand même mises en attente, sans comparateur ; * une pour les instructions dont un seul opérande manque, qui n'utilise qu'un comparateur par entrée ; * une pour les instructions dont deux opérandes manquent à l'appel, qui utilise deux comparateurs par entrée. C'est beaucoup plus économique que d'utiliser une seule grosse fenêtre d'instruction qui contiendrait autant d'entrées que les trois précédentes réunies, avec deux comparateurs par entrée. Certains sont même allés plus loin, et ont proposé de supprimer la fenêtre d'instruction avec deux opérandes par entrée. Les instructions dont deux opérandes sont inconnus au décodage sont stockées dans la fenêtre d'instruction pour instructions avec un comparateur par entrée. Un circuit de prédiction se charge alors de prédire l'opérande manquant, cette prédiction étant vérifiée plus loin dans le pipeline. Il serait cependant étonnant qu'une telle proposition ait donné lieu à la moindre implémentation réelle. ===Les optimisations de la consommation d'énergie avancées=== D'autres chercheurs ont conservé une fenêtre d'instruction unique, avec autant de comparateurs par entrée qu'il y a d'opérandes possibles par instruction. Simplement, le processus de détection des opérandes prêts est légèrement ralenti : on ne vérifie qu'un opérande par cycle. Pour vérifier les deux opérandes d'une entrée, on doit attendre deux cycles. Enfin, certains chercheurs ont proposé des fenêtres d'instruction segmentées. Les instructions circulent à chaque cycle d'un segment vers le suivant : en conséquence, certains segments conservent les instructions les plus anciennes, un autre les instructions les plus jeunes, etc. Seul le denier segment, celui qui contient les instructions les plus vielles, peut émettre une instruction : la détection des opérandes se fait seulement dans le dernier segment, qui contient les instructions les plus anciennes. On économise ainsi beaucoup de comparateurs. Certains chercheurs ont tenté de pipeliner l'étape de sélection des opérandes, ainsi que l'étage d'arbitrage. Mais en faisant cela, il faut plusieurs cycles pour détecter qu'une instruction a ses opérandes prêts, ce qui pose problème face à de nombreuses dépendances RAW. Pour éviter de trop perdre en performances, certains chercheurs ont décidé d'utiliser des techniques pour prédire quelles seront les instructions dont les opérandes seront bientôt prêts. Si détecter qu'une instruction est prête prend n cycles, le processeur devra tenter de prédire la future disponibilité des opérandes n cycles en avance pour obtenir des performances optimales. ===Remplacer la mémoire associative par une RAM=== Une autre optimisation possible est de remplacer la fenêtre d'instruction par une mémoire RAM, dont chaque mot mémoire correspondrait à une entrée. Une telle optimisation permet en théorie de se passer des comparateurs associés à chaque entrée, mais au prix de l'ajout de circuits annexes potentiellement couteux. La première de ces techniques, la '''recherche directe par étiquette''' (direct tag search) fut créée par Weiss et son collègue Smith. Ils cherchaient à améliorer l'algorithme de Tomasulo, un algorithme qu'on expliquera dans quelques chapitres. Rappelons que chaque instruction produit un résultat, qui devra être rapatrié dans une ou plusieurs entrées de la fenêtre d'instruction. L'optimisation de la recherche directe par étiquette fonctionne dans le cas où le résultat de l'instruction n'est utilisé que par une seule entrée, et pas plusieurs. Le principe est simple : chaque champ « opérande » d'une entrée est adressable via le nom de registre de cette opérande. Pour faire le lien entre entrée et nom de registre, la recherche directe par étiquette ajoute une table de correspondances matérielle, une mémoire RAM qui mémorise les adresses des champs « opérande » des entrées. Les adresses envoyées dans cette mémoire sont les noms de registres des résultats. Lors de l'émission, la table de correspondances est mise à jour. Les numéros des champs « opérande » réservés lors de l'émission sont mémorisés dans les mots mémoire qui correspondent aux deux registres sources. Toutefois, une petite vérification est faite lors de l'émission : si il y a déjà une correspondance dans la table pour un registre source, alors une autre instruction compte lire ce registre. Pour éviter d'écraser les données de l'instruction précédente dans la table de correspondances, l'émission de l'instruction est bloquée. [[File:Recherche directe par étiquette.png|centre|vignette|upright=2|Recherche directe par étiquette.]] ==Les fenêtres d’instruction avec préplanification== Avec la '''préplanification''' (''prescheduling''), la fenêtre d’instruction est composée de mémoires FIFO dans lesquelles les instructions sont triées dans l'ordre d'émission. Il n'y a pas de logique d’émission proprement dite, celle-ci se bornant à vérifier si l'instruction située au début de la FIFO peut s’exécuter. Par contre, le préplanificateur détecte les dépendances et en déduit où insérer les instructions dans le tampon d'émission, à l'endroit le plus adéquat. [[File:Préplanification.jpg|centre|vignette|upright=2|Préplanification.]] ===L'usage de FIFO multiples=== La technique de préplanification la plus simple utilise plusieurs FIFO. Quand une instruction a une dépendance avec une autre instruction, les deux sont placées dans la même FIFO. Pour cela, le préplanificateur détecte les chaines d'instructions dépendantes, et place les instructions dans la FIFO adéquate. A chaque cycle, l'unité d'émission lit une micro-opération dans chaque FIFO et vérifie si elle peut l'émettre. Si la micro-opération n'a pas ses opérandes disponibles, ou qu'une dépendance structurelle survient, alors la FIFO est bloquée. La micro-opération attend que la dépendance soit résolue, bloquant toutes les instructions précédentes. Mais les autres FIFO ne sont pas bloquées, laissant de la marge de manœuvre. [[File:Préplanification par FIFO multiples.png|centre|vignette|upright=1.5|Préplanification par FIFO multiples.]] ===La technique du tampon trié=== La technique du '''tampon trié''' trie les instructions selon le temps d'attente avant leur exécution. Les instructions qui sont censées s’exécuter bientôt sont insérées au tout début de la FIFO, tandis que les instructions qui s’exécuteront dans un long moment sont insérées vers la fin. Là encore, l'unité d'émission lit une micro-opération dans la FIFO, et détermine si elle peut être émise. Si une dépendance survient, l'émission est retardée, et la FIFO est bloquée. [[File:Préplanification par tampon trié.png|centre|vignette|upright=1.5|Préplanification par tampon trié.]] La technique a cependant quelques problèmes assez importants. Le premier problème est que la FIFO est bloquée lorsqu'une micro-opération ne peut être émise. Le second problème est que le temps avant exécution n'est pas toujours connu, notamment pour les instructions d'accès mémoire. Et cela se répercute sur les instructions dépendantes de celles-ci. Pour résoudre ce genre de problèmes, l'usage d'un pipeline à ''replay'' est possible, et est même l'une des meilleures solution possible, malgré ses défauts. L'idée est que les lecture sont pré-planifiées en supposant qu'elles font un succès de cache L1. Si la prédiction est fausse, la lecture est ré-exécutée plusieurs cycles plus tard, en supposant qu'elle fait un succès dans le cache L2, et ainsi de suite. Elle est alors ré-insérée dans la FIFO, elle est pré-planifiée une seconde fois. Il en est de même si une micro-opération ne peut pas être émise : il suffit de la réinsérer dans la FIFO au bon endroit, en attendant que ses dépendances soient résolus. Ainsi, l'instruction fautive ne bloque pas la fenêtre d’instruction, et retente sa chance autant de fois qu'il le faut. [[File:Préplanification par fenêtre d’instruction scorebarodée.png|centre|vignette|upright=1.5|Préplanification par fenêtre d’instruction scorebarodée.]] Une autre solution utilise deux fenêtres d’instruction : une FIFO gérée par la préplanification, et une vraie fenêtre d'instruction pour les instructions dont le temps d'attente ne peut pas être déterminé. Il est possible de mettre cette dernière avant la préplanification, afin de gérer les temps d'attente des instructions d'accès mémoire. Quand le temps d'attente d'une lecture devient connu, ses instructions dépendantes sont gérées avec préplanification. [[File:Préplanification avec fenêtre d’instruction.png|centre|vignette|upright=2.5|Préplanification avec fenêtre d’instruction.]] ===Les fenêtres d'instruction avec allocation temporelle statique=== L''''allocation temporelle statique''' correspond à une technique utilisée sur les processeurs Cuzco de l'entreprise Condor. La technique en question a été présenté en 2025, mais des idées similaires ont été présentées dans la littérature académique. Elle ressemble beaucoup aux techniques de pré-planification, avec cependant quelques différences. L'idée est simple : le processeur dispose de plusieurs fenêtres d'instruction, qui mettent en attente les micro-opérations. Lors de l'étape de renommage de registres, le processeur détermine dans combien de cycles d'horloge la micro-opération sera prête pour exécution. La micro-opération est alors mise en attente durant ce nombre de cycles, dans les fenêtres d'instruction, puis est émise une fois ce nombre de cycles écoulés. Ce faisant, les fenêtres d'instruction n'ont pas besoin de détecter la disponibilité des opérandes à chaque cycle, pour chaque micro-opération en attente. Le ''timing'' de l'émission des micro-opérations est décidé à l'avance. L'implémentation exacte n'est pas connue, mais plusieurs solutions sont imaginables. Par exemple, la fenêtre d'instruction peut simplement être composée de plusieurs mémoires de petite taille, chacune contenant les micro-opérations destinées à être exécutées dans N cycles, N étant différent pour chaque mémoire. Une autre solution, plus réaliste, utilise une fenêtre d'instruction dans laquelle la micro-opération est couplée à des champs pour les opérandes, et un champ compteur. Le champ compteur est initialisé avec le nombre de cycles à attendre, et est décrémenté à chaque cycle d'horloge. Quand il atteint zéro, la micro-opération est émise. Vous remarquerez que la méthode ne marche que si toutes les micro-opérations prennent un nombre fixe de cycles d'horloge. Et autant c'est le cas pour les micro-opérations arithmétiques ou logiques, autant les accès mémoire ne rentrent pas dans ce cadre. En théorie, on ne sait pas combien de temps prendra un accès mémoire. Et cette incertitude se répercute sur les instructions dépendantes d'un accès mémoire. Pour éviter cela, le processeur réutilise un pipeline à ''replay'' tel que vu dans le chapitre précédent. L'unité de renommage de registre suppose que tout accès mémoire fait un succès de cache L1, et décide des ''timings'' d'émission sous cette hypothèse. Si une lecture subit un défaut de cache, elle est ré-exécutée, de même que toutes les instructions dépendantes. Pour cela, le registre de destination de la lecture est marqué comme invalide, grâce à un bit spécifique attaché au registre. Toute instruction qui lit une opérande invalide est elle aussi ré-executée de zéro. Pour simplifier, l'unité d'émission ressemble à une unité d'émission dans l'ordre, avec un registre de disponibilité, qu'on aurait amélioré pour aller au-delà de la simple détection des dépendances d'instruction. Pour déterminer les ''timings'' d'émission, à savoir quand émettre une micro-opération, le processeur utilise une unité d'émission à deux étages. Le premier étage est appelé le ''register scoreboard'', le second étage est appelé la ''Time Ressource Matrix''. Les deux étages communiquent entre eux, comme on va le voir, et leurs noms donnent une idée de ce qu'ils font. Le premier étage gère les dépendances de registres, le second gère les dépendances structurelles. Le premier étage est un registre de disponibilité amélioré, qui gère les dépendances de registre. Cet étage sait quand tel registre sera écrit, et donc que l'opérande écrite dedans sera disponible à partir de tel cycle d'horloge. Il le sait car l'étage suivant l'aura prévenu, mais laissons cela de côté pour le moment. Quand une micro-opération rentre dans cet étage, il vérifie les dépendances avec les registres et les micro-opérations antérieures. Vu qu'il sait quand les registres seront disponibles, il peut déterminer quand l'instruction pourra s'exécuter. Par exemple, si une micro-opération lit les deux registres R7 et R15, qui sont disponibles respectivement dans 5 et 7 cycles, le premier étage sait que la micro-opération devra attendre 7 cycles. Mais tout cela ne suffit pas à déterminer quand émettre une micro-opération. En effet, il fait aussi gérer les dépendances structurelles, ce qui est le boulot du second étage. Le second étage utilise pour cela une ''Time Ressource Matrix'', qui mémorise l'occupation de diverses "ressources", pour les 256 cycles d'horloge à venir. Les ressources en question sont les ports de lecture/écriture du banc de registre, les ALUs utilisées, si la micro-opération utilise l'unité mémoire, etc. Le second étage prend en entrée une micro-opération, détermine quelles "ressources" elle utilise, puis regarde leur disponibilité. Elle détecte alors les dépendances structurelles et détermine alors quand peut s'exécuter la micro-opération. Elle peut retarder l'émission de quelques cycles, si une dépendance structurelle est détectée. Une fois sortie du second étage, on sait quand la micro-opération va être émise, à quel cycle précisément. Et vu que la durée de l'instruction est fixe, on sait quand cette micro-opération va se terminer, quand son résultat sera disponible. Cela permet de mettre à jour la ''Time Ressource Matrix'', pour préciser que le port d'écriture sera occupé à tel moment. De plus, cette information est transmise au premier étage, qui sait alors quand est enregistré le résultat dans le registre de destination. C'est comme cela que le premier étage sait quand un registre est disponible : le second étage le prévient, quand il émet une instruction ! La ''Time Ressource Matrix''mémorise l'occupation des "ressources" pour les 256 cycles d'horloge à venir. Cependant, elle ne vérifie pas les dépendances pour les 256 cycles suivants. Quand elle reçoit une micro-opération, elle teste les dépendances structurelles pour seulement les 8 prochains cycles maximum. Si la micro-opération ne peut pas être émise pendant ces 8 cycles, le pipeline est bloqué, un ''pipeline stall'' est émis. Pour être plus précis, vu que le processeur peut décoder 8 micro-opérations en même temps, cela permet de ne consulter que 64 cycles d'horloge sur les 256. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les premiers processeurs Intel | prevText=Les premiers processeurs Intel | next=Le renommage de registres | nextText=Le renommage de registres }} </noinclude> 5l6ophdb80ftkyu9af6ry0v81jvlbye 773589 773588 2026-09-29T17:37:15Z Mewtow 31375 /* La fenêtre d'instruction centralisée */ 773589 wikitext text/x-wiki Dans les chapitres précédents, nous avons parlé des techniques dites d''''émission dans l'ordre'''. L'idée est d’exécuter une nouvelle micro-opération à chaque cycle, dans des unités de calcul séparées. Les instructions sont émises consécutivement, mais les instructions s’exécutent en parallèle dans des unités de calcul séparées. Par contre, quand l'unité d'émission ne peut pas émettre une instruction, elle bloque tout le pipeline. Les instructions qui suivent sont elles aussi bloquées, elle doivent attendre leur tour, même si elles sont en capacité de s'exécuter. Les techniques d'exécution dans le désordre que nous allons voir dans ce chapitre corrigent ce point précis. Elles sont dites à '''émission dans le désordre'''. Elles se distinguent des précédentes sur un point précis : quand l'unité d'émission bloque l'émission d'une instruction, les instructions suivantes peuvent poursuivre. L'émission des instructions peut donc se faire dans le désordre, dans le sens où une instruction peut être émise alors qu'une instruction précédente ne l'est pas encore. L'avantage de l'émission dans le désordre est qu'une instruction s'exécute dès que ses opérandes sont disponibles. Par disponible, on veut dire présent soit dans le réseau de contournement, soit dans les registres. Le processeur détecte automatiquement quand les opérandes d'une instruction sont sont disponibles, et il l’exécute à ce moment là. Dès qu'une instruction a ses opérandes disponibles, elle est émise et exécutée. C'est là la seule contrainte : les dépendances WAR, WAW et autres sont gérées par un ROB ou toute autre technique d'exception précise, seules les dépendances RAW limitent l'exécution. Mais avant de poursuivre, quelques point niveaux terminologie : * L'émission dans le désordre est un terme parlant et assez précis. Malheureusement, la terminologie la plus utilisée par d''''exécution dans le désordre'''. Et nous utiliserons ce terme dans la suite du cours, histoire de ne pas trop dévier de la nomenclature habituelle. * Nous utiliserons parfois l'abréviation OOO pour parler d'exécution dans le désordre. L'abréviation est celle de ''Out Of Order Excution''. * Nous utiliserons aussi l'abréviation ''µop'' pour parler de micro-opération, ''µops'' au pluriels pour parler de plusieurs micro-opérations, ou des micro-opérations en général. L'exécution dans le désordre ne gére en effet que des µops, elle se situe après l'étape de décodage. Mais avant de poursuivre, précisons une chose importante : l'exécution dans le désordre traite les accès mémoire à part. La majorité des processeurs OOO assez anciens exécutent les accès mémoire dans l'ordre, seules les µops entières/flottantes/branchements sont exécutées dans le désordre. Les processeurs datant d'après les années 2010 sont capable d'exécuter les accès mémoire dans le désordre, mais l'implémentation en question est assez particulière. Un chapitre entier sera dédié à l'exécution dans le désordre des µops mémoire. Nous allons volontairement mettre de côté la gestion des accès mémoire dans ce chapitre. ==Les fenêtres d’instruction : généralités== [[File:File de micro-opération.png|vignette|upright=1|File de micro-opérations]] Pour décrire comment est implémentée l'émission dans le désordre, il faut commencer par parler des processeurs sans. Les processeurs sans exécution dans le désordre ont une unité d'émission qui bloque tout le pipeline dès qu'une µop ne peut pas être émise. Pour limiter l'impact de ce blocage, quelques rares processeurs incorporent une '''file de micro-opération''', une mémoire FIFO qui met en attente les µops. Vu que c'est une mémoire FIFO, les µops sont émises dans l'ordre, à savoir l'ordre d'ajout, dans l'ordre de décodage. Le schéma ci-dessous illustre une telle file d'attente couplée à un ''scoreboard''. Sur le principe, l'exécution dans le désordre améliore la file de µops sur un point : ce n'est plus une mémoire FIFO. Les µops sont insérées dans l'ordre, mais peuvent sortir dans le désordre (être émises dans le désordre). La file de µops devient alors une '''fenêtre d'instruction''', terme traduit directement de l'anglais ''instruction Window''. Terme assez trompeur, car elles mettent en attente des µops, pas des instructions. Elles peuvent émettre des µops dans le désordre, ce qui fait que si une µop bloque le pipeline, les µops suivantes peuvent être émises. Si je commence le paragraphe précédent par "sur le principe", c'est car certaines techniques d'OOO utilisent des files de µops normales. Notez le pluriel ! Il existe dans les grandes lignes 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! File de µops améliorée |- ! Une seule "file de µops" | ''Scoreboard'' | Fenêtre d'instruction centralisée |- ! Plusieurs "file de µops" | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | Fenêtre d'instruction décentralisée |} ===La fenêtre d'instruction centralisée=== L'implémentation la plus simple de l'OOO utilise une unique '''fenêtre d'instruction'''. Les instructions décodées sont accumulées dans la fenêtre d'instruction, où elles attendent que leurs opérandes soient disponibles. La fenêtre d'instruction sert donc de file d'attente. Mais elle contient aussi une unité d'émission, qui détecte quelles µops sont prêtes à être émises. L'unité d'émission et la fenêtre d'instruction sont fusionnées ensemble, elles forment un seul circuit. Mais nous allons dire qu'elles sont conceptuellement séparées pour le moment. A chaque cycle, l'unité d'émission consulte la fenêtre d'instruction pour voir quelles µops peuvent s'exécuter, lesquelles ont leur opérandes de disponibles. La fenêtre d'instruction doit spécialement être conçue pour, c'est une sorte de mémoire associative très complexe, comme on le verra dans ce qui suit. [[File:OOO Issue.png|centre|vignette|upright=2.5|Exécution dans le désordre avec une fenêtre d'instruction]] Une fois qu'une µop sort du décodeur d'instructions, elle est ajoutée en parallèle dans la fenêtre d'instruction et le ROB. La raison est que les µops quittent la fenêtre d'instruction dans le désordre, et qu'elles doivent être remises en ordre par la suite. Le ROB s'occupe de cette remise en ordre, mais il a besoin de savoir dans quel ordre les µops sont censées être, et cet ordre est celui du décodage. Aussi, pour remplir le ROB, la seule opportunité est en sortie de l'unité de décodage. Dans le cas où une instruction est décodée en plusieurs micro-opérations, elles sont toutes insérées en même temps dans la fenêtre d'instruction et le ROB, en tenant compte de leur ordre. [[File:Fenêtre d'instruction.png|centre|vignette|upright=2|Fenêtre d'instruction.]] Les micro-opérations mémoire sont à part des autres, pour diverses raisons. Une de ces raisons est que les dépendances de données sont classées en deux types : les dépendances de registre et les dépendances d'adresse. Et les deux sont fondamentalement différentes. Autant on peut détecter les dépendances de registre lors de l'émission, autant c'est plus compliqué avec les dépendances d'adresse. De plus, rappelons que si les lectures peuvent s'exécuter dans le désordre, les écritures doivent s'exécuter dans l'ordre, ou du moins en donner l'illusion. Pour cela, le processeur remet les écritures dans l'ordre avec une sorte de mini-ROB intégré à l'unité mémoire, appelée la file d'écriture. Elle complémente le ROB, qui lui ne gère que les écritures dans les registres, mais les deux collaborent. La file d'écriture envoie une écriture à la mémoire RAM quand le ROB lui dit que c'est bon, les instructions précédentes sont terminées ''dans l'ordre du programme''. Les processeurs assez anciens n'autorisaient pas d'exécution dans le désordre des accès mémoire. Pour cela, la fenêtre d'instruction ne mémorise pas de µops mémoire. L'unité mémoire est précédée par une file de micro-opérations séparée, pour forcer l'exécution dans l'ordre des accès mémoire. [[File:Processeur avec émission dans l'ordre des accès mémoire.png|centre|vignette|upright=2|Processeur avec émission dans l'ordre des accès mémoire]] Les processeurs modernes ajoutent des techniques d'exécution dans le désordre des accès mémoire, mais nous les verrons dans un chapitre dédié. Elles permettent d'utiliser une fenêtre d'instruction unique, qui mémorise aussi les µops mémoire. Si elles sont mises en place, l'unité mémoire n'a pas besoin de file de µops séparée. L'idée est que les dépendances de registre sont traitées par la fenêtre d'instruction, mais que l'unité mémoire gére les dépendances d'adresse. Les dépendances d'adresse sont gérées par des techniques de ''désambiguation mémoire'', qui auront droit à un chapitre dédié. [[File:Processeur avec exécution dans le désodre des accès mémoire.png|centre|vignette|upright=2|Processeur avec exécution dans le désodre des accès mémoire]] Dans ce chapitre, on suppose que l'unité mémoire est précédée d'une file de micro-opération mémoire dédiée, rien que pour elle. ===Les fenêtres d'instruction décentralisées=== Une autre solution utilise plusieurs fenêtres d'instruction. Pour faire la différence avec l'usage d'une fenêtre d'instruction unique, nous allons parler de fenêtre d'instruction centralisée s'il n'y en a qu'une dans le processeur, de '''fenêtre d'instruction décentralisée''' s'il y en a plusieurs. Dans le cas général, chaque fenêtre d'instruction est associée à un type précis d'opération/instruction. La tendance moderne est d'utiliser une fenêtre d'instruction pour les instructions de calcul entières, une autre pour les flottantes. Il s'agit d'un choix simple et efficace, mais quelques processeurs font autrement, pour répondre à des contraintes très diverses. L'usage de fenêtres décentralisées simplifie la répartition des instructions sur les différentes unités de calcul. Par exemple, utiliser des fenêtres séparées pour les ALU et les FPU facilite la répartition des instructions de calcul sur les ALU. Une fenêtre centralisée demande de faire la différence entre instruction entière/flottante, puis de choisir sur quelle unité de calcul entière/flottante utiliser. Une fenêtre décentralisée fait les deux choix séparément : d'abord on envoie l'instruction dans la bonne fenêtre suivant si c'est une instruction flottante ou entière, et ensuite on gère la disponibilité des ALUs/opérandes. Et on peut adapter la même idée en séparant les unités d'accès mémoire des ALU entières, etc. Par contre, un défaut est que certaines fenêtres d'instruction peuvent être sous-utilisées. Par exemple, la station de réservation flottante est inutilisée si le programme n'exécute pas d'opérations flottantes. Ou encore, les fenêtres pour les accès mémoire peuvent être sous-utilisées, si le programme effectue peu d'accès mémoire relativement aux autres instructions. En fait, tout dépend de comment sont calibrées les fenêtres d'instruction et de la répartition des instructions dans le programme entre opérations entières, flottantes, mémoire. Par exemple, si un programma de deux fenêtres d'instructions identiques, une pour les calculs entiers et une autre pour les calculs flottants, elles ne seront utilisées à la perfection que si la moitié des instructions du programme fait des calculs flottants et l'autre des calculs entiers. Toute déviation par rapport à cette répartition idéale risque de laisser des entrées vides dans une fenêtre d’instruction. Un point important est que l'émission est découpée en deux étages avec des fenêtres d'instruction décentralisées. La première étape envoie l'instruction décodée vers la fenêtre d'instruction adéquate, la seconde gère l'émission proprement dit. La première est l'étage de ''dispatch'' qui envoie l'instruction dans la fenêtre d’instruction adéquate, selon que c'est une instruction flottante, entière, autre. La seconde est l'étage de ''scheduling'', qui gère la disponibilité des opérandes et des unités de calcul. En clair, on trie les instructions suivant leur type, suivant le type d'unité de calcul adéquate, puis on l'émet proprement dit. Faire ainsi a plusieurs avantages, avec cependant peu d'inconvénients. Lors de l'étape de ''dispatch'', l'instruction émise est ajoutée au tampon de réordonnancement, s'il existe. Sans cela, impossible de conserver l'ordre des instructions. Les instructions sont émises dans l'ordre au niveau de l'unité de ''dispatch'', pas au niveau de l'étage de ''scheduling''. Aussi, pour remplir le ROB, cela doit se faire au dernier moment où les instructions sont émises dans l'ordre, soit en sortie de l'unité de ''dispatch''. De plus, les micro-opérations mémoire sont traitées à part des autres, elles sont envoyées directement à l'unité mémoire. La gestion des calculs d'adresse est quelque peu complexe, mais ils peuvent être fait soit dans l'unité mémoire, soit dans les ALU entières, peu importe. Il y a aussi un système de contournement complexe entre ALU/FPU et unité mémoire, qui n'est pas représenté dans le schéma ci-dessous. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Il faut noter que quelques processeurs utilisent des méthodes intermédiaires entre les trois solutions précédentes. Par exemple, les processeurs AMD Zen utilisent une fenêtre d'instruction décentralisée un peu particulière. Les unités de calcul entières disposent d'une fenêtre d'instruction rien que pour elles, sur ce processeur. Les instructions flottantes sont quant à elles alimentées par une file de micro-opération, pas une fenêtre d'instruction ! La raison à ce choix est un compromis entre performance et cout en circuit. L'exécution dans le désordre est peu efficace sur les instructions flottantes, car les CPU n'ont que peu d'ALU flottantes séparées. Vu le cout en circuits d'une fenêtre d'instruction, les concepteurs du processeur ont préféré utiliser une file de micro-opération pour les opérations flottantes. ===L'usage de plusieurs files d'instruction=== Une dernière méthode d'OOO utilise plusieurs files de micro-opération. L'idée est qu'une fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement une file de micro-opération pour les opérations entières, une autre pour les opérations flottantes, une autre pour les accès mémoire. D'autres processeurs utilisent une file pour les accès mémoire et une autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. La présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que la technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si une dépendance bloque une FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans une autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer la disponibilité des registres. Quand un registre est lu ou écrit par une instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. La logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : une pour les instructions d'accès mémoire et une autre pour les autres instructions. Si jamais une instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de la lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'une est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est la file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. ===Avantages et inconvénients de chaque implémentation=== Un processeur contient soit une fenêtre d'instruction unique, soit plusieurs fenêtres d'instruction séparées. Typiquement, les fenêtres d’instruction séparées sont spécialisées, dans le sens où on a une fenêtre pour les instructions flottantes, une autre pour les instructions entières, une autre pour les accès mémoire, etc. Pour résumer, on a le choix entre une grosse fenêtre généraliste et plusieurs fenêtres spécialisées, sauf que la fenêtre centralisée est lente et complexe, contrairement aux fenêtres spécialisées. Les deux méthodes ont des inconvénients et des avantages différents. Dans les grandes lignes, l'avantage des fenêtres décentralisées est qu'elles sont plus petites qu'une grosse fenêtre d'instruction. Cela simplifie la gestion du contournement et de la répartition des instructions sur les unités de calcul, comme on le verra dans quelques paragraphes. Elles sont donc moins complexes et plus rapides. L'autre avantage, c'est qu'il est possible de démarrer l'exécution de plusieurs instructions simultanément : une instruction par fenêtre décentralisée, contre une par fenêtre d'instruction. Mais les fenêtres décentralisées sont souvent sous-utilisées, partiellement remplies, contrairement aux fenêtres d'instruction. Il arrive qu'une fenêtre d'instruction soit remplie, alors que les autres sont vides. Par exemple, prenons un processeur avec une fenêtre d'instruction reliée à la FPU, et une autre reliée aux autres ALUs. Si le processeur n'exécute que des opérations flottantes, la fenêtre reliée à la FPU sera pleine, alors que l'autre sera vide. L'exécution des instructions dans le désordre est alors limitée par la petite taille de la fenêtre, qui ne peut plus accepter de nouvelle instruction flottante. Avec une fenêtre unique, on n'aurait pas eu ce problème : on aurait eu une énorme fenêtre d'instruction remplie d'instruction flottante, au lieu d'une petite fenêtre spécialisée. Il est maintenant temps de voir en quoi sont faites les fenêtres d’instruction, qu'elles soient centralisées ou décentralisées. Nous allons aussi voir quelle est la logique d'émission associée. ==L'implémentation d'une fenêtre d'instruction : généralités== Une fenêtre d'instruction est une mémoire qui mémorise des micro-opérations. Elle est cependant plus complexe qu'une mémoire RAM ou qu'une FIFO et ressemble un petit peu à une mémoire cache. Elle dispose d'un port d'écriture et d'un port de lecture, au minimum. Le port d'écriture permet à l'unité de décodage d'insérer une micro-opération dedans, d'ajouter la micro-opération qui vient d'être décodée. Si une instruction machine est décodée en plusieurs micro-opération, deux possibilités. La première est de les insérer un par un, ce qui fait qu'on peut se contenter d'un seul port d'écriture. L'autre possibilité est de les ajouter en même temps, ce qui demande plusieurs ports d'écriture. Le port de lecture sert à émettre une instruction. On part du principe que la fenêtre d'instruction ne peut émettre qu'une seule instruction à la fois, car les processeurs que nous avons vu précédemment sont de ce type. Mais nous verrons dans quelques chapitre qu'il existe des processeurs dits superscalaires, qui sont capables d'émettre plusieurs instructions par cycle. Dans ce cas, la fenêtre d'instruction a un seul port de lecture. Un processeur superscalaire, quant à lui, doit avoir un port de lecture par unité de calcul, ce qui fait beaucoup plus. ===Les entrées d'une fenêtre d’instruction=== Les fenêtres d'instruction sont composées d''''entrées''', des mots mémoire qui stockent une instruction. Une instruction réserve une entrée après son décodage et la libère dès qu'elle est envoyée aux unités de calcul. Une entrée contient l'opcode (les signaux de commande à envoyer à l'ALU), le registre de destination du résultat, les registres de chaque opérande, et éventuellement des signaux de commande en plus. De plus, chaque opérande est couplée à un bit de disponibilité, qui indique si elle est disponible. Quand un opérande est écrit dans les registres, le bit de présence correspondant est mis à jour. Enfin, chaque entrée possède un bit ''empty'' qui indique si elle est vide, cette information étant utile pour réserver des entrées. [[File:Entrée d'une station de réservation - sans les tags.png|centre|vignette|upright=3|Entrée d'une fenêtre d'instruction]] Nous verrons dans quelques chapitres que certaines fenêtres d'instruction sont capables de mémoriser les opérandes des instructions. De telles fenêtres d'instruction seront appelées, dans ce cours, des '''stations de réservation'''. Les entrées des stations de réservation sont assez semblables à celle des fenêtres d'instruction, à un détail près : les opérandes de l'instruction sont enregistrées directement dans des champs séparés. Il y a deux champs, un par opérande, pour stocker l'opérande elle-même, lue depuis les registres ou obtenue via le réseau de contournement. Notons que les champs pour les opérandes viennent en plus des champs pour les noms de registres, encore que les deux peuvent être fusionnés si on veut optimiser le tout. [[File:Entrée d'une station de réservation.png|centre|vignette|upright=3|Entrée d'une station de réservation.]] Précisons que la terminologie n'est pas très fiable. Les termes "fenêtre d'instruction" et "station de réservation" ne regroupent pas du tout la même chose d'un papier de recherche à l'autre, d'un bouquin à l'autre, d'un chercheur à l'autre, d'un ingénieur à l'autre, d'un professeur à l'autre. Le terme initial vient pourtant de l'article original sur l'algorithme de Tomasulo, où il désignait une fenêtre d'instruction associée à une unité de calcul précise. Mais le terme a ensuite été réutilisé, ce qui fait que certains processeurs avec plusieurs unités de calcul sont décrit comme ayant une unique station de réservation. En bref : c'est le bazar ! Mais nous en reparlerons dans le chapitre sur le renommage de registres, car c'est la place idéale pour les aborder. Toujours est-il que j'ai fait le choix de confondre les concepts de fenêtre d'instruction et de station de réservation avec les concepts de '''lecture avant émission''' et de '''lecture après émission'''. La différence entre les deux est que les registres sont lus après émission avec une fenêtre d'instruction, avant avec des stations de réservation. Dans le cas "avant émission", les opérandes sont mémorisées dans la station de réservation. Et cette différence a une influence sur le pipeline du processeur, le banc de registres et tout ce qui s'en suit. Un désavantage de la lecture avant émission est qu'il faut stocker les opérandes après lecture, ici dans les stations de réservation. Mais un avantage est que le banc de registre a besoin de moins de ports de lecture, car une bonne partie des opérandes sont fournies par le système de contournement. Nous verrons cela dans le détail dans le chapitre sur les processeurs superscalaires. Il a été proposé de fusionner le tampon de ré-ordonnancement avec la fenêtre d'instruction dans une structure unique. La méthode a notamment été utilisée sur les processeurs d'architecture K6 d'AMD. Le tout donnait une structure appelée le '''DRIS''' (''deferred scheduling register renaming instruction shelf''). La différence avec une fenêtre d’instruction normale est que les entrées sont libérée non pas quand l'instruction est exécutée/émise, mais quand elle termine son exécution et quitte le ROB. La fenêtre d'instruction doit alors incorporer des bits pour savoir si telle entrée a émis sont instruction ou non. ===La logique d'éveil et de sélection=== Dans le cas qui va suivre, on suppose que le processeur ne peut émettre qu'une instruction à la fois. Chaque cycle, une instruction est sélectionnée et est envoyée dans le chemin de données, soit à une ALU, soit à une unité d'accès mémoire. La sélection d'une instruction est effectuée par l'unité d'émission, qui est aussi appelée le '''''scheduler'''''. Elle gère la disponibilité des opérandes et la disponibilité des unités de calcul adéquate. Le choix de l'instruction émise doit être le plus pertinent possible, pour des raisons de performances. Pour le premier point, l'unité d'émission détermine quelles instructions sont candidates pour l'émission. Les ''instructions candidates'' sont celles dont tous les opérandes sont prêts. Le processeur contient un circuit qui détecte les instructions candidates : la '''logique d’éveil''' (''wake-up logic''). Une fois que la logique d'éveil a fait son travail, une instruction est choisie pour s’exécuter en fonction de la disponibilité des unités de calcul adéquates. Ce rôle est dévolu à un circuit qu'on appelle la '''logique de sélection''', ou ''select logic''. [[File:Fonctionnement complet de la logique d’émission.jpg|centre|vignette|upright=1.5|Fonctionnement complet de la logique d’émission.]] La logique de sélection doit gérer le fait que les unités de calcul du processeur ne sont pas toutes identiques. Déjà, un processeur a généralement des unités séparées pour les instructions entières et flottantes, des unités spécialisées dans les accès mémoire, parfois des unités spécialisées pour les branchements. Une instruction doit être attribuée à la bonne unité de calcul, on ne doit pas envoyer une instruction entière dans une unité de calcul flottante. De plus, parmi les unités de calcul entières, toutes ne sont pas identiques. Par exemple, il est fréquent d'avoir plusieurs unités de calcul spécialisées dans les opérations simples (additions, soustractions, opérations logiques) avec une unité pour les multiplications/divisions séparées, parfois une unité spécialisée pour les décalages/rotations, etc. Là encore, allouer la bonne instruction à la bonne ALU est complexe. Plus les unités de calcul sont hétérogènes, plus la logique de sélection est compliquée. Les logiques d'éveil comme de sélection sont assez complexes. Comme on le verra plus bas, la logique de sélection la plus simple, qui gère une seule unité de calcul, est basée sur un encodeur à priorité couplé à d'autres circuits. Et pour gérer plusieurs ALUs, il faut mettre des encodeurs en cascade. Le résultat est que même en prenant une logique de sélection simple, elle sera assez lente et gourmande en circuits. Aussi, la logique de sélection met souvent un cycle d'horloge entier pour faire son travail, elle a son propre étage de pipeline attribué. La logique d'éveil est dans le même cas, ce qui fait qu'émettre une micro-opération demande deux cycles d'horloge. Le défaut est que cela rajoute des cycles d'horloges entre la fenêtre d'instruction et l'ALU, ce qui complique la gestion du pipeline. Ces cycles de retard sont à prendre en compte au moment d'émettre les instructions, les ''scheduler'' doit en tenir compte pour des performances optimales. Sans tenir compte de ces cycles de retard, les instructions arrivent en retard de quelques cycles à l'ALU, cycles de retard durant lesquels l'ALU n'a pas fait de calcul et a été sous-utilisée, sans compter que le système de contournement n'est pas utilisé au mieux. Et le problème est encore plus important sur les processeur avec des stations de réservation, qui utilisent la "lecture après émission" : cela rajoute un cycle d'horloge en plus, un temps de retard en plus. ===La logique d'éveil : l'émission anticipée=== La logique d'éveil doit tenir compte du fait qu'il y a plusieurs étages entre l'émission et l'exécution sur une unité de calcul. Par exemple, un processeur a souvent entre un et à cinq étages entre la file d'attente et les unités de calcul. Il faut lire les registres, gérer le contournement, et cela peut prendre quelques cycles d'horloge. Sur le Pentium 4, on trouve 6 étages entre la fenêtre d’instruction et l'entrée de l'ALU. Si les micro-opérations sont émises quand les opérandes sont disponibles, il y aura un délai de quelques cycles avant qu'elles atteignent l'ALU. Alors qu'idéalement, on souhaiterait que la micro-opération atteigne l'ALU dès que ses opérandes sont disponibles, pour profiter des techniques de contournement. Pour cela, la logique d'éveil émet les instructions quelques cycles en avance pour qu'elles arrivent au bon moment. Il s'agit d'une technique d''''émission anticipée''', dont nous avions parlé dans le chapitre sur le contournement. : Il faut noter que le problème se pose plus avec des fenêtres d'instruction qu'avec des stations de réservation. Les premières ont un étage en plus entre émission et ALU, vu qu'il faut lire des registres après l'émission. L'émission anticipée demande d'émettre un signal d'éveil en avance de quelques cycles, pile au bon moment. Par exemples, si on a deux étages entre l'ALU et l'unité d'émission, le signal de réveil sera généré deux cycles avant que le résultat soit effectivement calculé. L'implémentation varie, mais deux solutions sont possibles. La première est de générer le signal d'éveil dans l'ALU, ce qui n'a de sens que pour les opérations comme les multiplications ou les divisions, qui prennent plusieurs cycles. Une autre technique génère le signal de réveil dans une structure centralisée, spécialisée dans la génération des signaux d'éveil. L'unité de composée d'un registre à décalage par registre. Imaginons qu'une instruction est émise, que cette instruction mette N cycles à s'exécuter, et qu'elle écrive dans un registre de destination. L'unité sélectionne alors le registre à décalage associé au registre de destination, et met le bit numéro N à 1. Le registre décalé d'un cran à chaque cycle. Quand le bit sortant est un 1, alors le signal de validité pour l'opérande est généré. L'émission anticipée marche bien si l'instruction a une durée fixe, connue à l'avance. Et autant c'est le cas pour les instructions arithmétiques et logiques, autant ce n'est pas le cas pour les accès mémoire. Les accès mémoire ont une latence variable : quelques cycles pour un succès de cache, plusieurs dizaines de cycles pour un défaut de cache L1, pas loin de la centaine pour un défaut de cache L2, etc. Et cela pose des problèmes pour l'émission anticipée. L'émission en avance pour les accès mémoire est purement spéculative : le processeur émet des instructions en supposant que la lecture entrainera un succès de cache, quitte à annuler l'instruction en cas de défaut de cache. Mais faire ainsi demande non seulement d'annuler les instructions émises en avance, mais aussi de ne pas retirer les instructions émises en avance de la fenêtre d'instruction. Elles sont émises, mais une copie de sauvegarde est conservée dans la fenêtre d'instruction. Si le processeur détecte un défaut de cache, il peut alors ré-exécuter l'instruction. S'il détecte un succès de cache, les instructions lecture-dépendante sont retirées de la fenêtre d'instruction, la copie de sauvegarde est devenue inutile et est donc jetée. ===La logique de sélection : âge ou position ?=== La logique de sélection est primordiale pour de bonnes performances. Il existe deux méthodes principales pour sélectionner l'instruction à exécuter. La première est la plus simple : elle se base sur lé numéro de l'entrée. En effet, une fenêtre d'instruction est avant tout une sorte de mémoire, un mix entre mémoire associative, mémoire RAM, et FIFO. Et chaque entrée a un numéro, une adresse mémoire. Nous parlerons de numéro dans ce qui suit, car ce sera plus simple, le terme d'adresse mémoire étant peut-être un peu exagéré dans le contexte des fenêtres d'instruction. Toujours est-il que la fenêtre d'instruction est adressable dans le sens où on peut lui envoyer le numéro de l'entrée voulue, et la fenêtre d’instruction renvoie le contenu de l'entrée sur son port de lecture. Et c'est ce que fait la logique de sélection : elle génère le numéro de l'entrée à lire. Le numéro est alors envoyé sur l'entrée d'adresse de la fenêtre d’instruction, et elle fournit la micro-opération associée sur son port de lecture, son '''port d'émission'''. La première méthode de sélection, donc. Elle est basée sur sur le numéro de l'entrée. Si plusieurs entrées sont éveillées, la logique de sélection prend celle avec le plus petit numéro. Elle porte le nom de '''sélection par position''', sous-entendu position dans la fenêtre d'instruction. Vous l'avez peut-être deviné, mais la logique de sélection est alors un encodeur à priorité. Le circuit de sélection ne se résume donc pas seulement à un encodeur à priorité, mais c'est le circuit central. L'avantage d'une telle méthode de sélection est qu'elle est simple à implémenter : un encodeur à priorité est un circuit connu, facile à implémenter. Mais on remarque un défaut : un encodeur est un circuit assez rapide, mais qui utilise beaucoup de transistors, beaucoup de portes logiques, surtout si on veut qu'il soit rapide. Ce qui explique que la logique de sélection ait son propre étage de pipeline rien que pour elle. La seconde méthode s'appelle la '''sélection par âge''', au nom assez transparent. L'idée est de privilégier l'émission de l'instruction la plus ancienne. Elle demande que la fenêtre d'instruction trie les micro-opérations par ordre d'insertion dans la fenêtre d'instruction, ce qui en fait une pseudo-FIFO. Le tri est partiel, car les instructions peuvent sortir de la fenêtre d’instruction à tout moment. Compacter la fenêtre d'instruction, à savoir regrouper toutes les entrées valides est une idée, mais elle est compliquée à implémenter. Aussi, elles préfèrent encoder des informations sur l'ordre d'émission dans chaque entrée. L'encodeur à priorité doit alors travailler non pas sur des nombres entiers liés à l'ordre d'insertion dans la pseudo-FIFO. Elle est encore plus gourmande en circuits que la méthode précédente. Les processeurs haute performance utilisent souvent des méthodes hybrides. Par exemple, les processeurs AMD de microarchitecture Bulldozer utilisaient une méthode intermédiaire. Ils utilisaient une fenêtre d'instruction couplée à un encodeur à priorité pour la sélection par position, mais complémentaient le tout avec une unité qui mémorisait l'instruction la plus ancienne dans la fenêtre d’instruction. Le mécanisme de sélection par âge était utilisé en priorité. Mais si l'instruction la plus ancienne n'était pas prête, le processeur basculait sur le mécanisme de sélection par position. ===La compaction des fenêtres d'instruction=== À chaque cycle, les instructions décodées sont ajoutées dans la fenêtre d'instruction, dans des entrées vides. Vu que les instructions quittent celle-ci dans le désordre, ces vides sont dispersés dans la fenêtre d'instruction, ce qui pose problème pour déterminer où placer les nouvelles instructions. La solution la plus triviale consiste à conserver une liste des vides, mise à jour à chaque insertion ou émission d'instruction. Une autre solution consiste à éliminer les vides en compactant la fenêtre d'instruction à chaque cycle d'horloge. Des circuits se chargent de détecter les vides et de regrouper les instructions en un unique bloc. Il faut signaler que certaines processeurs arrivent à se passer de cette étape de compactage, mais au prix de fenêtres d'instruction nettement plus complexes. Autre problème : quand il faut choisir quelle instruction émettre, il y a toujours plusieurs candidats. Si on choisit mal, des instructions restent en attente trop longtemps parce que d'autres instructions plus jeunes leur passent devant. Pour éviter cela, les instructions les plus vielles, les plus anciennes, sont prioritaires. Pour cela, on peut utiliser une FIFO un peu spéciale pour la fenêtre d'instruction. Si les ajouts d'instruction se font dans l'ordre, les instructions ne quittent pas forcément la fenêtre d'instruction dans l'ordre imposé par une FIFO : les instructions restent triées dans leur ordre d'ajout, même s'il y a des vides entre elles. Dans ces condition, il est préférable que le compactage conserve l'ordre FIFO des instructions. Dans ces conditions, l'instruction la plus ancienne est celle qui est située à l'adresse la plus faible : le circuit de sélection peut donc être fabriqué avec des encodeurs, et est relativement simple. ==Les fenêtres d'instruction basées sur une matrice de dépendances== L'implémentation la plus simple étend le fonctionnement d'un pipeline dynamique usuel. Rappelez-vous le chapitre sur les pipeline dynamiques. Nous avions vu que de tels pipelines émettaient une instruction par cycle, quitte à émettre des bulles de pipeline en cas de dépendance bloquante. Et il est possible d'améliorer leur unité d'émission pour qu'elle soit compatible avec l'exécution dans le désordre. ===Rappels sur le registre de réservation/disponibilité=== L'émission d'une instruction est gouvernée par un ''registre de réservation'' qui indique quels registres sont réservés par une instruction, et ceux qui sont libres. Un registre réservé est un registre qui sera écrit par une instruction en cours d'exécution, mais qui n'a pas encore écrit son résultat. Les instructions candidates doivent avoir leurs opérandes dans des registres libres. Sinon, c'est signe que leurs opérandes sont réservées en écriture, donc pas encore écrites, donc pas disponibles. Si une instruction candidate veut lire ce registre, c'est signe qu'il y a une dépendance RAW : elle veut lire un registre réservé, qui est destiné à être écrit par une instruction en vol. Si elle veut écrire, c'est signe qu'elle veut écrire dans un registre où une autre instruction veut écrire : c'est une dépendance WAW. Dans les deux cas, l'instruction n'est pas émise. Le registre de réservation encode les registres réservés comme suit : chaque bit est associé à un registre. Le bit numéro 0 est associé au registre numéro 0, le bit numéro 1 au registre numéro 1, etc. Là, En clair, les numéros de registres réservés sont encodés en représentation non pas binaire, mais en représentation ''one-hot'' (vue au premier chapitre). {|class="wikitable" |+ Registre de réservation |- ! Registre 7 !! Registre 6 !! Registre 5 !! Registre 4 !! Registre 3 !! Registre 2 !! Registre 1 !! Registre 0 |- | 0 || 0 || 1 || 0 || 0 || 1 || 0 || 0 |} Avant d'émettre une instruction, l'unité d'émission extrait les registres opérande/destination et les convertis dans la même représentation que le registre de réservation, à savoir en représentation ''one-hot''. Le circuit de traduction binaire vers ''one-hot'' est, pour rappel, un simple décodeur. Puis, on fait un OU logique entre les sorties des décodeurs. Le résultat est un masque qui indique quels registres sont lus par l'instruction, encodé en représentation ''one-hot''. Appelons-le le '''masque d'opérandes'''. Le masque est alors comparé au registre de réservation pour vérifier si l'instruction peut être émise. [[File:Unité d'émission simple, dans l'ordre.png|centre|vignette|upright=2|Unité d'émission simple, dans l'ordre]] Si l'émission est autorisée, le registres de réservation est là aussi mis à jour. Le registre de réservation est aussi mis à jour dès qu'une instruction enregistre son résultat dans les registres, ou alors dès qu'il est disponible pour le contournement. Le bit associé au registre repasse alors à 0 (ou à 1). Sans contournement, la mise à jour se fait alors à la toute fin de l'instruction, quand elle se termine, lors de la dernière étape d'enregistrement, à la fin de son pipeline. Avec, elle se fait quand l'instruction quitte l'unité de calcul. ===L'extension à l'exécution dans le désordre : l'éveil par matrice de bits=== La différence entre un pipeline dynamique et l'exécution dans le désordre est que l'on passe d'une instruction à émettre à plusieurs. Plusieurs instructions sont mises en attente dans une fenêtre d’instruction, et y attendent leur tour. L'idée est alors d'envoyer le registre de disponibilité à toutes les entrées, à toutes les instructions en attente. Ainsi, on sait quelles sont les instructions qui peuvent s'exécuter et celles qui ne le peuvent pas. L'implémentation est assez simple, elle ressemble beaucoup à l'implémentation d'un pipeline dynamique simple, si ce n'est que des circuits sont dupliqués. L'implémentation utilise des fenêtres d'instruction légèrement différentes de celles introduites plus haut. Elles n'utilisent notamment pas de bits de disponibilité, mais autre chose. Lorsqu'une instruction est ajoutée à la fenêtre d'instruction, le masque de disponibilité des opérandes est stocké dans la fenêtre d'instruction. A chaque cycle, le registre de disponibilité est envoyée à toutes les entrées, et est comparé avec tous les masques de disponibilité des opérandes. Si une comparaison renvoie un 1, alors l'instruction de l'entrée est une instruction candidate à l'émission. [[File:Unité d'émission dans le désordre basée sur un registre de disponibilité.png|centre|vignette|upright=2.5|Unité d'émission dans le désordre basée sur un registre de disponibilité]] L'ensemble est implémenté avec l'aide d'une '''matrice de bits''', où chaque ligne correspond à une entrée et chaque colonne à un registre. À chaque croisement entre une ligne et une colonne, on trouve un bit. Si le bit de la ligne n et de la colonne m est à 1, cela veut dire : l'instruction dans l'entrée n a besoin de lire le registre m. S’il est à 0, alors cela veut dire que l'instruction stockée dans la ligne n n'a pas besoin de la donnée dans le registre m. [[File:Planificateur à matrice de bits.jpg|centre|vignette|upright=2|Planificateur à matrice de bits.]] Lorsqu'une instruction réserve une entrée, elle initialise la ligne en fonction des registres qu'elle souhaite lire. Pour vérifier si une instruction a ses opérandes prêts, le processeur compare le registre de disponibilité à la ligne associée à l'instruction/entrée. A chaque intersection ligne-colonne, se trouve un comparateur de 1 bit, qui détecte si le registre est demandé et disponible. Les résultats de cette porte sont ensuite envoyés à une porte ET, qui fait le gros du travail. [[File:Logique de détection de la disponibilité d'une instruction.jpg|centre|vignette|upright=2|Logique de détection de la disponibilité d'une instruction.]] ==Les fenêtres d'instruction basées sur une mémoire associative== Les processeurs modernes utilisent une mémoire associative pour la fenêtre d'instruction. Les mémoires associatives ont été abordées il y a quelques chapitres, mais faisons quelques rappels. Les mémoires associatives servent à accélérer la recherche de données dans un ensemble. Or, une fenêtre d'instruction vérifie régulièrement si chaque entrée est prête. Il s'agit d'un processus de recherche d'une instruction qui respecte une condition bien précise dans la mémoire, ce qui fait que les mémoires associatives sont donc tout indiquées. Comme vous le savez, les signaux de commande d'une instruction sont propagés avec celle-ci dans le pipeline, le nom du registre de destination ne faisant pas exception. Le nom de registre est envoyé à la fenêtre d'instruction lors de l'écriture du résultat dans les registres. S'il y a correspondance, l'opérande est disponible et son bit de disponibilité est mis à 1. On peut adapter cette méthode pour tenir compte du contournement assez simplement. [[File:Détection des dépendances par propagation du registre de destination.png|centre|vignette|upright=2|Détection des dépendances par propagation du registre de destination.]] En conséquence, le circuit de détection des dépendances est constitué d'un grand nombre de comparateurs : un par champ « nom de registre » dans chaque entrée. La logique d'éveil/''wake up'' regroupe tous les comparateurs, la logique de sélection est un circuit situé en-dehors de la mémoire associative. Les entrées sont dans la mémoire associative elle-même. [[File:Gestion des bits de validité.png|centre|vignette|upright=2|Gestion des bits de validité.]] L'implémentation la plus simple est celle du schéma précédent, où on utilise une mémoire associative unique. Une version plus élaborée sépare la fenêtre d'instruction en deux parties : une mémoire qui mémorise les registres des opérandes, une autre mémoire pour le reste. La mémoire pour les registres opérandes est la mémoire associative proprement dite, c'est elle qui est associées aux comparateurs, à la logique de ''wake-up''/réveil, etc. Par contre, l'autre mémoire est une mémoire RAM simplifiée, qui mémorise les informations qui n'ont pas besoin des comparateurs. L'opcode de l'instruction est là-dedans, par exemple. ===Les optimisations de la consommation d'énergie : la désactivation des portions inutilisées=== Le problème avec des fenêtres d'instruction de ce type est leur forte consommation énergétique, ainsi que le grand nombre de portes logiques utilisées, qui deviennent prohibitif pour des fenêtres d'instruction un peu grosses. Pour résoudre ce problème, certains ont optimisé les comparateurs. D'autres ont tenté de profiter du fait que la majorité des bits dans les entrées sont composés de zéros. Bref, les optimisations purement matérielles sont légion. Une première solution est de désactiver les entrées qui sont inutilisées, vides, sans instruction. Pour cela, on fait précéder les comparateurs par un circuit qui les connecte ou déconnecte des lignes de bit. Le circuit est commandé par le bit ''empty'' qui indique si une entrée est vide ou non. L'avantage est que la consommation d'énergie de la fenêtre d'instruction devient alors proportionnelle au nombre d'entrées non-vides, et non au nombre d'entrées total. Du moins, en apparence, les entrées non-utilisées doivent quand même être alimentées pour fonctionner, mais l'activité de comparaison disparait dans les entrées vides. Il est possible d'étendre cette technique aux entrées dont les opérandes sont prêtes. Les gains sont généralement assez bons, avec une réduction de consommation variant entre 30 et 50%, avec une implémentation très simple et très économe en circuits. Une autre solution, assez simple à mettre en place, consiste à désactiver une partie de la fenêtre d'instruction sin elle est inutilisée. Pour cela, il faut segmenter la fenêtre d'instruction avec la technique du ''wire partitionning''. Pour rappel, une fenêtre d'instruction est une mémoire associative. Et comme toute mémoire associative, elle contient des fils, les lignes de bit, qui relient les entrées/sorties à toutes les cellules mémoire. Plus une ligne de bit est longue, plus elle consomme d'énergie et plus le temps de lecture/écriture est long. L'idée est de segmenter les lignes de bits en plaçant des répéteurs qui recopient la tension d'un segment au suivant. Les répéteurs sont des tampons trois-états, ce qui permet de déconnecter les portions inutilisées de la ligne de bit. Ce faisant, la fenêtre d'instruction est découpée en segments, qui peuvent être désactivés si besoin. Si il y a peu d'instructions chargées dans la fenêtre d'instruction, les portions inutilisées sont désactivées. La technique marche d'autan mieux si les instructions sont compactées au début de la fenêtre d'instruction. [[File:Wire partitionning.png|centre|vignette|upright=2|Wire partitionning]] Tout le problème est de savoir quelles portions désactiver. La technique est assez simple si la fenêtre d'instruction est compactée, à savoir si toutes les instructions sont régulièrement regroupées au début de la mémoire CAM. Mais même avec cette optimisation, la décision de désactiver une portion de la fenêtre d'instruction n'est pas à prendre à la légère. Il ne faut pas désactiver une portion contenant des instructions pouvant être émise sous peu. La décision dépend de paramètres variés : proportion d'entrée vides, quantité d'entrées récemment activées/désactivées récemment, présences d'entrées avec un ''match'' d'opérandes récent, etc. Il est important de préciser que les techniques en question fonctionnent aussi sur les autres types de fenêtre d'instruction, qui ne sont pas basées sur des mémoires associatives. Nous allons voir celles-ci dans la suite du chapitre, mais gardez à l'esprit que ces optimisations, à savoir désactiver les entrées vides/prêts et partitionner la fenêtre d'instruction, sont des optimisations générales qui marchent avec presque tout. ===L'ajout d'une FIFO pour les instructions déjà prêtes à l'émission=== D'autres techniques permettent de réduire aussi bien le cout en circuits que la consommation d'énergie de la fenêtre d'instruction. L'idée est d'utiliser une mémoire associative quand elle est réellement nécessaire, mais d'utiliser une fenêtre d'instruction "normale" dès que possible. La méthode la plus simple tient compte du fait que certaines instructions ont déjà toutes leurs opérandes de disponibles à l'émission, mais doivent quand même être mises en attente, parce que l'ALU adéquate est occupée, parce que des dépendances WAW/WAR sont encore là, ou pour tout autre raison. Dans ce cas, elles sont mises en attente non pas dans la fenêtre d'instruction, mais dans une mémoire FIFO toute simple. L'idée est qu'au lieu d'avoir une énorme mémoire associative pour la fenêtre d'instruction, on déplace quelques entrées dans une petite FIFO annexe. Le résultat est un gain en terme d'énergie et de circuits, au prix d'une perte de performance mineure. La perte de performance en question se manifeste si aucune instruction n'a ses opérandes de prêtes à l'émission : le programme n'utilise pas la FIFO et voit alors une fenêtre d'instruction plus petite. Une amélioration de cette technique tient compte du fait que certaines instructions sont dans un cas intermédiaire. Elles ont déjà une opérande de prête lors de l'émission, mais pas l'autre. Le nombre d'opérandes varie suivant l’instruction : certaines n'ont besoin que d'un seul opérande. De plus, il arrive qu'une opération tout juste décodée ait déjà un ou plusieurs de ses opérandes de prêts. Cette constatation permet d'éviter d'utiliser des comparateurs pour les opérandes déjà prêts. Par exemple, on peut parfaitement utiliser trois fenêtres d'instruction : * une pour les instructions dont tous les opérandes sont prêts, mais qui sont quand même mises en attente, sans comparateur ; * une pour les instructions dont un seul opérande manque, qui n'utilise qu'un comparateur par entrée ; * une pour les instructions dont deux opérandes manquent à l'appel, qui utilise deux comparateurs par entrée. C'est beaucoup plus économique que d'utiliser une seule grosse fenêtre d'instruction qui contiendrait autant d'entrées que les trois précédentes réunies, avec deux comparateurs par entrée. Certains sont même allés plus loin, et ont proposé de supprimer la fenêtre d'instruction avec deux opérandes par entrée. Les instructions dont deux opérandes sont inconnus au décodage sont stockées dans la fenêtre d'instruction pour instructions avec un comparateur par entrée. Un circuit de prédiction se charge alors de prédire l'opérande manquant, cette prédiction étant vérifiée plus loin dans le pipeline. Il serait cependant étonnant qu'une telle proposition ait donné lieu à la moindre implémentation réelle. ===Les optimisations de la consommation d'énergie avancées=== D'autres chercheurs ont conservé une fenêtre d'instruction unique, avec autant de comparateurs par entrée qu'il y a d'opérandes possibles par instruction. Simplement, le processus de détection des opérandes prêts est légèrement ralenti : on ne vérifie qu'un opérande par cycle. Pour vérifier les deux opérandes d'une entrée, on doit attendre deux cycles. Enfin, certains chercheurs ont proposé des fenêtres d'instruction segmentées. Les instructions circulent à chaque cycle d'un segment vers le suivant : en conséquence, certains segments conservent les instructions les plus anciennes, un autre les instructions les plus jeunes, etc. Seul le denier segment, celui qui contient les instructions les plus vielles, peut émettre une instruction : la détection des opérandes se fait seulement dans le dernier segment, qui contient les instructions les plus anciennes. On économise ainsi beaucoup de comparateurs. Certains chercheurs ont tenté de pipeliner l'étape de sélection des opérandes, ainsi que l'étage d'arbitrage. Mais en faisant cela, il faut plusieurs cycles pour détecter qu'une instruction a ses opérandes prêts, ce qui pose problème face à de nombreuses dépendances RAW. Pour éviter de trop perdre en performances, certains chercheurs ont décidé d'utiliser des techniques pour prédire quelles seront les instructions dont les opérandes seront bientôt prêts. Si détecter qu'une instruction est prête prend n cycles, le processeur devra tenter de prédire la future disponibilité des opérandes n cycles en avance pour obtenir des performances optimales. ===Remplacer la mémoire associative par une RAM=== Une autre optimisation possible est de remplacer la fenêtre d'instruction par une mémoire RAM, dont chaque mot mémoire correspondrait à une entrée. Une telle optimisation permet en théorie de se passer des comparateurs associés à chaque entrée, mais au prix de l'ajout de circuits annexes potentiellement couteux. La première de ces techniques, la '''recherche directe par étiquette''' (direct tag search) fut créée par Weiss et son collègue Smith. Ils cherchaient à améliorer l'algorithme de Tomasulo, un algorithme qu'on expliquera dans quelques chapitres. Rappelons que chaque instruction produit un résultat, qui devra être rapatrié dans une ou plusieurs entrées de la fenêtre d'instruction. L'optimisation de la recherche directe par étiquette fonctionne dans le cas où le résultat de l'instruction n'est utilisé que par une seule entrée, et pas plusieurs. Le principe est simple : chaque champ « opérande » d'une entrée est adressable via le nom de registre de cette opérande. Pour faire le lien entre entrée et nom de registre, la recherche directe par étiquette ajoute une table de correspondances matérielle, une mémoire RAM qui mémorise les adresses des champs « opérande » des entrées. Les adresses envoyées dans cette mémoire sont les noms de registres des résultats. Lors de l'émission, la table de correspondances est mise à jour. Les numéros des champs « opérande » réservés lors de l'émission sont mémorisés dans les mots mémoire qui correspondent aux deux registres sources. Toutefois, une petite vérification est faite lors de l'émission : si il y a déjà une correspondance dans la table pour un registre source, alors une autre instruction compte lire ce registre. Pour éviter d'écraser les données de l'instruction précédente dans la table de correspondances, l'émission de l'instruction est bloquée. [[File:Recherche directe par étiquette.png|centre|vignette|upright=2|Recherche directe par étiquette.]] ==Les fenêtres d’instruction avec préplanification== Avec la '''préplanification''' (''prescheduling''), la fenêtre d’instruction est composée de mémoires FIFO dans lesquelles les instructions sont triées dans l'ordre d'émission. Il n'y a pas de logique d’émission proprement dite, celle-ci se bornant à vérifier si l'instruction située au début de la FIFO peut s’exécuter. Par contre, le préplanificateur détecte les dépendances et en déduit où insérer les instructions dans le tampon d'émission, à l'endroit le plus adéquat. [[File:Préplanification.jpg|centre|vignette|upright=2|Préplanification.]] ===L'usage de FIFO multiples=== La technique de préplanification la plus simple utilise plusieurs FIFO. Quand une instruction a une dépendance avec une autre instruction, les deux sont placées dans la même FIFO. Pour cela, le préplanificateur détecte les chaines d'instructions dépendantes, et place les instructions dans la FIFO adéquate. A chaque cycle, l'unité d'émission lit une micro-opération dans chaque FIFO et vérifie si elle peut l'émettre. Si la micro-opération n'a pas ses opérandes disponibles, ou qu'une dépendance structurelle survient, alors la FIFO est bloquée. La micro-opération attend que la dépendance soit résolue, bloquant toutes les instructions précédentes. Mais les autres FIFO ne sont pas bloquées, laissant de la marge de manœuvre. [[File:Préplanification par FIFO multiples.png|centre|vignette|upright=1.5|Préplanification par FIFO multiples.]] ===La technique du tampon trié=== La technique du '''tampon trié''' trie les instructions selon le temps d'attente avant leur exécution. Les instructions qui sont censées s’exécuter bientôt sont insérées au tout début de la FIFO, tandis que les instructions qui s’exécuteront dans un long moment sont insérées vers la fin. Là encore, l'unité d'émission lit une micro-opération dans la FIFO, et détermine si elle peut être émise. Si une dépendance survient, l'émission est retardée, et la FIFO est bloquée. [[File:Préplanification par tampon trié.png|centre|vignette|upright=1.5|Préplanification par tampon trié.]] La technique a cependant quelques problèmes assez importants. Le premier problème est que la FIFO est bloquée lorsqu'une micro-opération ne peut être émise. Le second problème est que le temps avant exécution n'est pas toujours connu, notamment pour les instructions d'accès mémoire. Et cela se répercute sur les instructions dépendantes de celles-ci. Pour résoudre ce genre de problèmes, l'usage d'un pipeline à ''replay'' est possible, et est même l'une des meilleures solution possible, malgré ses défauts. L'idée est que les lecture sont pré-planifiées en supposant qu'elles font un succès de cache L1. Si la prédiction est fausse, la lecture est ré-exécutée plusieurs cycles plus tard, en supposant qu'elle fait un succès dans le cache L2, et ainsi de suite. Elle est alors ré-insérée dans la FIFO, elle est pré-planifiée une seconde fois. Il en est de même si une micro-opération ne peut pas être émise : il suffit de la réinsérer dans la FIFO au bon endroit, en attendant que ses dépendances soient résolus. Ainsi, l'instruction fautive ne bloque pas la fenêtre d’instruction, et retente sa chance autant de fois qu'il le faut. [[File:Préplanification par fenêtre d’instruction scorebarodée.png|centre|vignette|upright=1.5|Préplanification par fenêtre d’instruction scorebarodée.]] Une autre solution utilise deux fenêtres d’instruction : une FIFO gérée par la préplanification, et une vraie fenêtre d'instruction pour les instructions dont le temps d'attente ne peut pas être déterminé. Il est possible de mettre cette dernière avant la préplanification, afin de gérer les temps d'attente des instructions d'accès mémoire. Quand le temps d'attente d'une lecture devient connu, ses instructions dépendantes sont gérées avec préplanification. [[File:Préplanification avec fenêtre d’instruction.png|centre|vignette|upright=2.5|Préplanification avec fenêtre d’instruction.]] ===Les fenêtres d'instruction avec allocation temporelle statique=== L''''allocation temporelle statique''' correspond à une technique utilisée sur les processeurs Cuzco de l'entreprise Condor. La technique en question a été présenté en 2025, mais des idées similaires ont été présentées dans la littérature académique. Elle ressemble beaucoup aux techniques de pré-planification, avec cependant quelques différences. L'idée est simple : le processeur dispose de plusieurs fenêtres d'instruction, qui mettent en attente les micro-opérations. Lors de l'étape de renommage de registres, le processeur détermine dans combien de cycles d'horloge la micro-opération sera prête pour exécution. La micro-opération est alors mise en attente durant ce nombre de cycles, dans les fenêtres d'instruction, puis est émise une fois ce nombre de cycles écoulés. Ce faisant, les fenêtres d'instruction n'ont pas besoin de détecter la disponibilité des opérandes à chaque cycle, pour chaque micro-opération en attente. Le ''timing'' de l'émission des micro-opérations est décidé à l'avance. L'implémentation exacte n'est pas connue, mais plusieurs solutions sont imaginables. Par exemple, la fenêtre d'instruction peut simplement être composée de plusieurs mémoires de petite taille, chacune contenant les micro-opérations destinées à être exécutées dans N cycles, N étant différent pour chaque mémoire. Une autre solution, plus réaliste, utilise une fenêtre d'instruction dans laquelle la micro-opération est couplée à des champs pour les opérandes, et un champ compteur. Le champ compteur est initialisé avec le nombre de cycles à attendre, et est décrémenté à chaque cycle d'horloge. Quand il atteint zéro, la micro-opération est émise. Vous remarquerez que la méthode ne marche que si toutes les micro-opérations prennent un nombre fixe de cycles d'horloge. Et autant c'est le cas pour les micro-opérations arithmétiques ou logiques, autant les accès mémoire ne rentrent pas dans ce cadre. En théorie, on ne sait pas combien de temps prendra un accès mémoire. Et cette incertitude se répercute sur les instructions dépendantes d'un accès mémoire. Pour éviter cela, le processeur réutilise un pipeline à ''replay'' tel que vu dans le chapitre précédent. L'unité de renommage de registre suppose que tout accès mémoire fait un succès de cache L1, et décide des ''timings'' d'émission sous cette hypothèse. Si une lecture subit un défaut de cache, elle est ré-exécutée, de même que toutes les instructions dépendantes. Pour cela, le registre de destination de la lecture est marqué comme invalide, grâce à un bit spécifique attaché au registre. Toute instruction qui lit une opérande invalide est elle aussi ré-executée de zéro. Pour simplifier, l'unité d'émission ressemble à une unité d'émission dans l'ordre, avec un registre de disponibilité, qu'on aurait amélioré pour aller au-delà de la simple détection des dépendances d'instruction. Pour déterminer les ''timings'' d'émission, à savoir quand émettre une micro-opération, le processeur utilise une unité d'émission à deux étages. Le premier étage est appelé le ''register scoreboard'', le second étage est appelé la ''Time Ressource Matrix''. Les deux étages communiquent entre eux, comme on va le voir, et leurs noms donnent une idée de ce qu'ils font. Le premier étage gère les dépendances de registres, le second gère les dépendances structurelles. Le premier étage est un registre de disponibilité amélioré, qui gère les dépendances de registre. Cet étage sait quand tel registre sera écrit, et donc que l'opérande écrite dedans sera disponible à partir de tel cycle d'horloge. Il le sait car l'étage suivant l'aura prévenu, mais laissons cela de côté pour le moment. Quand une micro-opération rentre dans cet étage, il vérifie les dépendances avec les registres et les micro-opérations antérieures. Vu qu'il sait quand les registres seront disponibles, il peut déterminer quand l'instruction pourra s'exécuter. Par exemple, si une micro-opération lit les deux registres R7 et R15, qui sont disponibles respectivement dans 5 et 7 cycles, le premier étage sait que la micro-opération devra attendre 7 cycles. Mais tout cela ne suffit pas à déterminer quand émettre une micro-opération. En effet, il fait aussi gérer les dépendances structurelles, ce qui est le boulot du second étage. Le second étage utilise pour cela une ''Time Ressource Matrix'', qui mémorise l'occupation de diverses "ressources", pour les 256 cycles d'horloge à venir. Les ressources en question sont les ports de lecture/écriture du banc de registre, les ALUs utilisées, si la micro-opération utilise l'unité mémoire, etc. Le second étage prend en entrée une micro-opération, détermine quelles "ressources" elle utilise, puis regarde leur disponibilité. Elle détecte alors les dépendances structurelles et détermine alors quand peut s'exécuter la micro-opération. Elle peut retarder l'émission de quelques cycles, si une dépendance structurelle est détectée. Une fois sortie du second étage, on sait quand la micro-opération va être émise, à quel cycle précisément. Et vu que la durée de l'instruction est fixe, on sait quand cette micro-opération va se terminer, quand son résultat sera disponible. Cela permet de mettre à jour la ''Time Ressource Matrix'', pour préciser que le port d'écriture sera occupé à tel moment. De plus, cette information est transmise au premier étage, qui sait alors quand est enregistré le résultat dans le registre de destination. C'est comme cela que le premier étage sait quand un registre est disponible : le second étage le prévient, quand il émet une instruction ! La ''Time Ressource Matrix''mémorise l'occupation des "ressources" pour les 256 cycles d'horloge à venir. Cependant, elle ne vérifie pas les dépendances pour les 256 cycles suivants. Quand elle reçoit une micro-opération, elle teste les dépendances structurelles pour seulement les 8 prochains cycles maximum. Si la micro-opération ne peut pas être émise pendant ces 8 cycles, le pipeline est bloqué, un ''pipeline stall'' est émis. Pour être plus précis, vu que le processeur peut décoder 8 micro-opérations en même temps, cela permet de ne consulter que 64 cycles d'horloge sur les 256. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les premiers processeurs Intel | prevText=Les premiers processeurs Intel | next=Le renommage de registres | nextText=Le renommage de registres }} </noinclude> 4tchozsiag6y858hmco7txl7t1emh46 773590 773589 2026-09-29T17:41:15Z Mewtow 31375 /* Les fenêtres d’instruction : généralités */ 773590 wikitext text/x-wiki Dans les chapitres précédents, nous avons parlé des techniques dites d''''émission dans l'ordre'''. L'idée est d’exécuter une nouvelle micro-opération à chaque cycle, dans des unités de calcul séparées. Les instructions sont émises consécutivement, mais les instructions s’exécutent en parallèle dans des unités de calcul séparées. Par contre, quand l'unité d'émission ne peut pas émettre une instruction, elle bloque tout le pipeline. Les instructions qui suivent sont elles aussi bloquées, elle doivent attendre leur tour, même si elles sont en capacité de s'exécuter. Les techniques d'exécution dans le désordre que nous allons voir dans ce chapitre corrigent ce point précis. Elles sont dites à '''émission dans le désordre'''. Elles se distinguent des précédentes sur un point précis : quand l'unité d'émission bloque l'émission d'une instruction, les instructions suivantes peuvent poursuivre. L'émission des instructions peut donc se faire dans le désordre, dans le sens où une instruction peut être émise alors qu'une instruction précédente ne l'est pas encore. L'avantage de l'émission dans le désordre est qu'une instruction s'exécute dès que ses opérandes sont disponibles. Par disponible, on veut dire présent soit dans le réseau de contournement, soit dans les registres. Le processeur détecte automatiquement quand les opérandes d'une instruction sont sont disponibles, et il l’exécute à ce moment là. Dès qu'une instruction a ses opérandes disponibles, elle est émise et exécutée. C'est là la seule contrainte : les dépendances WAR, WAW et autres sont gérées par un ROB ou toute autre technique d'exception précise, seules les dépendances RAW limitent l'exécution. Mais avant de poursuivre, quelques point niveaux terminologie : * L'émission dans le désordre est un terme parlant et assez précis. Malheureusement, la terminologie la plus utilisée par d''''exécution dans le désordre'''. Et nous utiliserons ce terme dans la suite du cours, histoire de ne pas trop dévier de la nomenclature habituelle. * Nous utiliserons parfois l'abréviation OOO pour parler d'exécution dans le désordre. L'abréviation est celle de ''Out Of Order Excution''. * Nous utiliserons aussi l'abréviation ''µop'' pour parler de micro-opération, ''µops'' au pluriels pour parler de plusieurs micro-opérations, ou des micro-opérations en général. L'exécution dans le désordre ne gére en effet que des µops, elle se situe après l'étape de décodage. Mais avant de poursuivre, précisons une chose importante : l'exécution dans le désordre traite les accès mémoire à part. La majorité des processeurs OOO assez anciens exécutent les accès mémoire dans l'ordre, seules les µops entières/flottantes/branchements sont exécutées dans le désordre. Les processeurs datant d'après les années 2010 sont capable d'exécuter les accès mémoire dans le désordre, mais l'implémentation en question est assez particulière. Un chapitre entier sera dédié à l'exécution dans le désordre des µops mémoire. Nous allons volontairement mettre de côté la gestion des accès mémoire dans ce chapitre. ==Les fenêtres d’instruction : généralités== [[File:File de micro-opération.png|vignette|upright=1|File de micro-opérations]] Pour décrire comment est implémentée l'émission dans le désordre, il faut commencer par parler des processeurs sans. Les processeurs sans exécution dans le désordre ont une unité d'émission qui bloque tout le pipeline dès qu'une µop ne peut pas être émise. Pour limiter l'impact de ce blocage, quelques rares processeurs incorporent une '''file de micro-opération''', une mémoire FIFO qui met en attente les µops. Vu que c'est une mémoire FIFO, les µops sont émises dans l'ordre, à savoir l'ordre d'ajout, dans l'ordre de décodage. Le schéma ci-dessous illustre une telle file d'attente couplée à un ''scoreboard''. Sur le principe, l'exécution dans le désordre améliore la file de µops sur un point : ce n'est plus une mémoire FIFO. Les µops sont insérées dans l'ordre, mais peuvent sortir dans le désordre (être émises dans le désordre). La file de µops devient alors une '''fenêtre d'instruction''', terme traduit directement de l'anglais ''instruction Window''. Terme assez trompeur, car elles mettent en attente des µops, pas des instructions. Elles peuvent émettre des µops dans le désordre, ce qui fait que si une µop bloque le pipeline, les µops suivantes peuvent être émises. Si je commence le paragraphe précédent par "sur le principe", c'est car certaines techniques d'OOO utilisent des files de µops normales. Il est par exemple possible d'utiliser une file de µops avec une fenêtre d'instruction, plusieurs files de µops, plusieurs fenêtres d'instructions avec une file de µops annexe, etc. Dasn les grandes lignes, il existe dans les grandes lignes 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! File de µops améliorée |- ! Une seule "file de µops" | ''Scoreboard'' | Fenêtre d'instruction centralisée |- ! Plusieurs "file de µops" | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | Fenêtre d'instruction décentralisée |} ===La fenêtre d'instruction centralisée=== L'implémentation la plus simple de l'OOO utilise une unique '''fenêtre d'instruction'''. Les instructions décodées sont accumulées dans la fenêtre d'instruction, où elles attendent que leurs opérandes soient disponibles. La fenêtre d'instruction sert donc de file d'attente. Mais elle contient aussi une unité d'émission, qui détecte quelles µops sont prêtes à être émises. L'unité d'émission et la fenêtre d'instruction sont fusionnées ensemble, elles forment un seul circuit. Mais nous allons dire qu'elles sont conceptuellement séparées pour le moment. A chaque cycle, l'unité d'émission consulte la fenêtre d'instruction pour voir quelles µops peuvent s'exécuter, lesquelles ont leur opérandes de disponibles. La fenêtre d'instruction doit spécialement être conçue pour, c'est une sorte de mémoire associative très complexe, comme on le verra dans ce qui suit. [[File:OOO Issue.png|centre|vignette|upright=2.5|Exécution dans le désordre avec une fenêtre d'instruction]] Une fois qu'une µop sort du décodeur d'instructions, elle est ajoutée en parallèle dans la fenêtre d'instruction et le ROB. La raison est que les µops quittent la fenêtre d'instruction dans le désordre, et qu'elles doivent être remises en ordre par la suite. Le ROB s'occupe de cette remise en ordre, mais il a besoin de savoir dans quel ordre les µops sont censées être, et cet ordre est celui du décodage. Aussi, pour remplir le ROB, la seule opportunité est en sortie de l'unité de décodage. Dans le cas où une instruction est décodée en plusieurs micro-opérations, elles sont toutes insérées en même temps dans la fenêtre d'instruction et le ROB, en tenant compte de leur ordre. [[File:Fenêtre d'instruction.png|centre|vignette|upright=2|Fenêtre d'instruction.]] Les micro-opérations mémoire sont à part des autres, pour diverses raisons. Une de ces raisons est que les dépendances de données sont classées en deux types : les dépendances de registre et les dépendances d'adresse. Et les deux sont fondamentalement différentes. Autant on peut détecter les dépendances de registre lors de l'émission, autant c'est plus compliqué avec les dépendances d'adresse. De plus, rappelons que si les lectures peuvent s'exécuter dans le désordre, les écritures doivent s'exécuter dans l'ordre, ou du moins en donner l'illusion. Pour cela, le processeur remet les écritures dans l'ordre avec une sorte de mini-ROB intégré à l'unité mémoire, appelée la file d'écriture. Elle complémente le ROB, qui lui ne gère que les écritures dans les registres, mais les deux collaborent. La file d'écriture envoie une écriture à la mémoire RAM quand le ROB lui dit que c'est bon, les instructions précédentes sont terminées ''dans l'ordre du programme''. Les processeurs assez anciens n'autorisaient pas d'exécution dans le désordre des accès mémoire. Pour cela, la fenêtre d'instruction ne mémorise pas de µops mémoire. L'unité mémoire est précédée par une file de micro-opérations séparée, pour forcer l'exécution dans l'ordre des accès mémoire. [[File:Processeur avec émission dans l'ordre des accès mémoire.png|centre|vignette|upright=2|Processeur avec émission dans l'ordre des accès mémoire]] Les processeurs modernes ajoutent des techniques d'exécution dans le désordre des accès mémoire, mais nous les verrons dans un chapitre dédié. Elles permettent d'utiliser une fenêtre d'instruction unique, qui mémorise aussi les µops mémoire. Si elles sont mises en place, l'unité mémoire n'a pas besoin de file de µops séparée. L'idée est que les dépendances de registre sont traitées par la fenêtre d'instruction, mais que l'unité mémoire gére les dépendances d'adresse. Les dépendances d'adresse sont gérées par des techniques de ''désambiguation mémoire'', qui auront droit à un chapitre dédié. [[File:Processeur avec exécution dans le désodre des accès mémoire.png|centre|vignette|upright=2|Processeur avec exécution dans le désodre des accès mémoire]] Dans ce chapitre, on suppose que l'unité mémoire est précédée d'une file de micro-opération mémoire dédiée, rien que pour elle. ===Les fenêtres d'instruction décentralisées=== Une autre solution utilise plusieurs fenêtres d'instruction. Pour faire la différence avec l'usage d'une fenêtre d'instruction unique, nous allons parler de fenêtre d'instruction centralisée s'il n'y en a qu'une dans le processeur, de '''fenêtre d'instruction décentralisée''' s'il y en a plusieurs. Dans le cas général, chaque fenêtre d'instruction est associée à un type précis d'opération/instruction. La tendance moderne est d'utiliser une fenêtre d'instruction pour les instructions de calcul entières, une autre pour les flottantes. Il s'agit d'un choix simple et efficace, mais quelques processeurs font autrement, pour répondre à des contraintes très diverses. L'usage de fenêtres décentralisées simplifie la répartition des instructions sur les différentes unités de calcul. Par exemple, utiliser des fenêtres séparées pour les ALU et les FPU facilite la répartition des instructions de calcul sur les ALU. Une fenêtre centralisée demande de faire la différence entre instruction entière/flottante, puis de choisir sur quelle unité de calcul entière/flottante utiliser. Une fenêtre décentralisée fait les deux choix séparément : d'abord on envoie l'instruction dans la bonne fenêtre suivant si c'est une instruction flottante ou entière, et ensuite on gère la disponibilité des ALUs/opérandes. Et on peut adapter la même idée en séparant les unités d'accès mémoire des ALU entières, etc. Par contre, un défaut est que certaines fenêtres d'instruction peuvent être sous-utilisées. Par exemple, la station de réservation flottante est inutilisée si le programme n'exécute pas d'opérations flottantes. Ou encore, les fenêtres pour les accès mémoire peuvent être sous-utilisées, si le programme effectue peu d'accès mémoire relativement aux autres instructions. En fait, tout dépend de comment sont calibrées les fenêtres d'instruction et de la répartition des instructions dans le programme entre opérations entières, flottantes, mémoire. Par exemple, si un programma de deux fenêtres d'instructions identiques, une pour les calculs entiers et une autre pour les calculs flottants, elles ne seront utilisées à la perfection que si la moitié des instructions du programme fait des calculs flottants et l'autre des calculs entiers. Toute déviation par rapport à cette répartition idéale risque de laisser des entrées vides dans une fenêtre d’instruction. Un point important est que l'émission est découpée en deux étages avec des fenêtres d'instruction décentralisées. La première étape envoie l'instruction décodée vers la fenêtre d'instruction adéquate, la seconde gère l'émission proprement dit. La première est l'étage de ''dispatch'' qui envoie l'instruction dans la fenêtre d’instruction adéquate, selon que c'est une instruction flottante, entière, autre. La seconde est l'étage de ''scheduling'', qui gère la disponibilité des opérandes et des unités de calcul. En clair, on trie les instructions suivant leur type, suivant le type d'unité de calcul adéquate, puis on l'émet proprement dit. Faire ainsi a plusieurs avantages, avec cependant peu d'inconvénients. Lors de l'étape de ''dispatch'', l'instruction émise est ajoutée au tampon de réordonnancement, s'il existe. Sans cela, impossible de conserver l'ordre des instructions. Les instructions sont émises dans l'ordre au niveau de l'unité de ''dispatch'', pas au niveau de l'étage de ''scheduling''. Aussi, pour remplir le ROB, cela doit se faire au dernier moment où les instructions sont émises dans l'ordre, soit en sortie de l'unité de ''dispatch''. De plus, les micro-opérations mémoire sont traitées à part des autres, elles sont envoyées directement à l'unité mémoire. La gestion des calculs d'adresse est quelque peu complexe, mais ils peuvent être fait soit dans l'unité mémoire, soit dans les ALU entières, peu importe. Il y a aussi un système de contournement complexe entre ALU/FPU et unité mémoire, qui n'est pas représenté dans le schéma ci-dessous. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Il faut noter que quelques processeurs utilisent des méthodes intermédiaires entre les trois solutions précédentes. Par exemple, les processeurs AMD Zen utilisent une fenêtre d'instruction décentralisée un peu particulière. Les unités de calcul entières disposent d'une fenêtre d'instruction rien que pour elles, sur ce processeur. Les instructions flottantes sont quant à elles alimentées par une file de micro-opération, pas une fenêtre d'instruction ! La raison à ce choix est un compromis entre performance et cout en circuit. L'exécution dans le désordre est peu efficace sur les instructions flottantes, car les CPU n'ont que peu d'ALU flottantes séparées. Vu le cout en circuits d'une fenêtre d'instruction, les concepteurs du processeur ont préféré utiliser une file de micro-opération pour les opérations flottantes. ===L'usage de plusieurs files d'instruction=== Une dernière méthode d'OOO utilise plusieurs files de micro-opération. L'idée est qu'une fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement une file de micro-opération pour les opérations entières, une autre pour les opérations flottantes, une autre pour les accès mémoire. D'autres processeurs utilisent une file pour les accès mémoire et une autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. La présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que la technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si une dépendance bloque une FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans une autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer la disponibilité des registres. Quand un registre est lu ou écrit par une instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. La logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : une pour les instructions d'accès mémoire et une autre pour les autres instructions. Si jamais une instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de la lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'une est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est la file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. ===Avantages et inconvénients de chaque implémentation=== Un processeur contient soit une fenêtre d'instruction unique, soit plusieurs fenêtres d'instruction séparées. Typiquement, les fenêtres d’instruction séparées sont spécialisées, dans le sens où on a une fenêtre pour les instructions flottantes, une autre pour les instructions entières, une autre pour les accès mémoire, etc. Pour résumer, on a le choix entre une grosse fenêtre généraliste et plusieurs fenêtres spécialisées, sauf que la fenêtre centralisée est lente et complexe, contrairement aux fenêtres spécialisées. Les deux méthodes ont des inconvénients et des avantages différents. Dans les grandes lignes, l'avantage des fenêtres décentralisées est qu'elles sont plus petites qu'une grosse fenêtre d'instruction. Cela simplifie la gestion du contournement et de la répartition des instructions sur les unités de calcul, comme on le verra dans quelques paragraphes. Elles sont donc moins complexes et plus rapides. L'autre avantage, c'est qu'il est possible de démarrer l'exécution de plusieurs instructions simultanément : une instruction par fenêtre décentralisée, contre une par fenêtre d'instruction. Mais les fenêtres décentralisées sont souvent sous-utilisées, partiellement remplies, contrairement aux fenêtres d'instruction. Il arrive qu'une fenêtre d'instruction soit remplie, alors que les autres sont vides. Par exemple, prenons un processeur avec une fenêtre d'instruction reliée à la FPU, et une autre reliée aux autres ALUs. Si le processeur n'exécute que des opérations flottantes, la fenêtre reliée à la FPU sera pleine, alors que l'autre sera vide. L'exécution des instructions dans le désordre est alors limitée par la petite taille de la fenêtre, qui ne peut plus accepter de nouvelle instruction flottante. Avec une fenêtre unique, on n'aurait pas eu ce problème : on aurait eu une énorme fenêtre d'instruction remplie d'instruction flottante, au lieu d'une petite fenêtre spécialisée. Il est maintenant temps de voir en quoi sont faites les fenêtres d’instruction, qu'elles soient centralisées ou décentralisées. Nous allons aussi voir quelle est la logique d'émission associée. ==L'implémentation d'une fenêtre d'instruction : généralités== Une fenêtre d'instruction est une mémoire qui mémorise des micro-opérations. Elle est cependant plus complexe qu'une mémoire RAM ou qu'une FIFO et ressemble un petit peu à une mémoire cache. Elle dispose d'un port d'écriture et d'un port de lecture, au minimum. Le port d'écriture permet à l'unité de décodage d'insérer une micro-opération dedans, d'ajouter la micro-opération qui vient d'être décodée. Si une instruction machine est décodée en plusieurs micro-opération, deux possibilités. La première est de les insérer un par un, ce qui fait qu'on peut se contenter d'un seul port d'écriture. L'autre possibilité est de les ajouter en même temps, ce qui demande plusieurs ports d'écriture. Le port de lecture sert à émettre une instruction. On part du principe que la fenêtre d'instruction ne peut émettre qu'une seule instruction à la fois, car les processeurs que nous avons vu précédemment sont de ce type. Mais nous verrons dans quelques chapitre qu'il existe des processeurs dits superscalaires, qui sont capables d'émettre plusieurs instructions par cycle. Dans ce cas, la fenêtre d'instruction a un seul port de lecture. Un processeur superscalaire, quant à lui, doit avoir un port de lecture par unité de calcul, ce qui fait beaucoup plus. ===Les entrées d'une fenêtre d’instruction=== Les fenêtres d'instruction sont composées d''''entrées''', des mots mémoire qui stockent une instruction. Une instruction réserve une entrée après son décodage et la libère dès qu'elle est envoyée aux unités de calcul. Une entrée contient l'opcode (les signaux de commande à envoyer à l'ALU), le registre de destination du résultat, les registres de chaque opérande, et éventuellement des signaux de commande en plus. De plus, chaque opérande est couplée à un bit de disponibilité, qui indique si elle est disponible. Quand un opérande est écrit dans les registres, le bit de présence correspondant est mis à jour. Enfin, chaque entrée possède un bit ''empty'' qui indique si elle est vide, cette information étant utile pour réserver des entrées. [[File:Entrée d'une station de réservation - sans les tags.png|centre|vignette|upright=3|Entrée d'une fenêtre d'instruction]] Nous verrons dans quelques chapitres que certaines fenêtres d'instruction sont capables de mémoriser les opérandes des instructions. De telles fenêtres d'instruction seront appelées, dans ce cours, des '''stations de réservation'''. Les entrées des stations de réservation sont assez semblables à celle des fenêtres d'instruction, à un détail près : les opérandes de l'instruction sont enregistrées directement dans des champs séparés. Il y a deux champs, un par opérande, pour stocker l'opérande elle-même, lue depuis les registres ou obtenue via le réseau de contournement. Notons que les champs pour les opérandes viennent en plus des champs pour les noms de registres, encore que les deux peuvent être fusionnés si on veut optimiser le tout. [[File:Entrée d'une station de réservation.png|centre|vignette|upright=3|Entrée d'une station de réservation.]] Précisons que la terminologie n'est pas très fiable. Les termes "fenêtre d'instruction" et "station de réservation" ne regroupent pas du tout la même chose d'un papier de recherche à l'autre, d'un bouquin à l'autre, d'un chercheur à l'autre, d'un ingénieur à l'autre, d'un professeur à l'autre. Le terme initial vient pourtant de l'article original sur l'algorithme de Tomasulo, où il désignait une fenêtre d'instruction associée à une unité de calcul précise. Mais le terme a ensuite été réutilisé, ce qui fait que certains processeurs avec plusieurs unités de calcul sont décrit comme ayant une unique station de réservation. En bref : c'est le bazar ! Mais nous en reparlerons dans le chapitre sur le renommage de registres, car c'est la place idéale pour les aborder. Toujours est-il que j'ai fait le choix de confondre les concepts de fenêtre d'instruction et de station de réservation avec les concepts de '''lecture avant émission''' et de '''lecture après émission'''. La différence entre les deux est que les registres sont lus après émission avec une fenêtre d'instruction, avant avec des stations de réservation. Dans le cas "avant émission", les opérandes sont mémorisées dans la station de réservation. Et cette différence a une influence sur le pipeline du processeur, le banc de registres et tout ce qui s'en suit. Un désavantage de la lecture avant émission est qu'il faut stocker les opérandes après lecture, ici dans les stations de réservation. Mais un avantage est que le banc de registre a besoin de moins de ports de lecture, car une bonne partie des opérandes sont fournies par le système de contournement. Nous verrons cela dans le détail dans le chapitre sur les processeurs superscalaires. Il a été proposé de fusionner le tampon de ré-ordonnancement avec la fenêtre d'instruction dans une structure unique. La méthode a notamment été utilisée sur les processeurs d'architecture K6 d'AMD. Le tout donnait une structure appelée le '''DRIS''' (''deferred scheduling register renaming instruction shelf''). La différence avec une fenêtre d’instruction normale est que les entrées sont libérée non pas quand l'instruction est exécutée/émise, mais quand elle termine son exécution et quitte le ROB. La fenêtre d'instruction doit alors incorporer des bits pour savoir si telle entrée a émis sont instruction ou non. ===La logique d'éveil et de sélection=== Dans le cas qui va suivre, on suppose que le processeur ne peut émettre qu'une instruction à la fois. Chaque cycle, une instruction est sélectionnée et est envoyée dans le chemin de données, soit à une ALU, soit à une unité d'accès mémoire. La sélection d'une instruction est effectuée par l'unité d'émission, qui est aussi appelée le '''''scheduler'''''. Elle gère la disponibilité des opérandes et la disponibilité des unités de calcul adéquate. Le choix de l'instruction émise doit être le plus pertinent possible, pour des raisons de performances. Pour le premier point, l'unité d'émission détermine quelles instructions sont candidates pour l'émission. Les ''instructions candidates'' sont celles dont tous les opérandes sont prêts. Le processeur contient un circuit qui détecte les instructions candidates : la '''logique d’éveil''' (''wake-up logic''). Une fois que la logique d'éveil a fait son travail, une instruction est choisie pour s’exécuter en fonction de la disponibilité des unités de calcul adéquates. Ce rôle est dévolu à un circuit qu'on appelle la '''logique de sélection''', ou ''select logic''. [[File:Fonctionnement complet de la logique d’émission.jpg|centre|vignette|upright=1.5|Fonctionnement complet de la logique d’émission.]] La logique de sélection doit gérer le fait que les unités de calcul du processeur ne sont pas toutes identiques. Déjà, un processeur a généralement des unités séparées pour les instructions entières et flottantes, des unités spécialisées dans les accès mémoire, parfois des unités spécialisées pour les branchements. Une instruction doit être attribuée à la bonne unité de calcul, on ne doit pas envoyer une instruction entière dans une unité de calcul flottante. De plus, parmi les unités de calcul entières, toutes ne sont pas identiques. Par exemple, il est fréquent d'avoir plusieurs unités de calcul spécialisées dans les opérations simples (additions, soustractions, opérations logiques) avec une unité pour les multiplications/divisions séparées, parfois une unité spécialisée pour les décalages/rotations, etc. Là encore, allouer la bonne instruction à la bonne ALU est complexe. Plus les unités de calcul sont hétérogènes, plus la logique de sélection est compliquée. Les logiques d'éveil comme de sélection sont assez complexes. Comme on le verra plus bas, la logique de sélection la plus simple, qui gère une seule unité de calcul, est basée sur un encodeur à priorité couplé à d'autres circuits. Et pour gérer plusieurs ALUs, il faut mettre des encodeurs en cascade. Le résultat est que même en prenant une logique de sélection simple, elle sera assez lente et gourmande en circuits. Aussi, la logique de sélection met souvent un cycle d'horloge entier pour faire son travail, elle a son propre étage de pipeline attribué. La logique d'éveil est dans le même cas, ce qui fait qu'émettre une micro-opération demande deux cycles d'horloge. Le défaut est que cela rajoute des cycles d'horloges entre la fenêtre d'instruction et l'ALU, ce qui complique la gestion du pipeline. Ces cycles de retard sont à prendre en compte au moment d'émettre les instructions, les ''scheduler'' doit en tenir compte pour des performances optimales. Sans tenir compte de ces cycles de retard, les instructions arrivent en retard de quelques cycles à l'ALU, cycles de retard durant lesquels l'ALU n'a pas fait de calcul et a été sous-utilisée, sans compter que le système de contournement n'est pas utilisé au mieux. Et le problème est encore plus important sur les processeur avec des stations de réservation, qui utilisent la "lecture après émission" : cela rajoute un cycle d'horloge en plus, un temps de retard en plus. ===La logique d'éveil : l'émission anticipée=== La logique d'éveil doit tenir compte du fait qu'il y a plusieurs étages entre l'émission et l'exécution sur une unité de calcul. Par exemple, un processeur a souvent entre un et à cinq étages entre la file d'attente et les unités de calcul. Il faut lire les registres, gérer le contournement, et cela peut prendre quelques cycles d'horloge. Sur le Pentium 4, on trouve 6 étages entre la fenêtre d’instruction et l'entrée de l'ALU. Si les micro-opérations sont émises quand les opérandes sont disponibles, il y aura un délai de quelques cycles avant qu'elles atteignent l'ALU. Alors qu'idéalement, on souhaiterait que la micro-opération atteigne l'ALU dès que ses opérandes sont disponibles, pour profiter des techniques de contournement. Pour cela, la logique d'éveil émet les instructions quelques cycles en avance pour qu'elles arrivent au bon moment. Il s'agit d'une technique d''''émission anticipée''', dont nous avions parlé dans le chapitre sur le contournement. : Il faut noter que le problème se pose plus avec des fenêtres d'instruction qu'avec des stations de réservation. Les premières ont un étage en plus entre émission et ALU, vu qu'il faut lire des registres après l'émission. L'émission anticipée demande d'émettre un signal d'éveil en avance de quelques cycles, pile au bon moment. Par exemples, si on a deux étages entre l'ALU et l'unité d'émission, le signal de réveil sera généré deux cycles avant que le résultat soit effectivement calculé. L'implémentation varie, mais deux solutions sont possibles. La première est de générer le signal d'éveil dans l'ALU, ce qui n'a de sens que pour les opérations comme les multiplications ou les divisions, qui prennent plusieurs cycles. Une autre technique génère le signal de réveil dans une structure centralisée, spécialisée dans la génération des signaux d'éveil. L'unité de composée d'un registre à décalage par registre. Imaginons qu'une instruction est émise, que cette instruction mette N cycles à s'exécuter, et qu'elle écrive dans un registre de destination. L'unité sélectionne alors le registre à décalage associé au registre de destination, et met le bit numéro N à 1. Le registre décalé d'un cran à chaque cycle. Quand le bit sortant est un 1, alors le signal de validité pour l'opérande est généré. L'émission anticipée marche bien si l'instruction a une durée fixe, connue à l'avance. Et autant c'est le cas pour les instructions arithmétiques et logiques, autant ce n'est pas le cas pour les accès mémoire. Les accès mémoire ont une latence variable : quelques cycles pour un succès de cache, plusieurs dizaines de cycles pour un défaut de cache L1, pas loin de la centaine pour un défaut de cache L2, etc. Et cela pose des problèmes pour l'émission anticipée. L'émission en avance pour les accès mémoire est purement spéculative : le processeur émet des instructions en supposant que la lecture entrainera un succès de cache, quitte à annuler l'instruction en cas de défaut de cache. Mais faire ainsi demande non seulement d'annuler les instructions émises en avance, mais aussi de ne pas retirer les instructions émises en avance de la fenêtre d'instruction. Elles sont émises, mais une copie de sauvegarde est conservée dans la fenêtre d'instruction. Si le processeur détecte un défaut de cache, il peut alors ré-exécuter l'instruction. S'il détecte un succès de cache, les instructions lecture-dépendante sont retirées de la fenêtre d'instruction, la copie de sauvegarde est devenue inutile et est donc jetée. ===La logique de sélection : âge ou position ?=== La logique de sélection est primordiale pour de bonnes performances. Il existe deux méthodes principales pour sélectionner l'instruction à exécuter. La première est la plus simple : elle se base sur lé numéro de l'entrée. En effet, une fenêtre d'instruction est avant tout une sorte de mémoire, un mix entre mémoire associative, mémoire RAM, et FIFO. Et chaque entrée a un numéro, une adresse mémoire. Nous parlerons de numéro dans ce qui suit, car ce sera plus simple, le terme d'adresse mémoire étant peut-être un peu exagéré dans le contexte des fenêtres d'instruction. Toujours est-il que la fenêtre d'instruction est adressable dans le sens où on peut lui envoyer le numéro de l'entrée voulue, et la fenêtre d’instruction renvoie le contenu de l'entrée sur son port de lecture. Et c'est ce que fait la logique de sélection : elle génère le numéro de l'entrée à lire. Le numéro est alors envoyé sur l'entrée d'adresse de la fenêtre d’instruction, et elle fournit la micro-opération associée sur son port de lecture, son '''port d'émission'''. La première méthode de sélection, donc. Elle est basée sur sur le numéro de l'entrée. Si plusieurs entrées sont éveillées, la logique de sélection prend celle avec le plus petit numéro. Elle porte le nom de '''sélection par position''', sous-entendu position dans la fenêtre d'instruction. Vous l'avez peut-être deviné, mais la logique de sélection est alors un encodeur à priorité. Le circuit de sélection ne se résume donc pas seulement à un encodeur à priorité, mais c'est le circuit central. L'avantage d'une telle méthode de sélection est qu'elle est simple à implémenter : un encodeur à priorité est un circuit connu, facile à implémenter. Mais on remarque un défaut : un encodeur est un circuit assez rapide, mais qui utilise beaucoup de transistors, beaucoup de portes logiques, surtout si on veut qu'il soit rapide. Ce qui explique que la logique de sélection ait son propre étage de pipeline rien que pour elle. La seconde méthode s'appelle la '''sélection par âge''', au nom assez transparent. L'idée est de privilégier l'émission de l'instruction la plus ancienne. Elle demande que la fenêtre d'instruction trie les micro-opérations par ordre d'insertion dans la fenêtre d'instruction, ce qui en fait une pseudo-FIFO. Le tri est partiel, car les instructions peuvent sortir de la fenêtre d’instruction à tout moment. Compacter la fenêtre d'instruction, à savoir regrouper toutes les entrées valides est une idée, mais elle est compliquée à implémenter. Aussi, elles préfèrent encoder des informations sur l'ordre d'émission dans chaque entrée. L'encodeur à priorité doit alors travailler non pas sur des nombres entiers liés à l'ordre d'insertion dans la pseudo-FIFO. Elle est encore plus gourmande en circuits que la méthode précédente. Les processeurs haute performance utilisent souvent des méthodes hybrides. Par exemple, les processeurs AMD de microarchitecture Bulldozer utilisaient une méthode intermédiaire. Ils utilisaient une fenêtre d'instruction couplée à un encodeur à priorité pour la sélection par position, mais complémentaient le tout avec une unité qui mémorisait l'instruction la plus ancienne dans la fenêtre d’instruction. Le mécanisme de sélection par âge était utilisé en priorité. Mais si l'instruction la plus ancienne n'était pas prête, le processeur basculait sur le mécanisme de sélection par position. ===La compaction des fenêtres d'instruction=== À chaque cycle, les instructions décodées sont ajoutées dans la fenêtre d'instruction, dans des entrées vides. Vu que les instructions quittent celle-ci dans le désordre, ces vides sont dispersés dans la fenêtre d'instruction, ce qui pose problème pour déterminer où placer les nouvelles instructions. La solution la plus triviale consiste à conserver une liste des vides, mise à jour à chaque insertion ou émission d'instruction. Une autre solution consiste à éliminer les vides en compactant la fenêtre d'instruction à chaque cycle d'horloge. Des circuits se chargent de détecter les vides et de regrouper les instructions en un unique bloc. Il faut signaler que certaines processeurs arrivent à se passer de cette étape de compactage, mais au prix de fenêtres d'instruction nettement plus complexes. Autre problème : quand il faut choisir quelle instruction émettre, il y a toujours plusieurs candidats. Si on choisit mal, des instructions restent en attente trop longtemps parce que d'autres instructions plus jeunes leur passent devant. Pour éviter cela, les instructions les plus vielles, les plus anciennes, sont prioritaires. Pour cela, on peut utiliser une FIFO un peu spéciale pour la fenêtre d'instruction. Si les ajouts d'instruction se font dans l'ordre, les instructions ne quittent pas forcément la fenêtre d'instruction dans l'ordre imposé par une FIFO : les instructions restent triées dans leur ordre d'ajout, même s'il y a des vides entre elles. Dans ces condition, il est préférable que le compactage conserve l'ordre FIFO des instructions. Dans ces conditions, l'instruction la plus ancienne est celle qui est située à l'adresse la plus faible : le circuit de sélection peut donc être fabriqué avec des encodeurs, et est relativement simple. ==Les fenêtres d'instruction basées sur une matrice de dépendances== L'implémentation la plus simple étend le fonctionnement d'un pipeline dynamique usuel. Rappelez-vous le chapitre sur les pipeline dynamiques. Nous avions vu que de tels pipelines émettaient une instruction par cycle, quitte à émettre des bulles de pipeline en cas de dépendance bloquante. Et il est possible d'améliorer leur unité d'émission pour qu'elle soit compatible avec l'exécution dans le désordre. ===Rappels sur le registre de réservation/disponibilité=== L'émission d'une instruction est gouvernée par un ''registre de réservation'' qui indique quels registres sont réservés par une instruction, et ceux qui sont libres. Un registre réservé est un registre qui sera écrit par une instruction en cours d'exécution, mais qui n'a pas encore écrit son résultat. Les instructions candidates doivent avoir leurs opérandes dans des registres libres. Sinon, c'est signe que leurs opérandes sont réservées en écriture, donc pas encore écrites, donc pas disponibles. Si une instruction candidate veut lire ce registre, c'est signe qu'il y a une dépendance RAW : elle veut lire un registre réservé, qui est destiné à être écrit par une instruction en vol. Si elle veut écrire, c'est signe qu'elle veut écrire dans un registre où une autre instruction veut écrire : c'est une dépendance WAW. Dans les deux cas, l'instruction n'est pas émise. Le registre de réservation encode les registres réservés comme suit : chaque bit est associé à un registre. Le bit numéro 0 est associé au registre numéro 0, le bit numéro 1 au registre numéro 1, etc. Là, En clair, les numéros de registres réservés sont encodés en représentation non pas binaire, mais en représentation ''one-hot'' (vue au premier chapitre). {|class="wikitable" |+ Registre de réservation |- ! Registre 7 !! Registre 6 !! Registre 5 !! Registre 4 !! Registre 3 !! Registre 2 !! Registre 1 !! Registre 0 |- | 0 || 0 || 1 || 0 || 0 || 1 || 0 || 0 |} Avant d'émettre une instruction, l'unité d'émission extrait les registres opérande/destination et les convertis dans la même représentation que le registre de réservation, à savoir en représentation ''one-hot''. Le circuit de traduction binaire vers ''one-hot'' est, pour rappel, un simple décodeur. Puis, on fait un OU logique entre les sorties des décodeurs. Le résultat est un masque qui indique quels registres sont lus par l'instruction, encodé en représentation ''one-hot''. Appelons-le le '''masque d'opérandes'''. Le masque est alors comparé au registre de réservation pour vérifier si l'instruction peut être émise. [[File:Unité d'émission simple, dans l'ordre.png|centre|vignette|upright=2|Unité d'émission simple, dans l'ordre]] Si l'émission est autorisée, le registres de réservation est là aussi mis à jour. Le registre de réservation est aussi mis à jour dès qu'une instruction enregistre son résultat dans les registres, ou alors dès qu'il est disponible pour le contournement. Le bit associé au registre repasse alors à 0 (ou à 1). Sans contournement, la mise à jour se fait alors à la toute fin de l'instruction, quand elle se termine, lors de la dernière étape d'enregistrement, à la fin de son pipeline. Avec, elle se fait quand l'instruction quitte l'unité de calcul. ===L'extension à l'exécution dans le désordre : l'éveil par matrice de bits=== La différence entre un pipeline dynamique et l'exécution dans le désordre est que l'on passe d'une instruction à émettre à plusieurs. Plusieurs instructions sont mises en attente dans une fenêtre d’instruction, et y attendent leur tour. L'idée est alors d'envoyer le registre de disponibilité à toutes les entrées, à toutes les instructions en attente. Ainsi, on sait quelles sont les instructions qui peuvent s'exécuter et celles qui ne le peuvent pas. L'implémentation est assez simple, elle ressemble beaucoup à l'implémentation d'un pipeline dynamique simple, si ce n'est que des circuits sont dupliqués. L'implémentation utilise des fenêtres d'instruction légèrement différentes de celles introduites plus haut. Elles n'utilisent notamment pas de bits de disponibilité, mais autre chose. Lorsqu'une instruction est ajoutée à la fenêtre d'instruction, le masque de disponibilité des opérandes est stocké dans la fenêtre d'instruction. A chaque cycle, le registre de disponibilité est envoyée à toutes les entrées, et est comparé avec tous les masques de disponibilité des opérandes. Si une comparaison renvoie un 1, alors l'instruction de l'entrée est une instruction candidate à l'émission. [[File:Unité d'émission dans le désordre basée sur un registre de disponibilité.png|centre|vignette|upright=2.5|Unité d'émission dans le désordre basée sur un registre de disponibilité]] L'ensemble est implémenté avec l'aide d'une '''matrice de bits''', où chaque ligne correspond à une entrée et chaque colonne à un registre. À chaque croisement entre une ligne et une colonne, on trouve un bit. Si le bit de la ligne n et de la colonne m est à 1, cela veut dire : l'instruction dans l'entrée n a besoin de lire le registre m. S’il est à 0, alors cela veut dire que l'instruction stockée dans la ligne n n'a pas besoin de la donnée dans le registre m. [[File:Planificateur à matrice de bits.jpg|centre|vignette|upright=2|Planificateur à matrice de bits.]] Lorsqu'une instruction réserve une entrée, elle initialise la ligne en fonction des registres qu'elle souhaite lire. Pour vérifier si une instruction a ses opérandes prêts, le processeur compare le registre de disponibilité à la ligne associée à l'instruction/entrée. A chaque intersection ligne-colonne, se trouve un comparateur de 1 bit, qui détecte si le registre est demandé et disponible. Les résultats de cette porte sont ensuite envoyés à une porte ET, qui fait le gros du travail. [[File:Logique de détection de la disponibilité d'une instruction.jpg|centre|vignette|upright=2|Logique de détection de la disponibilité d'une instruction.]] ==Les fenêtres d'instruction basées sur une mémoire associative== Les processeurs modernes utilisent une mémoire associative pour la fenêtre d'instruction. Les mémoires associatives ont été abordées il y a quelques chapitres, mais faisons quelques rappels. Les mémoires associatives servent à accélérer la recherche de données dans un ensemble. Or, une fenêtre d'instruction vérifie régulièrement si chaque entrée est prête. Il s'agit d'un processus de recherche d'une instruction qui respecte une condition bien précise dans la mémoire, ce qui fait que les mémoires associatives sont donc tout indiquées. Comme vous le savez, les signaux de commande d'une instruction sont propagés avec celle-ci dans le pipeline, le nom du registre de destination ne faisant pas exception. Le nom de registre est envoyé à la fenêtre d'instruction lors de l'écriture du résultat dans les registres. S'il y a correspondance, l'opérande est disponible et son bit de disponibilité est mis à 1. On peut adapter cette méthode pour tenir compte du contournement assez simplement. [[File:Détection des dépendances par propagation du registre de destination.png|centre|vignette|upright=2|Détection des dépendances par propagation du registre de destination.]] En conséquence, le circuit de détection des dépendances est constitué d'un grand nombre de comparateurs : un par champ « nom de registre » dans chaque entrée. La logique d'éveil/''wake up'' regroupe tous les comparateurs, la logique de sélection est un circuit situé en-dehors de la mémoire associative. Les entrées sont dans la mémoire associative elle-même. [[File:Gestion des bits de validité.png|centre|vignette|upright=2|Gestion des bits de validité.]] L'implémentation la plus simple est celle du schéma précédent, où on utilise une mémoire associative unique. Une version plus élaborée sépare la fenêtre d'instruction en deux parties : une mémoire qui mémorise les registres des opérandes, une autre mémoire pour le reste. La mémoire pour les registres opérandes est la mémoire associative proprement dite, c'est elle qui est associées aux comparateurs, à la logique de ''wake-up''/réveil, etc. Par contre, l'autre mémoire est une mémoire RAM simplifiée, qui mémorise les informations qui n'ont pas besoin des comparateurs. L'opcode de l'instruction est là-dedans, par exemple. ===Les optimisations de la consommation d'énergie : la désactivation des portions inutilisées=== Le problème avec des fenêtres d'instruction de ce type est leur forte consommation énergétique, ainsi que le grand nombre de portes logiques utilisées, qui deviennent prohibitif pour des fenêtres d'instruction un peu grosses. Pour résoudre ce problème, certains ont optimisé les comparateurs. D'autres ont tenté de profiter du fait que la majorité des bits dans les entrées sont composés de zéros. Bref, les optimisations purement matérielles sont légion. Une première solution est de désactiver les entrées qui sont inutilisées, vides, sans instruction. Pour cela, on fait précéder les comparateurs par un circuit qui les connecte ou déconnecte des lignes de bit. Le circuit est commandé par le bit ''empty'' qui indique si une entrée est vide ou non. L'avantage est que la consommation d'énergie de la fenêtre d'instruction devient alors proportionnelle au nombre d'entrées non-vides, et non au nombre d'entrées total. Du moins, en apparence, les entrées non-utilisées doivent quand même être alimentées pour fonctionner, mais l'activité de comparaison disparait dans les entrées vides. Il est possible d'étendre cette technique aux entrées dont les opérandes sont prêtes. Les gains sont généralement assez bons, avec une réduction de consommation variant entre 30 et 50%, avec une implémentation très simple et très économe en circuits. Une autre solution, assez simple à mettre en place, consiste à désactiver une partie de la fenêtre d'instruction sin elle est inutilisée. Pour cela, il faut segmenter la fenêtre d'instruction avec la technique du ''wire partitionning''. Pour rappel, une fenêtre d'instruction est une mémoire associative. Et comme toute mémoire associative, elle contient des fils, les lignes de bit, qui relient les entrées/sorties à toutes les cellules mémoire. Plus une ligne de bit est longue, plus elle consomme d'énergie et plus le temps de lecture/écriture est long. L'idée est de segmenter les lignes de bits en plaçant des répéteurs qui recopient la tension d'un segment au suivant. Les répéteurs sont des tampons trois-états, ce qui permet de déconnecter les portions inutilisées de la ligne de bit. Ce faisant, la fenêtre d'instruction est découpée en segments, qui peuvent être désactivés si besoin. Si il y a peu d'instructions chargées dans la fenêtre d'instruction, les portions inutilisées sont désactivées. La technique marche d'autan mieux si les instructions sont compactées au début de la fenêtre d'instruction. [[File:Wire partitionning.png|centre|vignette|upright=2|Wire partitionning]] Tout le problème est de savoir quelles portions désactiver. La technique est assez simple si la fenêtre d'instruction est compactée, à savoir si toutes les instructions sont régulièrement regroupées au début de la mémoire CAM. Mais même avec cette optimisation, la décision de désactiver une portion de la fenêtre d'instruction n'est pas à prendre à la légère. Il ne faut pas désactiver une portion contenant des instructions pouvant être émise sous peu. La décision dépend de paramètres variés : proportion d'entrée vides, quantité d'entrées récemment activées/désactivées récemment, présences d'entrées avec un ''match'' d'opérandes récent, etc. Il est important de préciser que les techniques en question fonctionnent aussi sur les autres types de fenêtre d'instruction, qui ne sont pas basées sur des mémoires associatives. Nous allons voir celles-ci dans la suite du chapitre, mais gardez à l'esprit que ces optimisations, à savoir désactiver les entrées vides/prêts et partitionner la fenêtre d'instruction, sont des optimisations générales qui marchent avec presque tout. ===L'ajout d'une FIFO pour les instructions déjà prêtes à l'émission=== D'autres techniques permettent de réduire aussi bien le cout en circuits que la consommation d'énergie de la fenêtre d'instruction. L'idée est d'utiliser une mémoire associative quand elle est réellement nécessaire, mais d'utiliser une fenêtre d'instruction "normale" dès que possible. La méthode la plus simple tient compte du fait que certaines instructions ont déjà toutes leurs opérandes de disponibles à l'émission, mais doivent quand même être mises en attente, parce que l'ALU adéquate est occupée, parce que des dépendances WAW/WAR sont encore là, ou pour tout autre raison. Dans ce cas, elles sont mises en attente non pas dans la fenêtre d'instruction, mais dans une mémoire FIFO toute simple. L'idée est qu'au lieu d'avoir une énorme mémoire associative pour la fenêtre d'instruction, on déplace quelques entrées dans une petite FIFO annexe. Le résultat est un gain en terme d'énergie et de circuits, au prix d'une perte de performance mineure. La perte de performance en question se manifeste si aucune instruction n'a ses opérandes de prêtes à l'émission : le programme n'utilise pas la FIFO et voit alors une fenêtre d'instruction plus petite. Une amélioration de cette technique tient compte du fait que certaines instructions sont dans un cas intermédiaire. Elles ont déjà une opérande de prête lors de l'émission, mais pas l'autre. Le nombre d'opérandes varie suivant l’instruction : certaines n'ont besoin que d'un seul opérande. De plus, il arrive qu'une opération tout juste décodée ait déjà un ou plusieurs de ses opérandes de prêts. Cette constatation permet d'éviter d'utiliser des comparateurs pour les opérandes déjà prêts. Par exemple, on peut parfaitement utiliser trois fenêtres d'instruction : * une pour les instructions dont tous les opérandes sont prêts, mais qui sont quand même mises en attente, sans comparateur ; * une pour les instructions dont un seul opérande manque, qui n'utilise qu'un comparateur par entrée ; * une pour les instructions dont deux opérandes manquent à l'appel, qui utilise deux comparateurs par entrée. C'est beaucoup plus économique que d'utiliser une seule grosse fenêtre d'instruction qui contiendrait autant d'entrées que les trois précédentes réunies, avec deux comparateurs par entrée. Certains sont même allés plus loin, et ont proposé de supprimer la fenêtre d'instruction avec deux opérandes par entrée. Les instructions dont deux opérandes sont inconnus au décodage sont stockées dans la fenêtre d'instruction pour instructions avec un comparateur par entrée. Un circuit de prédiction se charge alors de prédire l'opérande manquant, cette prédiction étant vérifiée plus loin dans le pipeline. Il serait cependant étonnant qu'une telle proposition ait donné lieu à la moindre implémentation réelle. ===Les optimisations de la consommation d'énergie avancées=== D'autres chercheurs ont conservé une fenêtre d'instruction unique, avec autant de comparateurs par entrée qu'il y a d'opérandes possibles par instruction. Simplement, le processus de détection des opérandes prêts est légèrement ralenti : on ne vérifie qu'un opérande par cycle. Pour vérifier les deux opérandes d'une entrée, on doit attendre deux cycles. Enfin, certains chercheurs ont proposé des fenêtres d'instruction segmentées. Les instructions circulent à chaque cycle d'un segment vers le suivant : en conséquence, certains segments conservent les instructions les plus anciennes, un autre les instructions les plus jeunes, etc. Seul le denier segment, celui qui contient les instructions les plus vielles, peut émettre une instruction : la détection des opérandes se fait seulement dans le dernier segment, qui contient les instructions les plus anciennes. On économise ainsi beaucoup de comparateurs. Certains chercheurs ont tenté de pipeliner l'étape de sélection des opérandes, ainsi que l'étage d'arbitrage. Mais en faisant cela, il faut plusieurs cycles pour détecter qu'une instruction a ses opérandes prêts, ce qui pose problème face à de nombreuses dépendances RAW. Pour éviter de trop perdre en performances, certains chercheurs ont décidé d'utiliser des techniques pour prédire quelles seront les instructions dont les opérandes seront bientôt prêts. Si détecter qu'une instruction est prête prend n cycles, le processeur devra tenter de prédire la future disponibilité des opérandes n cycles en avance pour obtenir des performances optimales. ===Remplacer la mémoire associative par une RAM=== Une autre optimisation possible est de remplacer la fenêtre d'instruction par une mémoire RAM, dont chaque mot mémoire correspondrait à une entrée. Une telle optimisation permet en théorie de se passer des comparateurs associés à chaque entrée, mais au prix de l'ajout de circuits annexes potentiellement couteux. La première de ces techniques, la '''recherche directe par étiquette''' (direct tag search) fut créée par Weiss et son collègue Smith. Ils cherchaient à améliorer l'algorithme de Tomasulo, un algorithme qu'on expliquera dans quelques chapitres. Rappelons que chaque instruction produit un résultat, qui devra être rapatrié dans une ou plusieurs entrées de la fenêtre d'instruction. L'optimisation de la recherche directe par étiquette fonctionne dans le cas où le résultat de l'instruction n'est utilisé que par une seule entrée, et pas plusieurs. Le principe est simple : chaque champ « opérande » d'une entrée est adressable via le nom de registre de cette opérande. Pour faire le lien entre entrée et nom de registre, la recherche directe par étiquette ajoute une table de correspondances matérielle, une mémoire RAM qui mémorise les adresses des champs « opérande » des entrées. Les adresses envoyées dans cette mémoire sont les noms de registres des résultats. Lors de l'émission, la table de correspondances est mise à jour. Les numéros des champs « opérande » réservés lors de l'émission sont mémorisés dans les mots mémoire qui correspondent aux deux registres sources. Toutefois, une petite vérification est faite lors de l'émission : si il y a déjà une correspondance dans la table pour un registre source, alors une autre instruction compte lire ce registre. Pour éviter d'écraser les données de l'instruction précédente dans la table de correspondances, l'émission de l'instruction est bloquée. [[File:Recherche directe par étiquette.png|centre|vignette|upright=2|Recherche directe par étiquette.]] ==Les fenêtres d’instruction avec préplanification== Avec la '''préplanification''' (''prescheduling''), la fenêtre d’instruction est composée de mémoires FIFO dans lesquelles les instructions sont triées dans l'ordre d'émission. Il n'y a pas de logique d’émission proprement dite, celle-ci se bornant à vérifier si l'instruction située au début de la FIFO peut s’exécuter. Par contre, le préplanificateur détecte les dépendances et en déduit où insérer les instructions dans le tampon d'émission, à l'endroit le plus adéquat. [[File:Préplanification.jpg|centre|vignette|upright=2|Préplanification.]] ===L'usage de FIFO multiples=== La technique de préplanification la plus simple utilise plusieurs FIFO. Quand une instruction a une dépendance avec une autre instruction, les deux sont placées dans la même FIFO. Pour cela, le préplanificateur détecte les chaines d'instructions dépendantes, et place les instructions dans la FIFO adéquate. A chaque cycle, l'unité d'émission lit une micro-opération dans chaque FIFO et vérifie si elle peut l'émettre. Si la micro-opération n'a pas ses opérandes disponibles, ou qu'une dépendance structurelle survient, alors la FIFO est bloquée. La micro-opération attend que la dépendance soit résolue, bloquant toutes les instructions précédentes. Mais les autres FIFO ne sont pas bloquées, laissant de la marge de manœuvre. [[File:Préplanification par FIFO multiples.png|centre|vignette|upright=1.5|Préplanification par FIFO multiples.]] ===La technique du tampon trié=== La technique du '''tampon trié''' trie les instructions selon le temps d'attente avant leur exécution. Les instructions qui sont censées s’exécuter bientôt sont insérées au tout début de la FIFO, tandis que les instructions qui s’exécuteront dans un long moment sont insérées vers la fin. Là encore, l'unité d'émission lit une micro-opération dans la FIFO, et détermine si elle peut être émise. Si une dépendance survient, l'émission est retardée, et la FIFO est bloquée. [[File:Préplanification par tampon trié.png|centre|vignette|upright=1.5|Préplanification par tampon trié.]] La technique a cependant quelques problèmes assez importants. Le premier problème est que la FIFO est bloquée lorsqu'une micro-opération ne peut être émise. Le second problème est que le temps avant exécution n'est pas toujours connu, notamment pour les instructions d'accès mémoire. Et cela se répercute sur les instructions dépendantes de celles-ci. Pour résoudre ce genre de problèmes, l'usage d'un pipeline à ''replay'' est possible, et est même l'une des meilleures solution possible, malgré ses défauts. L'idée est que les lecture sont pré-planifiées en supposant qu'elles font un succès de cache L1. Si la prédiction est fausse, la lecture est ré-exécutée plusieurs cycles plus tard, en supposant qu'elle fait un succès dans le cache L2, et ainsi de suite. Elle est alors ré-insérée dans la FIFO, elle est pré-planifiée une seconde fois. Il en est de même si une micro-opération ne peut pas être émise : il suffit de la réinsérer dans la FIFO au bon endroit, en attendant que ses dépendances soient résolus. Ainsi, l'instruction fautive ne bloque pas la fenêtre d’instruction, et retente sa chance autant de fois qu'il le faut. [[File:Préplanification par fenêtre d’instruction scorebarodée.png|centre|vignette|upright=1.5|Préplanification par fenêtre d’instruction scorebarodée.]] Une autre solution utilise deux fenêtres d’instruction : une FIFO gérée par la préplanification, et une vraie fenêtre d'instruction pour les instructions dont le temps d'attente ne peut pas être déterminé. Il est possible de mettre cette dernière avant la préplanification, afin de gérer les temps d'attente des instructions d'accès mémoire. Quand le temps d'attente d'une lecture devient connu, ses instructions dépendantes sont gérées avec préplanification. [[File:Préplanification avec fenêtre d’instruction.png|centre|vignette|upright=2.5|Préplanification avec fenêtre d’instruction.]] ===Les fenêtres d'instruction avec allocation temporelle statique=== L''''allocation temporelle statique''' correspond à une technique utilisée sur les processeurs Cuzco de l'entreprise Condor. La technique en question a été présenté en 2025, mais des idées similaires ont été présentées dans la littérature académique. Elle ressemble beaucoup aux techniques de pré-planification, avec cependant quelques différences. L'idée est simple : le processeur dispose de plusieurs fenêtres d'instruction, qui mettent en attente les micro-opérations. Lors de l'étape de renommage de registres, le processeur détermine dans combien de cycles d'horloge la micro-opération sera prête pour exécution. La micro-opération est alors mise en attente durant ce nombre de cycles, dans les fenêtres d'instruction, puis est émise une fois ce nombre de cycles écoulés. Ce faisant, les fenêtres d'instruction n'ont pas besoin de détecter la disponibilité des opérandes à chaque cycle, pour chaque micro-opération en attente. Le ''timing'' de l'émission des micro-opérations est décidé à l'avance. L'implémentation exacte n'est pas connue, mais plusieurs solutions sont imaginables. Par exemple, la fenêtre d'instruction peut simplement être composée de plusieurs mémoires de petite taille, chacune contenant les micro-opérations destinées à être exécutées dans N cycles, N étant différent pour chaque mémoire. Une autre solution, plus réaliste, utilise une fenêtre d'instruction dans laquelle la micro-opération est couplée à des champs pour les opérandes, et un champ compteur. Le champ compteur est initialisé avec le nombre de cycles à attendre, et est décrémenté à chaque cycle d'horloge. Quand il atteint zéro, la micro-opération est émise. Vous remarquerez que la méthode ne marche que si toutes les micro-opérations prennent un nombre fixe de cycles d'horloge. Et autant c'est le cas pour les micro-opérations arithmétiques ou logiques, autant les accès mémoire ne rentrent pas dans ce cadre. En théorie, on ne sait pas combien de temps prendra un accès mémoire. Et cette incertitude se répercute sur les instructions dépendantes d'un accès mémoire. Pour éviter cela, le processeur réutilise un pipeline à ''replay'' tel que vu dans le chapitre précédent. L'unité de renommage de registre suppose que tout accès mémoire fait un succès de cache L1, et décide des ''timings'' d'émission sous cette hypothèse. Si une lecture subit un défaut de cache, elle est ré-exécutée, de même que toutes les instructions dépendantes. Pour cela, le registre de destination de la lecture est marqué comme invalide, grâce à un bit spécifique attaché au registre. Toute instruction qui lit une opérande invalide est elle aussi ré-executée de zéro. Pour simplifier, l'unité d'émission ressemble à une unité d'émission dans l'ordre, avec un registre de disponibilité, qu'on aurait amélioré pour aller au-delà de la simple détection des dépendances d'instruction. Pour déterminer les ''timings'' d'émission, à savoir quand émettre une micro-opération, le processeur utilise une unité d'émission à deux étages. Le premier étage est appelé le ''register scoreboard'', le second étage est appelé la ''Time Ressource Matrix''. Les deux étages communiquent entre eux, comme on va le voir, et leurs noms donnent une idée de ce qu'ils font. Le premier étage gère les dépendances de registres, le second gère les dépendances structurelles. Le premier étage est un registre de disponibilité amélioré, qui gère les dépendances de registre. Cet étage sait quand tel registre sera écrit, et donc que l'opérande écrite dedans sera disponible à partir de tel cycle d'horloge. Il le sait car l'étage suivant l'aura prévenu, mais laissons cela de côté pour le moment. Quand une micro-opération rentre dans cet étage, il vérifie les dépendances avec les registres et les micro-opérations antérieures. Vu qu'il sait quand les registres seront disponibles, il peut déterminer quand l'instruction pourra s'exécuter. Par exemple, si une micro-opération lit les deux registres R7 et R15, qui sont disponibles respectivement dans 5 et 7 cycles, le premier étage sait que la micro-opération devra attendre 7 cycles. Mais tout cela ne suffit pas à déterminer quand émettre une micro-opération. En effet, il fait aussi gérer les dépendances structurelles, ce qui est le boulot du second étage. Le second étage utilise pour cela une ''Time Ressource Matrix'', qui mémorise l'occupation de diverses "ressources", pour les 256 cycles d'horloge à venir. Les ressources en question sont les ports de lecture/écriture du banc de registre, les ALUs utilisées, si la micro-opération utilise l'unité mémoire, etc. Le second étage prend en entrée une micro-opération, détermine quelles "ressources" elle utilise, puis regarde leur disponibilité. Elle détecte alors les dépendances structurelles et détermine alors quand peut s'exécuter la micro-opération. Elle peut retarder l'émission de quelques cycles, si une dépendance structurelle est détectée. Une fois sortie du second étage, on sait quand la micro-opération va être émise, à quel cycle précisément. Et vu que la durée de l'instruction est fixe, on sait quand cette micro-opération va se terminer, quand son résultat sera disponible. Cela permet de mettre à jour la ''Time Ressource Matrix'', pour préciser que le port d'écriture sera occupé à tel moment. De plus, cette information est transmise au premier étage, qui sait alors quand est enregistré le résultat dans le registre de destination. C'est comme cela que le premier étage sait quand un registre est disponible : le second étage le prévient, quand il émet une instruction ! La ''Time Ressource Matrix''mémorise l'occupation des "ressources" pour les 256 cycles d'horloge à venir. Cependant, elle ne vérifie pas les dépendances pour les 256 cycles suivants. Quand elle reçoit une micro-opération, elle teste les dépendances structurelles pour seulement les 8 prochains cycles maximum. Si la micro-opération ne peut pas être émise pendant ces 8 cycles, le pipeline est bloqué, un ''pipeline stall'' est émis. Pour être plus précis, vu que le processeur peut décoder 8 micro-opérations en même temps, cela permet de ne consulter que 64 cycles d'horloge sur les 256. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les premiers processeurs Intel | prevText=Les premiers processeurs Intel | next=Le renommage de registres | nextText=Le renommage de registres }} </noinclude> qcrv91e5gbw88f4koqb9e4hwati5ygj 773591 773590 2026-09-29T17:49:06Z Mewtow 31375 /* La fenêtre d'instruction centralisée */ 773591 wikitext text/x-wiki Dans les chapitres précédents, nous avons parlé des techniques dites d''''émission dans l'ordre'''. L'idée est d’exécuter une nouvelle micro-opération à chaque cycle, dans des unités de calcul séparées. Les instructions sont émises consécutivement, mais les instructions s’exécutent en parallèle dans des unités de calcul séparées. Par contre, quand l'unité d'émission ne peut pas émettre une instruction, elle bloque tout le pipeline. Les instructions qui suivent sont elles aussi bloquées, elle doivent attendre leur tour, même si elles sont en capacité de s'exécuter. Les techniques d'exécution dans le désordre que nous allons voir dans ce chapitre corrigent ce point précis. Elles sont dites à '''émission dans le désordre'''. Elles se distinguent des précédentes sur un point précis : quand l'unité d'émission bloque l'émission d'une instruction, les instructions suivantes peuvent poursuivre. L'émission des instructions peut donc se faire dans le désordre, dans le sens où une instruction peut être émise alors qu'une instruction précédente ne l'est pas encore. L'avantage de l'émission dans le désordre est qu'une instruction s'exécute dès que ses opérandes sont disponibles. Par disponible, on veut dire présent soit dans le réseau de contournement, soit dans les registres. Le processeur détecte automatiquement quand les opérandes d'une instruction sont sont disponibles, et il l’exécute à ce moment là. Dès qu'une instruction a ses opérandes disponibles, elle est émise et exécutée. C'est là la seule contrainte : les dépendances WAR, WAW et autres sont gérées par un ROB ou toute autre technique d'exception précise, seules les dépendances RAW limitent l'exécution. Mais avant de poursuivre, quelques point niveaux terminologie : * L'émission dans le désordre est un terme parlant et assez précis. Malheureusement, la terminologie la plus utilisée par d''''exécution dans le désordre'''. Et nous utiliserons ce terme dans la suite du cours, histoire de ne pas trop dévier de la nomenclature habituelle. * Nous utiliserons parfois l'abréviation OOO pour parler d'exécution dans le désordre. L'abréviation est celle de ''Out Of Order Excution''. * Nous utiliserons aussi l'abréviation ''µop'' pour parler de micro-opération, ''µops'' au pluriels pour parler de plusieurs micro-opérations, ou des micro-opérations en général. L'exécution dans le désordre ne gére en effet que des µops, elle se situe après l'étape de décodage. Mais avant de poursuivre, précisons une chose importante : l'exécution dans le désordre traite les accès mémoire à part. La majorité des processeurs OOO assez anciens exécutent les accès mémoire dans l'ordre, seules les µops entières/flottantes/branchements sont exécutées dans le désordre. Les processeurs datant d'après les années 2010 sont capable d'exécuter les accès mémoire dans le désordre, mais l'implémentation en question est assez particulière. Un chapitre entier sera dédié à l'exécution dans le désordre des µops mémoire. Nous allons volontairement mettre de côté la gestion des accès mémoire dans ce chapitre. ==Les fenêtres d’instruction : généralités== [[File:File de micro-opération.png|vignette|upright=1|File de micro-opérations]] Pour décrire comment est implémentée l'émission dans le désordre, il faut commencer par parler des processeurs sans. Les processeurs sans exécution dans le désordre ont une unité d'émission qui bloque tout le pipeline dès qu'une µop ne peut pas être émise. Pour limiter l'impact de ce blocage, quelques rares processeurs incorporent une '''file de micro-opération''', une mémoire FIFO qui met en attente les µops. Vu que c'est une mémoire FIFO, les µops sont émises dans l'ordre, à savoir l'ordre d'ajout, dans l'ordre de décodage. Le schéma ci-dessous illustre une telle file d'attente couplée à un ''scoreboard''. Sur le principe, l'exécution dans le désordre améliore la file de µops sur un point : ce n'est plus une mémoire FIFO. Les µops sont insérées dans l'ordre, mais peuvent sortir dans le désordre (être émises dans le désordre). La file de µops devient alors une '''fenêtre d'instruction''', terme traduit directement de l'anglais ''instruction Window''. Terme assez trompeur, car elles mettent en attente des µops, pas des instructions. Elles peuvent émettre des µops dans le désordre, ce qui fait que si une µop bloque le pipeline, les µops suivantes peuvent être émises. Si je commence le paragraphe précédent par "sur le principe", c'est car certaines techniques d'OOO utilisent des files de µops normales. Il est par exemple possible d'utiliser une file de µops avec une fenêtre d'instruction, plusieurs files de µops, plusieurs fenêtres d'instructions avec une file de µops annexe, etc. Dasn les grandes lignes, il existe dans les grandes lignes 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! File de µops améliorée |- ! Une seule "file de µops" | ''Scoreboard'' | Fenêtre d'instruction centralisée |- ! Plusieurs "file de µops" | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | Fenêtre d'instruction décentralisée |} ===La fenêtre d'instruction centralisée=== L'implémentation la plus simple de l'OOO utilise une unique '''fenêtre d'instruction'''. Les instructions décodées sont accumulées dans la fenêtre d'instruction, où elles attendent que leurs opérandes soient disponibles. La fenêtre d'instruction sert donc de file d'attente. Mais elle contient aussi une unité d'émission, qui détecte quelles µops sont prêtes à être émises. L'unité d'émission et la fenêtre d'instruction sont fusionnées ensemble, elles forment un seul circuit. Mais nous allons dire qu'elles sont conceptuellement séparées pour le moment. A chaque cycle, l'unité d'émission consulte la fenêtre d'instruction pour voir quelles µops peuvent s'exécuter, lesquelles ont leur opérandes de disponibles. La fenêtre d'instruction doit spécialement être conçue pour, c'est une sorte de mémoire associative très complexe, comme on le verra dans ce qui suit. [[File:OOO Issue.png|centre|vignette|upright=2.5|Exécution dans le désordre avec une fenêtre d'instruction]] Une fois qu'une µop sort du décodeur d'instructions, elle est ajoutée en parallèle dans la fenêtre d'instruction et le ROB. La raison est que les µops quittent la fenêtre d'instruction dans le désordre, et qu'elles doivent être remises en ordre par la suite. Le ROB s'occupe de cette remise en ordre, mais il a besoin de savoir dans quel ordre les µops sont censées être, et cet ordre est celui du décodage. Aussi, pour remplir le ROB, la seule opportunité est en sortie de l'unité de décodage. Dans le cas où une instruction est décodée en plusieurs micro-opérations, elles sont toutes insérées en même temps dans la fenêtre d'instruction et le ROB, en tenant compte de leur ordre. [[File:Fenêtre d'instruction.png|centre|vignette|upright=2|Fenêtre d'instruction.]] Les micro-opérations mémoire sont à part des autres, pour diverses raisons. Une de ces raisons est que les dépendances de données sont classées en deux types : les dépendances de registre et les dépendances d'adresse. Et les deux sont fondamentalement différentes. Autant on peut détecter les dépendances de registre lors de l'émission, autant c'est plus compliqué avec les dépendances d'adresse. De plus, rappelons que si les lectures peuvent s'exécuter dans le désordre, les écritures doivent s'exécuter dans l'ordre, ou du moins en donner l'illusion. Pour cela, le processeur remet les écritures dans l'ordre avec une sorte de mini-ROB intégré à l'unité mémoire, appelée la file d'écriture. Elle complémente le ROB, qui lui ne gère que les écritures dans les registres, mais les deux collaborent. La file d'écriture envoie une écriture à la mémoire RAM quand le ROB lui dit que c'est bon, les instructions précédentes sont terminées ''dans l'ordre du programme''. Les processeurs modernes ajoutent des techniques d'exécution dans le désordre des accès mémoire, mais nous les verrons dans un chapitre dédié. Elles permettent d'utiliser une fenêtre d'instruction unique, qui mémorise aussi les µops mémoire. Si elles sont mises en place, l'unité mémoire n'a pas besoin de file de µops séparée. L'idée est que les dépendances de registre sont traitées par la fenêtre d'instruction, mais que l'unité mémoire gére les dépendances d'adresse. Les dépendances d'adresse sont gérées par des techniques de ''désambiguation mémoire'', qui auront droit à un chapitre dédié. [[File:Processeur avec exécution dans le désodre des accès mémoire.png|centre|vignette|upright=2|Processeur avec exécution dans le désodre des accès mémoire]] Les processeurs assez anciens n'autorisaient pas d'exécution dans le désordre des accès mémoire. Concrétement, les accs mémoire devaient se faire dans l'ordre, mais les autres µops pouvaient être exécutées dans le désordre. Il s'agit donc d'un ordre entre µops mémoire, pas entre µops mémoire et autres µops. Les µops entières et flottantes pouvaient être exécutées avant une µops mémoire qui est avant elle dans l'ordre du programme, ce n'est pas un problème. Pour garantir l'ordre desd µops mémoire, l'unité mémoire est précédée par une file de micro-opérations séparée, pour forcer l'exécution dans l'ordre des accès mémoire. De plus, les µops mémoire ne peuvent pas utiliser la fenêtre d'instruction. Dit autrement, la fenêtre d'instruction ne mémorise pas de µops mémoire. Après le décodage, les µops sont réparties soit dans la file de µops mémoire, soit dans la fenêtre d'instruction. Le décodeur classe les µops suivant que ce sont des µops mémoire ou non, et les envoient à la bonne destination. Dans ce chapitre, on supposera que c'est cette solution qui est utilisée. [[File:Processeur avec émission dans l'ordre des accès mémoire.png|centre|vignette|upright=2|Processeur avec émission dans l'ordre des accès mémoire]] La solution précédente revient à scinder la fenêtre d'instruction en deux : une file de µops pour les µops mémoire, une fenêtre d'instruction pour les autres µops. Et cette scission peut aller plus loin, à savoir qu'on peut scinder une fenêtre d'instruction encore et encore. Ce qui nous amène à la section suivante. ===Les fenêtres d'instruction décentralisées=== Une autre solution utilise plusieurs fenêtres d'instruction. Pour faire la différence avec l'usage d'une fenêtre d'instruction unique, nous allons parler de fenêtre d'instruction centralisée s'il n'y en a qu'une dans le processeur, de '''fenêtre d'instruction décentralisée''' s'il y en a plusieurs. Dans le cas général, chaque fenêtre d'instruction est associée à un type précis d'opération/instruction. La tendance moderne est d'utiliser une fenêtre d'instruction pour les instructions de calcul entières, une autre pour les flottantes. Il s'agit d'un choix simple et efficace, mais quelques processeurs font autrement, pour répondre à des contraintes très diverses. L'usage de fenêtres décentralisées simplifie la répartition des instructions sur les différentes unités de calcul. Par exemple, utiliser des fenêtres séparées pour les ALU et les FPU facilite la répartition des instructions de calcul sur les ALU. Une fenêtre centralisée demande de faire la différence entre instruction entière/flottante, puis de choisir sur quelle unité de calcul entière/flottante utiliser. Une fenêtre décentralisée fait les deux choix séparément : d'abord on envoie l'instruction dans la bonne fenêtre suivant si c'est une instruction flottante ou entière, et ensuite on gère la disponibilité des ALUs/opérandes. Et on peut adapter la même idée en séparant les unités d'accès mémoire des ALU entières, etc. Par contre, un défaut est que certaines fenêtres d'instruction peuvent être sous-utilisées. Par exemple, la station de réservation flottante est inutilisée si le programme n'exécute pas d'opérations flottantes. Ou encore, les fenêtres pour les accès mémoire peuvent être sous-utilisées, si le programme effectue peu d'accès mémoire relativement aux autres instructions. En fait, tout dépend de comment sont calibrées les fenêtres d'instruction et de la répartition des instructions dans le programme entre opérations entières, flottantes, mémoire. Par exemple, si un programma de deux fenêtres d'instructions identiques, une pour les calculs entiers et une autre pour les calculs flottants, elles ne seront utilisées à la perfection que si la moitié des instructions du programme fait des calculs flottants et l'autre des calculs entiers. Toute déviation par rapport à cette répartition idéale risque de laisser des entrées vides dans une fenêtre d’instruction. Un point important est que l'émission est découpée en deux étages avec des fenêtres d'instruction décentralisées. La première étape envoie l'instruction décodée vers la fenêtre d'instruction adéquate, la seconde gère l'émission proprement dit. La première est l'étage de ''dispatch'' qui envoie l'instruction dans la fenêtre d’instruction adéquate, selon que c'est une instruction flottante, entière, autre. La seconde est l'étage de ''scheduling'', qui gère la disponibilité des opérandes et des unités de calcul. En clair, on trie les instructions suivant leur type, suivant le type d'unité de calcul adéquate, puis on l'émet proprement dit. Faire ainsi a plusieurs avantages, avec cependant peu d'inconvénients. Lors de l'étape de ''dispatch'', l'instruction émise est ajoutée au tampon de réordonnancement, s'il existe. Sans cela, impossible de conserver l'ordre des instructions. Les instructions sont émises dans l'ordre au niveau de l'unité de ''dispatch'', pas au niveau de l'étage de ''scheduling''. Aussi, pour remplir le ROB, cela doit se faire au dernier moment où les instructions sont émises dans l'ordre, soit en sortie de l'unité de ''dispatch''. De plus, les micro-opérations mémoire sont traitées à part des autres, elles sont envoyées directement à l'unité mémoire. La gestion des calculs d'adresse est quelque peu complexe, mais ils peuvent être fait soit dans l'unité mémoire, soit dans les ALU entières, peu importe. Il y a aussi un système de contournement complexe entre ALU/FPU et unité mémoire, qui n'est pas représenté dans le schéma ci-dessous. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Il faut noter que quelques processeurs utilisent des méthodes intermédiaires entre les trois solutions précédentes. Par exemple, les processeurs AMD Zen utilisent une fenêtre d'instruction décentralisée un peu particulière. Les unités de calcul entières disposent d'une fenêtre d'instruction rien que pour elles, sur ce processeur. Les instructions flottantes sont quant à elles alimentées par une file de micro-opération, pas une fenêtre d'instruction ! La raison à ce choix est un compromis entre performance et cout en circuit. L'exécution dans le désordre est peu efficace sur les instructions flottantes, car les CPU n'ont que peu d'ALU flottantes séparées. Vu le cout en circuits d'une fenêtre d'instruction, les concepteurs du processeur ont préféré utiliser une file de micro-opération pour les opérations flottantes. ===L'usage de plusieurs files d'instruction=== Une dernière méthode d'OOO utilise plusieurs files de micro-opération. L'idée est qu'une fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement une file de micro-opération pour les opérations entières, une autre pour les opérations flottantes, une autre pour les accès mémoire. D'autres processeurs utilisent une file pour les accès mémoire et une autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. La présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que la technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si une dépendance bloque une FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans une autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer la disponibilité des registres. Quand un registre est lu ou écrit par une instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. La logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : une pour les instructions d'accès mémoire et une autre pour les autres instructions. Si jamais une instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de la lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'une est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est la file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. ===Avantages et inconvénients de chaque implémentation=== Un processeur contient soit une fenêtre d'instruction unique, soit plusieurs fenêtres d'instruction séparées. Typiquement, les fenêtres d’instruction séparées sont spécialisées, dans le sens où on a une fenêtre pour les instructions flottantes, une autre pour les instructions entières, une autre pour les accès mémoire, etc. Pour résumer, on a le choix entre une grosse fenêtre généraliste et plusieurs fenêtres spécialisées, sauf que la fenêtre centralisée est lente et complexe, contrairement aux fenêtres spécialisées. Les deux méthodes ont des inconvénients et des avantages différents. Dans les grandes lignes, l'avantage des fenêtres décentralisées est qu'elles sont plus petites qu'une grosse fenêtre d'instruction. Cela simplifie la gestion du contournement et de la répartition des instructions sur les unités de calcul, comme on le verra dans quelques paragraphes. Elles sont donc moins complexes et plus rapides. L'autre avantage, c'est qu'il est possible de démarrer l'exécution de plusieurs instructions simultanément : une instruction par fenêtre décentralisée, contre une par fenêtre d'instruction. Mais les fenêtres décentralisées sont souvent sous-utilisées, partiellement remplies, contrairement aux fenêtres d'instruction. Il arrive qu'une fenêtre d'instruction soit remplie, alors que les autres sont vides. Par exemple, prenons un processeur avec une fenêtre d'instruction reliée à la FPU, et une autre reliée aux autres ALUs. Si le processeur n'exécute que des opérations flottantes, la fenêtre reliée à la FPU sera pleine, alors que l'autre sera vide. L'exécution des instructions dans le désordre est alors limitée par la petite taille de la fenêtre, qui ne peut plus accepter de nouvelle instruction flottante. Avec une fenêtre unique, on n'aurait pas eu ce problème : on aurait eu une énorme fenêtre d'instruction remplie d'instruction flottante, au lieu d'une petite fenêtre spécialisée. Il est maintenant temps de voir en quoi sont faites les fenêtres d’instruction, qu'elles soient centralisées ou décentralisées. Nous allons aussi voir quelle est la logique d'émission associée. ==L'implémentation d'une fenêtre d'instruction : généralités== Une fenêtre d'instruction est une mémoire qui mémorise des micro-opérations. Elle est cependant plus complexe qu'une mémoire RAM ou qu'une FIFO et ressemble un petit peu à une mémoire cache. Elle dispose d'un port d'écriture et d'un port de lecture, au minimum. Le port d'écriture permet à l'unité de décodage d'insérer une micro-opération dedans, d'ajouter la micro-opération qui vient d'être décodée. Si une instruction machine est décodée en plusieurs micro-opération, deux possibilités. La première est de les insérer un par un, ce qui fait qu'on peut se contenter d'un seul port d'écriture. L'autre possibilité est de les ajouter en même temps, ce qui demande plusieurs ports d'écriture. Le port de lecture sert à émettre une instruction. On part du principe que la fenêtre d'instruction ne peut émettre qu'une seule instruction à la fois, car les processeurs que nous avons vu précédemment sont de ce type. Mais nous verrons dans quelques chapitre qu'il existe des processeurs dits superscalaires, qui sont capables d'émettre plusieurs instructions par cycle. Dans ce cas, la fenêtre d'instruction a un seul port de lecture. Un processeur superscalaire, quant à lui, doit avoir un port de lecture par unité de calcul, ce qui fait beaucoup plus. ===Les entrées d'une fenêtre d’instruction=== Les fenêtres d'instruction sont composées d''''entrées''', des mots mémoire qui stockent une instruction. Une instruction réserve une entrée après son décodage et la libère dès qu'elle est envoyée aux unités de calcul. Une entrée contient l'opcode (les signaux de commande à envoyer à l'ALU), le registre de destination du résultat, les registres de chaque opérande, et éventuellement des signaux de commande en plus. De plus, chaque opérande est couplée à un bit de disponibilité, qui indique si elle est disponible. Quand un opérande est écrit dans les registres, le bit de présence correspondant est mis à jour. Enfin, chaque entrée possède un bit ''empty'' qui indique si elle est vide, cette information étant utile pour réserver des entrées. [[File:Entrée d'une station de réservation - sans les tags.png|centre|vignette|upright=3|Entrée d'une fenêtre d'instruction]] Nous verrons dans quelques chapitres que certaines fenêtres d'instruction sont capables de mémoriser les opérandes des instructions. De telles fenêtres d'instruction seront appelées, dans ce cours, des '''stations de réservation'''. Les entrées des stations de réservation sont assez semblables à celle des fenêtres d'instruction, à un détail près : les opérandes de l'instruction sont enregistrées directement dans des champs séparés. Il y a deux champs, un par opérande, pour stocker l'opérande elle-même, lue depuis les registres ou obtenue via le réseau de contournement. Notons que les champs pour les opérandes viennent en plus des champs pour les noms de registres, encore que les deux peuvent être fusionnés si on veut optimiser le tout. [[File:Entrée d'une station de réservation.png|centre|vignette|upright=3|Entrée d'une station de réservation.]] Précisons que la terminologie n'est pas très fiable. Les termes "fenêtre d'instruction" et "station de réservation" ne regroupent pas du tout la même chose d'un papier de recherche à l'autre, d'un bouquin à l'autre, d'un chercheur à l'autre, d'un ingénieur à l'autre, d'un professeur à l'autre. Le terme initial vient pourtant de l'article original sur l'algorithme de Tomasulo, où il désignait une fenêtre d'instruction associée à une unité de calcul précise. Mais le terme a ensuite été réutilisé, ce qui fait que certains processeurs avec plusieurs unités de calcul sont décrit comme ayant une unique station de réservation. En bref : c'est le bazar ! Mais nous en reparlerons dans le chapitre sur le renommage de registres, car c'est la place idéale pour les aborder. Toujours est-il que j'ai fait le choix de confondre les concepts de fenêtre d'instruction et de station de réservation avec les concepts de '''lecture avant émission''' et de '''lecture après émission'''. La différence entre les deux est que les registres sont lus après émission avec une fenêtre d'instruction, avant avec des stations de réservation. Dans le cas "avant émission", les opérandes sont mémorisées dans la station de réservation. Et cette différence a une influence sur le pipeline du processeur, le banc de registres et tout ce qui s'en suit. Un désavantage de la lecture avant émission est qu'il faut stocker les opérandes après lecture, ici dans les stations de réservation. Mais un avantage est que le banc de registre a besoin de moins de ports de lecture, car une bonne partie des opérandes sont fournies par le système de contournement. Nous verrons cela dans le détail dans le chapitre sur les processeurs superscalaires. Il a été proposé de fusionner le tampon de ré-ordonnancement avec la fenêtre d'instruction dans une structure unique. La méthode a notamment été utilisée sur les processeurs d'architecture K6 d'AMD. Le tout donnait une structure appelée le '''DRIS''' (''deferred scheduling register renaming instruction shelf''). La différence avec une fenêtre d’instruction normale est que les entrées sont libérée non pas quand l'instruction est exécutée/émise, mais quand elle termine son exécution et quitte le ROB. La fenêtre d'instruction doit alors incorporer des bits pour savoir si telle entrée a émis sont instruction ou non. ===La logique d'éveil et de sélection=== Dans le cas qui va suivre, on suppose que le processeur ne peut émettre qu'une instruction à la fois. Chaque cycle, une instruction est sélectionnée et est envoyée dans le chemin de données, soit à une ALU, soit à une unité d'accès mémoire. La sélection d'une instruction est effectuée par l'unité d'émission, qui est aussi appelée le '''''scheduler'''''. Elle gère la disponibilité des opérandes et la disponibilité des unités de calcul adéquate. Le choix de l'instruction émise doit être le plus pertinent possible, pour des raisons de performances. Pour le premier point, l'unité d'émission détermine quelles instructions sont candidates pour l'émission. Les ''instructions candidates'' sont celles dont tous les opérandes sont prêts. Le processeur contient un circuit qui détecte les instructions candidates : la '''logique d’éveil''' (''wake-up logic''). Une fois que la logique d'éveil a fait son travail, une instruction est choisie pour s’exécuter en fonction de la disponibilité des unités de calcul adéquates. Ce rôle est dévolu à un circuit qu'on appelle la '''logique de sélection''', ou ''select logic''. [[File:Fonctionnement complet de la logique d’émission.jpg|centre|vignette|upright=1.5|Fonctionnement complet de la logique d’émission.]] La logique de sélection doit gérer le fait que les unités de calcul du processeur ne sont pas toutes identiques. Déjà, un processeur a généralement des unités séparées pour les instructions entières et flottantes, des unités spécialisées dans les accès mémoire, parfois des unités spécialisées pour les branchements. Une instruction doit être attribuée à la bonne unité de calcul, on ne doit pas envoyer une instruction entière dans une unité de calcul flottante. De plus, parmi les unités de calcul entières, toutes ne sont pas identiques. Par exemple, il est fréquent d'avoir plusieurs unités de calcul spécialisées dans les opérations simples (additions, soustractions, opérations logiques) avec une unité pour les multiplications/divisions séparées, parfois une unité spécialisée pour les décalages/rotations, etc. Là encore, allouer la bonne instruction à la bonne ALU est complexe. Plus les unités de calcul sont hétérogènes, plus la logique de sélection est compliquée. Les logiques d'éveil comme de sélection sont assez complexes. Comme on le verra plus bas, la logique de sélection la plus simple, qui gère une seule unité de calcul, est basée sur un encodeur à priorité couplé à d'autres circuits. Et pour gérer plusieurs ALUs, il faut mettre des encodeurs en cascade. Le résultat est que même en prenant une logique de sélection simple, elle sera assez lente et gourmande en circuits. Aussi, la logique de sélection met souvent un cycle d'horloge entier pour faire son travail, elle a son propre étage de pipeline attribué. La logique d'éveil est dans le même cas, ce qui fait qu'émettre une micro-opération demande deux cycles d'horloge. Le défaut est que cela rajoute des cycles d'horloges entre la fenêtre d'instruction et l'ALU, ce qui complique la gestion du pipeline. Ces cycles de retard sont à prendre en compte au moment d'émettre les instructions, les ''scheduler'' doit en tenir compte pour des performances optimales. Sans tenir compte de ces cycles de retard, les instructions arrivent en retard de quelques cycles à l'ALU, cycles de retard durant lesquels l'ALU n'a pas fait de calcul et a été sous-utilisée, sans compter que le système de contournement n'est pas utilisé au mieux. Et le problème est encore plus important sur les processeur avec des stations de réservation, qui utilisent la "lecture après émission" : cela rajoute un cycle d'horloge en plus, un temps de retard en plus. ===La logique d'éveil : l'émission anticipée=== La logique d'éveil doit tenir compte du fait qu'il y a plusieurs étages entre l'émission et l'exécution sur une unité de calcul. Par exemple, un processeur a souvent entre un et à cinq étages entre la file d'attente et les unités de calcul. Il faut lire les registres, gérer le contournement, et cela peut prendre quelques cycles d'horloge. Sur le Pentium 4, on trouve 6 étages entre la fenêtre d’instruction et l'entrée de l'ALU. Si les micro-opérations sont émises quand les opérandes sont disponibles, il y aura un délai de quelques cycles avant qu'elles atteignent l'ALU. Alors qu'idéalement, on souhaiterait que la micro-opération atteigne l'ALU dès que ses opérandes sont disponibles, pour profiter des techniques de contournement. Pour cela, la logique d'éveil émet les instructions quelques cycles en avance pour qu'elles arrivent au bon moment. Il s'agit d'une technique d''''émission anticipée''', dont nous avions parlé dans le chapitre sur le contournement. : Il faut noter que le problème se pose plus avec des fenêtres d'instruction qu'avec des stations de réservation. Les premières ont un étage en plus entre émission et ALU, vu qu'il faut lire des registres après l'émission. L'émission anticipée demande d'émettre un signal d'éveil en avance de quelques cycles, pile au bon moment. Par exemples, si on a deux étages entre l'ALU et l'unité d'émission, le signal de réveil sera généré deux cycles avant que le résultat soit effectivement calculé. L'implémentation varie, mais deux solutions sont possibles. La première est de générer le signal d'éveil dans l'ALU, ce qui n'a de sens que pour les opérations comme les multiplications ou les divisions, qui prennent plusieurs cycles. Une autre technique génère le signal de réveil dans une structure centralisée, spécialisée dans la génération des signaux d'éveil. L'unité de composée d'un registre à décalage par registre. Imaginons qu'une instruction est émise, que cette instruction mette N cycles à s'exécuter, et qu'elle écrive dans un registre de destination. L'unité sélectionne alors le registre à décalage associé au registre de destination, et met le bit numéro N à 1. Le registre décalé d'un cran à chaque cycle. Quand le bit sortant est un 1, alors le signal de validité pour l'opérande est généré. L'émission anticipée marche bien si l'instruction a une durée fixe, connue à l'avance. Et autant c'est le cas pour les instructions arithmétiques et logiques, autant ce n'est pas le cas pour les accès mémoire. Les accès mémoire ont une latence variable : quelques cycles pour un succès de cache, plusieurs dizaines de cycles pour un défaut de cache L1, pas loin de la centaine pour un défaut de cache L2, etc. Et cela pose des problèmes pour l'émission anticipée. L'émission en avance pour les accès mémoire est purement spéculative : le processeur émet des instructions en supposant que la lecture entrainera un succès de cache, quitte à annuler l'instruction en cas de défaut de cache. Mais faire ainsi demande non seulement d'annuler les instructions émises en avance, mais aussi de ne pas retirer les instructions émises en avance de la fenêtre d'instruction. Elles sont émises, mais une copie de sauvegarde est conservée dans la fenêtre d'instruction. Si le processeur détecte un défaut de cache, il peut alors ré-exécuter l'instruction. S'il détecte un succès de cache, les instructions lecture-dépendante sont retirées de la fenêtre d'instruction, la copie de sauvegarde est devenue inutile et est donc jetée. ===La logique de sélection : âge ou position ?=== La logique de sélection est primordiale pour de bonnes performances. Il existe deux méthodes principales pour sélectionner l'instruction à exécuter. La première est la plus simple : elle se base sur lé numéro de l'entrée. En effet, une fenêtre d'instruction est avant tout une sorte de mémoire, un mix entre mémoire associative, mémoire RAM, et FIFO. Et chaque entrée a un numéro, une adresse mémoire. Nous parlerons de numéro dans ce qui suit, car ce sera plus simple, le terme d'adresse mémoire étant peut-être un peu exagéré dans le contexte des fenêtres d'instruction. Toujours est-il que la fenêtre d'instruction est adressable dans le sens où on peut lui envoyer le numéro de l'entrée voulue, et la fenêtre d’instruction renvoie le contenu de l'entrée sur son port de lecture. Et c'est ce que fait la logique de sélection : elle génère le numéro de l'entrée à lire. Le numéro est alors envoyé sur l'entrée d'adresse de la fenêtre d’instruction, et elle fournit la micro-opération associée sur son port de lecture, son '''port d'émission'''. La première méthode de sélection, donc. Elle est basée sur sur le numéro de l'entrée. Si plusieurs entrées sont éveillées, la logique de sélection prend celle avec le plus petit numéro. Elle porte le nom de '''sélection par position''', sous-entendu position dans la fenêtre d'instruction. Vous l'avez peut-être deviné, mais la logique de sélection est alors un encodeur à priorité. Le circuit de sélection ne se résume donc pas seulement à un encodeur à priorité, mais c'est le circuit central. L'avantage d'une telle méthode de sélection est qu'elle est simple à implémenter : un encodeur à priorité est un circuit connu, facile à implémenter. Mais on remarque un défaut : un encodeur est un circuit assez rapide, mais qui utilise beaucoup de transistors, beaucoup de portes logiques, surtout si on veut qu'il soit rapide. Ce qui explique que la logique de sélection ait son propre étage de pipeline rien que pour elle. La seconde méthode s'appelle la '''sélection par âge''', au nom assez transparent. L'idée est de privilégier l'émission de l'instruction la plus ancienne. Elle demande que la fenêtre d'instruction trie les micro-opérations par ordre d'insertion dans la fenêtre d'instruction, ce qui en fait une pseudo-FIFO. Le tri est partiel, car les instructions peuvent sortir de la fenêtre d’instruction à tout moment. Compacter la fenêtre d'instruction, à savoir regrouper toutes les entrées valides est une idée, mais elle est compliquée à implémenter. Aussi, elles préfèrent encoder des informations sur l'ordre d'émission dans chaque entrée. L'encodeur à priorité doit alors travailler non pas sur des nombres entiers liés à l'ordre d'insertion dans la pseudo-FIFO. Elle est encore plus gourmande en circuits que la méthode précédente. Les processeurs haute performance utilisent souvent des méthodes hybrides. Par exemple, les processeurs AMD de microarchitecture Bulldozer utilisaient une méthode intermédiaire. Ils utilisaient une fenêtre d'instruction couplée à un encodeur à priorité pour la sélection par position, mais complémentaient le tout avec une unité qui mémorisait l'instruction la plus ancienne dans la fenêtre d’instruction. Le mécanisme de sélection par âge était utilisé en priorité. Mais si l'instruction la plus ancienne n'était pas prête, le processeur basculait sur le mécanisme de sélection par position. ===La compaction des fenêtres d'instruction=== À chaque cycle, les instructions décodées sont ajoutées dans la fenêtre d'instruction, dans des entrées vides. Vu que les instructions quittent celle-ci dans le désordre, ces vides sont dispersés dans la fenêtre d'instruction, ce qui pose problème pour déterminer où placer les nouvelles instructions. La solution la plus triviale consiste à conserver une liste des vides, mise à jour à chaque insertion ou émission d'instruction. Une autre solution consiste à éliminer les vides en compactant la fenêtre d'instruction à chaque cycle d'horloge. Des circuits se chargent de détecter les vides et de regrouper les instructions en un unique bloc. Il faut signaler que certaines processeurs arrivent à se passer de cette étape de compactage, mais au prix de fenêtres d'instruction nettement plus complexes. Autre problème : quand il faut choisir quelle instruction émettre, il y a toujours plusieurs candidats. Si on choisit mal, des instructions restent en attente trop longtemps parce que d'autres instructions plus jeunes leur passent devant. Pour éviter cela, les instructions les plus vielles, les plus anciennes, sont prioritaires. Pour cela, on peut utiliser une FIFO un peu spéciale pour la fenêtre d'instruction. Si les ajouts d'instruction se font dans l'ordre, les instructions ne quittent pas forcément la fenêtre d'instruction dans l'ordre imposé par une FIFO : les instructions restent triées dans leur ordre d'ajout, même s'il y a des vides entre elles. Dans ces condition, il est préférable que le compactage conserve l'ordre FIFO des instructions. Dans ces conditions, l'instruction la plus ancienne est celle qui est située à l'adresse la plus faible : le circuit de sélection peut donc être fabriqué avec des encodeurs, et est relativement simple. ==Les fenêtres d'instruction basées sur une matrice de dépendances== L'implémentation la plus simple étend le fonctionnement d'un pipeline dynamique usuel. Rappelez-vous le chapitre sur les pipeline dynamiques. Nous avions vu que de tels pipelines émettaient une instruction par cycle, quitte à émettre des bulles de pipeline en cas de dépendance bloquante. Et il est possible d'améliorer leur unité d'émission pour qu'elle soit compatible avec l'exécution dans le désordre. ===Rappels sur le registre de réservation/disponibilité=== L'émission d'une instruction est gouvernée par un ''registre de réservation'' qui indique quels registres sont réservés par une instruction, et ceux qui sont libres. Un registre réservé est un registre qui sera écrit par une instruction en cours d'exécution, mais qui n'a pas encore écrit son résultat. Les instructions candidates doivent avoir leurs opérandes dans des registres libres. Sinon, c'est signe que leurs opérandes sont réservées en écriture, donc pas encore écrites, donc pas disponibles. Si une instruction candidate veut lire ce registre, c'est signe qu'il y a une dépendance RAW : elle veut lire un registre réservé, qui est destiné à être écrit par une instruction en vol. Si elle veut écrire, c'est signe qu'elle veut écrire dans un registre où une autre instruction veut écrire : c'est une dépendance WAW. Dans les deux cas, l'instruction n'est pas émise. Le registre de réservation encode les registres réservés comme suit : chaque bit est associé à un registre. Le bit numéro 0 est associé au registre numéro 0, le bit numéro 1 au registre numéro 1, etc. Là, En clair, les numéros de registres réservés sont encodés en représentation non pas binaire, mais en représentation ''one-hot'' (vue au premier chapitre). {|class="wikitable" |+ Registre de réservation |- ! Registre 7 !! Registre 6 !! Registre 5 !! Registre 4 !! Registre 3 !! Registre 2 !! Registre 1 !! Registre 0 |- | 0 || 0 || 1 || 0 || 0 || 1 || 0 || 0 |} Avant d'émettre une instruction, l'unité d'émission extrait les registres opérande/destination et les convertis dans la même représentation que le registre de réservation, à savoir en représentation ''one-hot''. Le circuit de traduction binaire vers ''one-hot'' est, pour rappel, un simple décodeur. Puis, on fait un OU logique entre les sorties des décodeurs. Le résultat est un masque qui indique quels registres sont lus par l'instruction, encodé en représentation ''one-hot''. Appelons-le le '''masque d'opérandes'''. Le masque est alors comparé au registre de réservation pour vérifier si l'instruction peut être émise. [[File:Unité d'émission simple, dans l'ordre.png|centre|vignette|upright=2|Unité d'émission simple, dans l'ordre]] Si l'émission est autorisée, le registres de réservation est là aussi mis à jour. Le registre de réservation est aussi mis à jour dès qu'une instruction enregistre son résultat dans les registres, ou alors dès qu'il est disponible pour le contournement. Le bit associé au registre repasse alors à 0 (ou à 1). Sans contournement, la mise à jour se fait alors à la toute fin de l'instruction, quand elle se termine, lors de la dernière étape d'enregistrement, à la fin de son pipeline. Avec, elle se fait quand l'instruction quitte l'unité de calcul. ===L'extension à l'exécution dans le désordre : l'éveil par matrice de bits=== La différence entre un pipeline dynamique et l'exécution dans le désordre est que l'on passe d'une instruction à émettre à plusieurs. Plusieurs instructions sont mises en attente dans une fenêtre d’instruction, et y attendent leur tour. L'idée est alors d'envoyer le registre de disponibilité à toutes les entrées, à toutes les instructions en attente. Ainsi, on sait quelles sont les instructions qui peuvent s'exécuter et celles qui ne le peuvent pas. L'implémentation est assez simple, elle ressemble beaucoup à l'implémentation d'un pipeline dynamique simple, si ce n'est que des circuits sont dupliqués. L'implémentation utilise des fenêtres d'instruction légèrement différentes de celles introduites plus haut. Elles n'utilisent notamment pas de bits de disponibilité, mais autre chose. Lorsqu'une instruction est ajoutée à la fenêtre d'instruction, le masque de disponibilité des opérandes est stocké dans la fenêtre d'instruction. A chaque cycle, le registre de disponibilité est envoyée à toutes les entrées, et est comparé avec tous les masques de disponibilité des opérandes. Si une comparaison renvoie un 1, alors l'instruction de l'entrée est une instruction candidate à l'émission. [[File:Unité d'émission dans le désordre basée sur un registre de disponibilité.png|centre|vignette|upright=2.5|Unité d'émission dans le désordre basée sur un registre de disponibilité]] L'ensemble est implémenté avec l'aide d'une '''matrice de bits''', où chaque ligne correspond à une entrée et chaque colonne à un registre. À chaque croisement entre une ligne et une colonne, on trouve un bit. Si le bit de la ligne n et de la colonne m est à 1, cela veut dire : l'instruction dans l'entrée n a besoin de lire le registre m. S’il est à 0, alors cela veut dire que l'instruction stockée dans la ligne n n'a pas besoin de la donnée dans le registre m. [[File:Planificateur à matrice de bits.jpg|centre|vignette|upright=2|Planificateur à matrice de bits.]] Lorsqu'une instruction réserve une entrée, elle initialise la ligne en fonction des registres qu'elle souhaite lire. Pour vérifier si une instruction a ses opérandes prêts, le processeur compare le registre de disponibilité à la ligne associée à l'instruction/entrée. A chaque intersection ligne-colonne, se trouve un comparateur de 1 bit, qui détecte si le registre est demandé et disponible. Les résultats de cette porte sont ensuite envoyés à une porte ET, qui fait le gros du travail. [[File:Logique de détection de la disponibilité d'une instruction.jpg|centre|vignette|upright=2|Logique de détection de la disponibilité d'une instruction.]] ==Les fenêtres d'instruction basées sur une mémoire associative== Les processeurs modernes utilisent une mémoire associative pour la fenêtre d'instruction. Les mémoires associatives ont été abordées il y a quelques chapitres, mais faisons quelques rappels. Les mémoires associatives servent à accélérer la recherche de données dans un ensemble. Or, une fenêtre d'instruction vérifie régulièrement si chaque entrée est prête. Il s'agit d'un processus de recherche d'une instruction qui respecte une condition bien précise dans la mémoire, ce qui fait que les mémoires associatives sont donc tout indiquées. Comme vous le savez, les signaux de commande d'une instruction sont propagés avec celle-ci dans le pipeline, le nom du registre de destination ne faisant pas exception. Le nom de registre est envoyé à la fenêtre d'instruction lors de l'écriture du résultat dans les registres. S'il y a correspondance, l'opérande est disponible et son bit de disponibilité est mis à 1. On peut adapter cette méthode pour tenir compte du contournement assez simplement. [[File:Détection des dépendances par propagation du registre de destination.png|centre|vignette|upright=2|Détection des dépendances par propagation du registre de destination.]] En conséquence, le circuit de détection des dépendances est constitué d'un grand nombre de comparateurs : un par champ « nom de registre » dans chaque entrée. La logique d'éveil/''wake up'' regroupe tous les comparateurs, la logique de sélection est un circuit situé en-dehors de la mémoire associative. Les entrées sont dans la mémoire associative elle-même. [[File:Gestion des bits de validité.png|centre|vignette|upright=2|Gestion des bits de validité.]] L'implémentation la plus simple est celle du schéma précédent, où on utilise une mémoire associative unique. Une version plus élaborée sépare la fenêtre d'instruction en deux parties : une mémoire qui mémorise les registres des opérandes, une autre mémoire pour le reste. La mémoire pour les registres opérandes est la mémoire associative proprement dite, c'est elle qui est associées aux comparateurs, à la logique de ''wake-up''/réveil, etc. Par contre, l'autre mémoire est une mémoire RAM simplifiée, qui mémorise les informations qui n'ont pas besoin des comparateurs. L'opcode de l'instruction est là-dedans, par exemple. ===Les optimisations de la consommation d'énergie : la désactivation des portions inutilisées=== Le problème avec des fenêtres d'instruction de ce type est leur forte consommation énergétique, ainsi que le grand nombre de portes logiques utilisées, qui deviennent prohibitif pour des fenêtres d'instruction un peu grosses. Pour résoudre ce problème, certains ont optimisé les comparateurs. D'autres ont tenté de profiter du fait que la majorité des bits dans les entrées sont composés de zéros. Bref, les optimisations purement matérielles sont légion. Une première solution est de désactiver les entrées qui sont inutilisées, vides, sans instruction. Pour cela, on fait précéder les comparateurs par un circuit qui les connecte ou déconnecte des lignes de bit. Le circuit est commandé par le bit ''empty'' qui indique si une entrée est vide ou non. L'avantage est que la consommation d'énergie de la fenêtre d'instruction devient alors proportionnelle au nombre d'entrées non-vides, et non au nombre d'entrées total. Du moins, en apparence, les entrées non-utilisées doivent quand même être alimentées pour fonctionner, mais l'activité de comparaison disparait dans les entrées vides. Il est possible d'étendre cette technique aux entrées dont les opérandes sont prêtes. Les gains sont généralement assez bons, avec une réduction de consommation variant entre 30 et 50%, avec une implémentation très simple et très économe en circuits. Une autre solution, assez simple à mettre en place, consiste à désactiver une partie de la fenêtre d'instruction sin elle est inutilisée. Pour cela, il faut segmenter la fenêtre d'instruction avec la technique du ''wire partitionning''. Pour rappel, une fenêtre d'instruction est une mémoire associative. Et comme toute mémoire associative, elle contient des fils, les lignes de bit, qui relient les entrées/sorties à toutes les cellules mémoire. Plus une ligne de bit est longue, plus elle consomme d'énergie et plus le temps de lecture/écriture est long. L'idée est de segmenter les lignes de bits en plaçant des répéteurs qui recopient la tension d'un segment au suivant. Les répéteurs sont des tampons trois-états, ce qui permet de déconnecter les portions inutilisées de la ligne de bit. Ce faisant, la fenêtre d'instruction est découpée en segments, qui peuvent être désactivés si besoin. Si il y a peu d'instructions chargées dans la fenêtre d'instruction, les portions inutilisées sont désactivées. La technique marche d'autan mieux si les instructions sont compactées au début de la fenêtre d'instruction. [[File:Wire partitionning.png|centre|vignette|upright=2|Wire partitionning]] Tout le problème est de savoir quelles portions désactiver. La technique est assez simple si la fenêtre d'instruction est compactée, à savoir si toutes les instructions sont régulièrement regroupées au début de la mémoire CAM. Mais même avec cette optimisation, la décision de désactiver une portion de la fenêtre d'instruction n'est pas à prendre à la légère. Il ne faut pas désactiver une portion contenant des instructions pouvant être émise sous peu. La décision dépend de paramètres variés : proportion d'entrée vides, quantité d'entrées récemment activées/désactivées récemment, présences d'entrées avec un ''match'' d'opérandes récent, etc. Il est important de préciser que les techniques en question fonctionnent aussi sur les autres types de fenêtre d'instruction, qui ne sont pas basées sur des mémoires associatives. Nous allons voir celles-ci dans la suite du chapitre, mais gardez à l'esprit que ces optimisations, à savoir désactiver les entrées vides/prêts et partitionner la fenêtre d'instruction, sont des optimisations générales qui marchent avec presque tout. ===L'ajout d'une FIFO pour les instructions déjà prêtes à l'émission=== D'autres techniques permettent de réduire aussi bien le cout en circuits que la consommation d'énergie de la fenêtre d'instruction. L'idée est d'utiliser une mémoire associative quand elle est réellement nécessaire, mais d'utiliser une fenêtre d'instruction "normale" dès que possible. La méthode la plus simple tient compte du fait que certaines instructions ont déjà toutes leurs opérandes de disponibles à l'émission, mais doivent quand même être mises en attente, parce que l'ALU adéquate est occupée, parce que des dépendances WAW/WAR sont encore là, ou pour tout autre raison. Dans ce cas, elles sont mises en attente non pas dans la fenêtre d'instruction, mais dans une mémoire FIFO toute simple. L'idée est qu'au lieu d'avoir une énorme mémoire associative pour la fenêtre d'instruction, on déplace quelques entrées dans une petite FIFO annexe. Le résultat est un gain en terme d'énergie et de circuits, au prix d'une perte de performance mineure. La perte de performance en question se manifeste si aucune instruction n'a ses opérandes de prêtes à l'émission : le programme n'utilise pas la FIFO et voit alors une fenêtre d'instruction plus petite. Une amélioration de cette technique tient compte du fait que certaines instructions sont dans un cas intermédiaire. Elles ont déjà une opérande de prête lors de l'émission, mais pas l'autre. Le nombre d'opérandes varie suivant l’instruction : certaines n'ont besoin que d'un seul opérande. De plus, il arrive qu'une opération tout juste décodée ait déjà un ou plusieurs de ses opérandes de prêts. Cette constatation permet d'éviter d'utiliser des comparateurs pour les opérandes déjà prêts. Par exemple, on peut parfaitement utiliser trois fenêtres d'instruction : * une pour les instructions dont tous les opérandes sont prêts, mais qui sont quand même mises en attente, sans comparateur ; * une pour les instructions dont un seul opérande manque, qui n'utilise qu'un comparateur par entrée ; * une pour les instructions dont deux opérandes manquent à l'appel, qui utilise deux comparateurs par entrée. C'est beaucoup plus économique que d'utiliser une seule grosse fenêtre d'instruction qui contiendrait autant d'entrées que les trois précédentes réunies, avec deux comparateurs par entrée. Certains sont même allés plus loin, et ont proposé de supprimer la fenêtre d'instruction avec deux opérandes par entrée. Les instructions dont deux opérandes sont inconnus au décodage sont stockées dans la fenêtre d'instruction pour instructions avec un comparateur par entrée. Un circuit de prédiction se charge alors de prédire l'opérande manquant, cette prédiction étant vérifiée plus loin dans le pipeline. Il serait cependant étonnant qu'une telle proposition ait donné lieu à la moindre implémentation réelle. ===Les optimisations de la consommation d'énergie avancées=== D'autres chercheurs ont conservé une fenêtre d'instruction unique, avec autant de comparateurs par entrée qu'il y a d'opérandes possibles par instruction. Simplement, le processus de détection des opérandes prêts est légèrement ralenti : on ne vérifie qu'un opérande par cycle. Pour vérifier les deux opérandes d'une entrée, on doit attendre deux cycles. Enfin, certains chercheurs ont proposé des fenêtres d'instruction segmentées. Les instructions circulent à chaque cycle d'un segment vers le suivant : en conséquence, certains segments conservent les instructions les plus anciennes, un autre les instructions les plus jeunes, etc. Seul le denier segment, celui qui contient les instructions les plus vielles, peut émettre une instruction : la détection des opérandes se fait seulement dans le dernier segment, qui contient les instructions les plus anciennes. On économise ainsi beaucoup de comparateurs. Certains chercheurs ont tenté de pipeliner l'étape de sélection des opérandes, ainsi que l'étage d'arbitrage. Mais en faisant cela, il faut plusieurs cycles pour détecter qu'une instruction a ses opérandes prêts, ce qui pose problème face à de nombreuses dépendances RAW. Pour éviter de trop perdre en performances, certains chercheurs ont décidé d'utiliser des techniques pour prédire quelles seront les instructions dont les opérandes seront bientôt prêts. Si détecter qu'une instruction est prête prend n cycles, le processeur devra tenter de prédire la future disponibilité des opérandes n cycles en avance pour obtenir des performances optimales. ===Remplacer la mémoire associative par une RAM=== Une autre optimisation possible est de remplacer la fenêtre d'instruction par une mémoire RAM, dont chaque mot mémoire correspondrait à une entrée. Une telle optimisation permet en théorie de se passer des comparateurs associés à chaque entrée, mais au prix de l'ajout de circuits annexes potentiellement couteux. La première de ces techniques, la '''recherche directe par étiquette''' (direct tag search) fut créée par Weiss et son collègue Smith. Ils cherchaient à améliorer l'algorithme de Tomasulo, un algorithme qu'on expliquera dans quelques chapitres. Rappelons que chaque instruction produit un résultat, qui devra être rapatrié dans une ou plusieurs entrées de la fenêtre d'instruction. L'optimisation de la recherche directe par étiquette fonctionne dans le cas où le résultat de l'instruction n'est utilisé que par une seule entrée, et pas plusieurs. Le principe est simple : chaque champ « opérande » d'une entrée est adressable via le nom de registre de cette opérande. Pour faire le lien entre entrée et nom de registre, la recherche directe par étiquette ajoute une table de correspondances matérielle, une mémoire RAM qui mémorise les adresses des champs « opérande » des entrées. Les adresses envoyées dans cette mémoire sont les noms de registres des résultats. Lors de l'émission, la table de correspondances est mise à jour. Les numéros des champs « opérande » réservés lors de l'émission sont mémorisés dans les mots mémoire qui correspondent aux deux registres sources. Toutefois, une petite vérification est faite lors de l'émission : si il y a déjà une correspondance dans la table pour un registre source, alors une autre instruction compte lire ce registre. Pour éviter d'écraser les données de l'instruction précédente dans la table de correspondances, l'émission de l'instruction est bloquée. [[File:Recherche directe par étiquette.png|centre|vignette|upright=2|Recherche directe par étiquette.]] ==Les fenêtres d’instruction avec préplanification== Avec la '''préplanification''' (''prescheduling''), la fenêtre d’instruction est composée de mémoires FIFO dans lesquelles les instructions sont triées dans l'ordre d'émission. Il n'y a pas de logique d’émission proprement dite, celle-ci se bornant à vérifier si l'instruction située au début de la FIFO peut s’exécuter. Par contre, le préplanificateur détecte les dépendances et en déduit où insérer les instructions dans le tampon d'émission, à l'endroit le plus adéquat. [[File:Préplanification.jpg|centre|vignette|upright=2|Préplanification.]] ===L'usage de FIFO multiples=== La technique de préplanification la plus simple utilise plusieurs FIFO. Quand une instruction a une dépendance avec une autre instruction, les deux sont placées dans la même FIFO. Pour cela, le préplanificateur détecte les chaines d'instructions dépendantes, et place les instructions dans la FIFO adéquate. A chaque cycle, l'unité d'émission lit une micro-opération dans chaque FIFO et vérifie si elle peut l'émettre. Si la micro-opération n'a pas ses opérandes disponibles, ou qu'une dépendance structurelle survient, alors la FIFO est bloquée. La micro-opération attend que la dépendance soit résolue, bloquant toutes les instructions précédentes. Mais les autres FIFO ne sont pas bloquées, laissant de la marge de manœuvre. [[File:Préplanification par FIFO multiples.png|centre|vignette|upright=1.5|Préplanification par FIFO multiples.]] ===La technique du tampon trié=== La technique du '''tampon trié''' trie les instructions selon le temps d'attente avant leur exécution. Les instructions qui sont censées s’exécuter bientôt sont insérées au tout début de la FIFO, tandis que les instructions qui s’exécuteront dans un long moment sont insérées vers la fin. Là encore, l'unité d'émission lit une micro-opération dans la FIFO, et détermine si elle peut être émise. Si une dépendance survient, l'émission est retardée, et la FIFO est bloquée. [[File:Préplanification par tampon trié.png|centre|vignette|upright=1.5|Préplanification par tampon trié.]] La technique a cependant quelques problèmes assez importants. Le premier problème est que la FIFO est bloquée lorsqu'une micro-opération ne peut être émise. Le second problème est que le temps avant exécution n'est pas toujours connu, notamment pour les instructions d'accès mémoire. Et cela se répercute sur les instructions dépendantes de celles-ci. Pour résoudre ce genre de problèmes, l'usage d'un pipeline à ''replay'' est possible, et est même l'une des meilleures solution possible, malgré ses défauts. L'idée est que les lecture sont pré-planifiées en supposant qu'elles font un succès de cache L1. Si la prédiction est fausse, la lecture est ré-exécutée plusieurs cycles plus tard, en supposant qu'elle fait un succès dans le cache L2, et ainsi de suite. Elle est alors ré-insérée dans la FIFO, elle est pré-planifiée une seconde fois. Il en est de même si une micro-opération ne peut pas être émise : il suffit de la réinsérer dans la FIFO au bon endroit, en attendant que ses dépendances soient résolus. Ainsi, l'instruction fautive ne bloque pas la fenêtre d’instruction, et retente sa chance autant de fois qu'il le faut. [[File:Préplanification par fenêtre d’instruction scorebarodée.png|centre|vignette|upright=1.5|Préplanification par fenêtre d’instruction scorebarodée.]] Une autre solution utilise deux fenêtres d’instruction : une FIFO gérée par la préplanification, et une vraie fenêtre d'instruction pour les instructions dont le temps d'attente ne peut pas être déterminé. Il est possible de mettre cette dernière avant la préplanification, afin de gérer les temps d'attente des instructions d'accès mémoire. Quand le temps d'attente d'une lecture devient connu, ses instructions dépendantes sont gérées avec préplanification. [[File:Préplanification avec fenêtre d’instruction.png|centre|vignette|upright=2.5|Préplanification avec fenêtre d’instruction.]] ===Les fenêtres d'instruction avec allocation temporelle statique=== L''''allocation temporelle statique''' correspond à une technique utilisée sur les processeurs Cuzco de l'entreprise Condor. La technique en question a été présenté en 2025, mais des idées similaires ont été présentées dans la littérature académique. Elle ressemble beaucoup aux techniques de pré-planification, avec cependant quelques différences. L'idée est simple : le processeur dispose de plusieurs fenêtres d'instruction, qui mettent en attente les micro-opérations. Lors de l'étape de renommage de registres, le processeur détermine dans combien de cycles d'horloge la micro-opération sera prête pour exécution. La micro-opération est alors mise en attente durant ce nombre de cycles, dans les fenêtres d'instruction, puis est émise une fois ce nombre de cycles écoulés. Ce faisant, les fenêtres d'instruction n'ont pas besoin de détecter la disponibilité des opérandes à chaque cycle, pour chaque micro-opération en attente. Le ''timing'' de l'émission des micro-opérations est décidé à l'avance. L'implémentation exacte n'est pas connue, mais plusieurs solutions sont imaginables. Par exemple, la fenêtre d'instruction peut simplement être composée de plusieurs mémoires de petite taille, chacune contenant les micro-opérations destinées à être exécutées dans N cycles, N étant différent pour chaque mémoire. Une autre solution, plus réaliste, utilise une fenêtre d'instruction dans laquelle la micro-opération est couplée à des champs pour les opérandes, et un champ compteur. Le champ compteur est initialisé avec le nombre de cycles à attendre, et est décrémenté à chaque cycle d'horloge. Quand il atteint zéro, la micro-opération est émise. Vous remarquerez que la méthode ne marche que si toutes les micro-opérations prennent un nombre fixe de cycles d'horloge. Et autant c'est le cas pour les micro-opérations arithmétiques ou logiques, autant les accès mémoire ne rentrent pas dans ce cadre. En théorie, on ne sait pas combien de temps prendra un accès mémoire. Et cette incertitude se répercute sur les instructions dépendantes d'un accès mémoire. Pour éviter cela, le processeur réutilise un pipeline à ''replay'' tel que vu dans le chapitre précédent. L'unité de renommage de registre suppose que tout accès mémoire fait un succès de cache L1, et décide des ''timings'' d'émission sous cette hypothèse. Si une lecture subit un défaut de cache, elle est ré-exécutée, de même que toutes les instructions dépendantes. Pour cela, le registre de destination de la lecture est marqué comme invalide, grâce à un bit spécifique attaché au registre. Toute instruction qui lit une opérande invalide est elle aussi ré-executée de zéro. Pour simplifier, l'unité d'émission ressemble à une unité d'émission dans l'ordre, avec un registre de disponibilité, qu'on aurait amélioré pour aller au-delà de la simple détection des dépendances d'instruction. Pour déterminer les ''timings'' d'émission, à savoir quand émettre une micro-opération, le processeur utilise une unité d'émission à deux étages. Le premier étage est appelé le ''register scoreboard'', le second étage est appelé la ''Time Ressource Matrix''. Les deux étages communiquent entre eux, comme on va le voir, et leurs noms donnent une idée de ce qu'ils font. Le premier étage gère les dépendances de registres, le second gère les dépendances structurelles. Le premier étage est un registre de disponibilité amélioré, qui gère les dépendances de registre. Cet étage sait quand tel registre sera écrit, et donc que l'opérande écrite dedans sera disponible à partir de tel cycle d'horloge. Il le sait car l'étage suivant l'aura prévenu, mais laissons cela de côté pour le moment. Quand une micro-opération rentre dans cet étage, il vérifie les dépendances avec les registres et les micro-opérations antérieures. Vu qu'il sait quand les registres seront disponibles, il peut déterminer quand l'instruction pourra s'exécuter. Par exemple, si une micro-opération lit les deux registres R7 et R15, qui sont disponibles respectivement dans 5 et 7 cycles, le premier étage sait que la micro-opération devra attendre 7 cycles. Mais tout cela ne suffit pas à déterminer quand émettre une micro-opération. En effet, il fait aussi gérer les dépendances structurelles, ce qui est le boulot du second étage. Le second étage utilise pour cela une ''Time Ressource Matrix'', qui mémorise l'occupation de diverses "ressources", pour les 256 cycles d'horloge à venir. Les ressources en question sont les ports de lecture/écriture du banc de registre, les ALUs utilisées, si la micro-opération utilise l'unité mémoire, etc. Le second étage prend en entrée une micro-opération, détermine quelles "ressources" elle utilise, puis regarde leur disponibilité. Elle détecte alors les dépendances structurelles et détermine alors quand peut s'exécuter la micro-opération. Elle peut retarder l'émission de quelques cycles, si une dépendance structurelle est détectée. Une fois sortie du second étage, on sait quand la micro-opération va être émise, à quel cycle précisément. Et vu que la durée de l'instruction est fixe, on sait quand cette micro-opération va se terminer, quand son résultat sera disponible. Cela permet de mettre à jour la ''Time Ressource Matrix'', pour préciser que le port d'écriture sera occupé à tel moment. De plus, cette information est transmise au premier étage, qui sait alors quand est enregistré le résultat dans le registre de destination. C'est comme cela que le premier étage sait quand un registre est disponible : le second étage le prévient, quand il émet une instruction ! La ''Time Ressource Matrix''mémorise l'occupation des "ressources" pour les 256 cycles d'horloge à venir. Cependant, elle ne vérifie pas les dépendances pour les 256 cycles suivants. Quand elle reçoit une micro-opération, elle teste les dépendances structurelles pour seulement les 8 prochains cycles maximum. Si la micro-opération ne peut pas être émise pendant ces 8 cycles, le pipeline est bloqué, un ''pipeline stall'' est émis. Pour être plus précis, vu que le processeur peut décoder 8 micro-opérations en même temps, cela permet de ne consulter que 64 cycles d'horloge sur les 256. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les premiers processeurs Intel | prevText=Les premiers processeurs Intel | next=Le renommage de registres | nextText=Le renommage de registres }} </noinclude> 3ec303av853by9ssko2sjw22yo4bg9p 773592 773591 2026-09-29T17:55:02Z Mewtow 31375 /* Les fenêtres d'instruction décentralisées */ 773592 wikitext text/x-wiki Dans les chapitres précédents, nous avons parlé des techniques dites d''''émission dans l'ordre'''. L'idée est d’exécuter une nouvelle micro-opération à chaque cycle, dans des unités de calcul séparées. Les instructions sont émises consécutivement, mais les instructions s’exécutent en parallèle dans des unités de calcul séparées. Par contre, quand l'unité d'émission ne peut pas émettre une instruction, elle bloque tout le pipeline. Les instructions qui suivent sont elles aussi bloquées, elle doivent attendre leur tour, même si elles sont en capacité de s'exécuter. Les techniques d'exécution dans le désordre que nous allons voir dans ce chapitre corrigent ce point précis. Elles sont dites à '''émission dans le désordre'''. Elles se distinguent des précédentes sur un point précis : quand l'unité d'émission bloque l'émission d'une instruction, les instructions suivantes peuvent poursuivre. L'émission des instructions peut donc se faire dans le désordre, dans le sens où une instruction peut être émise alors qu'une instruction précédente ne l'est pas encore. L'avantage de l'émission dans le désordre est qu'une instruction s'exécute dès que ses opérandes sont disponibles. Par disponible, on veut dire présent soit dans le réseau de contournement, soit dans les registres. Le processeur détecte automatiquement quand les opérandes d'une instruction sont sont disponibles, et il l’exécute à ce moment là. Dès qu'une instruction a ses opérandes disponibles, elle est émise et exécutée. C'est là la seule contrainte : les dépendances WAR, WAW et autres sont gérées par un ROB ou toute autre technique d'exception précise, seules les dépendances RAW limitent l'exécution. Mais avant de poursuivre, quelques point niveaux terminologie : * L'émission dans le désordre est un terme parlant et assez précis. Malheureusement, la terminologie la plus utilisée par d''''exécution dans le désordre'''. Et nous utiliserons ce terme dans la suite du cours, histoire de ne pas trop dévier de la nomenclature habituelle. * Nous utiliserons parfois l'abréviation OOO pour parler d'exécution dans le désordre. L'abréviation est celle de ''Out Of Order Excution''. * Nous utiliserons aussi l'abréviation ''µop'' pour parler de micro-opération, ''µops'' au pluriels pour parler de plusieurs micro-opérations, ou des micro-opérations en général. L'exécution dans le désordre ne gére en effet que des µops, elle se situe après l'étape de décodage. Mais avant de poursuivre, précisons une chose importante : l'exécution dans le désordre traite les accès mémoire à part. La majorité des processeurs OOO assez anciens exécutent les accès mémoire dans l'ordre, seules les µops entières/flottantes/branchements sont exécutées dans le désordre. Les processeurs datant d'après les années 2010 sont capable d'exécuter les accès mémoire dans le désordre, mais l'implémentation en question est assez particulière. Un chapitre entier sera dédié à l'exécution dans le désordre des µops mémoire. Nous allons volontairement mettre de côté la gestion des accès mémoire dans ce chapitre. ==Les fenêtres d’instruction : généralités== [[File:File de micro-opération.png|vignette|upright=1|File de micro-opérations]] Pour décrire comment est implémentée l'émission dans le désordre, il faut commencer par parler des processeurs sans. Les processeurs sans exécution dans le désordre ont une unité d'émission qui bloque tout le pipeline dès qu'une µop ne peut pas être émise. Pour limiter l'impact de ce blocage, quelques rares processeurs incorporent une '''file de micro-opération''', une mémoire FIFO qui met en attente les µops. Vu que c'est une mémoire FIFO, les µops sont émises dans l'ordre, à savoir l'ordre d'ajout, dans l'ordre de décodage. Le schéma ci-dessous illustre une telle file d'attente couplée à un ''scoreboard''. Sur le principe, l'exécution dans le désordre améliore la file de µops sur un point : ce n'est plus une mémoire FIFO. Les µops sont insérées dans l'ordre, mais peuvent sortir dans le désordre (être émises dans le désordre). La file de µops devient alors une '''fenêtre d'instruction''', terme traduit directement de l'anglais ''instruction Window''. Terme assez trompeur, car elles mettent en attente des µops, pas des instructions. Elles peuvent émettre des µops dans le désordre, ce qui fait que si une µop bloque le pipeline, les µops suivantes peuvent être émises. Si je commence le paragraphe précédent par "sur le principe", c'est car certaines techniques d'OOO utilisent des files de µops normales. Il est par exemple possible d'utiliser une file de µops avec une fenêtre d'instruction, plusieurs files de µops, plusieurs fenêtres d'instructions avec une file de µops annexe, etc. Dasn les grandes lignes, il existe dans les grandes lignes 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! File de µops améliorée |- ! Une seule "file de µops" | ''Scoreboard'' | Fenêtre d'instruction centralisée |- ! Plusieurs "file de µops" | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | Fenêtre d'instruction décentralisée |} ===La fenêtre d'instruction centralisée=== L'implémentation la plus simple de l'OOO utilise une unique '''fenêtre d'instruction'''. Les instructions décodées sont accumulées dans la fenêtre d'instruction, où elles attendent que leurs opérandes soient disponibles. La fenêtre d'instruction sert donc de file d'attente. Mais elle contient aussi une unité d'émission, qui détecte quelles µops sont prêtes à être émises. L'unité d'émission et la fenêtre d'instruction sont fusionnées ensemble, elles forment un seul circuit. Mais nous allons dire qu'elles sont conceptuellement séparées pour le moment. A chaque cycle, l'unité d'émission consulte la fenêtre d'instruction pour voir quelles µops peuvent s'exécuter, lesquelles ont leur opérandes de disponibles. La fenêtre d'instruction doit spécialement être conçue pour, c'est une sorte de mémoire associative très complexe, comme on le verra dans ce qui suit. [[File:OOO Issue.png|centre|vignette|upright=2.5|Exécution dans le désordre avec une fenêtre d'instruction]] Une fois qu'une µop sort du décodeur d'instructions, elle est ajoutée en parallèle dans la fenêtre d'instruction et le ROB. La raison est que les µops quittent la fenêtre d'instruction dans le désordre, et qu'elles doivent être remises en ordre par la suite. Le ROB s'occupe de cette remise en ordre, mais il a besoin de savoir dans quel ordre les µops sont censées être, et cet ordre est celui du décodage. Aussi, pour remplir le ROB, la seule opportunité est en sortie de l'unité de décodage. Dans le cas où une instruction est décodée en plusieurs micro-opérations, elles sont toutes insérées en même temps dans la fenêtre d'instruction et le ROB, en tenant compte de leur ordre. [[File:Fenêtre d'instruction.png|centre|vignette|upright=2|Fenêtre d'instruction.]] Les micro-opérations mémoire sont à part des autres, pour diverses raisons. Une de ces raisons est que les dépendances de données sont classées en deux types : les dépendances de registre et les dépendances d'adresse. Et les deux sont fondamentalement différentes. Autant on peut détecter les dépendances de registre lors de l'émission, autant c'est plus compliqué avec les dépendances d'adresse. De plus, rappelons que si les lectures peuvent s'exécuter dans le désordre, les écritures doivent s'exécuter dans l'ordre, ou du moins en donner l'illusion. Pour cela, le processeur remet les écritures dans l'ordre avec une sorte de mini-ROB intégré à l'unité mémoire, appelée la file d'écriture. Elle complémente le ROB, qui lui ne gère que les écritures dans les registres, mais les deux collaborent. La file d'écriture envoie une écriture à la mémoire RAM quand le ROB lui dit que c'est bon, les instructions précédentes sont terminées ''dans l'ordre du programme''. Les processeurs modernes ajoutent des techniques d'exécution dans le désordre des accès mémoire, mais nous les verrons dans un chapitre dédié. Elles permettent d'utiliser une fenêtre d'instruction unique, qui mémorise aussi les µops mémoire. Si elles sont mises en place, l'unité mémoire n'a pas besoin de file de µops séparée. L'idée est que les dépendances de registre sont traitées par la fenêtre d'instruction, mais que l'unité mémoire gére les dépendances d'adresse. Les dépendances d'adresse sont gérées par des techniques de ''désambiguation mémoire'', qui auront droit à un chapitre dédié. [[File:Processeur avec exécution dans le désodre des accès mémoire.png|centre|vignette|upright=2|Processeur avec exécution dans le désodre des accès mémoire]] Les processeurs assez anciens n'autorisaient pas d'exécution dans le désordre des accès mémoire. Concrétement, les accs mémoire devaient se faire dans l'ordre, mais les autres µops pouvaient être exécutées dans le désordre. Il s'agit donc d'un ordre entre µops mémoire, pas entre µops mémoire et autres µops. Les µops entières et flottantes pouvaient être exécutées avant une µops mémoire qui est avant elle dans l'ordre du programme, ce n'est pas un problème. Pour garantir l'ordre desd µops mémoire, l'unité mémoire est précédée par une file de micro-opérations séparée, pour forcer l'exécution dans l'ordre des accès mémoire. De plus, les µops mémoire ne peuvent pas utiliser la fenêtre d'instruction. Dit autrement, la fenêtre d'instruction ne mémorise pas de µops mémoire. Après le décodage, les µops sont réparties soit dans la file de µops mémoire, soit dans la fenêtre d'instruction. Le décodeur classe les µops suivant que ce sont des µops mémoire ou non, et les envoient à la bonne destination. Dans ce chapitre, on supposera que c'est cette solution qui est utilisée. [[File:Processeur avec émission dans l'ordre des accès mémoire.png|centre|vignette|upright=2|Processeur avec émission dans l'ordre des accès mémoire]] La solution précédente revient à scinder la fenêtre d'instruction en deux : une file de µops pour les µops mémoire, une fenêtre d'instruction pour les autres µops. Et cette scission peut aller plus loin, à savoir qu'on peut scinder une fenêtre d'instruction encore et encore. Ce qui nous amène à la section suivante. ===Les fenêtres d'instruction décentralisées=== Nous venons de voir qu'il est possible de scinder la fenêtre d'instruction en plusieurs fenêtres d'instruction plus petites. les fenêtres d'instruction résultantes étaient de plus "spécialisées" : une pour les µops mémoire, simplifiée en une file de µops classique, et une autre pour les autres instructions. Sachez qu'il est possible d'aller plus loin, par exemple en séparant la fenêtre d'instruction en une fenêtre spécialisée dans les µops flottantes et une autre pour les µops entières. Et ce n'est là qu'un exemple parmi de nombreuses autres possibilités. Pour faire la différence avec l'usage d'une fenêtre d'instruction unique, nous allons parler de fenêtre d'instruction centralisée s'il n'y en a qu'une dans le processeur, de '''fenêtre d'instruction décentralisée''' s'il y en a plusieurs. Dans le cas général, chaque fenêtre d'instruction est associée à un type précis d'opération/instruction. La tendance moderne est d'utiliser une fenêtre d'instruction pour les µops de calcul entières, une autre pour les µops flottantes, une autre pour les µops mémoire. Il s'agit d'un choix simple et efficace, mais quelques processeurs font autrement, pour répondre à des contraintes très diverses. L'usage de fenêtres décentralisées simplifie la répartition des instructions sur les différentes unités de calcul. Par exemple, utiliser des fenêtres séparées pour les ALU et les FPU facilite la répartition des instructions de calcul sur les ALU. Une fenêtre centralisée demande de faire la différence entre instruction entière/flottante, puis de choisir sur quelle unité de calcul entière/flottante utiliser. Une fenêtre décentralisée fait les deux choix séparément : d'abord on envoie l'instruction dans la bonne fenêtre suivant si c'est une instruction flottante ou entière, et ensuite on gère la disponibilité des ALUs/opérandes. Et on peut adapter la même idée en séparant les unités d'accès mémoire des ALU entières, etc. Par contre, un défaut est que certaines fenêtres d'instruction peuvent être sous-utilisées. Par exemple, la station de réservation flottante est inutilisée si le programme n'exécute pas d'opérations flottantes. Ou encore, les fenêtres pour les accès mémoire peuvent être sous-utilisées, si le programme effectue peu d'accès mémoire relativement aux autres instructions. En fait, tout dépend de comment sont calibrées les fenêtres d'instruction et de la répartition des instructions dans le programme entre opérations entières, flottantes, mémoire. Par exemple, si un programma de deux fenêtres d'instructions identiques, une pour les calculs entiers et une autre pour les calculs flottants, elles ne seront utilisées à la perfection que si la moitié des instructions du programme fait des calculs flottants et l'autre des calculs entiers. Toute déviation par rapport à cette répartition idéale risque de laisser des entrées vides dans une fenêtre d’instruction. Un point important est que l'émission est découpée en deux étages avec des fenêtres d'instruction décentralisées. La première étape envoie l'instruction décodée vers la fenêtre d'instruction adéquate, la seconde gère l'émission proprement dit. La première est l'étage de ''dispatch'' qui envoie l'instruction dans la fenêtre d’instruction adéquate, selon que c'est une instruction flottante, entière, autre. La seconde est l'étage de ''scheduling'', qui gère la disponibilité des opérandes et des unités de calcul. En clair, on trie les instructions suivant leur type, suivant le type d'unité de calcul adéquate, puis on l'émet proprement dit. Faire ainsi a plusieurs avantages, avec cependant peu d'inconvénients. Lors de l'étape de ''dispatch'', l'instruction émise est ajoutée au tampon de réordonnancement, s'il existe. Sans cela, impossible de conserver l'ordre des instructions. Les instructions sont émises dans l'ordre au niveau de l'unité de ''dispatch'', pas au niveau de l'étage de ''scheduling''. Aussi, pour remplir le ROB, cela doit se faire au dernier moment où les instructions sont émises dans l'ordre, soit en sortie de l'unité de ''dispatch''. De plus, les micro-opérations mémoire sont traitées à part des autres, elles sont envoyées directement à l'unité mémoire. La gestion des calculs d'adresse est quelque peu complexe, mais ils peuvent être fait soit dans l'unité mémoire, soit dans les ALU entières, peu importe. Il y a aussi un système de contournement complexe entre ALU/FPU et unité mémoire, qui n'est pas représenté dans le schéma ci-dessous. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Il faut noter que quelques processeurs utilisent des méthodes intermédiaires entre les trois solutions précédentes. Par exemple, les processeurs AMD Zen utilisent une fenêtre d'instruction décentralisée un peu particulière. Les unités de calcul entières disposent d'une fenêtre d'instruction rien que pour elles, sur ce processeur. Les instructions flottantes sont quant à elles alimentées par une file de micro-opération, pas une fenêtre d'instruction ! La raison à ce choix est un compromis entre performance et cout en circuit. L'exécution dans le désordre est peu efficace sur les instructions flottantes, car les CPU n'ont que peu d'ALU flottantes séparées. Vu le cout en circuits d'une fenêtre d'instruction, les concepteurs du processeur ont préféré utiliser une file de micro-opération pour les opérations flottantes. ===L'usage de plusieurs files d'instruction=== Une dernière méthode d'OOO utilise plusieurs files de micro-opération. L'idée est qu'une fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement une file de micro-opération pour les opérations entières, une autre pour les opérations flottantes, une autre pour les accès mémoire. D'autres processeurs utilisent une file pour les accès mémoire et une autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. La présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que la technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si une dépendance bloque une FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans une autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer la disponibilité des registres. Quand un registre est lu ou écrit par une instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. La logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : une pour les instructions d'accès mémoire et une autre pour les autres instructions. Si jamais une instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de la lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'une est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est la file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. ===Avantages et inconvénients de chaque implémentation=== Un processeur contient soit une fenêtre d'instruction unique, soit plusieurs fenêtres d'instruction séparées. Typiquement, les fenêtres d’instruction séparées sont spécialisées, dans le sens où on a une fenêtre pour les instructions flottantes, une autre pour les instructions entières, une autre pour les accès mémoire, etc. Pour résumer, on a le choix entre une grosse fenêtre généraliste et plusieurs fenêtres spécialisées, sauf que la fenêtre centralisée est lente et complexe, contrairement aux fenêtres spécialisées. Les deux méthodes ont des inconvénients et des avantages différents. Dans les grandes lignes, l'avantage des fenêtres décentralisées est qu'elles sont plus petites qu'une grosse fenêtre d'instruction. Cela simplifie la gestion du contournement et de la répartition des instructions sur les unités de calcul, comme on le verra dans quelques paragraphes. Elles sont donc moins complexes et plus rapides. L'autre avantage, c'est qu'il est possible de démarrer l'exécution de plusieurs instructions simultanément : une instruction par fenêtre décentralisée, contre une par fenêtre d'instruction. Mais les fenêtres décentralisées sont souvent sous-utilisées, partiellement remplies, contrairement aux fenêtres d'instruction. Il arrive qu'une fenêtre d'instruction soit remplie, alors que les autres sont vides. Par exemple, prenons un processeur avec une fenêtre d'instruction reliée à la FPU, et une autre reliée aux autres ALUs. Si le processeur n'exécute que des opérations flottantes, la fenêtre reliée à la FPU sera pleine, alors que l'autre sera vide. L'exécution des instructions dans le désordre est alors limitée par la petite taille de la fenêtre, qui ne peut plus accepter de nouvelle instruction flottante. Avec une fenêtre unique, on n'aurait pas eu ce problème : on aurait eu une énorme fenêtre d'instruction remplie d'instruction flottante, au lieu d'une petite fenêtre spécialisée. Il est maintenant temps de voir en quoi sont faites les fenêtres d’instruction, qu'elles soient centralisées ou décentralisées. Nous allons aussi voir quelle est la logique d'émission associée. ==L'implémentation d'une fenêtre d'instruction : généralités== Une fenêtre d'instruction est une mémoire qui mémorise des micro-opérations. Elle est cependant plus complexe qu'une mémoire RAM ou qu'une FIFO et ressemble un petit peu à une mémoire cache. Elle dispose d'un port d'écriture et d'un port de lecture, au minimum. Le port d'écriture permet à l'unité de décodage d'insérer une micro-opération dedans, d'ajouter la micro-opération qui vient d'être décodée. Si une instruction machine est décodée en plusieurs micro-opération, deux possibilités. La première est de les insérer un par un, ce qui fait qu'on peut se contenter d'un seul port d'écriture. L'autre possibilité est de les ajouter en même temps, ce qui demande plusieurs ports d'écriture. Le port de lecture sert à émettre une instruction. On part du principe que la fenêtre d'instruction ne peut émettre qu'une seule instruction à la fois, car les processeurs que nous avons vu précédemment sont de ce type. Mais nous verrons dans quelques chapitre qu'il existe des processeurs dits superscalaires, qui sont capables d'émettre plusieurs instructions par cycle. Dans ce cas, la fenêtre d'instruction a un seul port de lecture. Un processeur superscalaire, quant à lui, doit avoir un port de lecture par unité de calcul, ce qui fait beaucoup plus. ===Les entrées d'une fenêtre d’instruction=== Les fenêtres d'instruction sont composées d''''entrées''', des mots mémoire qui stockent une instruction. Une instruction réserve une entrée après son décodage et la libère dès qu'elle est envoyée aux unités de calcul. Une entrée contient l'opcode (les signaux de commande à envoyer à l'ALU), le registre de destination du résultat, les registres de chaque opérande, et éventuellement des signaux de commande en plus. De plus, chaque opérande est couplée à un bit de disponibilité, qui indique si elle est disponible. Quand un opérande est écrit dans les registres, le bit de présence correspondant est mis à jour. Enfin, chaque entrée possède un bit ''empty'' qui indique si elle est vide, cette information étant utile pour réserver des entrées. [[File:Entrée d'une station de réservation - sans les tags.png|centre|vignette|upright=3|Entrée d'une fenêtre d'instruction]] Nous verrons dans quelques chapitres que certaines fenêtres d'instruction sont capables de mémoriser les opérandes des instructions. De telles fenêtres d'instruction seront appelées, dans ce cours, des '''stations de réservation'''. Les entrées des stations de réservation sont assez semblables à celle des fenêtres d'instruction, à un détail près : les opérandes de l'instruction sont enregistrées directement dans des champs séparés. Il y a deux champs, un par opérande, pour stocker l'opérande elle-même, lue depuis les registres ou obtenue via le réseau de contournement. Notons que les champs pour les opérandes viennent en plus des champs pour les noms de registres, encore que les deux peuvent être fusionnés si on veut optimiser le tout. [[File:Entrée d'une station de réservation.png|centre|vignette|upright=3|Entrée d'une station de réservation.]] Précisons que la terminologie n'est pas très fiable. Les termes "fenêtre d'instruction" et "station de réservation" ne regroupent pas du tout la même chose d'un papier de recherche à l'autre, d'un bouquin à l'autre, d'un chercheur à l'autre, d'un ingénieur à l'autre, d'un professeur à l'autre. Le terme initial vient pourtant de l'article original sur l'algorithme de Tomasulo, où il désignait une fenêtre d'instruction associée à une unité de calcul précise. Mais le terme a ensuite été réutilisé, ce qui fait que certains processeurs avec plusieurs unités de calcul sont décrit comme ayant une unique station de réservation. En bref : c'est le bazar ! Mais nous en reparlerons dans le chapitre sur le renommage de registres, car c'est la place idéale pour les aborder. Toujours est-il que j'ai fait le choix de confondre les concepts de fenêtre d'instruction et de station de réservation avec les concepts de '''lecture avant émission''' et de '''lecture après émission'''. La différence entre les deux est que les registres sont lus après émission avec une fenêtre d'instruction, avant avec des stations de réservation. Dans le cas "avant émission", les opérandes sont mémorisées dans la station de réservation. Et cette différence a une influence sur le pipeline du processeur, le banc de registres et tout ce qui s'en suit. Un désavantage de la lecture avant émission est qu'il faut stocker les opérandes après lecture, ici dans les stations de réservation. Mais un avantage est que le banc de registre a besoin de moins de ports de lecture, car une bonne partie des opérandes sont fournies par le système de contournement. Nous verrons cela dans le détail dans le chapitre sur les processeurs superscalaires. Il a été proposé de fusionner le tampon de ré-ordonnancement avec la fenêtre d'instruction dans une structure unique. La méthode a notamment été utilisée sur les processeurs d'architecture K6 d'AMD. Le tout donnait une structure appelée le '''DRIS''' (''deferred scheduling register renaming instruction shelf''). La différence avec une fenêtre d’instruction normale est que les entrées sont libérée non pas quand l'instruction est exécutée/émise, mais quand elle termine son exécution et quitte le ROB. La fenêtre d'instruction doit alors incorporer des bits pour savoir si telle entrée a émis sont instruction ou non. ===La logique d'éveil et de sélection=== Dans le cas qui va suivre, on suppose que le processeur ne peut émettre qu'une instruction à la fois. Chaque cycle, une instruction est sélectionnée et est envoyée dans le chemin de données, soit à une ALU, soit à une unité d'accès mémoire. La sélection d'une instruction est effectuée par l'unité d'émission, qui est aussi appelée le '''''scheduler'''''. Elle gère la disponibilité des opérandes et la disponibilité des unités de calcul adéquate. Le choix de l'instruction émise doit être le plus pertinent possible, pour des raisons de performances. Pour le premier point, l'unité d'émission détermine quelles instructions sont candidates pour l'émission. Les ''instructions candidates'' sont celles dont tous les opérandes sont prêts. Le processeur contient un circuit qui détecte les instructions candidates : la '''logique d’éveil''' (''wake-up logic''). Une fois que la logique d'éveil a fait son travail, une instruction est choisie pour s’exécuter en fonction de la disponibilité des unités de calcul adéquates. Ce rôle est dévolu à un circuit qu'on appelle la '''logique de sélection''', ou ''select logic''. [[File:Fonctionnement complet de la logique d’émission.jpg|centre|vignette|upright=1.5|Fonctionnement complet de la logique d’émission.]] La logique de sélection doit gérer le fait que les unités de calcul du processeur ne sont pas toutes identiques. Déjà, un processeur a généralement des unités séparées pour les instructions entières et flottantes, des unités spécialisées dans les accès mémoire, parfois des unités spécialisées pour les branchements. Une instruction doit être attribuée à la bonne unité de calcul, on ne doit pas envoyer une instruction entière dans une unité de calcul flottante. De plus, parmi les unités de calcul entières, toutes ne sont pas identiques. Par exemple, il est fréquent d'avoir plusieurs unités de calcul spécialisées dans les opérations simples (additions, soustractions, opérations logiques) avec une unité pour les multiplications/divisions séparées, parfois une unité spécialisée pour les décalages/rotations, etc. Là encore, allouer la bonne instruction à la bonne ALU est complexe. Plus les unités de calcul sont hétérogènes, plus la logique de sélection est compliquée. Les logiques d'éveil comme de sélection sont assez complexes. Comme on le verra plus bas, la logique de sélection la plus simple, qui gère une seule unité de calcul, est basée sur un encodeur à priorité couplé à d'autres circuits. Et pour gérer plusieurs ALUs, il faut mettre des encodeurs en cascade. Le résultat est que même en prenant une logique de sélection simple, elle sera assez lente et gourmande en circuits. Aussi, la logique de sélection met souvent un cycle d'horloge entier pour faire son travail, elle a son propre étage de pipeline attribué. La logique d'éveil est dans le même cas, ce qui fait qu'émettre une micro-opération demande deux cycles d'horloge. Le défaut est que cela rajoute des cycles d'horloges entre la fenêtre d'instruction et l'ALU, ce qui complique la gestion du pipeline. Ces cycles de retard sont à prendre en compte au moment d'émettre les instructions, les ''scheduler'' doit en tenir compte pour des performances optimales. Sans tenir compte de ces cycles de retard, les instructions arrivent en retard de quelques cycles à l'ALU, cycles de retard durant lesquels l'ALU n'a pas fait de calcul et a été sous-utilisée, sans compter que le système de contournement n'est pas utilisé au mieux. Et le problème est encore plus important sur les processeur avec des stations de réservation, qui utilisent la "lecture après émission" : cela rajoute un cycle d'horloge en plus, un temps de retard en plus. ===La logique d'éveil : l'émission anticipée=== La logique d'éveil doit tenir compte du fait qu'il y a plusieurs étages entre l'émission et l'exécution sur une unité de calcul. Par exemple, un processeur a souvent entre un et à cinq étages entre la file d'attente et les unités de calcul. Il faut lire les registres, gérer le contournement, et cela peut prendre quelques cycles d'horloge. Sur le Pentium 4, on trouve 6 étages entre la fenêtre d’instruction et l'entrée de l'ALU. Si les micro-opérations sont émises quand les opérandes sont disponibles, il y aura un délai de quelques cycles avant qu'elles atteignent l'ALU. Alors qu'idéalement, on souhaiterait que la micro-opération atteigne l'ALU dès que ses opérandes sont disponibles, pour profiter des techniques de contournement. Pour cela, la logique d'éveil émet les instructions quelques cycles en avance pour qu'elles arrivent au bon moment. Il s'agit d'une technique d''''émission anticipée''', dont nous avions parlé dans le chapitre sur le contournement. : Il faut noter que le problème se pose plus avec des fenêtres d'instruction qu'avec des stations de réservation. Les premières ont un étage en plus entre émission et ALU, vu qu'il faut lire des registres après l'émission. L'émission anticipée demande d'émettre un signal d'éveil en avance de quelques cycles, pile au bon moment. Par exemples, si on a deux étages entre l'ALU et l'unité d'émission, le signal de réveil sera généré deux cycles avant que le résultat soit effectivement calculé. L'implémentation varie, mais deux solutions sont possibles. La première est de générer le signal d'éveil dans l'ALU, ce qui n'a de sens que pour les opérations comme les multiplications ou les divisions, qui prennent plusieurs cycles. Une autre technique génère le signal de réveil dans une structure centralisée, spécialisée dans la génération des signaux d'éveil. L'unité de composée d'un registre à décalage par registre. Imaginons qu'une instruction est émise, que cette instruction mette N cycles à s'exécuter, et qu'elle écrive dans un registre de destination. L'unité sélectionne alors le registre à décalage associé au registre de destination, et met le bit numéro N à 1. Le registre décalé d'un cran à chaque cycle. Quand le bit sortant est un 1, alors le signal de validité pour l'opérande est généré. L'émission anticipée marche bien si l'instruction a une durée fixe, connue à l'avance. Et autant c'est le cas pour les instructions arithmétiques et logiques, autant ce n'est pas le cas pour les accès mémoire. Les accès mémoire ont une latence variable : quelques cycles pour un succès de cache, plusieurs dizaines de cycles pour un défaut de cache L1, pas loin de la centaine pour un défaut de cache L2, etc. Et cela pose des problèmes pour l'émission anticipée. L'émission en avance pour les accès mémoire est purement spéculative : le processeur émet des instructions en supposant que la lecture entrainera un succès de cache, quitte à annuler l'instruction en cas de défaut de cache. Mais faire ainsi demande non seulement d'annuler les instructions émises en avance, mais aussi de ne pas retirer les instructions émises en avance de la fenêtre d'instruction. Elles sont émises, mais une copie de sauvegarde est conservée dans la fenêtre d'instruction. Si le processeur détecte un défaut de cache, il peut alors ré-exécuter l'instruction. S'il détecte un succès de cache, les instructions lecture-dépendante sont retirées de la fenêtre d'instruction, la copie de sauvegarde est devenue inutile et est donc jetée. ===La logique de sélection : âge ou position ?=== La logique de sélection est primordiale pour de bonnes performances. Il existe deux méthodes principales pour sélectionner l'instruction à exécuter. La première est la plus simple : elle se base sur lé numéro de l'entrée. En effet, une fenêtre d'instruction est avant tout une sorte de mémoire, un mix entre mémoire associative, mémoire RAM, et FIFO. Et chaque entrée a un numéro, une adresse mémoire. Nous parlerons de numéro dans ce qui suit, car ce sera plus simple, le terme d'adresse mémoire étant peut-être un peu exagéré dans le contexte des fenêtres d'instruction. Toujours est-il que la fenêtre d'instruction est adressable dans le sens où on peut lui envoyer le numéro de l'entrée voulue, et la fenêtre d’instruction renvoie le contenu de l'entrée sur son port de lecture. Et c'est ce que fait la logique de sélection : elle génère le numéro de l'entrée à lire. Le numéro est alors envoyé sur l'entrée d'adresse de la fenêtre d’instruction, et elle fournit la micro-opération associée sur son port de lecture, son '''port d'émission'''. La première méthode de sélection, donc. Elle est basée sur sur le numéro de l'entrée. Si plusieurs entrées sont éveillées, la logique de sélection prend celle avec le plus petit numéro. Elle porte le nom de '''sélection par position''', sous-entendu position dans la fenêtre d'instruction. Vous l'avez peut-être deviné, mais la logique de sélection est alors un encodeur à priorité. Le circuit de sélection ne se résume donc pas seulement à un encodeur à priorité, mais c'est le circuit central. L'avantage d'une telle méthode de sélection est qu'elle est simple à implémenter : un encodeur à priorité est un circuit connu, facile à implémenter. Mais on remarque un défaut : un encodeur est un circuit assez rapide, mais qui utilise beaucoup de transistors, beaucoup de portes logiques, surtout si on veut qu'il soit rapide. Ce qui explique que la logique de sélection ait son propre étage de pipeline rien que pour elle. La seconde méthode s'appelle la '''sélection par âge''', au nom assez transparent. L'idée est de privilégier l'émission de l'instruction la plus ancienne. Elle demande que la fenêtre d'instruction trie les micro-opérations par ordre d'insertion dans la fenêtre d'instruction, ce qui en fait une pseudo-FIFO. Le tri est partiel, car les instructions peuvent sortir de la fenêtre d’instruction à tout moment. Compacter la fenêtre d'instruction, à savoir regrouper toutes les entrées valides est une idée, mais elle est compliquée à implémenter. Aussi, elles préfèrent encoder des informations sur l'ordre d'émission dans chaque entrée. L'encodeur à priorité doit alors travailler non pas sur des nombres entiers liés à l'ordre d'insertion dans la pseudo-FIFO. Elle est encore plus gourmande en circuits que la méthode précédente. Les processeurs haute performance utilisent souvent des méthodes hybrides. Par exemple, les processeurs AMD de microarchitecture Bulldozer utilisaient une méthode intermédiaire. Ils utilisaient une fenêtre d'instruction couplée à un encodeur à priorité pour la sélection par position, mais complémentaient le tout avec une unité qui mémorisait l'instruction la plus ancienne dans la fenêtre d’instruction. Le mécanisme de sélection par âge était utilisé en priorité. Mais si l'instruction la plus ancienne n'était pas prête, le processeur basculait sur le mécanisme de sélection par position. ===La compaction des fenêtres d'instruction=== À chaque cycle, les instructions décodées sont ajoutées dans la fenêtre d'instruction, dans des entrées vides. Vu que les instructions quittent celle-ci dans le désordre, ces vides sont dispersés dans la fenêtre d'instruction, ce qui pose problème pour déterminer où placer les nouvelles instructions. La solution la plus triviale consiste à conserver une liste des vides, mise à jour à chaque insertion ou émission d'instruction. Une autre solution consiste à éliminer les vides en compactant la fenêtre d'instruction à chaque cycle d'horloge. Des circuits se chargent de détecter les vides et de regrouper les instructions en un unique bloc. Il faut signaler que certaines processeurs arrivent à se passer de cette étape de compactage, mais au prix de fenêtres d'instruction nettement plus complexes. Autre problème : quand il faut choisir quelle instruction émettre, il y a toujours plusieurs candidats. Si on choisit mal, des instructions restent en attente trop longtemps parce que d'autres instructions plus jeunes leur passent devant. Pour éviter cela, les instructions les plus vielles, les plus anciennes, sont prioritaires. Pour cela, on peut utiliser une FIFO un peu spéciale pour la fenêtre d'instruction. Si les ajouts d'instruction se font dans l'ordre, les instructions ne quittent pas forcément la fenêtre d'instruction dans l'ordre imposé par une FIFO : les instructions restent triées dans leur ordre d'ajout, même s'il y a des vides entre elles. Dans ces condition, il est préférable que le compactage conserve l'ordre FIFO des instructions. Dans ces conditions, l'instruction la plus ancienne est celle qui est située à l'adresse la plus faible : le circuit de sélection peut donc être fabriqué avec des encodeurs, et est relativement simple. ==Les fenêtres d'instruction basées sur une matrice de dépendances== L'implémentation la plus simple étend le fonctionnement d'un pipeline dynamique usuel. Rappelez-vous le chapitre sur les pipeline dynamiques. Nous avions vu que de tels pipelines émettaient une instruction par cycle, quitte à émettre des bulles de pipeline en cas de dépendance bloquante. Et il est possible d'améliorer leur unité d'émission pour qu'elle soit compatible avec l'exécution dans le désordre. ===Rappels sur le registre de réservation/disponibilité=== L'émission d'une instruction est gouvernée par un ''registre de réservation'' qui indique quels registres sont réservés par une instruction, et ceux qui sont libres. Un registre réservé est un registre qui sera écrit par une instruction en cours d'exécution, mais qui n'a pas encore écrit son résultat. Les instructions candidates doivent avoir leurs opérandes dans des registres libres. Sinon, c'est signe que leurs opérandes sont réservées en écriture, donc pas encore écrites, donc pas disponibles. Si une instruction candidate veut lire ce registre, c'est signe qu'il y a une dépendance RAW : elle veut lire un registre réservé, qui est destiné à être écrit par une instruction en vol. Si elle veut écrire, c'est signe qu'elle veut écrire dans un registre où une autre instruction veut écrire : c'est une dépendance WAW. Dans les deux cas, l'instruction n'est pas émise. Le registre de réservation encode les registres réservés comme suit : chaque bit est associé à un registre. Le bit numéro 0 est associé au registre numéro 0, le bit numéro 1 au registre numéro 1, etc. Là, En clair, les numéros de registres réservés sont encodés en représentation non pas binaire, mais en représentation ''one-hot'' (vue au premier chapitre). {|class="wikitable" |+ Registre de réservation |- ! Registre 7 !! Registre 6 !! Registre 5 !! Registre 4 !! Registre 3 !! Registre 2 !! Registre 1 !! Registre 0 |- | 0 || 0 || 1 || 0 || 0 || 1 || 0 || 0 |} Avant d'émettre une instruction, l'unité d'émission extrait les registres opérande/destination et les convertis dans la même représentation que le registre de réservation, à savoir en représentation ''one-hot''. Le circuit de traduction binaire vers ''one-hot'' est, pour rappel, un simple décodeur. Puis, on fait un OU logique entre les sorties des décodeurs. Le résultat est un masque qui indique quels registres sont lus par l'instruction, encodé en représentation ''one-hot''. Appelons-le le '''masque d'opérandes'''. Le masque est alors comparé au registre de réservation pour vérifier si l'instruction peut être émise. [[File:Unité d'émission simple, dans l'ordre.png|centre|vignette|upright=2|Unité d'émission simple, dans l'ordre]] Si l'émission est autorisée, le registres de réservation est là aussi mis à jour. Le registre de réservation est aussi mis à jour dès qu'une instruction enregistre son résultat dans les registres, ou alors dès qu'il est disponible pour le contournement. Le bit associé au registre repasse alors à 0 (ou à 1). Sans contournement, la mise à jour se fait alors à la toute fin de l'instruction, quand elle se termine, lors de la dernière étape d'enregistrement, à la fin de son pipeline. Avec, elle se fait quand l'instruction quitte l'unité de calcul. ===L'extension à l'exécution dans le désordre : l'éveil par matrice de bits=== La différence entre un pipeline dynamique et l'exécution dans le désordre est que l'on passe d'une instruction à émettre à plusieurs. Plusieurs instructions sont mises en attente dans une fenêtre d’instruction, et y attendent leur tour. L'idée est alors d'envoyer le registre de disponibilité à toutes les entrées, à toutes les instructions en attente. Ainsi, on sait quelles sont les instructions qui peuvent s'exécuter et celles qui ne le peuvent pas. L'implémentation est assez simple, elle ressemble beaucoup à l'implémentation d'un pipeline dynamique simple, si ce n'est que des circuits sont dupliqués. L'implémentation utilise des fenêtres d'instruction légèrement différentes de celles introduites plus haut. Elles n'utilisent notamment pas de bits de disponibilité, mais autre chose. Lorsqu'une instruction est ajoutée à la fenêtre d'instruction, le masque de disponibilité des opérandes est stocké dans la fenêtre d'instruction. A chaque cycle, le registre de disponibilité est envoyée à toutes les entrées, et est comparé avec tous les masques de disponibilité des opérandes. Si une comparaison renvoie un 1, alors l'instruction de l'entrée est une instruction candidate à l'émission. [[File:Unité d'émission dans le désordre basée sur un registre de disponibilité.png|centre|vignette|upright=2.5|Unité d'émission dans le désordre basée sur un registre de disponibilité]] L'ensemble est implémenté avec l'aide d'une '''matrice de bits''', où chaque ligne correspond à une entrée et chaque colonne à un registre. À chaque croisement entre une ligne et une colonne, on trouve un bit. Si le bit de la ligne n et de la colonne m est à 1, cela veut dire : l'instruction dans l'entrée n a besoin de lire le registre m. S’il est à 0, alors cela veut dire que l'instruction stockée dans la ligne n n'a pas besoin de la donnée dans le registre m. [[File:Planificateur à matrice de bits.jpg|centre|vignette|upright=2|Planificateur à matrice de bits.]] Lorsqu'une instruction réserve une entrée, elle initialise la ligne en fonction des registres qu'elle souhaite lire. Pour vérifier si une instruction a ses opérandes prêts, le processeur compare le registre de disponibilité à la ligne associée à l'instruction/entrée. A chaque intersection ligne-colonne, se trouve un comparateur de 1 bit, qui détecte si le registre est demandé et disponible. Les résultats de cette porte sont ensuite envoyés à une porte ET, qui fait le gros du travail. [[File:Logique de détection de la disponibilité d'une instruction.jpg|centre|vignette|upright=2|Logique de détection de la disponibilité d'une instruction.]] ==Les fenêtres d'instruction basées sur une mémoire associative== Les processeurs modernes utilisent une mémoire associative pour la fenêtre d'instruction. Les mémoires associatives ont été abordées il y a quelques chapitres, mais faisons quelques rappels. Les mémoires associatives servent à accélérer la recherche de données dans un ensemble. Or, une fenêtre d'instruction vérifie régulièrement si chaque entrée est prête. Il s'agit d'un processus de recherche d'une instruction qui respecte une condition bien précise dans la mémoire, ce qui fait que les mémoires associatives sont donc tout indiquées. Comme vous le savez, les signaux de commande d'une instruction sont propagés avec celle-ci dans le pipeline, le nom du registre de destination ne faisant pas exception. Le nom de registre est envoyé à la fenêtre d'instruction lors de l'écriture du résultat dans les registres. S'il y a correspondance, l'opérande est disponible et son bit de disponibilité est mis à 1. On peut adapter cette méthode pour tenir compte du contournement assez simplement. [[File:Détection des dépendances par propagation du registre de destination.png|centre|vignette|upright=2|Détection des dépendances par propagation du registre de destination.]] En conséquence, le circuit de détection des dépendances est constitué d'un grand nombre de comparateurs : un par champ « nom de registre » dans chaque entrée. La logique d'éveil/''wake up'' regroupe tous les comparateurs, la logique de sélection est un circuit situé en-dehors de la mémoire associative. Les entrées sont dans la mémoire associative elle-même. [[File:Gestion des bits de validité.png|centre|vignette|upright=2|Gestion des bits de validité.]] L'implémentation la plus simple est celle du schéma précédent, où on utilise une mémoire associative unique. Une version plus élaborée sépare la fenêtre d'instruction en deux parties : une mémoire qui mémorise les registres des opérandes, une autre mémoire pour le reste. La mémoire pour les registres opérandes est la mémoire associative proprement dite, c'est elle qui est associées aux comparateurs, à la logique de ''wake-up''/réveil, etc. Par contre, l'autre mémoire est une mémoire RAM simplifiée, qui mémorise les informations qui n'ont pas besoin des comparateurs. L'opcode de l'instruction est là-dedans, par exemple. ===Les optimisations de la consommation d'énergie : la désactivation des portions inutilisées=== Le problème avec des fenêtres d'instruction de ce type est leur forte consommation énergétique, ainsi que le grand nombre de portes logiques utilisées, qui deviennent prohibitif pour des fenêtres d'instruction un peu grosses. Pour résoudre ce problème, certains ont optimisé les comparateurs. D'autres ont tenté de profiter du fait que la majorité des bits dans les entrées sont composés de zéros. Bref, les optimisations purement matérielles sont légion. Une première solution est de désactiver les entrées qui sont inutilisées, vides, sans instruction. Pour cela, on fait précéder les comparateurs par un circuit qui les connecte ou déconnecte des lignes de bit. Le circuit est commandé par le bit ''empty'' qui indique si une entrée est vide ou non. L'avantage est que la consommation d'énergie de la fenêtre d'instruction devient alors proportionnelle au nombre d'entrées non-vides, et non au nombre d'entrées total. Du moins, en apparence, les entrées non-utilisées doivent quand même être alimentées pour fonctionner, mais l'activité de comparaison disparait dans les entrées vides. Il est possible d'étendre cette technique aux entrées dont les opérandes sont prêtes. Les gains sont généralement assez bons, avec une réduction de consommation variant entre 30 et 50%, avec une implémentation très simple et très économe en circuits. Une autre solution, assez simple à mettre en place, consiste à désactiver une partie de la fenêtre d'instruction sin elle est inutilisée. Pour cela, il faut segmenter la fenêtre d'instruction avec la technique du ''wire partitionning''. Pour rappel, une fenêtre d'instruction est une mémoire associative. Et comme toute mémoire associative, elle contient des fils, les lignes de bit, qui relient les entrées/sorties à toutes les cellules mémoire. Plus une ligne de bit est longue, plus elle consomme d'énergie et plus le temps de lecture/écriture est long. L'idée est de segmenter les lignes de bits en plaçant des répéteurs qui recopient la tension d'un segment au suivant. Les répéteurs sont des tampons trois-états, ce qui permet de déconnecter les portions inutilisées de la ligne de bit. Ce faisant, la fenêtre d'instruction est découpée en segments, qui peuvent être désactivés si besoin. Si il y a peu d'instructions chargées dans la fenêtre d'instruction, les portions inutilisées sont désactivées. La technique marche d'autan mieux si les instructions sont compactées au début de la fenêtre d'instruction. [[File:Wire partitionning.png|centre|vignette|upright=2|Wire partitionning]] Tout le problème est de savoir quelles portions désactiver. La technique est assez simple si la fenêtre d'instruction est compactée, à savoir si toutes les instructions sont régulièrement regroupées au début de la mémoire CAM. Mais même avec cette optimisation, la décision de désactiver une portion de la fenêtre d'instruction n'est pas à prendre à la légère. Il ne faut pas désactiver une portion contenant des instructions pouvant être émise sous peu. La décision dépend de paramètres variés : proportion d'entrée vides, quantité d'entrées récemment activées/désactivées récemment, présences d'entrées avec un ''match'' d'opérandes récent, etc. Il est important de préciser que les techniques en question fonctionnent aussi sur les autres types de fenêtre d'instruction, qui ne sont pas basées sur des mémoires associatives. Nous allons voir celles-ci dans la suite du chapitre, mais gardez à l'esprit que ces optimisations, à savoir désactiver les entrées vides/prêts et partitionner la fenêtre d'instruction, sont des optimisations générales qui marchent avec presque tout. ===L'ajout d'une FIFO pour les instructions déjà prêtes à l'émission=== D'autres techniques permettent de réduire aussi bien le cout en circuits que la consommation d'énergie de la fenêtre d'instruction. L'idée est d'utiliser une mémoire associative quand elle est réellement nécessaire, mais d'utiliser une fenêtre d'instruction "normale" dès que possible. La méthode la plus simple tient compte du fait que certaines instructions ont déjà toutes leurs opérandes de disponibles à l'émission, mais doivent quand même être mises en attente, parce que l'ALU adéquate est occupée, parce que des dépendances WAW/WAR sont encore là, ou pour tout autre raison. Dans ce cas, elles sont mises en attente non pas dans la fenêtre d'instruction, mais dans une mémoire FIFO toute simple. L'idée est qu'au lieu d'avoir une énorme mémoire associative pour la fenêtre d'instruction, on déplace quelques entrées dans une petite FIFO annexe. Le résultat est un gain en terme d'énergie et de circuits, au prix d'une perte de performance mineure. La perte de performance en question se manifeste si aucune instruction n'a ses opérandes de prêtes à l'émission : le programme n'utilise pas la FIFO et voit alors une fenêtre d'instruction plus petite. Une amélioration de cette technique tient compte du fait que certaines instructions sont dans un cas intermédiaire. Elles ont déjà une opérande de prête lors de l'émission, mais pas l'autre. Le nombre d'opérandes varie suivant l’instruction : certaines n'ont besoin que d'un seul opérande. De plus, il arrive qu'une opération tout juste décodée ait déjà un ou plusieurs de ses opérandes de prêts. Cette constatation permet d'éviter d'utiliser des comparateurs pour les opérandes déjà prêts. Par exemple, on peut parfaitement utiliser trois fenêtres d'instruction : * une pour les instructions dont tous les opérandes sont prêts, mais qui sont quand même mises en attente, sans comparateur ; * une pour les instructions dont un seul opérande manque, qui n'utilise qu'un comparateur par entrée ; * une pour les instructions dont deux opérandes manquent à l'appel, qui utilise deux comparateurs par entrée. C'est beaucoup plus économique que d'utiliser une seule grosse fenêtre d'instruction qui contiendrait autant d'entrées que les trois précédentes réunies, avec deux comparateurs par entrée. Certains sont même allés plus loin, et ont proposé de supprimer la fenêtre d'instruction avec deux opérandes par entrée. Les instructions dont deux opérandes sont inconnus au décodage sont stockées dans la fenêtre d'instruction pour instructions avec un comparateur par entrée. Un circuit de prédiction se charge alors de prédire l'opérande manquant, cette prédiction étant vérifiée plus loin dans le pipeline. Il serait cependant étonnant qu'une telle proposition ait donné lieu à la moindre implémentation réelle. ===Les optimisations de la consommation d'énergie avancées=== D'autres chercheurs ont conservé une fenêtre d'instruction unique, avec autant de comparateurs par entrée qu'il y a d'opérandes possibles par instruction. Simplement, le processus de détection des opérandes prêts est légèrement ralenti : on ne vérifie qu'un opérande par cycle. Pour vérifier les deux opérandes d'une entrée, on doit attendre deux cycles. Enfin, certains chercheurs ont proposé des fenêtres d'instruction segmentées. Les instructions circulent à chaque cycle d'un segment vers le suivant : en conséquence, certains segments conservent les instructions les plus anciennes, un autre les instructions les plus jeunes, etc. Seul le denier segment, celui qui contient les instructions les plus vielles, peut émettre une instruction : la détection des opérandes se fait seulement dans le dernier segment, qui contient les instructions les plus anciennes. On économise ainsi beaucoup de comparateurs. Certains chercheurs ont tenté de pipeliner l'étape de sélection des opérandes, ainsi que l'étage d'arbitrage. Mais en faisant cela, il faut plusieurs cycles pour détecter qu'une instruction a ses opérandes prêts, ce qui pose problème face à de nombreuses dépendances RAW. Pour éviter de trop perdre en performances, certains chercheurs ont décidé d'utiliser des techniques pour prédire quelles seront les instructions dont les opérandes seront bientôt prêts. Si détecter qu'une instruction est prête prend n cycles, le processeur devra tenter de prédire la future disponibilité des opérandes n cycles en avance pour obtenir des performances optimales. ===Remplacer la mémoire associative par une RAM=== Une autre optimisation possible est de remplacer la fenêtre d'instruction par une mémoire RAM, dont chaque mot mémoire correspondrait à une entrée. Une telle optimisation permet en théorie de se passer des comparateurs associés à chaque entrée, mais au prix de l'ajout de circuits annexes potentiellement couteux. La première de ces techniques, la '''recherche directe par étiquette''' (direct tag search) fut créée par Weiss et son collègue Smith. Ils cherchaient à améliorer l'algorithme de Tomasulo, un algorithme qu'on expliquera dans quelques chapitres. Rappelons que chaque instruction produit un résultat, qui devra être rapatrié dans une ou plusieurs entrées de la fenêtre d'instruction. L'optimisation de la recherche directe par étiquette fonctionne dans le cas où le résultat de l'instruction n'est utilisé que par une seule entrée, et pas plusieurs. Le principe est simple : chaque champ « opérande » d'une entrée est adressable via le nom de registre de cette opérande. Pour faire le lien entre entrée et nom de registre, la recherche directe par étiquette ajoute une table de correspondances matérielle, une mémoire RAM qui mémorise les adresses des champs « opérande » des entrées. Les adresses envoyées dans cette mémoire sont les noms de registres des résultats. Lors de l'émission, la table de correspondances est mise à jour. Les numéros des champs « opérande » réservés lors de l'émission sont mémorisés dans les mots mémoire qui correspondent aux deux registres sources. Toutefois, une petite vérification est faite lors de l'émission : si il y a déjà une correspondance dans la table pour un registre source, alors une autre instruction compte lire ce registre. Pour éviter d'écraser les données de l'instruction précédente dans la table de correspondances, l'émission de l'instruction est bloquée. [[File:Recherche directe par étiquette.png|centre|vignette|upright=2|Recherche directe par étiquette.]] ==Les fenêtres d’instruction avec préplanification== Avec la '''préplanification''' (''prescheduling''), la fenêtre d’instruction est composée de mémoires FIFO dans lesquelles les instructions sont triées dans l'ordre d'émission. Il n'y a pas de logique d’émission proprement dite, celle-ci se bornant à vérifier si l'instruction située au début de la FIFO peut s’exécuter. Par contre, le préplanificateur détecte les dépendances et en déduit où insérer les instructions dans le tampon d'émission, à l'endroit le plus adéquat. [[File:Préplanification.jpg|centre|vignette|upright=2|Préplanification.]] ===L'usage de FIFO multiples=== La technique de préplanification la plus simple utilise plusieurs FIFO. Quand une instruction a une dépendance avec une autre instruction, les deux sont placées dans la même FIFO. Pour cela, le préplanificateur détecte les chaines d'instructions dépendantes, et place les instructions dans la FIFO adéquate. A chaque cycle, l'unité d'émission lit une micro-opération dans chaque FIFO et vérifie si elle peut l'émettre. Si la micro-opération n'a pas ses opérandes disponibles, ou qu'une dépendance structurelle survient, alors la FIFO est bloquée. La micro-opération attend que la dépendance soit résolue, bloquant toutes les instructions précédentes. Mais les autres FIFO ne sont pas bloquées, laissant de la marge de manœuvre. [[File:Préplanification par FIFO multiples.png|centre|vignette|upright=1.5|Préplanification par FIFO multiples.]] ===La technique du tampon trié=== La technique du '''tampon trié''' trie les instructions selon le temps d'attente avant leur exécution. Les instructions qui sont censées s’exécuter bientôt sont insérées au tout début de la FIFO, tandis que les instructions qui s’exécuteront dans un long moment sont insérées vers la fin. Là encore, l'unité d'émission lit une micro-opération dans la FIFO, et détermine si elle peut être émise. Si une dépendance survient, l'émission est retardée, et la FIFO est bloquée. [[File:Préplanification par tampon trié.png|centre|vignette|upright=1.5|Préplanification par tampon trié.]] La technique a cependant quelques problèmes assez importants. Le premier problème est que la FIFO est bloquée lorsqu'une micro-opération ne peut être émise. Le second problème est que le temps avant exécution n'est pas toujours connu, notamment pour les instructions d'accès mémoire. Et cela se répercute sur les instructions dépendantes de celles-ci. Pour résoudre ce genre de problèmes, l'usage d'un pipeline à ''replay'' est possible, et est même l'une des meilleures solution possible, malgré ses défauts. L'idée est que les lecture sont pré-planifiées en supposant qu'elles font un succès de cache L1. Si la prédiction est fausse, la lecture est ré-exécutée plusieurs cycles plus tard, en supposant qu'elle fait un succès dans le cache L2, et ainsi de suite. Elle est alors ré-insérée dans la FIFO, elle est pré-planifiée une seconde fois. Il en est de même si une micro-opération ne peut pas être émise : il suffit de la réinsérer dans la FIFO au bon endroit, en attendant que ses dépendances soient résolus. Ainsi, l'instruction fautive ne bloque pas la fenêtre d’instruction, et retente sa chance autant de fois qu'il le faut. [[File:Préplanification par fenêtre d’instruction scorebarodée.png|centre|vignette|upright=1.5|Préplanification par fenêtre d’instruction scorebarodée.]] Une autre solution utilise deux fenêtres d’instruction : une FIFO gérée par la préplanification, et une vraie fenêtre d'instruction pour les instructions dont le temps d'attente ne peut pas être déterminé. Il est possible de mettre cette dernière avant la préplanification, afin de gérer les temps d'attente des instructions d'accès mémoire. Quand le temps d'attente d'une lecture devient connu, ses instructions dépendantes sont gérées avec préplanification. [[File:Préplanification avec fenêtre d’instruction.png|centre|vignette|upright=2.5|Préplanification avec fenêtre d’instruction.]] ===Les fenêtres d'instruction avec allocation temporelle statique=== L''''allocation temporelle statique''' correspond à une technique utilisée sur les processeurs Cuzco de l'entreprise Condor. La technique en question a été présenté en 2025, mais des idées similaires ont été présentées dans la littérature académique. Elle ressemble beaucoup aux techniques de pré-planification, avec cependant quelques différences. L'idée est simple : le processeur dispose de plusieurs fenêtres d'instruction, qui mettent en attente les micro-opérations. Lors de l'étape de renommage de registres, le processeur détermine dans combien de cycles d'horloge la micro-opération sera prête pour exécution. La micro-opération est alors mise en attente durant ce nombre de cycles, dans les fenêtres d'instruction, puis est émise une fois ce nombre de cycles écoulés. Ce faisant, les fenêtres d'instruction n'ont pas besoin de détecter la disponibilité des opérandes à chaque cycle, pour chaque micro-opération en attente. Le ''timing'' de l'émission des micro-opérations est décidé à l'avance. L'implémentation exacte n'est pas connue, mais plusieurs solutions sont imaginables. Par exemple, la fenêtre d'instruction peut simplement être composée de plusieurs mémoires de petite taille, chacune contenant les micro-opérations destinées à être exécutées dans N cycles, N étant différent pour chaque mémoire. Une autre solution, plus réaliste, utilise une fenêtre d'instruction dans laquelle la micro-opération est couplée à des champs pour les opérandes, et un champ compteur. Le champ compteur est initialisé avec le nombre de cycles à attendre, et est décrémenté à chaque cycle d'horloge. Quand il atteint zéro, la micro-opération est émise. Vous remarquerez que la méthode ne marche que si toutes les micro-opérations prennent un nombre fixe de cycles d'horloge. Et autant c'est le cas pour les micro-opérations arithmétiques ou logiques, autant les accès mémoire ne rentrent pas dans ce cadre. En théorie, on ne sait pas combien de temps prendra un accès mémoire. Et cette incertitude se répercute sur les instructions dépendantes d'un accès mémoire. Pour éviter cela, le processeur réutilise un pipeline à ''replay'' tel que vu dans le chapitre précédent. L'unité de renommage de registre suppose que tout accès mémoire fait un succès de cache L1, et décide des ''timings'' d'émission sous cette hypothèse. Si une lecture subit un défaut de cache, elle est ré-exécutée, de même que toutes les instructions dépendantes. Pour cela, le registre de destination de la lecture est marqué comme invalide, grâce à un bit spécifique attaché au registre. Toute instruction qui lit une opérande invalide est elle aussi ré-executée de zéro. Pour simplifier, l'unité d'émission ressemble à une unité d'émission dans l'ordre, avec un registre de disponibilité, qu'on aurait amélioré pour aller au-delà de la simple détection des dépendances d'instruction. Pour déterminer les ''timings'' d'émission, à savoir quand émettre une micro-opération, le processeur utilise une unité d'émission à deux étages. Le premier étage est appelé le ''register scoreboard'', le second étage est appelé la ''Time Ressource Matrix''. Les deux étages communiquent entre eux, comme on va le voir, et leurs noms donnent une idée de ce qu'ils font. Le premier étage gère les dépendances de registres, le second gère les dépendances structurelles. Le premier étage est un registre de disponibilité amélioré, qui gère les dépendances de registre. Cet étage sait quand tel registre sera écrit, et donc que l'opérande écrite dedans sera disponible à partir de tel cycle d'horloge. Il le sait car l'étage suivant l'aura prévenu, mais laissons cela de côté pour le moment. Quand une micro-opération rentre dans cet étage, il vérifie les dépendances avec les registres et les micro-opérations antérieures. Vu qu'il sait quand les registres seront disponibles, il peut déterminer quand l'instruction pourra s'exécuter. Par exemple, si une micro-opération lit les deux registres R7 et R15, qui sont disponibles respectivement dans 5 et 7 cycles, le premier étage sait que la micro-opération devra attendre 7 cycles. Mais tout cela ne suffit pas à déterminer quand émettre une micro-opération. En effet, il fait aussi gérer les dépendances structurelles, ce qui est le boulot du second étage. Le second étage utilise pour cela une ''Time Ressource Matrix'', qui mémorise l'occupation de diverses "ressources", pour les 256 cycles d'horloge à venir. Les ressources en question sont les ports de lecture/écriture du banc de registre, les ALUs utilisées, si la micro-opération utilise l'unité mémoire, etc. Le second étage prend en entrée une micro-opération, détermine quelles "ressources" elle utilise, puis regarde leur disponibilité. Elle détecte alors les dépendances structurelles et détermine alors quand peut s'exécuter la micro-opération. Elle peut retarder l'émission de quelques cycles, si une dépendance structurelle est détectée. Une fois sortie du second étage, on sait quand la micro-opération va être émise, à quel cycle précisément. Et vu que la durée de l'instruction est fixe, on sait quand cette micro-opération va se terminer, quand son résultat sera disponible. Cela permet de mettre à jour la ''Time Ressource Matrix'', pour préciser que le port d'écriture sera occupé à tel moment. De plus, cette information est transmise au premier étage, qui sait alors quand est enregistré le résultat dans le registre de destination. C'est comme cela que le premier étage sait quand un registre est disponible : le second étage le prévient, quand il émet une instruction ! La ''Time Ressource Matrix''mémorise l'occupation des "ressources" pour les 256 cycles d'horloge à venir. Cependant, elle ne vérifie pas les dépendances pour les 256 cycles suivants. Quand elle reçoit une micro-opération, elle teste les dépendances structurelles pour seulement les 8 prochains cycles maximum. Si la micro-opération ne peut pas être émise pendant ces 8 cycles, le pipeline est bloqué, un ''pipeline stall'' est émis. Pour être plus précis, vu que le processeur peut décoder 8 micro-opérations en même temps, cela permet de ne consulter que 64 cycles d'horloge sur les 256. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les premiers processeurs Intel | prevText=Les premiers processeurs Intel | next=Le renommage de registres | nextText=Le renommage de registres }} </noinclude> coabuc20419276vfeo96or0fxlv3eab 773593 773592 2026-09-29T18:32:23Z Mewtow 31375 /* Les fenêtres d'instruction décentralisées */ 773593 wikitext text/x-wiki Dans les chapitres précédents, nous avons parlé des techniques dites d''''émission dans l'ordre'''. L'idée est d’exécuter une nouvelle micro-opération à chaque cycle, dans des unités de calcul séparées. Les instructions sont émises consécutivement, mais les instructions s’exécutent en parallèle dans des unités de calcul séparées. Par contre, quand l'unité d'émission ne peut pas émettre une instruction, elle bloque tout le pipeline. Les instructions qui suivent sont elles aussi bloquées, elle doivent attendre leur tour, même si elles sont en capacité de s'exécuter. Les techniques d'exécution dans le désordre que nous allons voir dans ce chapitre corrigent ce point précis. Elles sont dites à '''émission dans le désordre'''. Elles se distinguent des précédentes sur un point précis : quand l'unité d'émission bloque l'émission d'une instruction, les instructions suivantes peuvent poursuivre. L'émission des instructions peut donc se faire dans le désordre, dans le sens où une instruction peut être émise alors qu'une instruction précédente ne l'est pas encore. L'avantage de l'émission dans le désordre est qu'une instruction s'exécute dès que ses opérandes sont disponibles. Par disponible, on veut dire présent soit dans le réseau de contournement, soit dans les registres. Le processeur détecte automatiquement quand les opérandes d'une instruction sont sont disponibles, et il l’exécute à ce moment là. Dès qu'une instruction a ses opérandes disponibles, elle est émise et exécutée. C'est là la seule contrainte : les dépendances WAR, WAW et autres sont gérées par un ROB ou toute autre technique d'exception précise, seules les dépendances RAW limitent l'exécution. Mais avant de poursuivre, quelques point niveaux terminologie : * L'émission dans le désordre est un terme parlant et assez précis. Malheureusement, la terminologie la plus utilisée par d''''exécution dans le désordre'''. Et nous utiliserons ce terme dans la suite du cours, histoire de ne pas trop dévier de la nomenclature habituelle. * Nous utiliserons parfois l'abréviation OOO pour parler d'exécution dans le désordre. L'abréviation est celle de ''Out Of Order Excution''. * Nous utiliserons aussi l'abréviation ''µop'' pour parler de micro-opération, ''µops'' au pluriels pour parler de plusieurs micro-opérations, ou des micro-opérations en général. L'exécution dans le désordre ne gére en effet que des µops, elle se situe après l'étape de décodage. Mais avant de poursuivre, précisons une chose importante : l'exécution dans le désordre traite les accès mémoire à part. La majorité des processeurs OOO assez anciens exécutent les accès mémoire dans l'ordre, seules les µops entières/flottantes/branchements sont exécutées dans le désordre. Les processeurs datant d'après les années 2010 sont capable d'exécuter les accès mémoire dans le désordre, mais l'implémentation en question est assez particulière. Un chapitre entier sera dédié à l'exécution dans le désordre des µops mémoire. Nous allons volontairement mettre de côté la gestion des accès mémoire dans ce chapitre. ==Les fenêtres d’instruction : généralités== [[File:File de micro-opération.png|vignette|upright=1|File de micro-opérations]] Pour décrire comment est implémentée l'émission dans le désordre, il faut commencer par parler des processeurs sans. Les processeurs sans exécution dans le désordre ont une unité d'émission qui bloque tout le pipeline dès qu'une µop ne peut pas être émise. Pour limiter l'impact de ce blocage, quelques rares processeurs incorporent une '''file de micro-opération''', une mémoire FIFO qui met en attente les µops. Vu que c'est une mémoire FIFO, les µops sont émises dans l'ordre, à savoir l'ordre d'ajout, dans l'ordre de décodage. Le schéma ci-dessous illustre une telle file d'attente couplée à un ''scoreboard''. Sur le principe, l'exécution dans le désordre améliore la file de µops sur un point : ce n'est plus une mémoire FIFO. Les µops sont insérées dans l'ordre, mais peuvent sortir dans le désordre (être émises dans le désordre). La file de µops devient alors une '''fenêtre d'instruction''', terme traduit directement de l'anglais ''instruction Window''. Terme assez trompeur, car elles mettent en attente des µops, pas des instructions. Elles peuvent émettre des µops dans le désordre, ce qui fait que si une µop bloque le pipeline, les µops suivantes peuvent être émises. Si je commence le paragraphe précédent par "sur le principe", c'est car certaines techniques d'OOO utilisent des files de µops normales. Il est par exemple possible d'utiliser une file de µops avec une fenêtre d'instruction, plusieurs files de µops, plusieurs fenêtres d'instructions avec une file de µops annexe, etc. Dasn les grandes lignes, il existe dans les grandes lignes 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! File de µops améliorée |- ! Une seule "file de µops" | ''Scoreboard'' | Fenêtre d'instruction centralisée |- ! Plusieurs "file de µops" | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | Fenêtre d'instruction décentralisée |} ===La fenêtre d'instruction centralisée=== L'implémentation la plus simple de l'OOO utilise une unique '''fenêtre d'instruction'''. Les instructions décodées sont accumulées dans la fenêtre d'instruction, où elles attendent que leurs opérandes soient disponibles. La fenêtre d'instruction sert donc de file d'attente. Mais elle contient aussi une unité d'émission, qui détecte quelles µops sont prêtes à être émises. L'unité d'émission et la fenêtre d'instruction sont fusionnées ensemble, elles forment un seul circuit. Mais nous allons dire qu'elles sont conceptuellement séparées pour le moment. A chaque cycle, l'unité d'émission consulte la fenêtre d'instruction pour voir quelles µops peuvent s'exécuter, lesquelles ont leur opérandes de disponibles. La fenêtre d'instruction doit spécialement être conçue pour, c'est une sorte de mémoire associative très complexe, comme on le verra dans ce qui suit. [[File:OOO Issue.png|centre|vignette|upright=2.5|Exécution dans le désordre avec une fenêtre d'instruction]] Une fois qu'une µop sort du décodeur d'instructions, elle est ajoutée en parallèle dans la fenêtre d'instruction et le ROB. La raison est que les µops quittent la fenêtre d'instruction dans le désordre, et qu'elles doivent être remises en ordre par la suite. Le ROB s'occupe de cette remise en ordre, mais il a besoin de savoir dans quel ordre les µops sont censées être, et cet ordre est celui du décodage. Aussi, pour remplir le ROB, la seule opportunité est en sortie de l'unité de décodage. Dans le cas où une instruction est décodée en plusieurs micro-opérations, elles sont toutes insérées en même temps dans la fenêtre d'instruction et le ROB, en tenant compte de leur ordre. [[File:Fenêtre d'instruction.png|centre|vignette|upright=2|Fenêtre d'instruction.]] Les micro-opérations mémoire sont à part des autres, pour diverses raisons. Une de ces raisons est que les dépendances de données sont classées en deux types : les dépendances de registre et les dépendances d'adresse. Et les deux sont fondamentalement différentes. Autant on peut détecter les dépendances de registre lors de l'émission, autant c'est plus compliqué avec les dépendances d'adresse. De plus, rappelons que si les lectures peuvent s'exécuter dans le désordre, les écritures doivent s'exécuter dans l'ordre, ou du moins en donner l'illusion. Pour cela, le processeur remet les écritures dans l'ordre avec une sorte de mini-ROB intégré à l'unité mémoire, appelée la file d'écriture. Elle complémente le ROB, qui lui ne gère que les écritures dans les registres, mais les deux collaborent. La file d'écriture envoie une écriture à la mémoire RAM quand le ROB lui dit que c'est bon, les instructions précédentes sont terminées ''dans l'ordre du programme''. Les processeurs modernes ajoutent des techniques d'exécution dans le désordre des accès mémoire, mais nous les verrons dans un chapitre dédié. Elles permettent d'utiliser une fenêtre d'instruction unique, qui mémorise aussi les µops mémoire. Si elles sont mises en place, l'unité mémoire n'a pas besoin de file de µops séparée. L'idée est que les dépendances de registre sont traitées par la fenêtre d'instruction, mais que l'unité mémoire gére les dépendances d'adresse. Les dépendances d'adresse sont gérées par des techniques de ''désambiguation mémoire'', qui auront droit à un chapitre dédié. [[File:Processeur avec exécution dans le désodre des accès mémoire.png|centre|vignette|upright=2|Processeur avec exécution dans le désodre des accès mémoire]] Les processeurs assez anciens n'autorisaient pas d'exécution dans le désordre des accès mémoire. Concrétement, les accs mémoire devaient se faire dans l'ordre, mais les autres µops pouvaient être exécutées dans le désordre. Il s'agit donc d'un ordre entre µops mémoire, pas entre µops mémoire et autres µops. Les µops entières et flottantes pouvaient être exécutées avant une µops mémoire qui est avant elle dans l'ordre du programme, ce n'est pas un problème. Pour garantir l'ordre desd µops mémoire, l'unité mémoire est précédée par une file de micro-opérations séparée, pour forcer l'exécution dans l'ordre des accès mémoire. De plus, les µops mémoire ne peuvent pas utiliser la fenêtre d'instruction. Dit autrement, la fenêtre d'instruction ne mémorise pas de µops mémoire. Après le décodage, les µops sont réparties soit dans la file de µops mémoire, soit dans la fenêtre d'instruction. Le décodeur classe les µops suivant que ce sont des µops mémoire ou non, et les envoient à la bonne destination. Dans ce chapitre, on supposera que c'est cette solution qui est utilisée. [[File:Processeur avec émission dans l'ordre des accès mémoire.png|centre|vignette|upright=2|Processeur avec émission dans l'ordre des accès mémoire]] La solution précédente revient à scinder la fenêtre d'instruction en deux : une file de µops pour les µops mémoire, une fenêtre d'instruction pour les autres µops. Et cette scission peut aller plus loin, à savoir qu'on peut scinder une fenêtre d'instruction encore et encore. Ce qui nous amène à la section suivante. ===Les fenêtres d'instruction décentralisées=== Nous venons de voir qu'il est possible de scinder la fenêtre d'instruction en plusieurs fenêtres d'instruction plus petites, plus "spécialisées" : une pour les µops mémoire, simplifiée en une file de µops classique, et une autre pour les autres instructions. Sachez qu'il est possible d'aller plus loin, par exemple en séparant la fenêtre d'instruction en une fenêtre spécialisée dans les µops flottantes et une autre pour les µops entières. Et ce n'est là qu'un exemple parmi de nombreuses autres possibilités. Pour faire la différence avec une fenêtre d'instruction unique, nous allons parler de fenêtre d'instruction centralisée s'il n'y en a qu'une, de '''fenêtre d'instruction décentralisée''' s'il y en a plusieurs. Il est possible d'associer chaque fenêtre d'instruction à un type précis de µops. Par exemple, avec une fenêtre d'instruction pour les µops de calcul entières, une autre pour les µops flottantes, une autre pour les µops mémoire. Il s'agit d'un choix simple et efficace, mais quelques processeurs font autrement, pour répondre à des contraintes très diverses. L'usage de fenêtres décentralisées simplifie la répartition des µops sur les unités de calcul. Par exemple, utiliser des fenêtres séparées pour les ALU et les FPU facilite la répartition des instructions de calcul sur les ALU. Une fenêtre centralisée demande de faire la différence entre instruction entière/flottante, puis de choisir sur quelle unité de calcul entière/flottante utiliser. Une fenêtre décentralisée fait les deux choix séparément : d'abord on envoie l'instruction dans la bonne fenêtre suivant si c'est une instruction flottante ou entière, et ensuite on gère la disponibilité des ALUs/opérandes. Et on peut adapter la même idée en séparant les unités d'accès mémoire des ALU entières, etc. Par contre, un défaut est que certaines fenêtres d'instruction peuvent être sous-utilisées. Par exemple, la station de réservation flottante est inutilisée si le programme n'exécute pas d'opérations flottantes. Ou encore, les fenêtres pour les accès mémoire peuvent être sous-utilisées, si le programme effectue peu d'accès mémoire relativement aux autres instructions. En fait, tout dépend de comment sont calibrées les fenêtres d'instruction et de la répartition des instructions dans le programme entre opérations entières, flottantes, mémoire. Par exemple, si un programma de deux fenêtres d'instructions identiques, une pour les calculs entiers et une autre pour les calculs flottants, elles ne seront utilisées à la perfection que si la moitié des instructions du programme fait des calculs flottants et l'autre des calculs entiers. Toute déviation par rapport à cette répartition idéale risque de laisser des entrées vides dans une fenêtre d’instruction. Un point important est que l'émission est découpée en deux étages avec des fenêtres d'instruction décentralisées. La première étape envoie l'instruction décodée vers la fenêtre d'instruction adéquate, la seconde gère l'émission proprement dit. La première est l'étage de ''dispatch'' qui envoie l'instruction dans la fenêtre d’instruction adéquate, selon que c'est une instruction flottante, entière, autre. La seconde est l'étage de ''scheduling'', qui gère la disponibilité des opérandes et des unités de calcul. En clair, on trie les instructions suivant leur type, suivant le type d'unité de calcul adéquate, puis on l'émet proprement dit. Faire ainsi a plusieurs avantages, avec cependant peu d'inconvénients. Lors de l'étape de ''dispatch'', l'instruction émise est ajoutée au tampon de réordonnancement, s'il existe. Sans cela, impossible de conserver l'ordre des instructions. Les instructions sont émises dans l'ordre au niveau de l'unité de ''dispatch'', pas au niveau de l'étage de ''scheduling''. Aussi, pour remplir le ROB, cela doit se faire au dernier moment où les instructions sont émises dans l'ordre, soit en sortie de l'unité de ''dispatch''. De plus, les micro-opérations mémoire sont traitées à part des autres, elles sont envoyées directement à l'unité mémoire. La gestion des calculs d'adresse est quelque peu complexe, mais ils peuvent être fait soit dans l'unité mémoire, soit dans les ALU entières, peu importe. Il y a aussi un système de contournement complexe entre ALU/FPU et unité mémoire, qui n'est pas représenté dans le schéma ci-dessous. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Il faut noter que quelques processeurs utilisent des méthodes intermédiaires entre les trois solutions précédentes. Par exemple, les processeurs AMD Zen utilisent une fenêtre d'instruction décentralisée un peu particulière. Les unités de calcul entières disposent d'une fenêtre d'instruction rien que pour elles, sur ce processeur. Les instructions flottantes sont quant à elles alimentées par une file de micro-opération, pas une fenêtre d'instruction ! La raison à ce choix est un compromis entre performance et cout en circuit. L'exécution dans le désordre est peu efficace sur les instructions flottantes, car les CPU n'ont que peu d'ALU flottantes séparées. Vu le cout en circuits d'une fenêtre d'instruction, les concepteurs du processeur ont préféré utiliser une file de micro-opération pour les opérations flottantes. ===L'usage de plusieurs files d'instruction=== Une dernière méthode d'OOO utilise plusieurs files de micro-opération. L'idée est qu'une fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement une file de micro-opération pour les opérations entières, une autre pour les opérations flottantes, une autre pour les accès mémoire. D'autres processeurs utilisent une file pour les accès mémoire et une autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. La présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que la technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si une dépendance bloque une FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans une autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer la disponibilité des registres. Quand un registre est lu ou écrit par une instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. La logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : une pour les instructions d'accès mémoire et une autre pour les autres instructions. Si jamais une instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de la lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'une est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est la file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. ===Avantages et inconvénients de chaque implémentation=== Un processeur contient soit une fenêtre d'instruction unique, soit plusieurs fenêtres d'instruction séparées. Typiquement, les fenêtres d’instruction séparées sont spécialisées, dans le sens où on a une fenêtre pour les instructions flottantes, une autre pour les instructions entières, une autre pour les accès mémoire, etc. Pour résumer, on a le choix entre une grosse fenêtre généraliste et plusieurs fenêtres spécialisées, sauf que la fenêtre centralisée est lente et complexe, contrairement aux fenêtres spécialisées. Les deux méthodes ont des inconvénients et des avantages différents. Dans les grandes lignes, l'avantage des fenêtres décentralisées est qu'elles sont plus petites qu'une grosse fenêtre d'instruction. Cela simplifie la gestion du contournement et de la répartition des instructions sur les unités de calcul, comme on le verra dans quelques paragraphes. Elles sont donc moins complexes et plus rapides. L'autre avantage, c'est qu'il est possible de démarrer l'exécution de plusieurs instructions simultanément : une instruction par fenêtre décentralisée, contre une par fenêtre d'instruction. Mais les fenêtres décentralisées sont souvent sous-utilisées, partiellement remplies, contrairement aux fenêtres d'instruction. Il arrive qu'une fenêtre d'instruction soit remplie, alors que les autres sont vides. Par exemple, prenons un processeur avec une fenêtre d'instruction reliée à la FPU, et une autre reliée aux autres ALUs. Si le processeur n'exécute que des opérations flottantes, la fenêtre reliée à la FPU sera pleine, alors que l'autre sera vide. L'exécution des instructions dans le désordre est alors limitée par la petite taille de la fenêtre, qui ne peut plus accepter de nouvelle instruction flottante. Avec une fenêtre unique, on n'aurait pas eu ce problème : on aurait eu une énorme fenêtre d'instruction remplie d'instruction flottante, au lieu d'une petite fenêtre spécialisée. Il est maintenant temps de voir en quoi sont faites les fenêtres d’instruction, qu'elles soient centralisées ou décentralisées. Nous allons aussi voir quelle est la logique d'émission associée. ==L'implémentation d'une fenêtre d'instruction : généralités== Une fenêtre d'instruction est une mémoire qui mémorise des micro-opérations. Elle est cependant plus complexe qu'une mémoire RAM ou qu'une FIFO et ressemble un petit peu à une mémoire cache. Elle dispose d'un port d'écriture et d'un port de lecture, au minimum. Le port d'écriture permet à l'unité de décodage d'insérer une micro-opération dedans, d'ajouter la micro-opération qui vient d'être décodée. Si une instruction machine est décodée en plusieurs micro-opération, deux possibilités. La première est de les insérer un par un, ce qui fait qu'on peut se contenter d'un seul port d'écriture. L'autre possibilité est de les ajouter en même temps, ce qui demande plusieurs ports d'écriture. Le port de lecture sert à émettre une instruction. On part du principe que la fenêtre d'instruction ne peut émettre qu'une seule instruction à la fois, car les processeurs que nous avons vu précédemment sont de ce type. Mais nous verrons dans quelques chapitre qu'il existe des processeurs dits superscalaires, qui sont capables d'émettre plusieurs instructions par cycle. Dans ce cas, la fenêtre d'instruction a un seul port de lecture. Un processeur superscalaire, quant à lui, doit avoir un port de lecture par unité de calcul, ce qui fait beaucoup plus. ===Les entrées d'une fenêtre d’instruction=== Les fenêtres d'instruction sont composées d''''entrées''', des mots mémoire qui stockent une instruction. Une instruction réserve une entrée après son décodage et la libère dès qu'elle est envoyée aux unités de calcul. Une entrée contient l'opcode (les signaux de commande à envoyer à l'ALU), le registre de destination du résultat, les registres de chaque opérande, et éventuellement des signaux de commande en plus. De plus, chaque opérande est couplée à un bit de disponibilité, qui indique si elle est disponible. Quand un opérande est écrit dans les registres, le bit de présence correspondant est mis à jour. Enfin, chaque entrée possède un bit ''empty'' qui indique si elle est vide, cette information étant utile pour réserver des entrées. [[File:Entrée d'une station de réservation - sans les tags.png|centre|vignette|upright=3|Entrée d'une fenêtre d'instruction]] Nous verrons dans quelques chapitres que certaines fenêtres d'instruction sont capables de mémoriser les opérandes des instructions. De telles fenêtres d'instruction seront appelées, dans ce cours, des '''stations de réservation'''. Les entrées des stations de réservation sont assez semblables à celle des fenêtres d'instruction, à un détail près : les opérandes de l'instruction sont enregistrées directement dans des champs séparés. Il y a deux champs, un par opérande, pour stocker l'opérande elle-même, lue depuis les registres ou obtenue via le réseau de contournement. Notons que les champs pour les opérandes viennent en plus des champs pour les noms de registres, encore que les deux peuvent être fusionnés si on veut optimiser le tout. [[File:Entrée d'une station de réservation.png|centre|vignette|upright=3|Entrée d'une station de réservation.]] Précisons que la terminologie n'est pas très fiable. Les termes "fenêtre d'instruction" et "station de réservation" ne regroupent pas du tout la même chose d'un papier de recherche à l'autre, d'un bouquin à l'autre, d'un chercheur à l'autre, d'un ingénieur à l'autre, d'un professeur à l'autre. Le terme initial vient pourtant de l'article original sur l'algorithme de Tomasulo, où il désignait une fenêtre d'instruction associée à une unité de calcul précise. Mais le terme a ensuite été réutilisé, ce qui fait que certains processeurs avec plusieurs unités de calcul sont décrit comme ayant une unique station de réservation. En bref : c'est le bazar ! Mais nous en reparlerons dans le chapitre sur le renommage de registres, car c'est la place idéale pour les aborder. Toujours est-il que j'ai fait le choix de confondre les concepts de fenêtre d'instruction et de station de réservation avec les concepts de '''lecture avant émission''' et de '''lecture après émission'''. La différence entre les deux est que les registres sont lus après émission avec une fenêtre d'instruction, avant avec des stations de réservation. Dans le cas "avant émission", les opérandes sont mémorisées dans la station de réservation. Et cette différence a une influence sur le pipeline du processeur, le banc de registres et tout ce qui s'en suit. Un désavantage de la lecture avant émission est qu'il faut stocker les opérandes après lecture, ici dans les stations de réservation. Mais un avantage est que le banc de registre a besoin de moins de ports de lecture, car une bonne partie des opérandes sont fournies par le système de contournement. Nous verrons cela dans le détail dans le chapitre sur les processeurs superscalaires. Il a été proposé de fusionner le tampon de ré-ordonnancement avec la fenêtre d'instruction dans une structure unique. La méthode a notamment été utilisée sur les processeurs d'architecture K6 d'AMD. Le tout donnait une structure appelée le '''DRIS''' (''deferred scheduling register renaming instruction shelf''). La différence avec une fenêtre d’instruction normale est que les entrées sont libérée non pas quand l'instruction est exécutée/émise, mais quand elle termine son exécution et quitte le ROB. La fenêtre d'instruction doit alors incorporer des bits pour savoir si telle entrée a émis sont instruction ou non. ===La logique d'éveil et de sélection=== Dans le cas qui va suivre, on suppose que le processeur ne peut émettre qu'une instruction à la fois. Chaque cycle, une instruction est sélectionnée et est envoyée dans le chemin de données, soit à une ALU, soit à une unité d'accès mémoire. La sélection d'une instruction est effectuée par l'unité d'émission, qui est aussi appelée le '''''scheduler'''''. Elle gère la disponibilité des opérandes et la disponibilité des unités de calcul adéquate. Le choix de l'instruction émise doit être le plus pertinent possible, pour des raisons de performances. Pour le premier point, l'unité d'émission détermine quelles instructions sont candidates pour l'émission. Les ''instructions candidates'' sont celles dont tous les opérandes sont prêts. Le processeur contient un circuit qui détecte les instructions candidates : la '''logique d’éveil''' (''wake-up logic''). Une fois que la logique d'éveil a fait son travail, une instruction est choisie pour s’exécuter en fonction de la disponibilité des unités de calcul adéquates. Ce rôle est dévolu à un circuit qu'on appelle la '''logique de sélection''', ou ''select logic''. [[File:Fonctionnement complet de la logique d’émission.jpg|centre|vignette|upright=1.5|Fonctionnement complet de la logique d’émission.]] La logique de sélection doit gérer le fait que les unités de calcul du processeur ne sont pas toutes identiques. Déjà, un processeur a généralement des unités séparées pour les instructions entières et flottantes, des unités spécialisées dans les accès mémoire, parfois des unités spécialisées pour les branchements. Une instruction doit être attribuée à la bonne unité de calcul, on ne doit pas envoyer une instruction entière dans une unité de calcul flottante. De plus, parmi les unités de calcul entières, toutes ne sont pas identiques. Par exemple, il est fréquent d'avoir plusieurs unités de calcul spécialisées dans les opérations simples (additions, soustractions, opérations logiques) avec une unité pour les multiplications/divisions séparées, parfois une unité spécialisée pour les décalages/rotations, etc. Là encore, allouer la bonne instruction à la bonne ALU est complexe. Plus les unités de calcul sont hétérogènes, plus la logique de sélection est compliquée. Les logiques d'éveil comme de sélection sont assez complexes. Comme on le verra plus bas, la logique de sélection la plus simple, qui gère une seule unité de calcul, est basée sur un encodeur à priorité couplé à d'autres circuits. Et pour gérer plusieurs ALUs, il faut mettre des encodeurs en cascade. Le résultat est que même en prenant une logique de sélection simple, elle sera assez lente et gourmande en circuits. Aussi, la logique de sélection met souvent un cycle d'horloge entier pour faire son travail, elle a son propre étage de pipeline attribué. La logique d'éveil est dans le même cas, ce qui fait qu'émettre une micro-opération demande deux cycles d'horloge. Le défaut est que cela rajoute des cycles d'horloges entre la fenêtre d'instruction et l'ALU, ce qui complique la gestion du pipeline. Ces cycles de retard sont à prendre en compte au moment d'émettre les instructions, les ''scheduler'' doit en tenir compte pour des performances optimales. Sans tenir compte de ces cycles de retard, les instructions arrivent en retard de quelques cycles à l'ALU, cycles de retard durant lesquels l'ALU n'a pas fait de calcul et a été sous-utilisée, sans compter que le système de contournement n'est pas utilisé au mieux. Et le problème est encore plus important sur les processeur avec des stations de réservation, qui utilisent la "lecture après émission" : cela rajoute un cycle d'horloge en plus, un temps de retard en plus. ===La logique d'éveil : l'émission anticipée=== La logique d'éveil doit tenir compte du fait qu'il y a plusieurs étages entre l'émission et l'exécution sur une unité de calcul. Par exemple, un processeur a souvent entre un et à cinq étages entre la file d'attente et les unités de calcul. Il faut lire les registres, gérer le contournement, et cela peut prendre quelques cycles d'horloge. Sur le Pentium 4, on trouve 6 étages entre la fenêtre d’instruction et l'entrée de l'ALU. Si les micro-opérations sont émises quand les opérandes sont disponibles, il y aura un délai de quelques cycles avant qu'elles atteignent l'ALU. Alors qu'idéalement, on souhaiterait que la micro-opération atteigne l'ALU dès que ses opérandes sont disponibles, pour profiter des techniques de contournement. Pour cela, la logique d'éveil émet les instructions quelques cycles en avance pour qu'elles arrivent au bon moment. Il s'agit d'une technique d''''émission anticipée''', dont nous avions parlé dans le chapitre sur le contournement. : Il faut noter que le problème se pose plus avec des fenêtres d'instruction qu'avec des stations de réservation. Les premières ont un étage en plus entre émission et ALU, vu qu'il faut lire des registres après l'émission. L'émission anticipée demande d'émettre un signal d'éveil en avance de quelques cycles, pile au bon moment. Par exemples, si on a deux étages entre l'ALU et l'unité d'émission, le signal de réveil sera généré deux cycles avant que le résultat soit effectivement calculé. L'implémentation varie, mais deux solutions sont possibles. La première est de générer le signal d'éveil dans l'ALU, ce qui n'a de sens que pour les opérations comme les multiplications ou les divisions, qui prennent plusieurs cycles. Une autre technique génère le signal de réveil dans une structure centralisée, spécialisée dans la génération des signaux d'éveil. L'unité de composée d'un registre à décalage par registre. Imaginons qu'une instruction est émise, que cette instruction mette N cycles à s'exécuter, et qu'elle écrive dans un registre de destination. L'unité sélectionne alors le registre à décalage associé au registre de destination, et met le bit numéro N à 1. Le registre décalé d'un cran à chaque cycle. Quand le bit sortant est un 1, alors le signal de validité pour l'opérande est généré. L'émission anticipée marche bien si l'instruction a une durée fixe, connue à l'avance. Et autant c'est le cas pour les instructions arithmétiques et logiques, autant ce n'est pas le cas pour les accès mémoire. Les accès mémoire ont une latence variable : quelques cycles pour un succès de cache, plusieurs dizaines de cycles pour un défaut de cache L1, pas loin de la centaine pour un défaut de cache L2, etc. Et cela pose des problèmes pour l'émission anticipée. L'émission en avance pour les accès mémoire est purement spéculative : le processeur émet des instructions en supposant que la lecture entrainera un succès de cache, quitte à annuler l'instruction en cas de défaut de cache. Mais faire ainsi demande non seulement d'annuler les instructions émises en avance, mais aussi de ne pas retirer les instructions émises en avance de la fenêtre d'instruction. Elles sont émises, mais une copie de sauvegarde est conservée dans la fenêtre d'instruction. Si le processeur détecte un défaut de cache, il peut alors ré-exécuter l'instruction. S'il détecte un succès de cache, les instructions lecture-dépendante sont retirées de la fenêtre d'instruction, la copie de sauvegarde est devenue inutile et est donc jetée. ===La logique de sélection : âge ou position ?=== La logique de sélection est primordiale pour de bonnes performances. Il existe deux méthodes principales pour sélectionner l'instruction à exécuter. La première est la plus simple : elle se base sur lé numéro de l'entrée. En effet, une fenêtre d'instruction est avant tout une sorte de mémoire, un mix entre mémoire associative, mémoire RAM, et FIFO. Et chaque entrée a un numéro, une adresse mémoire. Nous parlerons de numéro dans ce qui suit, car ce sera plus simple, le terme d'adresse mémoire étant peut-être un peu exagéré dans le contexte des fenêtres d'instruction. Toujours est-il que la fenêtre d'instruction est adressable dans le sens où on peut lui envoyer le numéro de l'entrée voulue, et la fenêtre d’instruction renvoie le contenu de l'entrée sur son port de lecture. Et c'est ce que fait la logique de sélection : elle génère le numéro de l'entrée à lire. Le numéro est alors envoyé sur l'entrée d'adresse de la fenêtre d’instruction, et elle fournit la micro-opération associée sur son port de lecture, son '''port d'émission'''. La première méthode de sélection, donc. Elle est basée sur sur le numéro de l'entrée. Si plusieurs entrées sont éveillées, la logique de sélection prend celle avec le plus petit numéro. Elle porte le nom de '''sélection par position''', sous-entendu position dans la fenêtre d'instruction. Vous l'avez peut-être deviné, mais la logique de sélection est alors un encodeur à priorité. Le circuit de sélection ne se résume donc pas seulement à un encodeur à priorité, mais c'est le circuit central. L'avantage d'une telle méthode de sélection est qu'elle est simple à implémenter : un encodeur à priorité est un circuit connu, facile à implémenter. Mais on remarque un défaut : un encodeur est un circuit assez rapide, mais qui utilise beaucoup de transistors, beaucoup de portes logiques, surtout si on veut qu'il soit rapide. Ce qui explique que la logique de sélection ait son propre étage de pipeline rien que pour elle. La seconde méthode s'appelle la '''sélection par âge''', au nom assez transparent. L'idée est de privilégier l'émission de l'instruction la plus ancienne. Elle demande que la fenêtre d'instruction trie les micro-opérations par ordre d'insertion dans la fenêtre d'instruction, ce qui en fait une pseudo-FIFO. Le tri est partiel, car les instructions peuvent sortir de la fenêtre d’instruction à tout moment. Compacter la fenêtre d'instruction, à savoir regrouper toutes les entrées valides est une idée, mais elle est compliquée à implémenter. Aussi, elles préfèrent encoder des informations sur l'ordre d'émission dans chaque entrée. L'encodeur à priorité doit alors travailler non pas sur des nombres entiers liés à l'ordre d'insertion dans la pseudo-FIFO. Elle est encore plus gourmande en circuits que la méthode précédente. Les processeurs haute performance utilisent souvent des méthodes hybrides. Par exemple, les processeurs AMD de microarchitecture Bulldozer utilisaient une méthode intermédiaire. Ils utilisaient une fenêtre d'instruction couplée à un encodeur à priorité pour la sélection par position, mais complémentaient le tout avec une unité qui mémorisait l'instruction la plus ancienne dans la fenêtre d’instruction. Le mécanisme de sélection par âge était utilisé en priorité. Mais si l'instruction la plus ancienne n'était pas prête, le processeur basculait sur le mécanisme de sélection par position. ===La compaction des fenêtres d'instruction=== À chaque cycle, les instructions décodées sont ajoutées dans la fenêtre d'instruction, dans des entrées vides. Vu que les instructions quittent celle-ci dans le désordre, ces vides sont dispersés dans la fenêtre d'instruction, ce qui pose problème pour déterminer où placer les nouvelles instructions. La solution la plus triviale consiste à conserver une liste des vides, mise à jour à chaque insertion ou émission d'instruction. Une autre solution consiste à éliminer les vides en compactant la fenêtre d'instruction à chaque cycle d'horloge. Des circuits se chargent de détecter les vides et de regrouper les instructions en un unique bloc. Il faut signaler que certaines processeurs arrivent à se passer de cette étape de compactage, mais au prix de fenêtres d'instruction nettement plus complexes. Autre problème : quand il faut choisir quelle instruction émettre, il y a toujours plusieurs candidats. Si on choisit mal, des instructions restent en attente trop longtemps parce que d'autres instructions plus jeunes leur passent devant. Pour éviter cela, les instructions les plus vielles, les plus anciennes, sont prioritaires. Pour cela, on peut utiliser une FIFO un peu spéciale pour la fenêtre d'instruction. Si les ajouts d'instruction se font dans l'ordre, les instructions ne quittent pas forcément la fenêtre d'instruction dans l'ordre imposé par une FIFO : les instructions restent triées dans leur ordre d'ajout, même s'il y a des vides entre elles. Dans ces condition, il est préférable que le compactage conserve l'ordre FIFO des instructions. Dans ces conditions, l'instruction la plus ancienne est celle qui est située à l'adresse la plus faible : le circuit de sélection peut donc être fabriqué avec des encodeurs, et est relativement simple. ==Les fenêtres d'instruction basées sur une matrice de dépendances== L'implémentation la plus simple étend le fonctionnement d'un pipeline dynamique usuel. Rappelez-vous le chapitre sur les pipeline dynamiques. Nous avions vu que de tels pipelines émettaient une instruction par cycle, quitte à émettre des bulles de pipeline en cas de dépendance bloquante. Et il est possible d'améliorer leur unité d'émission pour qu'elle soit compatible avec l'exécution dans le désordre. ===Rappels sur le registre de réservation/disponibilité=== L'émission d'une instruction est gouvernée par un ''registre de réservation'' qui indique quels registres sont réservés par une instruction, et ceux qui sont libres. Un registre réservé est un registre qui sera écrit par une instruction en cours d'exécution, mais qui n'a pas encore écrit son résultat. Les instructions candidates doivent avoir leurs opérandes dans des registres libres. Sinon, c'est signe que leurs opérandes sont réservées en écriture, donc pas encore écrites, donc pas disponibles. Si une instruction candidate veut lire ce registre, c'est signe qu'il y a une dépendance RAW : elle veut lire un registre réservé, qui est destiné à être écrit par une instruction en vol. Si elle veut écrire, c'est signe qu'elle veut écrire dans un registre où une autre instruction veut écrire : c'est une dépendance WAW. Dans les deux cas, l'instruction n'est pas émise. Le registre de réservation encode les registres réservés comme suit : chaque bit est associé à un registre. Le bit numéro 0 est associé au registre numéro 0, le bit numéro 1 au registre numéro 1, etc. Là, En clair, les numéros de registres réservés sont encodés en représentation non pas binaire, mais en représentation ''one-hot'' (vue au premier chapitre). {|class="wikitable" |+ Registre de réservation |- ! Registre 7 !! Registre 6 !! Registre 5 !! Registre 4 !! Registre 3 !! Registre 2 !! Registre 1 !! Registre 0 |- | 0 || 0 || 1 || 0 || 0 || 1 || 0 || 0 |} Avant d'émettre une instruction, l'unité d'émission extrait les registres opérande/destination et les convertis dans la même représentation que le registre de réservation, à savoir en représentation ''one-hot''. Le circuit de traduction binaire vers ''one-hot'' est, pour rappel, un simple décodeur. Puis, on fait un OU logique entre les sorties des décodeurs. Le résultat est un masque qui indique quels registres sont lus par l'instruction, encodé en représentation ''one-hot''. Appelons-le le '''masque d'opérandes'''. Le masque est alors comparé au registre de réservation pour vérifier si l'instruction peut être émise. [[File:Unité d'émission simple, dans l'ordre.png|centre|vignette|upright=2|Unité d'émission simple, dans l'ordre]] Si l'émission est autorisée, le registres de réservation est là aussi mis à jour. Le registre de réservation est aussi mis à jour dès qu'une instruction enregistre son résultat dans les registres, ou alors dès qu'il est disponible pour le contournement. Le bit associé au registre repasse alors à 0 (ou à 1). Sans contournement, la mise à jour se fait alors à la toute fin de l'instruction, quand elle se termine, lors de la dernière étape d'enregistrement, à la fin de son pipeline. Avec, elle se fait quand l'instruction quitte l'unité de calcul. ===L'extension à l'exécution dans le désordre : l'éveil par matrice de bits=== La différence entre un pipeline dynamique et l'exécution dans le désordre est que l'on passe d'une instruction à émettre à plusieurs. Plusieurs instructions sont mises en attente dans une fenêtre d’instruction, et y attendent leur tour. L'idée est alors d'envoyer le registre de disponibilité à toutes les entrées, à toutes les instructions en attente. Ainsi, on sait quelles sont les instructions qui peuvent s'exécuter et celles qui ne le peuvent pas. L'implémentation est assez simple, elle ressemble beaucoup à l'implémentation d'un pipeline dynamique simple, si ce n'est que des circuits sont dupliqués. L'implémentation utilise des fenêtres d'instruction légèrement différentes de celles introduites plus haut. Elles n'utilisent notamment pas de bits de disponibilité, mais autre chose. Lorsqu'une instruction est ajoutée à la fenêtre d'instruction, le masque de disponibilité des opérandes est stocké dans la fenêtre d'instruction. A chaque cycle, le registre de disponibilité est envoyée à toutes les entrées, et est comparé avec tous les masques de disponibilité des opérandes. Si une comparaison renvoie un 1, alors l'instruction de l'entrée est une instruction candidate à l'émission. [[File:Unité d'émission dans le désordre basée sur un registre de disponibilité.png|centre|vignette|upright=2.5|Unité d'émission dans le désordre basée sur un registre de disponibilité]] L'ensemble est implémenté avec l'aide d'une '''matrice de bits''', où chaque ligne correspond à une entrée et chaque colonne à un registre. À chaque croisement entre une ligne et une colonne, on trouve un bit. Si le bit de la ligne n et de la colonne m est à 1, cela veut dire : l'instruction dans l'entrée n a besoin de lire le registre m. S’il est à 0, alors cela veut dire que l'instruction stockée dans la ligne n n'a pas besoin de la donnée dans le registre m. [[File:Planificateur à matrice de bits.jpg|centre|vignette|upright=2|Planificateur à matrice de bits.]] Lorsqu'une instruction réserve une entrée, elle initialise la ligne en fonction des registres qu'elle souhaite lire. Pour vérifier si une instruction a ses opérandes prêts, le processeur compare le registre de disponibilité à la ligne associée à l'instruction/entrée. A chaque intersection ligne-colonne, se trouve un comparateur de 1 bit, qui détecte si le registre est demandé et disponible. Les résultats de cette porte sont ensuite envoyés à une porte ET, qui fait le gros du travail. [[File:Logique de détection de la disponibilité d'une instruction.jpg|centre|vignette|upright=2|Logique de détection de la disponibilité d'une instruction.]] ==Les fenêtres d'instruction basées sur une mémoire associative== Les processeurs modernes utilisent une mémoire associative pour la fenêtre d'instruction. Les mémoires associatives ont été abordées il y a quelques chapitres, mais faisons quelques rappels. Les mémoires associatives servent à accélérer la recherche de données dans un ensemble. Or, une fenêtre d'instruction vérifie régulièrement si chaque entrée est prête. Il s'agit d'un processus de recherche d'une instruction qui respecte une condition bien précise dans la mémoire, ce qui fait que les mémoires associatives sont donc tout indiquées. Comme vous le savez, les signaux de commande d'une instruction sont propagés avec celle-ci dans le pipeline, le nom du registre de destination ne faisant pas exception. Le nom de registre est envoyé à la fenêtre d'instruction lors de l'écriture du résultat dans les registres. S'il y a correspondance, l'opérande est disponible et son bit de disponibilité est mis à 1. On peut adapter cette méthode pour tenir compte du contournement assez simplement. [[File:Détection des dépendances par propagation du registre de destination.png|centre|vignette|upright=2|Détection des dépendances par propagation du registre de destination.]] En conséquence, le circuit de détection des dépendances est constitué d'un grand nombre de comparateurs : un par champ « nom de registre » dans chaque entrée. La logique d'éveil/''wake up'' regroupe tous les comparateurs, la logique de sélection est un circuit situé en-dehors de la mémoire associative. Les entrées sont dans la mémoire associative elle-même. [[File:Gestion des bits de validité.png|centre|vignette|upright=2|Gestion des bits de validité.]] L'implémentation la plus simple est celle du schéma précédent, où on utilise une mémoire associative unique. Une version plus élaborée sépare la fenêtre d'instruction en deux parties : une mémoire qui mémorise les registres des opérandes, une autre mémoire pour le reste. La mémoire pour les registres opérandes est la mémoire associative proprement dite, c'est elle qui est associées aux comparateurs, à la logique de ''wake-up''/réveil, etc. Par contre, l'autre mémoire est une mémoire RAM simplifiée, qui mémorise les informations qui n'ont pas besoin des comparateurs. L'opcode de l'instruction est là-dedans, par exemple. ===Les optimisations de la consommation d'énergie : la désactivation des portions inutilisées=== Le problème avec des fenêtres d'instruction de ce type est leur forte consommation énergétique, ainsi que le grand nombre de portes logiques utilisées, qui deviennent prohibitif pour des fenêtres d'instruction un peu grosses. Pour résoudre ce problème, certains ont optimisé les comparateurs. D'autres ont tenté de profiter du fait que la majorité des bits dans les entrées sont composés de zéros. Bref, les optimisations purement matérielles sont légion. Une première solution est de désactiver les entrées qui sont inutilisées, vides, sans instruction. Pour cela, on fait précéder les comparateurs par un circuit qui les connecte ou déconnecte des lignes de bit. Le circuit est commandé par le bit ''empty'' qui indique si une entrée est vide ou non. L'avantage est que la consommation d'énergie de la fenêtre d'instruction devient alors proportionnelle au nombre d'entrées non-vides, et non au nombre d'entrées total. Du moins, en apparence, les entrées non-utilisées doivent quand même être alimentées pour fonctionner, mais l'activité de comparaison disparait dans les entrées vides. Il est possible d'étendre cette technique aux entrées dont les opérandes sont prêtes. Les gains sont généralement assez bons, avec une réduction de consommation variant entre 30 et 50%, avec une implémentation très simple et très économe en circuits. Une autre solution, assez simple à mettre en place, consiste à désactiver une partie de la fenêtre d'instruction sin elle est inutilisée. Pour cela, il faut segmenter la fenêtre d'instruction avec la technique du ''wire partitionning''. Pour rappel, une fenêtre d'instruction est une mémoire associative. Et comme toute mémoire associative, elle contient des fils, les lignes de bit, qui relient les entrées/sorties à toutes les cellules mémoire. Plus une ligne de bit est longue, plus elle consomme d'énergie et plus le temps de lecture/écriture est long. L'idée est de segmenter les lignes de bits en plaçant des répéteurs qui recopient la tension d'un segment au suivant. Les répéteurs sont des tampons trois-états, ce qui permet de déconnecter les portions inutilisées de la ligne de bit. Ce faisant, la fenêtre d'instruction est découpée en segments, qui peuvent être désactivés si besoin. Si il y a peu d'instructions chargées dans la fenêtre d'instruction, les portions inutilisées sont désactivées. La technique marche d'autan mieux si les instructions sont compactées au début de la fenêtre d'instruction. [[File:Wire partitionning.png|centre|vignette|upright=2|Wire partitionning]] Tout le problème est de savoir quelles portions désactiver. La technique est assez simple si la fenêtre d'instruction est compactée, à savoir si toutes les instructions sont régulièrement regroupées au début de la mémoire CAM. Mais même avec cette optimisation, la décision de désactiver une portion de la fenêtre d'instruction n'est pas à prendre à la légère. Il ne faut pas désactiver une portion contenant des instructions pouvant être émise sous peu. La décision dépend de paramètres variés : proportion d'entrée vides, quantité d'entrées récemment activées/désactivées récemment, présences d'entrées avec un ''match'' d'opérandes récent, etc. Il est important de préciser que les techniques en question fonctionnent aussi sur les autres types de fenêtre d'instruction, qui ne sont pas basées sur des mémoires associatives. Nous allons voir celles-ci dans la suite du chapitre, mais gardez à l'esprit que ces optimisations, à savoir désactiver les entrées vides/prêts et partitionner la fenêtre d'instruction, sont des optimisations générales qui marchent avec presque tout. ===L'ajout d'une FIFO pour les instructions déjà prêtes à l'émission=== D'autres techniques permettent de réduire aussi bien le cout en circuits que la consommation d'énergie de la fenêtre d'instruction. L'idée est d'utiliser une mémoire associative quand elle est réellement nécessaire, mais d'utiliser une fenêtre d'instruction "normale" dès que possible. La méthode la plus simple tient compte du fait que certaines instructions ont déjà toutes leurs opérandes de disponibles à l'émission, mais doivent quand même être mises en attente, parce que l'ALU adéquate est occupée, parce que des dépendances WAW/WAR sont encore là, ou pour tout autre raison. Dans ce cas, elles sont mises en attente non pas dans la fenêtre d'instruction, mais dans une mémoire FIFO toute simple. L'idée est qu'au lieu d'avoir une énorme mémoire associative pour la fenêtre d'instruction, on déplace quelques entrées dans une petite FIFO annexe. Le résultat est un gain en terme d'énergie et de circuits, au prix d'une perte de performance mineure. La perte de performance en question se manifeste si aucune instruction n'a ses opérandes de prêtes à l'émission : le programme n'utilise pas la FIFO et voit alors une fenêtre d'instruction plus petite. Une amélioration de cette technique tient compte du fait que certaines instructions sont dans un cas intermédiaire. Elles ont déjà une opérande de prête lors de l'émission, mais pas l'autre. Le nombre d'opérandes varie suivant l’instruction : certaines n'ont besoin que d'un seul opérande. De plus, il arrive qu'une opération tout juste décodée ait déjà un ou plusieurs de ses opérandes de prêts. Cette constatation permet d'éviter d'utiliser des comparateurs pour les opérandes déjà prêts. Par exemple, on peut parfaitement utiliser trois fenêtres d'instruction : * une pour les instructions dont tous les opérandes sont prêts, mais qui sont quand même mises en attente, sans comparateur ; * une pour les instructions dont un seul opérande manque, qui n'utilise qu'un comparateur par entrée ; * une pour les instructions dont deux opérandes manquent à l'appel, qui utilise deux comparateurs par entrée. C'est beaucoup plus économique que d'utiliser une seule grosse fenêtre d'instruction qui contiendrait autant d'entrées que les trois précédentes réunies, avec deux comparateurs par entrée. Certains sont même allés plus loin, et ont proposé de supprimer la fenêtre d'instruction avec deux opérandes par entrée. Les instructions dont deux opérandes sont inconnus au décodage sont stockées dans la fenêtre d'instruction pour instructions avec un comparateur par entrée. Un circuit de prédiction se charge alors de prédire l'opérande manquant, cette prédiction étant vérifiée plus loin dans le pipeline. Il serait cependant étonnant qu'une telle proposition ait donné lieu à la moindre implémentation réelle. ===Les optimisations de la consommation d'énergie avancées=== D'autres chercheurs ont conservé une fenêtre d'instruction unique, avec autant de comparateurs par entrée qu'il y a d'opérandes possibles par instruction. Simplement, le processus de détection des opérandes prêts est légèrement ralenti : on ne vérifie qu'un opérande par cycle. Pour vérifier les deux opérandes d'une entrée, on doit attendre deux cycles. Enfin, certains chercheurs ont proposé des fenêtres d'instruction segmentées. Les instructions circulent à chaque cycle d'un segment vers le suivant : en conséquence, certains segments conservent les instructions les plus anciennes, un autre les instructions les plus jeunes, etc. Seul le denier segment, celui qui contient les instructions les plus vielles, peut émettre une instruction : la détection des opérandes se fait seulement dans le dernier segment, qui contient les instructions les plus anciennes. On économise ainsi beaucoup de comparateurs. Certains chercheurs ont tenté de pipeliner l'étape de sélection des opérandes, ainsi que l'étage d'arbitrage. Mais en faisant cela, il faut plusieurs cycles pour détecter qu'une instruction a ses opérandes prêts, ce qui pose problème face à de nombreuses dépendances RAW. Pour éviter de trop perdre en performances, certains chercheurs ont décidé d'utiliser des techniques pour prédire quelles seront les instructions dont les opérandes seront bientôt prêts. Si détecter qu'une instruction est prête prend n cycles, le processeur devra tenter de prédire la future disponibilité des opérandes n cycles en avance pour obtenir des performances optimales. ===Remplacer la mémoire associative par une RAM=== Une autre optimisation possible est de remplacer la fenêtre d'instruction par une mémoire RAM, dont chaque mot mémoire correspondrait à une entrée. Une telle optimisation permet en théorie de se passer des comparateurs associés à chaque entrée, mais au prix de l'ajout de circuits annexes potentiellement couteux. La première de ces techniques, la '''recherche directe par étiquette''' (direct tag search) fut créée par Weiss et son collègue Smith. Ils cherchaient à améliorer l'algorithme de Tomasulo, un algorithme qu'on expliquera dans quelques chapitres. Rappelons que chaque instruction produit un résultat, qui devra être rapatrié dans une ou plusieurs entrées de la fenêtre d'instruction. L'optimisation de la recherche directe par étiquette fonctionne dans le cas où le résultat de l'instruction n'est utilisé que par une seule entrée, et pas plusieurs. Le principe est simple : chaque champ « opérande » d'une entrée est adressable via le nom de registre de cette opérande. Pour faire le lien entre entrée et nom de registre, la recherche directe par étiquette ajoute une table de correspondances matérielle, une mémoire RAM qui mémorise les adresses des champs « opérande » des entrées. Les adresses envoyées dans cette mémoire sont les noms de registres des résultats. Lors de l'émission, la table de correspondances est mise à jour. Les numéros des champs « opérande » réservés lors de l'émission sont mémorisés dans les mots mémoire qui correspondent aux deux registres sources. Toutefois, une petite vérification est faite lors de l'émission : si il y a déjà une correspondance dans la table pour un registre source, alors une autre instruction compte lire ce registre. Pour éviter d'écraser les données de l'instruction précédente dans la table de correspondances, l'émission de l'instruction est bloquée. [[File:Recherche directe par étiquette.png|centre|vignette|upright=2|Recherche directe par étiquette.]] ==Les fenêtres d’instruction avec préplanification== Avec la '''préplanification''' (''prescheduling''), la fenêtre d’instruction est composée de mémoires FIFO dans lesquelles les instructions sont triées dans l'ordre d'émission. Il n'y a pas de logique d’émission proprement dite, celle-ci se bornant à vérifier si l'instruction située au début de la FIFO peut s’exécuter. Par contre, le préplanificateur détecte les dépendances et en déduit où insérer les instructions dans le tampon d'émission, à l'endroit le plus adéquat. [[File:Préplanification.jpg|centre|vignette|upright=2|Préplanification.]] ===L'usage de FIFO multiples=== La technique de préplanification la plus simple utilise plusieurs FIFO. Quand une instruction a une dépendance avec une autre instruction, les deux sont placées dans la même FIFO. Pour cela, le préplanificateur détecte les chaines d'instructions dépendantes, et place les instructions dans la FIFO adéquate. A chaque cycle, l'unité d'émission lit une micro-opération dans chaque FIFO et vérifie si elle peut l'émettre. Si la micro-opération n'a pas ses opérandes disponibles, ou qu'une dépendance structurelle survient, alors la FIFO est bloquée. La micro-opération attend que la dépendance soit résolue, bloquant toutes les instructions précédentes. Mais les autres FIFO ne sont pas bloquées, laissant de la marge de manœuvre. [[File:Préplanification par FIFO multiples.png|centre|vignette|upright=1.5|Préplanification par FIFO multiples.]] ===La technique du tampon trié=== La technique du '''tampon trié''' trie les instructions selon le temps d'attente avant leur exécution. Les instructions qui sont censées s’exécuter bientôt sont insérées au tout début de la FIFO, tandis que les instructions qui s’exécuteront dans un long moment sont insérées vers la fin. Là encore, l'unité d'émission lit une micro-opération dans la FIFO, et détermine si elle peut être émise. Si une dépendance survient, l'émission est retardée, et la FIFO est bloquée. [[File:Préplanification par tampon trié.png|centre|vignette|upright=1.5|Préplanification par tampon trié.]] La technique a cependant quelques problèmes assez importants. Le premier problème est que la FIFO est bloquée lorsqu'une micro-opération ne peut être émise. Le second problème est que le temps avant exécution n'est pas toujours connu, notamment pour les instructions d'accès mémoire. Et cela se répercute sur les instructions dépendantes de celles-ci. Pour résoudre ce genre de problèmes, l'usage d'un pipeline à ''replay'' est possible, et est même l'une des meilleures solution possible, malgré ses défauts. L'idée est que les lecture sont pré-planifiées en supposant qu'elles font un succès de cache L1. Si la prédiction est fausse, la lecture est ré-exécutée plusieurs cycles plus tard, en supposant qu'elle fait un succès dans le cache L2, et ainsi de suite. Elle est alors ré-insérée dans la FIFO, elle est pré-planifiée une seconde fois. Il en est de même si une micro-opération ne peut pas être émise : il suffit de la réinsérer dans la FIFO au bon endroit, en attendant que ses dépendances soient résolus. Ainsi, l'instruction fautive ne bloque pas la fenêtre d’instruction, et retente sa chance autant de fois qu'il le faut. [[File:Préplanification par fenêtre d’instruction scorebarodée.png|centre|vignette|upright=1.5|Préplanification par fenêtre d’instruction scorebarodée.]] Une autre solution utilise deux fenêtres d’instruction : une FIFO gérée par la préplanification, et une vraie fenêtre d'instruction pour les instructions dont le temps d'attente ne peut pas être déterminé. Il est possible de mettre cette dernière avant la préplanification, afin de gérer les temps d'attente des instructions d'accès mémoire. Quand le temps d'attente d'une lecture devient connu, ses instructions dépendantes sont gérées avec préplanification. [[File:Préplanification avec fenêtre d’instruction.png|centre|vignette|upright=2.5|Préplanification avec fenêtre d’instruction.]] ===Les fenêtres d'instruction avec allocation temporelle statique=== L''''allocation temporelle statique''' correspond à une technique utilisée sur les processeurs Cuzco de l'entreprise Condor. La technique en question a été présenté en 2025, mais des idées similaires ont été présentées dans la littérature académique. Elle ressemble beaucoup aux techniques de pré-planification, avec cependant quelques différences. L'idée est simple : le processeur dispose de plusieurs fenêtres d'instruction, qui mettent en attente les micro-opérations. Lors de l'étape de renommage de registres, le processeur détermine dans combien de cycles d'horloge la micro-opération sera prête pour exécution. La micro-opération est alors mise en attente durant ce nombre de cycles, dans les fenêtres d'instruction, puis est émise une fois ce nombre de cycles écoulés. Ce faisant, les fenêtres d'instruction n'ont pas besoin de détecter la disponibilité des opérandes à chaque cycle, pour chaque micro-opération en attente. Le ''timing'' de l'émission des micro-opérations est décidé à l'avance. L'implémentation exacte n'est pas connue, mais plusieurs solutions sont imaginables. Par exemple, la fenêtre d'instruction peut simplement être composée de plusieurs mémoires de petite taille, chacune contenant les micro-opérations destinées à être exécutées dans N cycles, N étant différent pour chaque mémoire. Une autre solution, plus réaliste, utilise une fenêtre d'instruction dans laquelle la micro-opération est couplée à des champs pour les opérandes, et un champ compteur. Le champ compteur est initialisé avec le nombre de cycles à attendre, et est décrémenté à chaque cycle d'horloge. Quand il atteint zéro, la micro-opération est émise. Vous remarquerez que la méthode ne marche que si toutes les micro-opérations prennent un nombre fixe de cycles d'horloge. Et autant c'est le cas pour les micro-opérations arithmétiques ou logiques, autant les accès mémoire ne rentrent pas dans ce cadre. En théorie, on ne sait pas combien de temps prendra un accès mémoire. Et cette incertitude se répercute sur les instructions dépendantes d'un accès mémoire. Pour éviter cela, le processeur réutilise un pipeline à ''replay'' tel que vu dans le chapitre précédent. L'unité de renommage de registre suppose que tout accès mémoire fait un succès de cache L1, et décide des ''timings'' d'émission sous cette hypothèse. Si une lecture subit un défaut de cache, elle est ré-exécutée, de même que toutes les instructions dépendantes. Pour cela, le registre de destination de la lecture est marqué comme invalide, grâce à un bit spécifique attaché au registre. Toute instruction qui lit une opérande invalide est elle aussi ré-executée de zéro. Pour simplifier, l'unité d'émission ressemble à une unité d'émission dans l'ordre, avec un registre de disponibilité, qu'on aurait amélioré pour aller au-delà de la simple détection des dépendances d'instruction. Pour déterminer les ''timings'' d'émission, à savoir quand émettre une micro-opération, le processeur utilise une unité d'émission à deux étages. Le premier étage est appelé le ''register scoreboard'', le second étage est appelé la ''Time Ressource Matrix''. Les deux étages communiquent entre eux, comme on va le voir, et leurs noms donnent une idée de ce qu'ils font. Le premier étage gère les dépendances de registres, le second gère les dépendances structurelles. Le premier étage est un registre de disponibilité amélioré, qui gère les dépendances de registre. Cet étage sait quand tel registre sera écrit, et donc que l'opérande écrite dedans sera disponible à partir de tel cycle d'horloge. Il le sait car l'étage suivant l'aura prévenu, mais laissons cela de côté pour le moment. Quand une micro-opération rentre dans cet étage, il vérifie les dépendances avec les registres et les micro-opérations antérieures. Vu qu'il sait quand les registres seront disponibles, il peut déterminer quand l'instruction pourra s'exécuter. Par exemple, si une micro-opération lit les deux registres R7 et R15, qui sont disponibles respectivement dans 5 et 7 cycles, le premier étage sait que la micro-opération devra attendre 7 cycles. Mais tout cela ne suffit pas à déterminer quand émettre une micro-opération. En effet, il fait aussi gérer les dépendances structurelles, ce qui est le boulot du second étage. Le second étage utilise pour cela une ''Time Ressource Matrix'', qui mémorise l'occupation de diverses "ressources", pour les 256 cycles d'horloge à venir. Les ressources en question sont les ports de lecture/écriture du banc de registre, les ALUs utilisées, si la micro-opération utilise l'unité mémoire, etc. Le second étage prend en entrée une micro-opération, détermine quelles "ressources" elle utilise, puis regarde leur disponibilité. Elle détecte alors les dépendances structurelles et détermine alors quand peut s'exécuter la micro-opération. Elle peut retarder l'émission de quelques cycles, si une dépendance structurelle est détectée. Une fois sortie du second étage, on sait quand la micro-opération va être émise, à quel cycle précisément. Et vu que la durée de l'instruction est fixe, on sait quand cette micro-opération va se terminer, quand son résultat sera disponible. Cela permet de mettre à jour la ''Time Ressource Matrix'', pour préciser que le port d'écriture sera occupé à tel moment. De plus, cette information est transmise au premier étage, qui sait alors quand est enregistré le résultat dans le registre de destination. C'est comme cela que le premier étage sait quand un registre est disponible : le second étage le prévient, quand il émet une instruction ! La ''Time Ressource Matrix''mémorise l'occupation des "ressources" pour les 256 cycles d'horloge à venir. Cependant, elle ne vérifie pas les dépendances pour les 256 cycles suivants. Quand elle reçoit une micro-opération, elle teste les dépendances structurelles pour seulement les 8 prochains cycles maximum. Si la micro-opération ne peut pas être émise pendant ces 8 cycles, le pipeline est bloqué, un ''pipeline stall'' est émis. Pour être plus précis, vu que le processeur peut décoder 8 micro-opérations en même temps, cela permet de ne consulter que 64 cycles d'horloge sur les 256. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les premiers processeurs Intel | prevText=Les premiers processeurs Intel | next=Le renommage de registres | nextText=Le renommage de registres }} </noinclude> 2xol1htkbg14plg3a98i2784ynx1hpr 773594 773593 2026-09-29T18:50:24Z Mewtow 31375 /* Les fenêtres d'instruction décentralisées */ 773594 wikitext text/x-wiki Dans les chapitres précédents, nous avons parlé des techniques dites d''''émission dans l'ordre'''. L'idée est d’exécuter une nouvelle micro-opération à chaque cycle, dans des unités de calcul séparées. Les instructions sont émises consécutivement, mais les instructions s’exécutent en parallèle dans des unités de calcul séparées. Par contre, quand l'unité d'émission ne peut pas émettre une instruction, elle bloque tout le pipeline. Les instructions qui suivent sont elles aussi bloquées, elle doivent attendre leur tour, même si elles sont en capacité de s'exécuter. Les techniques d'exécution dans le désordre que nous allons voir dans ce chapitre corrigent ce point précis. Elles sont dites à '''émission dans le désordre'''. Elles se distinguent des précédentes sur un point précis : quand l'unité d'émission bloque l'émission d'une instruction, les instructions suivantes peuvent poursuivre. L'émission des instructions peut donc se faire dans le désordre, dans le sens où une instruction peut être émise alors qu'une instruction précédente ne l'est pas encore. L'avantage de l'émission dans le désordre est qu'une instruction s'exécute dès que ses opérandes sont disponibles. Par disponible, on veut dire présent soit dans le réseau de contournement, soit dans les registres. Le processeur détecte automatiquement quand les opérandes d'une instruction sont sont disponibles, et il l’exécute à ce moment là. Dès qu'une instruction a ses opérandes disponibles, elle est émise et exécutée. C'est là la seule contrainte : les dépendances WAR, WAW et autres sont gérées par un ROB ou toute autre technique d'exception précise, seules les dépendances RAW limitent l'exécution. Mais avant de poursuivre, quelques point niveaux terminologie : * L'émission dans le désordre est un terme parlant et assez précis. Malheureusement, la terminologie la plus utilisée par d''''exécution dans le désordre'''. Et nous utiliserons ce terme dans la suite du cours, histoire de ne pas trop dévier de la nomenclature habituelle. * Nous utiliserons parfois l'abréviation OOO pour parler d'exécution dans le désordre. L'abréviation est celle de ''Out Of Order Excution''. * Nous utiliserons aussi l'abréviation ''µop'' pour parler de micro-opération, ''µops'' au pluriels pour parler de plusieurs micro-opérations, ou des micro-opérations en général. L'exécution dans le désordre ne gére en effet que des µops, elle se situe après l'étape de décodage. Mais avant de poursuivre, précisons une chose importante : l'exécution dans le désordre traite les accès mémoire à part. La majorité des processeurs OOO assez anciens exécutent les accès mémoire dans l'ordre, seules les µops entières/flottantes/branchements sont exécutées dans le désordre. Les processeurs datant d'après les années 2010 sont capable d'exécuter les accès mémoire dans le désordre, mais l'implémentation en question est assez particulière. Un chapitre entier sera dédié à l'exécution dans le désordre des µops mémoire. Nous allons volontairement mettre de côté la gestion des accès mémoire dans ce chapitre. ==Les fenêtres d’instruction : généralités== [[File:File de micro-opération.png|vignette|upright=1|File de micro-opérations]] Pour décrire comment est implémentée l'émission dans le désordre, il faut commencer par parler des processeurs sans. Les processeurs sans exécution dans le désordre ont une unité d'émission qui bloque tout le pipeline dès qu'une µop ne peut pas être émise. Pour limiter l'impact de ce blocage, quelques rares processeurs incorporent une '''file de micro-opération''', une mémoire FIFO qui met en attente les µops. Vu que c'est une mémoire FIFO, les µops sont émises dans l'ordre, à savoir l'ordre d'ajout, dans l'ordre de décodage. Le schéma ci-dessous illustre une telle file d'attente couplée à un ''scoreboard''. Sur le principe, l'exécution dans le désordre améliore la file de µops sur un point : ce n'est plus une mémoire FIFO. Les µops sont insérées dans l'ordre, mais peuvent sortir dans le désordre (être émises dans le désordre). La file de µops devient alors une '''fenêtre d'instruction''', terme traduit directement de l'anglais ''instruction Window''. Terme assez trompeur, car elles mettent en attente des µops, pas des instructions. Elles peuvent émettre des µops dans le désordre, ce qui fait que si une µop bloque le pipeline, les µops suivantes peuvent être émises. Si je commence le paragraphe précédent par "sur le principe", c'est car certaines techniques d'OOO utilisent des files de µops normales. Il est par exemple possible d'utiliser une file de µops avec une fenêtre d'instruction, plusieurs files de µops, plusieurs fenêtres d'instructions avec une file de µops annexe, etc. Dasn les grandes lignes, il existe dans les grandes lignes 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! File de µops améliorée |- ! Une seule "file de µops" | ''Scoreboard'' | Fenêtre d'instruction centralisée |- ! Plusieurs "file de µops" | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | Fenêtre d'instruction décentralisée |} ===La fenêtre d'instruction centralisée=== L'implémentation la plus simple de l'OOO utilise une unique '''fenêtre d'instruction'''. Les instructions décodées sont accumulées dans la fenêtre d'instruction, où elles attendent que leurs opérandes soient disponibles. La fenêtre d'instruction sert donc de file d'attente. Mais elle contient aussi une unité d'émission, qui détecte quelles µops sont prêtes à être émises. L'unité d'émission et la fenêtre d'instruction sont fusionnées ensemble, elles forment un seul circuit. Mais nous allons dire qu'elles sont conceptuellement séparées pour le moment. A chaque cycle, l'unité d'émission consulte la fenêtre d'instruction pour voir quelles µops peuvent s'exécuter, lesquelles ont leur opérandes de disponibles. La fenêtre d'instruction doit spécialement être conçue pour, c'est une sorte de mémoire associative très complexe, comme on le verra dans ce qui suit. [[File:OOO Issue.png|centre|vignette|upright=2.5|Exécution dans le désordre avec une fenêtre d'instruction]] Une fois qu'une µop sort du décodeur d'instructions, elle est ajoutée en parallèle dans la fenêtre d'instruction et le ROB. La raison est que les µops quittent la fenêtre d'instruction dans le désordre, et qu'elles doivent être remises en ordre par la suite. Le ROB s'occupe de cette remise en ordre, mais il a besoin de savoir dans quel ordre les µops sont censées être, et cet ordre est celui du décodage. Aussi, pour remplir le ROB, la seule opportunité est en sortie de l'unité de décodage. Dans le cas où une instruction est décodée en plusieurs micro-opérations, elles sont toutes insérées en même temps dans la fenêtre d'instruction et le ROB, en tenant compte de leur ordre. [[File:Fenêtre d'instruction.png|centre|vignette|upright=2|Fenêtre d'instruction.]] Les micro-opérations mémoire sont à part des autres, pour diverses raisons. Une de ces raisons est que les dépendances de données sont classées en deux types : les dépendances de registre et les dépendances d'adresse. Et les deux sont fondamentalement différentes. Autant on peut détecter les dépendances de registre lors de l'émission, autant c'est plus compliqué avec les dépendances d'adresse. De plus, rappelons que si les lectures peuvent s'exécuter dans le désordre, les écritures doivent s'exécuter dans l'ordre, ou du moins en donner l'illusion. Pour cela, le processeur remet les écritures dans l'ordre avec une sorte de mini-ROB intégré à l'unité mémoire, appelée la file d'écriture. Elle complémente le ROB, qui lui ne gère que les écritures dans les registres, mais les deux collaborent. La file d'écriture envoie une écriture à la mémoire RAM quand le ROB lui dit que c'est bon, les instructions précédentes sont terminées ''dans l'ordre du programme''. Les processeurs modernes ajoutent des techniques d'exécution dans le désordre des accès mémoire, mais nous les verrons dans un chapitre dédié. Elles permettent d'utiliser une fenêtre d'instruction unique, qui mémorise aussi les µops mémoire. Si elles sont mises en place, l'unité mémoire n'a pas besoin de file de µops séparée. L'idée est que les dépendances de registre sont traitées par la fenêtre d'instruction, mais que l'unité mémoire gére les dépendances d'adresse. Les dépendances d'adresse sont gérées par des techniques de ''désambiguation mémoire'', qui auront droit à un chapitre dédié. [[File:Processeur avec exécution dans le désodre des accès mémoire.png|centre|vignette|upright=2|Processeur avec exécution dans le désodre des accès mémoire]] Les processeurs assez anciens n'autorisaient pas d'exécution dans le désordre des accès mémoire. Concrétement, les accs mémoire devaient se faire dans l'ordre, mais les autres µops pouvaient être exécutées dans le désordre. Il s'agit donc d'un ordre entre µops mémoire, pas entre µops mémoire et autres µops. Les µops entières et flottantes pouvaient être exécutées avant une µops mémoire qui est avant elle dans l'ordre du programme, ce n'est pas un problème. Pour garantir l'ordre desd µops mémoire, l'unité mémoire est précédée par une file de micro-opérations séparée, pour forcer l'exécution dans l'ordre des accès mémoire. De plus, les µops mémoire ne peuvent pas utiliser la fenêtre d'instruction. Dit autrement, la fenêtre d'instruction ne mémorise pas de µops mémoire. Après le décodage, les µops sont réparties soit dans la file de µops mémoire, soit dans la fenêtre d'instruction. Le décodeur classe les µops suivant que ce sont des µops mémoire ou non, et les envoient à la bonne destination. Dans ce chapitre, on supposera que c'est cette solution qui est utilisée. [[File:Processeur avec émission dans l'ordre des accès mémoire.png|centre|vignette|upright=2|Processeur avec émission dans l'ordre des accès mémoire]] La solution précédente revient à scinder la fenêtre d'instruction en deux : une file de µops pour les µops mémoire, une fenêtre d'instruction pour les autres µops. Et cette scission peut aller plus loin, à savoir qu'on peut scinder une fenêtre d'instruction encore et encore. Ce qui nous amène à la section suivante. ===Les fenêtres d'instruction décentralisées=== Nous venons de voir qu'il est possible de scinder la fenêtre d'instruction en plusieurs fenêtres d'instruction plus petites, plus "spécialisées" : une pour les µops mémoire, simplifiée en une file de µops classique, et une autre pour les autres instructions. Sachez qu'il est possible d'aller plus loin, par exemple en séparant la fenêtre d'instruction en une fenêtre spécialisée dans les µops flottantes et une autre pour les µops entières. Et ce n'est là qu'un exemple parmi de nombreuses autres possibilités. Pour faire la différence avec une fenêtre d'instruction unique, nous allons parler de fenêtre d'instruction centralisée s'il n'y en a qu'une, de '''fenêtre d'instruction décentralisée''' s'il y en a plusieurs. Il est possible d'associer chaque fenêtre d'instruction à un type précis de µops. Par exemple, avec une fenêtre d'instruction pour les µops de calcul entières, une autre pour les µops flottantes, une autre pour les µops mémoire. Il s'agit d'un choix simple et efficace, mais quelques processeurs font autrement, pour répondre à des contraintes très diverses. Un autre exemple : les processeurs Intel de microarchitecture Skylake utilisent une fenêtre d'instruction pour les opérations entières/flottantes, et une fenêtre d'instruction séparée pour les µops mémoire. Il s'agit bien d'une fenêtre d’instruction, le processeur utilise l'exécution dans le désordre des accès mémoire. Un avantage est que les deux fenêtres d'instructions sont plus spécialisées, ce qui entraine des économies de circuit. Les opérations entières/flottantes ont besoin de deux registres pour les opérandes et d'un autre résultat, alors que les µops mémoire n'ont besoin que de deux registres maximum. En utilisant une fenêtre d'instruction unique, chaque entrée doit mémoriser l'opcode et trois registres, dont un est inutilisé pour les µops mémoire et les branchements. En utilisant des fenêtres d’instructions séparées, celle pour les µops entières/flottantes a trois registres par entrée, contre seulement deux registres par entrée pour celle des µops mémoire. Il est aussi possible d'utiliser une fenêtre d'instruction pour les opérations flottantes et une autre pour les autres µops (µops entières et parfois mémoire avec). L'avantage est que cela simplifie grandement le processeur. Les flottants sont gérés à part des entiers. Ils ont leurs propres registres, des FPU séparées des ALU entières, bref : la séparation est complète. Utiliser une fenêtre d'instruction séparée va dans ce sens. Un cas extrême est celui où chaque ALU a sa propre fenêtre d'instruction. Nous parlerons alors de '''fenêtres d'instruction totalement décentralisées'''. Un exemple historique est celui de la fpu de l'IBM 360 modèle 90. Elle disposait d'un additionneur flottant, d'un multiplieur flottant, et d'une unité mémoire pour les lectures/écritures flottantes. Les trois unités avaient leur propre fenêtre d'instruction. Les processeurs AMD utilisent beaucoup cette technique, contrairement à Intel qui préfère utiliser des fenêtres centralisées sur les anciens processeurs, deux ou trois fenêtres sur les processeurs récents (2020 et plus). L'usage de fenêtres décentralisées simplifie la répartition des µops sur les unités de calcul. Par exemple, utiliser des fenêtres séparées pour les ALU et les FPU facilite la répartition des instructions de calcul sur les ALU. Une fenêtre centralisée demande de faire la différence entre instruction entière/flottante, puis de choisir sur quelle unité de calcul entière/flottante utiliser. Une fenêtre décentralisée fait les deux choix séparément : d'abord on envoie l'instruction dans la bonne fenêtre suivant si c'est une instruction flottante ou entière, et ensuite on gère la disponibilité des ALUs/opérandes. Et on peut adapter la même idée en séparant les unités d'accès mémoire des ALU entières, etc. Par contre, un défaut est que certaines fenêtres d'instruction peuvent être sous-utilisées. Par exemple, la station de réservation flottante est inutilisée si le programme n'exécute pas d'opérations flottantes. Ou encore, les fenêtres pour les accès mémoire peuvent être sous-utilisées, si le programme effectue peu d'accès mémoire relativement aux autres instructions. En fait, tout dépend de comment sont calibrées les fenêtres d'instruction et de la répartition des instructions dans le programme entre opérations entières, flottantes, mémoire. Par exemple, si un programma de deux fenêtres d'instructions identiques, une pour les calculs entiers et une autre pour les calculs flottants, elles ne seront utilisées à la perfection que si la moitié des instructions du programme fait des calculs flottants et l'autre des calculs entiers. Toute déviation par rapport à cette répartition idéale risque de laisser des entrées vides dans une fenêtre d’instruction. Un point important est que l'émission est découpée en deux étages avec des fenêtres d'instruction décentralisées. La première étape envoie l'instruction décodée vers la fenêtre d'instruction adéquate, la seconde gère l'émission proprement dit. La première est l'étage de ''dispatch'' qui envoie l'instruction dans la fenêtre d’instruction adéquate, selon que c'est une instruction flottante, entière, autre. La seconde est l'étage de ''scheduling'', qui gère la disponibilité des opérandes et des unités de calcul. En clair, on trie les instructions suivant leur type, suivant le type d'unité de calcul adéquate, puis on l'émet proprement dit. Faire ainsi a plusieurs avantages, avec cependant peu d'inconvénients. Lors de l'étape de ''dispatch'', l'instruction émise est ajoutée au tampon de réordonnancement, s'il existe. Sans cela, impossible de conserver l'ordre des instructions. Les instructions sont émises dans l'ordre au niveau de l'unité de ''dispatch'', pas au niveau de l'étage de ''scheduling''. Aussi, pour remplir le ROB, cela doit se faire au dernier moment où les instructions sont émises dans l'ordre, soit en sortie de l'unité de ''dispatch''. De plus, les micro-opérations mémoire sont traitées à part des autres, elles sont envoyées directement à l'unité mémoire. La gestion des calculs d'adresse est quelque peu complexe, mais ils peuvent être fait soit dans l'unité mémoire, soit dans les ALU entières, peu importe. Il y a aussi un système de contournement complexe entre ALU/FPU et unité mémoire, qui n'est pas représenté dans le schéma ci-dessous. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Il faut noter que quelques processeurs utilisent des méthodes intermédiaires entre les trois solutions précédentes. Par exemple, les processeurs AMD Zen utilisent une fenêtre d'instruction décentralisée un peu particulière. Les unités de calcul entières disposent d'une fenêtre d'instruction rien que pour elles, sur ce processeur. Les instructions flottantes sont quant à elles alimentées par une file de micro-opération, pas une fenêtre d'instruction ! La raison à ce choix est un compromis entre performance et cout en circuit. L'exécution dans le désordre est peu efficace sur les instructions flottantes, car les CPU n'ont que peu d'ALU flottantes séparées. Vu le cout en circuits d'une fenêtre d'instruction, les concepteurs du processeur ont préféré utiliser une file de micro-opération pour les opérations flottantes. ===L'usage de plusieurs files d'instruction=== Une dernière méthode d'OOO utilise plusieurs files de micro-opération. L'idée est qu'une fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement une file de micro-opération pour les opérations entières, une autre pour les opérations flottantes, une autre pour les accès mémoire. D'autres processeurs utilisent une file pour les accès mémoire et une autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. La présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que la technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si une dépendance bloque une FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans une autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer la disponibilité des registres. Quand un registre est lu ou écrit par une instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. La logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : une pour les instructions d'accès mémoire et une autre pour les autres instructions. Si jamais une instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de la lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'une est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est la file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. ===Avantages et inconvénients de chaque implémentation=== Un processeur contient soit une fenêtre d'instruction unique, soit plusieurs fenêtres d'instruction séparées. Typiquement, les fenêtres d’instruction séparées sont spécialisées, dans le sens où on a une fenêtre pour les instructions flottantes, une autre pour les instructions entières, une autre pour les accès mémoire, etc. Pour résumer, on a le choix entre une grosse fenêtre généraliste et plusieurs fenêtres spécialisées, sauf que la fenêtre centralisée est lente et complexe, contrairement aux fenêtres spécialisées. Les deux méthodes ont des inconvénients et des avantages différents. Dans les grandes lignes, l'avantage des fenêtres décentralisées est qu'elles sont plus petites qu'une grosse fenêtre d'instruction. Cela simplifie la gestion du contournement et de la répartition des instructions sur les unités de calcul, comme on le verra dans quelques paragraphes. Elles sont donc moins complexes et plus rapides. L'autre avantage, c'est qu'il est possible de démarrer l'exécution de plusieurs instructions simultanément : une instruction par fenêtre décentralisée, contre une par fenêtre d'instruction. Mais les fenêtres décentralisées sont souvent sous-utilisées, partiellement remplies, contrairement aux fenêtres d'instruction. Il arrive qu'une fenêtre d'instruction soit remplie, alors que les autres sont vides. Par exemple, prenons un processeur avec une fenêtre d'instruction reliée à la FPU, et une autre reliée aux autres ALUs. Si le processeur n'exécute que des opérations flottantes, la fenêtre reliée à la FPU sera pleine, alors que l'autre sera vide. L'exécution des instructions dans le désordre est alors limitée par la petite taille de la fenêtre, qui ne peut plus accepter de nouvelle instruction flottante. Avec une fenêtre unique, on n'aurait pas eu ce problème : on aurait eu une énorme fenêtre d'instruction remplie d'instruction flottante, au lieu d'une petite fenêtre spécialisée. Il est maintenant temps de voir en quoi sont faites les fenêtres d’instruction, qu'elles soient centralisées ou décentralisées. Nous allons aussi voir quelle est la logique d'émission associée. ==L'implémentation d'une fenêtre d'instruction : généralités== Une fenêtre d'instruction est une mémoire qui mémorise des micro-opérations. Elle est cependant plus complexe qu'une mémoire RAM ou qu'une FIFO et ressemble un petit peu à une mémoire cache. Elle dispose d'un port d'écriture et d'un port de lecture, au minimum. Le port d'écriture permet à l'unité de décodage d'insérer une micro-opération dedans, d'ajouter la micro-opération qui vient d'être décodée. Si une instruction machine est décodée en plusieurs micro-opération, deux possibilités. La première est de les insérer un par un, ce qui fait qu'on peut se contenter d'un seul port d'écriture. L'autre possibilité est de les ajouter en même temps, ce qui demande plusieurs ports d'écriture. Le port de lecture sert à émettre une instruction. On part du principe que la fenêtre d'instruction ne peut émettre qu'une seule instruction à la fois, car les processeurs que nous avons vu précédemment sont de ce type. Mais nous verrons dans quelques chapitre qu'il existe des processeurs dits superscalaires, qui sont capables d'émettre plusieurs instructions par cycle. Dans ce cas, la fenêtre d'instruction a un seul port de lecture. Un processeur superscalaire, quant à lui, doit avoir un port de lecture par unité de calcul, ce qui fait beaucoup plus. ===Les entrées d'une fenêtre d’instruction=== Les fenêtres d'instruction sont composées d''''entrées''', des mots mémoire qui stockent une instruction. Une instruction réserve une entrée après son décodage et la libère dès qu'elle est envoyée aux unités de calcul. Une entrée contient l'opcode (les signaux de commande à envoyer à l'ALU), le registre de destination du résultat, les registres de chaque opérande, et éventuellement des signaux de commande en plus. De plus, chaque opérande est couplée à un bit de disponibilité, qui indique si elle est disponible. Quand un opérande est écrit dans les registres, le bit de présence correspondant est mis à jour. Enfin, chaque entrée possède un bit ''empty'' qui indique si elle est vide, cette information étant utile pour réserver des entrées. [[File:Entrée d'une station de réservation - sans les tags.png|centre|vignette|upright=3|Entrée d'une fenêtre d'instruction]] Nous verrons dans quelques chapitres que certaines fenêtres d'instruction sont capables de mémoriser les opérandes des instructions. De telles fenêtres d'instruction seront appelées, dans ce cours, des '''stations de réservation'''. Les entrées des stations de réservation sont assez semblables à celle des fenêtres d'instruction, à un détail près : les opérandes de l'instruction sont enregistrées directement dans des champs séparés. Il y a deux champs, un par opérande, pour stocker l'opérande elle-même, lue depuis les registres ou obtenue via le réseau de contournement. Notons que les champs pour les opérandes viennent en plus des champs pour les noms de registres, encore que les deux peuvent être fusionnés si on veut optimiser le tout. [[File:Entrée d'une station de réservation.png|centre|vignette|upright=3|Entrée d'une station de réservation.]] Précisons que la terminologie n'est pas très fiable. Les termes "fenêtre d'instruction" et "station de réservation" ne regroupent pas du tout la même chose d'un papier de recherche à l'autre, d'un bouquin à l'autre, d'un chercheur à l'autre, d'un ingénieur à l'autre, d'un professeur à l'autre. Le terme initial vient pourtant de l'article original sur l'algorithme de Tomasulo, où il désignait une fenêtre d'instruction associée à une unité de calcul précise. Mais le terme a ensuite été réutilisé, ce qui fait que certains processeurs avec plusieurs unités de calcul sont décrit comme ayant une unique station de réservation. En bref : c'est le bazar ! Mais nous en reparlerons dans le chapitre sur le renommage de registres, car c'est la place idéale pour les aborder. Toujours est-il que j'ai fait le choix de confondre les concepts de fenêtre d'instruction et de station de réservation avec les concepts de '''lecture avant émission''' et de '''lecture après émission'''. La différence entre les deux est que les registres sont lus après émission avec une fenêtre d'instruction, avant avec des stations de réservation. Dans le cas "avant émission", les opérandes sont mémorisées dans la station de réservation. Et cette différence a une influence sur le pipeline du processeur, le banc de registres et tout ce qui s'en suit. Un désavantage de la lecture avant émission est qu'il faut stocker les opérandes après lecture, ici dans les stations de réservation. Mais un avantage est que le banc de registre a besoin de moins de ports de lecture, car une bonne partie des opérandes sont fournies par le système de contournement. Nous verrons cela dans le détail dans le chapitre sur les processeurs superscalaires. Il a été proposé de fusionner le tampon de ré-ordonnancement avec la fenêtre d'instruction dans une structure unique. La méthode a notamment été utilisée sur les processeurs d'architecture K6 d'AMD. Le tout donnait une structure appelée le '''DRIS''' (''deferred scheduling register renaming instruction shelf''). La différence avec une fenêtre d’instruction normale est que les entrées sont libérée non pas quand l'instruction est exécutée/émise, mais quand elle termine son exécution et quitte le ROB. La fenêtre d'instruction doit alors incorporer des bits pour savoir si telle entrée a émis sont instruction ou non. ===La logique d'éveil et de sélection=== Dans le cas qui va suivre, on suppose que le processeur ne peut émettre qu'une instruction à la fois. Chaque cycle, une instruction est sélectionnée et est envoyée dans le chemin de données, soit à une ALU, soit à une unité d'accès mémoire. La sélection d'une instruction est effectuée par l'unité d'émission, qui est aussi appelée le '''''scheduler'''''. Elle gère la disponibilité des opérandes et la disponibilité des unités de calcul adéquate. Le choix de l'instruction émise doit être le plus pertinent possible, pour des raisons de performances. Pour le premier point, l'unité d'émission détermine quelles instructions sont candidates pour l'émission. Les ''instructions candidates'' sont celles dont tous les opérandes sont prêts. Le processeur contient un circuit qui détecte les instructions candidates : la '''logique d’éveil''' (''wake-up logic''). Une fois que la logique d'éveil a fait son travail, une instruction est choisie pour s’exécuter en fonction de la disponibilité des unités de calcul adéquates. Ce rôle est dévolu à un circuit qu'on appelle la '''logique de sélection''', ou ''select logic''. [[File:Fonctionnement complet de la logique d’émission.jpg|centre|vignette|upright=1.5|Fonctionnement complet de la logique d’émission.]] La logique de sélection doit gérer le fait que les unités de calcul du processeur ne sont pas toutes identiques. Déjà, un processeur a généralement des unités séparées pour les instructions entières et flottantes, des unités spécialisées dans les accès mémoire, parfois des unités spécialisées pour les branchements. Une instruction doit être attribuée à la bonne unité de calcul, on ne doit pas envoyer une instruction entière dans une unité de calcul flottante. De plus, parmi les unités de calcul entières, toutes ne sont pas identiques. Par exemple, il est fréquent d'avoir plusieurs unités de calcul spécialisées dans les opérations simples (additions, soustractions, opérations logiques) avec une unité pour les multiplications/divisions séparées, parfois une unité spécialisée pour les décalages/rotations, etc. Là encore, allouer la bonne instruction à la bonne ALU est complexe. Plus les unités de calcul sont hétérogènes, plus la logique de sélection est compliquée. Les logiques d'éveil comme de sélection sont assez complexes. Comme on le verra plus bas, la logique de sélection la plus simple, qui gère une seule unité de calcul, est basée sur un encodeur à priorité couplé à d'autres circuits. Et pour gérer plusieurs ALUs, il faut mettre des encodeurs en cascade. Le résultat est que même en prenant une logique de sélection simple, elle sera assez lente et gourmande en circuits. Aussi, la logique de sélection met souvent un cycle d'horloge entier pour faire son travail, elle a son propre étage de pipeline attribué. La logique d'éveil est dans le même cas, ce qui fait qu'émettre une micro-opération demande deux cycles d'horloge. Le défaut est que cela rajoute des cycles d'horloges entre la fenêtre d'instruction et l'ALU, ce qui complique la gestion du pipeline. Ces cycles de retard sont à prendre en compte au moment d'émettre les instructions, les ''scheduler'' doit en tenir compte pour des performances optimales. Sans tenir compte de ces cycles de retard, les instructions arrivent en retard de quelques cycles à l'ALU, cycles de retard durant lesquels l'ALU n'a pas fait de calcul et a été sous-utilisée, sans compter que le système de contournement n'est pas utilisé au mieux. Et le problème est encore plus important sur les processeur avec des stations de réservation, qui utilisent la "lecture après émission" : cela rajoute un cycle d'horloge en plus, un temps de retard en plus. ===La logique d'éveil : l'émission anticipée=== La logique d'éveil doit tenir compte du fait qu'il y a plusieurs étages entre l'émission et l'exécution sur une unité de calcul. Par exemple, un processeur a souvent entre un et à cinq étages entre la file d'attente et les unités de calcul. Il faut lire les registres, gérer le contournement, et cela peut prendre quelques cycles d'horloge. Sur le Pentium 4, on trouve 6 étages entre la fenêtre d’instruction et l'entrée de l'ALU. Si les micro-opérations sont émises quand les opérandes sont disponibles, il y aura un délai de quelques cycles avant qu'elles atteignent l'ALU. Alors qu'idéalement, on souhaiterait que la micro-opération atteigne l'ALU dès que ses opérandes sont disponibles, pour profiter des techniques de contournement. Pour cela, la logique d'éveil émet les instructions quelques cycles en avance pour qu'elles arrivent au bon moment. Il s'agit d'une technique d''''émission anticipée''', dont nous avions parlé dans le chapitre sur le contournement. : Il faut noter que le problème se pose plus avec des fenêtres d'instruction qu'avec des stations de réservation. Les premières ont un étage en plus entre émission et ALU, vu qu'il faut lire des registres après l'émission. L'émission anticipée demande d'émettre un signal d'éveil en avance de quelques cycles, pile au bon moment. Par exemples, si on a deux étages entre l'ALU et l'unité d'émission, le signal de réveil sera généré deux cycles avant que le résultat soit effectivement calculé. L'implémentation varie, mais deux solutions sont possibles. La première est de générer le signal d'éveil dans l'ALU, ce qui n'a de sens que pour les opérations comme les multiplications ou les divisions, qui prennent plusieurs cycles. Une autre technique génère le signal de réveil dans une structure centralisée, spécialisée dans la génération des signaux d'éveil. L'unité de composée d'un registre à décalage par registre. Imaginons qu'une instruction est émise, que cette instruction mette N cycles à s'exécuter, et qu'elle écrive dans un registre de destination. L'unité sélectionne alors le registre à décalage associé au registre de destination, et met le bit numéro N à 1. Le registre décalé d'un cran à chaque cycle. Quand le bit sortant est un 1, alors le signal de validité pour l'opérande est généré. L'émission anticipée marche bien si l'instruction a une durée fixe, connue à l'avance. Et autant c'est le cas pour les instructions arithmétiques et logiques, autant ce n'est pas le cas pour les accès mémoire. Les accès mémoire ont une latence variable : quelques cycles pour un succès de cache, plusieurs dizaines de cycles pour un défaut de cache L1, pas loin de la centaine pour un défaut de cache L2, etc. Et cela pose des problèmes pour l'émission anticipée. L'émission en avance pour les accès mémoire est purement spéculative : le processeur émet des instructions en supposant que la lecture entrainera un succès de cache, quitte à annuler l'instruction en cas de défaut de cache. Mais faire ainsi demande non seulement d'annuler les instructions émises en avance, mais aussi de ne pas retirer les instructions émises en avance de la fenêtre d'instruction. Elles sont émises, mais une copie de sauvegarde est conservée dans la fenêtre d'instruction. Si le processeur détecte un défaut de cache, il peut alors ré-exécuter l'instruction. S'il détecte un succès de cache, les instructions lecture-dépendante sont retirées de la fenêtre d'instruction, la copie de sauvegarde est devenue inutile et est donc jetée. ===La logique de sélection : âge ou position ?=== La logique de sélection est primordiale pour de bonnes performances. Il existe deux méthodes principales pour sélectionner l'instruction à exécuter. La première est la plus simple : elle se base sur lé numéro de l'entrée. En effet, une fenêtre d'instruction est avant tout une sorte de mémoire, un mix entre mémoire associative, mémoire RAM, et FIFO. Et chaque entrée a un numéro, une adresse mémoire. Nous parlerons de numéro dans ce qui suit, car ce sera plus simple, le terme d'adresse mémoire étant peut-être un peu exagéré dans le contexte des fenêtres d'instruction. Toujours est-il que la fenêtre d'instruction est adressable dans le sens où on peut lui envoyer le numéro de l'entrée voulue, et la fenêtre d’instruction renvoie le contenu de l'entrée sur son port de lecture. Et c'est ce que fait la logique de sélection : elle génère le numéro de l'entrée à lire. Le numéro est alors envoyé sur l'entrée d'adresse de la fenêtre d’instruction, et elle fournit la micro-opération associée sur son port de lecture, son '''port d'émission'''. La première méthode de sélection, donc. Elle est basée sur sur le numéro de l'entrée. Si plusieurs entrées sont éveillées, la logique de sélection prend celle avec le plus petit numéro. Elle porte le nom de '''sélection par position''', sous-entendu position dans la fenêtre d'instruction. Vous l'avez peut-être deviné, mais la logique de sélection est alors un encodeur à priorité. Le circuit de sélection ne se résume donc pas seulement à un encodeur à priorité, mais c'est le circuit central. L'avantage d'une telle méthode de sélection est qu'elle est simple à implémenter : un encodeur à priorité est un circuit connu, facile à implémenter. Mais on remarque un défaut : un encodeur est un circuit assez rapide, mais qui utilise beaucoup de transistors, beaucoup de portes logiques, surtout si on veut qu'il soit rapide. Ce qui explique que la logique de sélection ait son propre étage de pipeline rien que pour elle. La seconde méthode s'appelle la '''sélection par âge''', au nom assez transparent. L'idée est de privilégier l'émission de l'instruction la plus ancienne. Elle demande que la fenêtre d'instruction trie les micro-opérations par ordre d'insertion dans la fenêtre d'instruction, ce qui en fait une pseudo-FIFO. Le tri est partiel, car les instructions peuvent sortir de la fenêtre d’instruction à tout moment. Compacter la fenêtre d'instruction, à savoir regrouper toutes les entrées valides est une idée, mais elle est compliquée à implémenter. Aussi, elles préfèrent encoder des informations sur l'ordre d'émission dans chaque entrée. L'encodeur à priorité doit alors travailler non pas sur des nombres entiers liés à l'ordre d'insertion dans la pseudo-FIFO. Elle est encore plus gourmande en circuits que la méthode précédente. Les processeurs haute performance utilisent souvent des méthodes hybrides. Par exemple, les processeurs AMD de microarchitecture Bulldozer utilisaient une méthode intermédiaire. Ils utilisaient une fenêtre d'instruction couplée à un encodeur à priorité pour la sélection par position, mais complémentaient le tout avec une unité qui mémorisait l'instruction la plus ancienne dans la fenêtre d’instruction. Le mécanisme de sélection par âge était utilisé en priorité. Mais si l'instruction la plus ancienne n'était pas prête, le processeur basculait sur le mécanisme de sélection par position. ===La compaction des fenêtres d'instruction=== À chaque cycle, les instructions décodées sont ajoutées dans la fenêtre d'instruction, dans des entrées vides. Vu que les instructions quittent celle-ci dans le désordre, ces vides sont dispersés dans la fenêtre d'instruction, ce qui pose problème pour déterminer où placer les nouvelles instructions. La solution la plus triviale consiste à conserver une liste des vides, mise à jour à chaque insertion ou émission d'instruction. Une autre solution consiste à éliminer les vides en compactant la fenêtre d'instruction à chaque cycle d'horloge. Des circuits se chargent de détecter les vides et de regrouper les instructions en un unique bloc. Il faut signaler que certaines processeurs arrivent à se passer de cette étape de compactage, mais au prix de fenêtres d'instruction nettement plus complexes. Autre problème : quand il faut choisir quelle instruction émettre, il y a toujours plusieurs candidats. Si on choisit mal, des instructions restent en attente trop longtemps parce que d'autres instructions plus jeunes leur passent devant. Pour éviter cela, les instructions les plus vielles, les plus anciennes, sont prioritaires. Pour cela, on peut utiliser une FIFO un peu spéciale pour la fenêtre d'instruction. Si les ajouts d'instruction se font dans l'ordre, les instructions ne quittent pas forcément la fenêtre d'instruction dans l'ordre imposé par une FIFO : les instructions restent triées dans leur ordre d'ajout, même s'il y a des vides entre elles. Dans ces condition, il est préférable que le compactage conserve l'ordre FIFO des instructions. Dans ces conditions, l'instruction la plus ancienne est celle qui est située à l'adresse la plus faible : le circuit de sélection peut donc être fabriqué avec des encodeurs, et est relativement simple. ==Les fenêtres d'instruction basées sur une matrice de dépendances== L'implémentation la plus simple étend le fonctionnement d'un pipeline dynamique usuel. Rappelez-vous le chapitre sur les pipeline dynamiques. Nous avions vu que de tels pipelines émettaient une instruction par cycle, quitte à émettre des bulles de pipeline en cas de dépendance bloquante. Et il est possible d'améliorer leur unité d'émission pour qu'elle soit compatible avec l'exécution dans le désordre. ===Rappels sur le registre de réservation/disponibilité=== L'émission d'une instruction est gouvernée par un ''registre de réservation'' qui indique quels registres sont réservés par une instruction, et ceux qui sont libres. Un registre réservé est un registre qui sera écrit par une instruction en cours d'exécution, mais qui n'a pas encore écrit son résultat. Les instructions candidates doivent avoir leurs opérandes dans des registres libres. Sinon, c'est signe que leurs opérandes sont réservées en écriture, donc pas encore écrites, donc pas disponibles. Si une instruction candidate veut lire ce registre, c'est signe qu'il y a une dépendance RAW : elle veut lire un registre réservé, qui est destiné à être écrit par une instruction en vol. Si elle veut écrire, c'est signe qu'elle veut écrire dans un registre où une autre instruction veut écrire : c'est une dépendance WAW. Dans les deux cas, l'instruction n'est pas émise. Le registre de réservation encode les registres réservés comme suit : chaque bit est associé à un registre. Le bit numéro 0 est associé au registre numéro 0, le bit numéro 1 au registre numéro 1, etc. Là, En clair, les numéros de registres réservés sont encodés en représentation non pas binaire, mais en représentation ''one-hot'' (vue au premier chapitre). {|class="wikitable" |+ Registre de réservation |- ! Registre 7 !! Registre 6 !! Registre 5 !! Registre 4 !! Registre 3 !! Registre 2 !! Registre 1 !! Registre 0 |- | 0 || 0 || 1 || 0 || 0 || 1 || 0 || 0 |} Avant d'émettre une instruction, l'unité d'émission extrait les registres opérande/destination et les convertis dans la même représentation que le registre de réservation, à savoir en représentation ''one-hot''. Le circuit de traduction binaire vers ''one-hot'' est, pour rappel, un simple décodeur. Puis, on fait un OU logique entre les sorties des décodeurs. Le résultat est un masque qui indique quels registres sont lus par l'instruction, encodé en représentation ''one-hot''. Appelons-le le '''masque d'opérandes'''. Le masque est alors comparé au registre de réservation pour vérifier si l'instruction peut être émise. [[File:Unité d'émission simple, dans l'ordre.png|centre|vignette|upright=2|Unité d'émission simple, dans l'ordre]] Si l'émission est autorisée, le registres de réservation est là aussi mis à jour. Le registre de réservation est aussi mis à jour dès qu'une instruction enregistre son résultat dans les registres, ou alors dès qu'il est disponible pour le contournement. Le bit associé au registre repasse alors à 0 (ou à 1). Sans contournement, la mise à jour se fait alors à la toute fin de l'instruction, quand elle se termine, lors de la dernière étape d'enregistrement, à la fin de son pipeline. Avec, elle se fait quand l'instruction quitte l'unité de calcul. ===L'extension à l'exécution dans le désordre : l'éveil par matrice de bits=== La différence entre un pipeline dynamique et l'exécution dans le désordre est que l'on passe d'une instruction à émettre à plusieurs. Plusieurs instructions sont mises en attente dans une fenêtre d’instruction, et y attendent leur tour. L'idée est alors d'envoyer le registre de disponibilité à toutes les entrées, à toutes les instructions en attente. Ainsi, on sait quelles sont les instructions qui peuvent s'exécuter et celles qui ne le peuvent pas. L'implémentation est assez simple, elle ressemble beaucoup à l'implémentation d'un pipeline dynamique simple, si ce n'est que des circuits sont dupliqués. L'implémentation utilise des fenêtres d'instruction légèrement différentes de celles introduites plus haut. Elles n'utilisent notamment pas de bits de disponibilité, mais autre chose. Lorsqu'une instruction est ajoutée à la fenêtre d'instruction, le masque de disponibilité des opérandes est stocké dans la fenêtre d'instruction. A chaque cycle, le registre de disponibilité est envoyée à toutes les entrées, et est comparé avec tous les masques de disponibilité des opérandes. Si une comparaison renvoie un 1, alors l'instruction de l'entrée est une instruction candidate à l'émission. [[File:Unité d'émission dans le désordre basée sur un registre de disponibilité.png|centre|vignette|upright=2.5|Unité d'émission dans le désordre basée sur un registre de disponibilité]] L'ensemble est implémenté avec l'aide d'une '''matrice de bits''', où chaque ligne correspond à une entrée et chaque colonne à un registre. À chaque croisement entre une ligne et une colonne, on trouve un bit. Si le bit de la ligne n et de la colonne m est à 1, cela veut dire : l'instruction dans l'entrée n a besoin de lire le registre m. S’il est à 0, alors cela veut dire que l'instruction stockée dans la ligne n n'a pas besoin de la donnée dans le registre m. [[File:Planificateur à matrice de bits.jpg|centre|vignette|upright=2|Planificateur à matrice de bits.]] Lorsqu'une instruction réserve une entrée, elle initialise la ligne en fonction des registres qu'elle souhaite lire. Pour vérifier si une instruction a ses opérandes prêts, le processeur compare le registre de disponibilité à la ligne associée à l'instruction/entrée. A chaque intersection ligne-colonne, se trouve un comparateur de 1 bit, qui détecte si le registre est demandé et disponible. Les résultats de cette porte sont ensuite envoyés à une porte ET, qui fait le gros du travail. [[File:Logique de détection de la disponibilité d'une instruction.jpg|centre|vignette|upright=2|Logique de détection de la disponibilité d'une instruction.]] ==Les fenêtres d'instruction basées sur une mémoire associative== Les processeurs modernes utilisent une mémoire associative pour la fenêtre d'instruction. Les mémoires associatives ont été abordées il y a quelques chapitres, mais faisons quelques rappels. Les mémoires associatives servent à accélérer la recherche de données dans un ensemble. Or, une fenêtre d'instruction vérifie régulièrement si chaque entrée est prête. Il s'agit d'un processus de recherche d'une instruction qui respecte une condition bien précise dans la mémoire, ce qui fait que les mémoires associatives sont donc tout indiquées. Comme vous le savez, les signaux de commande d'une instruction sont propagés avec celle-ci dans le pipeline, le nom du registre de destination ne faisant pas exception. Le nom de registre est envoyé à la fenêtre d'instruction lors de l'écriture du résultat dans les registres. S'il y a correspondance, l'opérande est disponible et son bit de disponibilité est mis à 1. On peut adapter cette méthode pour tenir compte du contournement assez simplement. [[File:Détection des dépendances par propagation du registre de destination.png|centre|vignette|upright=2|Détection des dépendances par propagation du registre de destination.]] En conséquence, le circuit de détection des dépendances est constitué d'un grand nombre de comparateurs : un par champ « nom de registre » dans chaque entrée. La logique d'éveil/''wake up'' regroupe tous les comparateurs, la logique de sélection est un circuit situé en-dehors de la mémoire associative. Les entrées sont dans la mémoire associative elle-même. [[File:Gestion des bits de validité.png|centre|vignette|upright=2|Gestion des bits de validité.]] L'implémentation la plus simple est celle du schéma précédent, où on utilise une mémoire associative unique. Une version plus élaborée sépare la fenêtre d'instruction en deux parties : une mémoire qui mémorise les registres des opérandes, une autre mémoire pour le reste. La mémoire pour les registres opérandes est la mémoire associative proprement dite, c'est elle qui est associées aux comparateurs, à la logique de ''wake-up''/réveil, etc. Par contre, l'autre mémoire est une mémoire RAM simplifiée, qui mémorise les informations qui n'ont pas besoin des comparateurs. L'opcode de l'instruction est là-dedans, par exemple. ===Les optimisations de la consommation d'énergie : la désactivation des portions inutilisées=== Le problème avec des fenêtres d'instruction de ce type est leur forte consommation énergétique, ainsi que le grand nombre de portes logiques utilisées, qui deviennent prohibitif pour des fenêtres d'instruction un peu grosses. Pour résoudre ce problème, certains ont optimisé les comparateurs. D'autres ont tenté de profiter du fait que la majorité des bits dans les entrées sont composés de zéros. Bref, les optimisations purement matérielles sont légion. Une première solution est de désactiver les entrées qui sont inutilisées, vides, sans instruction. Pour cela, on fait précéder les comparateurs par un circuit qui les connecte ou déconnecte des lignes de bit. Le circuit est commandé par le bit ''empty'' qui indique si une entrée est vide ou non. L'avantage est que la consommation d'énergie de la fenêtre d'instruction devient alors proportionnelle au nombre d'entrées non-vides, et non au nombre d'entrées total. Du moins, en apparence, les entrées non-utilisées doivent quand même être alimentées pour fonctionner, mais l'activité de comparaison disparait dans les entrées vides. Il est possible d'étendre cette technique aux entrées dont les opérandes sont prêtes. Les gains sont généralement assez bons, avec une réduction de consommation variant entre 30 et 50%, avec une implémentation très simple et très économe en circuits. Une autre solution, assez simple à mettre en place, consiste à désactiver une partie de la fenêtre d'instruction sin elle est inutilisée. Pour cela, il faut segmenter la fenêtre d'instruction avec la technique du ''wire partitionning''. Pour rappel, une fenêtre d'instruction est une mémoire associative. Et comme toute mémoire associative, elle contient des fils, les lignes de bit, qui relient les entrées/sorties à toutes les cellules mémoire. Plus une ligne de bit est longue, plus elle consomme d'énergie et plus le temps de lecture/écriture est long. L'idée est de segmenter les lignes de bits en plaçant des répéteurs qui recopient la tension d'un segment au suivant. Les répéteurs sont des tampons trois-états, ce qui permet de déconnecter les portions inutilisées de la ligne de bit. Ce faisant, la fenêtre d'instruction est découpée en segments, qui peuvent être désactivés si besoin. Si il y a peu d'instructions chargées dans la fenêtre d'instruction, les portions inutilisées sont désactivées. La technique marche d'autan mieux si les instructions sont compactées au début de la fenêtre d'instruction. [[File:Wire partitionning.png|centre|vignette|upright=2|Wire partitionning]] Tout le problème est de savoir quelles portions désactiver. La technique est assez simple si la fenêtre d'instruction est compactée, à savoir si toutes les instructions sont régulièrement regroupées au début de la mémoire CAM. Mais même avec cette optimisation, la décision de désactiver une portion de la fenêtre d'instruction n'est pas à prendre à la légère. Il ne faut pas désactiver une portion contenant des instructions pouvant être émise sous peu. La décision dépend de paramètres variés : proportion d'entrée vides, quantité d'entrées récemment activées/désactivées récemment, présences d'entrées avec un ''match'' d'opérandes récent, etc. Il est important de préciser que les techniques en question fonctionnent aussi sur les autres types de fenêtre d'instruction, qui ne sont pas basées sur des mémoires associatives. Nous allons voir celles-ci dans la suite du chapitre, mais gardez à l'esprit que ces optimisations, à savoir désactiver les entrées vides/prêts et partitionner la fenêtre d'instruction, sont des optimisations générales qui marchent avec presque tout. ===L'ajout d'une FIFO pour les instructions déjà prêtes à l'émission=== D'autres techniques permettent de réduire aussi bien le cout en circuits que la consommation d'énergie de la fenêtre d'instruction. L'idée est d'utiliser une mémoire associative quand elle est réellement nécessaire, mais d'utiliser une fenêtre d'instruction "normale" dès que possible. La méthode la plus simple tient compte du fait que certaines instructions ont déjà toutes leurs opérandes de disponibles à l'émission, mais doivent quand même être mises en attente, parce que l'ALU adéquate est occupée, parce que des dépendances WAW/WAR sont encore là, ou pour tout autre raison. Dans ce cas, elles sont mises en attente non pas dans la fenêtre d'instruction, mais dans une mémoire FIFO toute simple. L'idée est qu'au lieu d'avoir une énorme mémoire associative pour la fenêtre d'instruction, on déplace quelques entrées dans une petite FIFO annexe. Le résultat est un gain en terme d'énergie et de circuits, au prix d'une perte de performance mineure. La perte de performance en question se manifeste si aucune instruction n'a ses opérandes de prêtes à l'émission : le programme n'utilise pas la FIFO et voit alors une fenêtre d'instruction plus petite. Une amélioration de cette technique tient compte du fait que certaines instructions sont dans un cas intermédiaire. Elles ont déjà une opérande de prête lors de l'émission, mais pas l'autre. Le nombre d'opérandes varie suivant l’instruction : certaines n'ont besoin que d'un seul opérande. De plus, il arrive qu'une opération tout juste décodée ait déjà un ou plusieurs de ses opérandes de prêts. Cette constatation permet d'éviter d'utiliser des comparateurs pour les opérandes déjà prêts. Par exemple, on peut parfaitement utiliser trois fenêtres d'instruction : * une pour les instructions dont tous les opérandes sont prêts, mais qui sont quand même mises en attente, sans comparateur ; * une pour les instructions dont un seul opérande manque, qui n'utilise qu'un comparateur par entrée ; * une pour les instructions dont deux opérandes manquent à l'appel, qui utilise deux comparateurs par entrée. C'est beaucoup plus économique que d'utiliser une seule grosse fenêtre d'instruction qui contiendrait autant d'entrées que les trois précédentes réunies, avec deux comparateurs par entrée. Certains sont même allés plus loin, et ont proposé de supprimer la fenêtre d'instruction avec deux opérandes par entrée. Les instructions dont deux opérandes sont inconnus au décodage sont stockées dans la fenêtre d'instruction pour instructions avec un comparateur par entrée. Un circuit de prédiction se charge alors de prédire l'opérande manquant, cette prédiction étant vérifiée plus loin dans le pipeline. Il serait cependant étonnant qu'une telle proposition ait donné lieu à la moindre implémentation réelle. ===Les optimisations de la consommation d'énergie avancées=== D'autres chercheurs ont conservé une fenêtre d'instruction unique, avec autant de comparateurs par entrée qu'il y a d'opérandes possibles par instruction. Simplement, le processus de détection des opérandes prêts est légèrement ralenti : on ne vérifie qu'un opérande par cycle. Pour vérifier les deux opérandes d'une entrée, on doit attendre deux cycles. Enfin, certains chercheurs ont proposé des fenêtres d'instruction segmentées. Les instructions circulent à chaque cycle d'un segment vers le suivant : en conséquence, certains segments conservent les instructions les plus anciennes, un autre les instructions les plus jeunes, etc. Seul le denier segment, celui qui contient les instructions les plus vielles, peut émettre une instruction : la détection des opérandes se fait seulement dans le dernier segment, qui contient les instructions les plus anciennes. On économise ainsi beaucoup de comparateurs. Certains chercheurs ont tenté de pipeliner l'étape de sélection des opérandes, ainsi que l'étage d'arbitrage. Mais en faisant cela, il faut plusieurs cycles pour détecter qu'une instruction a ses opérandes prêts, ce qui pose problème face à de nombreuses dépendances RAW. Pour éviter de trop perdre en performances, certains chercheurs ont décidé d'utiliser des techniques pour prédire quelles seront les instructions dont les opérandes seront bientôt prêts. Si détecter qu'une instruction est prête prend n cycles, le processeur devra tenter de prédire la future disponibilité des opérandes n cycles en avance pour obtenir des performances optimales. ===Remplacer la mémoire associative par une RAM=== Une autre optimisation possible est de remplacer la fenêtre d'instruction par une mémoire RAM, dont chaque mot mémoire correspondrait à une entrée. Une telle optimisation permet en théorie de se passer des comparateurs associés à chaque entrée, mais au prix de l'ajout de circuits annexes potentiellement couteux. La première de ces techniques, la '''recherche directe par étiquette''' (direct tag search) fut créée par Weiss et son collègue Smith. Ils cherchaient à améliorer l'algorithme de Tomasulo, un algorithme qu'on expliquera dans quelques chapitres. Rappelons que chaque instruction produit un résultat, qui devra être rapatrié dans une ou plusieurs entrées de la fenêtre d'instruction. L'optimisation de la recherche directe par étiquette fonctionne dans le cas où le résultat de l'instruction n'est utilisé que par une seule entrée, et pas plusieurs. Le principe est simple : chaque champ « opérande » d'une entrée est adressable via le nom de registre de cette opérande. Pour faire le lien entre entrée et nom de registre, la recherche directe par étiquette ajoute une table de correspondances matérielle, une mémoire RAM qui mémorise les adresses des champs « opérande » des entrées. Les adresses envoyées dans cette mémoire sont les noms de registres des résultats. Lors de l'émission, la table de correspondances est mise à jour. Les numéros des champs « opérande » réservés lors de l'émission sont mémorisés dans les mots mémoire qui correspondent aux deux registres sources. Toutefois, une petite vérification est faite lors de l'émission : si il y a déjà une correspondance dans la table pour un registre source, alors une autre instruction compte lire ce registre. Pour éviter d'écraser les données de l'instruction précédente dans la table de correspondances, l'émission de l'instruction est bloquée. [[File:Recherche directe par étiquette.png|centre|vignette|upright=2|Recherche directe par étiquette.]] ==Les fenêtres d’instruction avec préplanification== Avec la '''préplanification''' (''prescheduling''), la fenêtre d’instruction est composée de mémoires FIFO dans lesquelles les instructions sont triées dans l'ordre d'émission. Il n'y a pas de logique d’émission proprement dite, celle-ci se bornant à vérifier si l'instruction située au début de la FIFO peut s’exécuter. Par contre, le préplanificateur détecte les dépendances et en déduit où insérer les instructions dans le tampon d'émission, à l'endroit le plus adéquat. [[File:Préplanification.jpg|centre|vignette|upright=2|Préplanification.]] ===L'usage de FIFO multiples=== La technique de préplanification la plus simple utilise plusieurs FIFO. Quand une instruction a une dépendance avec une autre instruction, les deux sont placées dans la même FIFO. Pour cela, le préplanificateur détecte les chaines d'instructions dépendantes, et place les instructions dans la FIFO adéquate. A chaque cycle, l'unité d'émission lit une micro-opération dans chaque FIFO et vérifie si elle peut l'émettre. Si la micro-opération n'a pas ses opérandes disponibles, ou qu'une dépendance structurelle survient, alors la FIFO est bloquée. La micro-opération attend que la dépendance soit résolue, bloquant toutes les instructions précédentes. Mais les autres FIFO ne sont pas bloquées, laissant de la marge de manœuvre. [[File:Préplanification par FIFO multiples.png|centre|vignette|upright=1.5|Préplanification par FIFO multiples.]] ===La technique du tampon trié=== La technique du '''tampon trié''' trie les instructions selon le temps d'attente avant leur exécution. Les instructions qui sont censées s’exécuter bientôt sont insérées au tout début de la FIFO, tandis que les instructions qui s’exécuteront dans un long moment sont insérées vers la fin. Là encore, l'unité d'émission lit une micro-opération dans la FIFO, et détermine si elle peut être émise. Si une dépendance survient, l'émission est retardée, et la FIFO est bloquée. [[File:Préplanification par tampon trié.png|centre|vignette|upright=1.5|Préplanification par tampon trié.]] La technique a cependant quelques problèmes assez importants. Le premier problème est que la FIFO est bloquée lorsqu'une micro-opération ne peut être émise. Le second problème est que le temps avant exécution n'est pas toujours connu, notamment pour les instructions d'accès mémoire. Et cela se répercute sur les instructions dépendantes de celles-ci. Pour résoudre ce genre de problèmes, l'usage d'un pipeline à ''replay'' est possible, et est même l'une des meilleures solution possible, malgré ses défauts. L'idée est que les lecture sont pré-planifiées en supposant qu'elles font un succès de cache L1. Si la prédiction est fausse, la lecture est ré-exécutée plusieurs cycles plus tard, en supposant qu'elle fait un succès dans le cache L2, et ainsi de suite. Elle est alors ré-insérée dans la FIFO, elle est pré-planifiée une seconde fois. Il en est de même si une micro-opération ne peut pas être émise : il suffit de la réinsérer dans la FIFO au bon endroit, en attendant que ses dépendances soient résolus. Ainsi, l'instruction fautive ne bloque pas la fenêtre d’instruction, et retente sa chance autant de fois qu'il le faut. [[File:Préplanification par fenêtre d’instruction scorebarodée.png|centre|vignette|upright=1.5|Préplanification par fenêtre d’instruction scorebarodée.]] Une autre solution utilise deux fenêtres d’instruction : une FIFO gérée par la préplanification, et une vraie fenêtre d'instruction pour les instructions dont le temps d'attente ne peut pas être déterminé. Il est possible de mettre cette dernière avant la préplanification, afin de gérer les temps d'attente des instructions d'accès mémoire. Quand le temps d'attente d'une lecture devient connu, ses instructions dépendantes sont gérées avec préplanification. [[File:Préplanification avec fenêtre d’instruction.png|centre|vignette|upright=2.5|Préplanification avec fenêtre d’instruction.]] ===Les fenêtres d'instruction avec allocation temporelle statique=== L''''allocation temporelle statique''' correspond à une technique utilisée sur les processeurs Cuzco de l'entreprise Condor. La technique en question a été présenté en 2025, mais des idées similaires ont été présentées dans la littérature académique. Elle ressemble beaucoup aux techniques de pré-planification, avec cependant quelques différences. L'idée est simple : le processeur dispose de plusieurs fenêtres d'instruction, qui mettent en attente les micro-opérations. Lors de l'étape de renommage de registres, le processeur détermine dans combien de cycles d'horloge la micro-opération sera prête pour exécution. La micro-opération est alors mise en attente durant ce nombre de cycles, dans les fenêtres d'instruction, puis est émise une fois ce nombre de cycles écoulés. Ce faisant, les fenêtres d'instruction n'ont pas besoin de détecter la disponibilité des opérandes à chaque cycle, pour chaque micro-opération en attente. Le ''timing'' de l'émission des micro-opérations est décidé à l'avance. L'implémentation exacte n'est pas connue, mais plusieurs solutions sont imaginables. Par exemple, la fenêtre d'instruction peut simplement être composée de plusieurs mémoires de petite taille, chacune contenant les micro-opérations destinées à être exécutées dans N cycles, N étant différent pour chaque mémoire. Une autre solution, plus réaliste, utilise une fenêtre d'instruction dans laquelle la micro-opération est couplée à des champs pour les opérandes, et un champ compteur. Le champ compteur est initialisé avec le nombre de cycles à attendre, et est décrémenté à chaque cycle d'horloge. Quand il atteint zéro, la micro-opération est émise. Vous remarquerez que la méthode ne marche que si toutes les micro-opérations prennent un nombre fixe de cycles d'horloge. Et autant c'est le cas pour les micro-opérations arithmétiques ou logiques, autant les accès mémoire ne rentrent pas dans ce cadre. En théorie, on ne sait pas combien de temps prendra un accès mémoire. Et cette incertitude se répercute sur les instructions dépendantes d'un accès mémoire. Pour éviter cela, le processeur réutilise un pipeline à ''replay'' tel que vu dans le chapitre précédent. L'unité de renommage de registre suppose que tout accès mémoire fait un succès de cache L1, et décide des ''timings'' d'émission sous cette hypothèse. Si une lecture subit un défaut de cache, elle est ré-exécutée, de même que toutes les instructions dépendantes. Pour cela, le registre de destination de la lecture est marqué comme invalide, grâce à un bit spécifique attaché au registre. Toute instruction qui lit une opérande invalide est elle aussi ré-executée de zéro. Pour simplifier, l'unité d'émission ressemble à une unité d'émission dans l'ordre, avec un registre de disponibilité, qu'on aurait amélioré pour aller au-delà de la simple détection des dépendances d'instruction. Pour déterminer les ''timings'' d'émission, à savoir quand émettre une micro-opération, le processeur utilise une unité d'émission à deux étages. Le premier étage est appelé le ''register scoreboard'', le second étage est appelé la ''Time Ressource Matrix''. Les deux étages communiquent entre eux, comme on va le voir, et leurs noms donnent une idée de ce qu'ils font. Le premier étage gère les dépendances de registres, le second gère les dépendances structurelles. Le premier étage est un registre de disponibilité amélioré, qui gère les dépendances de registre. Cet étage sait quand tel registre sera écrit, et donc que l'opérande écrite dedans sera disponible à partir de tel cycle d'horloge. Il le sait car l'étage suivant l'aura prévenu, mais laissons cela de côté pour le moment. Quand une micro-opération rentre dans cet étage, il vérifie les dépendances avec les registres et les micro-opérations antérieures. Vu qu'il sait quand les registres seront disponibles, il peut déterminer quand l'instruction pourra s'exécuter. Par exemple, si une micro-opération lit les deux registres R7 et R15, qui sont disponibles respectivement dans 5 et 7 cycles, le premier étage sait que la micro-opération devra attendre 7 cycles. Mais tout cela ne suffit pas à déterminer quand émettre une micro-opération. En effet, il fait aussi gérer les dépendances structurelles, ce qui est le boulot du second étage. Le second étage utilise pour cela une ''Time Ressource Matrix'', qui mémorise l'occupation de diverses "ressources", pour les 256 cycles d'horloge à venir. Les ressources en question sont les ports de lecture/écriture du banc de registre, les ALUs utilisées, si la micro-opération utilise l'unité mémoire, etc. Le second étage prend en entrée une micro-opération, détermine quelles "ressources" elle utilise, puis regarde leur disponibilité. Elle détecte alors les dépendances structurelles et détermine alors quand peut s'exécuter la micro-opération. Elle peut retarder l'émission de quelques cycles, si une dépendance structurelle est détectée. Une fois sortie du second étage, on sait quand la micro-opération va être émise, à quel cycle précisément. Et vu que la durée de l'instruction est fixe, on sait quand cette micro-opération va se terminer, quand son résultat sera disponible. Cela permet de mettre à jour la ''Time Ressource Matrix'', pour préciser que le port d'écriture sera occupé à tel moment. De plus, cette information est transmise au premier étage, qui sait alors quand est enregistré le résultat dans le registre de destination. C'est comme cela que le premier étage sait quand un registre est disponible : le second étage le prévient, quand il émet une instruction ! La ''Time Ressource Matrix''mémorise l'occupation des "ressources" pour les 256 cycles d'horloge à venir. Cependant, elle ne vérifie pas les dépendances pour les 256 cycles suivants. Quand elle reçoit une micro-opération, elle teste les dépendances structurelles pour seulement les 8 prochains cycles maximum. Si la micro-opération ne peut pas être émise pendant ces 8 cycles, le pipeline est bloqué, un ''pipeline stall'' est émis. Pour être plus précis, vu que le processeur peut décoder 8 micro-opérations en même temps, cela permet de ne consulter que 64 cycles d'horloge sur les 256. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les premiers processeurs Intel | prevText=Les premiers processeurs Intel | next=Le renommage de registres | nextText=Le renommage de registres }} </noinclude> b50o96imb24z464vio3trd4nqlzsf1z 773595 773594 2026-09-29T18:51:29Z Mewtow 31375 /* Les fenêtres d'instruction décentralisées */ 773595 wikitext text/x-wiki Dans les chapitres précédents, nous avons parlé des techniques dites d''''émission dans l'ordre'''. L'idée est d’exécuter une nouvelle micro-opération à chaque cycle, dans des unités de calcul séparées. Les instructions sont émises consécutivement, mais les instructions s’exécutent en parallèle dans des unités de calcul séparées. Par contre, quand l'unité d'émission ne peut pas émettre une instruction, elle bloque tout le pipeline. Les instructions qui suivent sont elles aussi bloquées, elle doivent attendre leur tour, même si elles sont en capacité de s'exécuter. Les techniques d'exécution dans le désordre que nous allons voir dans ce chapitre corrigent ce point précis. Elles sont dites à '''émission dans le désordre'''. Elles se distinguent des précédentes sur un point précis : quand l'unité d'émission bloque l'émission d'une instruction, les instructions suivantes peuvent poursuivre. L'émission des instructions peut donc se faire dans le désordre, dans le sens où une instruction peut être émise alors qu'une instruction précédente ne l'est pas encore. L'avantage de l'émission dans le désordre est qu'une instruction s'exécute dès que ses opérandes sont disponibles. Par disponible, on veut dire présent soit dans le réseau de contournement, soit dans les registres. Le processeur détecte automatiquement quand les opérandes d'une instruction sont sont disponibles, et il l’exécute à ce moment là. Dès qu'une instruction a ses opérandes disponibles, elle est émise et exécutée. C'est là la seule contrainte : les dépendances WAR, WAW et autres sont gérées par un ROB ou toute autre technique d'exception précise, seules les dépendances RAW limitent l'exécution. Mais avant de poursuivre, quelques point niveaux terminologie : * L'émission dans le désordre est un terme parlant et assez précis. Malheureusement, la terminologie la plus utilisée par d''''exécution dans le désordre'''. Et nous utiliserons ce terme dans la suite du cours, histoire de ne pas trop dévier de la nomenclature habituelle. * Nous utiliserons parfois l'abréviation OOO pour parler d'exécution dans le désordre. L'abréviation est celle de ''Out Of Order Excution''. * Nous utiliserons aussi l'abréviation ''µop'' pour parler de micro-opération, ''µops'' au pluriels pour parler de plusieurs micro-opérations, ou des micro-opérations en général. L'exécution dans le désordre ne gére en effet que des µops, elle se situe après l'étape de décodage. Mais avant de poursuivre, précisons une chose importante : l'exécution dans le désordre traite les accès mémoire à part. La majorité des processeurs OOO assez anciens exécutent les accès mémoire dans l'ordre, seules les µops entières/flottantes/branchements sont exécutées dans le désordre. Les processeurs datant d'après les années 2010 sont capable d'exécuter les accès mémoire dans le désordre, mais l'implémentation en question est assez particulière. Un chapitre entier sera dédié à l'exécution dans le désordre des µops mémoire. Nous allons volontairement mettre de côté la gestion des accès mémoire dans ce chapitre. ==Les fenêtres d’instruction : généralités== [[File:File de micro-opération.png|vignette|upright=1|File de micro-opérations]] Pour décrire comment est implémentée l'émission dans le désordre, il faut commencer par parler des processeurs sans. Les processeurs sans exécution dans le désordre ont une unité d'émission qui bloque tout le pipeline dès qu'une µop ne peut pas être émise. Pour limiter l'impact de ce blocage, quelques rares processeurs incorporent une '''file de micro-opération''', une mémoire FIFO qui met en attente les µops. Vu que c'est une mémoire FIFO, les µops sont émises dans l'ordre, à savoir l'ordre d'ajout, dans l'ordre de décodage. Le schéma ci-dessous illustre une telle file d'attente couplée à un ''scoreboard''. Sur le principe, l'exécution dans le désordre améliore la file de µops sur un point : ce n'est plus une mémoire FIFO. Les µops sont insérées dans l'ordre, mais peuvent sortir dans le désordre (être émises dans le désordre). La file de µops devient alors une '''fenêtre d'instruction''', terme traduit directement de l'anglais ''instruction Window''. Terme assez trompeur, car elles mettent en attente des µops, pas des instructions. Elles peuvent émettre des µops dans le désordre, ce qui fait que si une µop bloque le pipeline, les µops suivantes peuvent être émises. Si je commence le paragraphe précédent par "sur le principe", c'est car certaines techniques d'OOO utilisent des files de µops normales. Il est par exemple possible d'utiliser une file de µops avec une fenêtre d'instruction, plusieurs files de µops, plusieurs fenêtres d'instructions avec une file de µops annexe, etc. Dasn les grandes lignes, il existe dans les grandes lignes 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! File de µops améliorée |- ! Une seule "file de µops" | ''Scoreboard'' | Fenêtre d'instruction centralisée |- ! Plusieurs "file de µops" | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | Fenêtre d'instruction décentralisée |} ===La fenêtre d'instruction centralisée=== L'implémentation la plus simple de l'OOO utilise une unique '''fenêtre d'instruction'''. Les instructions décodées sont accumulées dans la fenêtre d'instruction, où elles attendent que leurs opérandes soient disponibles. La fenêtre d'instruction sert donc de file d'attente. Mais elle contient aussi une unité d'émission, qui détecte quelles µops sont prêtes à être émises. L'unité d'émission et la fenêtre d'instruction sont fusionnées ensemble, elles forment un seul circuit. Mais nous allons dire qu'elles sont conceptuellement séparées pour le moment. A chaque cycle, l'unité d'émission consulte la fenêtre d'instruction pour voir quelles µops peuvent s'exécuter, lesquelles ont leur opérandes de disponibles. La fenêtre d'instruction doit spécialement être conçue pour, c'est une sorte de mémoire associative très complexe, comme on le verra dans ce qui suit. [[File:OOO Issue.png|centre|vignette|upright=2.5|Exécution dans le désordre avec une fenêtre d'instruction]] Une fois qu'une µop sort du décodeur d'instructions, elle est ajoutée en parallèle dans la fenêtre d'instruction et le ROB. La raison est que les µops quittent la fenêtre d'instruction dans le désordre, et qu'elles doivent être remises en ordre par la suite. Le ROB s'occupe de cette remise en ordre, mais il a besoin de savoir dans quel ordre les µops sont censées être, et cet ordre est celui du décodage. Aussi, pour remplir le ROB, la seule opportunité est en sortie de l'unité de décodage. Dans le cas où une instruction est décodée en plusieurs micro-opérations, elles sont toutes insérées en même temps dans la fenêtre d'instruction et le ROB, en tenant compte de leur ordre. [[File:Fenêtre d'instruction.png|centre|vignette|upright=2|Fenêtre d'instruction.]] Les micro-opérations mémoire sont à part des autres, pour diverses raisons. Une de ces raisons est que les dépendances de données sont classées en deux types : les dépendances de registre et les dépendances d'adresse. Et les deux sont fondamentalement différentes. Autant on peut détecter les dépendances de registre lors de l'émission, autant c'est plus compliqué avec les dépendances d'adresse. De plus, rappelons que si les lectures peuvent s'exécuter dans le désordre, les écritures doivent s'exécuter dans l'ordre, ou du moins en donner l'illusion. Pour cela, le processeur remet les écritures dans l'ordre avec une sorte de mini-ROB intégré à l'unité mémoire, appelée la file d'écriture. Elle complémente le ROB, qui lui ne gère que les écritures dans les registres, mais les deux collaborent. La file d'écriture envoie une écriture à la mémoire RAM quand le ROB lui dit que c'est bon, les instructions précédentes sont terminées ''dans l'ordre du programme''. Les processeurs modernes ajoutent des techniques d'exécution dans le désordre des accès mémoire, mais nous les verrons dans un chapitre dédié. Elles permettent d'utiliser une fenêtre d'instruction unique, qui mémorise aussi les µops mémoire. Si elles sont mises en place, l'unité mémoire n'a pas besoin de file de µops séparée. L'idée est que les dépendances de registre sont traitées par la fenêtre d'instruction, mais que l'unité mémoire gére les dépendances d'adresse. Les dépendances d'adresse sont gérées par des techniques de ''désambiguation mémoire'', qui auront droit à un chapitre dédié. [[File:Processeur avec exécution dans le désodre des accès mémoire.png|centre|vignette|upright=2|Processeur avec exécution dans le désodre des accès mémoire]] Les processeurs assez anciens n'autorisaient pas d'exécution dans le désordre des accès mémoire. Concrétement, les accs mémoire devaient se faire dans l'ordre, mais les autres µops pouvaient être exécutées dans le désordre. Il s'agit donc d'un ordre entre µops mémoire, pas entre µops mémoire et autres µops. Les µops entières et flottantes pouvaient être exécutées avant une µops mémoire qui est avant elle dans l'ordre du programme, ce n'est pas un problème. Pour garantir l'ordre desd µops mémoire, l'unité mémoire est précédée par une file de micro-opérations séparée, pour forcer l'exécution dans l'ordre des accès mémoire. De plus, les µops mémoire ne peuvent pas utiliser la fenêtre d'instruction. Dit autrement, la fenêtre d'instruction ne mémorise pas de µops mémoire. Après le décodage, les µops sont réparties soit dans la file de µops mémoire, soit dans la fenêtre d'instruction. Le décodeur classe les µops suivant que ce sont des µops mémoire ou non, et les envoient à la bonne destination. Dans ce chapitre, on supposera que c'est cette solution qui est utilisée. [[File:Processeur avec émission dans l'ordre des accès mémoire.png|centre|vignette|upright=2|Processeur avec émission dans l'ordre des accès mémoire]] La solution précédente revient à scinder la fenêtre d'instruction en deux : une file de µops pour les µops mémoire, une fenêtre d'instruction pour les autres µops. Et cette scission peut aller plus loin, à savoir qu'on peut scinder une fenêtre d'instruction encore et encore. Ce qui nous amène à la section suivante. ===Les fenêtres d'instruction décentralisées=== Nous venons de voir qu'il est possible de scinder la fenêtre d'instruction en plusieurs fenêtres d'instruction plus petites, plus "spécialisées" : une pour les µops mémoire, simplifiée en une file de µops classique, et une autre pour les autres instructions. Sachez qu'il est possible d'aller plus loin, par exemple en séparant la fenêtre d'instruction en une fenêtre spécialisée dans les µops flottantes et une autre pour les µops entières. Et ce n'est là qu'un exemple parmi de nombreuses autres possibilités. Pour faire la différence avec une fenêtre d'instruction unique, nous allons parler de fenêtre d'instruction centralisée s'il n'y en a qu'une, de '''fenêtre d'instruction décentralisée''' s'il y en a plusieurs. Il est possible d'associer chaque fenêtre d'instruction à un type précis de µops. Par exemple, avec une fenêtre d'instruction pour les µops de calcul entières, une autre pour les µops flottantes, une autre pour les µops mémoire. Il s'agit d'un choix simple et efficace, mais quelques processeurs font autrement, pour répondre à des contraintes très diverses. Un autre exemple : les processeurs Intel de microarchitecture Skylake utilisent une fenêtre d'instruction pour les opérations entières/flottantes, et une fenêtre d'instruction séparée pour les µops mémoire. Il s'agit bien d'une fenêtre d’instruction, le processeur utilise l'exécution dans le désordre des accès mémoire. Un avantage est que les deux fenêtres d'instructions sont plus spécialisées, ce qui entraine des économies de circuit. Les opérations entières/flottantes ont besoin de deux registres pour les opérandes et d'un autre résultat, alors que les µops mémoire n'ont besoin que de deux registres maximum. En utilisant une fenêtre d'instruction unique, chaque entrée doit mémoriser l'opcode et trois registres, dont un est inutilisé pour les µops mémoire et les branchements. En utilisant des fenêtres d’instructions séparées, celle pour les µops entières/flottantes a trois registres par entrée, contre seulement deux registres par entrée pour celle des µops mémoire. Il est possible d'utiliser une fenêtre d'instruction pour les opérations flottantes et une autre pour les autres µops (µops entières et parfois mémoire avec). L'avantage est que cela simplifie grandement le processeur. Les flottants sont gérés à part des entiers. Ils ont leurs propres registres, des FPU séparées des ALU entières, bref : la séparation est complète. Utiliser une fenêtre d'instruction séparée va dans ce sens. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Un cas extrême est celui où chaque ALU a sa propre fenêtre d'instruction. Nous parlerons alors de '''fenêtres d'instruction totalement décentralisées'''. Un exemple historique est celui de la fpu de l'IBM 360 modèle 90. Elle disposait d'un additionneur flottant, d'un multiplieur flottant, et d'une unité mémoire pour les lectures/écritures flottantes. Les trois unités avaient leur propre fenêtre d'instruction. Les processeurs AMD utilisent beaucoup cette technique, contrairement à Intel qui préfère utiliser des fenêtres centralisées sur les anciens processeurs, deux ou trois fenêtres sur les processeurs récents (2020 et plus). L'usage de fenêtres décentralisées simplifie la répartition des µops sur les unités de calcul. Par exemple, utiliser des fenêtres séparées pour les ALU et les FPU facilite la répartition des instructions de calcul sur les ALU. Une fenêtre centralisée demande de faire la différence entre instruction entière/flottante, puis de choisir sur quelle unité de calcul entière/flottante utiliser. Une fenêtre décentralisée fait les deux choix séparément : d'abord on envoie l'instruction dans la bonne fenêtre suivant si c'est une instruction flottante ou entière, et ensuite on gère la disponibilité des ALUs/opérandes. Et on peut adapter la même idée en séparant les unités d'accès mémoire des ALU entières, etc. Par contre, un défaut est que certaines fenêtres d'instruction peuvent être sous-utilisées. Par exemple, la station de réservation flottante est inutilisée si le programme n'exécute pas d'opérations flottantes. Ou encore, les fenêtres pour les accès mémoire peuvent être sous-utilisées, si le programme effectue peu d'accès mémoire relativement aux autres instructions. En fait, tout dépend de comment sont calibrées les fenêtres d'instruction et de la répartition des instructions dans le programme entre opérations entières, flottantes, mémoire. Par exemple, si un programma de deux fenêtres d'instructions identiques, une pour les calculs entiers et une autre pour les calculs flottants, elles ne seront utilisées à la perfection que si la moitié des instructions du programme fait des calculs flottants et l'autre des calculs entiers. Toute déviation par rapport à cette répartition idéale risque de laisser des entrées vides dans une fenêtre d’instruction. Un point important est que l'émission est découpée en deux étages avec des fenêtres d'instruction décentralisées. La première étape envoie l'instruction décodée vers la fenêtre d'instruction adéquate, la seconde gère l'émission proprement dit. La première est l'étage de ''dispatch'' qui envoie l'instruction dans la fenêtre d’instruction adéquate, selon que c'est une instruction flottante, entière, autre. La seconde est l'étage de ''scheduling'', qui gère la disponibilité des opérandes et des unités de calcul. En clair, on trie les instructions suivant leur type, suivant le type d'unité de calcul adéquate, puis on l'émet proprement dit. Faire ainsi a plusieurs avantages, avec cependant peu d'inconvénients. Lors de l'étape de ''dispatch'', l'instruction émise est ajoutée au tampon de réordonnancement, s'il existe. Sans cela, impossible de conserver l'ordre des instructions. Les instructions sont émises dans l'ordre au niveau de l'unité de ''dispatch'', pas au niveau de l'étage de ''scheduling''. Aussi, pour remplir le ROB, cela doit se faire au dernier moment où les instructions sont émises dans l'ordre, soit en sortie de l'unité de ''dispatch''. De plus, les micro-opérations mémoire sont traitées à part des autres, elles sont envoyées directement à l'unité mémoire. La gestion des calculs d'adresse est quelque peu complexe, mais ils peuvent être fait soit dans l'unité mémoire, soit dans les ALU entières, peu importe. Il y a aussi un système de contournement complexe entre ALU/FPU et unité mémoire, qui n'est pas représenté dans le schéma ci-dessous. Il faut noter que quelques processeurs utilisent des méthodes intermédiaires entre les trois solutions précédentes. Par exemple, les processeurs AMD Zen utilisent une fenêtre d'instruction décentralisée un peu particulière. Les unités de calcul entières disposent d'une fenêtre d'instruction rien que pour elles, sur ce processeur. Les instructions flottantes sont quant à elles alimentées par une file de micro-opération, pas une fenêtre d'instruction ! La raison à ce choix est un compromis entre performance et cout en circuit. L'exécution dans le désordre est peu efficace sur les instructions flottantes, car les CPU n'ont que peu d'ALU flottantes séparées. Vu le cout en circuits d'une fenêtre d'instruction, les concepteurs du processeur ont préféré utiliser une file de micro-opération pour les opérations flottantes. ===L'usage de plusieurs files d'instruction=== Une dernière méthode d'OOO utilise plusieurs files de micro-opération. L'idée est qu'une fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement une file de micro-opération pour les opérations entières, une autre pour les opérations flottantes, une autre pour les accès mémoire. D'autres processeurs utilisent une file pour les accès mémoire et une autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. La présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que la technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si une dépendance bloque une FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans une autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer la disponibilité des registres. Quand un registre est lu ou écrit par une instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. La logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : une pour les instructions d'accès mémoire et une autre pour les autres instructions. Si jamais une instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de la lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'une est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est la file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. ===Avantages et inconvénients de chaque implémentation=== Un processeur contient soit une fenêtre d'instruction unique, soit plusieurs fenêtres d'instruction séparées. Typiquement, les fenêtres d’instruction séparées sont spécialisées, dans le sens où on a une fenêtre pour les instructions flottantes, une autre pour les instructions entières, une autre pour les accès mémoire, etc. Pour résumer, on a le choix entre une grosse fenêtre généraliste et plusieurs fenêtres spécialisées, sauf que la fenêtre centralisée est lente et complexe, contrairement aux fenêtres spécialisées. Les deux méthodes ont des inconvénients et des avantages différents. Dans les grandes lignes, l'avantage des fenêtres décentralisées est qu'elles sont plus petites qu'une grosse fenêtre d'instruction. Cela simplifie la gestion du contournement et de la répartition des instructions sur les unités de calcul, comme on le verra dans quelques paragraphes. Elles sont donc moins complexes et plus rapides. L'autre avantage, c'est qu'il est possible de démarrer l'exécution de plusieurs instructions simultanément : une instruction par fenêtre décentralisée, contre une par fenêtre d'instruction. Mais les fenêtres décentralisées sont souvent sous-utilisées, partiellement remplies, contrairement aux fenêtres d'instruction. Il arrive qu'une fenêtre d'instruction soit remplie, alors que les autres sont vides. Par exemple, prenons un processeur avec une fenêtre d'instruction reliée à la FPU, et une autre reliée aux autres ALUs. Si le processeur n'exécute que des opérations flottantes, la fenêtre reliée à la FPU sera pleine, alors que l'autre sera vide. L'exécution des instructions dans le désordre est alors limitée par la petite taille de la fenêtre, qui ne peut plus accepter de nouvelle instruction flottante. Avec une fenêtre unique, on n'aurait pas eu ce problème : on aurait eu une énorme fenêtre d'instruction remplie d'instruction flottante, au lieu d'une petite fenêtre spécialisée. Il est maintenant temps de voir en quoi sont faites les fenêtres d’instruction, qu'elles soient centralisées ou décentralisées. Nous allons aussi voir quelle est la logique d'émission associée. ==L'implémentation d'une fenêtre d'instruction : généralités== Une fenêtre d'instruction est une mémoire qui mémorise des micro-opérations. Elle est cependant plus complexe qu'une mémoire RAM ou qu'une FIFO et ressemble un petit peu à une mémoire cache. Elle dispose d'un port d'écriture et d'un port de lecture, au minimum. Le port d'écriture permet à l'unité de décodage d'insérer une micro-opération dedans, d'ajouter la micro-opération qui vient d'être décodée. Si une instruction machine est décodée en plusieurs micro-opération, deux possibilités. La première est de les insérer un par un, ce qui fait qu'on peut se contenter d'un seul port d'écriture. L'autre possibilité est de les ajouter en même temps, ce qui demande plusieurs ports d'écriture. Le port de lecture sert à émettre une instruction. On part du principe que la fenêtre d'instruction ne peut émettre qu'une seule instruction à la fois, car les processeurs que nous avons vu précédemment sont de ce type. Mais nous verrons dans quelques chapitre qu'il existe des processeurs dits superscalaires, qui sont capables d'émettre plusieurs instructions par cycle. Dans ce cas, la fenêtre d'instruction a un seul port de lecture. Un processeur superscalaire, quant à lui, doit avoir un port de lecture par unité de calcul, ce qui fait beaucoup plus. ===Les entrées d'une fenêtre d’instruction=== Les fenêtres d'instruction sont composées d''''entrées''', des mots mémoire qui stockent une instruction. Une instruction réserve une entrée après son décodage et la libère dès qu'elle est envoyée aux unités de calcul. Une entrée contient l'opcode (les signaux de commande à envoyer à l'ALU), le registre de destination du résultat, les registres de chaque opérande, et éventuellement des signaux de commande en plus. De plus, chaque opérande est couplée à un bit de disponibilité, qui indique si elle est disponible. Quand un opérande est écrit dans les registres, le bit de présence correspondant est mis à jour. Enfin, chaque entrée possède un bit ''empty'' qui indique si elle est vide, cette information étant utile pour réserver des entrées. [[File:Entrée d'une station de réservation - sans les tags.png|centre|vignette|upright=3|Entrée d'une fenêtre d'instruction]] Nous verrons dans quelques chapitres que certaines fenêtres d'instruction sont capables de mémoriser les opérandes des instructions. De telles fenêtres d'instruction seront appelées, dans ce cours, des '''stations de réservation'''. Les entrées des stations de réservation sont assez semblables à celle des fenêtres d'instruction, à un détail près : les opérandes de l'instruction sont enregistrées directement dans des champs séparés. Il y a deux champs, un par opérande, pour stocker l'opérande elle-même, lue depuis les registres ou obtenue via le réseau de contournement. Notons que les champs pour les opérandes viennent en plus des champs pour les noms de registres, encore que les deux peuvent être fusionnés si on veut optimiser le tout. [[File:Entrée d'une station de réservation.png|centre|vignette|upright=3|Entrée d'une station de réservation.]] Précisons que la terminologie n'est pas très fiable. Les termes "fenêtre d'instruction" et "station de réservation" ne regroupent pas du tout la même chose d'un papier de recherche à l'autre, d'un bouquin à l'autre, d'un chercheur à l'autre, d'un ingénieur à l'autre, d'un professeur à l'autre. Le terme initial vient pourtant de l'article original sur l'algorithme de Tomasulo, où il désignait une fenêtre d'instruction associée à une unité de calcul précise. Mais le terme a ensuite été réutilisé, ce qui fait que certains processeurs avec plusieurs unités de calcul sont décrit comme ayant une unique station de réservation. En bref : c'est le bazar ! Mais nous en reparlerons dans le chapitre sur le renommage de registres, car c'est la place idéale pour les aborder. Toujours est-il que j'ai fait le choix de confondre les concepts de fenêtre d'instruction et de station de réservation avec les concepts de '''lecture avant émission''' et de '''lecture après émission'''. La différence entre les deux est que les registres sont lus après émission avec une fenêtre d'instruction, avant avec des stations de réservation. Dans le cas "avant émission", les opérandes sont mémorisées dans la station de réservation. Et cette différence a une influence sur le pipeline du processeur, le banc de registres et tout ce qui s'en suit. Un désavantage de la lecture avant émission est qu'il faut stocker les opérandes après lecture, ici dans les stations de réservation. Mais un avantage est que le banc de registre a besoin de moins de ports de lecture, car une bonne partie des opérandes sont fournies par le système de contournement. Nous verrons cela dans le détail dans le chapitre sur les processeurs superscalaires. Il a été proposé de fusionner le tampon de ré-ordonnancement avec la fenêtre d'instruction dans une structure unique. La méthode a notamment été utilisée sur les processeurs d'architecture K6 d'AMD. Le tout donnait une structure appelée le '''DRIS''' (''deferred scheduling register renaming instruction shelf''). La différence avec une fenêtre d’instruction normale est que les entrées sont libérée non pas quand l'instruction est exécutée/émise, mais quand elle termine son exécution et quitte le ROB. La fenêtre d'instruction doit alors incorporer des bits pour savoir si telle entrée a émis sont instruction ou non. ===La logique d'éveil et de sélection=== Dans le cas qui va suivre, on suppose que le processeur ne peut émettre qu'une instruction à la fois. Chaque cycle, une instruction est sélectionnée et est envoyée dans le chemin de données, soit à une ALU, soit à une unité d'accès mémoire. La sélection d'une instruction est effectuée par l'unité d'émission, qui est aussi appelée le '''''scheduler'''''. Elle gère la disponibilité des opérandes et la disponibilité des unités de calcul adéquate. Le choix de l'instruction émise doit être le plus pertinent possible, pour des raisons de performances. Pour le premier point, l'unité d'émission détermine quelles instructions sont candidates pour l'émission. Les ''instructions candidates'' sont celles dont tous les opérandes sont prêts. Le processeur contient un circuit qui détecte les instructions candidates : la '''logique d’éveil''' (''wake-up logic''). Une fois que la logique d'éveil a fait son travail, une instruction est choisie pour s’exécuter en fonction de la disponibilité des unités de calcul adéquates. Ce rôle est dévolu à un circuit qu'on appelle la '''logique de sélection''', ou ''select logic''. [[File:Fonctionnement complet de la logique d’émission.jpg|centre|vignette|upright=1.5|Fonctionnement complet de la logique d’émission.]] La logique de sélection doit gérer le fait que les unités de calcul du processeur ne sont pas toutes identiques. Déjà, un processeur a généralement des unités séparées pour les instructions entières et flottantes, des unités spécialisées dans les accès mémoire, parfois des unités spécialisées pour les branchements. Une instruction doit être attribuée à la bonne unité de calcul, on ne doit pas envoyer une instruction entière dans une unité de calcul flottante. De plus, parmi les unités de calcul entières, toutes ne sont pas identiques. Par exemple, il est fréquent d'avoir plusieurs unités de calcul spécialisées dans les opérations simples (additions, soustractions, opérations logiques) avec une unité pour les multiplications/divisions séparées, parfois une unité spécialisée pour les décalages/rotations, etc. Là encore, allouer la bonne instruction à la bonne ALU est complexe. Plus les unités de calcul sont hétérogènes, plus la logique de sélection est compliquée. Les logiques d'éveil comme de sélection sont assez complexes. Comme on le verra plus bas, la logique de sélection la plus simple, qui gère une seule unité de calcul, est basée sur un encodeur à priorité couplé à d'autres circuits. Et pour gérer plusieurs ALUs, il faut mettre des encodeurs en cascade. Le résultat est que même en prenant une logique de sélection simple, elle sera assez lente et gourmande en circuits. Aussi, la logique de sélection met souvent un cycle d'horloge entier pour faire son travail, elle a son propre étage de pipeline attribué. La logique d'éveil est dans le même cas, ce qui fait qu'émettre une micro-opération demande deux cycles d'horloge. Le défaut est que cela rajoute des cycles d'horloges entre la fenêtre d'instruction et l'ALU, ce qui complique la gestion du pipeline. Ces cycles de retard sont à prendre en compte au moment d'émettre les instructions, les ''scheduler'' doit en tenir compte pour des performances optimales. Sans tenir compte de ces cycles de retard, les instructions arrivent en retard de quelques cycles à l'ALU, cycles de retard durant lesquels l'ALU n'a pas fait de calcul et a été sous-utilisée, sans compter que le système de contournement n'est pas utilisé au mieux. Et le problème est encore plus important sur les processeur avec des stations de réservation, qui utilisent la "lecture après émission" : cela rajoute un cycle d'horloge en plus, un temps de retard en plus. ===La logique d'éveil : l'émission anticipée=== La logique d'éveil doit tenir compte du fait qu'il y a plusieurs étages entre l'émission et l'exécution sur une unité de calcul. Par exemple, un processeur a souvent entre un et à cinq étages entre la file d'attente et les unités de calcul. Il faut lire les registres, gérer le contournement, et cela peut prendre quelques cycles d'horloge. Sur le Pentium 4, on trouve 6 étages entre la fenêtre d’instruction et l'entrée de l'ALU. Si les micro-opérations sont émises quand les opérandes sont disponibles, il y aura un délai de quelques cycles avant qu'elles atteignent l'ALU. Alors qu'idéalement, on souhaiterait que la micro-opération atteigne l'ALU dès que ses opérandes sont disponibles, pour profiter des techniques de contournement. Pour cela, la logique d'éveil émet les instructions quelques cycles en avance pour qu'elles arrivent au bon moment. Il s'agit d'une technique d''''émission anticipée''', dont nous avions parlé dans le chapitre sur le contournement. : Il faut noter que le problème se pose plus avec des fenêtres d'instruction qu'avec des stations de réservation. Les premières ont un étage en plus entre émission et ALU, vu qu'il faut lire des registres après l'émission. L'émission anticipée demande d'émettre un signal d'éveil en avance de quelques cycles, pile au bon moment. Par exemples, si on a deux étages entre l'ALU et l'unité d'émission, le signal de réveil sera généré deux cycles avant que le résultat soit effectivement calculé. L'implémentation varie, mais deux solutions sont possibles. La première est de générer le signal d'éveil dans l'ALU, ce qui n'a de sens que pour les opérations comme les multiplications ou les divisions, qui prennent plusieurs cycles. Une autre technique génère le signal de réveil dans une structure centralisée, spécialisée dans la génération des signaux d'éveil. L'unité de composée d'un registre à décalage par registre. Imaginons qu'une instruction est émise, que cette instruction mette N cycles à s'exécuter, et qu'elle écrive dans un registre de destination. L'unité sélectionne alors le registre à décalage associé au registre de destination, et met le bit numéro N à 1. Le registre décalé d'un cran à chaque cycle. Quand le bit sortant est un 1, alors le signal de validité pour l'opérande est généré. L'émission anticipée marche bien si l'instruction a une durée fixe, connue à l'avance. Et autant c'est le cas pour les instructions arithmétiques et logiques, autant ce n'est pas le cas pour les accès mémoire. Les accès mémoire ont une latence variable : quelques cycles pour un succès de cache, plusieurs dizaines de cycles pour un défaut de cache L1, pas loin de la centaine pour un défaut de cache L2, etc. Et cela pose des problèmes pour l'émission anticipée. L'émission en avance pour les accès mémoire est purement spéculative : le processeur émet des instructions en supposant que la lecture entrainera un succès de cache, quitte à annuler l'instruction en cas de défaut de cache. Mais faire ainsi demande non seulement d'annuler les instructions émises en avance, mais aussi de ne pas retirer les instructions émises en avance de la fenêtre d'instruction. Elles sont émises, mais une copie de sauvegarde est conservée dans la fenêtre d'instruction. Si le processeur détecte un défaut de cache, il peut alors ré-exécuter l'instruction. S'il détecte un succès de cache, les instructions lecture-dépendante sont retirées de la fenêtre d'instruction, la copie de sauvegarde est devenue inutile et est donc jetée. ===La logique de sélection : âge ou position ?=== La logique de sélection est primordiale pour de bonnes performances. Il existe deux méthodes principales pour sélectionner l'instruction à exécuter. La première est la plus simple : elle se base sur lé numéro de l'entrée. En effet, une fenêtre d'instruction est avant tout une sorte de mémoire, un mix entre mémoire associative, mémoire RAM, et FIFO. Et chaque entrée a un numéro, une adresse mémoire. Nous parlerons de numéro dans ce qui suit, car ce sera plus simple, le terme d'adresse mémoire étant peut-être un peu exagéré dans le contexte des fenêtres d'instruction. Toujours est-il que la fenêtre d'instruction est adressable dans le sens où on peut lui envoyer le numéro de l'entrée voulue, et la fenêtre d’instruction renvoie le contenu de l'entrée sur son port de lecture. Et c'est ce que fait la logique de sélection : elle génère le numéro de l'entrée à lire. Le numéro est alors envoyé sur l'entrée d'adresse de la fenêtre d’instruction, et elle fournit la micro-opération associée sur son port de lecture, son '''port d'émission'''. La première méthode de sélection, donc. Elle est basée sur sur le numéro de l'entrée. Si plusieurs entrées sont éveillées, la logique de sélection prend celle avec le plus petit numéro. Elle porte le nom de '''sélection par position''', sous-entendu position dans la fenêtre d'instruction. Vous l'avez peut-être deviné, mais la logique de sélection est alors un encodeur à priorité. Le circuit de sélection ne se résume donc pas seulement à un encodeur à priorité, mais c'est le circuit central. L'avantage d'une telle méthode de sélection est qu'elle est simple à implémenter : un encodeur à priorité est un circuit connu, facile à implémenter. Mais on remarque un défaut : un encodeur est un circuit assez rapide, mais qui utilise beaucoup de transistors, beaucoup de portes logiques, surtout si on veut qu'il soit rapide. Ce qui explique que la logique de sélection ait son propre étage de pipeline rien que pour elle. La seconde méthode s'appelle la '''sélection par âge''', au nom assez transparent. L'idée est de privilégier l'émission de l'instruction la plus ancienne. Elle demande que la fenêtre d'instruction trie les micro-opérations par ordre d'insertion dans la fenêtre d'instruction, ce qui en fait une pseudo-FIFO. Le tri est partiel, car les instructions peuvent sortir de la fenêtre d’instruction à tout moment. Compacter la fenêtre d'instruction, à savoir regrouper toutes les entrées valides est une idée, mais elle est compliquée à implémenter. Aussi, elles préfèrent encoder des informations sur l'ordre d'émission dans chaque entrée. L'encodeur à priorité doit alors travailler non pas sur des nombres entiers liés à l'ordre d'insertion dans la pseudo-FIFO. Elle est encore plus gourmande en circuits que la méthode précédente. Les processeurs haute performance utilisent souvent des méthodes hybrides. Par exemple, les processeurs AMD de microarchitecture Bulldozer utilisaient une méthode intermédiaire. Ils utilisaient une fenêtre d'instruction couplée à un encodeur à priorité pour la sélection par position, mais complémentaient le tout avec une unité qui mémorisait l'instruction la plus ancienne dans la fenêtre d’instruction. Le mécanisme de sélection par âge était utilisé en priorité. Mais si l'instruction la plus ancienne n'était pas prête, le processeur basculait sur le mécanisme de sélection par position. ===La compaction des fenêtres d'instruction=== À chaque cycle, les instructions décodées sont ajoutées dans la fenêtre d'instruction, dans des entrées vides. Vu que les instructions quittent celle-ci dans le désordre, ces vides sont dispersés dans la fenêtre d'instruction, ce qui pose problème pour déterminer où placer les nouvelles instructions. La solution la plus triviale consiste à conserver une liste des vides, mise à jour à chaque insertion ou émission d'instruction. Une autre solution consiste à éliminer les vides en compactant la fenêtre d'instruction à chaque cycle d'horloge. Des circuits se chargent de détecter les vides et de regrouper les instructions en un unique bloc. Il faut signaler que certaines processeurs arrivent à se passer de cette étape de compactage, mais au prix de fenêtres d'instruction nettement plus complexes. Autre problème : quand il faut choisir quelle instruction émettre, il y a toujours plusieurs candidats. Si on choisit mal, des instructions restent en attente trop longtemps parce que d'autres instructions plus jeunes leur passent devant. Pour éviter cela, les instructions les plus vielles, les plus anciennes, sont prioritaires. Pour cela, on peut utiliser une FIFO un peu spéciale pour la fenêtre d'instruction. Si les ajouts d'instruction se font dans l'ordre, les instructions ne quittent pas forcément la fenêtre d'instruction dans l'ordre imposé par une FIFO : les instructions restent triées dans leur ordre d'ajout, même s'il y a des vides entre elles. Dans ces condition, il est préférable que le compactage conserve l'ordre FIFO des instructions. Dans ces conditions, l'instruction la plus ancienne est celle qui est située à l'adresse la plus faible : le circuit de sélection peut donc être fabriqué avec des encodeurs, et est relativement simple. ==Les fenêtres d'instruction basées sur une matrice de dépendances== L'implémentation la plus simple étend le fonctionnement d'un pipeline dynamique usuel. Rappelez-vous le chapitre sur les pipeline dynamiques. Nous avions vu que de tels pipelines émettaient une instruction par cycle, quitte à émettre des bulles de pipeline en cas de dépendance bloquante. Et il est possible d'améliorer leur unité d'émission pour qu'elle soit compatible avec l'exécution dans le désordre. ===Rappels sur le registre de réservation/disponibilité=== L'émission d'une instruction est gouvernée par un ''registre de réservation'' qui indique quels registres sont réservés par une instruction, et ceux qui sont libres. Un registre réservé est un registre qui sera écrit par une instruction en cours d'exécution, mais qui n'a pas encore écrit son résultat. Les instructions candidates doivent avoir leurs opérandes dans des registres libres. Sinon, c'est signe que leurs opérandes sont réservées en écriture, donc pas encore écrites, donc pas disponibles. Si une instruction candidate veut lire ce registre, c'est signe qu'il y a une dépendance RAW : elle veut lire un registre réservé, qui est destiné à être écrit par une instruction en vol. Si elle veut écrire, c'est signe qu'elle veut écrire dans un registre où une autre instruction veut écrire : c'est une dépendance WAW. Dans les deux cas, l'instruction n'est pas émise. Le registre de réservation encode les registres réservés comme suit : chaque bit est associé à un registre. Le bit numéro 0 est associé au registre numéro 0, le bit numéro 1 au registre numéro 1, etc. Là, En clair, les numéros de registres réservés sont encodés en représentation non pas binaire, mais en représentation ''one-hot'' (vue au premier chapitre). {|class="wikitable" |+ Registre de réservation |- ! Registre 7 !! Registre 6 !! Registre 5 !! Registre 4 !! Registre 3 !! Registre 2 !! Registre 1 !! Registre 0 |- | 0 || 0 || 1 || 0 || 0 || 1 || 0 || 0 |} Avant d'émettre une instruction, l'unité d'émission extrait les registres opérande/destination et les convertis dans la même représentation que le registre de réservation, à savoir en représentation ''one-hot''. Le circuit de traduction binaire vers ''one-hot'' est, pour rappel, un simple décodeur. Puis, on fait un OU logique entre les sorties des décodeurs. Le résultat est un masque qui indique quels registres sont lus par l'instruction, encodé en représentation ''one-hot''. Appelons-le le '''masque d'opérandes'''. Le masque est alors comparé au registre de réservation pour vérifier si l'instruction peut être émise. [[File:Unité d'émission simple, dans l'ordre.png|centre|vignette|upright=2|Unité d'émission simple, dans l'ordre]] Si l'émission est autorisée, le registres de réservation est là aussi mis à jour. Le registre de réservation est aussi mis à jour dès qu'une instruction enregistre son résultat dans les registres, ou alors dès qu'il est disponible pour le contournement. Le bit associé au registre repasse alors à 0 (ou à 1). Sans contournement, la mise à jour se fait alors à la toute fin de l'instruction, quand elle se termine, lors de la dernière étape d'enregistrement, à la fin de son pipeline. Avec, elle se fait quand l'instruction quitte l'unité de calcul. ===L'extension à l'exécution dans le désordre : l'éveil par matrice de bits=== La différence entre un pipeline dynamique et l'exécution dans le désordre est que l'on passe d'une instruction à émettre à plusieurs. Plusieurs instructions sont mises en attente dans une fenêtre d’instruction, et y attendent leur tour. L'idée est alors d'envoyer le registre de disponibilité à toutes les entrées, à toutes les instructions en attente. Ainsi, on sait quelles sont les instructions qui peuvent s'exécuter et celles qui ne le peuvent pas. L'implémentation est assez simple, elle ressemble beaucoup à l'implémentation d'un pipeline dynamique simple, si ce n'est que des circuits sont dupliqués. L'implémentation utilise des fenêtres d'instruction légèrement différentes de celles introduites plus haut. Elles n'utilisent notamment pas de bits de disponibilité, mais autre chose. Lorsqu'une instruction est ajoutée à la fenêtre d'instruction, le masque de disponibilité des opérandes est stocké dans la fenêtre d'instruction. A chaque cycle, le registre de disponibilité est envoyée à toutes les entrées, et est comparé avec tous les masques de disponibilité des opérandes. Si une comparaison renvoie un 1, alors l'instruction de l'entrée est une instruction candidate à l'émission. [[File:Unité d'émission dans le désordre basée sur un registre de disponibilité.png|centre|vignette|upright=2.5|Unité d'émission dans le désordre basée sur un registre de disponibilité]] L'ensemble est implémenté avec l'aide d'une '''matrice de bits''', où chaque ligne correspond à une entrée et chaque colonne à un registre. À chaque croisement entre une ligne et une colonne, on trouve un bit. Si le bit de la ligne n et de la colonne m est à 1, cela veut dire : l'instruction dans l'entrée n a besoin de lire le registre m. S’il est à 0, alors cela veut dire que l'instruction stockée dans la ligne n n'a pas besoin de la donnée dans le registre m. [[File:Planificateur à matrice de bits.jpg|centre|vignette|upright=2|Planificateur à matrice de bits.]] Lorsqu'une instruction réserve une entrée, elle initialise la ligne en fonction des registres qu'elle souhaite lire. Pour vérifier si une instruction a ses opérandes prêts, le processeur compare le registre de disponibilité à la ligne associée à l'instruction/entrée. A chaque intersection ligne-colonne, se trouve un comparateur de 1 bit, qui détecte si le registre est demandé et disponible. Les résultats de cette porte sont ensuite envoyés à une porte ET, qui fait le gros du travail. [[File:Logique de détection de la disponibilité d'une instruction.jpg|centre|vignette|upright=2|Logique de détection de la disponibilité d'une instruction.]] ==Les fenêtres d'instruction basées sur une mémoire associative== Les processeurs modernes utilisent une mémoire associative pour la fenêtre d'instruction. Les mémoires associatives ont été abordées il y a quelques chapitres, mais faisons quelques rappels. Les mémoires associatives servent à accélérer la recherche de données dans un ensemble. Or, une fenêtre d'instruction vérifie régulièrement si chaque entrée est prête. Il s'agit d'un processus de recherche d'une instruction qui respecte une condition bien précise dans la mémoire, ce qui fait que les mémoires associatives sont donc tout indiquées. Comme vous le savez, les signaux de commande d'une instruction sont propagés avec celle-ci dans le pipeline, le nom du registre de destination ne faisant pas exception. Le nom de registre est envoyé à la fenêtre d'instruction lors de l'écriture du résultat dans les registres. S'il y a correspondance, l'opérande est disponible et son bit de disponibilité est mis à 1. On peut adapter cette méthode pour tenir compte du contournement assez simplement. [[File:Détection des dépendances par propagation du registre de destination.png|centre|vignette|upright=2|Détection des dépendances par propagation du registre de destination.]] En conséquence, le circuit de détection des dépendances est constitué d'un grand nombre de comparateurs : un par champ « nom de registre » dans chaque entrée. La logique d'éveil/''wake up'' regroupe tous les comparateurs, la logique de sélection est un circuit situé en-dehors de la mémoire associative. Les entrées sont dans la mémoire associative elle-même. [[File:Gestion des bits de validité.png|centre|vignette|upright=2|Gestion des bits de validité.]] L'implémentation la plus simple est celle du schéma précédent, où on utilise une mémoire associative unique. Une version plus élaborée sépare la fenêtre d'instruction en deux parties : une mémoire qui mémorise les registres des opérandes, une autre mémoire pour le reste. La mémoire pour les registres opérandes est la mémoire associative proprement dite, c'est elle qui est associées aux comparateurs, à la logique de ''wake-up''/réveil, etc. Par contre, l'autre mémoire est une mémoire RAM simplifiée, qui mémorise les informations qui n'ont pas besoin des comparateurs. L'opcode de l'instruction est là-dedans, par exemple. ===Les optimisations de la consommation d'énergie : la désactivation des portions inutilisées=== Le problème avec des fenêtres d'instruction de ce type est leur forte consommation énergétique, ainsi que le grand nombre de portes logiques utilisées, qui deviennent prohibitif pour des fenêtres d'instruction un peu grosses. Pour résoudre ce problème, certains ont optimisé les comparateurs. D'autres ont tenté de profiter du fait que la majorité des bits dans les entrées sont composés de zéros. Bref, les optimisations purement matérielles sont légion. Une première solution est de désactiver les entrées qui sont inutilisées, vides, sans instruction. Pour cela, on fait précéder les comparateurs par un circuit qui les connecte ou déconnecte des lignes de bit. Le circuit est commandé par le bit ''empty'' qui indique si une entrée est vide ou non. L'avantage est que la consommation d'énergie de la fenêtre d'instruction devient alors proportionnelle au nombre d'entrées non-vides, et non au nombre d'entrées total. Du moins, en apparence, les entrées non-utilisées doivent quand même être alimentées pour fonctionner, mais l'activité de comparaison disparait dans les entrées vides. Il est possible d'étendre cette technique aux entrées dont les opérandes sont prêtes. Les gains sont généralement assez bons, avec une réduction de consommation variant entre 30 et 50%, avec une implémentation très simple et très économe en circuits. Une autre solution, assez simple à mettre en place, consiste à désactiver une partie de la fenêtre d'instruction sin elle est inutilisée. Pour cela, il faut segmenter la fenêtre d'instruction avec la technique du ''wire partitionning''. Pour rappel, une fenêtre d'instruction est une mémoire associative. Et comme toute mémoire associative, elle contient des fils, les lignes de bit, qui relient les entrées/sorties à toutes les cellules mémoire. Plus une ligne de bit est longue, plus elle consomme d'énergie et plus le temps de lecture/écriture est long. L'idée est de segmenter les lignes de bits en plaçant des répéteurs qui recopient la tension d'un segment au suivant. Les répéteurs sont des tampons trois-états, ce qui permet de déconnecter les portions inutilisées de la ligne de bit. Ce faisant, la fenêtre d'instruction est découpée en segments, qui peuvent être désactivés si besoin. Si il y a peu d'instructions chargées dans la fenêtre d'instruction, les portions inutilisées sont désactivées. La technique marche d'autan mieux si les instructions sont compactées au début de la fenêtre d'instruction. [[File:Wire partitionning.png|centre|vignette|upright=2|Wire partitionning]] Tout le problème est de savoir quelles portions désactiver. La technique est assez simple si la fenêtre d'instruction est compactée, à savoir si toutes les instructions sont régulièrement regroupées au début de la mémoire CAM. Mais même avec cette optimisation, la décision de désactiver une portion de la fenêtre d'instruction n'est pas à prendre à la légère. Il ne faut pas désactiver une portion contenant des instructions pouvant être émise sous peu. La décision dépend de paramètres variés : proportion d'entrée vides, quantité d'entrées récemment activées/désactivées récemment, présences d'entrées avec un ''match'' d'opérandes récent, etc. Il est important de préciser que les techniques en question fonctionnent aussi sur les autres types de fenêtre d'instruction, qui ne sont pas basées sur des mémoires associatives. Nous allons voir celles-ci dans la suite du chapitre, mais gardez à l'esprit que ces optimisations, à savoir désactiver les entrées vides/prêts et partitionner la fenêtre d'instruction, sont des optimisations générales qui marchent avec presque tout. ===L'ajout d'une FIFO pour les instructions déjà prêtes à l'émission=== D'autres techniques permettent de réduire aussi bien le cout en circuits que la consommation d'énergie de la fenêtre d'instruction. L'idée est d'utiliser une mémoire associative quand elle est réellement nécessaire, mais d'utiliser une fenêtre d'instruction "normale" dès que possible. La méthode la plus simple tient compte du fait que certaines instructions ont déjà toutes leurs opérandes de disponibles à l'émission, mais doivent quand même être mises en attente, parce que l'ALU adéquate est occupée, parce que des dépendances WAW/WAR sont encore là, ou pour tout autre raison. Dans ce cas, elles sont mises en attente non pas dans la fenêtre d'instruction, mais dans une mémoire FIFO toute simple. L'idée est qu'au lieu d'avoir une énorme mémoire associative pour la fenêtre d'instruction, on déplace quelques entrées dans une petite FIFO annexe. Le résultat est un gain en terme d'énergie et de circuits, au prix d'une perte de performance mineure. La perte de performance en question se manifeste si aucune instruction n'a ses opérandes de prêtes à l'émission : le programme n'utilise pas la FIFO et voit alors une fenêtre d'instruction plus petite. Une amélioration de cette technique tient compte du fait que certaines instructions sont dans un cas intermédiaire. Elles ont déjà une opérande de prête lors de l'émission, mais pas l'autre. Le nombre d'opérandes varie suivant l’instruction : certaines n'ont besoin que d'un seul opérande. De plus, il arrive qu'une opération tout juste décodée ait déjà un ou plusieurs de ses opérandes de prêts. Cette constatation permet d'éviter d'utiliser des comparateurs pour les opérandes déjà prêts. Par exemple, on peut parfaitement utiliser trois fenêtres d'instruction : * une pour les instructions dont tous les opérandes sont prêts, mais qui sont quand même mises en attente, sans comparateur ; * une pour les instructions dont un seul opérande manque, qui n'utilise qu'un comparateur par entrée ; * une pour les instructions dont deux opérandes manquent à l'appel, qui utilise deux comparateurs par entrée. C'est beaucoup plus économique que d'utiliser une seule grosse fenêtre d'instruction qui contiendrait autant d'entrées que les trois précédentes réunies, avec deux comparateurs par entrée. Certains sont même allés plus loin, et ont proposé de supprimer la fenêtre d'instruction avec deux opérandes par entrée. Les instructions dont deux opérandes sont inconnus au décodage sont stockées dans la fenêtre d'instruction pour instructions avec un comparateur par entrée. Un circuit de prédiction se charge alors de prédire l'opérande manquant, cette prédiction étant vérifiée plus loin dans le pipeline. Il serait cependant étonnant qu'une telle proposition ait donné lieu à la moindre implémentation réelle. ===Les optimisations de la consommation d'énergie avancées=== D'autres chercheurs ont conservé une fenêtre d'instruction unique, avec autant de comparateurs par entrée qu'il y a d'opérandes possibles par instruction. Simplement, le processus de détection des opérandes prêts est légèrement ralenti : on ne vérifie qu'un opérande par cycle. Pour vérifier les deux opérandes d'une entrée, on doit attendre deux cycles. Enfin, certains chercheurs ont proposé des fenêtres d'instruction segmentées. Les instructions circulent à chaque cycle d'un segment vers le suivant : en conséquence, certains segments conservent les instructions les plus anciennes, un autre les instructions les plus jeunes, etc. Seul le denier segment, celui qui contient les instructions les plus vielles, peut émettre une instruction : la détection des opérandes se fait seulement dans le dernier segment, qui contient les instructions les plus anciennes. On économise ainsi beaucoup de comparateurs. Certains chercheurs ont tenté de pipeliner l'étape de sélection des opérandes, ainsi que l'étage d'arbitrage. Mais en faisant cela, il faut plusieurs cycles pour détecter qu'une instruction a ses opérandes prêts, ce qui pose problème face à de nombreuses dépendances RAW. Pour éviter de trop perdre en performances, certains chercheurs ont décidé d'utiliser des techniques pour prédire quelles seront les instructions dont les opérandes seront bientôt prêts. Si détecter qu'une instruction est prête prend n cycles, le processeur devra tenter de prédire la future disponibilité des opérandes n cycles en avance pour obtenir des performances optimales. ===Remplacer la mémoire associative par une RAM=== Une autre optimisation possible est de remplacer la fenêtre d'instruction par une mémoire RAM, dont chaque mot mémoire correspondrait à une entrée. Une telle optimisation permet en théorie de se passer des comparateurs associés à chaque entrée, mais au prix de l'ajout de circuits annexes potentiellement couteux. La première de ces techniques, la '''recherche directe par étiquette''' (direct tag search) fut créée par Weiss et son collègue Smith. Ils cherchaient à améliorer l'algorithme de Tomasulo, un algorithme qu'on expliquera dans quelques chapitres. Rappelons que chaque instruction produit un résultat, qui devra être rapatrié dans une ou plusieurs entrées de la fenêtre d'instruction. L'optimisation de la recherche directe par étiquette fonctionne dans le cas où le résultat de l'instruction n'est utilisé que par une seule entrée, et pas plusieurs. Le principe est simple : chaque champ « opérande » d'une entrée est adressable via le nom de registre de cette opérande. Pour faire le lien entre entrée et nom de registre, la recherche directe par étiquette ajoute une table de correspondances matérielle, une mémoire RAM qui mémorise les adresses des champs « opérande » des entrées. Les adresses envoyées dans cette mémoire sont les noms de registres des résultats. Lors de l'émission, la table de correspondances est mise à jour. Les numéros des champs « opérande » réservés lors de l'émission sont mémorisés dans les mots mémoire qui correspondent aux deux registres sources. Toutefois, une petite vérification est faite lors de l'émission : si il y a déjà une correspondance dans la table pour un registre source, alors une autre instruction compte lire ce registre. Pour éviter d'écraser les données de l'instruction précédente dans la table de correspondances, l'émission de l'instruction est bloquée. [[File:Recherche directe par étiquette.png|centre|vignette|upright=2|Recherche directe par étiquette.]] ==Les fenêtres d’instruction avec préplanification== Avec la '''préplanification''' (''prescheduling''), la fenêtre d’instruction est composée de mémoires FIFO dans lesquelles les instructions sont triées dans l'ordre d'émission. Il n'y a pas de logique d’émission proprement dite, celle-ci se bornant à vérifier si l'instruction située au début de la FIFO peut s’exécuter. Par contre, le préplanificateur détecte les dépendances et en déduit où insérer les instructions dans le tampon d'émission, à l'endroit le plus adéquat. [[File:Préplanification.jpg|centre|vignette|upright=2|Préplanification.]] ===L'usage de FIFO multiples=== La technique de préplanification la plus simple utilise plusieurs FIFO. Quand une instruction a une dépendance avec une autre instruction, les deux sont placées dans la même FIFO. Pour cela, le préplanificateur détecte les chaines d'instructions dépendantes, et place les instructions dans la FIFO adéquate. A chaque cycle, l'unité d'émission lit une micro-opération dans chaque FIFO et vérifie si elle peut l'émettre. Si la micro-opération n'a pas ses opérandes disponibles, ou qu'une dépendance structurelle survient, alors la FIFO est bloquée. La micro-opération attend que la dépendance soit résolue, bloquant toutes les instructions précédentes. Mais les autres FIFO ne sont pas bloquées, laissant de la marge de manœuvre. [[File:Préplanification par FIFO multiples.png|centre|vignette|upright=1.5|Préplanification par FIFO multiples.]] ===La technique du tampon trié=== La technique du '''tampon trié''' trie les instructions selon le temps d'attente avant leur exécution. Les instructions qui sont censées s’exécuter bientôt sont insérées au tout début de la FIFO, tandis que les instructions qui s’exécuteront dans un long moment sont insérées vers la fin. Là encore, l'unité d'émission lit une micro-opération dans la FIFO, et détermine si elle peut être émise. Si une dépendance survient, l'émission est retardée, et la FIFO est bloquée. [[File:Préplanification par tampon trié.png|centre|vignette|upright=1.5|Préplanification par tampon trié.]] La technique a cependant quelques problèmes assez importants. Le premier problème est que la FIFO est bloquée lorsqu'une micro-opération ne peut être émise. Le second problème est que le temps avant exécution n'est pas toujours connu, notamment pour les instructions d'accès mémoire. Et cela se répercute sur les instructions dépendantes de celles-ci. Pour résoudre ce genre de problèmes, l'usage d'un pipeline à ''replay'' est possible, et est même l'une des meilleures solution possible, malgré ses défauts. L'idée est que les lecture sont pré-planifiées en supposant qu'elles font un succès de cache L1. Si la prédiction est fausse, la lecture est ré-exécutée plusieurs cycles plus tard, en supposant qu'elle fait un succès dans le cache L2, et ainsi de suite. Elle est alors ré-insérée dans la FIFO, elle est pré-planifiée une seconde fois. Il en est de même si une micro-opération ne peut pas être émise : il suffit de la réinsérer dans la FIFO au bon endroit, en attendant que ses dépendances soient résolus. Ainsi, l'instruction fautive ne bloque pas la fenêtre d’instruction, et retente sa chance autant de fois qu'il le faut. [[File:Préplanification par fenêtre d’instruction scorebarodée.png|centre|vignette|upright=1.5|Préplanification par fenêtre d’instruction scorebarodée.]] Une autre solution utilise deux fenêtres d’instruction : une FIFO gérée par la préplanification, et une vraie fenêtre d'instruction pour les instructions dont le temps d'attente ne peut pas être déterminé. Il est possible de mettre cette dernière avant la préplanification, afin de gérer les temps d'attente des instructions d'accès mémoire. Quand le temps d'attente d'une lecture devient connu, ses instructions dépendantes sont gérées avec préplanification. [[File:Préplanification avec fenêtre d’instruction.png|centre|vignette|upright=2.5|Préplanification avec fenêtre d’instruction.]] ===Les fenêtres d'instruction avec allocation temporelle statique=== L''''allocation temporelle statique''' correspond à une technique utilisée sur les processeurs Cuzco de l'entreprise Condor. La technique en question a été présenté en 2025, mais des idées similaires ont été présentées dans la littérature académique. Elle ressemble beaucoup aux techniques de pré-planification, avec cependant quelques différences. L'idée est simple : le processeur dispose de plusieurs fenêtres d'instruction, qui mettent en attente les micro-opérations. Lors de l'étape de renommage de registres, le processeur détermine dans combien de cycles d'horloge la micro-opération sera prête pour exécution. La micro-opération est alors mise en attente durant ce nombre de cycles, dans les fenêtres d'instruction, puis est émise une fois ce nombre de cycles écoulés. Ce faisant, les fenêtres d'instruction n'ont pas besoin de détecter la disponibilité des opérandes à chaque cycle, pour chaque micro-opération en attente. Le ''timing'' de l'émission des micro-opérations est décidé à l'avance. L'implémentation exacte n'est pas connue, mais plusieurs solutions sont imaginables. Par exemple, la fenêtre d'instruction peut simplement être composée de plusieurs mémoires de petite taille, chacune contenant les micro-opérations destinées à être exécutées dans N cycles, N étant différent pour chaque mémoire. Une autre solution, plus réaliste, utilise une fenêtre d'instruction dans laquelle la micro-opération est couplée à des champs pour les opérandes, et un champ compteur. Le champ compteur est initialisé avec le nombre de cycles à attendre, et est décrémenté à chaque cycle d'horloge. Quand il atteint zéro, la micro-opération est émise. Vous remarquerez que la méthode ne marche que si toutes les micro-opérations prennent un nombre fixe de cycles d'horloge. Et autant c'est le cas pour les micro-opérations arithmétiques ou logiques, autant les accès mémoire ne rentrent pas dans ce cadre. En théorie, on ne sait pas combien de temps prendra un accès mémoire. Et cette incertitude se répercute sur les instructions dépendantes d'un accès mémoire. Pour éviter cela, le processeur réutilise un pipeline à ''replay'' tel que vu dans le chapitre précédent. L'unité de renommage de registre suppose que tout accès mémoire fait un succès de cache L1, et décide des ''timings'' d'émission sous cette hypothèse. Si une lecture subit un défaut de cache, elle est ré-exécutée, de même que toutes les instructions dépendantes. Pour cela, le registre de destination de la lecture est marqué comme invalide, grâce à un bit spécifique attaché au registre. Toute instruction qui lit une opérande invalide est elle aussi ré-executée de zéro. Pour simplifier, l'unité d'émission ressemble à une unité d'émission dans l'ordre, avec un registre de disponibilité, qu'on aurait amélioré pour aller au-delà de la simple détection des dépendances d'instruction. Pour déterminer les ''timings'' d'émission, à savoir quand émettre une micro-opération, le processeur utilise une unité d'émission à deux étages. Le premier étage est appelé le ''register scoreboard'', le second étage est appelé la ''Time Ressource Matrix''. Les deux étages communiquent entre eux, comme on va le voir, et leurs noms donnent une idée de ce qu'ils font. Le premier étage gère les dépendances de registres, le second gère les dépendances structurelles. Le premier étage est un registre de disponibilité amélioré, qui gère les dépendances de registre. Cet étage sait quand tel registre sera écrit, et donc que l'opérande écrite dedans sera disponible à partir de tel cycle d'horloge. Il le sait car l'étage suivant l'aura prévenu, mais laissons cela de côté pour le moment. Quand une micro-opération rentre dans cet étage, il vérifie les dépendances avec les registres et les micro-opérations antérieures. Vu qu'il sait quand les registres seront disponibles, il peut déterminer quand l'instruction pourra s'exécuter. Par exemple, si une micro-opération lit les deux registres R7 et R15, qui sont disponibles respectivement dans 5 et 7 cycles, le premier étage sait que la micro-opération devra attendre 7 cycles. Mais tout cela ne suffit pas à déterminer quand émettre une micro-opération. En effet, il fait aussi gérer les dépendances structurelles, ce qui est le boulot du second étage. Le second étage utilise pour cela une ''Time Ressource Matrix'', qui mémorise l'occupation de diverses "ressources", pour les 256 cycles d'horloge à venir. Les ressources en question sont les ports de lecture/écriture du banc de registre, les ALUs utilisées, si la micro-opération utilise l'unité mémoire, etc. Le second étage prend en entrée une micro-opération, détermine quelles "ressources" elle utilise, puis regarde leur disponibilité. Elle détecte alors les dépendances structurelles et détermine alors quand peut s'exécuter la micro-opération. Elle peut retarder l'émission de quelques cycles, si une dépendance structurelle est détectée. Une fois sortie du second étage, on sait quand la micro-opération va être émise, à quel cycle précisément. Et vu que la durée de l'instruction est fixe, on sait quand cette micro-opération va se terminer, quand son résultat sera disponible. Cela permet de mettre à jour la ''Time Ressource Matrix'', pour préciser que le port d'écriture sera occupé à tel moment. De plus, cette information est transmise au premier étage, qui sait alors quand est enregistré le résultat dans le registre de destination. C'est comme cela que le premier étage sait quand un registre est disponible : le second étage le prévient, quand il émet une instruction ! La ''Time Ressource Matrix''mémorise l'occupation des "ressources" pour les 256 cycles d'horloge à venir. Cependant, elle ne vérifie pas les dépendances pour les 256 cycles suivants. Quand elle reçoit une micro-opération, elle teste les dépendances structurelles pour seulement les 8 prochains cycles maximum. Si la micro-opération ne peut pas être émise pendant ces 8 cycles, le pipeline est bloqué, un ''pipeline stall'' est émis. Pour être plus précis, vu que le processeur peut décoder 8 micro-opérations en même temps, cela permet de ne consulter que 64 cycles d'horloge sur les 256. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les premiers processeurs Intel | prevText=Les premiers processeurs Intel | next=Le renommage de registres | nextText=Le renommage de registres }} </noinclude> 2g7yscbslfg3kvwej4ctgzp8aukb3to 773596 773595 2026-09-29T18:58:51Z Mewtow 31375 /* Les fenêtres d'instruction décentralisées */ 773596 wikitext text/x-wiki Dans les chapitres précédents, nous avons parlé des techniques dites d''''émission dans l'ordre'''. L'idée est d’exécuter une nouvelle micro-opération à chaque cycle, dans des unités de calcul séparées. Les instructions sont émises consécutivement, mais les instructions s’exécutent en parallèle dans des unités de calcul séparées. Par contre, quand l'unité d'émission ne peut pas émettre une instruction, elle bloque tout le pipeline. Les instructions qui suivent sont elles aussi bloquées, elle doivent attendre leur tour, même si elles sont en capacité de s'exécuter. Les techniques d'exécution dans le désordre que nous allons voir dans ce chapitre corrigent ce point précis. Elles sont dites à '''émission dans le désordre'''. Elles se distinguent des précédentes sur un point précis : quand l'unité d'émission bloque l'émission d'une instruction, les instructions suivantes peuvent poursuivre. L'émission des instructions peut donc se faire dans le désordre, dans le sens où une instruction peut être émise alors qu'une instruction précédente ne l'est pas encore. L'avantage de l'émission dans le désordre est qu'une instruction s'exécute dès que ses opérandes sont disponibles. Par disponible, on veut dire présent soit dans le réseau de contournement, soit dans les registres. Le processeur détecte automatiquement quand les opérandes d'une instruction sont sont disponibles, et il l’exécute à ce moment là. Dès qu'une instruction a ses opérandes disponibles, elle est émise et exécutée. C'est là la seule contrainte : les dépendances WAR, WAW et autres sont gérées par un ROB ou toute autre technique d'exception précise, seules les dépendances RAW limitent l'exécution. Mais avant de poursuivre, quelques point niveaux terminologie : * L'émission dans le désordre est un terme parlant et assez précis. Malheureusement, la terminologie la plus utilisée par d''''exécution dans le désordre'''. Et nous utiliserons ce terme dans la suite du cours, histoire de ne pas trop dévier de la nomenclature habituelle. * Nous utiliserons parfois l'abréviation OOO pour parler d'exécution dans le désordre. L'abréviation est celle de ''Out Of Order Excution''. * Nous utiliserons aussi l'abréviation ''µop'' pour parler de micro-opération, ''µops'' au pluriels pour parler de plusieurs micro-opérations, ou des micro-opérations en général. L'exécution dans le désordre ne gére en effet que des µops, elle se situe après l'étape de décodage. Mais avant de poursuivre, précisons une chose importante : l'exécution dans le désordre traite les accès mémoire à part. La majorité des processeurs OOO assez anciens exécutent les accès mémoire dans l'ordre, seules les µops entières/flottantes/branchements sont exécutées dans le désordre. Les processeurs datant d'après les années 2010 sont capable d'exécuter les accès mémoire dans le désordre, mais l'implémentation en question est assez particulière. Un chapitre entier sera dédié à l'exécution dans le désordre des µops mémoire. Nous allons volontairement mettre de côté la gestion des accès mémoire dans ce chapitre. ==Les fenêtres d’instruction : généralités== [[File:File de micro-opération.png|vignette|upright=1|File de micro-opérations]] Pour décrire comment est implémentée l'émission dans le désordre, il faut commencer par parler des processeurs sans. Les processeurs sans exécution dans le désordre ont une unité d'émission qui bloque tout le pipeline dès qu'une µop ne peut pas être émise. Pour limiter l'impact de ce blocage, quelques rares processeurs incorporent une '''file de micro-opération''', une mémoire FIFO qui met en attente les µops. Vu que c'est une mémoire FIFO, les µops sont émises dans l'ordre, à savoir l'ordre d'ajout, dans l'ordre de décodage. Le schéma ci-dessous illustre une telle file d'attente couplée à un ''scoreboard''. Sur le principe, l'exécution dans le désordre améliore la file de µops sur un point : ce n'est plus une mémoire FIFO. Les µops sont insérées dans l'ordre, mais peuvent sortir dans le désordre (être émises dans le désordre). La file de µops devient alors une '''fenêtre d'instruction''', terme traduit directement de l'anglais ''instruction Window''. Terme assez trompeur, car elles mettent en attente des µops, pas des instructions. Elles peuvent émettre des µops dans le désordre, ce qui fait que si une µop bloque le pipeline, les µops suivantes peuvent être émises. Si je commence le paragraphe précédent par "sur le principe", c'est car certaines techniques d'OOO utilisent des files de µops normales. Il est par exemple possible d'utiliser une file de µops avec une fenêtre d'instruction, plusieurs files de µops, plusieurs fenêtres d'instructions avec une file de µops annexe, etc. Dasn les grandes lignes, il existe dans les grandes lignes 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! File de µops améliorée |- ! Une seule "file de µops" | ''Scoreboard'' | Fenêtre d'instruction centralisée |- ! Plusieurs "file de µops" | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | Fenêtre d'instruction décentralisée |} ===La fenêtre d'instruction centralisée=== L'implémentation la plus simple de l'OOO utilise une unique '''fenêtre d'instruction'''. Les instructions décodées sont accumulées dans la fenêtre d'instruction, où elles attendent que leurs opérandes soient disponibles. La fenêtre d'instruction sert donc de file d'attente. Mais elle contient aussi une unité d'émission, qui détecte quelles µops sont prêtes à être émises. L'unité d'émission et la fenêtre d'instruction sont fusionnées ensemble, elles forment un seul circuit. Mais nous allons dire qu'elles sont conceptuellement séparées pour le moment. A chaque cycle, l'unité d'émission consulte la fenêtre d'instruction pour voir quelles µops peuvent s'exécuter, lesquelles ont leur opérandes de disponibles. La fenêtre d'instruction doit spécialement être conçue pour, c'est une sorte de mémoire associative très complexe, comme on le verra dans ce qui suit. [[File:OOO Issue.png|centre|vignette|upright=2.5|Exécution dans le désordre avec une fenêtre d'instruction]] Une fois qu'une µop sort du décodeur d'instructions, elle est ajoutée en parallèle dans la fenêtre d'instruction et le ROB. La raison est que les µops quittent la fenêtre d'instruction dans le désordre, et qu'elles doivent être remises en ordre par la suite. Le ROB s'occupe de cette remise en ordre, mais il a besoin de savoir dans quel ordre les µops sont censées être, et cet ordre est celui du décodage. Aussi, pour remplir le ROB, la seule opportunité est en sortie de l'unité de décodage. Dans le cas où une instruction est décodée en plusieurs micro-opérations, elles sont toutes insérées en même temps dans la fenêtre d'instruction et le ROB, en tenant compte de leur ordre. [[File:Fenêtre d'instruction.png|centre|vignette|upright=2|Fenêtre d'instruction.]] Les micro-opérations mémoire sont à part des autres, pour diverses raisons. Une de ces raisons est que les dépendances de données sont classées en deux types : les dépendances de registre et les dépendances d'adresse. Et les deux sont fondamentalement différentes. Autant on peut détecter les dépendances de registre lors de l'émission, autant c'est plus compliqué avec les dépendances d'adresse. De plus, rappelons que si les lectures peuvent s'exécuter dans le désordre, les écritures doivent s'exécuter dans l'ordre, ou du moins en donner l'illusion. Pour cela, le processeur remet les écritures dans l'ordre avec une sorte de mini-ROB intégré à l'unité mémoire, appelée la file d'écriture. Elle complémente le ROB, qui lui ne gère que les écritures dans les registres, mais les deux collaborent. La file d'écriture envoie une écriture à la mémoire RAM quand le ROB lui dit que c'est bon, les instructions précédentes sont terminées ''dans l'ordre du programme''. Les processeurs modernes ajoutent des techniques d'exécution dans le désordre des accès mémoire, mais nous les verrons dans un chapitre dédié. Elles permettent d'utiliser une fenêtre d'instruction unique, qui mémorise aussi les µops mémoire. Si elles sont mises en place, l'unité mémoire n'a pas besoin de file de µops séparée. L'idée est que les dépendances de registre sont traitées par la fenêtre d'instruction, mais que l'unité mémoire gére les dépendances d'adresse. Les dépendances d'adresse sont gérées par des techniques de ''désambiguation mémoire'', qui auront droit à un chapitre dédié. [[File:Processeur avec exécution dans le désodre des accès mémoire.png|centre|vignette|upright=2|Processeur avec exécution dans le désodre des accès mémoire]] Les processeurs assez anciens n'autorisaient pas d'exécution dans le désordre des accès mémoire. Concrétement, les accs mémoire devaient se faire dans l'ordre, mais les autres µops pouvaient être exécutées dans le désordre. Il s'agit donc d'un ordre entre µops mémoire, pas entre µops mémoire et autres µops. Les µops entières et flottantes pouvaient être exécutées avant une µops mémoire qui est avant elle dans l'ordre du programme, ce n'est pas un problème. Pour garantir l'ordre desd µops mémoire, l'unité mémoire est précédée par une file de micro-opérations séparée, pour forcer l'exécution dans l'ordre des accès mémoire. De plus, les µops mémoire ne peuvent pas utiliser la fenêtre d'instruction. Dit autrement, la fenêtre d'instruction ne mémorise pas de µops mémoire. Après le décodage, les µops sont réparties soit dans la file de µops mémoire, soit dans la fenêtre d'instruction. Le décodeur classe les µops suivant que ce sont des µops mémoire ou non, et les envoient à la bonne destination. Dans ce chapitre, on supposera que c'est cette solution qui est utilisée. [[File:Processeur avec émission dans l'ordre des accès mémoire.png|centre|vignette|upright=2|Processeur avec émission dans l'ordre des accès mémoire]] La solution précédente revient à scinder la fenêtre d'instruction en deux : une file de µops pour les µops mémoire, une fenêtre d'instruction pour les autres µops. Et cette scission peut aller plus loin, à savoir qu'on peut scinder une fenêtre d'instruction encore et encore. Ce qui nous amène à la section suivante. ===Les fenêtres d'instruction décentralisées=== Nous venons de voir qu'il est possible de scinder la fenêtre d'instruction en une fenêtre d'instruction pour les µops mémoire (simplifiée en une file de µops classique), et une autre pour les autres µops. Sachez qu'il est possible d'aller plus loin, par exemple en séparant la fenêtre d'instruction en une fenêtre spécialisée dans les µops flottantes et une autre pour les µops entières. Et ce n'est là qu'un exemple parmi de nombreuses autres possibilités. Pour faire la différence avec une fenêtre d'instruction unique, nous allons parler de fenêtre d'instruction centralisée s'il n'y en a qu'une, de '''fenêtre d'instruction décentralisée''' s'il y en a plusieurs. Il est possible d'associer chaque fenêtre d'instruction à un type précis de µops. Par exemple, avec une fenêtre d'instruction pour les µops de calcul entières, une autre pour les µops flottantes, une autre pour les µops mémoire. Il s'agit d'un choix simple et efficace, mais quelques processeurs font autrement, pour répondre à des contraintes très diverses. [[File:Processeur avec des fenêtres d'instruction décentralisées.png|centre|vignette|upright=2|Processeur avec des fenêtres d'instruction décentralisées]] Un autre exemple : les processeurs Intel de microarchitecture Skylake utilisent une fenêtre d'instruction pour les opérations entières/flottantes, et une fenêtre d'instruction séparée pour les µops mémoire. Il s'agit bien d'une fenêtre d’instruction, le processeur utilise l'exécution dans le désordre des accès mémoire. Un avantage est que les deux fenêtres d'instructions sont plus spécialisées, ce qui entraine des économies de circuit. Les opérations entières/flottantes ont besoin de deux registres pour les opérandes et d'un autre résultat, alors que les µops mémoire n'ont besoin que de deux registres maximum. En utilisant une fenêtre d'instruction unique, chaque entrée doit mémoriser l'opcode et trois registres, dont un est inutilisé pour les µops mémoire et les branchements. En utilisant des fenêtres d’instructions séparées, celle pour les µops entières/flottantes a trois registres par entrée, contre seulement deux registres par entrée pour celle des µops mémoire. Il est possible d'utiliser une fenêtre d'instruction pour les opérations flottantes et une autre pour les autres µops (µops entières et parfois mémoire avec). L'avantage est que cela simplifie grandement le processeur. Les flottants sont gérés à part des entiers. Ils ont leurs propres registres, des FPU séparées des ALU entières, bref : la séparation est complète. Utiliser une fenêtre d'instruction séparée va dans ce sens. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Un cas extrême est celui où chaque ALU a sa propre fenêtre d'instruction. Nous parlerons alors de '''fenêtres d'instruction totalement décentralisées'''. Un exemple historique est celui de la fpu de l'IBM 360 modèle 90. Elle disposait d'un additionneur flottant, d'un multiplieur flottant, et d'une unité mémoire pour les lectures/écritures flottantes. Les trois unités avaient leur propre fenêtre d'instruction. Les processeurs AMD utilisent beaucoup cette technique, contrairement à Intel qui préfère utiliser des fenêtres centralisées sur les anciens processeurs, deux ou trois fenêtres sur les processeurs récents (2020 et plus). L'usage de fenêtres décentralisées simplifie la répartition des µops sur les unités de calcul. Par exemple, utiliser des fenêtres séparées pour les ALU et les FPU facilite la répartition des instructions de calcul sur les ALU. Une fenêtre centralisée demande de faire la différence entre instruction entière/flottante, puis de choisir sur quelle unité de calcul entière/flottante utiliser. Une fenêtre décentralisée fait les deux choix séparément : d'abord on envoie l'instruction dans la bonne fenêtre suivant si c'est une instruction flottante ou entière, et ensuite on gère la disponibilité des ALUs/opérandes. Et on peut adapter la même idée en séparant les unités d'accès mémoire des ALU entières, etc. Par contre, un défaut est que certaines fenêtres d'instruction peuvent être sous-utilisées. Par exemple, la station de réservation flottante est inutilisée si le programme n'exécute pas d'opérations flottantes. Ou encore, les fenêtres pour les accès mémoire peuvent être sous-utilisées, si le programme effectue peu d'accès mémoire relativement aux autres instructions. En fait, tout dépend de comment sont calibrées les fenêtres d'instruction et de la répartition des instructions dans le programme entre opérations entières, flottantes, mémoire. Par exemple, si un programma de deux fenêtres d'instructions identiques, une pour les calculs entiers et une autre pour les calculs flottants, elles ne seront utilisées à la perfection que si la moitié des instructions du programme fait des calculs flottants et l'autre des calculs entiers. Toute déviation par rapport à cette répartition idéale risque de laisser des entrées vides dans une fenêtre d’instruction. Un point important est que l'émission est découpée en deux étages avec des fenêtres d'instruction décentralisées. La première étape envoie l'instruction décodée vers la fenêtre d'instruction adéquate, la seconde gère l'émission proprement dit. La première est l'étage de ''dispatch'' qui envoie l'instruction dans la fenêtre d’instruction adéquate, selon que c'est une instruction flottante, entière, autre. La seconde est l'étage de ''scheduling'', qui gère la disponibilité des opérandes et des unités de calcul. En clair, on trie les instructions suivant leur type, suivant le type d'unité de calcul adéquate, puis on l'émet proprement dit. Faire ainsi a plusieurs avantages, avec cependant peu d'inconvénients. Lors de l'étape de ''dispatch'', l'instruction émise est ajoutée au tampon de réordonnancement, s'il existe. Sans cela, impossible de conserver l'ordre des instructions. Les instructions sont émises dans l'ordre au niveau de l'unité de ''dispatch'', pas au niveau de l'étage de ''scheduling''. Aussi, pour remplir le ROB, cela doit se faire au dernier moment où les instructions sont émises dans l'ordre, soit en sortie de l'unité de ''dispatch''. De plus, les micro-opérations mémoire sont traitées à part des autres, elles sont envoyées directement à l'unité mémoire. La gestion des calculs d'adresse est quelque peu complexe, mais ils peuvent être fait soit dans l'unité mémoire, soit dans les ALU entières, peu importe. Il y a aussi un système de contournement complexe entre ALU/FPU et unité mémoire, qui n'est pas représenté dans le schéma ci-dessous. Il faut noter que quelques processeurs utilisent des méthodes intermédiaires entre les trois solutions précédentes. Par exemple, les processeurs AMD Zen utilisent une fenêtre d'instruction décentralisée un peu particulière. Les unités de calcul entières disposent d'une fenêtre d'instruction rien que pour elles, sur ce processeur. Les instructions flottantes sont quant à elles alimentées par une file de micro-opération, pas une fenêtre d'instruction ! La raison à ce choix est un compromis entre performance et cout en circuit. L'exécution dans le désordre est peu efficace sur les instructions flottantes, car les CPU n'ont que peu d'ALU flottantes séparées. Vu le cout en circuits d'une fenêtre d'instruction, les concepteurs du processeur ont préféré utiliser une file de micro-opération pour les opérations flottantes. ===L'usage de plusieurs files d'instruction=== Une dernière méthode d'OOO utilise plusieurs files de micro-opération. L'idée est qu'une fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement une file de micro-opération pour les opérations entières, une autre pour les opérations flottantes, une autre pour les accès mémoire. D'autres processeurs utilisent une file pour les accès mémoire et une autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. La présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que la technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si une dépendance bloque une FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans une autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer la disponibilité des registres. Quand un registre est lu ou écrit par une instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. La logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : une pour les instructions d'accès mémoire et une autre pour les autres instructions. Si jamais une instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de la lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'une est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est la file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. ===Avantages et inconvénients de chaque implémentation=== Un processeur contient soit une fenêtre d'instruction unique, soit plusieurs fenêtres d'instruction séparées. Typiquement, les fenêtres d’instruction séparées sont spécialisées, dans le sens où on a une fenêtre pour les instructions flottantes, une autre pour les instructions entières, une autre pour les accès mémoire, etc. Pour résumer, on a le choix entre une grosse fenêtre généraliste et plusieurs fenêtres spécialisées, sauf que la fenêtre centralisée est lente et complexe, contrairement aux fenêtres spécialisées. Les deux méthodes ont des inconvénients et des avantages différents. Dans les grandes lignes, l'avantage des fenêtres décentralisées est qu'elles sont plus petites qu'une grosse fenêtre d'instruction. Cela simplifie la gestion du contournement et de la répartition des instructions sur les unités de calcul, comme on le verra dans quelques paragraphes. Elles sont donc moins complexes et plus rapides. L'autre avantage, c'est qu'il est possible de démarrer l'exécution de plusieurs instructions simultanément : une instruction par fenêtre décentralisée, contre une par fenêtre d'instruction. Mais les fenêtres décentralisées sont souvent sous-utilisées, partiellement remplies, contrairement aux fenêtres d'instruction. Il arrive qu'une fenêtre d'instruction soit remplie, alors que les autres sont vides. Par exemple, prenons un processeur avec une fenêtre d'instruction reliée à la FPU, et une autre reliée aux autres ALUs. Si le processeur n'exécute que des opérations flottantes, la fenêtre reliée à la FPU sera pleine, alors que l'autre sera vide. L'exécution des instructions dans le désordre est alors limitée par la petite taille de la fenêtre, qui ne peut plus accepter de nouvelle instruction flottante. Avec une fenêtre unique, on n'aurait pas eu ce problème : on aurait eu une énorme fenêtre d'instruction remplie d'instruction flottante, au lieu d'une petite fenêtre spécialisée. Il est maintenant temps de voir en quoi sont faites les fenêtres d’instruction, qu'elles soient centralisées ou décentralisées. Nous allons aussi voir quelle est la logique d'émission associée. ==L'implémentation d'une fenêtre d'instruction : généralités== Une fenêtre d'instruction est une mémoire qui mémorise des micro-opérations. Elle est cependant plus complexe qu'une mémoire RAM ou qu'une FIFO et ressemble un petit peu à une mémoire cache. Elle dispose d'un port d'écriture et d'un port de lecture, au minimum. Le port d'écriture permet à l'unité de décodage d'insérer une micro-opération dedans, d'ajouter la micro-opération qui vient d'être décodée. Si une instruction machine est décodée en plusieurs micro-opération, deux possibilités. La première est de les insérer un par un, ce qui fait qu'on peut se contenter d'un seul port d'écriture. L'autre possibilité est de les ajouter en même temps, ce qui demande plusieurs ports d'écriture. Le port de lecture sert à émettre une instruction. On part du principe que la fenêtre d'instruction ne peut émettre qu'une seule instruction à la fois, car les processeurs que nous avons vu précédemment sont de ce type. Mais nous verrons dans quelques chapitre qu'il existe des processeurs dits superscalaires, qui sont capables d'émettre plusieurs instructions par cycle. Dans ce cas, la fenêtre d'instruction a un seul port de lecture. Un processeur superscalaire, quant à lui, doit avoir un port de lecture par unité de calcul, ce qui fait beaucoup plus. ===Les entrées d'une fenêtre d’instruction=== Les fenêtres d'instruction sont composées d''''entrées''', des mots mémoire qui stockent une instruction. Une instruction réserve une entrée après son décodage et la libère dès qu'elle est envoyée aux unités de calcul. Une entrée contient l'opcode (les signaux de commande à envoyer à l'ALU), le registre de destination du résultat, les registres de chaque opérande, et éventuellement des signaux de commande en plus. De plus, chaque opérande est couplée à un bit de disponibilité, qui indique si elle est disponible. Quand un opérande est écrit dans les registres, le bit de présence correspondant est mis à jour. Enfin, chaque entrée possède un bit ''empty'' qui indique si elle est vide, cette information étant utile pour réserver des entrées. [[File:Entrée d'une station de réservation - sans les tags.png|centre|vignette|upright=3|Entrée d'une fenêtre d'instruction]] Nous verrons dans quelques chapitres que certaines fenêtres d'instruction sont capables de mémoriser les opérandes des instructions. De telles fenêtres d'instruction seront appelées, dans ce cours, des '''stations de réservation'''. Les entrées des stations de réservation sont assez semblables à celle des fenêtres d'instruction, à un détail près : les opérandes de l'instruction sont enregistrées directement dans des champs séparés. Il y a deux champs, un par opérande, pour stocker l'opérande elle-même, lue depuis les registres ou obtenue via le réseau de contournement. Notons que les champs pour les opérandes viennent en plus des champs pour les noms de registres, encore que les deux peuvent être fusionnés si on veut optimiser le tout. [[File:Entrée d'une station de réservation.png|centre|vignette|upright=3|Entrée d'une station de réservation.]] Précisons que la terminologie n'est pas très fiable. Les termes "fenêtre d'instruction" et "station de réservation" ne regroupent pas du tout la même chose d'un papier de recherche à l'autre, d'un bouquin à l'autre, d'un chercheur à l'autre, d'un ingénieur à l'autre, d'un professeur à l'autre. Le terme initial vient pourtant de l'article original sur l'algorithme de Tomasulo, où il désignait une fenêtre d'instruction associée à une unité de calcul précise. Mais le terme a ensuite été réutilisé, ce qui fait que certains processeurs avec plusieurs unités de calcul sont décrit comme ayant une unique station de réservation. En bref : c'est le bazar ! Mais nous en reparlerons dans le chapitre sur le renommage de registres, car c'est la place idéale pour les aborder. Toujours est-il que j'ai fait le choix de confondre les concepts de fenêtre d'instruction et de station de réservation avec les concepts de '''lecture avant émission''' et de '''lecture après émission'''. La différence entre les deux est que les registres sont lus après émission avec une fenêtre d'instruction, avant avec des stations de réservation. Dans le cas "avant émission", les opérandes sont mémorisées dans la station de réservation. Et cette différence a une influence sur le pipeline du processeur, le banc de registres et tout ce qui s'en suit. Un désavantage de la lecture avant émission est qu'il faut stocker les opérandes après lecture, ici dans les stations de réservation. Mais un avantage est que le banc de registre a besoin de moins de ports de lecture, car une bonne partie des opérandes sont fournies par le système de contournement. Nous verrons cela dans le détail dans le chapitre sur les processeurs superscalaires. Il a été proposé de fusionner le tampon de ré-ordonnancement avec la fenêtre d'instruction dans une structure unique. La méthode a notamment été utilisée sur les processeurs d'architecture K6 d'AMD. Le tout donnait une structure appelée le '''DRIS''' (''deferred scheduling register renaming instruction shelf''). La différence avec une fenêtre d’instruction normale est que les entrées sont libérée non pas quand l'instruction est exécutée/émise, mais quand elle termine son exécution et quitte le ROB. La fenêtre d'instruction doit alors incorporer des bits pour savoir si telle entrée a émis sont instruction ou non. ===La logique d'éveil et de sélection=== Dans le cas qui va suivre, on suppose que le processeur ne peut émettre qu'une instruction à la fois. Chaque cycle, une instruction est sélectionnée et est envoyée dans le chemin de données, soit à une ALU, soit à une unité d'accès mémoire. La sélection d'une instruction est effectuée par l'unité d'émission, qui est aussi appelée le '''''scheduler'''''. Elle gère la disponibilité des opérandes et la disponibilité des unités de calcul adéquate. Le choix de l'instruction émise doit être le plus pertinent possible, pour des raisons de performances. Pour le premier point, l'unité d'émission détermine quelles instructions sont candidates pour l'émission. Les ''instructions candidates'' sont celles dont tous les opérandes sont prêts. Le processeur contient un circuit qui détecte les instructions candidates : la '''logique d’éveil''' (''wake-up logic''). Une fois que la logique d'éveil a fait son travail, une instruction est choisie pour s’exécuter en fonction de la disponibilité des unités de calcul adéquates. Ce rôle est dévolu à un circuit qu'on appelle la '''logique de sélection''', ou ''select logic''. [[File:Fonctionnement complet de la logique d’émission.jpg|centre|vignette|upright=1.5|Fonctionnement complet de la logique d’émission.]] La logique de sélection doit gérer le fait que les unités de calcul du processeur ne sont pas toutes identiques. Déjà, un processeur a généralement des unités séparées pour les instructions entières et flottantes, des unités spécialisées dans les accès mémoire, parfois des unités spécialisées pour les branchements. Une instruction doit être attribuée à la bonne unité de calcul, on ne doit pas envoyer une instruction entière dans une unité de calcul flottante. De plus, parmi les unités de calcul entières, toutes ne sont pas identiques. Par exemple, il est fréquent d'avoir plusieurs unités de calcul spécialisées dans les opérations simples (additions, soustractions, opérations logiques) avec une unité pour les multiplications/divisions séparées, parfois une unité spécialisée pour les décalages/rotations, etc. Là encore, allouer la bonne instruction à la bonne ALU est complexe. Plus les unités de calcul sont hétérogènes, plus la logique de sélection est compliquée. Les logiques d'éveil comme de sélection sont assez complexes. Comme on le verra plus bas, la logique de sélection la plus simple, qui gère une seule unité de calcul, est basée sur un encodeur à priorité couplé à d'autres circuits. Et pour gérer plusieurs ALUs, il faut mettre des encodeurs en cascade. Le résultat est que même en prenant une logique de sélection simple, elle sera assez lente et gourmande en circuits. Aussi, la logique de sélection met souvent un cycle d'horloge entier pour faire son travail, elle a son propre étage de pipeline attribué. La logique d'éveil est dans le même cas, ce qui fait qu'émettre une micro-opération demande deux cycles d'horloge. Le défaut est que cela rajoute des cycles d'horloges entre la fenêtre d'instruction et l'ALU, ce qui complique la gestion du pipeline. Ces cycles de retard sont à prendre en compte au moment d'émettre les instructions, les ''scheduler'' doit en tenir compte pour des performances optimales. Sans tenir compte de ces cycles de retard, les instructions arrivent en retard de quelques cycles à l'ALU, cycles de retard durant lesquels l'ALU n'a pas fait de calcul et a été sous-utilisée, sans compter que le système de contournement n'est pas utilisé au mieux. Et le problème est encore plus important sur les processeur avec des stations de réservation, qui utilisent la "lecture après émission" : cela rajoute un cycle d'horloge en plus, un temps de retard en plus. ===La logique d'éveil : l'émission anticipée=== La logique d'éveil doit tenir compte du fait qu'il y a plusieurs étages entre l'émission et l'exécution sur une unité de calcul. Par exemple, un processeur a souvent entre un et à cinq étages entre la file d'attente et les unités de calcul. Il faut lire les registres, gérer le contournement, et cela peut prendre quelques cycles d'horloge. Sur le Pentium 4, on trouve 6 étages entre la fenêtre d’instruction et l'entrée de l'ALU. Si les micro-opérations sont émises quand les opérandes sont disponibles, il y aura un délai de quelques cycles avant qu'elles atteignent l'ALU. Alors qu'idéalement, on souhaiterait que la micro-opération atteigne l'ALU dès que ses opérandes sont disponibles, pour profiter des techniques de contournement. Pour cela, la logique d'éveil émet les instructions quelques cycles en avance pour qu'elles arrivent au bon moment. Il s'agit d'une technique d''''émission anticipée''', dont nous avions parlé dans le chapitre sur le contournement. : Il faut noter que le problème se pose plus avec des fenêtres d'instruction qu'avec des stations de réservation. Les premières ont un étage en plus entre émission et ALU, vu qu'il faut lire des registres après l'émission. L'émission anticipée demande d'émettre un signal d'éveil en avance de quelques cycles, pile au bon moment. Par exemples, si on a deux étages entre l'ALU et l'unité d'émission, le signal de réveil sera généré deux cycles avant que le résultat soit effectivement calculé. L'implémentation varie, mais deux solutions sont possibles. La première est de générer le signal d'éveil dans l'ALU, ce qui n'a de sens que pour les opérations comme les multiplications ou les divisions, qui prennent plusieurs cycles. Une autre technique génère le signal de réveil dans une structure centralisée, spécialisée dans la génération des signaux d'éveil. L'unité de composée d'un registre à décalage par registre. Imaginons qu'une instruction est émise, que cette instruction mette N cycles à s'exécuter, et qu'elle écrive dans un registre de destination. L'unité sélectionne alors le registre à décalage associé au registre de destination, et met le bit numéro N à 1. Le registre décalé d'un cran à chaque cycle. Quand le bit sortant est un 1, alors le signal de validité pour l'opérande est généré. L'émission anticipée marche bien si l'instruction a une durée fixe, connue à l'avance. Et autant c'est le cas pour les instructions arithmétiques et logiques, autant ce n'est pas le cas pour les accès mémoire. Les accès mémoire ont une latence variable : quelques cycles pour un succès de cache, plusieurs dizaines de cycles pour un défaut de cache L1, pas loin de la centaine pour un défaut de cache L2, etc. Et cela pose des problèmes pour l'émission anticipée. L'émission en avance pour les accès mémoire est purement spéculative : le processeur émet des instructions en supposant que la lecture entrainera un succès de cache, quitte à annuler l'instruction en cas de défaut de cache. Mais faire ainsi demande non seulement d'annuler les instructions émises en avance, mais aussi de ne pas retirer les instructions émises en avance de la fenêtre d'instruction. Elles sont émises, mais une copie de sauvegarde est conservée dans la fenêtre d'instruction. Si le processeur détecte un défaut de cache, il peut alors ré-exécuter l'instruction. S'il détecte un succès de cache, les instructions lecture-dépendante sont retirées de la fenêtre d'instruction, la copie de sauvegarde est devenue inutile et est donc jetée. ===La logique de sélection : âge ou position ?=== La logique de sélection est primordiale pour de bonnes performances. Il existe deux méthodes principales pour sélectionner l'instruction à exécuter. La première est la plus simple : elle se base sur lé numéro de l'entrée. En effet, une fenêtre d'instruction est avant tout une sorte de mémoire, un mix entre mémoire associative, mémoire RAM, et FIFO. Et chaque entrée a un numéro, une adresse mémoire. Nous parlerons de numéro dans ce qui suit, car ce sera plus simple, le terme d'adresse mémoire étant peut-être un peu exagéré dans le contexte des fenêtres d'instruction. Toujours est-il que la fenêtre d'instruction est adressable dans le sens où on peut lui envoyer le numéro de l'entrée voulue, et la fenêtre d’instruction renvoie le contenu de l'entrée sur son port de lecture. Et c'est ce que fait la logique de sélection : elle génère le numéro de l'entrée à lire. Le numéro est alors envoyé sur l'entrée d'adresse de la fenêtre d’instruction, et elle fournit la micro-opération associée sur son port de lecture, son '''port d'émission'''. La première méthode de sélection, donc. Elle est basée sur sur le numéro de l'entrée. Si plusieurs entrées sont éveillées, la logique de sélection prend celle avec le plus petit numéro. Elle porte le nom de '''sélection par position''', sous-entendu position dans la fenêtre d'instruction. Vous l'avez peut-être deviné, mais la logique de sélection est alors un encodeur à priorité. Le circuit de sélection ne se résume donc pas seulement à un encodeur à priorité, mais c'est le circuit central. L'avantage d'une telle méthode de sélection est qu'elle est simple à implémenter : un encodeur à priorité est un circuit connu, facile à implémenter. Mais on remarque un défaut : un encodeur est un circuit assez rapide, mais qui utilise beaucoup de transistors, beaucoup de portes logiques, surtout si on veut qu'il soit rapide. Ce qui explique que la logique de sélection ait son propre étage de pipeline rien que pour elle. La seconde méthode s'appelle la '''sélection par âge''', au nom assez transparent. L'idée est de privilégier l'émission de l'instruction la plus ancienne. Elle demande que la fenêtre d'instruction trie les micro-opérations par ordre d'insertion dans la fenêtre d'instruction, ce qui en fait une pseudo-FIFO. Le tri est partiel, car les instructions peuvent sortir de la fenêtre d’instruction à tout moment. Compacter la fenêtre d'instruction, à savoir regrouper toutes les entrées valides est une idée, mais elle est compliquée à implémenter. Aussi, elles préfèrent encoder des informations sur l'ordre d'émission dans chaque entrée. L'encodeur à priorité doit alors travailler non pas sur des nombres entiers liés à l'ordre d'insertion dans la pseudo-FIFO. Elle est encore plus gourmande en circuits que la méthode précédente. Les processeurs haute performance utilisent souvent des méthodes hybrides. Par exemple, les processeurs AMD de microarchitecture Bulldozer utilisaient une méthode intermédiaire. Ils utilisaient une fenêtre d'instruction couplée à un encodeur à priorité pour la sélection par position, mais complémentaient le tout avec une unité qui mémorisait l'instruction la plus ancienne dans la fenêtre d’instruction. Le mécanisme de sélection par âge était utilisé en priorité. Mais si l'instruction la plus ancienne n'était pas prête, le processeur basculait sur le mécanisme de sélection par position. ===La compaction des fenêtres d'instruction=== À chaque cycle, les instructions décodées sont ajoutées dans la fenêtre d'instruction, dans des entrées vides. Vu que les instructions quittent celle-ci dans le désordre, ces vides sont dispersés dans la fenêtre d'instruction, ce qui pose problème pour déterminer où placer les nouvelles instructions. La solution la plus triviale consiste à conserver une liste des vides, mise à jour à chaque insertion ou émission d'instruction. Une autre solution consiste à éliminer les vides en compactant la fenêtre d'instruction à chaque cycle d'horloge. Des circuits se chargent de détecter les vides et de regrouper les instructions en un unique bloc. Il faut signaler que certaines processeurs arrivent à se passer de cette étape de compactage, mais au prix de fenêtres d'instruction nettement plus complexes. Autre problème : quand il faut choisir quelle instruction émettre, il y a toujours plusieurs candidats. Si on choisit mal, des instructions restent en attente trop longtemps parce que d'autres instructions plus jeunes leur passent devant. Pour éviter cela, les instructions les plus vielles, les plus anciennes, sont prioritaires. Pour cela, on peut utiliser une FIFO un peu spéciale pour la fenêtre d'instruction. Si les ajouts d'instruction se font dans l'ordre, les instructions ne quittent pas forcément la fenêtre d'instruction dans l'ordre imposé par une FIFO : les instructions restent triées dans leur ordre d'ajout, même s'il y a des vides entre elles. Dans ces condition, il est préférable que le compactage conserve l'ordre FIFO des instructions. Dans ces conditions, l'instruction la plus ancienne est celle qui est située à l'adresse la plus faible : le circuit de sélection peut donc être fabriqué avec des encodeurs, et est relativement simple. ==Les fenêtres d'instruction basées sur une matrice de dépendances== L'implémentation la plus simple étend le fonctionnement d'un pipeline dynamique usuel. Rappelez-vous le chapitre sur les pipeline dynamiques. Nous avions vu que de tels pipelines émettaient une instruction par cycle, quitte à émettre des bulles de pipeline en cas de dépendance bloquante. Et il est possible d'améliorer leur unité d'émission pour qu'elle soit compatible avec l'exécution dans le désordre. ===Rappels sur le registre de réservation/disponibilité=== L'émission d'une instruction est gouvernée par un ''registre de réservation'' qui indique quels registres sont réservés par une instruction, et ceux qui sont libres. Un registre réservé est un registre qui sera écrit par une instruction en cours d'exécution, mais qui n'a pas encore écrit son résultat. Les instructions candidates doivent avoir leurs opérandes dans des registres libres. Sinon, c'est signe que leurs opérandes sont réservées en écriture, donc pas encore écrites, donc pas disponibles. Si une instruction candidate veut lire ce registre, c'est signe qu'il y a une dépendance RAW : elle veut lire un registre réservé, qui est destiné à être écrit par une instruction en vol. Si elle veut écrire, c'est signe qu'elle veut écrire dans un registre où une autre instruction veut écrire : c'est une dépendance WAW. Dans les deux cas, l'instruction n'est pas émise. Le registre de réservation encode les registres réservés comme suit : chaque bit est associé à un registre. Le bit numéro 0 est associé au registre numéro 0, le bit numéro 1 au registre numéro 1, etc. Là, En clair, les numéros de registres réservés sont encodés en représentation non pas binaire, mais en représentation ''one-hot'' (vue au premier chapitre). {|class="wikitable" |+ Registre de réservation |- ! Registre 7 !! Registre 6 !! Registre 5 !! Registre 4 !! Registre 3 !! Registre 2 !! Registre 1 !! Registre 0 |- | 0 || 0 || 1 || 0 || 0 || 1 || 0 || 0 |} Avant d'émettre une instruction, l'unité d'émission extrait les registres opérande/destination et les convertis dans la même représentation que le registre de réservation, à savoir en représentation ''one-hot''. Le circuit de traduction binaire vers ''one-hot'' est, pour rappel, un simple décodeur. Puis, on fait un OU logique entre les sorties des décodeurs. Le résultat est un masque qui indique quels registres sont lus par l'instruction, encodé en représentation ''one-hot''. Appelons-le le '''masque d'opérandes'''. Le masque est alors comparé au registre de réservation pour vérifier si l'instruction peut être émise. [[File:Unité d'émission simple, dans l'ordre.png|centre|vignette|upright=2|Unité d'émission simple, dans l'ordre]] Si l'émission est autorisée, le registres de réservation est là aussi mis à jour. Le registre de réservation est aussi mis à jour dès qu'une instruction enregistre son résultat dans les registres, ou alors dès qu'il est disponible pour le contournement. Le bit associé au registre repasse alors à 0 (ou à 1). Sans contournement, la mise à jour se fait alors à la toute fin de l'instruction, quand elle se termine, lors de la dernière étape d'enregistrement, à la fin de son pipeline. Avec, elle se fait quand l'instruction quitte l'unité de calcul. ===L'extension à l'exécution dans le désordre : l'éveil par matrice de bits=== La différence entre un pipeline dynamique et l'exécution dans le désordre est que l'on passe d'une instruction à émettre à plusieurs. Plusieurs instructions sont mises en attente dans une fenêtre d’instruction, et y attendent leur tour. L'idée est alors d'envoyer le registre de disponibilité à toutes les entrées, à toutes les instructions en attente. Ainsi, on sait quelles sont les instructions qui peuvent s'exécuter et celles qui ne le peuvent pas. L'implémentation est assez simple, elle ressemble beaucoup à l'implémentation d'un pipeline dynamique simple, si ce n'est que des circuits sont dupliqués. L'implémentation utilise des fenêtres d'instruction légèrement différentes de celles introduites plus haut. Elles n'utilisent notamment pas de bits de disponibilité, mais autre chose. Lorsqu'une instruction est ajoutée à la fenêtre d'instruction, le masque de disponibilité des opérandes est stocké dans la fenêtre d'instruction. A chaque cycle, le registre de disponibilité est envoyée à toutes les entrées, et est comparé avec tous les masques de disponibilité des opérandes. Si une comparaison renvoie un 1, alors l'instruction de l'entrée est une instruction candidate à l'émission. [[File:Unité d'émission dans le désordre basée sur un registre de disponibilité.png|centre|vignette|upright=2.5|Unité d'émission dans le désordre basée sur un registre de disponibilité]] L'ensemble est implémenté avec l'aide d'une '''matrice de bits''', où chaque ligne correspond à une entrée et chaque colonne à un registre. À chaque croisement entre une ligne et une colonne, on trouve un bit. Si le bit de la ligne n et de la colonne m est à 1, cela veut dire : l'instruction dans l'entrée n a besoin de lire le registre m. S’il est à 0, alors cela veut dire que l'instruction stockée dans la ligne n n'a pas besoin de la donnée dans le registre m. [[File:Planificateur à matrice de bits.jpg|centre|vignette|upright=2|Planificateur à matrice de bits.]] Lorsqu'une instruction réserve une entrée, elle initialise la ligne en fonction des registres qu'elle souhaite lire. Pour vérifier si une instruction a ses opérandes prêts, le processeur compare le registre de disponibilité à la ligne associée à l'instruction/entrée. A chaque intersection ligne-colonne, se trouve un comparateur de 1 bit, qui détecte si le registre est demandé et disponible. Les résultats de cette porte sont ensuite envoyés à une porte ET, qui fait le gros du travail. [[File:Logique de détection de la disponibilité d'une instruction.jpg|centre|vignette|upright=2|Logique de détection de la disponibilité d'une instruction.]] ==Les fenêtres d'instruction basées sur une mémoire associative== Les processeurs modernes utilisent une mémoire associative pour la fenêtre d'instruction. Les mémoires associatives ont été abordées il y a quelques chapitres, mais faisons quelques rappels. Les mémoires associatives servent à accélérer la recherche de données dans un ensemble. Or, une fenêtre d'instruction vérifie régulièrement si chaque entrée est prête. Il s'agit d'un processus de recherche d'une instruction qui respecte une condition bien précise dans la mémoire, ce qui fait que les mémoires associatives sont donc tout indiquées. Comme vous le savez, les signaux de commande d'une instruction sont propagés avec celle-ci dans le pipeline, le nom du registre de destination ne faisant pas exception. Le nom de registre est envoyé à la fenêtre d'instruction lors de l'écriture du résultat dans les registres. S'il y a correspondance, l'opérande est disponible et son bit de disponibilité est mis à 1. On peut adapter cette méthode pour tenir compte du contournement assez simplement. [[File:Détection des dépendances par propagation du registre de destination.png|centre|vignette|upright=2|Détection des dépendances par propagation du registre de destination.]] En conséquence, le circuit de détection des dépendances est constitué d'un grand nombre de comparateurs : un par champ « nom de registre » dans chaque entrée. La logique d'éveil/''wake up'' regroupe tous les comparateurs, la logique de sélection est un circuit situé en-dehors de la mémoire associative. Les entrées sont dans la mémoire associative elle-même. [[File:Gestion des bits de validité.png|centre|vignette|upright=2|Gestion des bits de validité.]] L'implémentation la plus simple est celle du schéma précédent, où on utilise une mémoire associative unique. Une version plus élaborée sépare la fenêtre d'instruction en deux parties : une mémoire qui mémorise les registres des opérandes, une autre mémoire pour le reste. La mémoire pour les registres opérandes est la mémoire associative proprement dite, c'est elle qui est associées aux comparateurs, à la logique de ''wake-up''/réveil, etc. Par contre, l'autre mémoire est une mémoire RAM simplifiée, qui mémorise les informations qui n'ont pas besoin des comparateurs. L'opcode de l'instruction est là-dedans, par exemple. ===Les optimisations de la consommation d'énergie : la désactivation des portions inutilisées=== Le problème avec des fenêtres d'instruction de ce type est leur forte consommation énergétique, ainsi que le grand nombre de portes logiques utilisées, qui deviennent prohibitif pour des fenêtres d'instruction un peu grosses. Pour résoudre ce problème, certains ont optimisé les comparateurs. D'autres ont tenté de profiter du fait que la majorité des bits dans les entrées sont composés de zéros. Bref, les optimisations purement matérielles sont légion. Une première solution est de désactiver les entrées qui sont inutilisées, vides, sans instruction. Pour cela, on fait précéder les comparateurs par un circuit qui les connecte ou déconnecte des lignes de bit. Le circuit est commandé par le bit ''empty'' qui indique si une entrée est vide ou non. L'avantage est que la consommation d'énergie de la fenêtre d'instruction devient alors proportionnelle au nombre d'entrées non-vides, et non au nombre d'entrées total. Du moins, en apparence, les entrées non-utilisées doivent quand même être alimentées pour fonctionner, mais l'activité de comparaison disparait dans les entrées vides. Il est possible d'étendre cette technique aux entrées dont les opérandes sont prêtes. Les gains sont généralement assez bons, avec une réduction de consommation variant entre 30 et 50%, avec une implémentation très simple et très économe en circuits. Une autre solution, assez simple à mettre en place, consiste à désactiver une partie de la fenêtre d'instruction sin elle est inutilisée. Pour cela, il faut segmenter la fenêtre d'instruction avec la technique du ''wire partitionning''. Pour rappel, une fenêtre d'instruction est une mémoire associative. Et comme toute mémoire associative, elle contient des fils, les lignes de bit, qui relient les entrées/sorties à toutes les cellules mémoire. Plus une ligne de bit est longue, plus elle consomme d'énergie et plus le temps de lecture/écriture est long. L'idée est de segmenter les lignes de bits en plaçant des répéteurs qui recopient la tension d'un segment au suivant. Les répéteurs sont des tampons trois-états, ce qui permet de déconnecter les portions inutilisées de la ligne de bit. Ce faisant, la fenêtre d'instruction est découpée en segments, qui peuvent être désactivés si besoin. Si il y a peu d'instructions chargées dans la fenêtre d'instruction, les portions inutilisées sont désactivées. La technique marche d'autan mieux si les instructions sont compactées au début de la fenêtre d'instruction. [[File:Wire partitionning.png|centre|vignette|upright=2|Wire partitionning]] Tout le problème est de savoir quelles portions désactiver. La technique est assez simple si la fenêtre d'instruction est compactée, à savoir si toutes les instructions sont régulièrement regroupées au début de la mémoire CAM. Mais même avec cette optimisation, la décision de désactiver une portion de la fenêtre d'instruction n'est pas à prendre à la légère. Il ne faut pas désactiver une portion contenant des instructions pouvant être émise sous peu. La décision dépend de paramètres variés : proportion d'entrée vides, quantité d'entrées récemment activées/désactivées récemment, présences d'entrées avec un ''match'' d'opérandes récent, etc. Il est important de préciser que les techniques en question fonctionnent aussi sur les autres types de fenêtre d'instruction, qui ne sont pas basées sur des mémoires associatives. Nous allons voir celles-ci dans la suite du chapitre, mais gardez à l'esprit que ces optimisations, à savoir désactiver les entrées vides/prêts et partitionner la fenêtre d'instruction, sont des optimisations générales qui marchent avec presque tout. ===L'ajout d'une FIFO pour les instructions déjà prêtes à l'émission=== D'autres techniques permettent de réduire aussi bien le cout en circuits que la consommation d'énergie de la fenêtre d'instruction. L'idée est d'utiliser une mémoire associative quand elle est réellement nécessaire, mais d'utiliser une fenêtre d'instruction "normale" dès que possible. La méthode la plus simple tient compte du fait que certaines instructions ont déjà toutes leurs opérandes de disponibles à l'émission, mais doivent quand même être mises en attente, parce que l'ALU adéquate est occupée, parce que des dépendances WAW/WAR sont encore là, ou pour tout autre raison. Dans ce cas, elles sont mises en attente non pas dans la fenêtre d'instruction, mais dans une mémoire FIFO toute simple. L'idée est qu'au lieu d'avoir une énorme mémoire associative pour la fenêtre d'instruction, on déplace quelques entrées dans une petite FIFO annexe. Le résultat est un gain en terme d'énergie et de circuits, au prix d'une perte de performance mineure. La perte de performance en question se manifeste si aucune instruction n'a ses opérandes de prêtes à l'émission : le programme n'utilise pas la FIFO et voit alors une fenêtre d'instruction plus petite. Une amélioration de cette technique tient compte du fait que certaines instructions sont dans un cas intermédiaire. Elles ont déjà une opérande de prête lors de l'émission, mais pas l'autre. Le nombre d'opérandes varie suivant l’instruction : certaines n'ont besoin que d'un seul opérande. De plus, il arrive qu'une opération tout juste décodée ait déjà un ou plusieurs de ses opérandes de prêts. Cette constatation permet d'éviter d'utiliser des comparateurs pour les opérandes déjà prêts. Par exemple, on peut parfaitement utiliser trois fenêtres d'instruction : * une pour les instructions dont tous les opérandes sont prêts, mais qui sont quand même mises en attente, sans comparateur ; * une pour les instructions dont un seul opérande manque, qui n'utilise qu'un comparateur par entrée ; * une pour les instructions dont deux opérandes manquent à l'appel, qui utilise deux comparateurs par entrée. C'est beaucoup plus économique que d'utiliser une seule grosse fenêtre d'instruction qui contiendrait autant d'entrées que les trois précédentes réunies, avec deux comparateurs par entrée. Certains sont même allés plus loin, et ont proposé de supprimer la fenêtre d'instruction avec deux opérandes par entrée. Les instructions dont deux opérandes sont inconnus au décodage sont stockées dans la fenêtre d'instruction pour instructions avec un comparateur par entrée. Un circuit de prédiction se charge alors de prédire l'opérande manquant, cette prédiction étant vérifiée plus loin dans le pipeline. Il serait cependant étonnant qu'une telle proposition ait donné lieu à la moindre implémentation réelle. ===Les optimisations de la consommation d'énergie avancées=== D'autres chercheurs ont conservé une fenêtre d'instruction unique, avec autant de comparateurs par entrée qu'il y a d'opérandes possibles par instruction. Simplement, le processus de détection des opérandes prêts est légèrement ralenti : on ne vérifie qu'un opérande par cycle. Pour vérifier les deux opérandes d'une entrée, on doit attendre deux cycles. Enfin, certains chercheurs ont proposé des fenêtres d'instruction segmentées. Les instructions circulent à chaque cycle d'un segment vers le suivant : en conséquence, certains segments conservent les instructions les plus anciennes, un autre les instructions les plus jeunes, etc. Seul le denier segment, celui qui contient les instructions les plus vielles, peut émettre une instruction : la détection des opérandes se fait seulement dans le dernier segment, qui contient les instructions les plus anciennes. On économise ainsi beaucoup de comparateurs. Certains chercheurs ont tenté de pipeliner l'étape de sélection des opérandes, ainsi que l'étage d'arbitrage. Mais en faisant cela, il faut plusieurs cycles pour détecter qu'une instruction a ses opérandes prêts, ce qui pose problème face à de nombreuses dépendances RAW. Pour éviter de trop perdre en performances, certains chercheurs ont décidé d'utiliser des techniques pour prédire quelles seront les instructions dont les opérandes seront bientôt prêts. Si détecter qu'une instruction est prête prend n cycles, le processeur devra tenter de prédire la future disponibilité des opérandes n cycles en avance pour obtenir des performances optimales. ===Remplacer la mémoire associative par une RAM=== Une autre optimisation possible est de remplacer la fenêtre d'instruction par une mémoire RAM, dont chaque mot mémoire correspondrait à une entrée. Une telle optimisation permet en théorie de se passer des comparateurs associés à chaque entrée, mais au prix de l'ajout de circuits annexes potentiellement couteux. La première de ces techniques, la '''recherche directe par étiquette''' (direct tag search) fut créée par Weiss et son collègue Smith. Ils cherchaient à améliorer l'algorithme de Tomasulo, un algorithme qu'on expliquera dans quelques chapitres. Rappelons que chaque instruction produit un résultat, qui devra être rapatrié dans une ou plusieurs entrées de la fenêtre d'instruction. L'optimisation de la recherche directe par étiquette fonctionne dans le cas où le résultat de l'instruction n'est utilisé que par une seule entrée, et pas plusieurs. Le principe est simple : chaque champ « opérande » d'une entrée est adressable via le nom de registre de cette opérande. Pour faire le lien entre entrée et nom de registre, la recherche directe par étiquette ajoute une table de correspondances matérielle, une mémoire RAM qui mémorise les adresses des champs « opérande » des entrées. Les adresses envoyées dans cette mémoire sont les noms de registres des résultats. Lors de l'émission, la table de correspondances est mise à jour. Les numéros des champs « opérande » réservés lors de l'émission sont mémorisés dans les mots mémoire qui correspondent aux deux registres sources. Toutefois, une petite vérification est faite lors de l'émission : si il y a déjà une correspondance dans la table pour un registre source, alors une autre instruction compte lire ce registre. Pour éviter d'écraser les données de l'instruction précédente dans la table de correspondances, l'émission de l'instruction est bloquée. [[File:Recherche directe par étiquette.png|centre|vignette|upright=2|Recherche directe par étiquette.]] ==Les fenêtres d’instruction avec préplanification== Avec la '''préplanification''' (''prescheduling''), la fenêtre d’instruction est composée de mémoires FIFO dans lesquelles les instructions sont triées dans l'ordre d'émission. Il n'y a pas de logique d’émission proprement dite, celle-ci se bornant à vérifier si l'instruction située au début de la FIFO peut s’exécuter. Par contre, le préplanificateur détecte les dépendances et en déduit où insérer les instructions dans le tampon d'émission, à l'endroit le plus adéquat. [[File:Préplanification.jpg|centre|vignette|upright=2|Préplanification.]] ===L'usage de FIFO multiples=== La technique de préplanification la plus simple utilise plusieurs FIFO. Quand une instruction a une dépendance avec une autre instruction, les deux sont placées dans la même FIFO. Pour cela, le préplanificateur détecte les chaines d'instructions dépendantes, et place les instructions dans la FIFO adéquate. A chaque cycle, l'unité d'émission lit une micro-opération dans chaque FIFO et vérifie si elle peut l'émettre. Si la micro-opération n'a pas ses opérandes disponibles, ou qu'une dépendance structurelle survient, alors la FIFO est bloquée. La micro-opération attend que la dépendance soit résolue, bloquant toutes les instructions précédentes. Mais les autres FIFO ne sont pas bloquées, laissant de la marge de manœuvre. [[File:Préplanification par FIFO multiples.png|centre|vignette|upright=1.5|Préplanification par FIFO multiples.]] ===La technique du tampon trié=== La technique du '''tampon trié''' trie les instructions selon le temps d'attente avant leur exécution. Les instructions qui sont censées s’exécuter bientôt sont insérées au tout début de la FIFO, tandis que les instructions qui s’exécuteront dans un long moment sont insérées vers la fin. Là encore, l'unité d'émission lit une micro-opération dans la FIFO, et détermine si elle peut être émise. Si une dépendance survient, l'émission est retardée, et la FIFO est bloquée. [[File:Préplanification par tampon trié.png|centre|vignette|upright=1.5|Préplanification par tampon trié.]] La technique a cependant quelques problèmes assez importants. Le premier problème est que la FIFO est bloquée lorsqu'une micro-opération ne peut être émise. Le second problème est que le temps avant exécution n'est pas toujours connu, notamment pour les instructions d'accès mémoire. Et cela se répercute sur les instructions dépendantes de celles-ci. Pour résoudre ce genre de problèmes, l'usage d'un pipeline à ''replay'' est possible, et est même l'une des meilleures solution possible, malgré ses défauts. L'idée est que les lecture sont pré-planifiées en supposant qu'elles font un succès de cache L1. Si la prédiction est fausse, la lecture est ré-exécutée plusieurs cycles plus tard, en supposant qu'elle fait un succès dans le cache L2, et ainsi de suite. Elle est alors ré-insérée dans la FIFO, elle est pré-planifiée une seconde fois. Il en est de même si une micro-opération ne peut pas être émise : il suffit de la réinsérer dans la FIFO au bon endroit, en attendant que ses dépendances soient résolus. Ainsi, l'instruction fautive ne bloque pas la fenêtre d’instruction, et retente sa chance autant de fois qu'il le faut. [[File:Préplanification par fenêtre d’instruction scorebarodée.png|centre|vignette|upright=1.5|Préplanification par fenêtre d’instruction scorebarodée.]] Une autre solution utilise deux fenêtres d’instruction : une FIFO gérée par la préplanification, et une vraie fenêtre d'instruction pour les instructions dont le temps d'attente ne peut pas être déterminé. Il est possible de mettre cette dernière avant la préplanification, afin de gérer les temps d'attente des instructions d'accès mémoire. Quand le temps d'attente d'une lecture devient connu, ses instructions dépendantes sont gérées avec préplanification. [[File:Préplanification avec fenêtre d’instruction.png|centre|vignette|upright=2.5|Préplanification avec fenêtre d’instruction.]] ===Les fenêtres d'instruction avec allocation temporelle statique=== L''''allocation temporelle statique''' correspond à une technique utilisée sur les processeurs Cuzco de l'entreprise Condor. La technique en question a été présenté en 2025, mais des idées similaires ont été présentées dans la littérature académique. Elle ressemble beaucoup aux techniques de pré-planification, avec cependant quelques différences. L'idée est simple : le processeur dispose de plusieurs fenêtres d'instruction, qui mettent en attente les micro-opérations. Lors de l'étape de renommage de registres, le processeur détermine dans combien de cycles d'horloge la micro-opération sera prête pour exécution. La micro-opération est alors mise en attente durant ce nombre de cycles, dans les fenêtres d'instruction, puis est émise une fois ce nombre de cycles écoulés. Ce faisant, les fenêtres d'instruction n'ont pas besoin de détecter la disponibilité des opérandes à chaque cycle, pour chaque micro-opération en attente. Le ''timing'' de l'émission des micro-opérations est décidé à l'avance. L'implémentation exacte n'est pas connue, mais plusieurs solutions sont imaginables. Par exemple, la fenêtre d'instruction peut simplement être composée de plusieurs mémoires de petite taille, chacune contenant les micro-opérations destinées à être exécutées dans N cycles, N étant différent pour chaque mémoire. Une autre solution, plus réaliste, utilise une fenêtre d'instruction dans laquelle la micro-opération est couplée à des champs pour les opérandes, et un champ compteur. Le champ compteur est initialisé avec le nombre de cycles à attendre, et est décrémenté à chaque cycle d'horloge. Quand il atteint zéro, la micro-opération est émise. Vous remarquerez que la méthode ne marche que si toutes les micro-opérations prennent un nombre fixe de cycles d'horloge. Et autant c'est le cas pour les micro-opérations arithmétiques ou logiques, autant les accès mémoire ne rentrent pas dans ce cadre. En théorie, on ne sait pas combien de temps prendra un accès mémoire. Et cette incertitude se répercute sur les instructions dépendantes d'un accès mémoire. Pour éviter cela, le processeur réutilise un pipeline à ''replay'' tel que vu dans le chapitre précédent. L'unité de renommage de registre suppose que tout accès mémoire fait un succès de cache L1, et décide des ''timings'' d'émission sous cette hypothèse. Si une lecture subit un défaut de cache, elle est ré-exécutée, de même que toutes les instructions dépendantes. Pour cela, le registre de destination de la lecture est marqué comme invalide, grâce à un bit spécifique attaché au registre. Toute instruction qui lit une opérande invalide est elle aussi ré-executée de zéro. Pour simplifier, l'unité d'émission ressemble à une unité d'émission dans l'ordre, avec un registre de disponibilité, qu'on aurait amélioré pour aller au-delà de la simple détection des dépendances d'instruction. Pour déterminer les ''timings'' d'émission, à savoir quand émettre une micro-opération, le processeur utilise une unité d'émission à deux étages. Le premier étage est appelé le ''register scoreboard'', le second étage est appelé la ''Time Ressource Matrix''. Les deux étages communiquent entre eux, comme on va le voir, et leurs noms donnent une idée de ce qu'ils font. Le premier étage gère les dépendances de registres, le second gère les dépendances structurelles. Le premier étage est un registre de disponibilité amélioré, qui gère les dépendances de registre. Cet étage sait quand tel registre sera écrit, et donc que l'opérande écrite dedans sera disponible à partir de tel cycle d'horloge. Il le sait car l'étage suivant l'aura prévenu, mais laissons cela de côté pour le moment. Quand une micro-opération rentre dans cet étage, il vérifie les dépendances avec les registres et les micro-opérations antérieures. Vu qu'il sait quand les registres seront disponibles, il peut déterminer quand l'instruction pourra s'exécuter. Par exemple, si une micro-opération lit les deux registres R7 et R15, qui sont disponibles respectivement dans 5 et 7 cycles, le premier étage sait que la micro-opération devra attendre 7 cycles. Mais tout cela ne suffit pas à déterminer quand émettre une micro-opération. En effet, il fait aussi gérer les dépendances structurelles, ce qui est le boulot du second étage. Le second étage utilise pour cela une ''Time Ressource Matrix'', qui mémorise l'occupation de diverses "ressources", pour les 256 cycles d'horloge à venir. Les ressources en question sont les ports de lecture/écriture du banc de registre, les ALUs utilisées, si la micro-opération utilise l'unité mémoire, etc. Le second étage prend en entrée une micro-opération, détermine quelles "ressources" elle utilise, puis regarde leur disponibilité. Elle détecte alors les dépendances structurelles et détermine alors quand peut s'exécuter la micro-opération. Elle peut retarder l'émission de quelques cycles, si une dépendance structurelle est détectée. Une fois sortie du second étage, on sait quand la micro-opération va être émise, à quel cycle précisément. Et vu que la durée de l'instruction est fixe, on sait quand cette micro-opération va se terminer, quand son résultat sera disponible. Cela permet de mettre à jour la ''Time Ressource Matrix'', pour préciser que le port d'écriture sera occupé à tel moment. De plus, cette information est transmise au premier étage, qui sait alors quand est enregistré le résultat dans le registre de destination. C'est comme cela que le premier étage sait quand un registre est disponible : le second étage le prévient, quand il émet une instruction ! La ''Time Ressource Matrix''mémorise l'occupation des "ressources" pour les 256 cycles d'horloge à venir. Cependant, elle ne vérifie pas les dépendances pour les 256 cycles suivants. Quand elle reçoit une micro-opération, elle teste les dépendances structurelles pour seulement les 8 prochains cycles maximum. Si la micro-opération ne peut pas être émise pendant ces 8 cycles, le pipeline est bloqué, un ''pipeline stall'' est émis. Pour être plus précis, vu que le processeur peut décoder 8 micro-opérations en même temps, cela permet de ne consulter que 64 cycles d'horloge sur les 256. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les premiers processeurs Intel | prevText=Les premiers processeurs Intel | next=Le renommage de registres | nextText=Le renommage de registres }} </noinclude> kiv28da1w57pak683qyeda1j5r1qagt 773597 773596 2026-09-29T19:14:07Z Mewtow 31375 /* Les fenêtres d'instruction décentralisées */ 773597 wikitext text/x-wiki Dans les chapitres précédents, nous avons parlé des techniques dites d''''émission dans l'ordre'''. L'idée est d’exécuter une nouvelle micro-opération à chaque cycle, dans des unités de calcul séparées. Les instructions sont émises consécutivement, mais les instructions s’exécutent en parallèle dans des unités de calcul séparées. Par contre, quand l'unité d'émission ne peut pas émettre une instruction, elle bloque tout le pipeline. Les instructions qui suivent sont elles aussi bloquées, elle doivent attendre leur tour, même si elles sont en capacité de s'exécuter. Les techniques d'exécution dans le désordre que nous allons voir dans ce chapitre corrigent ce point précis. Elles sont dites à '''émission dans le désordre'''. Elles se distinguent des précédentes sur un point précis : quand l'unité d'émission bloque l'émission d'une instruction, les instructions suivantes peuvent poursuivre. L'émission des instructions peut donc se faire dans le désordre, dans le sens où une instruction peut être émise alors qu'une instruction précédente ne l'est pas encore. L'avantage de l'émission dans le désordre est qu'une instruction s'exécute dès que ses opérandes sont disponibles. Par disponible, on veut dire présent soit dans le réseau de contournement, soit dans les registres. Le processeur détecte automatiquement quand les opérandes d'une instruction sont sont disponibles, et il l’exécute à ce moment là. Dès qu'une instruction a ses opérandes disponibles, elle est émise et exécutée. C'est là la seule contrainte : les dépendances WAR, WAW et autres sont gérées par un ROB ou toute autre technique d'exception précise, seules les dépendances RAW limitent l'exécution. Mais avant de poursuivre, quelques point niveaux terminologie : * L'émission dans le désordre est un terme parlant et assez précis. Malheureusement, la terminologie la plus utilisée par d''''exécution dans le désordre'''. Et nous utiliserons ce terme dans la suite du cours, histoire de ne pas trop dévier de la nomenclature habituelle. * Nous utiliserons parfois l'abréviation OOO pour parler d'exécution dans le désordre. L'abréviation est celle de ''Out Of Order Excution''. * Nous utiliserons aussi l'abréviation ''µop'' pour parler de micro-opération, ''µops'' au pluriels pour parler de plusieurs micro-opérations, ou des micro-opérations en général. L'exécution dans le désordre ne gére en effet que des µops, elle se situe après l'étape de décodage. Mais avant de poursuivre, précisons une chose importante : l'exécution dans le désordre traite les accès mémoire à part. La majorité des processeurs OOO assez anciens exécutent les accès mémoire dans l'ordre, seules les µops entières/flottantes/branchements sont exécutées dans le désordre. Les processeurs datant d'après les années 2010 sont capable d'exécuter les accès mémoire dans le désordre, mais l'implémentation en question est assez particulière. Un chapitre entier sera dédié à l'exécution dans le désordre des µops mémoire. Nous allons volontairement mettre de côté la gestion des accès mémoire dans ce chapitre. ==Les fenêtres d’instruction : généralités== [[File:File de micro-opération.png|vignette|upright=1|File de micro-opérations]] Pour décrire comment est implémentée l'émission dans le désordre, il faut commencer par parler des processeurs sans. Les processeurs sans exécution dans le désordre ont une unité d'émission qui bloque tout le pipeline dès qu'une µop ne peut pas être émise. Pour limiter l'impact de ce blocage, quelques rares processeurs incorporent une '''file de micro-opération''', une mémoire FIFO qui met en attente les µops. Vu que c'est une mémoire FIFO, les µops sont émises dans l'ordre, à savoir l'ordre d'ajout, dans l'ordre de décodage. Le schéma ci-dessous illustre une telle file d'attente couplée à un ''scoreboard''. Sur le principe, l'exécution dans le désordre améliore la file de µops sur un point : ce n'est plus une mémoire FIFO. Les µops sont insérées dans l'ordre, mais peuvent sortir dans le désordre (être émises dans le désordre). La file de µops devient alors une '''fenêtre d'instruction''', terme traduit directement de l'anglais ''instruction Window''. Terme assez trompeur, car elles mettent en attente des µops, pas des instructions. Elles peuvent émettre des µops dans le désordre, ce qui fait que si une µop bloque le pipeline, les µops suivantes peuvent être émises. Si je commence le paragraphe précédent par "sur le principe", c'est car certaines techniques d'OOO utilisent des files de µops normales. Il est par exemple possible d'utiliser une file de µops avec une fenêtre d'instruction, plusieurs files de µops, plusieurs fenêtres d'instructions avec une file de µops annexe, etc. Dasn les grandes lignes, il existe dans les grandes lignes 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! File de µops améliorée |- ! Une seule "file de µops" | ''Scoreboard'' | Fenêtre d'instruction centralisée |- ! Plusieurs "file de µops" | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | Fenêtre d'instruction décentralisée |} ===La fenêtre d'instruction centralisée=== L'implémentation la plus simple de l'OOO utilise une unique '''fenêtre d'instruction'''. Les instructions décodées sont accumulées dans la fenêtre d'instruction, où elles attendent que leurs opérandes soient disponibles. La fenêtre d'instruction sert donc de file d'attente. Mais elle contient aussi une unité d'émission, qui détecte quelles µops sont prêtes à être émises. L'unité d'émission et la fenêtre d'instruction sont fusionnées ensemble, elles forment un seul circuit. Mais nous allons dire qu'elles sont conceptuellement séparées pour le moment. A chaque cycle, l'unité d'émission consulte la fenêtre d'instruction pour voir quelles µops peuvent s'exécuter, lesquelles ont leur opérandes de disponibles. La fenêtre d'instruction doit spécialement être conçue pour, c'est une sorte de mémoire associative très complexe, comme on le verra dans ce qui suit. [[File:OOO Issue.png|centre|vignette|upright=2.5|Exécution dans le désordre avec une fenêtre d'instruction]] Une fois qu'une µop sort du décodeur d'instructions, elle est ajoutée en parallèle dans la fenêtre d'instruction et le ROB. La raison est que les µops quittent la fenêtre d'instruction dans le désordre, et qu'elles doivent être remises en ordre par la suite. Le ROB s'occupe de cette remise en ordre, mais il a besoin de savoir dans quel ordre les µops sont censées être, et cet ordre est celui du décodage. Aussi, pour remplir le ROB, la seule opportunité est en sortie de l'unité de décodage. Dans le cas où une instruction est décodée en plusieurs micro-opérations, elles sont toutes insérées en même temps dans la fenêtre d'instruction et le ROB, en tenant compte de leur ordre. [[File:Fenêtre d'instruction.png|centre|vignette|upright=2|Fenêtre d'instruction.]] Les micro-opérations mémoire sont à part des autres, pour diverses raisons. Une de ces raisons est que les dépendances de données sont classées en deux types : les dépendances de registre et les dépendances d'adresse. Et les deux sont fondamentalement différentes. Autant on peut détecter les dépendances de registre lors de l'émission, autant c'est plus compliqué avec les dépendances d'adresse. De plus, rappelons que si les lectures peuvent s'exécuter dans le désordre, les écritures doivent s'exécuter dans l'ordre, ou du moins en donner l'illusion. Pour cela, le processeur remet les écritures dans l'ordre avec une sorte de mini-ROB intégré à l'unité mémoire, appelée la file d'écriture. Elle complémente le ROB, qui lui ne gère que les écritures dans les registres, mais les deux collaborent. La file d'écriture envoie une écriture à la mémoire RAM quand le ROB lui dit que c'est bon, les instructions précédentes sont terminées ''dans l'ordre du programme''. Les processeurs modernes ajoutent des techniques d'exécution dans le désordre des accès mémoire, mais nous les verrons dans un chapitre dédié. Elles permettent d'utiliser une fenêtre d'instruction unique, qui mémorise aussi les µops mémoire. Si elles sont mises en place, l'unité mémoire n'a pas besoin de file de µops séparée. L'idée est que les dépendances de registre sont traitées par la fenêtre d'instruction, mais que l'unité mémoire gére les dépendances d'adresse. Les dépendances d'adresse sont gérées par des techniques de ''désambiguation mémoire'', qui auront droit à un chapitre dédié. [[File:Processeur avec exécution dans le désodre des accès mémoire.png|centre|vignette|upright=2|Processeur avec exécution dans le désodre des accès mémoire]] Les processeurs assez anciens n'autorisaient pas d'exécution dans le désordre des accès mémoire. Concrétement, les accs mémoire devaient se faire dans l'ordre, mais les autres µops pouvaient être exécutées dans le désordre. Il s'agit donc d'un ordre entre µops mémoire, pas entre µops mémoire et autres µops. Les µops entières et flottantes pouvaient être exécutées avant une µops mémoire qui est avant elle dans l'ordre du programme, ce n'est pas un problème. Pour garantir l'ordre desd µops mémoire, l'unité mémoire est précédée par une file de micro-opérations séparée, pour forcer l'exécution dans l'ordre des accès mémoire. De plus, les µops mémoire ne peuvent pas utiliser la fenêtre d'instruction. Dit autrement, la fenêtre d'instruction ne mémorise pas de µops mémoire. Après le décodage, les µops sont réparties soit dans la file de µops mémoire, soit dans la fenêtre d'instruction. Le décodeur classe les µops suivant que ce sont des µops mémoire ou non, et les envoient à la bonne destination. Dans ce chapitre, on supposera que c'est cette solution qui est utilisée. [[File:Processeur avec émission dans l'ordre des accès mémoire.png|centre|vignette|upright=2|Processeur avec émission dans l'ordre des accès mémoire]] La solution précédente revient à scinder la fenêtre d'instruction en deux : une file de µops pour les µops mémoire, une fenêtre d'instruction pour les autres µops. Et cette scission peut aller plus loin, à savoir qu'on peut scinder une fenêtre d'instruction encore et encore. Ce qui nous amène à la section suivante. ===Les fenêtres d'instruction décentralisées=== Nous venons de voir qu'il est possible de scinder la fenêtre d'instruction en une fenêtre d'instruction pour les µops mémoire (simplifiée en une file de µops classique), et une autre pour les autres µops. Sachez qu'il est possible d'aller plus loin, par exemple en séparant la fenêtre d'instruction en une fenêtre spécialisée dans les µops flottantes et une autre pour les µops entières. Et ce n'est là qu'un exemple parmi de nombreuses autres possibilités. Pour faire la différence avec une fenêtre d'instruction unique, nous allons parler de fenêtre d'instruction centralisée s'il n'y en a qu'une, de '''fenêtre d'instruction décentralisée''' s'il y en a plusieurs. Il est possible d'associer chaque fenêtre d'instruction à un type précis de µops. Par exemple, avec une fenêtre d'instruction pour les µops de calcul entières, une autre pour les µops flottantes, une autre pour les µops mémoire. Il s'agit d'un choix simple et efficace, mais quelques processeurs font autrement, pour répondre à des contraintes très diverses. [[File:Processeur avec des fenêtres d'instruction décentralisées.png|centre|vignette|upright=2|Processeur avec des fenêtres d'instruction décentralisées]] Reste à scinder la fenêtre d'instruction pour trier les µops suivant leur type. Si le processeur exécute les accès mémoire dans l'ordre, la méthode la plus simple utilise une fenêtre d'instruction pour les opérations flottantes et une autre pour les autres µops (µops entières et parfois mémoire avec). L'avantage est que cela simplifie grandement le processeur. Les flottants sont gérés à part des entiers. Ils ont leurs propres registres, des FPU séparées des ALU entières, bref : la séparation est complète. Utiliser une fenêtre d'instruction séparée va dans ce sens. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Il est possible de faire pareil sur les processeurs avec exécution dans le désordre des accès mémoire. Par exemple : les processeurs Intel de microarchitecture Skylake utilisent une fenêtre d'instruction pour les opérations entières/flottantes, et une fenêtre d'instruction séparée pour les µops mémoire. Un avantage est que les deux fenêtres d'instructions sont plus spécialisées, ce qui entraine des économies de circuit. Les opérations entières/flottantes ont besoin de deux registres pour les opérandes et d'un autre résultat, alors que les µops mémoire n'ont besoin que de deux registres maximum. En utilisant une fenêtre d'instruction unique, chaque entrée doit mémoriser l'opcode et trois registres, dont un est inutilisé pour les µops mémoire et les branchements. En utilisant des fenêtres d’instructions séparées, celle pour les µops entières/flottantes a trois registres par entrée, contre seulement deux registres par entrée pour celle des µops mémoire. Un cas extrême est celui où chaque ALU/FPU a sa propre fenêtre d'instruction. Nous parlerons alors de '''fenêtres d'instruction totalement décentralisées'''. Par exemple, il y a une fenêtre d'instruction pour l'ALU entière, une autre pour le multiplieur entier, une autre pour le ''barrel shifter'', une autre pour l'unité mémoire, une autre pour l'unitéé de branchements, une autre pour l'additionneur flottant, une dernière pour le multiplier flottant, etc. Un exemple historique est celui de la FPU de l'IBM 360 modèle 90. Elle disposait d'un additionneur flottant, d'un multiplieur flottant, et d'une unité mémoire pour les lectures/écritures flottantes. Les trois unités avaient leur propre fenêtre d'instruction. Les processeurs AMD utilisent beaucoup cette technique, contrairement à Intel qui préfère utiliser des fenêtres centralisées sur les anciens processeurs, deux ou trois fenêtres sur les processeurs récents (2020 et plus). Les processeurs AMD utilisaient précisément une fenêtre d'instruction par ALU entière, alors que les FPUs partagent une fenêtre d’instructions flottantes unique. Mais nous verrons cela en détail dans le chapitre sur les processeurs superscalaires x86. Un point important est qu'avec des fenêtres d'instruction décentralisées, l'émission est découpée en deux étages. La première étape envoie une µops vers la fenêtre d'instruction adéquate, la seconde émet la µops depuis la fenêtre d'instruction quand ses opérandes sont prêtes. La première est l'étage de '''''dispatch''''' qui envoie l'instruction dans la fenêtre d’instruction adéquate, selon que c'est une instruction flottante, entière, autre. La seconde est l'étage de '''''scheduling''''', qui gère la disponibilité des opérandes et des unités de calcul. La µop émise est ajoutée au tampon de réordonnancement, s'il existe, lors de l'étape de ''dispatch''. Il faut noter que quelques processeurs utilisent des méthodes intermédiaires entre les trois solutions précédentes. Par exemple, les processeurs AMD Zen utilisent une fenêtre d'instruction décentralisée un peu particulière. Les unités de calcul entières disposent d'une fenêtre d'instruction rien que pour elles, sur ce processeur. Les instructions flottantes sont quant à elles alimentées par une file de micro-opération, pas une fenêtre d'instruction ! La raison à ce choix est un compromis entre performance et cout en circuit. L'exécution dans le désordre est peu efficace sur les instructions flottantes, car les CPU n'ont que peu d'ALU flottantes séparées. Vu le cout en circuits d'une fenêtre d'instruction, les concepteurs du processeur ont préféré utiliser une file de micro-opération pour les opérations flottantes. ===L'usage de plusieurs files d'instruction=== Une dernière méthode d'OOO utilise plusieurs files de micro-opération. L'idée est qu'une fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement une file de micro-opération pour les opérations entières, une autre pour les opérations flottantes, une autre pour les accès mémoire. D'autres processeurs utilisent une file pour les accès mémoire et une autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. La présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que la technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si une dépendance bloque une FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans une autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer la disponibilité des registres. Quand un registre est lu ou écrit par une instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. La logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : une pour les instructions d'accès mémoire et une autre pour les autres instructions. Si jamais une instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de la lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'une est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est la file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. ===Avantages et inconvénients de chaque implémentation=== Un processeur contient soit une fenêtre d'instruction unique, soit plusieurs fenêtres d'instruction séparées. Typiquement, les fenêtres d’instruction séparées sont spécialisées, dans le sens où on a une fenêtre pour les instructions flottantes, une autre pour les instructions entières, une autre pour les accès mémoire, etc. Pour résumer, on a le choix entre une grosse fenêtre généraliste et plusieurs fenêtres spécialisées, sauf que la fenêtre centralisée est lente et complexe, contrairement aux fenêtres spécialisées. Les deux méthodes ont des inconvénients et des avantages différents. Dans les grandes lignes, l'avantage des fenêtres décentralisées est qu'elles sont plus petites qu'une grosse fenêtre d'instruction. Cela simplifie la gestion du contournement et de la répartition des instructions sur les unités de calcul, comme on le verra dans quelques paragraphes. Elles sont donc moins complexes et plus rapides. L'autre avantage, c'est qu'il est possible de démarrer l'exécution de plusieurs instructions simultanément : une instruction par fenêtre décentralisée, contre une par fenêtre d'instruction. Mais les fenêtres décentralisées sont souvent sous-utilisées, partiellement remplies, contrairement aux fenêtres d'instruction. Il arrive qu'une fenêtre d'instruction soit remplie, alors que les autres sont vides. Par exemple, prenons un processeur avec une fenêtre d'instruction reliée à la FPU, et une autre reliée aux autres ALUs. Si le processeur n'exécute que des opérations flottantes, la fenêtre reliée à la FPU sera pleine, alors que l'autre sera vide. L'exécution des instructions dans le désordre est alors limitée par la petite taille de la fenêtre, qui ne peut plus accepter de nouvelle instruction flottante. Avec une fenêtre unique, on n'aurait pas eu ce problème : on aurait eu une énorme fenêtre d'instruction remplie d'instruction flottante, au lieu d'une petite fenêtre spécialisée. Il est maintenant temps de voir en quoi sont faites les fenêtres d’instruction, qu'elles soient centralisées ou décentralisées. Nous allons aussi voir quelle est la logique d'émission associée. ==L'implémentation d'une fenêtre d'instruction : généralités== Une fenêtre d'instruction est une mémoire qui mémorise des micro-opérations. Elle est cependant plus complexe qu'une mémoire RAM ou qu'une FIFO et ressemble un petit peu à une mémoire cache. Elle dispose d'un port d'écriture et d'un port de lecture, au minimum. Le port d'écriture permet à l'unité de décodage d'insérer une micro-opération dedans, d'ajouter la micro-opération qui vient d'être décodée. Si une instruction machine est décodée en plusieurs micro-opération, deux possibilités. La première est de les insérer un par un, ce qui fait qu'on peut se contenter d'un seul port d'écriture. L'autre possibilité est de les ajouter en même temps, ce qui demande plusieurs ports d'écriture. Le port de lecture sert à émettre une instruction. On part du principe que la fenêtre d'instruction ne peut émettre qu'une seule instruction à la fois, car les processeurs que nous avons vu précédemment sont de ce type. Mais nous verrons dans quelques chapitre qu'il existe des processeurs dits superscalaires, qui sont capables d'émettre plusieurs instructions par cycle. Dans ce cas, la fenêtre d'instruction a un seul port de lecture. Un processeur superscalaire, quant à lui, doit avoir un port de lecture par unité de calcul, ce qui fait beaucoup plus. ===Les entrées d'une fenêtre d’instruction=== Les fenêtres d'instruction sont composées d''''entrées''', des mots mémoire qui stockent une instruction. Une instruction réserve une entrée après son décodage et la libère dès qu'elle est envoyée aux unités de calcul. Une entrée contient l'opcode (les signaux de commande à envoyer à l'ALU), le registre de destination du résultat, les registres de chaque opérande, et éventuellement des signaux de commande en plus. De plus, chaque opérande est couplée à un bit de disponibilité, qui indique si elle est disponible. Quand un opérande est écrit dans les registres, le bit de présence correspondant est mis à jour. Enfin, chaque entrée possède un bit ''empty'' qui indique si elle est vide, cette information étant utile pour réserver des entrées. [[File:Entrée d'une station de réservation - sans les tags.png|centre|vignette|upright=3|Entrée d'une fenêtre d'instruction]] Nous verrons dans quelques chapitres que certaines fenêtres d'instruction sont capables de mémoriser les opérandes des instructions. De telles fenêtres d'instruction seront appelées, dans ce cours, des '''stations de réservation'''. Les entrées des stations de réservation sont assez semblables à celle des fenêtres d'instruction, à un détail près : les opérandes de l'instruction sont enregistrées directement dans des champs séparés. Il y a deux champs, un par opérande, pour stocker l'opérande elle-même, lue depuis les registres ou obtenue via le réseau de contournement. Notons que les champs pour les opérandes viennent en plus des champs pour les noms de registres, encore que les deux peuvent être fusionnés si on veut optimiser le tout. [[File:Entrée d'une station de réservation.png|centre|vignette|upright=3|Entrée d'une station de réservation.]] Précisons que la terminologie n'est pas très fiable. Les termes "fenêtre d'instruction" et "station de réservation" ne regroupent pas du tout la même chose d'un papier de recherche à l'autre, d'un bouquin à l'autre, d'un chercheur à l'autre, d'un ingénieur à l'autre, d'un professeur à l'autre. Le terme initial vient pourtant de l'article original sur l'algorithme de Tomasulo, où il désignait une fenêtre d'instruction associée à une unité de calcul précise. Mais le terme a ensuite été réutilisé, ce qui fait que certains processeurs avec plusieurs unités de calcul sont décrit comme ayant une unique station de réservation. En bref : c'est le bazar ! Mais nous en reparlerons dans le chapitre sur le renommage de registres, car c'est la place idéale pour les aborder. Toujours est-il que j'ai fait le choix de confondre les concepts de fenêtre d'instruction et de station de réservation avec les concepts de '''lecture avant émission''' et de '''lecture après émission'''. La différence entre les deux est que les registres sont lus après émission avec une fenêtre d'instruction, avant avec des stations de réservation. Dans le cas "avant émission", les opérandes sont mémorisées dans la station de réservation. Et cette différence a une influence sur le pipeline du processeur, le banc de registres et tout ce qui s'en suit. Un désavantage de la lecture avant émission est qu'il faut stocker les opérandes après lecture, ici dans les stations de réservation. Mais un avantage est que le banc de registre a besoin de moins de ports de lecture, car une bonne partie des opérandes sont fournies par le système de contournement. Nous verrons cela dans le détail dans le chapitre sur les processeurs superscalaires. Il a été proposé de fusionner le tampon de ré-ordonnancement avec la fenêtre d'instruction dans une structure unique. La méthode a notamment été utilisée sur les processeurs d'architecture K6 d'AMD. Le tout donnait une structure appelée le '''DRIS''' (''deferred scheduling register renaming instruction shelf''). La différence avec une fenêtre d’instruction normale est que les entrées sont libérée non pas quand l'instruction est exécutée/émise, mais quand elle termine son exécution et quitte le ROB. La fenêtre d'instruction doit alors incorporer des bits pour savoir si telle entrée a émis sont instruction ou non. ===La logique d'éveil et de sélection=== Dans le cas qui va suivre, on suppose que le processeur ne peut émettre qu'une instruction à la fois. Chaque cycle, une instruction est sélectionnée et est envoyée dans le chemin de données, soit à une ALU, soit à une unité d'accès mémoire. La sélection d'une instruction est effectuée par l'unité d'émission, qui est aussi appelée le '''''scheduler'''''. Elle gère la disponibilité des opérandes et la disponibilité des unités de calcul adéquate. Le choix de l'instruction émise doit être le plus pertinent possible, pour des raisons de performances. Pour le premier point, l'unité d'émission détermine quelles instructions sont candidates pour l'émission. Les ''instructions candidates'' sont celles dont tous les opérandes sont prêts. Le processeur contient un circuit qui détecte les instructions candidates : la '''logique d’éveil''' (''wake-up logic''). Une fois que la logique d'éveil a fait son travail, une instruction est choisie pour s’exécuter en fonction de la disponibilité des unités de calcul adéquates. Ce rôle est dévolu à un circuit qu'on appelle la '''logique de sélection''', ou ''select logic''. [[File:Fonctionnement complet de la logique d’émission.jpg|centre|vignette|upright=1.5|Fonctionnement complet de la logique d’émission.]] La logique de sélection doit gérer le fait que les unités de calcul du processeur ne sont pas toutes identiques. Déjà, un processeur a généralement des unités séparées pour les instructions entières et flottantes, des unités spécialisées dans les accès mémoire, parfois des unités spécialisées pour les branchements. Une instruction doit être attribuée à la bonne unité de calcul, on ne doit pas envoyer une instruction entière dans une unité de calcul flottante. De plus, parmi les unités de calcul entières, toutes ne sont pas identiques. Par exemple, il est fréquent d'avoir plusieurs unités de calcul spécialisées dans les opérations simples (additions, soustractions, opérations logiques) avec une unité pour les multiplications/divisions séparées, parfois une unité spécialisée pour les décalages/rotations, etc. Là encore, allouer la bonne instruction à la bonne ALU est complexe. Plus les unités de calcul sont hétérogènes, plus la logique de sélection est compliquée. Les logiques d'éveil comme de sélection sont assez complexes. Comme on le verra plus bas, la logique de sélection la plus simple, qui gère une seule unité de calcul, est basée sur un encodeur à priorité couplé à d'autres circuits. Et pour gérer plusieurs ALUs, il faut mettre des encodeurs en cascade. Le résultat est que même en prenant une logique de sélection simple, elle sera assez lente et gourmande en circuits. Aussi, la logique de sélection met souvent un cycle d'horloge entier pour faire son travail, elle a son propre étage de pipeline attribué. La logique d'éveil est dans le même cas, ce qui fait qu'émettre une micro-opération demande deux cycles d'horloge. Le défaut est que cela rajoute des cycles d'horloges entre la fenêtre d'instruction et l'ALU, ce qui complique la gestion du pipeline. Ces cycles de retard sont à prendre en compte au moment d'émettre les instructions, les ''scheduler'' doit en tenir compte pour des performances optimales. Sans tenir compte de ces cycles de retard, les instructions arrivent en retard de quelques cycles à l'ALU, cycles de retard durant lesquels l'ALU n'a pas fait de calcul et a été sous-utilisée, sans compter que le système de contournement n'est pas utilisé au mieux. Et le problème est encore plus important sur les processeur avec des stations de réservation, qui utilisent la "lecture après émission" : cela rajoute un cycle d'horloge en plus, un temps de retard en plus. ===La logique d'éveil : l'émission anticipée=== La logique d'éveil doit tenir compte du fait qu'il y a plusieurs étages entre l'émission et l'exécution sur une unité de calcul. Par exemple, un processeur a souvent entre un et à cinq étages entre la file d'attente et les unités de calcul. Il faut lire les registres, gérer le contournement, et cela peut prendre quelques cycles d'horloge. Sur le Pentium 4, on trouve 6 étages entre la fenêtre d’instruction et l'entrée de l'ALU. Si les micro-opérations sont émises quand les opérandes sont disponibles, il y aura un délai de quelques cycles avant qu'elles atteignent l'ALU. Alors qu'idéalement, on souhaiterait que la micro-opération atteigne l'ALU dès que ses opérandes sont disponibles, pour profiter des techniques de contournement. Pour cela, la logique d'éveil émet les instructions quelques cycles en avance pour qu'elles arrivent au bon moment. Il s'agit d'une technique d''''émission anticipée''', dont nous avions parlé dans le chapitre sur le contournement. : Il faut noter que le problème se pose plus avec des fenêtres d'instruction qu'avec des stations de réservation. Les premières ont un étage en plus entre émission et ALU, vu qu'il faut lire des registres après l'émission. L'émission anticipée demande d'émettre un signal d'éveil en avance de quelques cycles, pile au bon moment. Par exemples, si on a deux étages entre l'ALU et l'unité d'émission, le signal de réveil sera généré deux cycles avant que le résultat soit effectivement calculé. L'implémentation varie, mais deux solutions sont possibles. La première est de générer le signal d'éveil dans l'ALU, ce qui n'a de sens que pour les opérations comme les multiplications ou les divisions, qui prennent plusieurs cycles. Une autre technique génère le signal de réveil dans une structure centralisée, spécialisée dans la génération des signaux d'éveil. L'unité de composée d'un registre à décalage par registre. Imaginons qu'une instruction est émise, que cette instruction mette N cycles à s'exécuter, et qu'elle écrive dans un registre de destination. L'unité sélectionne alors le registre à décalage associé au registre de destination, et met le bit numéro N à 1. Le registre décalé d'un cran à chaque cycle. Quand le bit sortant est un 1, alors le signal de validité pour l'opérande est généré. L'émission anticipée marche bien si l'instruction a une durée fixe, connue à l'avance. Et autant c'est le cas pour les instructions arithmétiques et logiques, autant ce n'est pas le cas pour les accès mémoire. Les accès mémoire ont une latence variable : quelques cycles pour un succès de cache, plusieurs dizaines de cycles pour un défaut de cache L1, pas loin de la centaine pour un défaut de cache L2, etc. Et cela pose des problèmes pour l'émission anticipée. L'émission en avance pour les accès mémoire est purement spéculative : le processeur émet des instructions en supposant que la lecture entrainera un succès de cache, quitte à annuler l'instruction en cas de défaut de cache. Mais faire ainsi demande non seulement d'annuler les instructions émises en avance, mais aussi de ne pas retirer les instructions émises en avance de la fenêtre d'instruction. Elles sont émises, mais une copie de sauvegarde est conservée dans la fenêtre d'instruction. Si le processeur détecte un défaut de cache, il peut alors ré-exécuter l'instruction. S'il détecte un succès de cache, les instructions lecture-dépendante sont retirées de la fenêtre d'instruction, la copie de sauvegarde est devenue inutile et est donc jetée. ===La logique de sélection : âge ou position ?=== La logique de sélection est primordiale pour de bonnes performances. Il existe deux méthodes principales pour sélectionner l'instruction à exécuter. La première est la plus simple : elle se base sur lé numéro de l'entrée. En effet, une fenêtre d'instruction est avant tout une sorte de mémoire, un mix entre mémoire associative, mémoire RAM, et FIFO. Et chaque entrée a un numéro, une adresse mémoire. Nous parlerons de numéro dans ce qui suit, car ce sera plus simple, le terme d'adresse mémoire étant peut-être un peu exagéré dans le contexte des fenêtres d'instruction. Toujours est-il que la fenêtre d'instruction est adressable dans le sens où on peut lui envoyer le numéro de l'entrée voulue, et la fenêtre d’instruction renvoie le contenu de l'entrée sur son port de lecture. Et c'est ce que fait la logique de sélection : elle génère le numéro de l'entrée à lire. Le numéro est alors envoyé sur l'entrée d'adresse de la fenêtre d’instruction, et elle fournit la micro-opération associée sur son port de lecture, son '''port d'émission'''. La première méthode de sélection, donc. Elle est basée sur sur le numéro de l'entrée. Si plusieurs entrées sont éveillées, la logique de sélection prend celle avec le plus petit numéro. Elle porte le nom de '''sélection par position''', sous-entendu position dans la fenêtre d'instruction. Vous l'avez peut-être deviné, mais la logique de sélection est alors un encodeur à priorité. Le circuit de sélection ne se résume donc pas seulement à un encodeur à priorité, mais c'est le circuit central. L'avantage d'une telle méthode de sélection est qu'elle est simple à implémenter : un encodeur à priorité est un circuit connu, facile à implémenter. Mais on remarque un défaut : un encodeur est un circuit assez rapide, mais qui utilise beaucoup de transistors, beaucoup de portes logiques, surtout si on veut qu'il soit rapide. Ce qui explique que la logique de sélection ait son propre étage de pipeline rien que pour elle. La seconde méthode s'appelle la '''sélection par âge''', au nom assez transparent. L'idée est de privilégier l'émission de l'instruction la plus ancienne. Elle demande que la fenêtre d'instruction trie les micro-opérations par ordre d'insertion dans la fenêtre d'instruction, ce qui en fait une pseudo-FIFO. Le tri est partiel, car les instructions peuvent sortir de la fenêtre d’instruction à tout moment. Compacter la fenêtre d'instruction, à savoir regrouper toutes les entrées valides est une idée, mais elle est compliquée à implémenter. Aussi, elles préfèrent encoder des informations sur l'ordre d'émission dans chaque entrée. L'encodeur à priorité doit alors travailler non pas sur des nombres entiers liés à l'ordre d'insertion dans la pseudo-FIFO. Elle est encore plus gourmande en circuits que la méthode précédente. Les processeurs haute performance utilisent souvent des méthodes hybrides. Par exemple, les processeurs AMD de microarchitecture Bulldozer utilisaient une méthode intermédiaire. Ils utilisaient une fenêtre d'instruction couplée à un encodeur à priorité pour la sélection par position, mais complémentaient le tout avec une unité qui mémorisait l'instruction la plus ancienne dans la fenêtre d’instruction. Le mécanisme de sélection par âge était utilisé en priorité. Mais si l'instruction la plus ancienne n'était pas prête, le processeur basculait sur le mécanisme de sélection par position. ===La compaction des fenêtres d'instruction=== À chaque cycle, les instructions décodées sont ajoutées dans la fenêtre d'instruction, dans des entrées vides. Vu que les instructions quittent celle-ci dans le désordre, ces vides sont dispersés dans la fenêtre d'instruction, ce qui pose problème pour déterminer où placer les nouvelles instructions. La solution la plus triviale consiste à conserver une liste des vides, mise à jour à chaque insertion ou émission d'instruction. Une autre solution consiste à éliminer les vides en compactant la fenêtre d'instruction à chaque cycle d'horloge. Des circuits se chargent de détecter les vides et de regrouper les instructions en un unique bloc. Il faut signaler que certaines processeurs arrivent à se passer de cette étape de compactage, mais au prix de fenêtres d'instruction nettement plus complexes. Autre problème : quand il faut choisir quelle instruction émettre, il y a toujours plusieurs candidats. Si on choisit mal, des instructions restent en attente trop longtemps parce que d'autres instructions plus jeunes leur passent devant. Pour éviter cela, les instructions les plus vielles, les plus anciennes, sont prioritaires. Pour cela, on peut utiliser une FIFO un peu spéciale pour la fenêtre d'instruction. Si les ajouts d'instruction se font dans l'ordre, les instructions ne quittent pas forcément la fenêtre d'instruction dans l'ordre imposé par une FIFO : les instructions restent triées dans leur ordre d'ajout, même s'il y a des vides entre elles. Dans ces condition, il est préférable que le compactage conserve l'ordre FIFO des instructions. Dans ces conditions, l'instruction la plus ancienne est celle qui est située à l'adresse la plus faible : le circuit de sélection peut donc être fabriqué avec des encodeurs, et est relativement simple. ==Les fenêtres d'instruction basées sur une matrice de dépendances== L'implémentation la plus simple étend le fonctionnement d'un pipeline dynamique usuel. Rappelez-vous le chapitre sur les pipeline dynamiques. Nous avions vu que de tels pipelines émettaient une instruction par cycle, quitte à émettre des bulles de pipeline en cas de dépendance bloquante. Et il est possible d'améliorer leur unité d'émission pour qu'elle soit compatible avec l'exécution dans le désordre. ===Rappels sur le registre de réservation/disponibilité=== L'émission d'une instruction est gouvernée par un ''registre de réservation'' qui indique quels registres sont réservés par une instruction, et ceux qui sont libres. Un registre réservé est un registre qui sera écrit par une instruction en cours d'exécution, mais qui n'a pas encore écrit son résultat. Les instructions candidates doivent avoir leurs opérandes dans des registres libres. Sinon, c'est signe que leurs opérandes sont réservées en écriture, donc pas encore écrites, donc pas disponibles. Si une instruction candidate veut lire ce registre, c'est signe qu'il y a une dépendance RAW : elle veut lire un registre réservé, qui est destiné à être écrit par une instruction en vol. Si elle veut écrire, c'est signe qu'elle veut écrire dans un registre où une autre instruction veut écrire : c'est une dépendance WAW. Dans les deux cas, l'instruction n'est pas émise. Le registre de réservation encode les registres réservés comme suit : chaque bit est associé à un registre. Le bit numéro 0 est associé au registre numéro 0, le bit numéro 1 au registre numéro 1, etc. Là, En clair, les numéros de registres réservés sont encodés en représentation non pas binaire, mais en représentation ''one-hot'' (vue au premier chapitre). {|class="wikitable" |+ Registre de réservation |- ! Registre 7 !! Registre 6 !! Registre 5 !! Registre 4 !! Registre 3 !! Registre 2 !! Registre 1 !! Registre 0 |- | 0 || 0 || 1 || 0 || 0 || 1 || 0 || 0 |} Avant d'émettre une instruction, l'unité d'émission extrait les registres opérande/destination et les convertis dans la même représentation que le registre de réservation, à savoir en représentation ''one-hot''. Le circuit de traduction binaire vers ''one-hot'' est, pour rappel, un simple décodeur. Puis, on fait un OU logique entre les sorties des décodeurs. Le résultat est un masque qui indique quels registres sont lus par l'instruction, encodé en représentation ''one-hot''. Appelons-le le '''masque d'opérandes'''. Le masque est alors comparé au registre de réservation pour vérifier si l'instruction peut être émise. [[File:Unité d'émission simple, dans l'ordre.png|centre|vignette|upright=2|Unité d'émission simple, dans l'ordre]] Si l'émission est autorisée, le registres de réservation est là aussi mis à jour. Le registre de réservation est aussi mis à jour dès qu'une instruction enregistre son résultat dans les registres, ou alors dès qu'il est disponible pour le contournement. Le bit associé au registre repasse alors à 0 (ou à 1). Sans contournement, la mise à jour se fait alors à la toute fin de l'instruction, quand elle se termine, lors de la dernière étape d'enregistrement, à la fin de son pipeline. Avec, elle se fait quand l'instruction quitte l'unité de calcul. ===L'extension à l'exécution dans le désordre : l'éveil par matrice de bits=== La différence entre un pipeline dynamique et l'exécution dans le désordre est que l'on passe d'une instruction à émettre à plusieurs. Plusieurs instructions sont mises en attente dans une fenêtre d’instruction, et y attendent leur tour. L'idée est alors d'envoyer le registre de disponibilité à toutes les entrées, à toutes les instructions en attente. Ainsi, on sait quelles sont les instructions qui peuvent s'exécuter et celles qui ne le peuvent pas. L'implémentation est assez simple, elle ressemble beaucoup à l'implémentation d'un pipeline dynamique simple, si ce n'est que des circuits sont dupliqués. L'implémentation utilise des fenêtres d'instruction légèrement différentes de celles introduites plus haut. Elles n'utilisent notamment pas de bits de disponibilité, mais autre chose. Lorsqu'une instruction est ajoutée à la fenêtre d'instruction, le masque de disponibilité des opérandes est stocké dans la fenêtre d'instruction. A chaque cycle, le registre de disponibilité est envoyée à toutes les entrées, et est comparé avec tous les masques de disponibilité des opérandes. Si une comparaison renvoie un 1, alors l'instruction de l'entrée est une instruction candidate à l'émission. [[File:Unité d'émission dans le désordre basée sur un registre de disponibilité.png|centre|vignette|upright=2.5|Unité d'émission dans le désordre basée sur un registre de disponibilité]] L'ensemble est implémenté avec l'aide d'une '''matrice de bits''', où chaque ligne correspond à une entrée et chaque colonne à un registre. À chaque croisement entre une ligne et une colonne, on trouve un bit. Si le bit de la ligne n et de la colonne m est à 1, cela veut dire : l'instruction dans l'entrée n a besoin de lire le registre m. S’il est à 0, alors cela veut dire que l'instruction stockée dans la ligne n n'a pas besoin de la donnée dans le registre m. [[File:Planificateur à matrice de bits.jpg|centre|vignette|upright=2|Planificateur à matrice de bits.]] Lorsqu'une instruction réserve une entrée, elle initialise la ligne en fonction des registres qu'elle souhaite lire. Pour vérifier si une instruction a ses opérandes prêts, le processeur compare le registre de disponibilité à la ligne associée à l'instruction/entrée. A chaque intersection ligne-colonne, se trouve un comparateur de 1 bit, qui détecte si le registre est demandé et disponible. Les résultats de cette porte sont ensuite envoyés à une porte ET, qui fait le gros du travail. [[File:Logique de détection de la disponibilité d'une instruction.jpg|centre|vignette|upright=2|Logique de détection de la disponibilité d'une instruction.]] ==Les fenêtres d'instruction basées sur une mémoire associative== Les processeurs modernes utilisent une mémoire associative pour la fenêtre d'instruction. Les mémoires associatives ont été abordées il y a quelques chapitres, mais faisons quelques rappels. Les mémoires associatives servent à accélérer la recherche de données dans un ensemble. Or, une fenêtre d'instruction vérifie régulièrement si chaque entrée est prête. Il s'agit d'un processus de recherche d'une instruction qui respecte une condition bien précise dans la mémoire, ce qui fait que les mémoires associatives sont donc tout indiquées. Comme vous le savez, les signaux de commande d'une instruction sont propagés avec celle-ci dans le pipeline, le nom du registre de destination ne faisant pas exception. Le nom de registre est envoyé à la fenêtre d'instruction lors de l'écriture du résultat dans les registres. S'il y a correspondance, l'opérande est disponible et son bit de disponibilité est mis à 1. On peut adapter cette méthode pour tenir compte du contournement assez simplement. [[File:Détection des dépendances par propagation du registre de destination.png|centre|vignette|upright=2|Détection des dépendances par propagation du registre de destination.]] En conséquence, le circuit de détection des dépendances est constitué d'un grand nombre de comparateurs : un par champ « nom de registre » dans chaque entrée. La logique d'éveil/''wake up'' regroupe tous les comparateurs, la logique de sélection est un circuit situé en-dehors de la mémoire associative. Les entrées sont dans la mémoire associative elle-même. [[File:Gestion des bits de validité.png|centre|vignette|upright=2|Gestion des bits de validité.]] L'implémentation la plus simple est celle du schéma précédent, où on utilise une mémoire associative unique. Une version plus élaborée sépare la fenêtre d'instruction en deux parties : une mémoire qui mémorise les registres des opérandes, une autre mémoire pour le reste. La mémoire pour les registres opérandes est la mémoire associative proprement dite, c'est elle qui est associées aux comparateurs, à la logique de ''wake-up''/réveil, etc. Par contre, l'autre mémoire est une mémoire RAM simplifiée, qui mémorise les informations qui n'ont pas besoin des comparateurs. L'opcode de l'instruction est là-dedans, par exemple. ===Les optimisations de la consommation d'énergie : la désactivation des portions inutilisées=== Le problème avec des fenêtres d'instruction de ce type est leur forte consommation énergétique, ainsi que le grand nombre de portes logiques utilisées, qui deviennent prohibitif pour des fenêtres d'instruction un peu grosses. Pour résoudre ce problème, certains ont optimisé les comparateurs. D'autres ont tenté de profiter du fait que la majorité des bits dans les entrées sont composés de zéros. Bref, les optimisations purement matérielles sont légion. Une première solution est de désactiver les entrées qui sont inutilisées, vides, sans instruction. Pour cela, on fait précéder les comparateurs par un circuit qui les connecte ou déconnecte des lignes de bit. Le circuit est commandé par le bit ''empty'' qui indique si une entrée est vide ou non. L'avantage est que la consommation d'énergie de la fenêtre d'instruction devient alors proportionnelle au nombre d'entrées non-vides, et non au nombre d'entrées total. Du moins, en apparence, les entrées non-utilisées doivent quand même être alimentées pour fonctionner, mais l'activité de comparaison disparait dans les entrées vides. Il est possible d'étendre cette technique aux entrées dont les opérandes sont prêtes. Les gains sont généralement assez bons, avec une réduction de consommation variant entre 30 et 50%, avec une implémentation très simple et très économe en circuits. Une autre solution, assez simple à mettre en place, consiste à désactiver une partie de la fenêtre d'instruction sin elle est inutilisée. Pour cela, il faut segmenter la fenêtre d'instruction avec la technique du ''wire partitionning''. Pour rappel, une fenêtre d'instruction est une mémoire associative. Et comme toute mémoire associative, elle contient des fils, les lignes de bit, qui relient les entrées/sorties à toutes les cellules mémoire. Plus une ligne de bit est longue, plus elle consomme d'énergie et plus le temps de lecture/écriture est long. L'idée est de segmenter les lignes de bits en plaçant des répéteurs qui recopient la tension d'un segment au suivant. Les répéteurs sont des tampons trois-états, ce qui permet de déconnecter les portions inutilisées de la ligne de bit. Ce faisant, la fenêtre d'instruction est découpée en segments, qui peuvent être désactivés si besoin. Si il y a peu d'instructions chargées dans la fenêtre d'instruction, les portions inutilisées sont désactivées. La technique marche d'autan mieux si les instructions sont compactées au début de la fenêtre d'instruction. [[File:Wire partitionning.png|centre|vignette|upright=2|Wire partitionning]] Tout le problème est de savoir quelles portions désactiver. La technique est assez simple si la fenêtre d'instruction est compactée, à savoir si toutes les instructions sont régulièrement regroupées au début de la mémoire CAM. Mais même avec cette optimisation, la décision de désactiver une portion de la fenêtre d'instruction n'est pas à prendre à la légère. Il ne faut pas désactiver une portion contenant des instructions pouvant être émise sous peu. La décision dépend de paramètres variés : proportion d'entrée vides, quantité d'entrées récemment activées/désactivées récemment, présences d'entrées avec un ''match'' d'opérandes récent, etc. Il est important de préciser que les techniques en question fonctionnent aussi sur les autres types de fenêtre d'instruction, qui ne sont pas basées sur des mémoires associatives. Nous allons voir celles-ci dans la suite du chapitre, mais gardez à l'esprit que ces optimisations, à savoir désactiver les entrées vides/prêts et partitionner la fenêtre d'instruction, sont des optimisations générales qui marchent avec presque tout. ===L'ajout d'une FIFO pour les instructions déjà prêtes à l'émission=== D'autres techniques permettent de réduire aussi bien le cout en circuits que la consommation d'énergie de la fenêtre d'instruction. L'idée est d'utiliser une mémoire associative quand elle est réellement nécessaire, mais d'utiliser une fenêtre d'instruction "normale" dès que possible. La méthode la plus simple tient compte du fait que certaines instructions ont déjà toutes leurs opérandes de disponibles à l'émission, mais doivent quand même être mises en attente, parce que l'ALU adéquate est occupée, parce que des dépendances WAW/WAR sont encore là, ou pour tout autre raison. Dans ce cas, elles sont mises en attente non pas dans la fenêtre d'instruction, mais dans une mémoire FIFO toute simple. L'idée est qu'au lieu d'avoir une énorme mémoire associative pour la fenêtre d'instruction, on déplace quelques entrées dans une petite FIFO annexe. Le résultat est un gain en terme d'énergie et de circuits, au prix d'une perte de performance mineure. La perte de performance en question se manifeste si aucune instruction n'a ses opérandes de prêtes à l'émission : le programme n'utilise pas la FIFO et voit alors une fenêtre d'instruction plus petite. Une amélioration de cette technique tient compte du fait que certaines instructions sont dans un cas intermédiaire. Elles ont déjà une opérande de prête lors de l'émission, mais pas l'autre. Le nombre d'opérandes varie suivant l’instruction : certaines n'ont besoin que d'un seul opérande. De plus, il arrive qu'une opération tout juste décodée ait déjà un ou plusieurs de ses opérandes de prêts. Cette constatation permet d'éviter d'utiliser des comparateurs pour les opérandes déjà prêts. Par exemple, on peut parfaitement utiliser trois fenêtres d'instruction : * une pour les instructions dont tous les opérandes sont prêts, mais qui sont quand même mises en attente, sans comparateur ; * une pour les instructions dont un seul opérande manque, qui n'utilise qu'un comparateur par entrée ; * une pour les instructions dont deux opérandes manquent à l'appel, qui utilise deux comparateurs par entrée. C'est beaucoup plus économique que d'utiliser une seule grosse fenêtre d'instruction qui contiendrait autant d'entrées que les trois précédentes réunies, avec deux comparateurs par entrée. Certains sont même allés plus loin, et ont proposé de supprimer la fenêtre d'instruction avec deux opérandes par entrée. Les instructions dont deux opérandes sont inconnus au décodage sont stockées dans la fenêtre d'instruction pour instructions avec un comparateur par entrée. Un circuit de prédiction se charge alors de prédire l'opérande manquant, cette prédiction étant vérifiée plus loin dans le pipeline. Il serait cependant étonnant qu'une telle proposition ait donné lieu à la moindre implémentation réelle. ===Les optimisations de la consommation d'énergie avancées=== D'autres chercheurs ont conservé une fenêtre d'instruction unique, avec autant de comparateurs par entrée qu'il y a d'opérandes possibles par instruction. Simplement, le processus de détection des opérandes prêts est légèrement ralenti : on ne vérifie qu'un opérande par cycle. Pour vérifier les deux opérandes d'une entrée, on doit attendre deux cycles. Enfin, certains chercheurs ont proposé des fenêtres d'instruction segmentées. Les instructions circulent à chaque cycle d'un segment vers le suivant : en conséquence, certains segments conservent les instructions les plus anciennes, un autre les instructions les plus jeunes, etc. Seul le denier segment, celui qui contient les instructions les plus vielles, peut émettre une instruction : la détection des opérandes se fait seulement dans le dernier segment, qui contient les instructions les plus anciennes. On économise ainsi beaucoup de comparateurs. Certains chercheurs ont tenté de pipeliner l'étape de sélection des opérandes, ainsi que l'étage d'arbitrage. Mais en faisant cela, il faut plusieurs cycles pour détecter qu'une instruction a ses opérandes prêts, ce qui pose problème face à de nombreuses dépendances RAW. Pour éviter de trop perdre en performances, certains chercheurs ont décidé d'utiliser des techniques pour prédire quelles seront les instructions dont les opérandes seront bientôt prêts. Si détecter qu'une instruction est prête prend n cycles, le processeur devra tenter de prédire la future disponibilité des opérandes n cycles en avance pour obtenir des performances optimales. ===Remplacer la mémoire associative par une RAM=== Une autre optimisation possible est de remplacer la fenêtre d'instruction par une mémoire RAM, dont chaque mot mémoire correspondrait à une entrée. Une telle optimisation permet en théorie de se passer des comparateurs associés à chaque entrée, mais au prix de l'ajout de circuits annexes potentiellement couteux. La première de ces techniques, la '''recherche directe par étiquette''' (direct tag search) fut créée par Weiss et son collègue Smith. Ils cherchaient à améliorer l'algorithme de Tomasulo, un algorithme qu'on expliquera dans quelques chapitres. Rappelons que chaque instruction produit un résultat, qui devra être rapatrié dans une ou plusieurs entrées de la fenêtre d'instruction. L'optimisation de la recherche directe par étiquette fonctionne dans le cas où le résultat de l'instruction n'est utilisé que par une seule entrée, et pas plusieurs. Le principe est simple : chaque champ « opérande » d'une entrée est adressable via le nom de registre de cette opérande. Pour faire le lien entre entrée et nom de registre, la recherche directe par étiquette ajoute une table de correspondances matérielle, une mémoire RAM qui mémorise les adresses des champs « opérande » des entrées. Les adresses envoyées dans cette mémoire sont les noms de registres des résultats. Lors de l'émission, la table de correspondances est mise à jour. Les numéros des champs « opérande » réservés lors de l'émission sont mémorisés dans les mots mémoire qui correspondent aux deux registres sources. Toutefois, une petite vérification est faite lors de l'émission : si il y a déjà une correspondance dans la table pour un registre source, alors une autre instruction compte lire ce registre. Pour éviter d'écraser les données de l'instruction précédente dans la table de correspondances, l'émission de l'instruction est bloquée. [[File:Recherche directe par étiquette.png|centre|vignette|upright=2|Recherche directe par étiquette.]] ==Les fenêtres d’instruction avec préplanification== Avec la '''préplanification''' (''prescheduling''), la fenêtre d’instruction est composée de mémoires FIFO dans lesquelles les instructions sont triées dans l'ordre d'émission. Il n'y a pas de logique d’émission proprement dite, celle-ci se bornant à vérifier si l'instruction située au début de la FIFO peut s’exécuter. Par contre, le préplanificateur détecte les dépendances et en déduit où insérer les instructions dans le tampon d'émission, à l'endroit le plus adéquat. [[File:Préplanification.jpg|centre|vignette|upright=2|Préplanification.]] ===L'usage de FIFO multiples=== La technique de préplanification la plus simple utilise plusieurs FIFO. Quand une instruction a une dépendance avec une autre instruction, les deux sont placées dans la même FIFO. Pour cela, le préplanificateur détecte les chaines d'instructions dépendantes, et place les instructions dans la FIFO adéquate. A chaque cycle, l'unité d'émission lit une micro-opération dans chaque FIFO et vérifie si elle peut l'émettre. Si la micro-opération n'a pas ses opérandes disponibles, ou qu'une dépendance structurelle survient, alors la FIFO est bloquée. La micro-opération attend que la dépendance soit résolue, bloquant toutes les instructions précédentes. Mais les autres FIFO ne sont pas bloquées, laissant de la marge de manœuvre. [[File:Préplanification par FIFO multiples.png|centre|vignette|upright=1.5|Préplanification par FIFO multiples.]] ===La technique du tampon trié=== La technique du '''tampon trié''' trie les instructions selon le temps d'attente avant leur exécution. Les instructions qui sont censées s’exécuter bientôt sont insérées au tout début de la FIFO, tandis que les instructions qui s’exécuteront dans un long moment sont insérées vers la fin. Là encore, l'unité d'émission lit une micro-opération dans la FIFO, et détermine si elle peut être émise. Si une dépendance survient, l'émission est retardée, et la FIFO est bloquée. [[File:Préplanification par tampon trié.png|centre|vignette|upright=1.5|Préplanification par tampon trié.]] La technique a cependant quelques problèmes assez importants. Le premier problème est que la FIFO est bloquée lorsqu'une micro-opération ne peut être émise. Le second problème est que le temps avant exécution n'est pas toujours connu, notamment pour les instructions d'accès mémoire. Et cela se répercute sur les instructions dépendantes de celles-ci. Pour résoudre ce genre de problèmes, l'usage d'un pipeline à ''replay'' est possible, et est même l'une des meilleures solution possible, malgré ses défauts. L'idée est que les lecture sont pré-planifiées en supposant qu'elles font un succès de cache L1. Si la prédiction est fausse, la lecture est ré-exécutée plusieurs cycles plus tard, en supposant qu'elle fait un succès dans le cache L2, et ainsi de suite. Elle est alors ré-insérée dans la FIFO, elle est pré-planifiée une seconde fois. Il en est de même si une micro-opération ne peut pas être émise : il suffit de la réinsérer dans la FIFO au bon endroit, en attendant que ses dépendances soient résolus. Ainsi, l'instruction fautive ne bloque pas la fenêtre d’instruction, et retente sa chance autant de fois qu'il le faut. [[File:Préplanification par fenêtre d’instruction scorebarodée.png|centre|vignette|upright=1.5|Préplanification par fenêtre d’instruction scorebarodée.]] Une autre solution utilise deux fenêtres d’instruction : une FIFO gérée par la préplanification, et une vraie fenêtre d'instruction pour les instructions dont le temps d'attente ne peut pas être déterminé. Il est possible de mettre cette dernière avant la préplanification, afin de gérer les temps d'attente des instructions d'accès mémoire. Quand le temps d'attente d'une lecture devient connu, ses instructions dépendantes sont gérées avec préplanification. [[File:Préplanification avec fenêtre d’instruction.png|centre|vignette|upright=2.5|Préplanification avec fenêtre d’instruction.]] ===Les fenêtres d'instruction avec allocation temporelle statique=== L''''allocation temporelle statique''' correspond à une technique utilisée sur les processeurs Cuzco de l'entreprise Condor. La technique en question a été présenté en 2025, mais des idées similaires ont été présentées dans la littérature académique. Elle ressemble beaucoup aux techniques de pré-planification, avec cependant quelques différences. L'idée est simple : le processeur dispose de plusieurs fenêtres d'instruction, qui mettent en attente les micro-opérations. Lors de l'étape de renommage de registres, le processeur détermine dans combien de cycles d'horloge la micro-opération sera prête pour exécution. La micro-opération est alors mise en attente durant ce nombre de cycles, dans les fenêtres d'instruction, puis est émise une fois ce nombre de cycles écoulés. Ce faisant, les fenêtres d'instruction n'ont pas besoin de détecter la disponibilité des opérandes à chaque cycle, pour chaque micro-opération en attente. Le ''timing'' de l'émission des micro-opérations est décidé à l'avance. L'implémentation exacte n'est pas connue, mais plusieurs solutions sont imaginables. Par exemple, la fenêtre d'instruction peut simplement être composée de plusieurs mémoires de petite taille, chacune contenant les micro-opérations destinées à être exécutées dans N cycles, N étant différent pour chaque mémoire. Une autre solution, plus réaliste, utilise une fenêtre d'instruction dans laquelle la micro-opération est couplée à des champs pour les opérandes, et un champ compteur. Le champ compteur est initialisé avec le nombre de cycles à attendre, et est décrémenté à chaque cycle d'horloge. Quand il atteint zéro, la micro-opération est émise. Vous remarquerez que la méthode ne marche que si toutes les micro-opérations prennent un nombre fixe de cycles d'horloge. Et autant c'est le cas pour les micro-opérations arithmétiques ou logiques, autant les accès mémoire ne rentrent pas dans ce cadre. En théorie, on ne sait pas combien de temps prendra un accès mémoire. Et cette incertitude se répercute sur les instructions dépendantes d'un accès mémoire. Pour éviter cela, le processeur réutilise un pipeline à ''replay'' tel que vu dans le chapitre précédent. L'unité de renommage de registre suppose que tout accès mémoire fait un succès de cache L1, et décide des ''timings'' d'émission sous cette hypothèse. Si une lecture subit un défaut de cache, elle est ré-exécutée, de même que toutes les instructions dépendantes. Pour cela, le registre de destination de la lecture est marqué comme invalide, grâce à un bit spécifique attaché au registre. Toute instruction qui lit une opérande invalide est elle aussi ré-executée de zéro. Pour simplifier, l'unité d'émission ressemble à une unité d'émission dans l'ordre, avec un registre de disponibilité, qu'on aurait amélioré pour aller au-delà de la simple détection des dépendances d'instruction. Pour déterminer les ''timings'' d'émission, à savoir quand émettre une micro-opération, le processeur utilise une unité d'émission à deux étages. Le premier étage est appelé le ''register scoreboard'', le second étage est appelé la ''Time Ressource Matrix''. Les deux étages communiquent entre eux, comme on va le voir, et leurs noms donnent une idée de ce qu'ils font. Le premier étage gère les dépendances de registres, le second gère les dépendances structurelles. Le premier étage est un registre de disponibilité amélioré, qui gère les dépendances de registre. Cet étage sait quand tel registre sera écrit, et donc que l'opérande écrite dedans sera disponible à partir de tel cycle d'horloge. Il le sait car l'étage suivant l'aura prévenu, mais laissons cela de côté pour le moment. Quand une micro-opération rentre dans cet étage, il vérifie les dépendances avec les registres et les micro-opérations antérieures. Vu qu'il sait quand les registres seront disponibles, il peut déterminer quand l'instruction pourra s'exécuter. Par exemple, si une micro-opération lit les deux registres R7 et R15, qui sont disponibles respectivement dans 5 et 7 cycles, le premier étage sait que la micro-opération devra attendre 7 cycles. Mais tout cela ne suffit pas à déterminer quand émettre une micro-opération. En effet, il fait aussi gérer les dépendances structurelles, ce qui est le boulot du second étage. Le second étage utilise pour cela une ''Time Ressource Matrix'', qui mémorise l'occupation de diverses "ressources", pour les 256 cycles d'horloge à venir. Les ressources en question sont les ports de lecture/écriture du banc de registre, les ALUs utilisées, si la micro-opération utilise l'unité mémoire, etc. Le second étage prend en entrée une micro-opération, détermine quelles "ressources" elle utilise, puis regarde leur disponibilité. Elle détecte alors les dépendances structurelles et détermine alors quand peut s'exécuter la micro-opération. Elle peut retarder l'émission de quelques cycles, si une dépendance structurelle est détectée. Une fois sortie du second étage, on sait quand la micro-opération va être émise, à quel cycle précisément. Et vu que la durée de l'instruction est fixe, on sait quand cette micro-opération va se terminer, quand son résultat sera disponible. Cela permet de mettre à jour la ''Time Ressource Matrix'', pour préciser que le port d'écriture sera occupé à tel moment. De plus, cette information est transmise au premier étage, qui sait alors quand est enregistré le résultat dans le registre de destination. C'est comme cela que le premier étage sait quand un registre est disponible : le second étage le prévient, quand il émet une instruction ! La ''Time Ressource Matrix''mémorise l'occupation des "ressources" pour les 256 cycles d'horloge à venir. Cependant, elle ne vérifie pas les dépendances pour les 256 cycles suivants. Quand elle reçoit une micro-opération, elle teste les dépendances structurelles pour seulement les 8 prochains cycles maximum. Si la micro-opération ne peut pas être émise pendant ces 8 cycles, le pipeline est bloqué, un ''pipeline stall'' est émis. Pour être plus précis, vu que le processeur peut décoder 8 micro-opérations en même temps, cela permet de ne consulter que 64 cycles d'horloge sur les 256. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les premiers processeurs Intel | prevText=Les premiers processeurs Intel | next=Le renommage de registres | nextText=Le renommage de registres }} </noinclude> 1wwhyzpwuke1fba8zr9jocwb5oyxxkl 773598 773597 2026-09-29T19:14:23Z Mewtow 31375 /* Les fenêtres d'instruction décentralisées */ 773598 wikitext text/x-wiki Dans les chapitres précédents, nous avons parlé des techniques dites d''''émission dans l'ordre'''. L'idée est d’exécuter une nouvelle micro-opération à chaque cycle, dans des unités de calcul séparées. Les instructions sont émises consécutivement, mais les instructions s’exécutent en parallèle dans des unités de calcul séparées. Par contre, quand l'unité d'émission ne peut pas émettre une instruction, elle bloque tout le pipeline. Les instructions qui suivent sont elles aussi bloquées, elle doivent attendre leur tour, même si elles sont en capacité de s'exécuter. Les techniques d'exécution dans le désordre que nous allons voir dans ce chapitre corrigent ce point précis. Elles sont dites à '''émission dans le désordre'''. Elles se distinguent des précédentes sur un point précis : quand l'unité d'émission bloque l'émission d'une instruction, les instructions suivantes peuvent poursuivre. L'émission des instructions peut donc se faire dans le désordre, dans le sens où une instruction peut être émise alors qu'une instruction précédente ne l'est pas encore. L'avantage de l'émission dans le désordre est qu'une instruction s'exécute dès que ses opérandes sont disponibles. Par disponible, on veut dire présent soit dans le réseau de contournement, soit dans les registres. Le processeur détecte automatiquement quand les opérandes d'une instruction sont sont disponibles, et il l’exécute à ce moment là. Dès qu'une instruction a ses opérandes disponibles, elle est émise et exécutée. C'est là la seule contrainte : les dépendances WAR, WAW et autres sont gérées par un ROB ou toute autre technique d'exception précise, seules les dépendances RAW limitent l'exécution. Mais avant de poursuivre, quelques point niveaux terminologie : * L'émission dans le désordre est un terme parlant et assez précis. Malheureusement, la terminologie la plus utilisée par d''''exécution dans le désordre'''. Et nous utiliserons ce terme dans la suite du cours, histoire de ne pas trop dévier de la nomenclature habituelle. * Nous utiliserons parfois l'abréviation OOO pour parler d'exécution dans le désordre. L'abréviation est celle de ''Out Of Order Excution''. * Nous utiliserons aussi l'abréviation ''µop'' pour parler de micro-opération, ''µops'' au pluriels pour parler de plusieurs micro-opérations, ou des micro-opérations en général. L'exécution dans le désordre ne gére en effet que des µops, elle se situe après l'étape de décodage. Mais avant de poursuivre, précisons une chose importante : l'exécution dans le désordre traite les accès mémoire à part. La majorité des processeurs OOO assez anciens exécutent les accès mémoire dans l'ordre, seules les µops entières/flottantes/branchements sont exécutées dans le désordre. Les processeurs datant d'après les années 2010 sont capable d'exécuter les accès mémoire dans le désordre, mais l'implémentation en question est assez particulière. Un chapitre entier sera dédié à l'exécution dans le désordre des µops mémoire. Nous allons volontairement mettre de côté la gestion des accès mémoire dans ce chapitre. ==Les fenêtres d’instruction : généralités== [[File:File de micro-opération.png|vignette|upright=1|File de micro-opérations]] Pour décrire comment est implémentée l'émission dans le désordre, il faut commencer par parler des processeurs sans. Les processeurs sans exécution dans le désordre ont une unité d'émission qui bloque tout le pipeline dès qu'une µop ne peut pas être émise. Pour limiter l'impact de ce blocage, quelques rares processeurs incorporent une '''file de micro-opération''', une mémoire FIFO qui met en attente les µops. Vu que c'est une mémoire FIFO, les µops sont émises dans l'ordre, à savoir l'ordre d'ajout, dans l'ordre de décodage. Le schéma ci-dessous illustre une telle file d'attente couplée à un ''scoreboard''. Sur le principe, l'exécution dans le désordre améliore la file de µops sur un point : ce n'est plus une mémoire FIFO. Les µops sont insérées dans l'ordre, mais peuvent sortir dans le désordre (être émises dans le désordre). La file de µops devient alors une '''fenêtre d'instruction''', terme traduit directement de l'anglais ''instruction Window''. Terme assez trompeur, car elles mettent en attente des µops, pas des instructions. Elles peuvent émettre des µops dans le désordre, ce qui fait que si une µop bloque le pipeline, les µops suivantes peuvent être émises. Si je commence le paragraphe précédent par "sur le principe", c'est car certaines techniques d'OOO utilisent des files de µops normales. Il est par exemple possible d'utiliser une file de µops avec une fenêtre d'instruction, plusieurs files de µops, plusieurs fenêtres d'instructions avec une file de µops annexe, etc. Dasn les grandes lignes, il existe dans les grandes lignes 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! File de µops améliorée |- ! Une seule "file de µops" | ''Scoreboard'' | Fenêtre d'instruction centralisée |- ! Plusieurs "file de µops" | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | Fenêtre d'instruction décentralisée |} ===La fenêtre d'instruction centralisée=== L'implémentation la plus simple de l'OOO utilise une unique '''fenêtre d'instruction'''. Les instructions décodées sont accumulées dans la fenêtre d'instruction, où elles attendent que leurs opérandes soient disponibles. La fenêtre d'instruction sert donc de file d'attente. Mais elle contient aussi une unité d'émission, qui détecte quelles µops sont prêtes à être émises. L'unité d'émission et la fenêtre d'instruction sont fusionnées ensemble, elles forment un seul circuit. Mais nous allons dire qu'elles sont conceptuellement séparées pour le moment. A chaque cycle, l'unité d'émission consulte la fenêtre d'instruction pour voir quelles µops peuvent s'exécuter, lesquelles ont leur opérandes de disponibles. La fenêtre d'instruction doit spécialement être conçue pour, c'est une sorte de mémoire associative très complexe, comme on le verra dans ce qui suit. [[File:OOO Issue.png|centre|vignette|upright=2.5|Exécution dans le désordre avec une fenêtre d'instruction]] Une fois qu'une µop sort du décodeur d'instructions, elle est ajoutée en parallèle dans la fenêtre d'instruction et le ROB. La raison est que les µops quittent la fenêtre d'instruction dans le désordre, et qu'elles doivent être remises en ordre par la suite. Le ROB s'occupe de cette remise en ordre, mais il a besoin de savoir dans quel ordre les µops sont censées être, et cet ordre est celui du décodage. Aussi, pour remplir le ROB, la seule opportunité est en sortie de l'unité de décodage. Dans le cas où une instruction est décodée en plusieurs micro-opérations, elles sont toutes insérées en même temps dans la fenêtre d'instruction et le ROB, en tenant compte de leur ordre. [[File:Fenêtre d'instruction.png|centre|vignette|upright=2|Fenêtre d'instruction.]] Les micro-opérations mémoire sont à part des autres, pour diverses raisons. Une de ces raisons est que les dépendances de données sont classées en deux types : les dépendances de registre et les dépendances d'adresse. Et les deux sont fondamentalement différentes. Autant on peut détecter les dépendances de registre lors de l'émission, autant c'est plus compliqué avec les dépendances d'adresse. De plus, rappelons que si les lectures peuvent s'exécuter dans le désordre, les écritures doivent s'exécuter dans l'ordre, ou du moins en donner l'illusion. Pour cela, le processeur remet les écritures dans l'ordre avec une sorte de mini-ROB intégré à l'unité mémoire, appelée la file d'écriture. Elle complémente le ROB, qui lui ne gère que les écritures dans les registres, mais les deux collaborent. La file d'écriture envoie une écriture à la mémoire RAM quand le ROB lui dit que c'est bon, les instructions précédentes sont terminées ''dans l'ordre du programme''. Les processeurs modernes ajoutent des techniques d'exécution dans le désordre des accès mémoire, mais nous les verrons dans un chapitre dédié. Elles permettent d'utiliser une fenêtre d'instruction unique, qui mémorise aussi les µops mémoire. Si elles sont mises en place, l'unité mémoire n'a pas besoin de file de µops séparée. L'idée est que les dépendances de registre sont traitées par la fenêtre d'instruction, mais que l'unité mémoire gére les dépendances d'adresse. Les dépendances d'adresse sont gérées par des techniques de ''désambiguation mémoire'', qui auront droit à un chapitre dédié. [[File:Processeur avec exécution dans le désodre des accès mémoire.png|centre|vignette|upright=2|Processeur avec exécution dans le désodre des accès mémoire]] Les processeurs assez anciens n'autorisaient pas d'exécution dans le désordre des accès mémoire. Concrétement, les accs mémoire devaient se faire dans l'ordre, mais les autres µops pouvaient être exécutées dans le désordre. Il s'agit donc d'un ordre entre µops mémoire, pas entre µops mémoire et autres µops. Les µops entières et flottantes pouvaient être exécutées avant une µops mémoire qui est avant elle dans l'ordre du programme, ce n'est pas un problème. Pour garantir l'ordre desd µops mémoire, l'unité mémoire est précédée par une file de micro-opérations séparée, pour forcer l'exécution dans l'ordre des accès mémoire. De plus, les µops mémoire ne peuvent pas utiliser la fenêtre d'instruction. Dit autrement, la fenêtre d'instruction ne mémorise pas de µops mémoire. Après le décodage, les µops sont réparties soit dans la file de µops mémoire, soit dans la fenêtre d'instruction. Le décodeur classe les µops suivant que ce sont des µops mémoire ou non, et les envoient à la bonne destination. Dans ce chapitre, on supposera que c'est cette solution qui est utilisée. [[File:Processeur avec émission dans l'ordre des accès mémoire.png|centre|vignette|upright=2|Processeur avec émission dans l'ordre des accès mémoire]] La solution précédente revient à scinder la fenêtre d'instruction en deux : une file de µops pour les µops mémoire, une fenêtre d'instruction pour les autres µops. Et cette scission peut aller plus loin, à savoir qu'on peut scinder une fenêtre d'instruction encore et encore. Ce qui nous amène à la section suivante. ===Les fenêtres d'instruction décentralisées=== Nous venons de voir qu'il est possible de scinder la fenêtre d'instruction en une fenêtre d'instruction pour les µops mémoire (simplifiée en une file de µops classique), et une autre pour les autres µops. Sachez qu'il est possible d'aller plus loin, par exemple en séparant la fenêtre d'instruction en une fenêtre spécialisée dans les µops flottantes et une autre pour les µops entières. Et ce n'est là qu'un exemple parmi de nombreuses autres possibilités. Pour faire la différence avec une fenêtre d'instruction unique, nous allons parler de fenêtre d'instruction centralisée s'il n'y en a qu'une, de '''fenêtre d'instruction décentralisée''' s'il y en a plusieurs. Il est possible d'associer chaque fenêtre d'instruction à un type précis de µops. Par exemple, avec une fenêtre d'instruction pour les µops de calcul entières, une autre pour les µops flottantes, une autre pour les µops mémoire. Il s'agit d'un choix simple et efficace, mais quelques processeurs font autrement, pour répondre à des contraintes très diverses. [[File:Processeur avec des fenêtres d'instruction décentralisées.png|centre|vignette|upright=2|Processeur avec des fenêtres d'instruction décentralisées]] Reste à scinder la fenêtre d'instruction pour trier les µops suivant leur type. Si le processeur exécute les accès mémoire dans l'ordre, la méthode la plus simple utilise une fenêtre d'instruction pour les opérations flottantes et une autre pour les autres µops (µops entières et parfois mémoire avec). L'avantage est que cela simplifie grandement le processeur. Les flottants sont gérés à part des entiers. Ils ont leurs propres registres, des FPU séparées des ALU entières, bref : la séparation est complète. Utiliser une fenêtre d'instruction séparée va dans ce sens. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Il est possible de faire pareil sur les processeurs avec exécution dans le désordre des accès mémoire. Par exemple : les processeurs Intel de microarchitecture Skylake utilisent une fenêtre d'instruction pour les opérations entières/flottantes, et une fenêtre d'instruction séparée pour les µops mémoire. Un avantage est que les deux fenêtres d'instructions sont plus spécialisées, ce qui entraine des économies de circuit. Les opérations entières/flottantes ont besoin de deux registres pour les opérandes et d'un autre résultat, alors que les µops mémoire n'ont besoin que de deux registres maximum. En utilisant une fenêtre d'instruction unique, chaque entrée doit mémoriser l'opcode et trois registres, dont un est inutilisé pour les µops mémoire et les branchements. En utilisant des fenêtres d’instructions séparées, celle pour les µops entières/flottantes a trois registres par entrée, contre seulement deux registres par entrée pour celle des µops mémoire. Un cas extrême est celui où chaque ALU/FPU a sa propre fenêtre d'instruction. Nous parlerons alors de '''fenêtres d'instruction totalement décentralisées'''. Par exemple, il y a une fenêtre d'instruction pour l'ALU entière, une autre pour le multiplieur entier, une autre pour le ''barrel shifter'', une autre pour l'unité mémoire, une autre pour l'unitéé de branchements, une autre pour l'additionneur flottant, une dernière pour le multiplier flottant, etc. Un exemple historique est celui de la FPU de l'IBM 360 modèle 90. Elle disposait d'un additionneur flottant, d'un multiplieur flottant, et d'une unité mémoire pour les lectures/écritures flottantes. Les trois unités avaient leur propre fenêtre d'instruction. Les processeurs AMD utilisent beaucoup cette technique, contrairement à Intel qui préfère utiliser des fenêtres centralisées sur les anciens processeurs, deux ou trois fenêtres sur les processeurs récents (2020 et plus). Les processeurs AMD utilisaient précisément une fenêtre d'instruction par ALU entière, alors que les FPUs partagent une fenêtre d’instructions flottantes unique. Mais nous verrons cela en détail dans le chapitre sur les processeurs superscalaires x86. Un point important est qu'avec des fenêtres d'instruction décentralisées, l'émission est découpée en deux étages. La première étape envoie une µops vers la fenêtre d'instruction adéquate, la seconde émet la µops depuis la fenêtre d'instruction quand ses opérandes sont prêtes. La première est l'étage de '''''dispatch''''' qui envoie l'instruction dans la fenêtre d’instruction adéquate, selon que c'est une instruction flottante, entière, autre. La seconde est l'étage de '''''scheduling''''', qui gère la disponibilité des opérandes et des unités de calcul. La µop émise est ajoutée au tampon de réordonnancement, s'il existe, lors de l'étape de ''dispatch''. ===L'usage de plusieurs files d'instruction=== Une dernière méthode d'OOO utilise plusieurs files de micro-opération. L'idée est qu'une fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement une file de micro-opération pour les opérations entières, une autre pour les opérations flottantes, une autre pour les accès mémoire. D'autres processeurs utilisent une file pour les accès mémoire et une autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. La présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que la technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si une dépendance bloque une FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans une autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer la disponibilité des registres. Quand un registre est lu ou écrit par une instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. La logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : une pour les instructions d'accès mémoire et une autre pour les autres instructions. Si jamais une instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de la lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'une est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est la file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. ===Avantages et inconvénients de chaque implémentation=== Un processeur contient soit une fenêtre d'instruction unique, soit plusieurs fenêtres d'instruction séparées. Typiquement, les fenêtres d’instruction séparées sont spécialisées, dans le sens où on a une fenêtre pour les instructions flottantes, une autre pour les instructions entières, une autre pour les accès mémoire, etc. Pour résumer, on a le choix entre une grosse fenêtre généraliste et plusieurs fenêtres spécialisées, sauf que la fenêtre centralisée est lente et complexe, contrairement aux fenêtres spécialisées. Les deux méthodes ont des inconvénients et des avantages différents. Dans les grandes lignes, l'avantage des fenêtres décentralisées est qu'elles sont plus petites qu'une grosse fenêtre d'instruction. Cela simplifie la gestion du contournement et de la répartition des instructions sur les unités de calcul, comme on le verra dans quelques paragraphes. Elles sont donc moins complexes et plus rapides. L'autre avantage, c'est qu'il est possible de démarrer l'exécution de plusieurs instructions simultanément : une instruction par fenêtre décentralisée, contre une par fenêtre d'instruction. Mais les fenêtres décentralisées sont souvent sous-utilisées, partiellement remplies, contrairement aux fenêtres d'instruction. Il arrive qu'une fenêtre d'instruction soit remplie, alors que les autres sont vides. Par exemple, prenons un processeur avec une fenêtre d'instruction reliée à la FPU, et une autre reliée aux autres ALUs. Si le processeur n'exécute que des opérations flottantes, la fenêtre reliée à la FPU sera pleine, alors que l'autre sera vide. L'exécution des instructions dans le désordre est alors limitée par la petite taille de la fenêtre, qui ne peut plus accepter de nouvelle instruction flottante. Avec une fenêtre unique, on n'aurait pas eu ce problème : on aurait eu une énorme fenêtre d'instruction remplie d'instruction flottante, au lieu d'une petite fenêtre spécialisée. Il est maintenant temps de voir en quoi sont faites les fenêtres d’instruction, qu'elles soient centralisées ou décentralisées. Nous allons aussi voir quelle est la logique d'émission associée. ==L'implémentation d'une fenêtre d'instruction : généralités== Une fenêtre d'instruction est une mémoire qui mémorise des micro-opérations. Elle est cependant plus complexe qu'une mémoire RAM ou qu'une FIFO et ressemble un petit peu à une mémoire cache. Elle dispose d'un port d'écriture et d'un port de lecture, au minimum. Le port d'écriture permet à l'unité de décodage d'insérer une micro-opération dedans, d'ajouter la micro-opération qui vient d'être décodée. Si une instruction machine est décodée en plusieurs micro-opération, deux possibilités. La première est de les insérer un par un, ce qui fait qu'on peut se contenter d'un seul port d'écriture. L'autre possibilité est de les ajouter en même temps, ce qui demande plusieurs ports d'écriture. Le port de lecture sert à émettre une instruction. On part du principe que la fenêtre d'instruction ne peut émettre qu'une seule instruction à la fois, car les processeurs que nous avons vu précédemment sont de ce type. Mais nous verrons dans quelques chapitre qu'il existe des processeurs dits superscalaires, qui sont capables d'émettre plusieurs instructions par cycle. Dans ce cas, la fenêtre d'instruction a un seul port de lecture. Un processeur superscalaire, quant à lui, doit avoir un port de lecture par unité de calcul, ce qui fait beaucoup plus. ===Les entrées d'une fenêtre d’instruction=== Les fenêtres d'instruction sont composées d''''entrées''', des mots mémoire qui stockent une instruction. Une instruction réserve une entrée après son décodage et la libère dès qu'elle est envoyée aux unités de calcul. Une entrée contient l'opcode (les signaux de commande à envoyer à l'ALU), le registre de destination du résultat, les registres de chaque opérande, et éventuellement des signaux de commande en plus. De plus, chaque opérande est couplée à un bit de disponibilité, qui indique si elle est disponible. Quand un opérande est écrit dans les registres, le bit de présence correspondant est mis à jour. Enfin, chaque entrée possède un bit ''empty'' qui indique si elle est vide, cette information étant utile pour réserver des entrées. [[File:Entrée d'une station de réservation - sans les tags.png|centre|vignette|upright=3|Entrée d'une fenêtre d'instruction]] Nous verrons dans quelques chapitres que certaines fenêtres d'instruction sont capables de mémoriser les opérandes des instructions. De telles fenêtres d'instruction seront appelées, dans ce cours, des '''stations de réservation'''. Les entrées des stations de réservation sont assez semblables à celle des fenêtres d'instruction, à un détail près : les opérandes de l'instruction sont enregistrées directement dans des champs séparés. Il y a deux champs, un par opérande, pour stocker l'opérande elle-même, lue depuis les registres ou obtenue via le réseau de contournement. Notons que les champs pour les opérandes viennent en plus des champs pour les noms de registres, encore que les deux peuvent être fusionnés si on veut optimiser le tout. [[File:Entrée d'une station de réservation.png|centre|vignette|upright=3|Entrée d'une station de réservation.]] Précisons que la terminologie n'est pas très fiable. Les termes "fenêtre d'instruction" et "station de réservation" ne regroupent pas du tout la même chose d'un papier de recherche à l'autre, d'un bouquin à l'autre, d'un chercheur à l'autre, d'un ingénieur à l'autre, d'un professeur à l'autre. Le terme initial vient pourtant de l'article original sur l'algorithme de Tomasulo, où il désignait une fenêtre d'instruction associée à une unité de calcul précise. Mais le terme a ensuite été réutilisé, ce qui fait que certains processeurs avec plusieurs unités de calcul sont décrit comme ayant une unique station de réservation. En bref : c'est le bazar ! Mais nous en reparlerons dans le chapitre sur le renommage de registres, car c'est la place idéale pour les aborder. Toujours est-il que j'ai fait le choix de confondre les concepts de fenêtre d'instruction et de station de réservation avec les concepts de '''lecture avant émission''' et de '''lecture après émission'''. La différence entre les deux est que les registres sont lus après émission avec une fenêtre d'instruction, avant avec des stations de réservation. Dans le cas "avant émission", les opérandes sont mémorisées dans la station de réservation. Et cette différence a une influence sur le pipeline du processeur, le banc de registres et tout ce qui s'en suit. Un désavantage de la lecture avant émission est qu'il faut stocker les opérandes après lecture, ici dans les stations de réservation. Mais un avantage est que le banc de registre a besoin de moins de ports de lecture, car une bonne partie des opérandes sont fournies par le système de contournement. Nous verrons cela dans le détail dans le chapitre sur les processeurs superscalaires. Il a été proposé de fusionner le tampon de ré-ordonnancement avec la fenêtre d'instruction dans une structure unique. La méthode a notamment été utilisée sur les processeurs d'architecture K6 d'AMD. Le tout donnait une structure appelée le '''DRIS''' (''deferred scheduling register renaming instruction shelf''). La différence avec une fenêtre d’instruction normale est que les entrées sont libérée non pas quand l'instruction est exécutée/émise, mais quand elle termine son exécution et quitte le ROB. La fenêtre d'instruction doit alors incorporer des bits pour savoir si telle entrée a émis sont instruction ou non. ===La logique d'éveil et de sélection=== Dans le cas qui va suivre, on suppose que le processeur ne peut émettre qu'une instruction à la fois. Chaque cycle, une instruction est sélectionnée et est envoyée dans le chemin de données, soit à une ALU, soit à une unité d'accès mémoire. La sélection d'une instruction est effectuée par l'unité d'émission, qui est aussi appelée le '''''scheduler'''''. Elle gère la disponibilité des opérandes et la disponibilité des unités de calcul adéquate. Le choix de l'instruction émise doit être le plus pertinent possible, pour des raisons de performances. Pour le premier point, l'unité d'émission détermine quelles instructions sont candidates pour l'émission. Les ''instructions candidates'' sont celles dont tous les opérandes sont prêts. Le processeur contient un circuit qui détecte les instructions candidates : la '''logique d’éveil''' (''wake-up logic''). Une fois que la logique d'éveil a fait son travail, une instruction est choisie pour s’exécuter en fonction de la disponibilité des unités de calcul adéquates. Ce rôle est dévolu à un circuit qu'on appelle la '''logique de sélection''', ou ''select logic''. [[File:Fonctionnement complet de la logique d’émission.jpg|centre|vignette|upright=1.5|Fonctionnement complet de la logique d’émission.]] La logique de sélection doit gérer le fait que les unités de calcul du processeur ne sont pas toutes identiques. Déjà, un processeur a généralement des unités séparées pour les instructions entières et flottantes, des unités spécialisées dans les accès mémoire, parfois des unités spécialisées pour les branchements. Une instruction doit être attribuée à la bonne unité de calcul, on ne doit pas envoyer une instruction entière dans une unité de calcul flottante. De plus, parmi les unités de calcul entières, toutes ne sont pas identiques. Par exemple, il est fréquent d'avoir plusieurs unités de calcul spécialisées dans les opérations simples (additions, soustractions, opérations logiques) avec une unité pour les multiplications/divisions séparées, parfois une unité spécialisée pour les décalages/rotations, etc. Là encore, allouer la bonne instruction à la bonne ALU est complexe. Plus les unités de calcul sont hétérogènes, plus la logique de sélection est compliquée. Les logiques d'éveil comme de sélection sont assez complexes. Comme on le verra plus bas, la logique de sélection la plus simple, qui gère une seule unité de calcul, est basée sur un encodeur à priorité couplé à d'autres circuits. Et pour gérer plusieurs ALUs, il faut mettre des encodeurs en cascade. Le résultat est que même en prenant une logique de sélection simple, elle sera assez lente et gourmande en circuits. Aussi, la logique de sélection met souvent un cycle d'horloge entier pour faire son travail, elle a son propre étage de pipeline attribué. La logique d'éveil est dans le même cas, ce qui fait qu'émettre une micro-opération demande deux cycles d'horloge. Le défaut est que cela rajoute des cycles d'horloges entre la fenêtre d'instruction et l'ALU, ce qui complique la gestion du pipeline. Ces cycles de retard sont à prendre en compte au moment d'émettre les instructions, les ''scheduler'' doit en tenir compte pour des performances optimales. Sans tenir compte de ces cycles de retard, les instructions arrivent en retard de quelques cycles à l'ALU, cycles de retard durant lesquels l'ALU n'a pas fait de calcul et a été sous-utilisée, sans compter que le système de contournement n'est pas utilisé au mieux. Et le problème est encore plus important sur les processeur avec des stations de réservation, qui utilisent la "lecture après émission" : cela rajoute un cycle d'horloge en plus, un temps de retard en plus. ===La logique d'éveil : l'émission anticipée=== La logique d'éveil doit tenir compte du fait qu'il y a plusieurs étages entre l'émission et l'exécution sur une unité de calcul. Par exemple, un processeur a souvent entre un et à cinq étages entre la file d'attente et les unités de calcul. Il faut lire les registres, gérer le contournement, et cela peut prendre quelques cycles d'horloge. Sur le Pentium 4, on trouve 6 étages entre la fenêtre d’instruction et l'entrée de l'ALU. Si les micro-opérations sont émises quand les opérandes sont disponibles, il y aura un délai de quelques cycles avant qu'elles atteignent l'ALU. Alors qu'idéalement, on souhaiterait que la micro-opération atteigne l'ALU dès que ses opérandes sont disponibles, pour profiter des techniques de contournement. Pour cela, la logique d'éveil émet les instructions quelques cycles en avance pour qu'elles arrivent au bon moment. Il s'agit d'une technique d''''émission anticipée''', dont nous avions parlé dans le chapitre sur le contournement. : Il faut noter que le problème se pose plus avec des fenêtres d'instruction qu'avec des stations de réservation. Les premières ont un étage en plus entre émission et ALU, vu qu'il faut lire des registres après l'émission. L'émission anticipée demande d'émettre un signal d'éveil en avance de quelques cycles, pile au bon moment. Par exemples, si on a deux étages entre l'ALU et l'unité d'émission, le signal de réveil sera généré deux cycles avant que le résultat soit effectivement calculé. L'implémentation varie, mais deux solutions sont possibles. La première est de générer le signal d'éveil dans l'ALU, ce qui n'a de sens que pour les opérations comme les multiplications ou les divisions, qui prennent plusieurs cycles. Une autre technique génère le signal de réveil dans une structure centralisée, spécialisée dans la génération des signaux d'éveil. L'unité de composée d'un registre à décalage par registre. Imaginons qu'une instruction est émise, que cette instruction mette N cycles à s'exécuter, et qu'elle écrive dans un registre de destination. L'unité sélectionne alors le registre à décalage associé au registre de destination, et met le bit numéro N à 1. Le registre décalé d'un cran à chaque cycle. Quand le bit sortant est un 1, alors le signal de validité pour l'opérande est généré. L'émission anticipée marche bien si l'instruction a une durée fixe, connue à l'avance. Et autant c'est le cas pour les instructions arithmétiques et logiques, autant ce n'est pas le cas pour les accès mémoire. Les accès mémoire ont une latence variable : quelques cycles pour un succès de cache, plusieurs dizaines de cycles pour un défaut de cache L1, pas loin de la centaine pour un défaut de cache L2, etc. Et cela pose des problèmes pour l'émission anticipée. L'émission en avance pour les accès mémoire est purement spéculative : le processeur émet des instructions en supposant que la lecture entrainera un succès de cache, quitte à annuler l'instruction en cas de défaut de cache. Mais faire ainsi demande non seulement d'annuler les instructions émises en avance, mais aussi de ne pas retirer les instructions émises en avance de la fenêtre d'instruction. Elles sont émises, mais une copie de sauvegarde est conservée dans la fenêtre d'instruction. Si le processeur détecte un défaut de cache, il peut alors ré-exécuter l'instruction. S'il détecte un succès de cache, les instructions lecture-dépendante sont retirées de la fenêtre d'instruction, la copie de sauvegarde est devenue inutile et est donc jetée. ===La logique de sélection : âge ou position ?=== La logique de sélection est primordiale pour de bonnes performances. Il existe deux méthodes principales pour sélectionner l'instruction à exécuter. La première est la plus simple : elle se base sur lé numéro de l'entrée. En effet, une fenêtre d'instruction est avant tout une sorte de mémoire, un mix entre mémoire associative, mémoire RAM, et FIFO. Et chaque entrée a un numéro, une adresse mémoire. Nous parlerons de numéro dans ce qui suit, car ce sera plus simple, le terme d'adresse mémoire étant peut-être un peu exagéré dans le contexte des fenêtres d'instruction. Toujours est-il que la fenêtre d'instruction est adressable dans le sens où on peut lui envoyer le numéro de l'entrée voulue, et la fenêtre d’instruction renvoie le contenu de l'entrée sur son port de lecture. Et c'est ce que fait la logique de sélection : elle génère le numéro de l'entrée à lire. Le numéro est alors envoyé sur l'entrée d'adresse de la fenêtre d’instruction, et elle fournit la micro-opération associée sur son port de lecture, son '''port d'émission'''. La première méthode de sélection, donc. Elle est basée sur sur le numéro de l'entrée. Si plusieurs entrées sont éveillées, la logique de sélection prend celle avec le plus petit numéro. Elle porte le nom de '''sélection par position''', sous-entendu position dans la fenêtre d'instruction. Vous l'avez peut-être deviné, mais la logique de sélection est alors un encodeur à priorité. Le circuit de sélection ne se résume donc pas seulement à un encodeur à priorité, mais c'est le circuit central. L'avantage d'une telle méthode de sélection est qu'elle est simple à implémenter : un encodeur à priorité est un circuit connu, facile à implémenter. Mais on remarque un défaut : un encodeur est un circuit assez rapide, mais qui utilise beaucoup de transistors, beaucoup de portes logiques, surtout si on veut qu'il soit rapide. Ce qui explique que la logique de sélection ait son propre étage de pipeline rien que pour elle. La seconde méthode s'appelle la '''sélection par âge''', au nom assez transparent. L'idée est de privilégier l'émission de l'instruction la plus ancienne. Elle demande que la fenêtre d'instruction trie les micro-opérations par ordre d'insertion dans la fenêtre d'instruction, ce qui en fait une pseudo-FIFO. Le tri est partiel, car les instructions peuvent sortir de la fenêtre d’instruction à tout moment. Compacter la fenêtre d'instruction, à savoir regrouper toutes les entrées valides est une idée, mais elle est compliquée à implémenter. Aussi, elles préfèrent encoder des informations sur l'ordre d'émission dans chaque entrée. L'encodeur à priorité doit alors travailler non pas sur des nombres entiers liés à l'ordre d'insertion dans la pseudo-FIFO. Elle est encore plus gourmande en circuits que la méthode précédente. Les processeurs haute performance utilisent souvent des méthodes hybrides. Par exemple, les processeurs AMD de microarchitecture Bulldozer utilisaient une méthode intermédiaire. Ils utilisaient une fenêtre d'instruction couplée à un encodeur à priorité pour la sélection par position, mais complémentaient le tout avec une unité qui mémorisait l'instruction la plus ancienne dans la fenêtre d’instruction. Le mécanisme de sélection par âge était utilisé en priorité. Mais si l'instruction la plus ancienne n'était pas prête, le processeur basculait sur le mécanisme de sélection par position. ===La compaction des fenêtres d'instruction=== À chaque cycle, les instructions décodées sont ajoutées dans la fenêtre d'instruction, dans des entrées vides. Vu que les instructions quittent celle-ci dans le désordre, ces vides sont dispersés dans la fenêtre d'instruction, ce qui pose problème pour déterminer où placer les nouvelles instructions. La solution la plus triviale consiste à conserver une liste des vides, mise à jour à chaque insertion ou émission d'instruction. Une autre solution consiste à éliminer les vides en compactant la fenêtre d'instruction à chaque cycle d'horloge. Des circuits se chargent de détecter les vides et de regrouper les instructions en un unique bloc. Il faut signaler que certaines processeurs arrivent à se passer de cette étape de compactage, mais au prix de fenêtres d'instruction nettement plus complexes. Autre problème : quand il faut choisir quelle instruction émettre, il y a toujours plusieurs candidats. Si on choisit mal, des instructions restent en attente trop longtemps parce que d'autres instructions plus jeunes leur passent devant. Pour éviter cela, les instructions les plus vielles, les plus anciennes, sont prioritaires. Pour cela, on peut utiliser une FIFO un peu spéciale pour la fenêtre d'instruction. Si les ajouts d'instruction se font dans l'ordre, les instructions ne quittent pas forcément la fenêtre d'instruction dans l'ordre imposé par une FIFO : les instructions restent triées dans leur ordre d'ajout, même s'il y a des vides entre elles. Dans ces condition, il est préférable que le compactage conserve l'ordre FIFO des instructions. Dans ces conditions, l'instruction la plus ancienne est celle qui est située à l'adresse la plus faible : le circuit de sélection peut donc être fabriqué avec des encodeurs, et est relativement simple. ==Les fenêtres d'instruction basées sur une matrice de dépendances== L'implémentation la plus simple étend le fonctionnement d'un pipeline dynamique usuel. Rappelez-vous le chapitre sur les pipeline dynamiques. Nous avions vu que de tels pipelines émettaient une instruction par cycle, quitte à émettre des bulles de pipeline en cas de dépendance bloquante. Et il est possible d'améliorer leur unité d'émission pour qu'elle soit compatible avec l'exécution dans le désordre. ===Rappels sur le registre de réservation/disponibilité=== L'émission d'une instruction est gouvernée par un ''registre de réservation'' qui indique quels registres sont réservés par une instruction, et ceux qui sont libres. Un registre réservé est un registre qui sera écrit par une instruction en cours d'exécution, mais qui n'a pas encore écrit son résultat. Les instructions candidates doivent avoir leurs opérandes dans des registres libres. Sinon, c'est signe que leurs opérandes sont réservées en écriture, donc pas encore écrites, donc pas disponibles. Si une instruction candidate veut lire ce registre, c'est signe qu'il y a une dépendance RAW : elle veut lire un registre réservé, qui est destiné à être écrit par une instruction en vol. Si elle veut écrire, c'est signe qu'elle veut écrire dans un registre où une autre instruction veut écrire : c'est une dépendance WAW. Dans les deux cas, l'instruction n'est pas émise. Le registre de réservation encode les registres réservés comme suit : chaque bit est associé à un registre. Le bit numéro 0 est associé au registre numéro 0, le bit numéro 1 au registre numéro 1, etc. Là, En clair, les numéros de registres réservés sont encodés en représentation non pas binaire, mais en représentation ''one-hot'' (vue au premier chapitre). {|class="wikitable" |+ Registre de réservation |- ! Registre 7 !! Registre 6 !! Registre 5 !! Registre 4 !! Registre 3 !! Registre 2 !! Registre 1 !! Registre 0 |- | 0 || 0 || 1 || 0 || 0 || 1 || 0 || 0 |} Avant d'émettre une instruction, l'unité d'émission extrait les registres opérande/destination et les convertis dans la même représentation que le registre de réservation, à savoir en représentation ''one-hot''. Le circuit de traduction binaire vers ''one-hot'' est, pour rappel, un simple décodeur. Puis, on fait un OU logique entre les sorties des décodeurs. Le résultat est un masque qui indique quels registres sont lus par l'instruction, encodé en représentation ''one-hot''. Appelons-le le '''masque d'opérandes'''. Le masque est alors comparé au registre de réservation pour vérifier si l'instruction peut être émise. [[File:Unité d'émission simple, dans l'ordre.png|centre|vignette|upright=2|Unité d'émission simple, dans l'ordre]] Si l'émission est autorisée, le registres de réservation est là aussi mis à jour. Le registre de réservation est aussi mis à jour dès qu'une instruction enregistre son résultat dans les registres, ou alors dès qu'il est disponible pour le contournement. Le bit associé au registre repasse alors à 0 (ou à 1). Sans contournement, la mise à jour se fait alors à la toute fin de l'instruction, quand elle se termine, lors de la dernière étape d'enregistrement, à la fin de son pipeline. Avec, elle se fait quand l'instruction quitte l'unité de calcul. ===L'extension à l'exécution dans le désordre : l'éveil par matrice de bits=== La différence entre un pipeline dynamique et l'exécution dans le désordre est que l'on passe d'une instruction à émettre à plusieurs. Plusieurs instructions sont mises en attente dans une fenêtre d’instruction, et y attendent leur tour. L'idée est alors d'envoyer le registre de disponibilité à toutes les entrées, à toutes les instructions en attente. Ainsi, on sait quelles sont les instructions qui peuvent s'exécuter et celles qui ne le peuvent pas. L'implémentation est assez simple, elle ressemble beaucoup à l'implémentation d'un pipeline dynamique simple, si ce n'est que des circuits sont dupliqués. L'implémentation utilise des fenêtres d'instruction légèrement différentes de celles introduites plus haut. Elles n'utilisent notamment pas de bits de disponibilité, mais autre chose. Lorsqu'une instruction est ajoutée à la fenêtre d'instruction, le masque de disponibilité des opérandes est stocké dans la fenêtre d'instruction. A chaque cycle, le registre de disponibilité est envoyée à toutes les entrées, et est comparé avec tous les masques de disponibilité des opérandes. Si une comparaison renvoie un 1, alors l'instruction de l'entrée est une instruction candidate à l'émission. [[File:Unité d'émission dans le désordre basée sur un registre de disponibilité.png|centre|vignette|upright=2.5|Unité d'émission dans le désordre basée sur un registre de disponibilité]] L'ensemble est implémenté avec l'aide d'une '''matrice de bits''', où chaque ligne correspond à une entrée et chaque colonne à un registre. À chaque croisement entre une ligne et une colonne, on trouve un bit. Si le bit de la ligne n et de la colonne m est à 1, cela veut dire : l'instruction dans l'entrée n a besoin de lire le registre m. S’il est à 0, alors cela veut dire que l'instruction stockée dans la ligne n n'a pas besoin de la donnée dans le registre m. [[File:Planificateur à matrice de bits.jpg|centre|vignette|upright=2|Planificateur à matrice de bits.]] Lorsqu'une instruction réserve une entrée, elle initialise la ligne en fonction des registres qu'elle souhaite lire. Pour vérifier si une instruction a ses opérandes prêts, le processeur compare le registre de disponibilité à la ligne associée à l'instruction/entrée. A chaque intersection ligne-colonne, se trouve un comparateur de 1 bit, qui détecte si le registre est demandé et disponible. Les résultats de cette porte sont ensuite envoyés à une porte ET, qui fait le gros du travail. [[File:Logique de détection de la disponibilité d'une instruction.jpg|centre|vignette|upright=2|Logique de détection de la disponibilité d'une instruction.]] ==Les fenêtres d'instruction basées sur une mémoire associative== Les processeurs modernes utilisent une mémoire associative pour la fenêtre d'instruction. Les mémoires associatives ont été abordées il y a quelques chapitres, mais faisons quelques rappels. Les mémoires associatives servent à accélérer la recherche de données dans un ensemble. Or, une fenêtre d'instruction vérifie régulièrement si chaque entrée est prête. Il s'agit d'un processus de recherche d'une instruction qui respecte une condition bien précise dans la mémoire, ce qui fait que les mémoires associatives sont donc tout indiquées. Comme vous le savez, les signaux de commande d'une instruction sont propagés avec celle-ci dans le pipeline, le nom du registre de destination ne faisant pas exception. Le nom de registre est envoyé à la fenêtre d'instruction lors de l'écriture du résultat dans les registres. S'il y a correspondance, l'opérande est disponible et son bit de disponibilité est mis à 1. On peut adapter cette méthode pour tenir compte du contournement assez simplement. [[File:Détection des dépendances par propagation du registre de destination.png|centre|vignette|upright=2|Détection des dépendances par propagation du registre de destination.]] En conséquence, le circuit de détection des dépendances est constitué d'un grand nombre de comparateurs : un par champ « nom de registre » dans chaque entrée. La logique d'éveil/''wake up'' regroupe tous les comparateurs, la logique de sélection est un circuit situé en-dehors de la mémoire associative. Les entrées sont dans la mémoire associative elle-même. [[File:Gestion des bits de validité.png|centre|vignette|upright=2|Gestion des bits de validité.]] L'implémentation la plus simple est celle du schéma précédent, où on utilise une mémoire associative unique. Une version plus élaborée sépare la fenêtre d'instruction en deux parties : une mémoire qui mémorise les registres des opérandes, une autre mémoire pour le reste. La mémoire pour les registres opérandes est la mémoire associative proprement dite, c'est elle qui est associées aux comparateurs, à la logique de ''wake-up''/réveil, etc. Par contre, l'autre mémoire est une mémoire RAM simplifiée, qui mémorise les informations qui n'ont pas besoin des comparateurs. L'opcode de l'instruction est là-dedans, par exemple. ===Les optimisations de la consommation d'énergie : la désactivation des portions inutilisées=== Le problème avec des fenêtres d'instruction de ce type est leur forte consommation énergétique, ainsi que le grand nombre de portes logiques utilisées, qui deviennent prohibitif pour des fenêtres d'instruction un peu grosses. Pour résoudre ce problème, certains ont optimisé les comparateurs. D'autres ont tenté de profiter du fait que la majorité des bits dans les entrées sont composés de zéros. Bref, les optimisations purement matérielles sont légion. Une première solution est de désactiver les entrées qui sont inutilisées, vides, sans instruction. Pour cela, on fait précéder les comparateurs par un circuit qui les connecte ou déconnecte des lignes de bit. Le circuit est commandé par le bit ''empty'' qui indique si une entrée est vide ou non. L'avantage est que la consommation d'énergie de la fenêtre d'instruction devient alors proportionnelle au nombre d'entrées non-vides, et non au nombre d'entrées total. Du moins, en apparence, les entrées non-utilisées doivent quand même être alimentées pour fonctionner, mais l'activité de comparaison disparait dans les entrées vides. Il est possible d'étendre cette technique aux entrées dont les opérandes sont prêtes. Les gains sont généralement assez bons, avec une réduction de consommation variant entre 30 et 50%, avec une implémentation très simple et très économe en circuits. Une autre solution, assez simple à mettre en place, consiste à désactiver une partie de la fenêtre d'instruction sin elle est inutilisée. Pour cela, il faut segmenter la fenêtre d'instruction avec la technique du ''wire partitionning''. Pour rappel, une fenêtre d'instruction est une mémoire associative. Et comme toute mémoire associative, elle contient des fils, les lignes de bit, qui relient les entrées/sorties à toutes les cellules mémoire. Plus une ligne de bit est longue, plus elle consomme d'énergie et plus le temps de lecture/écriture est long. L'idée est de segmenter les lignes de bits en plaçant des répéteurs qui recopient la tension d'un segment au suivant. Les répéteurs sont des tampons trois-états, ce qui permet de déconnecter les portions inutilisées de la ligne de bit. Ce faisant, la fenêtre d'instruction est découpée en segments, qui peuvent être désactivés si besoin. Si il y a peu d'instructions chargées dans la fenêtre d'instruction, les portions inutilisées sont désactivées. La technique marche d'autan mieux si les instructions sont compactées au début de la fenêtre d'instruction. [[File:Wire partitionning.png|centre|vignette|upright=2|Wire partitionning]] Tout le problème est de savoir quelles portions désactiver. La technique est assez simple si la fenêtre d'instruction est compactée, à savoir si toutes les instructions sont régulièrement regroupées au début de la mémoire CAM. Mais même avec cette optimisation, la décision de désactiver une portion de la fenêtre d'instruction n'est pas à prendre à la légère. Il ne faut pas désactiver une portion contenant des instructions pouvant être émise sous peu. La décision dépend de paramètres variés : proportion d'entrée vides, quantité d'entrées récemment activées/désactivées récemment, présences d'entrées avec un ''match'' d'opérandes récent, etc. Il est important de préciser que les techniques en question fonctionnent aussi sur les autres types de fenêtre d'instruction, qui ne sont pas basées sur des mémoires associatives. Nous allons voir celles-ci dans la suite du chapitre, mais gardez à l'esprit que ces optimisations, à savoir désactiver les entrées vides/prêts et partitionner la fenêtre d'instruction, sont des optimisations générales qui marchent avec presque tout. ===L'ajout d'une FIFO pour les instructions déjà prêtes à l'émission=== D'autres techniques permettent de réduire aussi bien le cout en circuits que la consommation d'énergie de la fenêtre d'instruction. L'idée est d'utiliser une mémoire associative quand elle est réellement nécessaire, mais d'utiliser une fenêtre d'instruction "normale" dès que possible. La méthode la plus simple tient compte du fait que certaines instructions ont déjà toutes leurs opérandes de disponibles à l'émission, mais doivent quand même être mises en attente, parce que l'ALU adéquate est occupée, parce que des dépendances WAW/WAR sont encore là, ou pour tout autre raison. Dans ce cas, elles sont mises en attente non pas dans la fenêtre d'instruction, mais dans une mémoire FIFO toute simple. L'idée est qu'au lieu d'avoir une énorme mémoire associative pour la fenêtre d'instruction, on déplace quelques entrées dans une petite FIFO annexe. Le résultat est un gain en terme d'énergie et de circuits, au prix d'une perte de performance mineure. La perte de performance en question se manifeste si aucune instruction n'a ses opérandes de prêtes à l'émission : le programme n'utilise pas la FIFO et voit alors une fenêtre d'instruction plus petite. Une amélioration de cette technique tient compte du fait que certaines instructions sont dans un cas intermédiaire. Elles ont déjà une opérande de prête lors de l'émission, mais pas l'autre. Le nombre d'opérandes varie suivant l’instruction : certaines n'ont besoin que d'un seul opérande. De plus, il arrive qu'une opération tout juste décodée ait déjà un ou plusieurs de ses opérandes de prêts. Cette constatation permet d'éviter d'utiliser des comparateurs pour les opérandes déjà prêts. Par exemple, on peut parfaitement utiliser trois fenêtres d'instruction : * une pour les instructions dont tous les opérandes sont prêts, mais qui sont quand même mises en attente, sans comparateur ; * une pour les instructions dont un seul opérande manque, qui n'utilise qu'un comparateur par entrée ; * une pour les instructions dont deux opérandes manquent à l'appel, qui utilise deux comparateurs par entrée. C'est beaucoup plus économique que d'utiliser une seule grosse fenêtre d'instruction qui contiendrait autant d'entrées que les trois précédentes réunies, avec deux comparateurs par entrée. Certains sont même allés plus loin, et ont proposé de supprimer la fenêtre d'instruction avec deux opérandes par entrée. Les instructions dont deux opérandes sont inconnus au décodage sont stockées dans la fenêtre d'instruction pour instructions avec un comparateur par entrée. Un circuit de prédiction se charge alors de prédire l'opérande manquant, cette prédiction étant vérifiée plus loin dans le pipeline. Il serait cependant étonnant qu'une telle proposition ait donné lieu à la moindre implémentation réelle. ===Les optimisations de la consommation d'énergie avancées=== D'autres chercheurs ont conservé une fenêtre d'instruction unique, avec autant de comparateurs par entrée qu'il y a d'opérandes possibles par instruction. Simplement, le processus de détection des opérandes prêts est légèrement ralenti : on ne vérifie qu'un opérande par cycle. Pour vérifier les deux opérandes d'une entrée, on doit attendre deux cycles. Enfin, certains chercheurs ont proposé des fenêtres d'instruction segmentées. Les instructions circulent à chaque cycle d'un segment vers le suivant : en conséquence, certains segments conservent les instructions les plus anciennes, un autre les instructions les plus jeunes, etc. Seul le denier segment, celui qui contient les instructions les plus vielles, peut émettre une instruction : la détection des opérandes se fait seulement dans le dernier segment, qui contient les instructions les plus anciennes. On économise ainsi beaucoup de comparateurs. Certains chercheurs ont tenté de pipeliner l'étape de sélection des opérandes, ainsi que l'étage d'arbitrage. Mais en faisant cela, il faut plusieurs cycles pour détecter qu'une instruction a ses opérandes prêts, ce qui pose problème face à de nombreuses dépendances RAW. Pour éviter de trop perdre en performances, certains chercheurs ont décidé d'utiliser des techniques pour prédire quelles seront les instructions dont les opérandes seront bientôt prêts. Si détecter qu'une instruction est prête prend n cycles, le processeur devra tenter de prédire la future disponibilité des opérandes n cycles en avance pour obtenir des performances optimales. ===Remplacer la mémoire associative par une RAM=== Une autre optimisation possible est de remplacer la fenêtre d'instruction par une mémoire RAM, dont chaque mot mémoire correspondrait à une entrée. Une telle optimisation permet en théorie de se passer des comparateurs associés à chaque entrée, mais au prix de l'ajout de circuits annexes potentiellement couteux. La première de ces techniques, la '''recherche directe par étiquette''' (direct tag search) fut créée par Weiss et son collègue Smith. Ils cherchaient à améliorer l'algorithme de Tomasulo, un algorithme qu'on expliquera dans quelques chapitres. Rappelons que chaque instruction produit un résultat, qui devra être rapatrié dans une ou plusieurs entrées de la fenêtre d'instruction. L'optimisation de la recherche directe par étiquette fonctionne dans le cas où le résultat de l'instruction n'est utilisé que par une seule entrée, et pas plusieurs. Le principe est simple : chaque champ « opérande » d'une entrée est adressable via le nom de registre de cette opérande. Pour faire le lien entre entrée et nom de registre, la recherche directe par étiquette ajoute une table de correspondances matérielle, une mémoire RAM qui mémorise les adresses des champs « opérande » des entrées. Les adresses envoyées dans cette mémoire sont les noms de registres des résultats. Lors de l'émission, la table de correspondances est mise à jour. Les numéros des champs « opérande » réservés lors de l'émission sont mémorisés dans les mots mémoire qui correspondent aux deux registres sources. Toutefois, une petite vérification est faite lors de l'émission : si il y a déjà une correspondance dans la table pour un registre source, alors une autre instruction compte lire ce registre. Pour éviter d'écraser les données de l'instruction précédente dans la table de correspondances, l'émission de l'instruction est bloquée. [[File:Recherche directe par étiquette.png|centre|vignette|upright=2|Recherche directe par étiquette.]] ==Les fenêtres d’instruction avec préplanification== Avec la '''préplanification''' (''prescheduling''), la fenêtre d’instruction est composée de mémoires FIFO dans lesquelles les instructions sont triées dans l'ordre d'émission. Il n'y a pas de logique d’émission proprement dite, celle-ci se bornant à vérifier si l'instruction située au début de la FIFO peut s’exécuter. Par contre, le préplanificateur détecte les dépendances et en déduit où insérer les instructions dans le tampon d'émission, à l'endroit le plus adéquat. [[File:Préplanification.jpg|centre|vignette|upright=2|Préplanification.]] ===L'usage de FIFO multiples=== La technique de préplanification la plus simple utilise plusieurs FIFO. Quand une instruction a une dépendance avec une autre instruction, les deux sont placées dans la même FIFO. Pour cela, le préplanificateur détecte les chaines d'instructions dépendantes, et place les instructions dans la FIFO adéquate. A chaque cycle, l'unité d'émission lit une micro-opération dans chaque FIFO et vérifie si elle peut l'émettre. Si la micro-opération n'a pas ses opérandes disponibles, ou qu'une dépendance structurelle survient, alors la FIFO est bloquée. La micro-opération attend que la dépendance soit résolue, bloquant toutes les instructions précédentes. Mais les autres FIFO ne sont pas bloquées, laissant de la marge de manœuvre. [[File:Préplanification par FIFO multiples.png|centre|vignette|upright=1.5|Préplanification par FIFO multiples.]] ===La technique du tampon trié=== La technique du '''tampon trié''' trie les instructions selon le temps d'attente avant leur exécution. Les instructions qui sont censées s’exécuter bientôt sont insérées au tout début de la FIFO, tandis que les instructions qui s’exécuteront dans un long moment sont insérées vers la fin. Là encore, l'unité d'émission lit une micro-opération dans la FIFO, et détermine si elle peut être émise. Si une dépendance survient, l'émission est retardée, et la FIFO est bloquée. [[File:Préplanification par tampon trié.png|centre|vignette|upright=1.5|Préplanification par tampon trié.]] La technique a cependant quelques problèmes assez importants. Le premier problème est que la FIFO est bloquée lorsqu'une micro-opération ne peut être émise. Le second problème est que le temps avant exécution n'est pas toujours connu, notamment pour les instructions d'accès mémoire. Et cela se répercute sur les instructions dépendantes de celles-ci. Pour résoudre ce genre de problèmes, l'usage d'un pipeline à ''replay'' est possible, et est même l'une des meilleures solution possible, malgré ses défauts. L'idée est que les lecture sont pré-planifiées en supposant qu'elles font un succès de cache L1. Si la prédiction est fausse, la lecture est ré-exécutée plusieurs cycles plus tard, en supposant qu'elle fait un succès dans le cache L2, et ainsi de suite. Elle est alors ré-insérée dans la FIFO, elle est pré-planifiée une seconde fois. Il en est de même si une micro-opération ne peut pas être émise : il suffit de la réinsérer dans la FIFO au bon endroit, en attendant que ses dépendances soient résolus. Ainsi, l'instruction fautive ne bloque pas la fenêtre d’instruction, et retente sa chance autant de fois qu'il le faut. [[File:Préplanification par fenêtre d’instruction scorebarodée.png|centre|vignette|upright=1.5|Préplanification par fenêtre d’instruction scorebarodée.]] Une autre solution utilise deux fenêtres d’instruction : une FIFO gérée par la préplanification, et une vraie fenêtre d'instruction pour les instructions dont le temps d'attente ne peut pas être déterminé. Il est possible de mettre cette dernière avant la préplanification, afin de gérer les temps d'attente des instructions d'accès mémoire. Quand le temps d'attente d'une lecture devient connu, ses instructions dépendantes sont gérées avec préplanification. [[File:Préplanification avec fenêtre d’instruction.png|centre|vignette|upright=2.5|Préplanification avec fenêtre d’instruction.]] ===Les fenêtres d'instruction avec allocation temporelle statique=== L''''allocation temporelle statique''' correspond à une technique utilisée sur les processeurs Cuzco de l'entreprise Condor. La technique en question a été présenté en 2025, mais des idées similaires ont été présentées dans la littérature académique. Elle ressemble beaucoup aux techniques de pré-planification, avec cependant quelques différences. L'idée est simple : le processeur dispose de plusieurs fenêtres d'instruction, qui mettent en attente les micro-opérations. Lors de l'étape de renommage de registres, le processeur détermine dans combien de cycles d'horloge la micro-opération sera prête pour exécution. La micro-opération est alors mise en attente durant ce nombre de cycles, dans les fenêtres d'instruction, puis est émise une fois ce nombre de cycles écoulés. Ce faisant, les fenêtres d'instruction n'ont pas besoin de détecter la disponibilité des opérandes à chaque cycle, pour chaque micro-opération en attente. Le ''timing'' de l'émission des micro-opérations est décidé à l'avance. L'implémentation exacte n'est pas connue, mais plusieurs solutions sont imaginables. Par exemple, la fenêtre d'instruction peut simplement être composée de plusieurs mémoires de petite taille, chacune contenant les micro-opérations destinées à être exécutées dans N cycles, N étant différent pour chaque mémoire. Une autre solution, plus réaliste, utilise une fenêtre d'instruction dans laquelle la micro-opération est couplée à des champs pour les opérandes, et un champ compteur. Le champ compteur est initialisé avec le nombre de cycles à attendre, et est décrémenté à chaque cycle d'horloge. Quand il atteint zéro, la micro-opération est émise. Vous remarquerez que la méthode ne marche que si toutes les micro-opérations prennent un nombre fixe de cycles d'horloge. Et autant c'est le cas pour les micro-opérations arithmétiques ou logiques, autant les accès mémoire ne rentrent pas dans ce cadre. En théorie, on ne sait pas combien de temps prendra un accès mémoire. Et cette incertitude se répercute sur les instructions dépendantes d'un accès mémoire. Pour éviter cela, le processeur réutilise un pipeline à ''replay'' tel que vu dans le chapitre précédent. L'unité de renommage de registre suppose que tout accès mémoire fait un succès de cache L1, et décide des ''timings'' d'émission sous cette hypothèse. Si une lecture subit un défaut de cache, elle est ré-exécutée, de même que toutes les instructions dépendantes. Pour cela, le registre de destination de la lecture est marqué comme invalide, grâce à un bit spécifique attaché au registre. Toute instruction qui lit une opérande invalide est elle aussi ré-executée de zéro. Pour simplifier, l'unité d'émission ressemble à une unité d'émission dans l'ordre, avec un registre de disponibilité, qu'on aurait amélioré pour aller au-delà de la simple détection des dépendances d'instruction. Pour déterminer les ''timings'' d'émission, à savoir quand émettre une micro-opération, le processeur utilise une unité d'émission à deux étages. Le premier étage est appelé le ''register scoreboard'', le second étage est appelé la ''Time Ressource Matrix''. Les deux étages communiquent entre eux, comme on va le voir, et leurs noms donnent une idée de ce qu'ils font. Le premier étage gère les dépendances de registres, le second gère les dépendances structurelles. Le premier étage est un registre de disponibilité amélioré, qui gère les dépendances de registre. Cet étage sait quand tel registre sera écrit, et donc que l'opérande écrite dedans sera disponible à partir de tel cycle d'horloge. Il le sait car l'étage suivant l'aura prévenu, mais laissons cela de côté pour le moment. Quand une micro-opération rentre dans cet étage, il vérifie les dépendances avec les registres et les micro-opérations antérieures. Vu qu'il sait quand les registres seront disponibles, il peut déterminer quand l'instruction pourra s'exécuter. Par exemple, si une micro-opération lit les deux registres R7 et R15, qui sont disponibles respectivement dans 5 et 7 cycles, le premier étage sait que la micro-opération devra attendre 7 cycles. Mais tout cela ne suffit pas à déterminer quand émettre une micro-opération. En effet, il fait aussi gérer les dépendances structurelles, ce qui est le boulot du second étage. Le second étage utilise pour cela une ''Time Ressource Matrix'', qui mémorise l'occupation de diverses "ressources", pour les 256 cycles d'horloge à venir. Les ressources en question sont les ports de lecture/écriture du banc de registre, les ALUs utilisées, si la micro-opération utilise l'unité mémoire, etc. Le second étage prend en entrée une micro-opération, détermine quelles "ressources" elle utilise, puis regarde leur disponibilité. Elle détecte alors les dépendances structurelles et détermine alors quand peut s'exécuter la micro-opération. Elle peut retarder l'émission de quelques cycles, si une dépendance structurelle est détectée. Une fois sortie du second étage, on sait quand la micro-opération va être émise, à quel cycle précisément. Et vu que la durée de l'instruction est fixe, on sait quand cette micro-opération va se terminer, quand son résultat sera disponible. Cela permet de mettre à jour la ''Time Ressource Matrix'', pour préciser que le port d'écriture sera occupé à tel moment. De plus, cette information est transmise au premier étage, qui sait alors quand est enregistré le résultat dans le registre de destination. C'est comme cela que le premier étage sait quand un registre est disponible : le second étage le prévient, quand il émet une instruction ! La ''Time Ressource Matrix''mémorise l'occupation des "ressources" pour les 256 cycles d'horloge à venir. Cependant, elle ne vérifie pas les dépendances pour les 256 cycles suivants. Quand elle reçoit une micro-opération, elle teste les dépendances structurelles pour seulement les 8 prochains cycles maximum. Si la micro-opération ne peut pas être émise pendant ces 8 cycles, le pipeline est bloqué, un ''pipeline stall'' est émis. Pour être plus précis, vu que le processeur peut décoder 8 micro-opérations en même temps, cela permet de ne consulter que 64 cycles d'horloge sur les 256. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les premiers processeurs Intel | prevText=Les premiers processeurs Intel | next=Le renommage de registres | nextText=Le renommage de registres }} </noinclude> qjcfh6gbaqtzi5xwql7b06m3k319sem 773600 773598 2026-09-29T19:33:14Z Mewtow 31375 /* Avantages et inconvénients de chaque implémentation */ 773600 wikitext text/x-wiki Dans les chapitres précédents, nous avons parlé des techniques dites d''''émission dans l'ordre'''. L'idée est d’exécuter une nouvelle micro-opération à chaque cycle, dans des unités de calcul séparées. Les instructions sont émises consécutivement, mais les instructions s’exécutent en parallèle dans des unités de calcul séparées. Par contre, quand l'unité d'émission ne peut pas émettre une instruction, elle bloque tout le pipeline. Les instructions qui suivent sont elles aussi bloquées, elle doivent attendre leur tour, même si elles sont en capacité de s'exécuter. Les techniques d'exécution dans le désordre que nous allons voir dans ce chapitre corrigent ce point précis. Elles sont dites à '''émission dans le désordre'''. Elles se distinguent des précédentes sur un point précis : quand l'unité d'émission bloque l'émission d'une instruction, les instructions suivantes peuvent poursuivre. L'émission des instructions peut donc se faire dans le désordre, dans le sens où une instruction peut être émise alors qu'une instruction précédente ne l'est pas encore. L'avantage de l'émission dans le désordre est qu'une instruction s'exécute dès que ses opérandes sont disponibles. Par disponible, on veut dire présent soit dans le réseau de contournement, soit dans les registres. Le processeur détecte automatiquement quand les opérandes d'une instruction sont sont disponibles, et il l’exécute à ce moment là. Dès qu'une instruction a ses opérandes disponibles, elle est émise et exécutée. C'est là la seule contrainte : les dépendances WAR, WAW et autres sont gérées par un ROB ou toute autre technique d'exception précise, seules les dépendances RAW limitent l'exécution. Mais avant de poursuivre, quelques point niveaux terminologie : * L'émission dans le désordre est un terme parlant et assez précis. Malheureusement, la terminologie la plus utilisée par d''''exécution dans le désordre'''. Et nous utiliserons ce terme dans la suite du cours, histoire de ne pas trop dévier de la nomenclature habituelle. * Nous utiliserons parfois l'abréviation OOO pour parler d'exécution dans le désordre. L'abréviation est celle de ''Out Of Order Excution''. * Nous utiliserons aussi l'abréviation ''µop'' pour parler de micro-opération, ''µops'' au pluriels pour parler de plusieurs micro-opérations, ou des micro-opérations en général. L'exécution dans le désordre ne gére en effet que des µops, elle se situe après l'étape de décodage. Mais avant de poursuivre, précisons une chose importante : l'exécution dans le désordre traite les accès mémoire à part. La majorité des processeurs OOO assez anciens exécutent les accès mémoire dans l'ordre, seules les µops entières/flottantes/branchements sont exécutées dans le désordre. Les processeurs datant d'après les années 2010 sont capable d'exécuter les accès mémoire dans le désordre, mais l'implémentation en question est assez particulière. Un chapitre entier sera dédié à l'exécution dans le désordre des µops mémoire. Nous allons volontairement mettre de côté la gestion des accès mémoire dans ce chapitre. ==Les fenêtres d’instruction : généralités== [[File:File de micro-opération.png|vignette|upright=1|File de micro-opérations]] Pour décrire comment est implémentée l'émission dans le désordre, il faut commencer par parler des processeurs sans. Les processeurs sans exécution dans le désordre ont une unité d'émission qui bloque tout le pipeline dès qu'une µop ne peut pas être émise. Pour limiter l'impact de ce blocage, quelques rares processeurs incorporent une '''file de micro-opération''', une mémoire FIFO qui met en attente les µops. Vu que c'est une mémoire FIFO, les µops sont émises dans l'ordre, à savoir l'ordre d'ajout, dans l'ordre de décodage. Le schéma ci-dessous illustre une telle file d'attente couplée à un ''scoreboard''. Sur le principe, l'exécution dans le désordre améliore la file de µops sur un point : ce n'est plus une mémoire FIFO. Les µops sont insérées dans l'ordre, mais peuvent sortir dans le désordre (être émises dans le désordre). La file de µops devient alors une '''fenêtre d'instruction''', terme traduit directement de l'anglais ''instruction Window''. Terme assez trompeur, car elles mettent en attente des µops, pas des instructions. Elles peuvent émettre des µops dans le désordre, ce qui fait que si une µop bloque le pipeline, les µops suivantes peuvent être émises. Si je commence le paragraphe précédent par "sur le principe", c'est car certaines techniques d'OOO utilisent des files de µops normales. Il est par exemple possible d'utiliser une file de µops avec une fenêtre d'instruction, plusieurs files de µops, plusieurs fenêtres d'instructions avec une file de µops annexe, etc. Dasn les grandes lignes, il existe dans les grandes lignes 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! File de µops améliorée |- ! Une seule "file de µops" | ''Scoreboard'' | Fenêtre d'instruction centralisée |- ! Plusieurs "file de µops" | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | Fenêtre d'instruction décentralisée |} ===La fenêtre d'instruction centralisée=== L'implémentation la plus simple de l'OOO utilise une unique '''fenêtre d'instruction'''. Les instructions décodées sont accumulées dans la fenêtre d'instruction, où elles attendent que leurs opérandes soient disponibles. La fenêtre d'instruction sert donc de file d'attente. Mais elle contient aussi une unité d'émission, qui détecte quelles µops sont prêtes à être émises. L'unité d'émission et la fenêtre d'instruction sont fusionnées ensemble, elles forment un seul circuit. Mais nous allons dire qu'elles sont conceptuellement séparées pour le moment. A chaque cycle, l'unité d'émission consulte la fenêtre d'instruction pour voir quelles µops peuvent s'exécuter, lesquelles ont leur opérandes de disponibles. La fenêtre d'instruction doit spécialement être conçue pour, c'est une sorte de mémoire associative très complexe, comme on le verra dans ce qui suit. [[File:OOO Issue.png|centre|vignette|upright=2.5|Exécution dans le désordre avec une fenêtre d'instruction]] Une fois qu'une µop sort du décodeur d'instructions, elle est ajoutée en parallèle dans la fenêtre d'instruction et le ROB. La raison est que les µops quittent la fenêtre d'instruction dans le désordre, et qu'elles doivent être remises en ordre par la suite. Le ROB s'occupe de cette remise en ordre, mais il a besoin de savoir dans quel ordre les µops sont censées être, et cet ordre est celui du décodage. Aussi, pour remplir le ROB, la seule opportunité est en sortie de l'unité de décodage. Dans le cas où une instruction est décodée en plusieurs micro-opérations, elles sont toutes insérées en même temps dans la fenêtre d'instruction et le ROB, en tenant compte de leur ordre. [[File:Fenêtre d'instruction.png|centre|vignette|upright=2|Fenêtre d'instruction.]] Les micro-opérations mémoire sont à part des autres, pour diverses raisons. Une de ces raisons est que les dépendances de données sont classées en deux types : les dépendances de registre et les dépendances d'adresse. Et les deux sont fondamentalement différentes. Autant on peut détecter les dépendances de registre lors de l'émission, autant c'est plus compliqué avec les dépendances d'adresse. De plus, rappelons que si les lectures peuvent s'exécuter dans le désordre, les écritures doivent s'exécuter dans l'ordre, ou du moins en donner l'illusion. Pour cela, le processeur remet les écritures dans l'ordre avec une sorte de mini-ROB intégré à l'unité mémoire, appelée la file d'écriture. Elle complémente le ROB, qui lui ne gère que les écritures dans les registres, mais les deux collaborent. La file d'écriture envoie une écriture à la mémoire RAM quand le ROB lui dit que c'est bon, les instructions précédentes sont terminées ''dans l'ordre du programme''. Les processeurs modernes ajoutent des techniques d'exécution dans le désordre des accès mémoire, mais nous les verrons dans un chapitre dédié. Elles permettent d'utiliser une fenêtre d'instruction unique, qui mémorise aussi les µops mémoire. Si elles sont mises en place, l'unité mémoire n'a pas besoin de file de µops séparée. L'idée est que les dépendances de registre sont traitées par la fenêtre d'instruction, mais que l'unité mémoire gére les dépendances d'adresse. Les dépendances d'adresse sont gérées par des techniques de ''désambiguation mémoire'', qui auront droit à un chapitre dédié. [[File:Processeur avec exécution dans le désodre des accès mémoire.png|centre|vignette|upright=2|Processeur avec exécution dans le désodre des accès mémoire]] Les processeurs assez anciens n'autorisaient pas d'exécution dans le désordre des accès mémoire. Concrétement, les accs mémoire devaient se faire dans l'ordre, mais les autres µops pouvaient être exécutées dans le désordre. Il s'agit donc d'un ordre entre µops mémoire, pas entre µops mémoire et autres µops. Les µops entières et flottantes pouvaient être exécutées avant une µops mémoire qui est avant elle dans l'ordre du programme, ce n'est pas un problème. Pour garantir l'ordre desd µops mémoire, l'unité mémoire est précédée par une file de micro-opérations séparée, pour forcer l'exécution dans l'ordre des accès mémoire. De plus, les µops mémoire ne peuvent pas utiliser la fenêtre d'instruction. Dit autrement, la fenêtre d'instruction ne mémorise pas de µops mémoire. Après le décodage, les µops sont réparties soit dans la file de µops mémoire, soit dans la fenêtre d'instruction. Le décodeur classe les µops suivant que ce sont des µops mémoire ou non, et les envoient à la bonne destination. Dans ce chapitre, on supposera que c'est cette solution qui est utilisée. [[File:Processeur avec émission dans l'ordre des accès mémoire.png|centre|vignette|upright=2|Processeur avec émission dans l'ordre des accès mémoire]] La solution précédente revient à scinder la fenêtre d'instruction en deux : une file de µops pour les µops mémoire, une fenêtre d'instruction pour les autres µops. Et cette scission peut aller plus loin, à savoir qu'on peut scinder une fenêtre d'instruction encore et encore. Ce qui nous amène à la section suivante. ===Les fenêtres d'instruction décentralisées=== Nous venons de voir qu'il est possible de scinder la fenêtre d'instruction en une fenêtre d'instruction pour les µops mémoire (simplifiée en une file de µops classique), et une autre pour les autres µops. Sachez qu'il est possible d'aller plus loin, par exemple en séparant la fenêtre d'instruction en une fenêtre spécialisée dans les µops flottantes et une autre pour les µops entières. Et ce n'est là qu'un exemple parmi de nombreuses autres possibilités. Pour faire la différence avec une fenêtre d'instruction unique, nous allons parler de fenêtre d'instruction centralisée s'il n'y en a qu'une, de '''fenêtre d'instruction décentralisée''' s'il y en a plusieurs. Il est possible d'associer chaque fenêtre d'instruction à un type précis de µops. Par exemple, avec une fenêtre d'instruction pour les µops de calcul entières, une autre pour les µops flottantes, une autre pour les µops mémoire. Il s'agit d'un choix simple et efficace, mais quelques processeurs font autrement, pour répondre à des contraintes très diverses. [[File:Processeur avec des fenêtres d'instruction décentralisées.png|centre|vignette|upright=2|Processeur avec des fenêtres d'instruction décentralisées]] Reste à scinder la fenêtre d'instruction pour trier les µops suivant leur type. Si le processeur exécute les accès mémoire dans l'ordre, la méthode la plus simple utilise une fenêtre d'instruction pour les opérations flottantes et une autre pour les autres µops (µops entières et parfois mémoire avec). L'avantage est que cela simplifie grandement le processeur. Les flottants sont gérés à part des entiers. Ils ont leurs propres registres, des FPU séparées des ALU entières, bref : la séparation est complète. Utiliser une fenêtre d'instruction séparée va dans ce sens. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Il est possible de faire pareil sur les processeurs avec exécution dans le désordre des accès mémoire. Par exemple : les processeurs Intel de microarchitecture Skylake utilisent une fenêtre d'instruction pour les opérations entières/flottantes, et une fenêtre d'instruction séparée pour les µops mémoire. Un avantage est que les deux fenêtres d'instructions sont plus spécialisées, ce qui entraine des économies de circuit. Les opérations entières/flottantes ont besoin de deux registres pour les opérandes et d'un autre résultat, alors que les µops mémoire n'ont besoin que de deux registres maximum. En utilisant une fenêtre d'instruction unique, chaque entrée doit mémoriser l'opcode et trois registres, dont un est inutilisé pour les µops mémoire et les branchements. En utilisant des fenêtres d’instructions séparées, celle pour les µops entières/flottantes a trois registres par entrée, contre seulement deux registres par entrée pour celle des µops mémoire. Un cas extrême est celui où chaque ALU/FPU a sa propre fenêtre d'instruction. Nous parlerons alors de '''fenêtres d'instruction totalement décentralisées'''. Par exemple, il y a une fenêtre d'instruction pour l'ALU entière, une autre pour le multiplieur entier, une autre pour le ''barrel shifter'', une autre pour l'unité mémoire, une autre pour l'unitéé de branchements, une autre pour l'additionneur flottant, une dernière pour le multiplier flottant, etc. Un exemple historique est celui de la FPU de l'IBM 360 modèle 90. Elle disposait d'un additionneur flottant, d'un multiplieur flottant, et d'une unité mémoire pour les lectures/écritures flottantes. Les trois unités avaient leur propre fenêtre d'instruction. Les processeurs AMD utilisent beaucoup cette technique, contrairement à Intel qui préfère utiliser des fenêtres centralisées sur les anciens processeurs, deux ou trois fenêtres sur les processeurs récents (2020 et plus). Les processeurs AMD utilisaient précisément une fenêtre d'instruction par ALU entière, alors que les FPUs partagent une fenêtre d’instructions flottantes unique. Mais nous verrons cela en détail dans le chapitre sur les processeurs superscalaires x86. Un point important est qu'avec des fenêtres d'instruction décentralisées, l'émission est découpée en deux étages. La première étape envoie une µops vers la fenêtre d'instruction adéquate, la seconde émet la µops depuis la fenêtre d'instruction quand ses opérandes sont prêtes. La première est l'étage de '''''dispatch''''' qui envoie l'instruction dans la fenêtre d’instruction adéquate, selon que c'est une instruction flottante, entière, autre. La seconde est l'étage de '''''scheduling''''', qui gère la disponibilité des opérandes et des unités de calcul. La µop émise est ajoutée au tampon de réordonnancement, s'il existe, lors de l'étape de ''dispatch''. ===L'usage de plusieurs files d'instruction=== Une dernière méthode d'OOO utilise plusieurs files de micro-opération. L'idée est qu'une fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement une file de micro-opération pour les opérations entières, une autre pour les opérations flottantes, une autre pour les accès mémoire. D'autres processeurs utilisent une file pour les accès mémoire et une autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. La présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que la technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si une dépendance bloque une FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans une autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer la disponibilité des registres. Quand un registre est lu ou écrit par une instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. La logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : une pour les instructions d'accès mémoire et une autre pour les autres instructions. Si jamais une instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de la lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'une est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est la file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. ===Avantages et inconvénients de chaque implémentation=== Pour résumer, on a le choix entre une grosse fenêtre d'instruction généraliste et plusieurs fenêtres spécialisées. Le choix entre les deux est un compromis entre économie de circuits et flexibilité. Avec une fenêtre décentralisée, il arrive qu'une fenêtre d'instruction soit remplie, alors que les autres sont sous-utilisées, voire vides. Pour comprendre pourquoi, comparons une fenêtre d'instruction unique, avec une fenêtre décentralisée séparant µops entières et flottantes. La fenêtre centralisée dispose de 64 entrées, la décentralisée a 32 entrées pour chaque fenêtre d'instruction. La fenêtre décentralisée peut mémoriser au maximum 32 µops entières et 32 *ops flottantes. Par contre, la fenêtre centralisée peut mémoriser 64 µops tout court. Si le programme exécuté n'utilise pas de nombres flottants, la différence devient flagrante. La fenêtre décentralisée sera limitée ) 32 µops, alors que la centralisée pourra mémoriser le double. Les performances seront donc meilleurs avec la fenêtre centralisée. Et au-delà de ça, la fenêtre décentralisée de l'exemple est utilisée de manière optimale si la moitié des µops sont des µops entières, et l'autre moitié des µops flottantes. Alors que la fenêtre centralisée se moque de la répartition entre µops entières et flottantes. Une subtilité est que le cout en transistors d'une fenêtre d'instruction n'est pas proportionnel au nombre de µops qu'elle peut mémoriser. Par exemple, si je compare une fenêtre d'instruction de 32 entrées (32 µops max), elle n'utilise pas deux fois plus transistors qu'une fenêtre de 16 entrées. Le cout en circuit n'est pas deux fois plus élevé, mais est approximativement 4 fois plus élevé. Le cout est presque quadratique, à savoir qu'il est proportionnel au carré du nombre d'entrées. Et il en est de même avec la performance, pour des raisons qu'on expliquera plus bas. Les fenêtres décentralisées utilisent plusieurs fenêtres d'instruction de "petite taille", donc plus rapides, économes en circuits et économes en énergie. Le compromis n'est donc pas entre une fenêtre centralisée à 64 entrées versus deux fenêtres de 32 entrées. Le compromis en pratique est entre une fenêtre centralisée de 64 entrées versus 3 fenêtres de 32 entrées. Un exemple pratique est celui de la microarchitecture ''Skylake'' d'Intel. Intel est passé d'une fenêtre centralisée pre-''Skylake'' à deux fenêtres décentralisées sur ''Skylake'',. Le nombre d'entrée était globalement le même entre les deux, même si l'évolution de la finesse de gravure entre les deux biaise un peu les résultats. Un avantage des fenêtres décentralisées est qu'il est possible de démarrer l'exécution de plusieurs µops simultanément : une µops par fenêtre d'instruction. Le fait est que deux fenêtres d'instructions différentes émettent leurs µops sans se synchroniser avec les autres. Deux fenêtres d'instruction peuvent donc émettre chacune une µops, ce qui fait deux µops émises lors du même cycle. Cela permet d'exécuter en même temps deux ou trois instructions 1-cycle, comme des additions, soustractions, décalages, etc. Il devient par exemple possible d'émettre une µop entière en même temps qu'une µop flottante, si les µops entières ont une fenêtre séparée de celle des µops flottantes. Il est maintenant temps de voir en quoi sont faites les fenêtres d’instruction, qu'elles soient centralisées ou décentralisées. Nous allons aussi voir quelle est la logique d'émission associée. ==L'implémentation d'une fenêtre d'instruction : généralités== Une fenêtre d'instruction est une mémoire qui mémorise des micro-opérations. Elle est cependant plus complexe qu'une mémoire RAM ou qu'une FIFO et ressemble un petit peu à une mémoire cache. Elle dispose d'un port d'écriture et d'un port de lecture, au minimum. Le port d'écriture permet à l'unité de décodage d'insérer une micro-opération dedans, d'ajouter la micro-opération qui vient d'être décodée. Si une instruction machine est décodée en plusieurs micro-opération, deux possibilités. La première est de les insérer un par un, ce qui fait qu'on peut se contenter d'un seul port d'écriture. L'autre possibilité est de les ajouter en même temps, ce qui demande plusieurs ports d'écriture. Le port de lecture sert à émettre une instruction. On part du principe que la fenêtre d'instruction ne peut émettre qu'une seule instruction à la fois, car les processeurs que nous avons vu précédemment sont de ce type. Mais nous verrons dans quelques chapitre qu'il existe des processeurs dits superscalaires, qui sont capables d'émettre plusieurs instructions par cycle. Dans ce cas, la fenêtre d'instruction a un seul port de lecture. Un processeur superscalaire, quant à lui, doit avoir un port de lecture par unité de calcul, ce qui fait beaucoup plus. ===Les entrées d'une fenêtre d’instruction=== Les fenêtres d'instruction sont composées d''''entrées''', des mots mémoire qui stockent une instruction. Une instruction réserve une entrée après son décodage et la libère dès qu'elle est envoyée aux unités de calcul. Une entrée contient l'opcode (les signaux de commande à envoyer à l'ALU), le registre de destination du résultat, les registres de chaque opérande, et éventuellement des signaux de commande en plus. De plus, chaque opérande est couplée à un bit de disponibilité, qui indique si elle est disponible. Quand un opérande est écrit dans les registres, le bit de présence correspondant est mis à jour. Enfin, chaque entrée possède un bit ''empty'' qui indique si elle est vide, cette information étant utile pour réserver des entrées. [[File:Entrée d'une station de réservation - sans les tags.png|centre|vignette|upright=3|Entrée d'une fenêtre d'instruction]] Nous verrons dans quelques chapitres que certaines fenêtres d'instruction sont capables de mémoriser les opérandes des instructions. De telles fenêtres d'instruction seront appelées, dans ce cours, des '''stations de réservation'''. Les entrées des stations de réservation sont assez semblables à celle des fenêtres d'instruction, à un détail près : les opérandes de l'instruction sont enregistrées directement dans des champs séparés. Il y a deux champs, un par opérande, pour stocker l'opérande elle-même, lue depuis les registres ou obtenue via le réseau de contournement. Notons que les champs pour les opérandes viennent en plus des champs pour les noms de registres, encore que les deux peuvent être fusionnés si on veut optimiser le tout. [[File:Entrée d'une station de réservation.png|centre|vignette|upright=3|Entrée d'une station de réservation.]] Précisons que la terminologie n'est pas très fiable. Les termes "fenêtre d'instruction" et "station de réservation" ne regroupent pas du tout la même chose d'un papier de recherche à l'autre, d'un bouquin à l'autre, d'un chercheur à l'autre, d'un ingénieur à l'autre, d'un professeur à l'autre. Le terme initial vient pourtant de l'article original sur l'algorithme de Tomasulo, où il désignait une fenêtre d'instruction associée à une unité de calcul précise. Mais le terme a ensuite été réutilisé, ce qui fait que certains processeurs avec plusieurs unités de calcul sont décrit comme ayant une unique station de réservation. En bref : c'est le bazar ! Mais nous en reparlerons dans le chapitre sur le renommage de registres, car c'est la place idéale pour les aborder. Toujours est-il que j'ai fait le choix de confondre les concepts de fenêtre d'instruction et de station de réservation avec les concepts de '''lecture avant émission''' et de '''lecture après émission'''. La différence entre les deux est que les registres sont lus après émission avec une fenêtre d'instruction, avant avec des stations de réservation. Dans le cas "avant émission", les opérandes sont mémorisées dans la station de réservation. Et cette différence a une influence sur le pipeline du processeur, le banc de registres et tout ce qui s'en suit. Un désavantage de la lecture avant émission est qu'il faut stocker les opérandes après lecture, ici dans les stations de réservation. Mais un avantage est que le banc de registre a besoin de moins de ports de lecture, car une bonne partie des opérandes sont fournies par le système de contournement. Nous verrons cela dans le détail dans le chapitre sur les processeurs superscalaires. Il a été proposé de fusionner le tampon de ré-ordonnancement avec la fenêtre d'instruction dans une structure unique. La méthode a notamment été utilisée sur les processeurs d'architecture K6 d'AMD. Le tout donnait une structure appelée le '''DRIS''' (''deferred scheduling register renaming instruction shelf''). La différence avec une fenêtre d’instruction normale est que les entrées sont libérée non pas quand l'instruction est exécutée/émise, mais quand elle termine son exécution et quitte le ROB. La fenêtre d'instruction doit alors incorporer des bits pour savoir si telle entrée a émis sont instruction ou non. ===La logique d'éveil et de sélection=== Dans le cas qui va suivre, on suppose que le processeur ne peut émettre qu'une instruction à la fois. Chaque cycle, une instruction est sélectionnée et est envoyée dans le chemin de données, soit à une ALU, soit à une unité d'accès mémoire. La sélection d'une instruction est effectuée par l'unité d'émission, qui est aussi appelée le '''''scheduler'''''. Elle gère la disponibilité des opérandes et la disponibilité des unités de calcul adéquate. Le choix de l'instruction émise doit être le plus pertinent possible, pour des raisons de performances. Pour le premier point, l'unité d'émission détermine quelles instructions sont candidates pour l'émission. Les ''instructions candidates'' sont celles dont tous les opérandes sont prêts. Le processeur contient un circuit qui détecte les instructions candidates : la '''logique d’éveil''' (''wake-up logic''). Une fois que la logique d'éveil a fait son travail, une instruction est choisie pour s’exécuter en fonction de la disponibilité des unités de calcul adéquates. Ce rôle est dévolu à un circuit qu'on appelle la '''logique de sélection''', ou ''select logic''. [[File:Fonctionnement complet de la logique d’émission.jpg|centre|vignette|upright=1.5|Fonctionnement complet de la logique d’émission.]] La logique de sélection doit gérer le fait que les unités de calcul du processeur ne sont pas toutes identiques. Déjà, un processeur a généralement des unités séparées pour les instructions entières et flottantes, des unités spécialisées dans les accès mémoire, parfois des unités spécialisées pour les branchements. Une instruction doit être attribuée à la bonne unité de calcul, on ne doit pas envoyer une instruction entière dans une unité de calcul flottante. De plus, parmi les unités de calcul entières, toutes ne sont pas identiques. Par exemple, il est fréquent d'avoir plusieurs unités de calcul spécialisées dans les opérations simples (additions, soustractions, opérations logiques) avec une unité pour les multiplications/divisions séparées, parfois une unité spécialisée pour les décalages/rotations, etc. Là encore, allouer la bonne instruction à la bonne ALU est complexe. Plus les unités de calcul sont hétérogènes, plus la logique de sélection est compliquée. Les logiques d'éveil comme de sélection sont assez complexes. Comme on le verra plus bas, la logique de sélection la plus simple, qui gère une seule unité de calcul, est basée sur un encodeur à priorité couplé à d'autres circuits. Et pour gérer plusieurs ALUs, il faut mettre des encodeurs en cascade. Le résultat est que même en prenant une logique de sélection simple, elle sera assez lente et gourmande en circuits. Aussi, la logique de sélection met souvent un cycle d'horloge entier pour faire son travail, elle a son propre étage de pipeline attribué. La logique d'éveil est dans le même cas, ce qui fait qu'émettre une micro-opération demande deux cycles d'horloge. Le défaut est que cela rajoute des cycles d'horloges entre la fenêtre d'instruction et l'ALU, ce qui complique la gestion du pipeline. Ces cycles de retard sont à prendre en compte au moment d'émettre les instructions, les ''scheduler'' doit en tenir compte pour des performances optimales. Sans tenir compte de ces cycles de retard, les instructions arrivent en retard de quelques cycles à l'ALU, cycles de retard durant lesquels l'ALU n'a pas fait de calcul et a été sous-utilisée, sans compter que le système de contournement n'est pas utilisé au mieux. Et le problème est encore plus important sur les processeur avec des stations de réservation, qui utilisent la "lecture après émission" : cela rajoute un cycle d'horloge en plus, un temps de retard en plus. ===La logique d'éveil : l'émission anticipée=== La logique d'éveil doit tenir compte du fait qu'il y a plusieurs étages entre l'émission et l'exécution sur une unité de calcul. Par exemple, un processeur a souvent entre un et à cinq étages entre la file d'attente et les unités de calcul. Il faut lire les registres, gérer le contournement, et cela peut prendre quelques cycles d'horloge. Sur le Pentium 4, on trouve 6 étages entre la fenêtre d’instruction et l'entrée de l'ALU. Si les micro-opérations sont émises quand les opérandes sont disponibles, il y aura un délai de quelques cycles avant qu'elles atteignent l'ALU. Alors qu'idéalement, on souhaiterait que la micro-opération atteigne l'ALU dès que ses opérandes sont disponibles, pour profiter des techniques de contournement. Pour cela, la logique d'éveil émet les instructions quelques cycles en avance pour qu'elles arrivent au bon moment. Il s'agit d'une technique d''''émission anticipée''', dont nous avions parlé dans le chapitre sur le contournement. : Il faut noter que le problème se pose plus avec des fenêtres d'instruction qu'avec des stations de réservation. Les premières ont un étage en plus entre émission et ALU, vu qu'il faut lire des registres après l'émission. L'émission anticipée demande d'émettre un signal d'éveil en avance de quelques cycles, pile au bon moment. Par exemples, si on a deux étages entre l'ALU et l'unité d'émission, le signal de réveil sera généré deux cycles avant que le résultat soit effectivement calculé. L'implémentation varie, mais deux solutions sont possibles. La première est de générer le signal d'éveil dans l'ALU, ce qui n'a de sens que pour les opérations comme les multiplications ou les divisions, qui prennent plusieurs cycles. Une autre technique génère le signal de réveil dans une structure centralisée, spécialisée dans la génération des signaux d'éveil. L'unité de composée d'un registre à décalage par registre. Imaginons qu'une instruction est émise, que cette instruction mette N cycles à s'exécuter, et qu'elle écrive dans un registre de destination. L'unité sélectionne alors le registre à décalage associé au registre de destination, et met le bit numéro N à 1. Le registre décalé d'un cran à chaque cycle. Quand le bit sortant est un 1, alors le signal de validité pour l'opérande est généré. L'émission anticipée marche bien si l'instruction a une durée fixe, connue à l'avance. Et autant c'est le cas pour les instructions arithmétiques et logiques, autant ce n'est pas le cas pour les accès mémoire. Les accès mémoire ont une latence variable : quelques cycles pour un succès de cache, plusieurs dizaines de cycles pour un défaut de cache L1, pas loin de la centaine pour un défaut de cache L2, etc. Et cela pose des problèmes pour l'émission anticipée. L'émission en avance pour les accès mémoire est purement spéculative : le processeur émet des instructions en supposant que la lecture entrainera un succès de cache, quitte à annuler l'instruction en cas de défaut de cache. Mais faire ainsi demande non seulement d'annuler les instructions émises en avance, mais aussi de ne pas retirer les instructions émises en avance de la fenêtre d'instruction. Elles sont émises, mais une copie de sauvegarde est conservée dans la fenêtre d'instruction. Si le processeur détecte un défaut de cache, il peut alors ré-exécuter l'instruction. S'il détecte un succès de cache, les instructions lecture-dépendante sont retirées de la fenêtre d'instruction, la copie de sauvegarde est devenue inutile et est donc jetée. ===La logique de sélection : âge ou position ?=== La logique de sélection est primordiale pour de bonnes performances. Il existe deux méthodes principales pour sélectionner l'instruction à exécuter. La première est la plus simple : elle se base sur lé numéro de l'entrée. En effet, une fenêtre d'instruction est avant tout une sorte de mémoire, un mix entre mémoire associative, mémoire RAM, et FIFO. Et chaque entrée a un numéro, une adresse mémoire. Nous parlerons de numéro dans ce qui suit, car ce sera plus simple, le terme d'adresse mémoire étant peut-être un peu exagéré dans le contexte des fenêtres d'instruction. Toujours est-il que la fenêtre d'instruction est adressable dans le sens où on peut lui envoyer le numéro de l'entrée voulue, et la fenêtre d’instruction renvoie le contenu de l'entrée sur son port de lecture. Et c'est ce que fait la logique de sélection : elle génère le numéro de l'entrée à lire. Le numéro est alors envoyé sur l'entrée d'adresse de la fenêtre d’instruction, et elle fournit la micro-opération associée sur son port de lecture, son '''port d'émission'''. La première méthode de sélection, donc. Elle est basée sur sur le numéro de l'entrée. Si plusieurs entrées sont éveillées, la logique de sélection prend celle avec le plus petit numéro. Elle porte le nom de '''sélection par position''', sous-entendu position dans la fenêtre d'instruction. Vous l'avez peut-être deviné, mais la logique de sélection est alors un encodeur à priorité. Le circuit de sélection ne se résume donc pas seulement à un encodeur à priorité, mais c'est le circuit central. L'avantage d'une telle méthode de sélection est qu'elle est simple à implémenter : un encodeur à priorité est un circuit connu, facile à implémenter. Mais on remarque un défaut : un encodeur est un circuit assez rapide, mais qui utilise beaucoup de transistors, beaucoup de portes logiques, surtout si on veut qu'il soit rapide. Ce qui explique que la logique de sélection ait son propre étage de pipeline rien que pour elle. La seconde méthode s'appelle la '''sélection par âge''', au nom assez transparent. L'idée est de privilégier l'émission de l'instruction la plus ancienne. Elle demande que la fenêtre d'instruction trie les micro-opérations par ordre d'insertion dans la fenêtre d'instruction, ce qui en fait une pseudo-FIFO. Le tri est partiel, car les instructions peuvent sortir de la fenêtre d’instruction à tout moment. Compacter la fenêtre d'instruction, à savoir regrouper toutes les entrées valides est une idée, mais elle est compliquée à implémenter. Aussi, elles préfèrent encoder des informations sur l'ordre d'émission dans chaque entrée. L'encodeur à priorité doit alors travailler non pas sur des nombres entiers liés à l'ordre d'insertion dans la pseudo-FIFO. Elle est encore plus gourmande en circuits que la méthode précédente. Les processeurs haute performance utilisent souvent des méthodes hybrides. Par exemple, les processeurs AMD de microarchitecture Bulldozer utilisaient une méthode intermédiaire. Ils utilisaient une fenêtre d'instruction couplée à un encodeur à priorité pour la sélection par position, mais complémentaient le tout avec une unité qui mémorisait l'instruction la plus ancienne dans la fenêtre d’instruction. Le mécanisme de sélection par âge était utilisé en priorité. Mais si l'instruction la plus ancienne n'était pas prête, le processeur basculait sur le mécanisme de sélection par position. ===La compaction des fenêtres d'instruction=== À chaque cycle, les instructions décodées sont ajoutées dans la fenêtre d'instruction, dans des entrées vides. Vu que les instructions quittent celle-ci dans le désordre, ces vides sont dispersés dans la fenêtre d'instruction, ce qui pose problème pour déterminer où placer les nouvelles instructions. La solution la plus triviale consiste à conserver une liste des vides, mise à jour à chaque insertion ou émission d'instruction. Une autre solution consiste à éliminer les vides en compactant la fenêtre d'instruction à chaque cycle d'horloge. Des circuits se chargent de détecter les vides et de regrouper les instructions en un unique bloc. Il faut signaler que certaines processeurs arrivent à se passer de cette étape de compactage, mais au prix de fenêtres d'instruction nettement plus complexes. Autre problème : quand il faut choisir quelle instruction émettre, il y a toujours plusieurs candidats. Si on choisit mal, des instructions restent en attente trop longtemps parce que d'autres instructions plus jeunes leur passent devant. Pour éviter cela, les instructions les plus vielles, les plus anciennes, sont prioritaires. Pour cela, on peut utiliser une FIFO un peu spéciale pour la fenêtre d'instruction. Si les ajouts d'instruction se font dans l'ordre, les instructions ne quittent pas forcément la fenêtre d'instruction dans l'ordre imposé par une FIFO : les instructions restent triées dans leur ordre d'ajout, même s'il y a des vides entre elles. Dans ces condition, il est préférable que le compactage conserve l'ordre FIFO des instructions. Dans ces conditions, l'instruction la plus ancienne est celle qui est située à l'adresse la plus faible : le circuit de sélection peut donc être fabriqué avec des encodeurs, et est relativement simple. ==Les fenêtres d'instruction basées sur une matrice de dépendances== L'implémentation la plus simple étend le fonctionnement d'un pipeline dynamique usuel. Rappelez-vous le chapitre sur les pipeline dynamiques. Nous avions vu que de tels pipelines émettaient une instruction par cycle, quitte à émettre des bulles de pipeline en cas de dépendance bloquante. Et il est possible d'améliorer leur unité d'émission pour qu'elle soit compatible avec l'exécution dans le désordre. ===Rappels sur le registre de réservation/disponibilité=== L'émission d'une instruction est gouvernée par un ''registre de réservation'' qui indique quels registres sont réservés par une instruction, et ceux qui sont libres. Un registre réservé est un registre qui sera écrit par une instruction en cours d'exécution, mais qui n'a pas encore écrit son résultat. Les instructions candidates doivent avoir leurs opérandes dans des registres libres. Sinon, c'est signe que leurs opérandes sont réservées en écriture, donc pas encore écrites, donc pas disponibles. Si une instruction candidate veut lire ce registre, c'est signe qu'il y a une dépendance RAW : elle veut lire un registre réservé, qui est destiné à être écrit par une instruction en vol. Si elle veut écrire, c'est signe qu'elle veut écrire dans un registre où une autre instruction veut écrire : c'est une dépendance WAW. Dans les deux cas, l'instruction n'est pas émise. Le registre de réservation encode les registres réservés comme suit : chaque bit est associé à un registre. Le bit numéro 0 est associé au registre numéro 0, le bit numéro 1 au registre numéro 1, etc. Là, En clair, les numéros de registres réservés sont encodés en représentation non pas binaire, mais en représentation ''one-hot'' (vue au premier chapitre). {|class="wikitable" |+ Registre de réservation |- ! Registre 7 !! Registre 6 !! Registre 5 !! Registre 4 !! Registre 3 !! Registre 2 !! Registre 1 !! Registre 0 |- | 0 || 0 || 1 || 0 || 0 || 1 || 0 || 0 |} Avant d'émettre une instruction, l'unité d'émission extrait les registres opérande/destination et les convertis dans la même représentation que le registre de réservation, à savoir en représentation ''one-hot''. Le circuit de traduction binaire vers ''one-hot'' est, pour rappel, un simple décodeur. Puis, on fait un OU logique entre les sorties des décodeurs. Le résultat est un masque qui indique quels registres sont lus par l'instruction, encodé en représentation ''one-hot''. Appelons-le le '''masque d'opérandes'''. Le masque est alors comparé au registre de réservation pour vérifier si l'instruction peut être émise. [[File:Unité d'émission simple, dans l'ordre.png|centre|vignette|upright=2|Unité d'émission simple, dans l'ordre]] Si l'émission est autorisée, le registres de réservation est là aussi mis à jour. Le registre de réservation est aussi mis à jour dès qu'une instruction enregistre son résultat dans les registres, ou alors dès qu'il est disponible pour le contournement. Le bit associé au registre repasse alors à 0 (ou à 1). Sans contournement, la mise à jour se fait alors à la toute fin de l'instruction, quand elle se termine, lors de la dernière étape d'enregistrement, à la fin de son pipeline. Avec, elle se fait quand l'instruction quitte l'unité de calcul. ===L'extension à l'exécution dans le désordre : l'éveil par matrice de bits=== La différence entre un pipeline dynamique et l'exécution dans le désordre est que l'on passe d'une instruction à émettre à plusieurs. Plusieurs instructions sont mises en attente dans une fenêtre d’instruction, et y attendent leur tour. L'idée est alors d'envoyer le registre de disponibilité à toutes les entrées, à toutes les instructions en attente. Ainsi, on sait quelles sont les instructions qui peuvent s'exécuter et celles qui ne le peuvent pas. L'implémentation est assez simple, elle ressemble beaucoup à l'implémentation d'un pipeline dynamique simple, si ce n'est que des circuits sont dupliqués. L'implémentation utilise des fenêtres d'instruction légèrement différentes de celles introduites plus haut. Elles n'utilisent notamment pas de bits de disponibilité, mais autre chose. Lorsqu'une instruction est ajoutée à la fenêtre d'instruction, le masque de disponibilité des opérandes est stocké dans la fenêtre d'instruction. A chaque cycle, le registre de disponibilité est envoyée à toutes les entrées, et est comparé avec tous les masques de disponibilité des opérandes. Si une comparaison renvoie un 1, alors l'instruction de l'entrée est une instruction candidate à l'émission. [[File:Unité d'émission dans le désordre basée sur un registre de disponibilité.png|centre|vignette|upright=2.5|Unité d'émission dans le désordre basée sur un registre de disponibilité]] L'ensemble est implémenté avec l'aide d'une '''matrice de bits''', où chaque ligne correspond à une entrée et chaque colonne à un registre. À chaque croisement entre une ligne et une colonne, on trouve un bit. Si le bit de la ligne n et de la colonne m est à 1, cela veut dire : l'instruction dans l'entrée n a besoin de lire le registre m. S’il est à 0, alors cela veut dire que l'instruction stockée dans la ligne n n'a pas besoin de la donnée dans le registre m. [[File:Planificateur à matrice de bits.jpg|centre|vignette|upright=2|Planificateur à matrice de bits.]] Lorsqu'une instruction réserve une entrée, elle initialise la ligne en fonction des registres qu'elle souhaite lire. Pour vérifier si une instruction a ses opérandes prêts, le processeur compare le registre de disponibilité à la ligne associée à l'instruction/entrée. A chaque intersection ligne-colonne, se trouve un comparateur de 1 bit, qui détecte si le registre est demandé et disponible. Les résultats de cette porte sont ensuite envoyés à une porte ET, qui fait le gros du travail. [[File:Logique de détection de la disponibilité d'une instruction.jpg|centre|vignette|upright=2|Logique de détection de la disponibilité d'une instruction.]] ==Les fenêtres d'instruction basées sur une mémoire associative== Les processeurs modernes utilisent une mémoire associative pour la fenêtre d'instruction. Les mémoires associatives ont été abordées il y a quelques chapitres, mais faisons quelques rappels. Les mémoires associatives servent à accélérer la recherche de données dans un ensemble. Or, une fenêtre d'instruction vérifie régulièrement si chaque entrée est prête. Il s'agit d'un processus de recherche d'une instruction qui respecte une condition bien précise dans la mémoire, ce qui fait que les mémoires associatives sont donc tout indiquées. Comme vous le savez, les signaux de commande d'une instruction sont propagés avec celle-ci dans le pipeline, le nom du registre de destination ne faisant pas exception. Le nom de registre est envoyé à la fenêtre d'instruction lors de l'écriture du résultat dans les registres. S'il y a correspondance, l'opérande est disponible et son bit de disponibilité est mis à 1. On peut adapter cette méthode pour tenir compte du contournement assez simplement. [[File:Détection des dépendances par propagation du registre de destination.png|centre|vignette|upright=2|Détection des dépendances par propagation du registre de destination.]] En conséquence, le circuit de détection des dépendances est constitué d'un grand nombre de comparateurs : un par champ « nom de registre » dans chaque entrée. La logique d'éveil/''wake up'' regroupe tous les comparateurs, la logique de sélection est un circuit situé en-dehors de la mémoire associative. Les entrées sont dans la mémoire associative elle-même. [[File:Gestion des bits de validité.png|centre|vignette|upright=2|Gestion des bits de validité.]] L'implémentation la plus simple est celle du schéma précédent, où on utilise une mémoire associative unique. Une version plus élaborée sépare la fenêtre d'instruction en deux parties : une mémoire qui mémorise les registres des opérandes, une autre mémoire pour le reste. La mémoire pour les registres opérandes est la mémoire associative proprement dite, c'est elle qui est associées aux comparateurs, à la logique de ''wake-up''/réveil, etc. Par contre, l'autre mémoire est une mémoire RAM simplifiée, qui mémorise les informations qui n'ont pas besoin des comparateurs. L'opcode de l'instruction est là-dedans, par exemple. ===Les optimisations de la consommation d'énergie : la désactivation des portions inutilisées=== Le problème avec des fenêtres d'instruction de ce type est leur forte consommation énergétique, ainsi que le grand nombre de portes logiques utilisées, qui deviennent prohibitif pour des fenêtres d'instruction un peu grosses. Pour résoudre ce problème, certains ont optimisé les comparateurs. D'autres ont tenté de profiter du fait que la majorité des bits dans les entrées sont composés de zéros. Bref, les optimisations purement matérielles sont légion. Une première solution est de désactiver les entrées qui sont inutilisées, vides, sans instruction. Pour cela, on fait précéder les comparateurs par un circuit qui les connecte ou déconnecte des lignes de bit. Le circuit est commandé par le bit ''empty'' qui indique si une entrée est vide ou non. L'avantage est que la consommation d'énergie de la fenêtre d'instruction devient alors proportionnelle au nombre d'entrées non-vides, et non au nombre d'entrées total. Du moins, en apparence, les entrées non-utilisées doivent quand même être alimentées pour fonctionner, mais l'activité de comparaison disparait dans les entrées vides. Il est possible d'étendre cette technique aux entrées dont les opérandes sont prêtes. Les gains sont généralement assez bons, avec une réduction de consommation variant entre 30 et 50%, avec une implémentation très simple et très économe en circuits. Une autre solution, assez simple à mettre en place, consiste à désactiver une partie de la fenêtre d'instruction sin elle est inutilisée. Pour cela, il faut segmenter la fenêtre d'instruction avec la technique du ''wire partitionning''. Pour rappel, une fenêtre d'instruction est une mémoire associative. Et comme toute mémoire associative, elle contient des fils, les lignes de bit, qui relient les entrées/sorties à toutes les cellules mémoire. Plus une ligne de bit est longue, plus elle consomme d'énergie et plus le temps de lecture/écriture est long. L'idée est de segmenter les lignes de bits en plaçant des répéteurs qui recopient la tension d'un segment au suivant. Les répéteurs sont des tampons trois-états, ce qui permet de déconnecter les portions inutilisées de la ligne de bit. Ce faisant, la fenêtre d'instruction est découpée en segments, qui peuvent être désactivés si besoin. Si il y a peu d'instructions chargées dans la fenêtre d'instruction, les portions inutilisées sont désactivées. La technique marche d'autan mieux si les instructions sont compactées au début de la fenêtre d'instruction. [[File:Wire partitionning.png|centre|vignette|upright=2|Wire partitionning]] Tout le problème est de savoir quelles portions désactiver. La technique est assez simple si la fenêtre d'instruction est compactée, à savoir si toutes les instructions sont régulièrement regroupées au début de la mémoire CAM. Mais même avec cette optimisation, la décision de désactiver une portion de la fenêtre d'instruction n'est pas à prendre à la légère. Il ne faut pas désactiver une portion contenant des instructions pouvant être émise sous peu. La décision dépend de paramètres variés : proportion d'entrée vides, quantité d'entrées récemment activées/désactivées récemment, présences d'entrées avec un ''match'' d'opérandes récent, etc. Il est important de préciser que les techniques en question fonctionnent aussi sur les autres types de fenêtre d'instruction, qui ne sont pas basées sur des mémoires associatives. Nous allons voir celles-ci dans la suite du chapitre, mais gardez à l'esprit que ces optimisations, à savoir désactiver les entrées vides/prêts et partitionner la fenêtre d'instruction, sont des optimisations générales qui marchent avec presque tout. ===L'ajout d'une FIFO pour les instructions déjà prêtes à l'émission=== D'autres techniques permettent de réduire aussi bien le cout en circuits que la consommation d'énergie de la fenêtre d'instruction. L'idée est d'utiliser une mémoire associative quand elle est réellement nécessaire, mais d'utiliser une fenêtre d'instruction "normale" dès que possible. La méthode la plus simple tient compte du fait que certaines instructions ont déjà toutes leurs opérandes de disponibles à l'émission, mais doivent quand même être mises en attente, parce que l'ALU adéquate est occupée, parce que des dépendances WAW/WAR sont encore là, ou pour tout autre raison. Dans ce cas, elles sont mises en attente non pas dans la fenêtre d'instruction, mais dans une mémoire FIFO toute simple. L'idée est qu'au lieu d'avoir une énorme mémoire associative pour la fenêtre d'instruction, on déplace quelques entrées dans une petite FIFO annexe. Le résultat est un gain en terme d'énergie et de circuits, au prix d'une perte de performance mineure. La perte de performance en question se manifeste si aucune instruction n'a ses opérandes de prêtes à l'émission : le programme n'utilise pas la FIFO et voit alors une fenêtre d'instruction plus petite. Une amélioration de cette technique tient compte du fait que certaines instructions sont dans un cas intermédiaire. Elles ont déjà une opérande de prête lors de l'émission, mais pas l'autre. Le nombre d'opérandes varie suivant l’instruction : certaines n'ont besoin que d'un seul opérande. De plus, il arrive qu'une opération tout juste décodée ait déjà un ou plusieurs de ses opérandes de prêts. Cette constatation permet d'éviter d'utiliser des comparateurs pour les opérandes déjà prêts. Par exemple, on peut parfaitement utiliser trois fenêtres d'instruction : * une pour les instructions dont tous les opérandes sont prêts, mais qui sont quand même mises en attente, sans comparateur ; * une pour les instructions dont un seul opérande manque, qui n'utilise qu'un comparateur par entrée ; * une pour les instructions dont deux opérandes manquent à l'appel, qui utilise deux comparateurs par entrée. C'est beaucoup plus économique que d'utiliser une seule grosse fenêtre d'instruction qui contiendrait autant d'entrées que les trois précédentes réunies, avec deux comparateurs par entrée. Certains sont même allés plus loin, et ont proposé de supprimer la fenêtre d'instruction avec deux opérandes par entrée. Les instructions dont deux opérandes sont inconnus au décodage sont stockées dans la fenêtre d'instruction pour instructions avec un comparateur par entrée. Un circuit de prédiction se charge alors de prédire l'opérande manquant, cette prédiction étant vérifiée plus loin dans le pipeline. Il serait cependant étonnant qu'une telle proposition ait donné lieu à la moindre implémentation réelle. ===Les optimisations de la consommation d'énergie avancées=== D'autres chercheurs ont conservé une fenêtre d'instruction unique, avec autant de comparateurs par entrée qu'il y a d'opérandes possibles par instruction. Simplement, le processus de détection des opérandes prêts est légèrement ralenti : on ne vérifie qu'un opérande par cycle. Pour vérifier les deux opérandes d'une entrée, on doit attendre deux cycles. Enfin, certains chercheurs ont proposé des fenêtres d'instruction segmentées. Les instructions circulent à chaque cycle d'un segment vers le suivant : en conséquence, certains segments conservent les instructions les plus anciennes, un autre les instructions les plus jeunes, etc. Seul le denier segment, celui qui contient les instructions les plus vielles, peut émettre une instruction : la détection des opérandes se fait seulement dans le dernier segment, qui contient les instructions les plus anciennes. On économise ainsi beaucoup de comparateurs. Certains chercheurs ont tenté de pipeliner l'étape de sélection des opérandes, ainsi que l'étage d'arbitrage. Mais en faisant cela, il faut plusieurs cycles pour détecter qu'une instruction a ses opérandes prêts, ce qui pose problème face à de nombreuses dépendances RAW. Pour éviter de trop perdre en performances, certains chercheurs ont décidé d'utiliser des techniques pour prédire quelles seront les instructions dont les opérandes seront bientôt prêts. Si détecter qu'une instruction est prête prend n cycles, le processeur devra tenter de prédire la future disponibilité des opérandes n cycles en avance pour obtenir des performances optimales. ===Remplacer la mémoire associative par une RAM=== Une autre optimisation possible est de remplacer la fenêtre d'instruction par une mémoire RAM, dont chaque mot mémoire correspondrait à une entrée. Une telle optimisation permet en théorie de se passer des comparateurs associés à chaque entrée, mais au prix de l'ajout de circuits annexes potentiellement couteux. La première de ces techniques, la '''recherche directe par étiquette''' (direct tag search) fut créée par Weiss et son collègue Smith. Ils cherchaient à améliorer l'algorithme de Tomasulo, un algorithme qu'on expliquera dans quelques chapitres. Rappelons que chaque instruction produit un résultat, qui devra être rapatrié dans une ou plusieurs entrées de la fenêtre d'instruction. L'optimisation de la recherche directe par étiquette fonctionne dans le cas où le résultat de l'instruction n'est utilisé que par une seule entrée, et pas plusieurs. Le principe est simple : chaque champ « opérande » d'une entrée est adressable via le nom de registre de cette opérande. Pour faire le lien entre entrée et nom de registre, la recherche directe par étiquette ajoute une table de correspondances matérielle, une mémoire RAM qui mémorise les adresses des champs « opérande » des entrées. Les adresses envoyées dans cette mémoire sont les noms de registres des résultats. Lors de l'émission, la table de correspondances est mise à jour. Les numéros des champs « opérande » réservés lors de l'émission sont mémorisés dans les mots mémoire qui correspondent aux deux registres sources. Toutefois, une petite vérification est faite lors de l'émission : si il y a déjà une correspondance dans la table pour un registre source, alors une autre instruction compte lire ce registre. Pour éviter d'écraser les données de l'instruction précédente dans la table de correspondances, l'émission de l'instruction est bloquée. [[File:Recherche directe par étiquette.png|centre|vignette|upright=2|Recherche directe par étiquette.]] ==Les fenêtres d’instruction avec préplanification== Avec la '''préplanification''' (''prescheduling''), la fenêtre d’instruction est composée de mémoires FIFO dans lesquelles les instructions sont triées dans l'ordre d'émission. Il n'y a pas de logique d’émission proprement dite, celle-ci se bornant à vérifier si l'instruction située au début de la FIFO peut s’exécuter. Par contre, le préplanificateur détecte les dépendances et en déduit où insérer les instructions dans le tampon d'émission, à l'endroit le plus adéquat. [[File:Préplanification.jpg|centre|vignette|upright=2|Préplanification.]] ===L'usage de FIFO multiples=== La technique de préplanification la plus simple utilise plusieurs FIFO. Quand une instruction a une dépendance avec une autre instruction, les deux sont placées dans la même FIFO. Pour cela, le préplanificateur détecte les chaines d'instructions dépendantes, et place les instructions dans la FIFO adéquate. A chaque cycle, l'unité d'émission lit une micro-opération dans chaque FIFO et vérifie si elle peut l'émettre. Si la micro-opération n'a pas ses opérandes disponibles, ou qu'une dépendance structurelle survient, alors la FIFO est bloquée. La micro-opération attend que la dépendance soit résolue, bloquant toutes les instructions précédentes. Mais les autres FIFO ne sont pas bloquées, laissant de la marge de manœuvre. [[File:Préplanification par FIFO multiples.png|centre|vignette|upright=1.5|Préplanification par FIFO multiples.]] ===La technique du tampon trié=== La technique du '''tampon trié''' trie les instructions selon le temps d'attente avant leur exécution. Les instructions qui sont censées s’exécuter bientôt sont insérées au tout début de la FIFO, tandis que les instructions qui s’exécuteront dans un long moment sont insérées vers la fin. Là encore, l'unité d'émission lit une micro-opération dans la FIFO, et détermine si elle peut être émise. Si une dépendance survient, l'émission est retardée, et la FIFO est bloquée. [[File:Préplanification par tampon trié.png|centre|vignette|upright=1.5|Préplanification par tampon trié.]] La technique a cependant quelques problèmes assez importants. Le premier problème est que la FIFO est bloquée lorsqu'une micro-opération ne peut être émise. Le second problème est que le temps avant exécution n'est pas toujours connu, notamment pour les instructions d'accès mémoire. Et cela se répercute sur les instructions dépendantes de celles-ci. Pour résoudre ce genre de problèmes, l'usage d'un pipeline à ''replay'' est possible, et est même l'une des meilleures solution possible, malgré ses défauts. L'idée est que les lecture sont pré-planifiées en supposant qu'elles font un succès de cache L1. Si la prédiction est fausse, la lecture est ré-exécutée plusieurs cycles plus tard, en supposant qu'elle fait un succès dans le cache L2, et ainsi de suite. Elle est alors ré-insérée dans la FIFO, elle est pré-planifiée une seconde fois. Il en est de même si une micro-opération ne peut pas être émise : il suffit de la réinsérer dans la FIFO au bon endroit, en attendant que ses dépendances soient résolus. Ainsi, l'instruction fautive ne bloque pas la fenêtre d’instruction, et retente sa chance autant de fois qu'il le faut. [[File:Préplanification par fenêtre d’instruction scorebarodée.png|centre|vignette|upright=1.5|Préplanification par fenêtre d’instruction scorebarodée.]] Une autre solution utilise deux fenêtres d’instruction : une FIFO gérée par la préplanification, et une vraie fenêtre d'instruction pour les instructions dont le temps d'attente ne peut pas être déterminé. Il est possible de mettre cette dernière avant la préplanification, afin de gérer les temps d'attente des instructions d'accès mémoire. Quand le temps d'attente d'une lecture devient connu, ses instructions dépendantes sont gérées avec préplanification. [[File:Préplanification avec fenêtre d’instruction.png|centre|vignette|upright=2.5|Préplanification avec fenêtre d’instruction.]] ===Les fenêtres d'instruction avec allocation temporelle statique=== L''''allocation temporelle statique''' correspond à une technique utilisée sur les processeurs Cuzco de l'entreprise Condor. La technique en question a été présenté en 2025, mais des idées similaires ont été présentées dans la littérature académique. Elle ressemble beaucoup aux techniques de pré-planification, avec cependant quelques différences. L'idée est simple : le processeur dispose de plusieurs fenêtres d'instruction, qui mettent en attente les micro-opérations. Lors de l'étape de renommage de registres, le processeur détermine dans combien de cycles d'horloge la micro-opération sera prête pour exécution. La micro-opération est alors mise en attente durant ce nombre de cycles, dans les fenêtres d'instruction, puis est émise une fois ce nombre de cycles écoulés. Ce faisant, les fenêtres d'instruction n'ont pas besoin de détecter la disponibilité des opérandes à chaque cycle, pour chaque micro-opération en attente. Le ''timing'' de l'émission des micro-opérations est décidé à l'avance. L'implémentation exacte n'est pas connue, mais plusieurs solutions sont imaginables. Par exemple, la fenêtre d'instruction peut simplement être composée de plusieurs mémoires de petite taille, chacune contenant les micro-opérations destinées à être exécutées dans N cycles, N étant différent pour chaque mémoire. Une autre solution, plus réaliste, utilise une fenêtre d'instruction dans laquelle la micro-opération est couplée à des champs pour les opérandes, et un champ compteur. Le champ compteur est initialisé avec le nombre de cycles à attendre, et est décrémenté à chaque cycle d'horloge. Quand il atteint zéro, la micro-opération est émise. Vous remarquerez que la méthode ne marche que si toutes les micro-opérations prennent un nombre fixe de cycles d'horloge. Et autant c'est le cas pour les micro-opérations arithmétiques ou logiques, autant les accès mémoire ne rentrent pas dans ce cadre. En théorie, on ne sait pas combien de temps prendra un accès mémoire. Et cette incertitude se répercute sur les instructions dépendantes d'un accès mémoire. Pour éviter cela, le processeur réutilise un pipeline à ''replay'' tel que vu dans le chapitre précédent. L'unité de renommage de registre suppose que tout accès mémoire fait un succès de cache L1, et décide des ''timings'' d'émission sous cette hypothèse. Si une lecture subit un défaut de cache, elle est ré-exécutée, de même que toutes les instructions dépendantes. Pour cela, le registre de destination de la lecture est marqué comme invalide, grâce à un bit spécifique attaché au registre. Toute instruction qui lit une opérande invalide est elle aussi ré-executée de zéro. Pour simplifier, l'unité d'émission ressemble à une unité d'émission dans l'ordre, avec un registre de disponibilité, qu'on aurait amélioré pour aller au-delà de la simple détection des dépendances d'instruction. Pour déterminer les ''timings'' d'émission, à savoir quand émettre une micro-opération, le processeur utilise une unité d'émission à deux étages. Le premier étage est appelé le ''register scoreboard'', le second étage est appelé la ''Time Ressource Matrix''. Les deux étages communiquent entre eux, comme on va le voir, et leurs noms donnent une idée de ce qu'ils font. Le premier étage gère les dépendances de registres, le second gère les dépendances structurelles. Le premier étage est un registre de disponibilité amélioré, qui gère les dépendances de registre. Cet étage sait quand tel registre sera écrit, et donc que l'opérande écrite dedans sera disponible à partir de tel cycle d'horloge. Il le sait car l'étage suivant l'aura prévenu, mais laissons cela de côté pour le moment. Quand une micro-opération rentre dans cet étage, il vérifie les dépendances avec les registres et les micro-opérations antérieures. Vu qu'il sait quand les registres seront disponibles, il peut déterminer quand l'instruction pourra s'exécuter. Par exemple, si une micro-opération lit les deux registres R7 et R15, qui sont disponibles respectivement dans 5 et 7 cycles, le premier étage sait que la micro-opération devra attendre 7 cycles. Mais tout cela ne suffit pas à déterminer quand émettre une micro-opération. En effet, il fait aussi gérer les dépendances structurelles, ce qui est le boulot du second étage. Le second étage utilise pour cela une ''Time Ressource Matrix'', qui mémorise l'occupation de diverses "ressources", pour les 256 cycles d'horloge à venir. Les ressources en question sont les ports de lecture/écriture du banc de registre, les ALUs utilisées, si la micro-opération utilise l'unité mémoire, etc. Le second étage prend en entrée une micro-opération, détermine quelles "ressources" elle utilise, puis regarde leur disponibilité. Elle détecte alors les dépendances structurelles et détermine alors quand peut s'exécuter la micro-opération. Elle peut retarder l'émission de quelques cycles, si une dépendance structurelle est détectée. Une fois sortie du second étage, on sait quand la micro-opération va être émise, à quel cycle précisément. Et vu que la durée de l'instruction est fixe, on sait quand cette micro-opération va se terminer, quand son résultat sera disponible. Cela permet de mettre à jour la ''Time Ressource Matrix'', pour préciser que le port d'écriture sera occupé à tel moment. De plus, cette information est transmise au premier étage, qui sait alors quand est enregistré le résultat dans le registre de destination. C'est comme cela que le premier étage sait quand un registre est disponible : le second étage le prévient, quand il émet une instruction ! La ''Time Ressource Matrix''mémorise l'occupation des "ressources" pour les 256 cycles d'horloge à venir. Cependant, elle ne vérifie pas les dépendances pour les 256 cycles suivants. Quand elle reçoit une micro-opération, elle teste les dépendances structurelles pour seulement les 8 prochains cycles maximum. Si la micro-opération ne peut pas être émise pendant ces 8 cycles, le pipeline est bloqué, un ''pipeline stall'' est émis. Pour être plus précis, vu que le processeur peut décoder 8 micro-opérations en même temps, cela permet de ne consulter que 64 cycles d'horloge sur les 256. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les premiers processeurs Intel | prevText=Les premiers processeurs Intel | next=Le renommage de registres | nextText=Le renommage de registres }} </noinclude> 5ca94kodid7w8xk1cmbi4btmxdgee16 773601 773600 2026-09-29T19:40:07Z Mewtow 31375 /* Les entrées d'une fenêtre d’instruction */ 773601 wikitext text/x-wiki Dans les chapitres précédents, nous avons parlé des techniques dites d''''émission dans l'ordre'''. L'idée est d’exécuter une nouvelle micro-opération à chaque cycle, dans des unités de calcul séparées. Les instructions sont émises consécutivement, mais les instructions s’exécutent en parallèle dans des unités de calcul séparées. Par contre, quand l'unité d'émission ne peut pas émettre une instruction, elle bloque tout le pipeline. Les instructions qui suivent sont elles aussi bloquées, elle doivent attendre leur tour, même si elles sont en capacité de s'exécuter. Les techniques d'exécution dans le désordre que nous allons voir dans ce chapitre corrigent ce point précis. Elles sont dites à '''émission dans le désordre'''. Elles se distinguent des précédentes sur un point précis : quand l'unité d'émission bloque l'émission d'une instruction, les instructions suivantes peuvent poursuivre. L'émission des instructions peut donc se faire dans le désordre, dans le sens où une instruction peut être émise alors qu'une instruction précédente ne l'est pas encore. L'avantage de l'émission dans le désordre est qu'une instruction s'exécute dès que ses opérandes sont disponibles. Par disponible, on veut dire présent soit dans le réseau de contournement, soit dans les registres. Le processeur détecte automatiquement quand les opérandes d'une instruction sont sont disponibles, et il l’exécute à ce moment là. Dès qu'une instruction a ses opérandes disponibles, elle est émise et exécutée. C'est là la seule contrainte : les dépendances WAR, WAW et autres sont gérées par un ROB ou toute autre technique d'exception précise, seules les dépendances RAW limitent l'exécution. Mais avant de poursuivre, quelques point niveaux terminologie : * L'émission dans le désordre est un terme parlant et assez précis. Malheureusement, la terminologie la plus utilisée par d''''exécution dans le désordre'''. Et nous utiliserons ce terme dans la suite du cours, histoire de ne pas trop dévier de la nomenclature habituelle. * Nous utiliserons parfois l'abréviation OOO pour parler d'exécution dans le désordre. L'abréviation est celle de ''Out Of Order Excution''. * Nous utiliserons aussi l'abréviation ''µop'' pour parler de micro-opération, ''µops'' au pluriels pour parler de plusieurs micro-opérations, ou des micro-opérations en général. L'exécution dans le désordre ne gére en effet que des µops, elle se situe après l'étape de décodage. Mais avant de poursuivre, précisons une chose importante : l'exécution dans le désordre traite les accès mémoire à part. La majorité des processeurs OOO assez anciens exécutent les accès mémoire dans l'ordre, seules les µops entières/flottantes/branchements sont exécutées dans le désordre. Les processeurs datant d'après les années 2010 sont capable d'exécuter les accès mémoire dans le désordre, mais l'implémentation en question est assez particulière. Un chapitre entier sera dédié à l'exécution dans le désordre des µops mémoire. Nous allons volontairement mettre de côté la gestion des accès mémoire dans ce chapitre. ==Les fenêtres d’instruction : généralités== [[File:File de micro-opération.png|vignette|upright=1|File de micro-opérations]] Pour décrire comment est implémentée l'émission dans le désordre, il faut commencer par parler des processeurs sans. Les processeurs sans exécution dans le désordre ont une unité d'émission qui bloque tout le pipeline dès qu'une µop ne peut pas être émise. Pour limiter l'impact de ce blocage, quelques rares processeurs incorporent une '''file de micro-opération''', une mémoire FIFO qui met en attente les µops. Vu que c'est une mémoire FIFO, les µops sont émises dans l'ordre, à savoir l'ordre d'ajout, dans l'ordre de décodage. Le schéma ci-dessous illustre une telle file d'attente couplée à un ''scoreboard''. Sur le principe, l'exécution dans le désordre améliore la file de µops sur un point : ce n'est plus une mémoire FIFO. Les µops sont insérées dans l'ordre, mais peuvent sortir dans le désordre (être émises dans le désordre). La file de µops devient alors une '''fenêtre d'instruction''', terme traduit directement de l'anglais ''instruction Window''. Terme assez trompeur, car elles mettent en attente des µops, pas des instructions. Elles peuvent émettre des µops dans le désordre, ce qui fait que si une µop bloque le pipeline, les µops suivantes peuvent être émises. Si je commence le paragraphe précédent par "sur le principe", c'est car certaines techniques d'OOO utilisent des files de µops normales. Il est par exemple possible d'utiliser une file de µops avec une fenêtre d'instruction, plusieurs files de µops, plusieurs fenêtres d'instructions avec une file de µops annexe, etc. Dasn les grandes lignes, il existe dans les grandes lignes 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! File de µops améliorée |- ! Une seule "file de µops" | ''Scoreboard'' | Fenêtre d'instruction centralisée |- ! Plusieurs "file de µops" | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | Fenêtre d'instruction décentralisée |} ===La fenêtre d'instruction centralisée=== L'implémentation la plus simple de l'OOO utilise une unique '''fenêtre d'instruction'''. Les instructions décodées sont accumulées dans la fenêtre d'instruction, où elles attendent que leurs opérandes soient disponibles. La fenêtre d'instruction sert donc de file d'attente. Mais elle contient aussi une unité d'émission, qui détecte quelles µops sont prêtes à être émises. L'unité d'émission et la fenêtre d'instruction sont fusionnées ensemble, elles forment un seul circuit. Mais nous allons dire qu'elles sont conceptuellement séparées pour le moment. A chaque cycle, l'unité d'émission consulte la fenêtre d'instruction pour voir quelles µops peuvent s'exécuter, lesquelles ont leur opérandes de disponibles. La fenêtre d'instruction doit spécialement être conçue pour, c'est une sorte de mémoire associative très complexe, comme on le verra dans ce qui suit. [[File:OOO Issue.png|centre|vignette|upright=2.5|Exécution dans le désordre avec une fenêtre d'instruction]] Une fois qu'une µop sort du décodeur d'instructions, elle est ajoutée en parallèle dans la fenêtre d'instruction et le ROB. La raison est que les µops quittent la fenêtre d'instruction dans le désordre, et qu'elles doivent être remises en ordre par la suite. Le ROB s'occupe de cette remise en ordre, mais il a besoin de savoir dans quel ordre les µops sont censées être, et cet ordre est celui du décodage. Aussi, pour remplir le ROB, la seule opportunité est en sortie de l'unité de décodage. Dans le cas où une instruction est décodée en plusieurs micro-opérations, elles sont toutes insérées en même temps dans la fenêtre d'instruction et le ROB, en tenant compte de leur ordre. [[File:Fenêtre d'instruction.png|centre|vignette|upright=2|Fenêtre d'instruction.]] Les micro-opérations mémoire sont à part des autres, pour diverses raisons. Une de ces raisons est que les dépendances de données sont classées en deux types : les dépendances de registre et les dépendances d'adresse. Et les deux sont fondamentalement différentes. Autant on peut détecter les dépendances de registre lors de l'émission, autant c'est plus compliqué avec les dépendances d'adresse. De plus, rappelons que si les lectures peuvent s'exécuter dans le désordre, les écritures doivent s'exécuter dans l'ordre, ou du moins en donner l'illusion. Pour cela, le processeur remet les écritures dans l'ordre avec une sorte de mini-ROB intégré à l'unité mémoire, appelée la file d'écriture. Elle complémente le ROB, qui lui ne gère que les écritures dans les registres, mais les deux collaborent. La file d'écriture envoie une écriture à la mémoire RAM quand le ROB lui dit que c'est bon, les instructions précédentes sont terminées ''dans l'ordre du programme''. Les processeurs modernes ajoutent des techniques d'exécution dans le désordre des accès mémoire, mais nous les verrons dans un chapitre dédié. Elles permettent d'utiliser une fenêtre d'instruction unique, qui mémorise aussi les µops mémoire. Si elles sont mises en place, l'unité mémoire n'a pas besoin de file de µops séparée. L'idée est que les dépendances de registre sont traitées par la fenêtre d'instruction, mais que l'unité mémoire gére les dépendances d'adresse. Les dépendances d'adresse sont gérées par des techniques de ''désambiguation mémoire'', qui auront droit à un chapitre dédié. [[File:Processeur avec exécution dans le désodre des accès mémoire.png|centre|vignette|upright=2|Processeur avec exécution dans le désodre des accès mémoire]] Les processeurs assez anciens n'autorisaient pas d'exécution dans le désordre des accès mémoire. Concrétement, les accs mémoire devaient se faire dans l'ordre, mais les autres µops pouvaient être exécutées dans le désordre. Il s'agit donc d'un ordre entre µops mémoire, pas entre µops mémoire et autres µops. Les µops entières et flottantes pouvaient être exécutées avant une µops mémoire qui est avant elle dans l'ordre du programme, ce n'est pas un problème. Pour garantir l'ordre desd µops mémoire, l'unité mémoire est précédée par une file de micro-opérations séparée, pour forcer l'exécution dans l'ordre des accès mémoire. De plus, les µops mémoire ne peuvent pas utiliser la fenêtre d'instruction. Dit autrement, la fenêtre d'instruction ne mémorise pas de µops mémoire. Après le décodage, les µops sont réparties soit dans la file de µops mémoire, soit dans la fenêtre d'instruction. Le décodeur classe les µops suivant que ce sont des µops mémoire ou non, et les envoient à la bonne destination. Dans ce chapitre, on supposera que c'est cette solution qui est utilisée. [[File:Processeur avec émission dans l'ordre des accès mémoire.png|centre|vignette|upright=2|Processeur avec émission dans l'ordre des accès mémoire]] La solution précédente revient à scinder la fenêtre d'instruction en deux : une file de µops pour les µops mémoire, une fenêtre d'instruction pour les autres µops. Et cette scission peut aller plus loin, à savoir qu'on peut scinder une fenêtre d'instruction encore et encore. Ce qui nous amène à la section suivante. ===Les fenêtres d'instruction décentralisées=== Nous venons de voir qu'il est possible de scinder la fenêtre d'instruction en une fenêtre d'instruction pour les µops mémoire (simplifiée en une file de µops classique), et une autre pour les autres µops. Sachez qu'il est possible d'aller plus loin, par exemple en séparant la fenêtre d'instruction en une fenêtre spécialisée dans les µops flottantes et une autre pour les µops entières. Et ce n'est là qu'un exemple parmi de nombreuses autres possibilités. Pour faire la différence avec une fenêtre d'instruction unique, nous allons parler de fenêtre d'instruction centralisée s'il n'y en a qu'une, de '''fenêtre d'instruction décentralisée''' s'il y en a plusieurs. Il est possible d'associer chaque fenêtre d'instruction à un type précis de µops. Par exemple, avec une fenêtre d'instruction pour les µops de calcul entières, une autre pour les µops flottantes, une autre pour les µops mémoire. Il s'agit d'un choix simple et efficace, mais quelques processeurs font autrement, pour répondre à des contraintes très diverses. [[File:Processeur avec des fenêtres d'instruction décentralisées.png|centre|vignette|upright=2|Processeur avec des fenêtres d'instruction décentralisées]] Reste à scinder la fenêtre d'instruction pour trier les µops suivant leur type. Si le processeur exécute les accès mémoire dans l'ordre, la méthode la plus simple utilise une fenêtre d'instruction pour les opérations flottantes et une autre pour les autres µops (µops entières et parfois mémoire avec). L'avantage est que cela simplifie grandement le processeur. Les flottants sont gérés à part des entiers. Ils ont leurs propres registres, des FPU séparées des ALU entières, bref : la séparation est complète. Utiliser une fenêtre d'instruction séparée va dans ce sens. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Il est possible de faire pareil sur les processeurs avec exécution dans le désordre des accès mémoire. Par exemple : les processeurs Intel de microarchitecture Skylake utilisent une fenêtre d'instruction pour les opérations entières/flottantes, et une fenêtre d'instruction séparée pour les µops mémoire. Un avantage est que les deux fenêtres d'instructions sont plus spécialisées, ce qui entraine des économies de circuit. Les opérations entières/flottantes ont besoin de deux registres pour les opérandes et d'un autre résultat, alors que les µops mémoire n'ont besoin que de deux registres maximum. En utilisant une fenêtre d'instruction unique, chaque entrée doit mémoriser l'opcode et trois registres, dont un est inutilisé pour les µops mémoire et les branchements. En utilisant des fenêtres d’instructions séparées, celle pour les µops entières/flottantes a trois registres par entrée, contre seulement deux registres par entrée pour celle des µops mémoire. Un cas extrême est celui où chaque ALU/FPU a sa propre fenêtre d'instruction. Nous parlerons alors de '''fenêtres d'instruction totalement décentralisées'''. Par exemple, il y a une fenêtre d'instruction pour l'ALU entière, une autre pour le multiplieur entier, une autre pour le ''barrel shifter'', une autre pour l'unité mémoire, une autre pour l'unitéé de branchements, une autre pour l'additionneur flottant, une dernière pour le multiplier flottant, etc. Un exemple historique est celui de la FPU de l'IBM 360 modèle 90. Elle disposait d'un additionneur flottant, d'un multiplieur flottant, et d'une unité mémoire pour les lectures/écritures flottantes. Les trois unités avaient leur propre fenêtre d'instruction. Les processeurs AMD utilisent beaucoup cette technique, contrairement à Intel qui préfère utiliser des fenêtres centralisées sur les anciens processeurs, deux ou trois fenêtres sur les processeurs récents (2020 et plus). Les processeurs AMD utilisaient précisément une fenêtre d'instruction par ALU entière, alors que les FPUs partagent une fenêtre d’instructions flottantes unique. Mais nous verrons cela en détail dans le chapitre sur les processeurs superscalaires x86. Un point important est qu'avec des fenêtres d'instruction décentralisées, l'émission est découpée en deux étages. La première étape envoie une µops vers la fenêtre d'instruction adéquate, la seconde émet la µops depuis la fenêtre d'instruction quand ses opérandes sont prêtes. La première est l'étage de '''''dispatch''''' qui envoie l'instruction dans la fenêtre d’instruction adéquate, selon que c'est une instruction flottante, entière, autre. La seconde est l'étage de '''''scheduling''''', qui gère la disponibilité des opérandes et des unités de calcul. La µop émise est ajoutée au tampon de réordonnancement, s'il existe, lors de l'étape de ''dispatch''. ===L'usage de plusieurs files d'instruction=== Une dernière méthode d'OOO utilise plusieurs files de micro-opération. L'idée est qu'une fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement une file de micro-opération pour les opérations entières, une autre pour les opérations flottantes, une autre pour les accès mémoire. D'autres processeurs utilisent une file pour les accès mémoire et une autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. La présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que la technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si une dépendance bloque une FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans une autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer la disponibilité des registres. Quand un registre est lu ou écrit par une instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. La logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : une pour les instructions d'accès mémoire et une autre pour les autres instructions. Si jamais une instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de la lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'une est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est la file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. ===Avantages et inconvénients de chaque implémentation=== Pour résumer, on a le choix entre une grosse fenêtre d'instruction généraliste et plusieurs fenêtres spécialisées. Le choix entre les deux est un compromis entre économie de circuits et flexibilité. Avec une fenêtre décentralisée, il arrive qu'une fenêtre d'instruction soit remplie, alors que les autres sont sous-utilisées, voire vides. Pour comprendre pourquoi, comparons une fenêtre d'instruction unique, avec une fenêtre décentralisée séparant µops entières et flottantes. La fenêtre centralisée dispose de 64 entrées, la décentralisée a 32 entrées pour chaque fenêtre d'instruction. La fenêtre décentralisée peut mémoriser au maximum 32 µops entières et 32 *ops flottantes. Par contre, la fenêtre centralisée peut mémoriser 64 µops tout court. Si le programme exécuté n'utilise pas de nombres flottants, la différence devient flagrante. La fenêtre décentralisée sera limitée ) 32 µops, alors que la centralisée pourra mémoriser le double. Les performances seront donc meilleurs avec la fenêtre centralisée. Et au-delà de ça, la fenêtre décentralisée de l'exemple est utilisée de manière optimale si la moitié des µops sont des µops entières, et l'autre moitié des µops flottantes. Alors que la fenêtre centralisée se moque de la répartition entre µops entières et flottantes. Une subtilité est que le cout en transistors d'une fenêtre d'instruction n'est pas proportionnel au nombre de µops qu'elle peut mémoriser. Par exemple, si je compare une fenêtre d'instruction de 32 entrées (32 µops max), elle n'utilise pas deux fois plus transistors qu'une fenêtre de 16 entrées. Le cout en circuit n'est pas deux fois plus élevé, mais est approximativement 4 fois plus élevé. Le cout est presque quadratique, à savoir qu'il est proportionnel au carré du nombre d'entrées. Et il en est de même avec la performance, pour des raisons qu'on expliquera plus bas. Les fenêtres décentralisées utilisent plusieurs fenêtres d'instruction de "petite taille", donc plus rapides, économes en circuits et économes en énergie. Le compromis n'est donc pas entre une fenêtre centralisée à 64 entrées versus deux fenêtres de 32 entrées. Le compromis en pratique est entre une fenêtre centralisée de 64 entrées versus 3 fenêtres de 32 entrées. Un exemple pratique est celui de la microarchitecture ''Skylake'' d'Intel. Intel est passé d'une fenêtre centralisée pre-''Skylake'' à deux fenêtres décentralisées sur ''Skylake'',. Le nombre d'entrée était globalement le même entre les deux, même si l'évolution de la finesse de gravure entre les deux biaise un peu les résultats. Un avantage des fenêtres décentralisées est qu'il est possible de démarrer l'exécution de plusieurs µops simultanément : une µops par fenêtre d'instruction. Le fait est que deux fenêtres d'instructions différentes émettent leurs µops sans se synchroniser avec les autres. Deux fenêtres d'instruction peuvent donc émettre chacune une µops, ce qui fait deux µops émises lors du même cycle. Cela permet d'exécuter en même temps deux ou trois instructions 1-cycle, comme des additions, soustractions, décalages, etc. Il devient par exemple possible d'émettre une µop entière en même temps qu'une µop flottante, si les µops entières ont une fenêtre séparée de celle des µops flottantes. Il est maintenant temps de voir en quoi sont faites les fenêtres d’instruction, qu'elles soient centralisées ou décentralisées. Nous allons aussi voir quelle est la logique d'émission associée. ==L'implémentation d'une fenêtre d'instruction : généralités== Une fenêtre d'instruction est une mémoire qui mémorise des micro-opérations. Elle est cependant plus complexe qu'une mémoire RAM ou qu'une FIFO et ressemble un petit peu à une mémoire cache. Elle dispose d'un port d'écriture et d'un port de lecture, au minimum. Le port d'écriture permet à l'unité de décodage d'insérer une micro-opération dedans, d'ajouter la micro-opération qui vient d'être décodée. Si une instruction machine est décodée en plusieurs micro-opération, deux possibilités. La première est de les insérer un par un, ce qui fait qu'on peut se contenter d'un seul port d'écriture. L'autre possibilité est de les ajouter en même temps, ce qui demande plusieurs ports d'écriture. Le port de lecture sert à émettre une instruction. On part du principe que la fenêtre d'instruction ne peut émettre qu'une seule instruction à la fois, car les processeurs que nous avons vu précédemment sont de ce type. Mais nous verrons dans quelques chapitre qu'il existe des processeurs dits superscalaires, qui sont capables d'émettre plusieurs instructions par cycle. Dans ce cas, la fenêtre d'instruction a un seul port de lecture. Un processeur superscalaire, quant à lui, doit avoir un port de lecture par unité de calcul, ce qui fait beaucoup plus. ===Les entrées d'une fenêtre d’instruction=== Les fenêtres d'instruction sont composées d''''entrées''', des mots mémoire qui stockent une instruction. Une instruction réserve une entrée après son décodage et la libère dès qu'elle est envoyée aux unités de calcul. Une entrée contient l'opcode (les signaux de commande à envoyer à l'ALU), le registre de destination du résultat, les registres de chaque opérande, et éventuellement des signaux de commande en plus. De plus, chaque opérande est couplée à un bit de disponibilité, qui indique si elle est disponible. Quand un opérande est écrit dans les registres, le bit de présence correspondant est mis à jour. Enfin, chaque entrée possède un bit ''empty'' qui indique si elle est vide, cette information étant utile pour réserver des entrées. [[File:Entrée d'une station de réservation - sans les tags.png|centre|vignette|upright=3|Entrée d'une fenêtre d'instruction]] Nous verrons dans quelques chapitres que certaines fenêtres d'instruction sont capables de mémoriser les opérandes des instructions. De telles fenêtres d'instruction seront appelées, dans ce cours, des '''stations de réservation'''. Les entrées des stations de réservation sont assez semblables à celle des fenêtres d'instruction, à un détail près : les opérandes de l'instruction sont enregistrées directement dans des champs séparés. Il y a deux champs, un par opérande, pour stocker l'opérande elle-même, lue depuis les registres ou obtenue via le réseau de contournement. Notons que les champs pour les opérandes viennent en plus des champs pour les noms de registres, encore que les deux peuvent être fusionnés si on veut optimiser le tout. [[File:Entrée d'une station de réservation.png|centre|vignette|upright=3|Entrée d'une station de réservation.]] Précisons que la terminologie n'est pas très fiable. Les termes "fenêtre d'instruction" et "station de réservation" ne regroupent pas du tout la même chose d'un papier de recherche à l'autre, d'un bouquin à l'autre, d'un chercheur à l'autre, d'un ingénieur à l'autre, d'un professeur à l'autre. Le terme initial vient pourtant de l'article original sur l'algorithme de Tomasulo, où il désignait une fenêtre d'instruction associée à une unité de calcul précise. Mais le terme a ensuite été réutilisé, ce qui fait que certains processeurs avec plusieurs unités de calcul sont décrit comme ayant une unique station de réservation. En bref : c'est le bazar ! Mais nous en reparlerons dans le chapitre sur le renommage de registres, car c'est la place idéale pour les aborder. Toujours est-il que j'ai fait le choix de confondre les concepts de fenêtre d'instruction et de station de réservation avec les concepts de '''lecture avant émission''' et de '''lecture après émission'''. La différence entre les deux est que les registres sont lus après émission avec une fenêtre d'instruction, avant avec des stations de réservation. Dans le cas "avant émission", les opérandes sont mémorisées dans la station de réservation. Et cette différence a une influence sur le pipeline du processeur, le banc de registres et tout ce qui s'en suit. Un désavantage de la lecture avant émission est qu'il faut stocker les opérandes après lecture, ici dans les stations de réservation. Mais un avantage est que le banc de registre a besoin de moins de ports de lecture, car une bonne partie des opérandes sont fournies par le système de contournement. Nous verrons cela dans le détail dans le chapitre sur les processeurs superscalaires. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Lecture après émission.]] [[File:Read Before Issue.png|centre|vignette|upright=2.5|Lecture avant émission.]] Il a été proposé de fusionner le tampon de ré-ordonnancement avec la fenêtre d'instruction dans une structure unique. La méthode a notamment été utilisée sur les processeurs d'architecture K6 d'AMD. Le tout donnait une structure appelée le '''DRIS''' (''deferred scheduling register renaming instruction shelf''). La différence avec une fenêtre d’instruction normale est que les entrées sont libérée non pas quand l'instruction est exécutée/émise, mais quand elle termine son exécution et quitte le ROB. La fenêtre d'instruction doit alors incorporer des bits pour savoir si telle entrée a émis sont instruction ou non. ===La logique d'éveil et de sélection=== Dans le cas qui va suivre, on suppose que le processeur ne peut émettre qu'une instruction à la fois. Chaque cycle, une instruction est sélectionnée et est envoyée dans le chemin de données, soit à une ALU, soit à une unité d'accès mémoire. La sélection d'une instruction est effectuée par l'unité d'émission, qui est aussi appelée le '''''scheduler'''''. Elle gère la disponibilité des opérandes et la disponibilité des unités de calcul adéquate. Le choix de l'instruction émise doit être le plus pertinent possible, pour des raisons de performances. Pour le premier point, l'unité d'émission détermine quelles instructions sont candidates pour l'émission. Les ''instructions candidates'' sont celles dont tous les opérandes sont prêts. Le processeur contient un circuit qui détecte les instructions candidates : la '''logique d’éveil''' (''wake-up logic''). Une fois que la logique d'éveil a fait son travail, une instruction est choisie pour s’exécuter en fonction de la disponibilité des unités de calcul adéquates. Ce rôle est dévolu à un circuit qu'on appelle la '''logique de sélection''', ou ''select logic''. [[File:Fonctionnement complet de la logique d’émission.jpg|centre|vignette|upright=1.5|Fonctionnement complet de la logique d’émission.]] La logique de sélection doit gérer le fait que les unités de calcul du processeur ne sont pas toutes identiques. Déjà, un processeur a généralement des unités séparées pour les instructions entières et flottantes, des unités spécialisées dans les accès mémoire, parfois des unités spécialisées pour les branchements. Une instruction doit être attribuée à la bonne unité de calcul, on ne doit pas envoyer une instruction entière dans une unité de calcul flottante. De plus, parmi les unités de calcul entières, toutes ne sont pas identiques. Par exemple, il est fréquent d'avoir plusieurs unités de calcul spécialisées dans les opérations simples (additions, soustractions, opérations logiques) avec une unité pour les multiplications/divisions séparées, parfois une unité spécialisée pour les décalages/rotations, etc. Là encore, allouer la bonne instruction à la bonne ALU est complexe. Plus les unités de calcul sont hétérogènes, plus la logique de sélection est compliquée. Les logiques d'éveil comme de sélection sont assez complexes. Comme on le verra plus bas, la logique de sélection la plus simple, qui gère une seule unité de calcul, est basée sur un encodeur à priorité couplé à d'autres circuits. Et pour gérer plusieurs ALUs, il faut mettre des encodeurs en cascade. Le résultat est que même en prenant une logique de sélection simple, elle sera assez lente et gourmande en circuits. Aussi, la logique de sélection met souvent un cycle d'horloge entier pour faire son travail, elle a son propre étage de pipeline attribué. La logique d'éveil est dans le même cas, ce qui fait qu'émettre une micro-opération demande deux cycles d'horloge. Le défaut est que cela rajoute des cycles d'horloges entre la fenêtre d'instruction et l'ALU, ce qui complique la gestion du pipeline. Ces cycles de retard sont à prendre en compte au moment d'émettre les instructions, les ''scheduler'' doit en tenir compte pour des performances optimales. Sans tenir compte de ces cycles de retard, les instructions arrivent en retard de quelques cycles à l'ALU, cycles de retard durant lesquels l'ALU n'a pas fait de calcul et a été sous-utilisée, sans compter que le système de contournement n'est pas utilisé au mieux. Et le problème est encore plus important sur les processeur avec des stations de réservation, qui utilisent la "lecture après émission" : cela rajoute un cycle d'horloge en plus, un temps de retard en plus. ===La logique d'éveil : l'émission anticipée=== La logique d'éveil doit tenir compte du fait qu'il y a plusieurs étages entre l'émission et l'exécution sur une unité de calcul. Par exemple, un processeur a souvent entre un et à cinq étages entre la file d'attente et les unités de calcul. Il faut lire les registres, gérer le contournement, et cela peut prendre quelques cycles d'horloge. Sur le Pentium 4, on trouve 6 étages entre la fenêtre d’instruction et l'entrée de l'ALU. Si les micro-opérations sont émises quand les opérandes sont disponibles, il y aura un délai de quelques cycles avant qu'elles atteignent l'ALU. Alors qu'idéalement, on souhaiterait que la micro-opération atteigne l'ALU dès que ses opérandes sont disponibles, pour profiter des techniques de contournement. Pour cela, la logique d'éveil émet les instructions quelques cycles en avance pour qu'elles arrivent au bon moment. Il s'agit d'une technique d''''émission anticipée''', dont nous avions parlé dans le chapitre sur le contournement. : Il faut noter que le problème se pose plus avec des fenêtres d'instruction qu'avec des stations de réservation. Les premières ont un étage en plus entre émission et ALU, vu qu'il faut lire des registres après l'émission. L'émission anticipée demande d'émettre un signal d'éveil en avance de quelques cycles, pile au bon moment. Par exemples, si on a deux étages entre l'ALU et l'unité d'émission, le signal de réveil sera généré deux cycles avant que le résultat soit effectivement calculé. L'implémentation varie, mais deux solutions sont possibles. La première est de générer le signal d'éveil dans l'ALU, ce qui n'a de sens que pour les opérations comme les multiplications ou les divisions, qui prennent plusieurs cycles. Une autre technique génère le signal de réveil dans une structure centralisée, spécialisée dans la génération des signaux d'éveil. L'unité de composée d'un registre à décalage par registre. Imaginons qu'une instruction est émise, que cette instruction mette N cycles à s'exécuter, et qu'elle écrive dans un registre de destination. L'unité sélectionne alors le registre à décalage associé au registre de destination, et met le bit numéro N à 1. Le registre décalé d'un cran à chaque cycle. Quand le bit sortant est un 1, alors le signal de validité pour l'opérande est généré. L'émission anticipée marche bien si l'instruction a une durée fixe, connue à l'avance. Et autant c'est le cas pour les instructions arithmétiques et logiques, autant ce n'est pas le cas pour les accès mémoire. Les accès mémoire ont une latence variable : quelques cycles pour un succès de cache, plusieurs dizaines de cycles pour un défaut de cache L1, pas loin de la centaine pour un défaut de cache L2, etc. Et cela pose des problèmes pour l'émission anticipée. L'émission en avance pour les accès mémoire est purement spéculative : le processeur émet des instructions en supposant que la lecture entrainera un succès de cache, quitte à annuler l'instruction en cas de défaut de cache. Mais faire ainsi demande non seulement d'annuler les instructions émises en avance, mais aussi de ne pas retirer les instructions émises en avance de la fenêtre d'instruction. Elles sont émises, mais une copie de sauvegarde est conservée dans la fenêtre d'instruction. Si le processeur détecte un défaut de cache, il peut alors ré-exécuter l'instruction. S'il détecte un succès de cache, les instructions lecture-dépendante sont retirées de la fenêtre d'instruction, la copie de sauvegarde est devenue inutile et est donc jetée. ===La logique de sélection : âge ou position ?=== La logique de sélection est primordiale pour de bonnes performances. Il existe deux méthodes principales pour sélectionner l'instruction à exécuter. La première est la plus simple : elle se base sur lé numéro de l'entrée. En effet, une fenêtre d'instruction est avant tout une sorte de mémoire, un mix entre mémoire associative, mémoire RAM, et FIFO. Et chaque entrée a un numéro, une adresse mémoire. Nous parlerons de numéro dans ce qui suit, car ce sera plus simple, le terme d'adresse mémoire étant peut-être un peu exagéré dans le contexte des fenêtres d'instruction. Toujours est-il que la fenêtre d'instruction est adressable dans le sens où on peut lui envoyer le numéro de l'entrée voulue, et la fenêtre d’instruction renvoie le contenu de l'entrée sur son port de lecture. Et c'est ce que fait la logique de sélection : elle génère le numéro de l'entrée à lire. Le numéro est alors envoyé sur l'entrée d'adresse de la fenêtre d’instruction, et elle fournit la micro-opération associée sur son port de lecture, son '''port d'émission'''. La première méthode de sélection, donc. Elle est basée sur sur le numéro de l'entrée. Si plusieurs entrées sont éveillées, la logique de sélection prend celle avec le plus petit numéro. Elle porte le nom de '''sélection par position''', sous-entendu position dans la fenêtre d'instruction. Vous l'avez peut-être deviné, mais la logique de sélection est alors un encodeur à priorité. Le circuit de sélection ne se résume donc pas seulement à un encodeur à priorité, mais c'est le circuit central. L'avantage d'une telle méthode de sélection est qu'elle est simple à implémenter : un encodeur à priorité est un circuit connu, facile à implémenter. Mais on remarque un défaut : un encodeur est un circuit assez rapide, mais qui utilise beaucoup de transistors, beaucoup de portes logiques, surtout si on veut qu'il soit rapide. Ce qui explique que la logique de sélection ait son propre étage de pipeline rien que pour elle. La seconde méthode s'appelle la '''sélection par âge''', au nom assez transparent. L'idée est de privilégier l'émission de l'instruction la plus ancienne. Elle demande que la fenêtre d'instruction trie les micro-opérations par ordre d'insertion dans la fenêtre d'instruction, ce qui en fait une pseudo-FIFO. Le tri est partiel, car les instructions peuvent sortir de la fenêtre d’instruction à tout moment. Compacter la fenêtre d'instruction, à savoir regrouper toutes les entrées valides est une idée, mais elle est compliquée à implémenter. Aussi, elles préfèrent encoder des informations sur l'ordre d'émission dans chaque entrée. L'encodeur à priorité doit alors travailler non pas sur des nombres entiers liés à l'ordre d'insertion dans la pseudo-FIFO. Elle est encore plus gourmande en circuits que la méthode précédente. Les processeurs haute performance utilisent souvent des méthodes hybrides. Par exemple, les processeurs AMD de microarchitecture Bulldozer utilisaient une méthode intermédiaire. Ils utilisaient une fenêtre d'instruction couplée à un encodeur à priorité pour la sélection par position, mais complémentaient le tout avec une unité qui mémorisait l'instruction la plus ancienne dans la fenêtre d’instruction. Le mécanisme de sélection par âge était utilisé en priorité. Mais si l'instruction la plus ancienne n'était pas prête, le processeur basculait sur le mécanisme de sélection par position. ===La compaction des fenêtres d'instruction=== À chaque cycle, les instructions décodées sont ajoutées dans la fenêtre d'instruction, dans des entrées vides. Vu que les instructions quittent celle-ci dans le désordre, ces vides sont dispersés dans la fenêtre d'instruction, ce qui pose problème pour déterminer où placer les nouvelles instructions. La solution la plus triviale consiste à conserver une liste des vides, mise à jour à chaque insertion ou émission d'instruction. Une autre solution consiste à éliminer les vides en compactant la fenêtre d'instruction à chaque cycle d'horloge. Des circuits se chargent de détecter les vides et de regrouper les instructions en un unique bloc. Il faut signaler que certaines processeurs arrivent à se passer de cette étape de compactage, mais au prix de fenêtres d'instruction nettement plus complexes. Autre problème : quand il faut choisir quelle instruction émettre, il y a toujours plusieurs candidats. Si on choisit mal, des instructions restent en attente trop longtemps parce que d'autres instructions plus jeunes leur passent devant. Pour éviter cela, les instructions les plus vielles, les plus anciennes, sont prioritaires. Pour cela, on peut utiliser une FIFO un peu spéciale pour la fenêtre d'instruction. Si les ajouts d'instruction se font dans l'ordre, les instructions ne quittent pas forcément la fenêtre d'instruction dans l'ordre imposé par une FIFO : les instructions restent triées dans leur ordre d'ajout, même s'il y a des vides entre elles. Dans ces condition, il est préférable que le compactage conserve l'ordre FIFO des instructions. Dans ces conditions, l'instruction la plus ancienne est celle qui est située à l'adresse la plus faible : le circuit de sélection peut donc être fabriqué avec des encodeurs, et est relativement simple. ==Les fenêtres d'instruction basées sur une matrice de dépendances== L'implémentation la plus simple étend le fonctionnement d'un pipeline dynamique usuel. Rappelez-vous le chapitre sur les pipeline dynamiques. Nous avions vu que de tels pipelines émettaient une instruction par cycle, quitte à émettre des bulles de pipeline en cas de dépendance bloquante. Et il est possible d'améliorer leur unité d'émission pour qu'elle soit compatible avec l'exécution dans le désordre. ===Rappels sur le registre de réservation/disponibilité=== L'émission d'une instruction est gouvernée par un ''registre de réservation'' qui indique quels registres sont réservés par une instruction, et ceux qui sont libres. Un registre réservé est un registre qui sera écrit par une instruction en cours d'exécution, mais qui n'a pas encore écrit son résultat. Les instructions candidates doivent avoir leurs opérandes dans des registres libres. Sinon, c'est signe que leurs opérandes sont réservées en écriture, donc pas encore écrites, donc pas disponibles. Si une instruction candidate veut lire ce registre, c'est signe qu'il y a une dépendance RAW : elle veut lire un registre réservé, qui est destiné à être écrit par une instruction en vol. Si elle veut écrire, c'est signe qu'elle veut écrire dans un registre où une autre instruction veut écrire : c'est une dépendance WAW. Dans les deux cas, l'instruction n'est pas émise. Le registre de réservation encode les registres réservés comme suit : chaque bit est associé à un registre. Le bit numéro 0 est associé au registre numéro 0, le bit numéro 1 au registre numéro 1, etc. Là, En clair, les numéros de registres réservés sont encodés en représentation non pas binaire, mais en représentation ''one-hot'' (vue au premier chapitre). {|class="wikitable" |+ Registre de réservation |- ! Registre 7 !! Registre 6 !! Registre 5 !! Registre 4 !! Registre 3 !! Registre 2 !! Registre 1 !! Registre 0 |- | 0 || 0 || 1 || 0 || 0 || 1 || 0 || 0 |} Avant d'émettre une instruction, l'unité d'émission extrait les registres opérande/destination et les convertis dans la même représentation que le registre de réservation, à savoir en représentation ''one-hot''. Le circuit de traduction binaire vers ''one-hot'' est, pour rappel, un simple décodeur. Puis, on fait un OU logique entre les sorties des décodeurs. Le résultat est un masque qui indique quels registres sont lus par l'instruction, encodé en représentation ''one-hot''. Appelons-le le '''masque d'opérandes'''. Le masque est alors comparé au registre de réservation pour vérifier si l'instruction peut être émise. [[File:Unité d'émission simple, dans l'ordre.png|centre|vignette|upright=2|Unité d'émission simple, dans l'ordre]] Si l'émission est autorisée, le registres de réservation est là aussi mis à jour. Le registre de réservation est aussi mis à jour dès qu'une instruction enregistre son résultat dans les registres, ou alors dès qu'il est disponible pour le contournement. Le bit associé au registre repasse alors à 0 (ou à 1). Sans contournement, la mise à jour se fait alors à la toute fin de l'instruction, quand elle se termine, lors de la dernière étape d'enregistrement, à la fin de son pipeline. Avec, elle se fait quand l'instruction quitte l'unité de calcul. ===L'extension à l'exécution dans le désordre : l'éveil par matrice de bits=== La différence entre un pipeline dynamique et l'exécution dans le désordre est que l'on passe d'une instruction à émettre à plusieurs. Plusieurs instructions sont mises en attente dans une fenêtre d’instruction, et y attendent leur tour. L'idée est alors d'envoyer le registre de disponibilité à toutes les entrées, à toutes les instructions en attente. Ainsi, on sait quelles sont les instructions qui peuvent s'exécuter et celles qui ne le peuvent pas. L'implémentation est assez simple, elle ressemble beaucoup à l'implémentation d'un pipeline dynamique simple, si ce n'est que des circuits sont dupliqués. L'implémentation utilise des fenêtres d'instruction légèrement différentes de celles introduites plus haut. Elles n'utilisent notamment pas de bits de disponibilité, mais autre chose. Lorsqu'une instruction est ajoutée à la fenêtre d'instruction, le masque de disponibilité des opérandes est stocké dans la fenêtre d'instruction. A chaque cycle, le registre de disponibilité est envoyée à toutes les entrées, et est comparé avec tous les masques de disponibilité des opérandes. Si une comparaison renvoie un 1, alors l'instruction de l'entrée est une instruction candidate à l'émission. [[File:Unité d'émission dans le désordre basée sur un registre de disponibilité.png|centre|vignette|upright=2.5|Unité d'émission dans le désordre basée sur un registre de disponibilité]] L'ensemble est implémenté avec l'aide d'une '''matrice de bits''', où chaque ligne correspond à une entrée et chaque colonne à un registre. À chaque croisement entre une ligne et une colonne, on trouve un bit. Si le bit de la ligne n et de la colonne m est à 1, cela veut dire : l'instruction dans l'entrée n a besoin de lire le registre m. S’il est à 0, alors cela veut dire que l'instruction stockée dans la ligne n n'a pas besoin de la donnée dans le registre m. [[File:Planificateur à matrice de bits.jpg|centre|vignette|upright=2|Planificateur à matrice de bits.]] Lorsqu'une instruction réserve une entrée, elle initialise la ligne en fonction des registres qu'elle souhaite lire. Pour vérifier si une instruction a ses opérandes prêts, le processeur compare le registre de disponibilité à la ligne associée à l'instruction/entrée. A chaque intersection ligne-colonne, se trouve un comparateur de 1 bit, qui détecte si le registre est demandé et disponible. Les résultats de cette porte sont ensuite envoyés à une porte ET, qui fait le gros du travail. [[File:Logique de détection de la disponibilité d'une instruction.jpg|centre|vignette|upright=2|Logique de détection de la disponibilité d'une instruction.]] ==Les fenêtres d'instruction basées sur une mémoire associative== Les processeurs modernes utilisent une mémoire associative pour la fenêtre d'instruction. Les mémoires associatives ont été abordées il y a quelques chapitres, mais faisons quelques rappels. Les mémoires associatives servent à accélérer la recherche de données dans un ensemble. Or, une fenêtre d'instruction vérifie régulièrement si chaque entrée est prête. Il s'agit d'un processus de recherche d'une instruction qui respecte une condition bien précise dans la mémoire, ce qui fait que les mémoires associatives sont donc tout indiquées. Comme vous le savez, les signaux de commande d'une instruction sont propagés avec celle-ci dans le pipeline, le nom du registre de destination ne faisant pas exception. Le nom de registre est envoyé à la fenêtre d'instruction lors de l'écriture du résultat dans les registres. S'il y a correspondance, l'opérande est disponible et son bit de disponibilité est mis à 1. On peut adapter cette méthode pour tenir compte du contournement assez simplement. [[File:Détection des dépendances par propagation du registre de destination.png|centre|vignette|upright=2|Détection des dépendances par propagation du registre de destination.]] En conséquence, le circuit de détection des dépendances est constitué d'un grand nombre de comparateurs : un par champ « nom de registre » dans chaque entrée. La logique d'éveil/''wake up'' regroupe tous les comparateurs, la logique de sélection est un circuit situé en-dehors de la mémoire associative. Les entrées sont dans la mémoire associative elle-même. [[File:Gestion des bits de validité.png|centre|vignette|upright=2|Gestion des bits de validité.]] L'implémentation la plus simple est celle du schéma précédent, où on utilise une mémoire associative unique. Une version plus élaborée sépare la fenêtre d'instruction en deux parties : une mémoire qui mémorise les registres des opérandes, une autre mémoire pour le reste. La mémoire pour les registres opérandes est la mémoire associative proprement dite, c'est elle qui est associées aux comparateurs, à la logique de ''wake-up''/réveil, etc. Par contre, l'autre mémoire est une mémoire RAM simplifiée, qui mémorise les informations qui n'ont pas besoin des comparateurs. L'opcode de l'instruction est là-dedans, par exemple. ===Les optimisations de la consommation d'énergie : la désactivation des portions inutilisées=== Le problème avec des fenêtres d'instruction de ce type est leur forte consommation énergétique, ainsi que le grand nombre de portes logiques utilisées, qui deviennent prohibitif pour des fenêtres d'instruction un peu grosses. Pour résoudre ce problème, certains ont optimisé les comparateurs. D'autres ont tenté de profiter du fait que la majorité des bits dans les entrées sont composés de zéros. Bref, les optimisations purement matérielles sont légion. Une première solution est de désactiver les entrées qui sont inutilisées, vides, sans instruction. Pour cela, on fait précéder les comparateurs par un circuit qui les connecte ou déconnecte des lignes de bit. Le circuit est commandé par le bit ''empty'' qui indique si une entrée est vide ou non. L'avantage est que la consommation d'énergie de la fenêtre d'instruction devient alors proportionnelle au nombre d'entrées non-vides, et non au nombre d'entrées total. Du moins, en apparence, les entrées non-utilisées doivent quand même être alimentées pour fonctionner, mais l'activité de comparaison disparait dans les entrées vides. Il est possible d'étendre cette technique aux entrées dont les opérandes sont prêtes. Les gains sont généralement assez bons, avec une réduction de consommation variant entre 30 et 50%, avec une implémentation très simple et très économe en circuits. Une autre solution, assez simple à mettre en place, consiste à désactiver une partie de la fenêtre d'instruction sin elle est inutilisée. Pour cela, il faut segmenter la fenêtre d'instruction avec la technique du ''wire partitionning''. Pour rappel, une fenêtre d'instruction est une mémoire associative. Et comme toute mémoire associative, elle contient des fils, les lignes de bit, qui relient les entrées/sorties à toutes les cellules mémoire. Plus une ligne de bit est longue, plus elle consomme d'énergie et plus le temps de lecture/écriture est long. L'idée est de segmenter les lignes de bits en plaçant des répéteurs qui recopient la tension d'un segment au suivant. Les répéteurs sont des tampons trois-états, ce qui permet de déconnecter les portions inutilisées de la ligne de bit. Ce faisant, la fenêtre d'instruction est découpée en segments, qui peuvent être désactivés si besoin. Si il y a peu d'instructions chargées dans la fenêtre d'instruction, les portions inutilisées sont désactivées. La technique marche d'autan mieux si les instructions sont compactées au début de la fenêtre d'instruction. [[File:Wire partitionning.png|centre|vignette|upright=2|Wire partitionning]] Tout le problème est de savoir quelles portions désactiver. La technique est assez simple si la fenêtre d'instruction est compactée, à savoir si toutes les instructions sont régulièrement regroupées au début de la mémoire CAM. Mais même avec cette optimisation, la décision de désactiver une portion de la fenêtre d'instruction n'est pas à prendre à la légère. Il ne faut pas désactiver une portion contenant des instructions pouvant être émise sous peu. La décision dépend de paramètres variés : proportion d'entrée vides, quantité d'entrées récemment activées/désactivées récemment, présences d'entrées avec un ''match'' d'opérandes récent, etc. Il est important de préciser que les techniques en question fonctionnent aussi sur les autres types de fenêtre d'instruction, qui ne sont pas basées sur des mémoires associatives. Nous allons voir celles-ci dans la suite du chapitre, mais gardez à l'esprit que ces optimisations, à savoir désactiver les entrées vides/prêts et partitionner la fenêtre d'instruction, sont des optimisations générales qui marchent avec presque tout. ===L'ajout d'une FIFO pour les instructions déjà prêtes à l'émission=== D'autres techniques permettent de réduire aussi bien le cout en circuits que la consommation d'énergie de la fenêtre d'instruction. L'idée est d'utiliser une mémoire associative quand elle est réellement nécessaire, mais d'utiliser une fenêtre d'instruction "normale" dès que possible. La méthode la plus simple tient compte du fait que certaines instructions ont déjà toutes leurs opérandes de disponibles à l'émission, mais doivent quand même être mises en attente, parce que l'ALU adéquate est occupée, parce que des dépendances WAW/WAR sont encore là, ou pour tout autre raison. Dans ce cas, elles sont mises en attente non pas dans la fenêtre d'instruction, mais dans une mémoire FIFO toute simple. L'idée est qu'au lieu d'avoir une énorme mémoire associative pour la fenêtre d'instruction, on déplace quelques entrées dans une petite FIFO annexe. Le résultat est un gain en terme d'énergie et de circuits, au prix d'une perte de performance mineure. La perte de performance en question se manifeste si aucune instruction n'a ses opérandes de prêtes à l'émission : le programme n'utilise pas la FIFO et voit alors une fenêtre d'instruction plus petite. Une amélioration de cette technique tient compte du fait que certaines instructions sont dans un cas intermédiaire. Elles ont déjà une opérande de prête lors de l'émission, mais pas l'autre. Le nombre d'opérandes varie suivant l’instruction : certaines n'ont besoin que d'un seul opérande. De plus, il arrive qu'une opération tout juste décodée ait déjà un ou plusieurs de ses opérandes de prêts. Cette constatation permet d'éviter d'utiliser des comparateurs pour les opérandes déjà prêts. Par exemple, on peut parfaitement utiliser trois fenêtres d'instruction : * une pour les instructions dont tous les opérandes sont prêts, mais qui sont quand même mises en attente, sans comparateur ; * une pour les instructions dont un seul opérande manque, qui n'utilise qu'un comparateur par entrée ; * une pour les instructions dont deux opérandes manquent à l'appel, qui utilise deux comparateurs par entrée. C'est beaucoup plus économique que d'utiliser une seule grosse fenêtre d'instruction qui contiendrait autant d'entrées que les trois précédentes réunies, avec deux comparateurs par entrée. Certains sont même allés plus loin, et ont proposé de supprimer la fenêtre d'instruction avec deux opérandes par entrée. Les instructions dont deux opérandes sont inconnus au décodage sont stockées dans la fenêtre d'instruction pour instructions avec un comparateur par entrée. Un circuit de prédiction se charge alors de prédire l'opérande manquant, cette prédiction étant vérifiée plus loin dans le pipeline. Il serait cependant étonnant qu'une telle proposition ait donné lieu à la moindre implémentation réelle. ===Les optimisations de la consommation d'énergie avancées=== D'autres chercheurs ont conservé une fenêtre d'instruction unique, avec autant de comparateurs par entrée qu'il y a d'opérandes possibles par instruction. Simplement, le processus de détection des opérandes prêts est légèrement ralenti : on ne vérifie qu'un opérande par cycle. Pour vérifier les deux opérandes d'une entrée, on doit attendre deux cycles. Enfin, certains chercheurs ont proposé des fenêtres d'instruction segmentées. Les instructions circulent à chaque cycle d'un segment vers le suivant : en conséquence, certains segments conservent les instructions les plus anciennes, un autre les instructions les plus jeunes, etc. Seul le denier segment, celui qui contient les instructions les plus vielles, peut émettre une instruction : la détection des opérandes se fait seulement dans le dernier segment, qui contient les instructions les plus anciennes. On économise ainsi beaucoup de comparateurs. Certains chercheurs ont tenté de pipeliner l'étape de sélection des opérandes, ainsi que l'étage d'arbitrage. Mais en faisant cela, il faut plusieurs cycles pour détecter qu'une instruction a ses opérandes prêts, ce qui pose problème face à de nombreuses dépendances RAW. Pour éviter de trop perdre en performances, certains chercheurs ont décidé d'utiliser des techniques pour prédire quelles seront les instructions dont les opérandes seront bientôt prêts. Si détecter qu'une instruction est prête prend n cycles, le processeur devra tenter de prédire la future disponibilité des opérandes n cycles en avance pour obtenir des performances optimales. ===Remplacer la mémoire associative par une RAM=== Une autre optimisation possible est de remplacer la fenêtre d'instruction par une mémoire RAM, dont chaque mot mémoire correspondrait à une entrée. Une telle optimisation permet en théorie de se passer des comparateurs associés à chaque entrée, mais au prix de l'ajout de circuits annexes potentiellement couteux. La première de ces techniques, la '''recherche directe par étiquette''' (direct tag search) fut créée par Weiss et son collègue Smith. Ils cherchaient à améliorer l'algorithme de Tomasulo, un algorithme qu'on expliquera dans quelques chapitres. Rappelons que chaque instruction produit un résultat, qui devra être rapatrié dans une ou plusieurs entrées de la fenêtre d'instruction. L'optimisation de la recherche directe par étiquette fonctionne dans le cas où le résultat de l'instruction n'est utilisé que par une seule entrée, et pas plusieurs. Le principe est simple : chaque champ « opérande » d'une entrée est adressable via le nom de registre de cette opérande. Pour faire le lien entre entrée et nom de registre, la recherche directe par étiquette ajoute une table de correspondances matérielle, une mémoire RAM qui mémorise les adresses des champs « opérande » des entrées. Les adresses envoyées dans cette mémoire sont les noms de registres des résultats. Lors de l'émission, la table de correspondances est mise à jour. Les numéros des champs « opérande » réservés lors de l'émission sont mémorisés dans les mots mémoire qui correspondent aux deux registres sources. Toutefois, une petite vérification est faite lors de l'émission : si il y a déjà une correspondance dans la table pour un registre source, alors une autre instruction compte lire ce registre. Pour éviter d'écraser les données de l'instruction précédente dans la table de correspondances, l'émission de l'instruction est bloquée. [[File:Recherche directe par étiquette.png|centre|vignette|upright=2|Recherche directe par étiquette.]] ==Les fenêtres d’instruction avec préplanification== Avec la '''préplanification''' (''prescheduling''), la fenêtre d’instruction est composée de mémoires FIFO dans lesquelles les instructions sont triées dans l'ordre d'émission. Il n'y a pas de logique d’émission proprement dite, celle-ci se bornant à vérifier si l'instruction située au début de la FIFO peut s’exécuter. Par contre, le préplanificateur détecte les dépendances et en déduit où insérer les instructions dans le tampon d'émission, à l'endroit le plus adéquat. [[File:Préplanification.jpg|centre|vignette|upright=2|Préplanification.]] ===L'usage de FIFO multiples=== La technique de préplanification la plus simple utilise plusieurs FIFO. Quand une instruction a une dépendance avec une autre instruction, les deux sont placées dans la même FIFO. Pour cela, le préplanificateur détecte les chaines d'instructions dépendantes, et place les instructions dans la FIFO adéquate. A chaque cycle, l'unité d'émission lit une micro-opération dans chaque FIFO et vérifie si elle peut l'émettre. Si la micro-opération n'a pas ses opérandes disponibles, ou qu'une dépendance structurelle survient, alors la FIFO est bloquée. La micro-opération attend que la dépendance soit résolue, bloquant toutes les instructions précédentes. Mais les autres FIFO ne sont pas bloquées, laissant de la marge de manœuvre. [[File:Préplanification par FIFO multiples.png|centre|vignette|upright=1.5|Préplanification par FIFO multiples.]] ===La technique du tampon trié=== La technique du '''tampon trié''' trie les instructions selon le temps d'attente avant leur exécution. Les instructions qui sont censées s’exécuter bientôt sont insérées au tout début de la FIFO, tandis que les instructions qui s’exécuteront dans un long moment sont insérées vers la fin. Là encore, l'unité d'émission lit une micro-opération dans la FIFO, et détermine si elle peut être émise. Si une dépendance survient, l'émission est retardée, et la FIFO est bloquée. [[File:Préplanification par tampon trié.png|centre|vignette|upright=1.5|Préplanification par tampon trié.]] La technique a cependant quelques problèmes assez importants. Le premier problème est que la FIFO est bloquée lorsqu'une micro-opération ne peut être émise. Le second problème est que le temps avant exécution n'est pas toujours connu, notamment pour les instructions d'accès mémoire. Et cela se répercute sur les instructions dépendantes de celles-ci. Pour résoudre ce genre de problèmes, l'usage d'un pipeline à ''replay'' est possible, et est même l'une des meilleures solution possible, malgré ses défauts. L'idée est que les lecture sont pré-planifiées en supposant qu'elles font un succès de cache L1. Si la prédiction est fausse, la lecture est ré-exécutée plusieurs cycles plus tard, en supposant qu'elle fait un succès dans le cache L2, et ainsi de suite. Elle est alors ré-insérée dans la FIFO, elle est pré-planifiée une seconde fois. Il en est de même si une micro-opération ne peut pas être émise : il suffit de la réinsérer dans la FIFO au bon endroit, en attendant que ses dépendances soient résolus. Ainsi, l'instruction fautive ne bloque pas la fenêtre d’instruction, et retente sa chance autant de fois qu'il le faut. [[File:Préplanification par fenêtre d’instruction scorebarodée.png|centre|vignette|upright=1.5|Préplanification par fenêtre d’instruction scorebarodée.]] Une autre solution utilise deux fenêtres d’instruction : une FIFO gérée par la préplanification, et une vraie fenêtre d'instruction pour les instructions dont le temps d'attente ne peut pas être déterminé. Il est possible de mettre cette dernière avant la préplanification, afin de gérer les temps d'attente des instructions d'accès mémoire. Quand le temps d'attente d'une lecture devient connu, ses instructions dépendantes sont gérées avec préplanification. [[File:Préplanification avec fenêtre d’instruction.png|centre|vignette|upright=2.5|Préplanification avec fenêtre d’instruction.]] ===Les fenêtres d'instruction avec allocation temporelle statique=== L''''allocation temporelle statique''' correspond à une technique utilisée sur les processeurs Cuzco de l'entreprise Condor. La technique en question a été présenté en 2025, mais des idées similaires ont été présentées dans la littérature académique. Elle ressemble beaucoup aux techniques de pré-planification, avec cependant quelques différences. L'idée est simple : le processeur dispose de plusieurs fenêtres d'instruction, qui mettent en attente les micro-opérations. Lors de l'étape de renommage de registres, le processeur détermine dans combien de cycles d'horloge la micro-opération sera prête pour exécution. La micro-opération est alors mise en attente durant ce nombre de cycles, dans les fenêtres d'instruction, puis est émise une fois ce nombre de cycles écoulés. Ce faisant, les fenêtres d'instruction n'ont pas besoin de détecter la disponibilité des opérandes à chaque cycle, pour chaque micro-opération en attente. Le ''timing'' de l'émission des micro-opérations est décidé à l'avance. L'implémentation exacte n'est pas connue, mais plusieurs solutions sont imaginables. Par exemple, la fenêtre d'instruction peut simplement être composée de plusieurs mémoires de petite taille, chacune contenant les micro-opérations destinées à être exécutées dans N cycles, N étant différent pour chaque mémoire. Une autre solution, plus réaliste, utilise une fenêtre d'instruction dans laquelle la micro-opération est couplée à des champs pour les opérandes, et un champ compteur. Le champ compteur est initialisé avec le nombre de cycles à attendre, et est décrémenté à chaque cycle d'horloge. Quand il atteint zéro, la micro-opération est émise. Vous remarquerez que la méthode ne marche que si toutes les micro-opérations prennent un nombre fixe de cycles d'horloge. Et autant c'est le cas pour les micro-opérations arithmétiques ou logiques, autant les accès mémoire ne rentrent pas dans ce cadre. En théorie, on ne sait pas combien de temps prendra un accès mémoire. Et cette incertitude se répercute sur les instructions dépendantes d'un accès mémoire. Pour éviter cela, le processeur réutilise un pipeline à ''replay'' tel que vu dans le chapitre précédent. L'unité de renommage de registre suppose que tout accès mémoire fait un succès de cache L1, et décide des ''timings'' d'émission sous cette hypothèse. Si une lecture subit un défaut de cache, elle est ré-exécutée, de même que toutes les instructions dépendantes. Pour cela, le registre de destination de la lecture est marqué comme invalide, grâce à un bit spécifique attaché au registre. Toute instruction qui lit une opérande invalide est elle aussi ré-executée de zéro. Pour simplifier, l'unité d'émission ressemble à une unité d'émission dans l'ordre, avec un registre de disponibilité, qu'on aurait amélioré pour aller au-delà de la simple détection des dépendances d'instruction. Pour déterminer les ''timings'' d'émission, à savoir quand émettre une micro-opération, le processeur utilise une unité d'émission à deux étages. Le premier étage est appelé le ''register scoreboard'', le second étage est appelé la ''Time Ressource Matrix''. Les deux étages communiquent entre eux, comme on va le voir, et leurs noms donnent une idée de ce qu'ils font. Le premier étage gère les dépendances de registres, le second gère les dépendances structurelles. Le premier étage est un registre de disponibilité amélioré, qui gère les dépendances de registre. Cet étage sait quand tel registre sera écrit, et donc que l'opérande écrite dedans sera disponible à partir de tel cycle d'horloge. Il le sait car l'étage suivant l'aura prévenu, mais laissons cela de côté pour le moment. Quand une micro-opération rentre dans cet étage, il vérifie les dépendances avec les registres et les micro-opérations antérieures. Vu qu'il sait quand les registres seront disponibles, il peut déterminer quand l'instruction pourra s'exécuter. Par exemple, si une micro-opération lit les deux registres R7 et R15, qui sont disponibles respectivement dans 5 et 7 cycles, le premier étage sait que la micro-opération devra attendre 7 cycles. Mais tout cela ne suffit pas à déterminer quand émettre une micro-opération. En effet, il fait aussi gérer les dépendances structurelles, ce qui est le boulot du second étage. Le second étage utilise pour cela une ''Time Ressource Matrix'', qui mémorise l'occupation de diverses "ressources", pour les 256 cycles d'horloge à venir. Les ressources en question sont les ports de lecture/écriture du banc de registre, les ALUs utilisées, si la micro-opération utilise l'unité mémoire, etc. Le second étage prend en entrée une micro-opération, détermine quelles "ressources" elle utilise, puis regarde leur disponibilité. Elle détecte alors les dépendances structurelles et détermine alors quand peut s'exécuter la micro-opération. Elle peut retarder l'émission de quelques cycles, si une dépendance structurelle est détectée. Une fois sortie du second étage, on sait quand la micro-opération va être émise, à quel cycle précisément. Et vu que la durée de l'instruction est fixe, on sait quand cette micro-opération va se terminer, quand son résultat sera disponible. Cela permet de mettre à jour la ''Time Ressource Matrix'', pour préciser que le port d'écriture sera occupé à tel moment. De plus, cette information est transmise au premier étage, qui sait alors quand est enregistré le résultat dans le registre de destination. C'est comme cela que le premier étage sait quand un registre est disponible : le second étage le prévient, quand il émet une instruction ! La ''Time Ressource Matrix''mémorise l'occupation des "ressources" pour les 256 cycles d'horloge à venir. Cependant, elle ne vérifie pas les dépendances pour les 256 cycles suivants. Quand elle reçoit une micro-opération, elle teste les dépendances structurelles pour seulement les 8 prochains cycles maximum. Si la micro-opération ne peut pas être émise pendant ces 8 cycles, le pipeline est bloqué, un ''pipeline stall'' est émis. Pour être plus précis, vu que le processeur peut décoder 8 micro-opérations en même temps, cela permet de ne consulter que 64 cycles d'horloge sur les 256. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les premiers processeurs Intel | prevText=Les premiers processeurs Intel | next=Le renommage de registres | nextText=Le renommage de registres }} </noinclude> ewyb8vtfjc9p5cogongxo90g9jyuzt3 773602 773601 2026-09-29T19:42:24Z Mewtow 31375 /* Les entrées d'une fenêtre d’instruction */ 773602 wikitext text/x-wiki Dans les chapitres précédents, nous avons parlé des techniques dites d''''émission dans l'ordre'''. L'idée est d’exécuter une nouvelle micro-opération à chaque cycle, dans des unités de calcul séparées. Les instructions sont émises consécutivement, mais les instructions s’exécutent en parallèle dans des unités de calcul séparées. Par contre, quand l'unité d'émission ne peut pas émettre une instruction, elle bloque tout le pipeline. Les instructions qui suivent sont elles aussi bloquées, elle doivent attendre leur tour, même si elles sont en capacité de s'exécuter. Les techniques d'exécution dans le désordre que nous allons voir dans ce chapitre corrigent ce point précis. Elles sont dites à '''émission dans le désordre'''. Elles se distinguent des précédentes sur un point précis : quand l'unité d'émission bloque l'émission d'une instruction, les instructions suivantes peuvent poursuivre. L'émission des instructions peut donc se faire dans le désordre, dans le sens où une instruction peut être émise alors qu'une instruction précédente ne l'est pas encore. L'avantage de l'émission dans le désordre est qu'une instruction s'exécute dès que ses opérandes sont disponibles. Par disponible, on veut dire présent soit dans le réseau de contournement, soit dans les registres. Le processeur détecte automatiquement quand les opérandes d'une instruction sont sont disponibles, et il l’exécute à ce moment là. Dès qu'une instruction a ses opérandes disponibles, elle est émise et exécutée. C'est là la seule contrainte : les dépendances WAR, WAW et autres sont gérées par un ROB ou toute autre technique d'exception précise, seules les dépendances RAW limitent l'exécution. Mais avant de poursuivre, quelques point niveaux terminologie : * L'émission dans le désordre est un terme parlant et assez précis. Malheureusement, la terminologie la plus utilisée par d''''exécution dans le désordre'''. Et nous utiliserons ce terme dans la suite du cours, histoire de ne pas trop dévier de la nomenclature habituelle. * Nous utiliserons parfois l'abréviation OOO pour parler d'exécution dans le désordre. L'abréviation est celle de ''Out Of Order Excution''. * Nous utiliserons aussi l'abréviation ''µop'' pour parler de micro-opération, ''µops'' au pluriels pour parler de plusieurs micro-opérations, ou des micro-opérations en général. L'exécution dans le désordre ne gére en effet que des µops, elle se situe après l'étape de décodage. Mais avant de poursuivre, précisons une chose importante : l'exécution dans le désordre traite les accès mémoire à part. La majorité des processeurs OOO assez anciens exécutent les accès mémoire dans l'ordre, seules les µops entières/flottantes/branchements sont exécutées dans le désordre. Les processeurs datant d'après les années 2010 sont capable d'exécuter les accès mémoire dans le désordre, mais l'implémentation en question est assez particulière. Un chapitre entier sera dédié à l'exécution dans le désordre des µops mémoire. Nous allons volontairement mettre de côté la gestion des accès mémoire dans ce chapitre. ==Les fenêtres d’instruction : généralités== [[File:File de micro-opération.png|vignette|upright=1|File de micro-opérations]] Pour décrire comment est implémentée l'émission dans le désordre, il faut commencer par parler des processeurs sans. Les processeurs sans exécution dans le désordre ont une unité d'émission qui bloque tout le pipeline dès qu'une µop ne peut pas être émise. Pour limiter l'impact de ce blocage, quelques rares processeurs incorporent une '''file de micro-opération''', une mémoire FIFO qui met en attente les µops. Vu que c'est une mémoire FIFO, les µops sont émises dans l'ordre, à savoir l'ordre d'ajout, dans l'ordre de décodage. Le schéma ci-dessous illustre une telle file d'attente couplée à un ''scoreboard''. Sur le principe, l'exécution dans le désordre améliore la file de µops sur un point : ce n'est plus une mémoire FIFO. Les µops sont insérées dans l'ordre, mais peuvent sortir dans le désordre (être émises dans le désordre). La file de µops devient alors une '''fenêtre d'instruction''', terme traduit directement de l'anglais ''instruction Window''. Terme assez trompeur, car elles mettent en attente des µops, pas des instructions. Elles peuvent émettre des µops dans le désordre, ce qui fait que si une µop bloque le pipeline, les µops suivantes peuvent être émises. Si je commence le paragraphe précédent par "sur le principe", c'est car certaines techniques d'OOO utilisent des files de µops normales. Il est par exemple possible d'utiliser une file de µops avec une fenêtre d'instruction, plusieurs files de µops, plusieurs fenêtres d'instructions avec une file de µops annexe, etc. Dasn les grandes lignes, il existe dans les grandes lignes 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! File de µops améliorée |- ! Une seule "file de µops" | ''Scoreboard'' | Fenêtre d'instruction centralisée |- ! Plusieurs "file de µops" | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | Fenêtre d'instruction décentralisée |} ===La fenêtre d'instruction centralisée=== L'implémentation la plus simple de l'OOO utilise une unique '''fenêtre d'instruction'''. Les instructions décodées sont accumulées dans la fenêtre d'instruction, où elles attendent que leurs opérandes soient disponibles. La fenêtre d'instruction sert donc de file d'attente. Mais elle contient aussi une unité d'émission, qui détecte quelles µops sont prêtes à être émises. L'unité d'émission et la fenêtre d'instruction sont fusionnées ensemble, elles forment un seul circuit. Mais nous allons dire qu'elles sont conceptuellement séparées pour le moment. A chaque cycle, l'unité d'émission consulte la fenêtre d'instruction pour voir quelles µops peuvent s'exécuter, lesquelles ont leur opérandes de disponibles. La fenêtre d'instruction doit spécialement être conçue pour, c'est une sorte de mémoire associative très complexe, comme on le verra dans ce qui suit. [[File:OOO Issue.png|centre|vignette|upright=2.5|Exécution dans le désordre avec une fenêtre d'instruction]] Une fois qu'une µop sort du décodeur d'instructions, elle est ajoutée en parallèle dans la fenêtre d'instruction et le ROB. La raison est que les µops quittent la fenêtre d'instruction dans le désordre, et qu'elles doivent être remises en ordre par la suite. Le ROB s'occupe de cette remise en ordre, mais il a besoin de savoir dans quel ordre les µops sont censées être, et cet ordre est celui du décodage. Aussi, pour remplir le ROB, la seule opportunité est en sortie de l'unité de décodage. Dans le cas où une instruction est décodée en plusieurs micro-opérations, elles sont toutes insérées en même temps dans la fenêtre d'instruction et le ROB, en tenant compte de leur ordre. [[File:Fenêtre d'instruction.png|centre|vignette|upright=2|Fenêtre d'instruction.]] Les micro-opérations mémoire sont à part des autres, pour diverses raisons. Une de ces raisons est que les dépendances de données sont classées en deux types : les dépendances de registre et les dépendances d'adresse. Et les deux sont fondamentalement différentes. Autant on peut détecter les dépendances de registre lors de l'émission, autant c'est plus compliqué avec les dépendances d'adresse. De plus, rappelons que si les lectures peuvent s'exécuter dans le désordre, les écritures doivent s'exécuter dans l'ordre, ou du moins en donner l'illusion. Pour cela, le processeur remet les écritures dans l'ordre avec une sorte de mini-ROB intégré à l'unité mémoire, appelée la file d'écriture. Elle complémente le ROB, qui lui ne gère que les écritures dans les registres, mais les deux collaborent. La file d'écriture envoie une écriture à la mémoire RAM quand le ROB lui dit que c'est bon, les instructions précédentes sont terminées ''dans l'ordre du programme''. Les processeurs modernes ajoutent des techniques d'exécution dans le désordre des accès mémoire, mais nous les verrons dans un chapitre dédié. Elles permettent d'utiliser une fenêtre d'instruction unique, qui mémorise aussi les µops mémoire. Si elles sont mises en place, l'unité mémoire n'a pas besoin de file de µops séparée. L'idée est que les dépendances de registre sont traitées par la fenêtre d'instruction, mais que l'unité mémoire gére les dépendances d'adresse. Les dépendances d'adresse sont gérées par des techniques de ''désambiguation mémoire'', qui auront droit à un chapitre dédié. [[File:Processeur avec exécution dans le désodre des accès mémoire.png|centre|vignette|upright=2|Processeur avec exécution dans le désodre des accès mémoire]] Les processeurs assez anciens n'autorisaient pas d'exécution dans le désordre des accès mémoire. Concrétement, les accs mémoire devaient se faire dans l'ordre, mais les autres µops pouvaient être exécutées dans le désordre. Il s'agit donc d'un ordre entre µops mémoire, pas entre µops mémoire et autres µops. Les µops entières et flottantes pouvaient être exécutées avant une µops mémoire qui est avant elle dans l'ordre du programme, ce n'est pas un problème. Pour garantir l'ordre desd µops mémoire, l'unité mémoire est précédée par une file de micro-opérations séparée, pour forcer l'exécution dans l'ordre des accès mémoire. De plus, les µops mémoire ne peuvent pas utiliser la fenêtre d'instruction. Dit autrement, la fenêtre d'instruction ne mémorise pas de µops mémoire. Après le décodage, les µops sont réparties soit dans la file de µops mémoire, soit dans la fenêtre d'instruction. Le décodeur classe les µops suivant que ce sont des µops mémoire ou non, et les envoient à la bonne destination. Dans ce chapitre, on supposera que c'est cette solution qui est utilisée. [[File:Processeur avec émission dans l'ordre des accès mémoire.png|centre|vignette|upright=2|Processeur avec émission dans l'ordre des accès mémoire]] La solution précédente revient à scinder la fenêtre d'instruction en deux : une file de µops pour les µops mémoire, une fenêtre d'instruction pour les autres µops. Et cette scission peut aller plus loin, à savoir qu'on peut scinder une fenêtre d'instruction encore et encore. Ce qui nous amène à la section suivante. ===Les fenêtres d'instruction décentralisées=== Nous venons de voir qu'il est possible de scinder la fenêtre d'instruction en une fenêtre d'instruction pour les µops mémoire (simplifiée en une file de µops classique), et une autre pour les autres µops. Sachez qu'il est possible d'aller plus loin, par exemple en séparant la fenêtre d'instruction en une fenêtre spécialisée dans les µops flottantes et une autre pour les µops entières. Et ce n'est là qu'un exemple parmi de nombreuses autres possibilités. Pour faire la différence avec une fenêtre d'instruction unique, nous allons parler de fenêtre d'instruction centralisée s'il n'y en a qu'une, de '''fenêtre d'instruction décentralisée''' s'il y en a plusieurs. Il est possible d'associer chaque fenêtre d'instruction à un type précis de µops. Par exemple, avec une fenêtre d'instruction pour les µops de calcul entières, une autre pour les µops flottantes, une autre pour les µops mémoire. Il s'agit d'un choix simple et efficace, mais quelques processeurs font autrement, pour répondre à des contraintes très diverses. [[File:Processeur avec des fenêtres d'instruction décentralisées.png|centre|vignette|upright=2|Processeur avec des fenêtres d'instruction décentralisées]] Reste à scinder la fenêtre d'instruction pour trier les µops suivant leur type. Si le processeur exécute les accès mémoire dans l'ordre, la méthode la plus simple utilise une fenêtre d'instruction pour les opérations flottantes et une autre pour les autres µops (µops entières et parfois mémoire avec). L'avantage est que cela simplifie grandement le processeur. Les flottants sont gérés à part des entiers. Ils ont leurs propres registres, des FPU séparées des ALU entières, bref : la séparation est complète. Utiliser une fenêtre d'instruction séparée va dans ce sens. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Il est possible de faire pareil sur les processeurs avec exécution dans le désordre des accès mémoire. Par exemple : les processeurs Intel de microarchitecture Skylake utilisent une fenêtre d'instruction pour les opérations entières/flottantes, et une fenêtre d'instruction séparée pour les µops mémoire. Un avantage est que les deux fenêtres d'instructions sont plus spécialisées, ce qui entraine des économies de circuit. Les opérations entières/flottantes ont besoin de deux registres pour les opérandes et d'un autre résultat, alors que les µops mémoire n'ont besoin que de deux registres maximum. En utilisant une fenêtre d'instruction unique, chaque entrée doit mémoriser l'opcode et trois registres, dont un est inutilisé pour les µops mémoire et les branchements. En utilisant des fenêtres d’instructions séparées, celle pour les µops entières/flottantes a trois registres par entrée, contre seulement deux registres par entrée pour celle des µops mémoire. Un cas extrême est celui où chaque ALU/FPU a sa propre fenêtre d'instruction. Nous parlerons alors de '''fenêtres d'instruction totalement décentralisées'''. Par exemple, il y a une fenêtre d'instruction pour l'ALU entière, une autre pour le multiplieur entier, une autre pour le ''barrel shifter'', une autre pour l'unité mémoire, une autre pour l'unitéé de branchements, une autre pour l'additionneur flottant, une dernière pour le multiplier flottant, etc. Un exemple historique est celui de la FPU de l'IBM 360 modèle 90. Elle disposait d'un additionneur flottant, d'un multiplieur flottant, et d'une unité mémoire pour les lectures/écritures flottantes. Les trois unités avaient leur propre fenêtre d'instruction. Les processeurs AMD utilisent beaucoup cette technique, contrairement à Intel qui préfère utiliser des fenêtres centralisées sur les anciens processeurs, deux ou trois fenêtres sur les processeurs récents (2020 et plus). Les processeurs AMD utilisaient précisément une fenêtre d'instruction par ALU entière, alors que les FPUs partagent une fenêtre d’instructions flottantes unique. Mais nous verrons cela en détail dans le chapitre sur les processeurs superscalaires x86. Un point important est qu'avec des fenêtres d'instruction décentralisées, l'émission est découpée en deux étages. La première étape envoie une µops vers la fenêtre d'instruction adéquate, la seconde émet la µops depuis la fenêtre d'instruction quand ses opérandes sont prêtes. La première est l'étage de '''''dispatch''''' qui envoie l'instruction dans la fenêtre d’instruction adéquate, selon que c'est une instruction flottante, entière, autre. La seconde est l'étage de '''''scheduling''''', qui gère la disponibilité des opérandes et des unités de calcul. La µop émise est ajoutée au tampon de réordonnancement, s'il existe, lors de l'étape de ''dispatch''. ===L'usage de plusieurs files d'instruction=== Une dernière méthode d'OOO utilise plusieurs files de micro-opération. L'idée est qu'une fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement une file de micro-opération pour les opérations entières, une autre pour les opérations flottantes, une autre pour les accès mémoire. D'autres processeurs utilisent une file pour les accès mémoire et une autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. La présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que la technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si une dépendance bloque une FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans une autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer la disponibilité des registres. Quand un registre est lu ou écrit par une instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. La logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : une pour les instructions d'accès mémoire et une autre pour les autres instructions. Si jamais une instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de la lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'une est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est la file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. ===Avantages et inconvénients de chaque implémentation=== Pour résumer, on a le choix entre une grosse fenêtre d'instruction généraliste et plusieurs fenêtres spécialisées. Le choix entre les deux est un compromis entre économie de circuits et flexibilité. Avec une fenêtre décentralisée, il arrive qu'une fenêtre d'instruction soit remplie, alors que les autres sont sous-utilisées, voire vides. Pour comprendre pourquoi, comparons une fenêtre d'instruction unique, avec une fenêtre décentralisée séparant µops entières et flottantes. La fenêtre centralisée dispose de 64 entrées, la décentralisée a 32 entrées pour chaque fenêtre d'instruction. La fenêtre décentralisée peut mémoriser au maximum 32 µops entières et 32 *ops flottantes. Par contre, la fenêtre centralisée peut mémoriser 64 µops tout court. Si le programme exécuté n'utilise pas de nombres flottants, la différence devient flagrante. La fenêtre décentralisée sera limitée ) 32 µops, alors que la centralisée pourra mémoriser le double. Les performances seront donc meilleurs avec la fenêtre centralisée. Et au-delà de ça, la fenêtre décentralisée de l'exemple est utilisée de manière optimale si la moitié des µops sont des µops entières, et l'autre moitié des µops flottantes. Alors que la fenêtre centralisée se moque de la répartition entre µops entières et flottantes. Une subtilité est que le cout en transistors d'une fenêtre d'instruction n'est pas proportionnel au nombre de µops qu'elle peut mémoriser. Par exemple, si je compare une fenêtre d'instruction de 32 entrées (32 µops max), elle n'utilise pas deux fois plus transistors qu'une fenêtre de 16 entrées. Le cout en circuit n'est pas deux fois plus élevé, mais est approximativement 4 fois plus élevé. Le cout est presque quadratique, à savoir qu'il est proportionnel au carré du nombre d'entrées. Et il en est de même avec la performance, pour des raisons qu'on expliquera plus bas. Les fenêtres décentralisées utilisent plusieurs fenêtres d'instruction de "petite taille", donc plus rapides, économes en circuits et économes en énergie. Le compromis n'est donc pas entre une fenêtre centralisée à 64 entrées versus deux fenêtres de 32 entrées. Le compromis en pratique est entre une fenêtre centralisée de 64 entrées versus 3 fenêtres de 32 entrées. Un exemple pratique est celui de la microarchitecture ''Skylake'' d'Intel. Intel est passé d'une fenêtre centralisée pre-''Skylake'' à deux fenêtres décentralisées sur ''Skylake'',. Le nombre d'entrée était globalement le même entre les deux, même si l'évolution de la finesse de gravure entre les deux biaise un peu les résultats. Un avantage des fenêtres décentralisées est qu'il est possible de démarrer l'exécution de plusieurs µops simultanément : une µops par fenêtre d'instruction. Le fait est que deux fenêtres d'instructions différentes émettent leurs µops sans se synchroniser avec les autres. Deux fenêtres d'instruction peuvent donc émettre chacune une µops, ce qui fait deux µops émises lors du même cycle. Cela permet d'exécuter en même temps deux ou trois instructions 1-cycle, comme des additions, soustractions, décalages, etc. Il devient par exemple possible d'émettre une µop entière en même temps qu'une µop flottante, si les µops entières ont une fenêtre séparée de celle des µops flottantes. Il est maintenant temps de voir en quoi sont faites les fenêtres d’instruction, qu'elles soient centralisées ou décentralisées. Nous allons aussi voir quelle est la logique d'émission associée. ==L'implémentation d'une fenêtre d'instruction : généralités== Une fenêtre d'instruction est une mémoire qui mémorise des micro-opérations. Elle est cependant plus complexe qu'une mémoire RAM ou qu'une FIFO et ressemble un petit peu à une mémoire cache. Elle dispose d'un port d'écriture et d'un port de lecture, au minimum. Le port d'écriture permet à l'unité de décodage d'insérer une micro-opération dedans, d'ajouter la micro-opération qui vient d'être décodée. Si une instruction machine est décodée en plusieurs micro-opération, deux possibilités. La première est de les insérer un par un, ce qui fait qu'on peut se contenter d'un seul port d'écriture. L'autre possibilité est de les ajouter en même temps, ce qui demande plusieurs ports d'écriture. Le port de lecture sert à émettre une instruction. On part du principe que la fenêtre d'instruction ne peut émettre qu'une seule instruction à la fois, car les processeurs que nous avons vu précédemment sont de ce type. Mais nous verrons dans quelques chapitre qu'il existe des processeurs dits superscalaires, qui sont capables d'émettre plusieurs instructions par cycle. Dans ce cas, la fenêtre d'instruction a un seul port de lecture. Un processeur superscalaire, quant à lui, doit avoir un port de lecture par unité de calcul, ce qui fait beaucoup plus. Les fenêtres d'instruction sont composées d''''entrées''', des mots mémoire qui stockent une instruction. Une instruction réserve une entrée après son décodage et la libère dès qu'elle est envoyée aux unités de calcul. Une entrée contient l'opcode (les signaux de commande à envoyer à l'ALU), le registre de destination du résultat, les registres de chaque opérande, et éventuellement des signaux de commande en plus. De plus, chaque opérande est couplée à un bit de disponibilité, qui indique si elle est disponible. Quand un opérande est écrit dans les registres, le bit de présence correspondant est mis à jour. Enfin, chaque entrée possède un bit ''empty'' qui indique si elle est vide, cette information étant utile pour réserver des entrées. [[File:Entrée d'une station de réservation - sans les tags.png|centre|vignette|upright=3|Entrée d'une fenêtre d'instruction]] ===Les stations de réservation=== Les '''stations de réservation''' sont des fenêtres d'instruction particulières, qui sont capables de mémoriser les opérandes des instructions. Les entrées des stations de réservation sont identiques à celle des autres fenêtres d'instruction, si ce n'est que les opérandes de l'instruction sont enregistrées directement dans des champs séparés. Il y a deux champs, un par opérande, pour stocker l'opérande elle-même, lue depuis les registres ou obtenue via le réseau de contournement. Notons que les champs pour les opérandes viennent en plus des champs pour les noms de registres, encore que les deux peuvent être fusionnés si on veut optimiser le tout. [[File:Entrée d'une station de réservation.png|centre|vignette|upright=3|Entrée d'une station de réservation.]] Précisons que la terminologie n'est pas très fiable. Les termes "fenêtre d'instruction" et "station de réservation" ne regroupent pas du tout la même chose d'un papier de recherche à l'autre, d'un bouquin à l'autre, d'un chercheur à l'autre, d'un ingénieur à l'autre, d'un professeur à l'autre. Le terme initial vient pourtant de l'article original sur l'algorithme de Tomasulo, où il désignait une fenêtre d'instruction associée à une unité de calcul précise. Mais le terme a ensuite été réutilisé, ce qui fait que certains processeurs avec plusieurs unités de calcul sont décrit comme ayant une unique station de réservation. En bref : c'est le bazar ! Mais nous en reparlerons dans le chapitre sur le renommage de registres, car c'est la place idéale pour les aborder. Toujours est-il que j'ai fait le choix de confondre les concepts de fenêtre d'instruction et de station de réservation avec les concepts de '''lecture avant émission''' et de '''lecture après émission'''. La différence entre les deux est que les registres sont lus après émission avec une fenêtre d'instruction, avant avec des stations de réservation. Dans le cas "avant émission", les opérandes sont mémorisées dans la station de réservation. Et cette différence a une influence sur le pipeline du processeur, le banc de registres et tout ce qui s'en suit. Un désavantage de la lecture avant émission est qu'il faut stocker les opérandes après lecture, ici dans les stations de réservation. Mais un avantage est que le banc de registre a besoin de moins de ports de lecture, car une bonne partie des opérandes sont fournies par le système de contournement. Nous verrons cela dans le détail dans le chapitre sur les processeurs superscalaires. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Lecture après émission.]] [[File:Read Before Issue.png|centre|vignette|upright=2.5|Lecture avant émission.]] Il a été proposé de fusionner le tampon de ré-ordonnancement avec la fenêtre d'instruction dans une structure unique. La méthode a notamment été utilisée sur les processeurs d'architecture K6 d'AMD. Le tout donnait une structure appelée le '''DRIS''' (''deferred scheduling register renaming instruction shelf''). La différence avec une fenêtre d’instruction normale est que les entrées sont libérée non pas quand l'instruction est exécutée/émise, mais quand elle termine son exécution et quitte le ROB. La fenêtre d'instruction doit alors incorporer des bits pour savoir si telle entrée a émis sont instruction ou non. ===La logique d'éveil et de sélection=== Dans le cas qui va suivre, on suppose que le processeur ne peut émettre qu'une instruction à la fois. Chaque cycle, une instruction est sélectionnée et est envoyée dans le chemin de données, soit à une ALU, soit à une unité d'accès mémoire. La sélection d'une instruction est effectuée par l'unité d'émission, qui est aussi appelée le '''''scheduler'''''. Elle gère la disponibilité des opérandes et la disponibilité des unités de calcul adéquate. Le choix de l'instruction émise doit être le plus pertinent possible, pour des raisons de performances. Pour le premier point, l'unité d'émission détermine quelles instructions sont candidates pour l'émission. Les ''instructions candidates'' sont celles dont tous les opérandes sont prêts. Le processeur contient un circuit qui détecte les instructions candidates : la '''logique d’éveil''' (''wake-up logic''). Une fois que la logique d'éveil a fait son travail, une instruction est choisie pour s’exécuter en fonction de la disponibilité des unités de calcul adéquates. Ce rôle est dévolu à un circuit qu'on appelle la '''logique de sélection''', ou ''select logic''. [[File:Fonctionnement complet de la logique d’émission.jpg|centre|vignette|upright=1.5|Fonctionnement complet de la logique d’émission.]] La logique de sélection doit gérer le fait que les unités de calcul du processeur ne sont pas toutes identiques. Déjà, un processeur a généralement des unités séparées pour les instructions entières et flottantes, des unités spécialisées dans les accès mémoire, parfois des unités spécialisées pour les branchements. Une instruction doit être attribuée à la bonne unité de calcul, on ne doit pas envoyer une instruction entière dans une unité de calcul flottante. De plus, parmi les unités de calcul entières, toutes ne sont pas identiques. Par exemple, il est fréquent d'avoir plusieurs unités de calcul spécialisées dans les opérations simples (additions, soustractions, opérations logiques) avec une unité pour les multiplications/divisions séparées, parfois une unité spécialisée pour les décalages/rotations, etc. Là encore, allouer la bonne instruction à la bonne ALU est complexe. Plus les unités de calcul sont hétérogènes, plus la logique de sélection est compliquée. Les logiques d'éveil comme de sélection sont assez complexes. Comme on le verra plus bas, la logique de sélection la plus simple, qui gère une seule unité de calcul, est basée sur un encodeur à priorité couplé à d'autres circuits. Et pour gérer plusieurs ALUs, il faut mettre des encodeurs en cascade. Le résultat est que même en prenant une logique de sélection simple, elle sera assez lente et gourmande en circuits. Aussi, la logique de sélection met souvent un cycle d'horloge entier pour faire son travail, elle a son propre étage de pipeline attribué. La logique d'éveil est dans le même cas, ce qui fait qu'émettre une micro-opération demande deux cycles d'horloge. Le défaut est que cela rajoute des cycles d'horloges entre la fenêtre d'instruction et l'ALU, ce qui complique la gestion du pipeline. Ces cycles de retard sont à prendre en compte au moment d'émettre les instructions, les ''scheduler'' doit en tenir compte pour des performances optimales. Sans tenir compte de ces cycles de retard, les instructions arrivent en retard de quelques cycles à l'ALU, cycles de retard durant lesquels l'ALU n'a pas fait de calcul et a été sous-utilisée, sans compter que le système de contournement n'est pas utilisé au mieux. Et le problème est encore plus important sur les processeur avec des stations de réservation, qui utilisent la "lecture après émission" : cela rajoute un cycle d'horloge en plus, un temps de retard en plus. ===La logique d'éveil : l'émission anticipée=== La logique d'éveil doit tenir compte du fait qu'il y a plusieurs étages entre l'émission et l'exécution sur une unité de calcul. Par exemple, un processeur a souvent entre un et à cinq étages entre la file d'attente et les unités de calcul. Il faut lire les registres, gérer le contournement, et cela peut prendre quelques cycles d'horloge. Sur le Pentium 4, on trouve 6 étages entre la fenêtre d’instruction et l'entrée de l'ALU. Si les micro-opérations sont émises quand les opérandes sont disponibles, il y aura un délai de quelques cycles avant qu'elles atteignent l'ALU. Alors qu'idéalement, on souhaiterait que la micro-opération atteigne l'ALU dès que ses opérandes sont disponibles, pour profiter des techniques de contournement. Pour cela, la logique d'éveil émet les instructions quelques cycles en avance pour qu'elles arrivent au bon moment. Il s'agit d'une technique d''''émission anticipée''', dont nous avions parlé dans le chapitre sur le contournement. : Il faut noter que le problème se pose plus avec des fenêtres d'instruction qu'avec des stations de réservation. Les premières ont un étage en plus entre émission et ALU, vu qu'il faut lire des registres après l'émission. L'émission anticipée demande d'émettre un signal d'éveil en avance de quelques cycles, pile au bon moment. Par exemples, si on a deux étages entre l'ALU et l'unité d'émission, le signal de réveil sera généré deux cycles avant que le résultat soit effectivement calculé. L'implémentation varie, mais deux solutions sont possibles. La première est de générer le signal d'éveil dans l'ALU, ce qui n'a de sens que pour les opérations comme les multiplications ou les divisions, qui prennent plusieurs cycles. Une autre technique génère le signal de réveil dans une structure centralisée, spécialisée dans la génération des signaux d'éveil. L'unité de composée d'un registre à décalage par registre. Imaginons qu'une instruction est émise, que cette instruction mette N cycles à s'exécuter, et qu'elle écrive dans un registre de destination. L'unité sélectionne alors le registre à décalage associé au registre de destination, et met le bit numéro N à 1. Le registre décalé d'un cran à chaque cycle. Quand le bit sortant est un 1, alors le signal de validité pour l'opérande est généré. L'émission anticipée marche bien si l'instruction a une durée fixe, connue à l'avance. Et autant c'est le cas pour les instructions arithmétiques et logiques, autant ce n'est pas le cas pour les accès mémoire. Les accès mémoire ont une latence variable : quelques cycles pour un succès de cache, plusieurs dizaines de cycles pour un défaut de cache L1, pas loin de la centaine pour un défaut de cache L2, etc. Et cela pose des problèmes pour l'émission anticipée. L'émission en avance pour les accès mémoire est purement spéculative : le processeur émet des instructions en supposant que la lecture entrainera un succès de cache, quitte à annuler l'instruction en cas de défaut de cache. Mais faire ainsi demande non seulement d'annuler les instructions émises en avance, mais aussi de ne pas retirer les instructions émises en avance de la fenêtre d'instruction. Elles sont émises, mais une copie de sauvegarde est conservée dans la fenêtre d'instruction. Si le processeur détecte un défaut de cache, il peut alors ré-exécuter l'instruction. S'il détecte un succès de cache, les instructions lecture-dépendante sont retirées de la fenêtre d'instruction, la copie de sauvegarde est devenue inutile et est donc jetée. ===La logique de sélection : âge ou position ?=== La logique de sélection est primordiale pour de bonnes performances. Il existe deux méthodes principales pour sélectionner l'instruction à exécuter. La première est la plus simple : elle se base sur lé numéro de l'entrée. En effet, une fenêtre d'instruction est avant tout une sorte de mémoire, un mix entre mémoire associative, mémoire RAM, et FIFO. Et chaque entrée a un numéro, une adresse mémoire. Nous parlerons de numéro dans ce qui suit, car ce sera plus simple, le terme d'adresse mémoire étant peut-être un peu exagéré dans le contexte des fenêtres d'instruction. Toujours est-il que la fenêtre d'instruction est adressable dans le sens où on peut lui envoyer le numéro de l'entrée voulue, et la fenêtre d’instruction renvoie le contenu de l'entrée sur son port de lecture. Et c'est ce que fait la logique de sélection : elle génère le numéro de l'entrée à lire. Le numéro est alors envoyé sur l'entrée d'adresse de la fenêtre d’instruction, et elle fournit la micro-opération associée sur son port de lecture, son '''port d'émission'''. La première méthode de sélection, donc. Elle est basée sur sur le numéro de l'entrée. Si plusieurs entrées sont éveillées, la logique de sélection prend celle avec le plus petit numéro. Elle porte le nom de '''sélection par position''', sous-entendu position dans la fenêtre d'instruction. Vous l'avez peut-être deviné, mais la logique de sélection est alors un encodeur à priorité. Le circuit de sélection ne se résume donc pas seulement à un encodeur à priorité, mais c'est le circuit central. L'avantage d'une telle méthode de sélection est qu'elle est simple à implémenter : un encodeur à priorité est un circuit connu, facile à implémenter. Mais on remarque un défaut : un encodeur est un circuit assez rapide, mais qui utilise beaucoup de transistors, beaucoup de portes logiques, surtout si on veut qu'il soit rapide. Ce qui explique que la logique de sélection ait son propre étage de pipeline rien que pour elle. La seconde méthode s'appelle la '''sélection par âge''', au nom assez transparent. L'idée est de privilégier l'émission de l'instruction la plus ancienne. Elle demande que la fenêtre d'instruction trie les micro-opérations par ordre d'insertion dans la fenêtre d'instruction, ce qui en fait une pseudo-FIFO. Le tri est partiel, car les instructions peuvent sortir de la fenêtre d’instruction à tout moment. Compacter la fenêtre d'instruction, à savoir regrouper toutes les entrées valides est une idée, mais elle est compliquée à implémenter. Aussi, elles préfèrent encoder des informations sur l'ordre d'émission dans chaque entrée. L'encodeur à priorité doit alors travailler non pas sur des nombres entiers liés à l'ordre d'insertion dans la pseudo-FIFO. Elle est encore plus gourmande en circuits que la méthode précédente. Les processeurs haute performance utilisent souvent des méthodes hybrides. Par exemple, les processeurs AMD de microarchitecture Bulldozer utilisaient une méthode intermédiaire. Ils utilisaient une fenêtre d'instruction couplée à un encodeur à priorité pour la sélection par position, mais complémentaient le tout avec une unité qui mémorisait l'instruction la plus ancienne dans la fenêtre d’instruction. Le mécanisme de sélection par âge était utilisé en priorité. Mais si l'instruction la plus ancienne n'était pas prête, le processeur basculait sur le mécanisme de sélection par position. ===La compaction des fenêtres d'instruction=== À chaque cycle, les instructions décodées sont ajoutées dans la fenêtre d'instruction, dans des entrées vides. Vu que les instructions quittent celle-ci dans le désordre, ces vides sont dispersés dans la fenêtre d'instruction, ce qui pose problème pour déterminer où placer les nouvelles instructions. La solution la plus triviale consiste à conserver une liste des vides, mise à jour à chaque insertion ou émission d'instruction. Une autre solution consiste à éliminer les vides en compactant la fenêtre d'instruction à chaque cycle d'horloge. Des circuits se chargent de détecter les vides et de regrouper les instructions en un unique bloc. Il faut signaler que certaines processeurs arrivent à se passer de cette étape de compactage, mais au prix de fenêtres d'instruction nettement plus complexes. Autre problème : quand il faut choisir quelle instruction émettre, il y a toujours plusieurs candidats. Si on choisit mal, des instructions restent en attente trop longtemps parce que d'autres instructions plus jeunes leur passent devant. Pour éviter cela, les instructions les plus vielles, les plus anciennes, sont prioritaires. Pour cela, on peut utiliser une FIFO un peu spéciale pour la fenêtre d'instruction. Si les ajouts d'instruction se font dans l'ordre, les instructions ne quittent pas forcément la fenêtre d'instruction dans l'ordre imposé par une FIFO : les instructions restent triées dans leur ordre d'ajout, même s'il y a des vides entre elles. Dans ces condition, il est préférable que le compactage conserve l'ordre FIFO des instructions. Dans ces conditions, l'instruction la plus ancienne est celle qui est située à l'adresse la plus faible : le circuit de sélection peut donc être fabriqué avec des encodeurs, et est relativement simple. ==Les fenêtres d'instruction basées sur une matrice de dépendances== L'implémentation la plus simple étend le fonctionnement d'un pipeline dynamique usuel. Rappelez-vous le chapitre sur les pipeline dynamiques. Nous avions vu que de tels pipelines émettaient une instruction par cycle, quitte à émettre des bulles de pipeline en cas de dépendance bloquante. Et il est possible d'améliorer leur unité d'émission pour qu'elle soit compatible avec l'exécution dans le désordre. ===Rappels sur le registre de réservation/disponibilité=== L'émission d'une instruction est gouvernée par un ''registre de réservation'' qui indique quels registres sont réservés par une instruction, et ceux qui sont libres. Un registre réservé est un registre qui sera écrit par une instruction en cours d'exécution, mais qui n'a pas encore écrit son résultat. Les instructions candidates doivent avoir leurs opérandes dans des registres libres. Sinon, c'est signe que leurs opérandes sont réservées en écriture, donc pas encore écrites, donc pas disponibles. Si une instruction candidate veut lire ce registre, c'est signe qu'il y a une dépendance RAW : elle veut lire un registre réservé, qui est destiné à être écrit par une instruction en vol. Si elle veut écrire, c'est signe qu'elle veut écrire dans un registre où une autre instruction veut écrire : c'est une dépendance WAW. Dans les deux cas, l'instruction n'est pas émise. Le registre de réservation encode les registres réservés comme suit : chaque bit est associé à un registre. Le bit numéro 0 est associé au registre numéro 0, le bit numéro 1 au registre numéro 1, etc. Là, En clair, les numéros de registres réservés sont encodés en représentation non pas binaire, mais en représentation ''one-hot'' (vue au premier chapitre). {|class="wikitable" |+ Registre de réservation |- ! Registre 7 !! Registre 6 !! Registre 5 !! Registre 4 !! Registre 3 !! Registre 2 !! Registre 1 !! Registre 0 |- | 0 || 0 || 1 || 0 || 0 || 1 || 0 || 0 |} Avant d'émettre une instruction, l'unité d'émission extrait les registres opérande/destination et les convertis dans la même représentation que le registre de réservation, à savoir en représentation ''one-hot''. Le circuit de traduction binaire vers ''one-hot'' est, pour rappel, un simple décodeur. Puis, on fait un OU logique entre les sorties des décodeurs. Le résultat est un masque qui indique quels registres sont lus par l'instruction, encodé en représentation ''one-hot''. Appelons-le le '''masque d'opérandes'''. Le masque est alors comparé au registre de réservation pour vérifier si l'instruction peut être émise. [[File:Unité d'émission simple, dans l'ordre.png|centre|vignette|upright=2|Unité d'émission simple, dans l'ordre]] Si l'émission est autorisée, le registres de réservation est là aussi mis à jour. Le registre de réservation est aussi mis à jour dès qu'une instruction enregistre son résultat dans les registres, ou alors dès qu'il est disponible pour le contournement. Le bit associé au registre repasse alors à 0 (ou à 1). Sans contournement, la mise à jour se fait alors à la toute fin de l'instruction, quand elle se termine, lors de la dernière étape d'enregistrement, à la fin de son pipeline. Avec, elle se fait quand l'instruction quitte l'unité de calcul. ===L'extension à l'exécution dans le désordre : l'éveil par matrice de bits=== La différence entre un pipeline dynamique et l'exécution dans le désordre est que l'on passe d'une instruction à émettre à plusieurs. Plusieurs instructions sont mises en attente dans une fenêtre d’instruction, et y attendent leur tour. L'idée est alors d'envoyer le registre de disponibilité à toutes les entrées, à toutes les instructions en attente. Ainsi, on sait quelles sont les instructions qui peuvent s'exécuter et celles qui ne le peuvent pas. L'implémentation est assez simple, elle ressemble beaucoup à l'implémentation d'un pipeline dynamique simple, si ce n'est que des circuits sont dupliqués. L'implémentation utilise des fenêtres d'instruction légèrement différentes de celles introduites plus haut. Elles n'utilisent notamment pas de bits de disponibilité, mais autre chose. Lorsqu'une instruction est ajoutée à la fenêtre d'instruction, le masque de disponibilité des opérandes est stocké dans la fenêtre d'instruction. A chaque cycle, le registre de disponibilité est envoyée à toutes les entrées, et est comparé avec tous les masques de disponibilité des opérandes. Si une comparaison renvoie un 1, alors l'instruction de l'entrée est une instruction candidate à l'émission. [[File:Unité d'émission dans le désordre basée sur un registre de disponibilité.png|centre|vignette|upright=2.5|Unité d'émission dans le désordre basée sur un registre de disponibilité]] L'ensemble est implémenté avec l'aide d'une '''matrice de bits''', où chaque ligne correspond à une entrée et chaque colonne à un registre. À chaque croisement entre une ligne et une colonne, on trouve un bit. Si le bit de la ligne n et de la colonne m est à 1, cela veut dire : l'instruction dans l'entrée n a besoin de lire le registre m. S’il est à 0, alors cela veut dire que l'instruction stockée dans la ligne n n'a pas besoin de la donnée dans le registre m. [[File:Planificateur à matrice de bits.jpg|centre|vignette|upright=2|Planificateur à matrice de bits.]] Lorsqu'une instruction réserve une entrée, elle initialise la ligne en fonction des registres qu'elle souhaite lire. Pour vérifier si une instruction a ses opérandes prêts, le processeur compare le registre de disponibilité à la ligne associée à l'instruction/entrée. A chaque intersection ligne-colonne, se trouve un comparateur de 1 bit, qui détecte si le registre est demandé et disponible. Les résultats de cette porte sont ensuite envoyés à une porte ET, qui fait le gros du travail. [[File:Logique de détection de la disponibilité d'une instruction.jpg|centre|vignette|upright=2|Logique de détection de la disponibilité d'une instruction.]] ==Les fenêtres d'instruction basées sur une mémoire associative== Les processeurs modernes utilisent une mémoire associative pour la fenêtre d'instruction. Les mémoires associatives ont été abordées il y a quelques chapitres, mais faisons quelques rappels. Les mémoires associatives servent à accélérer la recherche de données dans un ensemble. Or, une fenêtre d'instruction vérifie régulièrement si chaque entrée est prête. Il s'agit d'un processus de recherche d'une instruction qui respecte une condition bien précise dans la mémoire, ce qui fait que les mémoires associatives sont donc tout indiquées. Comme vous le savez, les signaux de commande d'une instruction sont propagés avec celle-ci dans le pipeline, le nom du registre de destination ne faisant pas exception. Le nom de registre est envoyé à la fenêtre d'instruction lors de l'écriture du résultat dans les registres. S'il y a correspondance, l'opérande est disponible et son bit de disponibilité est mis à 1. On peut adapter cette méthode pour tenir compte du contournement assez simplement. [[File:Détection des dépendances par propagation du registre de destination.png|centre|vignette|upright=2|Détection des dépendances par propagation du registre de destination.]] En conséquence, le circuit de détection des dépendances est constitué d'un grand nombre de comparateurs : un par champ « nom de registre » dans chaque entrée. La logique d'éveil/''wake up'' regroupe tous les comparateurs, la logique de sélection est un circuit situé en-dehors de la mémoire associative. Les entrées sont dans la mémoire associative elle-même. [[File:Gestion des bits de validité.png|centre|vignette|upright=2|Gestion des bits de validité.]] L'implémentation la plus simple est celle du schéma précédent, où on utilise une mémoire associative unique. Une version plus élaborée sépare la fenêtre d'instruction en deux parties : une mémoire qui mémorise les registres des opérandes, une autre mémoire pour le reste. La mémoire pour les registres opérandes est la mémoire associative proprement dite, c'est elle qui est associées aux comparateurs, à la logique de ''wake-up''/réveil, etc. Par contre, l'autre mémoire est une mémoire RAM simplifiée, qui mémorise les informations qui n'ont pas besoin des comparateurs. L'opcode de l'instruction est là-dedans, par exemple. ===Les optimisations de la consommation d'énergie : la désactivation des portions inutilisées=== Le problème avec des fenêtres d'instruction de ce type est leur forte consommation énergétique, ainsi que le grand nombre de portes logiques utilisées, qui deviennent prohibitif pour des fenêtres d'instruction un peu grosses. Pour résoudre ce problème, certains ont optimisé les comparateurs. D'autres ont tenté de profiter du fait que la majorité des bits dans les entrées sont composés de zéros. Bref, les optimisations purement matérielles sont légion. Une première solution est de désactiver les entrées qui sont inutilisées, vides, sans instruction. Pour cela, on fait précéder les comparateurs par un circuit qui les connecte ou déconnecte des lignes de bit. Le circuit est commandé par le bit ''empty'' qui indique si une entrée est vide ou non. L'avantage est que la consommation d'énergie de la fenêtre d'instruction devient alors proportionnelle au nombre d'entrées non-vides, et non au nombre d'entrées total. Du moins, en apparence, les entrées non-utilisées doivent quand même être alimentées pour fonctionner, mais l'activité de comparaison disparait dans les entrées vides. Il est possible d'étendre cette technique aux entrées dont les opérandes sont prêtes. Les gains sont généralement assez bons, avec une réduction de consommation variant entre 30 et 50%, avec une implémentation très simple et très économe en circuits. Une autre solution, assez simple à mettre en place, consiste à désactiver une partie de la fenêtre d'instruction sin elle est inutilisée. Pour cela, il faut segmenter la fenêtre d'instruction avec la technique du ''wire partitionning''. Pour rappel, une fenêtre d'instruction est une mémoire associative. Et comme toute mémoire associative, elle contient des fils, les lignes de bit, qui relient les entrées/sorties à toutes les cellules mémoire. Plus une ligne de bit est longue, plus elle consomme d'énergie et plus le temps de lecture/écriture est long. L'idée est de segmenter les lignes de bits en plaçant des répéteurs qui recopient la tension d'un segment au suivant. Les répéteurs sont des tampons trois-états, ce qui permet de déconnecter les portions inutilisées de la ligne de bit. Ce faisant, la fenêtre d'instruction est découpée en segments, qui peuvent être désactivés si besoin. Si il y a peu d'instructions chargées dans la fenêtre d'instruction, les portions inutilisées sont désactivées. La technique marche d'autan mieux si les instructions sont compactées au début de la fenêtre d'instruction. [[File:Wire partitionning.png|centre|vignette|upright=2|Wire partitionning]] Tout le problème est de savoir quelles portions désactiver. La technique est assez simple si la fenêtre d'instruction est compactée, à savoir si toutes les instructions sont régulièrement regroupées au début de la mémoire CAM. Mais même avec cette optimisation, la décision de désactiver une portion de la fenêtre d'instruction n'est pas à prendre à la légère. Il ne faut pas désactiver une portion contenant des instructions pouvant être émise sous peu. La décision dépend de paramètres variés : proportion d'entrée vides, quantité d'entrées récemment activées/désactivées récemment, présences d'entrées avec un ''match'' d'opérandes récent, etc. Il est important de préciser que les techniques en question fonctionnent aussi sur les autres types de fenêtre d'instruction, qui ne sont pas basées sur des mémoires associatives. Nous allons voir celles-ci dans la suite du chapitre, mais gardez à l'esprit que ces optimisations, à savoir désactiver les entrées vides/prêts et partitionner la fenêtre d'instruction, sont des optimisations générales qui marchent avec presque tout. ===L'ajout d'une FIFO pour les instructions déjà prêtes à l'émission=== D'autres techniques permettent de réduire aussi bien le cout en circuits que la consommation d'énergie de la fenêtre d'instruction. L'idée est d'utiliser une mémoire associative quand elle est réellement nécessaire, mais d'utiliser une fenêtre d'instruction "normale" dès que possible. La méthode la plus simple tient compte du fait que certaines instructions ont déjà toutes leurs opérandes de disponibles à l'émission, mais doivent quand même être mises en attente, parce que l'ALU adéquate est occupée, parce que des dépendances WAW/WAR sont encore là, ou pour tout autre raison. Dans ce cas, elles sont mises en attente non pas dans la fenêtre d'instruction, mais dans une mémoire FIFO toute simple. L'idée est qu'au lieu d'avoir une énorme mémoire associative pour la fenêtre d'instruction, on déplace quelques entrées dans une petite FIFO annexe. Le résultat est un gain en terme d'énergie et de circuits, au prix d'une perte de performance mineure. La perte de performance en question se manifeste si aucune instruction n'a ses opérandes de prêtes à l'émission : le programme n'utilise pas la FIFO et voit alors une fenêtre d'instruction plus petite. Une amélioration de cette technique tient compte du fait que certaines instructions sont dans un cas intermédiaire. Elles ont déjà une opérande de prête lors de l'émission, mais pas l'autre. Le nombre d'opérandes varie suivant l’instruction : certaines n'ont besoin que d'un seul opérande. De plus, il arrive qu'une opération tout juste décodée ait déjà un ou plusieurs de ses opérandes de prêts. Cette constatation permet d'éviter d'utiliser des comparateurs pour les opérandes déjà prêts. Par exemple, on peut parfaitement utiliser trois fenêtres d'instruction : * une pour les instructions dont tous les opérandes sont prêts, mais qui sont quand même mises en attente, sans comparateur ; * une pour les instructions dont un seul opérande manque, qui n'utilise qu'un comparateur par entrée ; * une pour les instructions dont deux opérandes manquent à l'appel, qui utilise deux comparateurs par entrée. C'est beaucoup plus économique que d'utiliser une seule grosse fenêtre d'instruction qui contiendrait autant d'entrées que les trois précédentes réunies, avec deux comparateurs par entrée. Certains sont même allés plus loin, et ont proposé de supprimer la fenêtre d'instruction avec deux opérandes par entrée. Les instructions dont deux opérandes sont inconnus au décodage sont stockées dans la fenêtre d'instruction pour instructions avec un comparateur par entrée. Un circuit de prédiction se charge alors de prédire l'opérande manquant, cette prédiction étant vérifiée plus loin dans le pipeline. Il serait cependant étonnant qu'une telle proposition ait donné lieu à la moindre implémentation réelle. ===Les optimisations de la consommation d'énergie avancées=== D'autres chercheurs ont conservé une fenêtre d'instruction unique, avec autant de comparateurs par entrée qu'il y a d'opérandes possibles par instruction. Simplement, le processus de détection des opérandes prêts est légèrement ralenti : on ne vérifie qu'un opérande par cycle. Pour vérifier les deux opérandes d'une entrée, on doit attendre deux cycles. Enfin, certains chercheurs ont proposé des fenêtres d'instruction segmentées. Les instructions circulent à chaque cycle d'un segment vers le suivant : en conséquence, certains segments conservent les instructions les plus anciennes, un autre les instructions les plus jeunes, etc. Seul le denier segment, celui qui contient les instructions les plus vielles, peut émettre une instruction : la détection des opérandes se fait seulement dans le dernier segment, qui contient les instructions les plus anciennes. On économise ainsi beaucoup de comparateurs. Certains chercheurs ont tenté de pipeliner l'étape de sélection des opérandes, ainsi que l'étage d'arbitrage. Mais en faisant cela, il faut plusieurs cycles pour détecter qu'une instruction a ses opérandes prêts, ce qui pose problème face à de nombreuses dépendances RAW. Pour éviter de trop perdre en performances, certains chercheurs ont décidé d'utiliser des techniques pour prédire quelles seront les instructions dont les opérandes seront bientôt prêts. Si détecter qu'une instruction est prête prend n cycles, le processeur devra tenter de prédire la future disponibilité des opérandes n cycles en avance pour obtenir des performances optimales. ===Remplacer la mémoire associative par une RAM=== Une autre optimisation possible est de remplacer la fenêtre d'instruction par une mémoire RAM, dont chaque mot mémoire correspondrait à une entrée. Une telle optimisation permet en théorie de se passer des comparateurs associés à chaque entrée, mais au prix de l'ajout de circuits annexes potentiellement couteux. La première de ces techniques, la '''recherche directe par étiquette''' (direct tag search) fut créée par Weiss et son collègue Smith. Ils cherchaient à améliorer l'algorithme de Tomasulo, un algorithme qu'on expliquera dans quelques chapitres. Rappelons que chaque instruction produit un résultat, qui devra être rapatrié dans une ou plusieurs entrées de la fenêtre d'instruction. L'optimisation de la recherche directe par étiquette fonctionne dans le cas où le résultat de l'instruction n'est utilisé que par une seule entrée, et pas plusieurs. Le principe est simple : chaque champ « opérande » d'une entrée est adressable via le nom de registre de cette opérande. Pour faire le lien entre entrée et nom de registre, la recherche directe par étiquette ajoute une table de correspondances matérielle, une mémoire RAM qui mémorise les adresses des champs « opérande » des entrées. Les adresses envoyées dans cette mémoire sont les noms de registres des résultats. Lors de l'émission, la table de correspondances est mise à jour. Les numéros des champs « opérande » réservés lors de l'émission sont mémorisés dans les mots mémoire qui correspondent aux deux registres sources. Toutefois, une petite vérification est faite lors de l'émission : si il y a déjà une correspondance dans la table pour un registre source, alors une autre instruction compte lire ce registre. Pour éviter d'écraser les données de l'instruction précédente dans la table de correspondances, l'émission de l'instruction est bloquée. [[File:Recherche directe par étiquette.png|centre|vignette|upright=2|Recherche directe par étiquette.]] ==Les fenêtres d’instruction avec préplanification== Avec la '''préplanification''' (''prescheduling''), la fenêtre d’instruction est composée de mémoires FIFO dans lesquelles les instructions sont triées dans l'ordre d'émission. Il n'y a pas de logique d’émission proprement dite, celle-ci se bornant à vérifier si l'instruction située au début de la FIFO peut s’exécuter. Par contre, le préplanificateur détecte les dépendances et en déduit où insérer les instructions dans le tampon d'émission, à l'endroit le plus adéquat. [[File:Préplanification.jpg|centre|vignette|upright=2|Préplanification.]] ===L'usage de FIFO multiples=== La technique de préplanification la plus simple utilise plusieurs FIFO. Quand une instruction a une dépendance avec une autre instruction, les deux sont placées dans la même FIFO. Pour cela, le préplanificateur détecte les chaines d'instructions dépendantes, et place les instructions dans la FIFO adéquate. A chaque cycle, l'unité d'émission lit une micro-opération dans chaque FIFO et vérifie si elle peut l'émettre. Si la micro-opération n'a pas ses opérandes disponibles, ou qu'une dépendance structurelle survient, alors la FIFO est bloquée. La micro-opération attend que la dépendance soit résolue, bloquant toutes les instructions précédentes. Mais les autres FIFO ne sont pas bloquées, laissant de la marge de manœuvre. [[File:Préplanification par FIFO multiples.png|centre|vignette|upright=1.5|Préplanification par FIFO multiples.]] ===La technique du tampon trié=== La technique du '''tampon trié''' trie les instructions selon le temps d'attente avant leur exécution. Les instructions qui sont censées s’exécuter bientôt sont insérées au tout début de la FIFO, tandis que les instructions qui s’exécuteront dans un long moment sont insérées vers la fin. Là encore, l'unité d'émission lit une micro-opération dans la FIFO, et détermine si elle peut être émise. Si une dépendance survient, l'émission est retardée, et la FIFO est bloquée. [[File:Préplanification par tampon trié.png|centre|vignette|upright=1.5|Préplanification par tampon trié.]] La technique a cependant quelques problèmes assez importants. Le premier problème est que la FIFO est bloquée lorsqu'une micro-opération ne peut être émise. Le second problème est que le temps avant exécution n'est pas toujours connu, notamment pour les instructions d'accès mémoire. Et cela se répercute sur les instructions dépendantes de celles-ci. Pour résoudre ce genre de problèmes, l'usage d'un pipeline à ''replay'' est possible, et est même l'une des meilleures solution possible, malgré ses défauts. L'idée est que les lecture sont pré-planifiées en supposant qu'elles font un succès de cache L1. Si la prédiction est fausse, la lecture est ré-exécutée plusieurs cycles plus tard, en supposant qu'elle fait un succès dans le cache L2, et ainsi de suite. Elle est alors ré-insérée dans la FIFO, elle est pré-planifiée une seconde fois. Il en est de même si une micro-opération ne peut pas être émise : il suffit de la réinsérer dans la FIFO au bon endroit, en attendant que ses dépendances soient résolus. Ainsi, l'instruction fautive ne bloque pas la fenêtre d’instruction, et retente sa chance autant de fois qu'il le faut. [[File:Préplanification par fenêtre d’instruction scorebarodée.png|centre|vignette|upright=1.5|Préplanification par fenêtre d’instruction scorebarodée.]] Une autre solution utilise deux fenêtres d’instruction : une FIFO gérée par la préplanification, et une vraie fenêtre d'instruction pour les instructions dont le temps d'attente ne peut pas être déterminé. Il est possible de mettre cette dernière avant la préplanification, afin de gérer les temps d'attente des instructions d'accès mémoire. Quand le temps d'attente d'une lecture devient connu, ses instructions dépendantes sont gérées avec préplanification. [[File:Préplanification avec fenêtre d’instruction.png|centre|vignette|upright=2.5|Préplanification avec fenêtre d’instruction.]] ===Les fenêtres d'instruction avec allocation temporelle statique=== L''''allocation temporelle statique''' correspond à une technique utilisée sur les processeurs Cuzco de l'entreprise Condor. La technique en question a été présenté en 2025, mais des idées similaires ont été présentées dans la littérature académique. Elle ressemble beaucoup aux techniques de pré-planification, avec cependant quelques différences. L'idée est simple : le processeur dispose de plusieurs fenêtres d'instruction, qui mettent en attente les micro-opérations. Lors de l'étape de renommage de registres, le processeur détermine dans combien de cycles d'horloge la micro-opération sera prête pour exécution. La micro-opération est alors mise en attente durant ce nombre de cycles, dans les fenêtres d'instruction, puis est émise une fois ce nombre de cycles écoulés. Ce faisant, les fenêtres d'instruction n'ont pas besoin de détecter la disponibilité des opérandes à chaque cycle, pour chaque micro-opération en attente. Le ''timing'' de l'émission des micro-opérations est décidé à l'avance. L'implémentation exacte n'est pas connue, mais plusieurs solutions sont imaginables. Par exemple, la fenêtre d'instruction peut simplement être composée de plusieurs mémoires de petite taille, chacune contenant les micro-opérations destinées à être exécutées dans N cycles, N étant différent pour chaque mémoire. Une autre solution, plus réaliste, utilise une fenêtre d'instruction dans laquelle la micro-opération est couplée à des champs pour les opérandes, et un champ compteur. Le champ compteur est initialisé avec le nombre de cycles à attendre, et est décrémenté à chaque cycle d'horloge. Quand il atteint zéro, la micro-opération est émise. Vous remarquerez que la méthode ne marche que si toutes les micro-opérations prennent un nombre fixe de cycles d'horloge. Et autant c'est le cas pour les micro-opérations arithmétiques ou logiques, autant les accès mémoire ne rentrent pas dans ce cadre. En théorie, on ne sait pas combien de temps prendra un accès mémoire. Et cette incertitude se répercute sur les instructions dépendantes d'un accès mémoire. Pour éviter cela, le processeur réutilise un pipeline à ''replay'' tel que vu dans le chapitre précédent. L'unité de renommage de registre suppose que tout accès mémoire fait un succès de cache L1, et décide des ''timings'' d'émission sous cette hypothèse. Si une lecture subit un défaut de cache, elle est ré-exécutée, de même que toutes les instructions dépendantes. Pour cela, le registre de destination de la lecture est marqué comme invalide, grâce à un bit spécifique attaché au registre. Toute instruction qui lit une opérande invalide est elle aussi ré-executée de zéro. Pour simplifier, l'unité d'émission ressemble à une unité d'émission dans l'ordre, avec un registre de disponibilité, qu'on aurait amélioré pour aller au-delà de la simple détection des dépendances d'instruction. Pour déterminer les ''timings'' d'émission, à savoir quand émettre une micro-opération, le processeur utilise une unité d'émission à deux étages. Le premier étage est appelé le ''register scoreboard'', le second étage est appelé la ''Time Ressource Matrix''. Les deux étages communiquent entre eux, comme on va le voir, et leurs noms donnent une idée de ce qu'ils font. Le premier étage gère les dépendances de registres, le second gère les dépendances structurelles. Le premier étage est un registre de disponibilité amélioré, qui gère les dépendances de registre. Cet étage sait quand tel registre sera écrit, et donc que l'opérande écrite dedans sera disponible à partir de tel cycle d'horloge. Il le sait car l'étage suivant l'aura prévenu, mais laissons cela de côté pour le moment. Quand une micro-opération rentre dans cet étage, il vérifie les dépendances avec les registres et les micro-opérations antérieures. Vu qu'il sait quand les registres seront disponibles, il peut déterminer quand l'instruction pourra s'exécuter. Par exemple, si une micro-opération lit les deux registres R7 et R15, qui sont disponibles respectivement dans 5 et 7 cycles, le premier étage sait que la micro-opération devra attendre 7 cycles. Mais tout cela ne suffit pas à déterminer quand émettre une micro-opération. En effet, il fait aussi gérer les dépendances structurelles, ce qui est le boulot du second étage. Le second étage utilise pour cela une ''Time Ressource Matrix'', qui mémorise l'occupation de diverses "ressources", pour les 256 cycles d'horloge à venir. Les ressources en question sont les ports de lecture/écriture du banc de registre, les ALUs utilisées, si la micro-opération utilise l'unité mémoire, etc. Le second étage prend en entrée une micro-opération, détermine quelles "ressources" elle utilise, puis regarde leur disponibilité. Elle détecte alors les dépendances structurelles et détermine alors quand peut s'exécuter la micro-opération. Elle peut retarder l'émission de quelques cycles, si une dépendance structurelle est détectée. Une fois sortie du second étage, on sait quand la micro-opération va être émise, à quel cycle précisément. Et vu que la durée de l'instruction est fixe, on sait quand cette micro-opération va se terminer, quand son résultat sera disponible. Cela permet de mettre à jour la ''Time Ressource Matrix'', pour préciser que le port d'écriture sera occupé à tel moment. De plus, cette information est transmise au premier étage, qui sait alors quand est enregistré le résultat dans le registre de destination. C'est comme cela que le premier étage sait quand un registre est disponible : le second étage le prévient, quand il émet une instruction ! La ''Time Ressource Matrix''mémorise l'occupation des "ressources" pour les 256 cycles d'horloge à venir. Cependant, elle ne vérifie pas les dépendances pour les 256 cycles suivants. Quand elle reçoit une micro-opération, elle teste les dépendances structurelles pour seulement les 8 prochains cycles maximum. Si la micro-opération ne peut pas être émise pendant ces 8 cycles, le pipeline est bloqué, un ''pipeline stall'' est émis. Pour être plus précis, vu que le processeur peut décoder 8 micro-opérations en même temps, cela permet de ne consulter que 64 cycles d'horloge sur les 256. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les premiers processeurs Intel | prevText=Les premiers processeurs Intel | next=Le renommage de registres | nextText=Le renommage de registres }} </noinclude> mkjyed14m56u11a7iyimm4673s23vt4 773603 773602 2026-09-29T19:42:57Z Mewtow 31375 /* L'implémentation d'une fenêtre d'instruction : généralités */ 773603 wikitext text/x-wiki Dans les chapitres précédents, nous avons parlé des techniques dites d''''émission dans l'ordre'''. L'idée est d’exécuter une nouvelle micro-opération à chaque cycle, dans des unités de calcul séparées. Les instructions sont émises consécutivement, mais les instructions s’exécutent en parallèle dans des unités de calcul séparées. Par contre, quand l'unité d'émission ne peut pas émettre une instruction, elle bloque tout le pipeline. Les instructions qui suivent sont elles aussi bloquées, elle doivent attendre leur tour, même si elles sont en capacité de s'exécuter. Les techniques d'exécution dans le désordre que nous allons voir dans ce chapitre corrigent ce point précis. Elles sont dites à '''émission dans le désordre'''. Elles se distinguent des précédentes sur un point précis : quand l'unité d'émission bloque l'émission d'une instruction, les instructions suivantes peuvent poursuivre. L'émission des instructions peut donc se faire dans le désordre, dans le sens où une instruction peut être émise alors qu'une instruction précédente ne l'est pas encore. L'avantage de l'émission dans le désordre est qu'une instruction s'exécute dès que ses opérandes sont disponibles. Par disponible, on veut dire présent soit dans le réseau de contournement, soit dans les registres. Le processeur détecte automatiquement quand les opérandes d'une instruction sont sont disponibles, et il l’exécute à ce moment là. Dès qu'une instruction a ses opérandes disponibles, elle est émise et exécutée. C'est là la seule contrainte : les dépendances WAR, WAW et autres sont gérées par un ROB ou toute autre technique d'exception précise, seules les dépendances RAW limitent l'exécution. Mais avant de poursuivre, quelques point niveaux terminologie : * L'émission dans le désordre est un terme parlant et assez précis. Malheureusement, la terminologie la plus utilisée par d''''exécution dans le désordre'''. Et nous utiliserons ce terme dans la suite du cours, histoire de ne pas trop dévier de la nomenclature habituelle. * Nous utiliserons parfois l'abréviation OOO pour parler d'exécution dans le désordre. L'abréviation est celle de ''Out Of Order Excution''. * Nous utiliserons aussi l'abréviation ''µop'' pour parler de micro-opération, ''µops'' au pluriels pour parler de plusieurs micro-opérations, ou des micro-opérations en général. L'exécution dans le désordre ne gére en effet que des µops, elle se situe après l'étape de décodage. Mais avant de poursuivre, précisons une chose importante : l'exécution dans le désordre traite les accès mémoire à part. La majorité des processeurs OOO assez anciens exécutent les accès mémoire dans l'ordre, seules les µops entières/flottantes/branchements sont exécutées dans le désordre. Les processeurs datant d'après les années 2010 sont capable d'exécuter les accès mémoire dans le désordre, mais l'implémentation en question est assez particulière. Un chapitre entier sera dédié à l'exécution dans le désordre des µops mémoire. Nous allons volontairement mettre de côté la gestion des accès mémoire dans ce chapitre. ==Les fenêtres d’instruction : généralités== [[File:File de micro-opération.png|vignette|upright=1|File de micro-opérations]] Pour décrire comment est implémentée l'émission dans le désordre, il faut commencer par parler des processeurs sans. Les processeurs sans exécution dans le désordre ont une unité d'émission qui bloque tout le pipeline dès qu'une µop ne peut pas être émise. Pour limiter l'impact de ce blocage, quelques rares processeurs incorporent une '''file de micro-opération''', une mémoire FIFO qui met en attente les µops. Vu que c'est une mémoire FIFO, les µops sont émises dans l'ordre, à savoir l'ordre d'ajout, dans l'ordre de décodage. Le schéma ci-dessous illustre une telle file d'attente couplée à un ''scoreboard''. Sur le principe, l'exécution dans le désordre améliore la file de µops sur un point : ce n'est plus une mémoire FIFO. Les µops sont insérées dans l'ordre, mais peuvent sortir dans le désordre (être émises dans le désordre). La file de µops devient alors une '''fenêtre d'instruction''', terme traduit directement de l'anglais ''instruction Window''. Terme assez trompeur, car elles mettent en attente des µops, pas des instructions. Elles peuvent émettre des µops dans le désordre, ce qui fait que si une µop bloque le pipeline, les µops suivantes peuvent être émises. Si je commence le paragraphe précédent par "sur le principe", c'est car certaines techniques d'OOO utilisent des files de µops normales. Il est par exemple possible d'utiliser une file de µops avec une fenêtre d'instruction, plusieurs files de µops, plusieurs fenêtres d'instructions avec une file de µops annexe, etc. Dasn les grandes lignes, il existe dans les grandes lignes 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! File de µops améliorée |- ! Une seule "file de µops" | ''Scoreboard'' | Fenêtre d'instruction centralisée |- ! Plusieurs "file de µops" | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | Fenêtre d'instruction décentralisée |} ===La fenêtre d'instruction centralisée=== L'implémentation la plus simple de l'OOO utilise une unique '''fenêtre d'instruction'''. Les instructions décodées sont accumulées dans la fenêtre d'instruction, où elles attendent que leurs opérandes soient disponibles. La fenêtre d'instruction sert donc de file d'attente. Mais elle contient aussi une unité d'émission, qui détecte quelles µops sont prêtes à être émises. L'unité d'émission et la fenêtre d'instruction sont fusionnées ensemble, elles forment un seul circuit. Mais nous allons dire qu'elles sont conceptuellement séparées pour le moment. A chaque cycle, l'unité d'émission consulte la fenêtre d'instruction pour voir quelles µops peuvent s'exécuter, lesquelles ont leur opérandes de disponibles. La fenêtre d'instruction doit spécialement être conçue pour, c'est une sorte de mémoire associative très complexe, comme on le verra dans ce qui suit. [[File:OOO Issue.png|centre|vignette|upright=2.5|Exécution dans le désordre avec une fenêtre d'instruction]] Une fois qu'une µop sort du décodeur d'instructions, elle est ajoutée en parallèle dans la fenêtre d'instruction et le ROB. La raison est que les µops quittent la fenêtre d'instruction dans le désordre, et qu'elles doivent être remises en ordre par la suite. Le ROB s'occupe de cette remise en ordre, mais il a besoin de savoir dans quel ordre les µops sont censées être, et cet ordre est celui du décodage. Aussi, pour remplir le ROB, la seule opportunité est en sortie de l'unité de décodage. Dans le cas où une instruction est décodée en plusieurs micro-opérations, elles sont toutes insérées en même temps dans la fenêtre d'instruction et le ROB, en tenant compte de leur ordre. [[File:Fenêtre d'instruction.png|centre|vignette|upright=2|Fenêtre d'instruction.]] Les micro-opérations mémoire sont à part des autres, pour diverses raisons. Une de ces raisons est que les dépendances de données sont classées en deux types : les dépendances de registre et les dépendances d'adresse. Et les deux sont fondamentalement différentes. Autant on peut détecter les dépendances de registre lors de l'émission, autant c'est plus compliqué avec les dépendances d'adresse. De plus, rappelons que si les lectures peuvent s'exécuter dans le désordre, les écritures doivent s'exécuter dans l'ordre, ou du moins en donner l'illusion. Pour cela, le processeur remet les écritures dans l'ordre avec une sorte de mini-ROB intégré à l'unité mémoire, appelée la file d'écriture. Elle complémente le ROB, qui lui ne gère que les écritures dans les registres, mais les deux collaborent. La file d'écriture envoie une écriture à la mémoire RAM quand le ROB lui dit que c'est bon, les instructions précédentes sont terminées ''dans l'ordre du programme''. Les processeurs modernes ajoutent des techniques d'exécution dans le désordre des accès mémoire, mais nous les verrons dans un chapitre dédié. Elles permettent d'utiliser une fenêtre d'instruction unique, qui mémorise aussi les µops mémoire. Si elles sont mises en place, l'unité mémoire n'a pas besoin de file de µops séparée. L'idée est que les dépendances de registre sont traitées par la fenêtre d'instruction, mais que l'unité mémoire gére les dépendances d'adresse. Les dépendances d'adresse sont gérées par des techniques de ''désambiguation mémoire'', qui auront droit à un chapitre dédié. [[File:Processeur avec exécution dans le désodre des accès mémoire.png|centre|vignette|upright=2|Processeur avec exécution dans le désodre des accès mémoire]] Les processeurs assez anciens n'autorisaient pas d'exécution dans le désordre des accès mémoire. Concrétement, les accs mémoire devaient se faire dans l'ordre, mais les autres µops pouvaient être exécutées dans le désordre. Il s'agit donc d'un ordre entre µops mémoire, pas entre µops mémoire et autres µops. Les µops entières et flottantes pouvaient être exécutées avant une µops mémoire qui est avant elle dans l'ordre du programme, ce n'est pas un problème. Pour garantir l'ordre desd µops mémoire, l'unité mémoire est précédée par une file de micro-opérations séparée, pour forcer l'exécution dans l'ordre des accès mémoire. De plus, les µops mémoire ne peuvent pas utiliser la fenêtre d'instruction. Dit autrement, la fenêtre d'instruction ne mémorise pas de µops mémoire. Après le décodage, les µops sont réparties soit dans la file de µops mémoire, soit dans la fenêtre d'instruction. Le décodeur classe les µops suivant que ce sont des µops mémoire ou non, et les envoient à la bonne destination. Dans ce chapitre, on supposera que c'est cette solution qui est utilisée. [[File:Processeur avec émission dans l'ordre des accès mémoire.png|centre|vignette|upright=2|Processeur avec émission dans l'ordre des accès mémoire]] La solution précédente revient à scinder la fenêtre d'instruction en deux : une file de µops pour les µops mémoire, une fenêtre d'instruction pour les autres µops. Et cette scission peut aller plus loin, à savoir qu'on peut scinder une fenêtre d'instruction encore et encore. Ce qui nous amène à la section suivante. ===Les fenêtres d'instruction décentralisées=== Nous venons de voir qu'il est possible de scinder la fenêtre d'instruction en une fenêtre d'instruction pour les µops mémoire (simplifiée en une file de µops classique), et une autre pour les autres µops. Sachez qu'il est possible d'aller plus loin, par exemple en séparant la fenêtre d'instruction en une fenêtre spécialisée dans les µops flottantes et une autre pour les µops entières. Et ce n'est là qu'un exemple parmi de nombreuses autres possibilités. Pour faire la différence avec une fenêtre d'instruction unique, nous allons parler de fenêtre d'instruction centralisée s'il n'y en a qu'une, de '''fenêtre d'instruction décentralisée''' s'il y en a plusieurs. Il est possible d'associer chaque fenêtre d'instruction à un type précis de µops. Par exemple, avec une fenêtre d'instruction pour les µops de calcul entières, une autre pour les µops flottantes, une autre pour les µops mémoire. Il s'agit d'un choix simple et efficace, mais quelques processeurs font autrement, pour répondre à des contraintes très diverses. [[File:Processeur avec des fenêtres d'instruction décentralisées.png|centre|vignette|upright=2|Processeur avec des fenêtres d'instruction décentralisées]] Reste à scinder la fenêtre d'instruction pour trier les µops suivant leur type. Si le processeur exécute les accès mémoire dans l'ordre, la méthode la plus simple utilise une fenêtre d'instruction pour les opérations flottantes et une autre pour les autres µops (µops entières et parfois mémoire avec). L'avantage est que cela simplifie grandement le processeur. Les flottants sont gérés à part des entiers. Ils ont leurs propres registres, des FPU séparées des ALU entières, bref : la séparation est complète. Utiliser une fenêtre d'instruction séparée va dans ce sens. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Il est possible de faire pareil sur les processeurs avec exécution dans le désordre des accès mémoire. Par exemple : les processeurs Intel de microarchitecture Skylake utilisent une fenêtre d'instruction pour les opérations entières/flottantes, et une fenêtre d'instruction séparée pour les µops mémoire. Un avantage est que les deux fenêtres d'instructions sont plus spécialisées, ce qui entraine des économies de circuit. Les opérations entières/flottantes ont besoin de deux registres pour les opérandes et d'un autre résultat, alors que les µops mémoire n'ont besoin que de deux registres maximum. En utilisant une fenêtre d'instruction unique, chaque entrée doit mémoriser l'opcode et trois registres, dont un est inutilisé pour les µops mémoire et les branchements. En utilisant des fenêtres d’instructions séparées, celle pour les µops entières/flottantes a trois registres par entrée, contre seulement deux registres par entrée pour celle des µops mémoire. Un cas extrême est celui où chaque ALU/FPU a sa propre fenêtre d'instruction. Nous parlerons alors de '''fenêtres d'instruction totalement décentralisées'''. Par exemple, il y a une fenêtre d'instruction pour l'ALU entière, une autre pour le multiplieur entier, une autre pour le ''barrel shifter'', une autre pour l'unité mémoire, une autre pour l'unitéé de branchements, une autre pour l'additionneur flottant, une dernière pour le multiplier flottant, etc. Un exemple historique est celui de la FPU de l'IBM 360 modèle 90. Elle disposait d'un additionneur flottant, d'un multiplieur flottant, et d'une unité mémoire pour les lectures/écritures flottantes. Les trois unités avaient leur propre fenêtre d'instruction. Les processeurs AMD utilisent beaucoup cette technique, contrairement à Intel qui préfère utiliser des fenêtres centralisées sur les anciens processeurs, deux ou trois fenêtres sur les processeurs récents (2020 et plus). Les processeurs AMD utilisaient précisément une fenêtre d'instruction par ALU entière, alors que les FPUs partagent une fenêtre d’instructions flottantes unique. Mais nous verrons cela en détail dans le chapitre sur les processeurs superscalaires x86. Un point important est qu'avec des fenêtres d'instruction décentralisées, l'émission est découpée en deux étages. La première étape envoie une µops vers la fenêtre d'instruction adéquate, la seconde émet la µops depuis la fenêtre d'instruction quand ses opérandes sont prêtes. La première est l'étage de '''''dispatch''''' qui envoie l'instruction dans la fenêtre d’instruction adéquate, selon que c'est une instruction flottante, entière, autre. La seconde est l'étage de '''''scheduling''''', qui gère la disponibilité des opérandes et des unités de calcul. La µop émise est ajoutée au tampon de réordonnancement, s'il existe, lors de l'étape de ''dispatch''. ===L'usage de plusieurs files d'instruction=== Une dernière méthode d'OOO utilise plusieurs files de micro-opération. L'idée est qu'une fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement une file de micro-opération pour les opérations entières, une autre pour les opérations flottantes, une autre pour les accès mémoire. D'autres processeurs utilisent une file pour les accès mémoire et une autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. La présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que la technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si une dépendance bloque une FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans une autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer la disponibilité des registres. Quand un registre est lu ou écrit par une instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. La logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : une pour les instructions d'accès mémoire et une autre pour les autres instructions. Si jamais une instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de la lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'une est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est la file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. ===Avantages et inconvénients de chaque implémentation=== Pour résumer, on a le choix entre une grosse fenêtre d'instruction généraliste et plusieurs fenêtres spécialisées. Le choix entre les deux est un compromis entre économie de circuits et flexibilité. Avec une fenêtre décentralisée, il arrive qu'une fenêtre d'instruction soit remplie, alors que les autres sont sous-utilisées, voire vides. Pour comprendre pourquoi, comparons une fenêtre d'instruction unique, avec une fenêtre décentralisée séparant µops entières et flottantes. La fenêtre centralisée dispose de 64 entrées, la décentralisée a 32 entrées pour chaque fenêtre d'instruction. La fenêtre décentralisée peut mémoriser au maximum 32 µops entières et 32 *ops flottantes. Par contre, la fenêtre centralisée peut mémoriser 64 µops tout court. Si le programme exécuté n'utilise pas de nombres flottants, la différence devient flagrante. La fenêtre décentralisée sera limitée ) 32 µops, alors que la centralisée pourra mémoriser le double. Les performances seront donc meilleurs avec la fenêtre centralisée. Et au-delà de ça, la fenêtre décentralisée de l'exemple est utilisée de manière optimale si la moitié des µops sont des µops entières, et l'autre moitié des µops flottantes. Alors que la fenêtre centralisée se moque de la répartition entre µops entières et flottantes. Une subtilité est que le cout en transistors d'une fenêtre d'instruction n'est pas proportionnel au nombre de µops qu'elle peut mémoriser. Par exemple, si je compare une fenêtre d'instruction de 32 entrées (32 µops max), elle n'utilise pas deux fois plus transistors qu'une fenêtre de 16 entrées. Le cout en circuit n'est pas deux fois plus élevé, mais est approximativement 4 fois plus élevé. Le cout est presque quadratique, à savoir qu'il est proportionnel au carré du nombre d'entrées. Et il en est de même avec la performance, pour des raisons qu'on expliquera plus bas. Les fenêtres décentralisées utilisent plusieurs fenêtres d'instruction de "petite taille", donc plus rapides, économes en circuits et économes en énergie. Le compromis n'est donc pas entre une fenêtre centralisée à 64 entrées versus deux fenêtres de 32 entrées. Le compromis en pratique est entre une fenêtre centralisée de 64 entrées versus 3 fenêtres de 32 entrées. Un exemple pratique est celui de la microarchitecture ''Skylake'' d'Intel. Intel est passé d'une fenêtre centralisée pre-''Skylake'' à deux fenêtres décentralisées sur ''Skylake'',. Le nombre d'entrée était globalement le même entre les deux, même si l'évolution de la finesse de gravure entre les deux biaise un peu les résultats. Un avantage des fenêtres décentralisées est qu'il est possible de démarrer l'exécution de plusieurs µops simultanément : une µops par fenêtre d'instruction. Le fait est que deux fenêtres d'instructions différentes émettent leurs µops sans se synchroniser avec les autres. Deux fenêtres d'instruction peuvent donc émettre chacune une µops, ce qui fait deux µops émises lors du même cycle. Cela permet d'exécuter en même temps deux ou trois instructions 1-cycle, comme des additions, soustractions, décalages, etc. Il devient par exemple possible d'émettre une µop entière en même temps qu'une µop flottante, si les µops entières ont une fenêtre séparée de celle des µops flottantes. Il est maintenant temps de voir en quoi sont faites les fenêtres d’instruction, qu'elles soient centralisées ou décentralisées. Nous allons aussi voir quelle est la logique d'émission associée. ==L'implémentation d'une fenêtre d'instruction : généralités== Une fenêtre d'instruction est une mémoire qui mémorise des micro-opérations. Elle est cependant plus complexe qu'une mémoire RAM ou qu'une FIFO et ressemble un petit peu à une mémoire cache. Elle dispose d'un port d'écriture et d'un port de lecture, au minimum. Le port d'écriture permet à l'unité de décodage d'insérer une micro-opération dedans, d'ajouter la micro-opération qui vient d'être décodée. Si une instruction machine est décodée en plusieurs micro-opération, deux possibilités. La première est de les insérer un par un, ce qui fait qu'on peut se contenter d'un seul port d'écriture. L'autre possibilité est de les ajouter en même temps, ce qui demande plusieurs ports d'écriture. Le port de lecture sert à émettre une instruction. On part du principe que la fenêtre d'instruction ne peut émettre qu'une seule instruction à la fois, car les processeurs que nous avons vu précédemment sont de ce type. Mais nous verrons dans quelques chapitre qu'il existe des processeurs dits superscalaires, qui sont capables d'émettre plusieurs instructions par cycle. Dans ce cas, la fenêtre d'instruction a un seul port de lecture. Un processeur superscalaire, quant à lui, doit avoir un port de lecture par unité de calcul, ce qui fait beaucoup plus. Les fenêtres d'instruction sont composées d''''entrées''', des mots mémoire qui stockent une instruction. Une instruction réserve une entrée après son décodage et la libère dès qu'elle est envoyée aux unités de calcul. Une entrée contient l'opcode (les signaux de commande à envoyer à l'ALU), le registre de destination du résultat, les registres de chaque opérande, et éventuellement des signaux de commande en plus. De plus, chaque opérande est couplée à un bit de disponibilité, qui indique si elle est disponible. Quand un opérande est écrit dans les registres, le bit de présence correspondant est mis à jour. Enfin, chaque entrée possède un bit ''empty'' qui indique si elle est vide, cette information étant utile pour réserver des entrées. [[File:Entrée d'une station de réservation - sans les tags.png|centre|vignette|upright=3|Entrée d'une fenêtre d'instruction]] ===Les stations de réservation=== Les '''stations de réservation''' sont des fenêtres d'instruction particulières, qui sont capables de mémoriser les opérandes des instructions. Les entrées des stations de réservation sont identiques à celle des autres fenêtres d'instruction, si ce n'est que les opérandes de l'instruction sont enregistrées directement dans des champs séparés. Il y a deux champs, un par opérande, pour stocker l'opérande elle-même, lue depuis les registres ou obtenue via le réseau de contournement. Notons que les champs pour les opérandes viennent en plus des champs pour les noms de registres, encore que les deux peuvent être fusionnés si on veut optimiser le tout. [[File:Entrée d'une station de réservation.png|centre|vignette|upright=3|Entrée d'une station de réservation.]] Précisons que la terminologie n'est pas très fiable. Les termes "fenêtre d'instruction" et "station de réservation" ne regroupent pas du tout la même chose d'un papier de recherche à l'autre, d'un bouquin à l'autre, d'un chercheur à l'autre, d'un ingénieur à l'autre, d'un professeur à l'autre. Le terme initial vient pourtant de l'article original sur l'algorithme de Tomasulo, où il désignait une fenêtre d'instruction associée à une unité de calcul précise. Mais le terme a ensuite été réutilisé, ce qui fait que certains processeurs avec plusieurs unités de calcul sont décrit comme ayant une unique station de réservation. En bref : c'est le bazar ! Mais nous en reparlerons dans le chapitre sur le renommage de registres, car c'est la place idéale pour les aborder. Toujours est-il que j'ai fait le choix de confondre les concepts de fenêtre d'instruction et de station de réservation avec les concepts de '''lecture avant émission''' et de '''lecture après émission'''. La différence entre les deux est que les registres sont lus après émission avec une fenêtre d'instruction, avant avec des stations de réservation. Dans le cas "avant émission", les opérandes sont mémorisées dans la station de réservation. Et cette différence a une influence sur le pipeline du processeur, le banc de registres et tout ce qui s'en suit. Un désavantage de la lecture avant émission est qu'il faut stocker les opérandes après lecture, ici dans les stations de réservation. Mais un avantage est que le banc de registre a besoin de moins de ports de lecture, car une bonne partie des opérandes sont fournies par le système de contournement. Nous verrons cela dans le détail dans le chapitre sur les processeurs superscalaires. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Lecture après émission.]] [[File:Read Before Issue.png|centre|vignette|upright=2.5|Lecture avant émission.]] ===La logique d'éveil et de sélection=== Dans le cas qui va suivre, on suppose que le processeur ne peut émettre qu'une instruction à la fois. Chaque cycle, une instruction est sélectionnée et est envoyée dans le chemin de données, soit à une ALU, soit à une unité d'accès mémoire. La sélection d'une instruction est effectuée par l'unité d'émission, qui est aussi appelée le '''''scheduler'''''. Elle gère la disponibilité des opérandes et la disponibilité des unités de calcul adéquate. Le choix de l'instruction émise doit être le plus pertinent possible, pour des raisons de performances. Pour le premier point, l'unité d'émission détermine quelles instructions sont candidates pour l'émission. Les ''instructions candidates'' sont celles dont tous les opérandes sont prêts. Le processeur contient un circuit qui détecte les instructions candidates : la '''logique d’éveil''' (''wake-up logic''). Une fois que la logique d'éveil a fait son travail, une instruction est choisie pour s’exécuter en fonction de la disponibilité des unités de calcul adéquates. Ce rôle est dévolu à un circuit qu'on appelle la '''logique de sélection''', ou ''select logic''. [[File:Fonctionnement complet de la logique d’émission.jpg|centre|vignette|upright=1.5|Fonctionnement complet de la logique d’émission.]] La logique de sélection doit gérer le fait que les unités de calcul du processeur ne sont pas toutes identiques. Déjà, un processeur a généralement des unités séparées pour les instructions entières et flottantes, des unités spécialisées dans les accès mémoire, parfois des unités spécialisées pour les branchements. Une instruction doit être attribuée à la bonne unité de calcul, on ne doit pas envoyer une instruction entière dans une unité de calcul flottante. De plus, parmi les unités de calcul entières, toutes ne sont pas identiques. Par exemple, il est fréquent d'avoir plusieurs unités de calcul spécialisées dans les opérations simples (additions, soustractions, opérations logiques) avec une unité pour les multiplications/divisions séparées, parfois une unité spécialisée pour les décalages/rotations, etc. Là encore, allouer la bonne instruction à la bonne ALU est complexe. Plus les unités de calcul sont hétérogènes, plus la logique de sélection est compliquée. Les logiques d'éveil comme de sélection sont assez complexes. Comme on le verra plus bas, la logique de sélection la plus simple, qui gère une seule unité de calcul, est basée sur un encodeur à priorité couplé à d'autres circuits. Et pour gérer plusieurs ALUs, il faut mettre des encodeurs en cascade. Le résultat est que même en prenant une logique de sélection simple, elle sera assez lente et gourmande en circuits. Aussi, la logique de sélection met souvent un cycle d'horloge entier pour faire son travail, elle a son propre étage de pipeline attribué. La logique d'éveil est dans le même cas, ce qui fait qu'émettre une micro-opération demande deux cycles d'horloge. Le défaut est que cela rajoute des cycles d'horloges entre la fenêtre d'instruction et l'ALU, ce qui complique la gestion du pipeline. Ces cycles de retard sont à prendre en compte au moment d'émettre les instructions, les ''scheduler'' doit en tenir compte pour des performances optimales. Sans tenir compte de ces cycles de retard, les instructions arrivent en retard de quelques cycles à l'ALU, cycles de retard durant lesquels l'ALU n'a pas fait de calcul et a été sous-utilisée, sans compter que le système de contournement n'est pas utilisé au mieux. Et le problème est encore plus important sur les processeur avec des stations de réservation, qui utilisent la "lecture après émission" : cela rajoute un cycle d'horloge en plus, un temps de retard en plus. ===La logique d'éveil : l'émission anticipée=== La logique d'éveil doit tenir compte du fait qu'il y a plusieurs étages entre l'émission et l'exécution sur une unité de calcul. Par exemple, un processeur a souvent entre un et à cinq étages entre la file d'attente et les unités de calcul. Il faut lire les registres, gérer le contournement, et cela peut prendre quelques cycles d'horloge. Sur le Pentium 4, on trouve 6 étages entre la fenêtre d’instruction et l'entrée de l'ALU. Si les micro-opérations sont émises quand les opérandes sont disponibles, il y aura un délai de quelques cycles avant qu'elles atteignent l'ALU. Alors qu'idéalement, on souhaiterait que la micro-opération atteigne l'ALU dès que ses opérandes sont disponibles, pour profiter des techniques de contournement. Pour cela, la logique d'éveil émet les instructions quelques cycles en avance pour qu'elles arrivent au bon moment. Il s'agit d'une technique d''''émission anticipée''', dont nous avions parlé dans le chapitre sur le contournement. : Il faut noter que le problème se pose plus avec des fenêtres d'instruction qu'avec des stations de réservation. Les premières ont un étage en plus entre émission et ALU, vu qu'il faut lire des registres après l'émission. L'émission anticipée demande d'émettre un signal d'éveil en avance de quelques cycles, pile au bon moment. Par exemples, si on a deux étages entre l'ALU et l'unité d'émission, le signal de réveil sera généré deux cycles avant que le résultat soit effectivement calculé. L'implémentation varie, mais deux solutions sont possibles. La première est de générer le signal d'éveil dans l'ALU, ce qui n'a de sens que pour les opérations comme les multiplications ou les divisions, qui prennent plusieurs cycles. Une autre technique génère le signal de réveil dans une structure centralisée, spécialisée dans la génération des signaux d'éveil. L'unité de composée d'un registre à décalage par registre. Imaginons qu'une instruction est émise, que cette instruction mette N cycles à s'exécuter, et qu'elle écrive dans un registre de destination. L'unité sélectionne alors le registre à décalage associé au registre de destination, et met le bit numéro N à 1. Le registre décalé d'un cran à chaque cycle. Quand le bit sortant est un 1, alors le signal de validité pour l'opérande est généré. L'émission anticipée marche bien si l'instruction a une durée fixe, connue à l'avance. Et autant c'est le cas pour les instructions arithmétiques et logiques, autant ce n'est pas le cas pour les accès mémoire. Les accès mémoire ont une latence variable : quelques cycles pour un succès de cache, plusieurs dizaines de cycles pour un défaut de cache L1, pas loin de la centaine pour un défaut de cache L2, etc. Et cela pose des problèmes pour l'émission anticipée. L'émission en avance pour les accès mémoire est purement spéculative : le processeur émet des instructions en supposant que la lecture entrainera un succès de cache, quitte à annuler l'instruction en cas de défaut de cache. Mais faire ainsi demande non seulement d'annuler les instructions émises en avance, mais aussi de ne pas retirer les instructions émises en avance de la fenêtre d'instruction. Elles sont émises, mais une copie de sauvegarde est conservée dans la fenêtre d'instruction. Si le processeur détecte un défaut de cache, il peut alors ré-exécuter l'instruction. S'il détecte un succès de cache, les instructions lecture-dépendante sont retirées de la fenêtre d'instruction, la copie de sauvegarde est devenue inutile et est donc jetée. ===La logique de sélection : âge ou position ?=== La logique de sélection est primordiale pour de bonnes performances. Il existe deux méthodes principales pour sélectionner l'instruction à exécuter. La première est la plus simple : elle se base sur lé numéro de l'entrée. En effet, une fenêtre d'instruction est avant tout une sorte de mémoire, un mix entre mémoire associative, mémoire RAM, et FIFO. Et chaque entrée a un numéro, une adresse mémoire. Nous parlerons de numéro dans ce qui suit, car ce sera plus simple, le terme d'adresse mémoire étant peut-être un peu exagéré dans le contexte des fenêtres d'instruction. Toujours est-il que la fenêtre d'instruction est adressable dans le sens où on peut lui envoyer le numéro de l'entrée voulue, et la fenêtre d’instruction renvoie le contenu de l'entrée sur son port de lecture. Et c'est ce que fait la logique de sélection : elle génère le numéro de l'entrée à lire. Le numéro est alors envoyé sur l'entrée d'adresse de la fenêtre d’instruction, et elle fournit la micro-opération associée sur son port de lecture, son '''port d'émission'''. La première méthode de sélection, donc. Elle est basée sur sur le numéro de l'entrée. Si plusieurs entrées sont éveillées, la logique de sélection prend celle avec le plus petit numéro. Elle porte le nom de '''sélection par position''', sous-entendu position dans la fenêtre d'instruction. Vous l'avez peut-être deviné, mais la logique de sélection est alors un encodeur à priorité. Le circuit de sélection ne se résume donc pas seulement à un encodeur à priorité, mais c'est le circuit central. L'avantage d'une telle méthode de sélection est qu'elle est simple à implémenter : un encodeur à priorité est un circuit connu, facile à implémenter. Mais on remarque un défaut : un encodeur est un circuit assez rapide, mais qui utilise beaucoup de transistors, beaucoup de portes logiques, surtout si on veut qu'il soit rapide. Ce qui explique que la logique de sélection ait son propre étage de pipeline rien que pour elle. La seconde méthode s'appelle la '''sélection par âge''', au nom assez transparent. L'idée est de privilégier l'émission de l'instruction la plus ancienne. Elle demande que la fenêtre d'instruction trie les micro-opérations par ordre d'insertion dans la fenêtre d'instruction, ce qui en fait une pseudo-FIFO. Le tri est partiel, car les instructions peuvent sortir de la fenêtre d’instruction à tout moment. Compacter la fenêtre d'instruction, à savoir regrouper toutes les entrées valides est une idée, mais elle est compliquée à implémenter. Aussi, elles préfèrent encoder des informations sur l'ordre d'émission dans chaque entrée. L'encodeur à priorité doit alors travailler non pas sur des nombres entiers liés à l'ordre d'insertion dans la pseudo-FIFO. Elle est encore plus gourmande en circuits que la méthode précédente. Les processeurs haute performance utilisent souvent des méthodes hybrides. Par exemple, les processeurs AMD de microarchitecture Bulldozer utilisaient une méthode intermédiaire. Ils utilisaient une fenêtre d'instruction couplée à un encodeur à priorité pour la sélection par position, mais complémentaient le tout avec une unité qui mémorisait l'instruction la plus ancienne dans la fenêtre d’instruction. Le mécanisme de sélection par âge était utilisé en priorité. Mais si l'instruction la plus ancienne n'était pas prête, le processeur basculait sur le mécanisme de sélection par position. ===La compaction des fenêtres d'instruction=== À chaque cycle, les instructions décodées sont ajoutées dans la fenêtre d'instruction, dans des entrées vides. Vu que les instructions quittent celle-ci dans le désordre, ces vides sont dispersés dans la fenêtre d'instruction, ce qui pose problème pour déterminer où placer les nouvelles instructions. La solution la plus triviale consiste à conserver une liste des vides, mise à jour à chaque insertion ou émission d'instruction. Une autre solution consiste à éliminer les vides en compactant la fenêtre d'instruction à chaque cycle d'horloge. Des circuits se chargent de détecter les vides et de regrouper les instructions en un unique bloc. Il faut signaler que certaines processeurs arrivent à se passer de cette étape de compactage, mais au prix de fenêtres d'instruction nettement plus complexes. Autre problème : quand il faut choisir quelle instruction émettre, il y a toujours plusieurs candidats. Si on choisit mal, des instructions restent en attente trop longtemps parce que d'autres instructions plus jeunes leur passent devant. Pour éviter cela, les instructions les plus vielles, les plus anciennes, sont prioritaires. Pour cela, on peut utiliser une FIFO un peu spéciale pour la fenêtre d'instruction. Si les ajouts d'instruction se font dans l'ordre, les instructions ne quittent pas forcément la fenêtre d'instruction dans l'ordre imposé par une FIFO : les instructions restent triées dans leur ordre d'ajout, même s'il y a des vides entre elles. Dans ces condition, il est préférable que le compactage conserve l'ordre FIFO des instructions. Dans ces conditions, l'instruction la plus ancienne est celle qui est située à l'adresse la plus faible : le circuit de sélection peut donc être fabriqué avec des encodeurs, et est relativement simple. ==Les fenêtres d'instruction basées sur une matrice de dépendances== L'implémentation la plus simple étend le fonctionnement d'un pipeline dynamique usuel. Rappelez-vous le chapitre sur les pipeline dynamiques. Nous avions vu que de tels pipelines émettaient une instruction par cycle, quitte à émettre des bulles de pipeline en cas de dépendance bloquante. Et il est possible d'améliorer leur unité d'émission pour qu'elle soit compatible avec l'exécution dans le désordre. ===Rappels sur le registre de réservation/disponibilité=== L'émission d'une instruction est gouvernée par un ''registre de réservation'' qui indique quels registres sont réservés par une instruction, et ceux qui sont libres. Un registre réservé est un registre qui sera écrit par une instruction en cours d'exécution, mais qui n'a pas encore écrit son résultat. Les instructions candidates doivent avoir leurs opérandes dans des registres libres. Sinon, c'est signe que leurs opérandes sont réservées en écriture, donc pas encore écrites, donc pas disponibles. Si une instruction candidate veut lire ce registre, c'est signe qu'il y a une dépendance RAW : elle veut lire un registre réservé, qui est destiné à être écrit par une instruction en vol. Si elle veut écrire, c'est signe qu'elle veut écrire dans un registre où une autre instruction veut écrire : c'est une dépendance WAW. Dans les deux cas, l'instruction n'est pas émise. Le registre de réservation encode les registres réservés comme suit : chaque bit est associé à un registre. Le bit numéro 0 est associé au registre numéro 0, le bit numéro 1 au registre numéro 1, etc. Là, En clair, les numéros de registres réservés sont encodés en représentation non pas binaire, mais en représentation ''one-hot'' (vue au premier chapitre). {|class="wikitable" |+ Registre de réservation |- ! Registre 7 !! Registre 6 !! Registre 5 !! Registre 4 !! Registre 3 !! Registre 2 !! Registre 1 !! Registre 0 |- | 0 || 0 || 1 || 0 || 0 || 1 || 0 || 0 |} Avant d'émettre une instruction, l'unité d'émission extrait les registres opérande/destination et les convertis dans la même représentation que le registre de réservation, à savoir en représentation ''one-hot''. Le circuit de traduction binaire vers ''one-hot'' est, pour rappel, un simple décodeur. Puis, on fait un OU logique entre les sorties des décodeurs. Le résultat est un masque qui indique quels registres sont lus par l'instruction, encodé en représentation ''one-hot''. Appelons-le le '''masque d'opérandes'''. Le masque est alors comparé au registre de réservation pour vérifier si l'instruction peut être émise. [[File:Unité d'émission simple, dans l'ordre.png|centre|vignette|upright=2|Unité d'émission simple, dans l'ordre]] Si l'émission est autorisée, le registres de réservation est là aussi mis à jour. Le registre de réservation est aussi mis à jour dès qu'une instruction enregistre son résultat dans les registres, ou alors dès qu'il est disponible pour le contournement. Le bit associé au registre repasse alors à 0 (ou à 1). Sans contournement, la mise à jour se fait alors à la toute fin de l'instruction, quand elle se termine, lors de la dernière étape d'enregistrement, à la fin de son pipeline. Avec, elle se fait quand l'instruction quitte l'unité de calcul. ===L'extension à l'exécution dans le désordre : l'éveil par matrice de bits=== La différence entre un pipeline dynamique et l'exécution dans le désordre est que l'on passe d'une instruction à émettre à plusieurs. Plusieurs instructions sont mises en attente dans une fenêtre d’instruction, et y attendent leur tour. L'idée est alors d'envoyer le registre de disponibilité à toutes les entrées, à toutes les instructions en attente. Ainsi, on sait quelles sont les instructions qui peuvent s'exécuter et celles qui ne le peuvent pas. L'implémentation est assez simple, elle ressemble beaucoup à l'implémentation d'un pipeline dynamique simple, si ce n'est que des circuits sont dupliqués. L'implémentation utilise des fenêtres d'instruction légèrement différentes de celles introduites plus haut. Elles n'utilisent notamment pas de bits de disponibilité, mais autre chose. Lorsqu'une instruction est ajoutée à la fenêtre d'instruction, le masque de disponibilité des opérandes est stocké dans la fenêtre d'instruction. A chaque cycle, le registre de disponibilité est envoyée à toutes les entrées, et est comparé avec tous les masques de disponibilité des opérandes. Si une comparaison renvoie un 1, alors l'instruction de l'entrée est une instruction candidate à l'émission. [[File:Unité d'émission dans le désordre basée sur un registre de disponibilité.png|centre|vignette|upright=2.5|Unité d'émission dans le désordre basée sur un registre de disponibilité]] L'ensemble est implémenté avec l'aide d'une '''matrice de bits''', où chaque ligne correspond à une entrée et chaque colonne à un registre. À chaque croisement entre une ligne et une colonne, on trouve un bit. Si le bit de la ligne n et de la colonne m est à 1, cela veut dire : l'instruction dans l'entrée n a besoin de lire le registre m. S’il est à 0, alors cela veut dire que l'instruction stockée dans la ligne n n'a pas besoin de la donnée dans le registre m. [[File:Planificateur à matrice de bits.jpg|centre|vignette|upright=2|Planificateur à matrice de bits.]] Lorsqu'une instruction réserve une entrée, elle initialise la ligne en fonction des registres qu'elle souhaite lire. Pour vérifier si une instruction a ses opérandes prêts, le processeur compare le registre de disponibilité à la ligne associée à l'instruction/entrée. A chaque intersection ligne-colonne, se trouve un comparateur de 1 bit, qui détecte si le registre est demandé et disponible. Les résultats de cette porte sont ensuite envoyés à une porte ET, qui fait le gros du travail. [[File:Logique de détection de la disponibilité d'une instruction.jpg|centre|vignette|upright=2|Logique de détection de la disponibilité d'une instruction.]] ==Les fenêtres d'instruction basées sur une mémoire associative== Les processeurs modernes utilisent une mémoire associative pour la fenêtre d'instruction. Les mémoires associatives ont été abordées il y a quelques chapitres, mais faisons quelques rappels. Les mémoires associatives servent à accélérer la recherche de données dans un ensemble. Or, une fenêtre d'instruction vérifie régulièrement si chaque entrée est prête. Il s'agit d'un processus de recherche d'une instruction qui respecte une condition bien précise dans la mémoire, ce qui fait que les mémoires associatives sont donc tout indiquées. Comme vous le savez, les signaux de commande d'une instruction sont propagés avec celle-ci dans le pipeline, le nom du registre de destination ne faisant pas exception. Le nom de registre est envoyé à la fenêtre d'instruction lors de l'écriture du résultat dans les registres. S'il y a correspondance, l'opérande est disponible et son bit de disponibilité est mis à 1. On peut adapter cette méthode pour tenir compte du contournement assez simplement. [[File:Détection des dépendances par propagation du registre de destination.png|centre|vignette|upright=2|Détection des dépendances par propagation du registre de destination.]] En conséquence, le circuit de détection des dépendances est constitué d'un grand nombre de comparateurs : un par champ « nom de registre » dans chaque entrée. La logique d'éveil/''wake up'' regroupe tous les comparateurs, la logique de sélection est un circuit situé en-dehors de la mémoire associative. Les entrées sont dans la mémoire associative elle-même. [[File:Gestion des bits de validité.png|centre|vignette|upright=2|Gestion des bits de validité.]] L'implémentation la plus simple est celle du schéma précédent, où on utilise une mémoire associative unique. Une version plus élaborée sépare la fenêtre d'instruction en deux parties : une mémoire qui mémorise les registres des opérandes, une autre mémoire pour le reste. La mémoire pour les registres opérandes est la mémoire associative proprement dite, c'est elle qui est associées aux comparateurs, à la logique de ''wake-up''/réveil, etc. Par contre, l'autre mémoire est une mémoire RAM simplifiée, qui mémorise les informations qui n'ont pas besoin des comparateurs. L'opcode de l'instruction est là-dedans, par exemple. ===Les optimisations de la consommation d'énergie : la désactivation des portions inutilisées=== Le problème avec des fenêtres d'instruction de ce type est leur forte consommation énergétique, ainsi que le grand nombre de portes logiques utilisées, qui deviennent prohibitif pour des fenêtres d'instruction un peu grosses. Pour résoudre ce problème, certains ont optimisé les comparateurs. D'autres ont tenté de profiter du fait que la majorité des bits dans les entrées sont composés de zéros. Bref, les optimisations purement matérielles sont légion. Une première solution est de désactiver les entrées qui sont inutilisées, vides, sans instruction. Pour cela, on fait précéder les comparateurs par un circuit qui les connecte ou déconnecte des lignes de bit. Le circuit est commandé par le bit ''empty'' qui indique si une entrée est vide ou non. L'avantage est que la consommation d'énergie de la fenêtre d'instruction devient alors proportionnelle au nombre d'entrées non-vides, et non au nombre d'entrées total. Du moins, en apparence, les entrées non-utilisées doivent quand même être alimentées pour fonctionner, mais l'activité de comparaison disparait dans les entrées vides. Il est possible d'étendre cette technique aux entrées dont les opérandes sont prêtes. Les gains sont généralement assez bons, avec une réduction de consommation variant entre 30 et 50%, avec une implémentation très simple et très économe en circuits. Une autre solution, assez simple à mettre en place, consiste à désactiver une partie de la fenêtre d'instruction sin elle est inutilisée. Pour cela, il faut segmenter la fenêtre d'instruction avec la technique du ''wire partitionning''. Pour rappel, une fenêtre d'instruction est une mémoire associative. Et comme toute mémoire associative, elle contient des fils, les lignes de bit, qui relient les entrées/sorties à toutes les cellules mémoire. Plus une ligne de bit est longue, plus elle consomme d'énergie et plus le temps de lecture/écriture est long. L'idée est de segmenter les lignes de bits en plaçant des répéteurs qui recopient la tension d'un segment au suivant. Les répéteurs sont des tampons trois-états, ce qui permet de déconnecter les portions inutilisées de la ligne de bit. Ce faisant, la fenêtre d'instruction est découpée en segments, qui peuvent être désactivés si besoin. Si il y a peu d'instructions chargées dans la fenêtre d'instruction, les portions inutilisées sont désactivées. La technique marche d'autan mieux si les instructions sont compactées au début de la fenêtre d'instruction. [[File:Wire partitionning.png|centre|vignette|upright=2|Wire partitionning]] Tout le problème est de savoir quelles portions désactiver. La technique est assez simple si la fenêtre d'instruction est compactée, à savoir si toutes les instructions sont régulièrement regroupées au début de la mémoire CAM. Mais même avec cette optimisation, la décision de désactiver une portion de la fenêtre d'instruction n'est pas à prendre à la légère. Il ne faut pas désactiver une portion contenant des instructions pouvant être émise sous peu. La décision dépend de paramètres variés : proportion d'entrée vides, quantité d'entrées récemment activées/désactivées récemment, présences d'entrées avec un ''match'' d'opérandes récent, etc. Il est important de préciser que les techniques en question fonctionnent aussi sur les autres types de fenêtre d'instruction, qui ne sont pas basées sur des mémoires associatives. Nous allons voir celles-ci dans la suite du chapitre, mais gardez à l'esprit que ces optimisations, à savoir désactiver les entrées vides/prêts et partitionner la fenêtre d'instruction, sont des optimisations générales qui marchent avec presque tout. ===L'ajout d'une FIFO pour les instructions déjà prêtes à l'émission=== D'autres techniques permettent de réduire aussi bien le cout en circuits que la consommation d'énergie de la fenêtre d'instruction. L'idée est d'utiliser une mémoire associative quand elle est réellement nécessaire, mais d'utiliser une fenêtre d'instruction "normale" dès que possible. La méthode la plus simple tient compte du fait que certaines instructions ont déjà toutes leurs opérandes de disponibles à l'émission, mais doivent quand même être mises en attente, parce que l'ALU adéquate est occupée, parce que des dépendances WAW/WAR sont encore là, ou pour tout autre raison. Dans ce cas, elles sont mises en attente non pas dans la fenêtre d'instruction, mais dans une mémoire FIFO toute simple. L'idée est qu'au lieu d'avoir une énorme mémoire associative pour la fenêtre d'instruction, on déplace quelques entrées dans une petite FIFO annexe. Le résultat est un gain en terme d'énergie et de circuits, au prix d'une perte de performance mineure. La perte de performance en question se manifeste si aucune instruction n'a ses opérandes de prêtes à l'émission : le programme n'utilise pas la FIFO et voit alors une fenêtre d'instruction plus petite. Une amélioration de cette technique tient compte du fait que certaines instructions sont dans un cas intermédiaire. Elles ont déjà une opérande de prête lors de l'émission, mais pas l'autre. Le nombre d'opérandes varie suivant l’instruction : certaines n'ont besoin que d'un seul opérande. De plus, il arrive qu'une opération tout juste décodée ait déjà un ou plusieurs de ses opérandes de prêts. Cette constatation permet d'éviter d'utiliser des comparateurs pour les opérandes déjà prêts. Par exemple, on peut parfaitement utiliser trois fenêtres d'instruction : * une pour les instructions dont tous les opérandes sont prêts, mais qui sont quand même mises en attente, sans comparateur ; * une pour les instructions dont un seul opérande manque, qui n'utilise qu'un comparateur par entrée ; * une pour les instructions dont deux opérandes manquent à l'appel, qui utilise deux comparateurs par entrée. C'est beaucoup plus économique que d'utiliser une seule grosse fenêtre d'instruction qui contiendrait autant d'entrées que les trois précédentes réunies, avec deux comparateurs par entrée. Certains sont même allés plus loin, et ont proposé de supprimer la fenêtre d'instruction avec deux opérandes par entrée. Les instructions dont deux opérandes sont inconnus au décodage sont stockées dans la fenêtre d'instruction pour instructions avec un comparateur par entrée. Un circuit de prédiction se charge alors de prédire l'opérande manquant, cette prédiction étant vérifiée plus loin dans le pipeline. Il serait cependant étonnant qu'une telle proposition ait donné lieu à la moindre implémentation réelle. ===Les optimisations de la consommation d'énergie avancées=== D'autres chercheurs ont conservé une fenêtre d'instruction unique, avec autant de comparateurs par entrée qu'il y a d'opérandes possibles par instruction. Simplement, le processus de détection des opérandes prêts est légèrement ralenti : on ne vérifie qu'un opérande par cycle. Pour vérifier les deux opérandes d'une entrée, on doit attendre deux cycles. Enfin, certains chercheurs ont proposé des fenêtres d'instruction segmentées. Les instructions circulent à chaque cycle d'un segment vers le suivant : en conséquence, certains segments conservent les instructions les plus anciennes, un autre les instructions les plus jeunes, etc. Seul le denier segment, celui qui contient les instructions les plus vielles, peut émettre une instruction : la détection des opérandes se fait seulement dans le dernier segment, qui contient les instructions les plus anciennes. On économise ainsi beaucoup de comparateurs. Certains chercheurs ont tenté de pipeliner l'étape de sélection des opérandes, ainsi que l'étage d'arbitrage. Mais en faisant cela, il faut plusieurs cycles pour détecter qu'une instruction a ses opérandes prêts, ce qui pose problème face à de nombreuses dépendances RAW. Pour éviter de trop perdre en performances, certains chercheurs ont décidé d'utiliser des techniques pour prédire quelles seront les instructions dont les opérandes seront bientôt prêts. Si détecter qu'une instruction est prête prend n cycles, le processeur devra tenter de prédire la future disponibilité des opérandes n cycles en avance pour obtenir des performances optimales. ===Remplacer la mémoire associative par une RAM=== Une autre optimisation possible est de remplacer la fenêtre d'instruction par une mémoire RAM, dont chaque mot mémoire correspondrait à une entrée. Une telle optimisation permet en théorie de se passer des comparateurs associés à chaque entrée, mais au prix de l'ajout de circuits annexes potentiellement couteux. La première de ces techniques, la '''recherche directe par étiquette''' (direct tag search) fut créée par Weiss et son collègue Smith. Ils cherchaient à améliorer l'algorithme de Tomasulo, un algorithme qu'on expliquera dans quelques chapitres. Rappelons que chaque instruction produit un résultat, qui devra être rapatrié dans une ou plusieurs entrées de la fenêtre d'instruction. L'optimisation de la recherche directe par étiquette fonctionne dans le cas où le résultat de l'instruction n'est utilisé que par une seule entrée, et pas plusieurs. Le principe est simple : chaque champ « opérande » d'une entrée est adressable via le nom de registre de cette opérande. Pour faire le lien entre entrée et nom de registre, la recherche directe par étiquette ajoute une table de correspondances matérielle, une mémoire RAM qui mémorise les adresses des champs « opérande » des entrées. Les adresses envoyées dans cette mémoire sont les noms de registres des résultats. Lors de l'émission, la table de correspondances est mise à jour. Les numéros des champs « opérande » réservés lors de l'émission sont mémorisés dans les mots mémoire qui correspondent aux deux registres sources. Toutefois, une petite vérification est faite lors de l'émission : si il y a déjà une correspondance dans la table pour un registre source, alors une autre instruction compte lire ce registre. Pour éviter d'écraser les données de l'instruction précédente dans la table de correspondances, l'émission de l'instruction est bloquée. [[File:Recherche directe par étiquette.png|centre|vignette|upright=2|Recherche directe par étiquette.]] ==Les fenêtres d’instruction avec préplanification== Avec la '''préplanification''' (''prescheduling''), la fenêtre d’instruction est composée de mémoires FIFO dans lesquelles les instructions sont triées dans l'ordre d'émission. Il n'y a pas de logique d’émission proprement dite, celle-ci se bornant à vérifier si l'instruction située au début de la FIFO peut s’exécuter. Par contre, le préplanificateur détecte les dépendances et en déduit où insérer les instructions dans le tampon d'émission, à l'endroit le plus adéquat. [[File:Préplanification.jpg|centre|vignette|upright=2|Préplanification.]] ===L'usage de FIFO multiples=== La technique de préplanification la plus simple utilise plusieurs FIFO. Quand une instruction a une dépendance avec une autre instruction, les deux sont placées dans la même FIFO. Pour cela, le préplanificateur détecte les chaines d'instructions dépendantes, et place les instructions dans la FIFO adéquate. A chaque cycle, l'unité d'émission lit une micro-opération dans chaque FIFO et vérifie si elle peut l'émettre. Si la micro-opération n'a pas ses opérandes disponibles, ou qu'une dépendance structurelle survient, alors la FIFO est bloquée. La micro-opération attend que la dépendance soit résolue, bloquant toutes les instructions précédentes. Mais les autres FIFO ne sont pas bloquées, laissant de la marge de manœuvre. [[File:Préplanification par FIFO multiples.png|centre|vignette|upright=1.5|Préplanification par FIFO multiples.]] ===La technique du tampon trié=== La technique du '''tampon trié''' trie les instructions selon le temps d'attente avant leur exécution. Les instructions qui sont censées s’exécuter bientôt sont insérées au tout début de la FIFO, tandis que les instructions qui s’exécuteront dans un long moment sont insérées vers la fin. Là encore, l'unité d'émission lit une micro-opération dans la FIFO, et détermine si elle peut être émise. Si une dépendance survient, l'émission est retardée, et la FIFO est bloquée. [[File:Préplanification par tampon trié.png|centre|vignette|upright=1.5|Préplanification par tampon trié.]] La technique a cependant quelques problèmes assez importants. Le premier problème est que la FIFO est bloquée lorsqu'une micro-opération ne peut être émise. Le second problème est que le temps avant exécution n'est pas toujours connu, notamment pour les instructions d'accès mémoire. Et cela se répercute sur les instructions dépendantes de celles-ci. Pour résoudre ce genre de problèmes, l'usage d'un pipeline à ''replay'' est possible, et est même l'une des meilleures solution possible, malgré ses défauts. L'idée est que les lecture sont pré-planifiées en supposant qu'elles font un succès de cache L1. Si la prédiction est fausse, la lecture est ré-exécutée plusieurs cycles plus tard, en supposant qu'elle fait un succès dans le cache L2, et ainsi de suite. Elle est alors ré-insérée dans la FIFO, elle est pré-planifiée une seconde fois. Il en est de même si une micro-opération ne peut pas être émise : il suffit de la réinsérer dans la FIFO au bon endroit, en attendant que ses dépendances soient résolus. Ainsi, l'instruction fautive ne bloque pas la fenêtre d’instruction, et retente sa chance autant de fois qu'il le faut. [[File:Préplanification par fenêtre d’instruction scorebarodée.png|centre|vignette|upright=1.5|Préplanification par fenêtre d’instruction scorebarodée.]] Une autre solution utilise deux fenêtres d’instruction : une FIFO gérée par la préplanification, et une vraie fenêtre d'instruction pour les instructions dont le temps d'attente ne peut pas être déterminé. Il est possible de mettre cette dernière avant la préplanification, afin de gérer les temps d'attente des instructions d'accès mémoire. Quand le temps d'attente d'une lecture devient connu, ses instructions dépendantes sont gérées avec préplanification. [[File:Préplanification avec fenêtre d’instruction.png|centre|vignette|upright=2.5|Préplanification avec fenêtre d’instruction.]] ===Les fenêtres d'instruction avec allocation temporelle statique=== L''''allocation temporelle statique''' correspond à une technique utilisée sur les processeurs Cuzco de l'entreprise Condor. La technique en question a été présenté en 2025, mais des idées similaires ont été présentées dans la littérature académique. Elle ressemble beaucoup aux techniques de pré-planification, avec cependant quelques différences. L'idée est simple : le processeur dispose de plusieurs fenêtres d'instruction, qui mettent en attente les micro-opérations. Lors de l'étape de renommage de registres, le processeur détermine dans combien de cycles d'horloge la micro-opération sera prête pour exécution. La micro-opération est alors mise en attente durant ce nombre de cycles, dans les fenêtres d'instruction, puis est émise une fois ce nombre de cycles écoulés. Ce faisant, les fenêtres d'instruction n'ont pas besoin de détecter la disponibilité des opérandes à chaque cycle, pour chaque micro-opération en attente. Le ''timing'' de l'émission des micro-opérations est décidé à l'avance. L'implémentation exacte n'est pas connue, mais plusieurs solutions sont imaginables. Par exemple, la fenêtre d'instruction peut simplement être composée de plusieurs mémoires de petite taille, chacune contenant les micro-opérations destinées à être exécutées dans N cycles, N étant différent pour chaque mémoire. Une autre solution, plus réaliste, utilise une fenêtre d'instruction dans laquelle la micro-opération est couplée à des champs pour les opérandes, et un champ compteur. Le champ compteur est initialisé avec le nombre de cycles à attendre, et est décrémenté à chaque cycle d'horloge. Quand il atteint zéro, la micro-opération est émise. Vous remarquerez que la méthode ne marche que si toutes les micro-opérations prennent un nombre fixe de cycles d'horloge. Et autant c'est le cas pour les micro-opérations arithmétiques ou logiques, autant les accès mémoire ne rentrent pas dans ce cadre. En théorie, on ne sait pas combien de temps prendra un accès mémoire. Et cette incertitude se répercute sur les instructions dépendantes d'un accès mémoire. Pour éviter cela, le processeur réutilise un pipeline à ''replay'' tel que vu dans le chapitre précédent. L'unité de renommage de registre suppose que tout accès mémoire fait un succès de cache L1, et décide des ''timings'' d'émission sous cette hypothèse. Si une lecture subit un défaut de cache, elle est ré-exécutée, de même que toutes les instructions dépendantes. Pour cela, le registre de destination de la lecture est marqué comme invalide, grâce à un bit spécifique attaché au registre. Toute instruction qui lit une opérande invalide est elle aussi ré-executée de zéro. Pour simplifier, l'unité d'émission ressemble à une unité d'émission dans l'ordre, avec un registre de disponibilité, qu'on aurait amélioré pour aller au-delà de la simple détection des dépendances d'instruction. Pour déterminer les ''timings'' d'émission, à savoir quand émettre une micro-opération, le processeur utilise une unité d'émission à deux étages. Le premier étage est appelé le ''register scoreboard'', le second étage est appelé la ''Time Ressource Matrix''. Les deux étages communiquent entre eux, comme on va le voir, et leurs noms donnent une idée de ce qu'ils font. Le premier étage gère les dépendances de registres, le second gère les dépendances structurelles. Le premier étage est un registre de disponibilité amélioré, qui gère les dépendances de registre. Cet étage sait quand tel registre sera écrit, et donc que l'opérande écrite dedans sera disponible à partir de tel cycle d'horloge. Il le sait car l'étage suivant l'aura prévenu, mais laissons cela de côté pour le moment. Quand une micro-opération rentre dans cet étage, il vérifie les dépendances avec les registres et les micro-opérations antérieures. Vu qu'il sait quand les registres seront disponibles, il peut déterminer quand l'instruction pourra s'exécuter. Par exemple, si une micro-opération lit les deux registres R7 et R15, qui sont disponibles respectivement dans 5 et 7 cycles, le premier étage sait que la micro-opération devra attendre 7 cycles. Mais tout cela ne suffit pas à déterminer quand émettre une micro-opération. En effet, il fait aussi gérer les dépendances structurelles, ce qui est le boulot du second étage. Le second étage utilise pour cela une ''Time Ressource Matrix'', qui mémorise l'occupation de diverses "ressources", pour les 256 cycles d'horloge à venir. Les ressources en question sont les ports de lecture/écriture du banc de registre, les ALUs utilisées, si la micro-opération utilise l'unité mémoire, etc. Le second étage prend en entrée une micro-opération, détermine quelles "ressources" elle utilise, puis regarde leur disponibilité. Elle détecte alors les dépendances structurelles et détermine alors quand peut s'exécuter la micro-opération. Elle peut retarder l'émission de quelques cycles, si une dépendance structurelle est détectée. Une fois sortie du second étage, on sait quand la micro-opération va être émise, à quel cycle précisément. Et vu que la durée de l'instruction est fixe, on sait quand cette micro-opération va se terminer, quand son résultat sera disponible. Cela permet de mettre à jour la ''Time Ressource Matrix'', pour préciser que le port d'écriture sera occupé à tel moment. De plus, cette information est transmise au premier étage, qui sait alors quand est enregistré le résultat dans le registre de destination. C'est comme cela que le premier étage sait quand un registre est disponible : le second étage le prévient, quand il émet une instruction ! La ''Time Ressource Matrix''mémorise l'occupation des "ressources" pour les 256 cycles d'horloge à venir. Cependant, elle ne vérifie pas les dépendances pour les 256 cycles suivants. Quand elle reçoit une micro-opération, elle teste les dépendances structurelles pour seulement les 8 prochains cycles maximum. Si la micro-opération ne peut pas être émise pendant ces 8 cycles, le pipeline est bloqué, un ''pipeline stall'' est émis. Pour être plus précis, vu que le processeur peut décoder 8 micro-opérations en même temps, cela permet de ne consulter que 64 cycles d'horloge sur les 256. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les premiers processeurs Intel | prevText=Les premiers processeurs Intel | next=Le renommage de registres | nextText=Le renommage de registres }} </noinclude> hsxl4kyegn107xllhn6n0sn2agxvu42 773604 773603 2026-09-29T19:46:12Z Mewtow 31375 /* Les fenêtres d'instruction basées sur une mémoire associative */ 773604 wikitext text/x-wiki Dans les chapitres précédents, nous avons parlé des techniques dites d''''émission dans l'ordre'''. L'idée est d’exécuter une nouvelle micro-opération à chaque cycle, dans des unités de calcul séparées. Les instructions sont émises consécutivement, mais les instructions s’exécutent en parallèle dans des unités de calcul séparées. Par contre, quand l'unité d'émission ne peut pas émettre une instruction, elle bloque tout le pipeline. Les instructions qui suivent sont elles aussi bloquées, elle doivent attendre leur tour, même si elles sont en capacité de s'exécuter. Les techniques d'exécution dans le désordre que nous allons voir dans ce chapitre corrigent ce point précis. Elles sont dites à '''émission dans le désordre'''. Elles se distinguent des précédentes sur un point précis : quand l'unité d'émission bloque l'émission d'une instruction, les instructions suivantes peuvent poursuivre. L'émission des instructions peut donc se faire dans le désordre, dans le sens où une instruction peut être émise alors qu'une instruction précédente ne l'est pas encore. L'avantage de l'émission dans le désordre est qu'une instruction s'exécute dès que ses opérandes sont disponibles. Par disponible, on veut dire présent soit dans le réseau de contournement, soit dans les registres. Le processeur détecte automatiquement quand les opérandes d'une instruction sont sont disponibles, et il l’exécute à ce moment là. Dès qu'une instruction a ses opérandes disponibles, elle est émise et exécutée. C'est là la seule contrainte : les dépendances WAR, WAW et autres sont gérées par un ROB ou toute autre technique d'exception précise, seules les dépendances RAW limitent l'exécution. Mais avant de poursuivre, quelques point niveaux terminologie : * L'émission dans le désordre est un terme parlant et assez précis. Malheureusement, la terminologie la plus utilisée par d''''exécution dans le désordre'''. Et nous utiliserons ce terme dans la suite du cours, histoire de ne pas trop dévier de la nomenclature habituelle. * Nous utiliserons parfois l'abréviation OOO pour parler d'exécution dans le désordre. L'abréviation est celle de ''Out Of Order Excution''. * Nous utiliserons aussi l'abréviation ''µop'' pour parler de micro-opération, ''µops'' au pluriels pour parler de plusieurs micro-opérations, ou des micro-opérations en général. L'exécution dans le désordre ne gére en effet que des µops, elle se situe après l'étape de décodage. Mais avant de poursuivre, précisons une chose importante : l'exécution dans le désordre traite les accès mémoire à part. La majorité des processeurs OOO assez anciens exécutent les accès mémoire dans l'ordre, seules les µops entières/flottantes/branchements sont exécutées dans le désordre. Les processeurs datant d'après les années 2010 sont capable d'exécuter les accès mémoire dans le désordre, mais l'implémentation en question est assez particulière. Un chapitre entier sera dédié à l'exécution dans le désordre des µops mémoire. Nous allons volontairement mettre de côté la gestion des accès mémoire dans ce chapitre. ==Les fenêtres d’instruction : généralités== [[File:File de micro-opération.png|vignette|upright=1|File de micro-opérations]] Pour décrire comment est implémentée l'émission dans le désordre, il faut commencer par parler des processeurs sans. Les processeurs sans exécution dans le désordre ont une unité d'émission qui bloque tout le pipeline dès qu'une µop ne peut pas être émise. Pour limiter l'impact de ce blocage, quelques rares processeurs incorporent une '''file de micro-opération''', une mémoire FIFO qui met en attente les µops. Vu que c'est une mémoire FIFO, les µops sont émises dans l'ordre, à savoir l'ordre d'ajout, dans l'ordre de décodage. Le schéma ci-dessous illustre une telle file d'attente couplée à un ''scoreboard''. Sur le principe, l'exécution dans le désordre améliore la file de µops sur un point : ce n'est plus une mémoire FIFO. Les µops sont insérées dans l'ordre, mais peuvent sortir dans le désordre (être émises dans le désordre). La file de µops devient alors une '''fenêtre d'instruction''', terme traduit directement de l'anglais ''instruction Window''. Terme assez trompeur, car elles mettent en attente des µops, pas des instructions. Elles peuvent émettre des µops dans le désordre, ce qui fait que si une µop bloque le pipeline, les µops suivantes peuvent être émises. Si je commence le paragraphe précédent par "sur le principe", c'est car certaines techniques d'OOO utilisent des files de µops normales. Il est par exemple possible d'utiliser une file de µops avec une fenêtre d'instruction, plusieurs files de µops, plusieurs fenêtres d'instructions avec une file de µops annexe, etc. Dasn les grandes lignes, il existe dans les grandes lignes 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! File de µops améliorée |- ! Une seule "file de µops" | ''Scoreboard'' | Fenêtre d'instruction centralisée |- ! Plusieurs "file de µops" | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | Fenêtre d'instruction décentralisée |} ===La fenêtre d'instruction centralisée=== L'implémentation la plus simple de l'OOO utilise une unique '''fenêtre d'instruction'''. Les instructions décodées sont accumulées dans la fenêtre d'instruction, où elles attendent que leurs opérandes soient disponibles. La fenêtre d'instruction sert donc de file d'attente. Mais elle contient aussi une unité d'émission, qui détecte quelles µops sont prêtes à être émises. L'unité d'émission et la fenêtre d'instruction sont fusionnées ensemble, elles forment un seul circuit. Mais nous allons dire qu'elles sont conceptuellement séparées pour le moment. A chaque cycle, l'unité d'émission consulte la fenêtre d'instruction pour voir quelles µops peuvent s'exécuter, lesquelles ont leur opérandes de disponibles. La fenêtre d'instruction doit spécialement être conçue pour, c'est une sorte de mémoire associative très complexe, comme on le verra dans ce qui suit. [[File:OOO Issue.png|centre|vignette|upright=2.5|Exécution dans le désordre avec une fenêtre d'instruction]] Une fois qu'une µop sort du décodeur d'instructions, elle est ajoutée en parallèle dans la fenêtre d'instruction et le ROB. La raison est que les µops quittent la fenêtre d'instruction dans le désordre, et qu'elles doivent être remises en ordre par la suite. Le ROB s'occupe de cette remise en ordre, mais il a besoin de savoir dans quel ordre les µops sont censées être, et cet ordre est celui du décodage. Aussi, pour remplir le ROB, la seule opportunité est en sortie de l'unité de décodage. Dans le cas où une instruction est décodée en plusieurs micro-opérations, elles sont toutes insérées en même temps dans la fenêtre d'instruction et le ROB, en tenant compte de leur ordre. [[File:Fenêtre d'instruction.png|centre|vignette|upright=2|Fenêtre d'instruction.]] Les micro-opérations mémoire sont à part des autres, pour diverses raisons. Une de ces raisons est que les dépendances de données sont classées en deux types : les dépendances de registre et les dépendances d'adresse. Et les deux sont fondamentalement différentes. Autant on peut détecter les dépendances de registre lors de l'émission, autant c'est plus compliqué avec les dépendances d'adresse. De plus, rappelons que si les lectures peuvent s'exécuter dans le désordre, les écritures doivent s'exécuter dans l'ordre, ou du moins en donner l'illusion. Pour cela, le processeur remet les écritures dans l'ordre avec une sorte de mini-ROB intégré à l'unité mémoire, appelée la file d'écriture. Elle complémente le ROB, qui lui ne gère que les écritures dans les registres, mais les deux collaborent. La file d'écriture envoie une écriture à la mémoire RAM quand le ROB lui dit que c'est bon, les instructions précédentes sont terminées ''dans l'ordre du programme''. Les processeurs modernes ajoutent des techniques d'exécution dans le désordre des accès mémoire, mais nous les verrons dans un chapitre dédié. Elles permettent d'utiliser une fenêtre d'instruction unique, qui mémorise aussi les µops mémoire. Si elles sont mises en place, l'unité mémoire n'a pas besoin de file de µops séparée. L'idée est que les dépendances de registre sont traitées par la fenêtre d'instruction, mais que l'unité mémoire gére les dépendances d'adresse. Les dépendances d'adresse sont gérées par des techniques de ''désambiguation mémoire'', qui auront droit à un chapitre dédié. [[File:Processeur avec exécution dans le désodre des accès mémoire.png|centre|vignette|upright=2|Processeur avec exécution dans le désodre des accès mémoire]] Les processeurs assez anciens n'autorisaient pas d'exécution dans le désordre des accès mémoire. Concrétement, les accs mémoire devaient se faire dans l'ordre, mais les autres µops pouvaient être exécutées dans le désordre. Il s'agit donc d'un ordre entre µops mémoire, pas entre µops mémoire et autres µops. Les µops entières et flottantes pouvaient être exécutées avant une µops mémoire qui est avant elle dans l'ordre du programme, ce n'est pas un problème. Pour garantir l'ordre desd µops mémoire, l'unité mémoire est précédée par une file de micro-opérations séparée, pour forcer l'exécution dans l'ordre des accès mémoire. De plus, les µops mémoire ne peuvent pas utiliser la fenêtre d'instruction. Dit autrement, la fenêtre d'instruction ne mémorise pas de µops mémoire. Après le décodage, les µops sont réparties soit dans la file de µops mémoire, soit dans la fenêtre d'instruction. Le décodeur classe les µops suivant que ce sont des µops mémoire ou non, et les envoient à la bonne destination. Dans ce chapitre, on supposera que c'est cette solution qui est utilisée. [[File:Processeur avec émission dans l'ordre des accès mémoire.png|centre|vignette|upright=2|Processeur avec émission dans l'ordre des accès mémoire]] La solution précédente revient à scinder la fenêtre d'instruction en deux : une file de µops pour les µops mémoire, une fenêtre d'instruction pour les autres µops. Et cette scission peut aller plus loin, à savoir qu'on peut scinder une fenêtre d'instruction encore et encore. Ce qui nous amène à la section suivante. ===Les fenêtres d'instruction décentralisées=== Nous venons de voir qu'il est possible de scinder la fenêtre d'instruction en une fenêtre d'instruction pour les µops mémoire (simplifiée en une file de µops classique), et une autre pour les autres µops. Sachez qu'il est possible d'aller plus loin, par exemple en séparant la fenêtre d'instruction en une fenêtre spécialisée dans les µops flottantes et une autre pour les µops entières. Et ce n'est là qu'un exemple parmi de nombreuses autres possibilités. Pour faire la différence avec une fenêtre d'instruction unique, nous allons parler de fenêtre d'instruction centralisée s'il n'y en a qu'une, de '''fenêtre d'instruction décentralisée''' s'il y en a plusieurs. Il est possible d'associer chaque fenêtre d'instruction à un type précis de µops. Par exemple, avec une fenêtre d'instruction pour les µops de calcul entières, une autre pour les µops flottantes, une autre pour les µops mémoire. Il s'agit d'un choix simple et efficace, mais quelques processeurs font autrement, pour répondre à des contraintes très diverses. [[File:Processeur avec des fenêtres d'instruction décentralisées.png|centre|vignette|upright=2|Processeur avec des fenêtres d'instruction décentralisées]] Reste à scinder la fenêtre d'instruction pour trier les µops suivant leur type. Si le processeur exécute les accès mémoire dans l'ordre, la méthode la plus simple utilise une fenêtre d'instruction pour les opérations flottantes et une autre pour les autres µops (µops entières et parfois mémoire avec). L'avantage est que cela simplifie grandement le processeur. Les flottants sont gérés à part des entiers. Ils ont leurs propres registres, des FPU séparées des ALU entières, bref : la séparation est complète. Utiliser une fenêtre d'instruction séparée va dans ce sens. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Il est possible de faire pareil sur les processeurs avec exécution dans le désordre des accès mémoire. Par exemple : les processeurs Intel de microarchitecture Skylake utilisent une fenêtre d'instruction pour les opérations entières/flottantes, et une fenêtre d'instruction séparée pour les µops mémoire. Un avantage est que les deux fenêtres d'instructions sont plus spécialisées, ce qui entraine des économies de circuit. Les opérations entières/flottantes ont besoin de deux registres pour les opérandes et d'un autre résultat, alors que les µops mémoire n'ont besoin que de deux registres maximum. En utilisant une fenêtre d'instruction unique, chaque entrée doit mémoriser l'opcode et trois registres, dont un est inutilisé pour les µops mémoire et les branchements. En utilisant des fenêtres d’instructions séparées, celle pour les µops entières/flottantes a trois registres par entrée, contre seulement deux registres par entrée pour celle des µops mémoire. Un cas extrême est celui où chaque ALU/FPU a sa propre fenêtre d'instruction. Nous parlerons alors de '''fenêtres d'instruction totalement décentralisées'''. Par exemple, il y a une fenêtre d'instruction pour l'ALU entière, une autre pour le multiplieur entier, une autre pour le ''barrel shifter'', une autre pour l'unité mémoire, une autre pour l'unitéé de branchements, une autre pour l'additionneur flottant, une dernière pour le multiplier flottant, etc. Un exemple historique est celui de la FPU de l'IBM 360 modèle 90. Elle disposait d'un additionneur flottant, d'un multiplieur flottant, et d'une unité mémoire pour les lectures/écritures flottantes. Les trois unités avaient leur propre fenêtre d'instruction. Les processeurs AMD utilisent beaucoup cette technique, contrairement à Intel qui préfère utiliser des fenêtres centralisées sur les anciens processeurs, deux ou trois fenêtres sur les processeurs récents (2020 et plus). Les processeurs AMD utilisaient précisément une fenêtre d'instruction par ALU entière, alors que les FPUs partagent une fenêtre d’instructions flottantes unique. Mais nous verrons cela en détail dans le chapitre sur les processeurs superscalaires x86. Un point important est qu'avec des fenêtres d'instruction décentralisées, l'émission est découpée en deux étages. La première étape envoie une µops vers la fenêtre d'instruction adéquate, la seconde émet la µops depuis la fenêtre d'instruction quand ses opérandes sont prêtes. La première est l'étage de '''''dispatch''''' qui envoie l'instruction dans la fenêtre d’instruction adéquate, selon que c'est une instruction flottante, entière, autre. La seconde est l'étage de '''''scheduling''''', qui gère la disponibilité des opérandes et des unités de calcul. La µop émise est ajoutée au tampon de réordonnancement, s'il existe, lors de l'étape de ''dispatch''. ===L'usage de plusieurs files d'instruction=== Une dernière méthode d'OOO utilise plusieurs files de micro-opération. L'idée est qu'une fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement une file de micro-opération pour les opérations entières, une autre pour les opérations flottantes, une autre pour les accès mémoire. D'autres processeurs utilisent une file pour les accès mémoire et une autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. La présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que la technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si une dépendance bloque une FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans une autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer la disponibilité des registres. Quand un registre est lu ou écrit par une instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. La logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : une pour les instructions d'accès mémoire et une autre pour les autres instructions. Si jamais une instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de la lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'une est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est la file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. ===Avantages et inconvénients de chaque implémentation=== Pour résumer, on a le choix entre une grosse fenêtre d'instruction généraliste et plusieurs fenêtres spécialisées. Le choix entre les deux est un compromis entre économie de circuits et flexibilité. Avec une fenêtre décentralisée, il arrive qu'une fenêtre d'instruction soit remplie, alors que les autres sont sous-utilisées, voire vides. Pour comprendre pourquoi, comparons une fenêtre d'instruction unique, avec une fenêtre décentralisée séparant µops entières et flottantes. La fenêtre centralisée dispose de 64 entrées, la décentralisée a 32 entrées pour chaque fenêtre d'instruction. La fenêtre décentralisée peut mémoriser au maximum 32 µops entières et 32 *ops flottantes. Par contre, la fenêtre centralisée peut mémoriser 64 µops tout court. Si le programme exécuté n'utilise pas de nombres flottants, la différence devient flagrante. La fenêtre décentralisée sera limitée ) 32 µops, alors que la centralisée pourra mémoriser le double. Les performances seront donc meilleurs avec la fenêtre centralisée. Et au-delà de ça, la fenêtre décentralisée de l'exemple est utilisée de manière optimale si la moitié des µops sont des µops entières, et l'autre moitié des µops flottantes. Alors que la fenêtre centralisée se moque de la répartition entre µops entières et flottantes. Une subtilité est que le cout en transistors d'une fenêtre d'instruction n'est pas proportionnel au nombre de µops qu'elle peut mémoriser. Par exemple, si je compare une fenêtre d'instruction de 32 entrées (32 µops max), elle n'utilise pas deux fois plus transistors qu'une fenêtre de 16 entrées. Le cout en circuit n'est pas deux fois plus élevé, mais est approximativement 4 fois plus élevé. Le cout est presque quadratique, à savoir qu'il est proportionnel au carré du nombre d'entrées. Et il en est de même avec la performance, pour des raisons qu'on expliquera plus bas. Les fenêtres décentralisées utilisent plusieurs fenêtres d'instruction de "petite taille", donc plus rapides, économes en circuits et économes en énergie. Le compromis n'est donc pas entre une fenêtre centralisée à 64 entrées versus deux fenêtres de 32 entrées. Le compromis en pratique est entre une fenêtre centralisée de 64 entrées versus 3 fenêtres de 32 entrées. Un exemple pratique est celui de la microarchitecture ''Skylake'' d'Intel. Intel est passé d'une fenêtre centralisée pre-''Skylake'' à deux fenêtres décentralisées sur ''Skylake'',. Le nombre d'entrée était globalement le même entre les deux, même si l'évolution de la finesse de gravure entre les deux biaise un peu les résultats. Un avantage des fenêtres décentralisées est qu'il est possible de démarrer l'exécution de plusieurs µops simultanément : une µops par fenêtre d'instruction. Le fait est que deux fenêtres d'instructions différentes émettent leurs µops sans se synchroniser avec les autres. Deux fenêtres d'instruction peuvent donc émettre chacune une µops, ce qui fait deux µops émises lors du même cycle. Cela permet d'exécuter en même temps deux ou trois instructions 1-cycle, comme des additions, soustractions, décalages, etc. Il devient par exemple possible d'émettre une µop entière en même temps qu'une µop flottante, si les µops entières ont une fenêtre séparée de celle des µops flottantes. Il est maintenant temps de voir en quoi sont faites les fenêtres d’instruction, qu'elles soient centralisées ou décentralisées. Nous allons aussi voir quelle est la logique d'émission associée. ==L'implémentation d'une fenêtre d'instruction : généralités== Une fenêtre d'instruction est une mémoire qui mémorise des micro-opérations. Elle est cependant plus complexe qu'une mémoire RAM ou qu'une FIFO et ressemble un petit peu à une mémoire cache. Elle dispose d'un port d'écriture et d'un port de lecture, au minimum. Le port d'écriture permet à l'unité de décodage d'insérer une micro-opération dedans, d'ajouter la micro-opération qui vient d'être décodée. Si une instruction machine est décodée en plusieurs micro-opération, deux possibilités. La première est de les insérer un par un, ce qui fait qu'on peut se contenter d'un seul port d'écriture. L'autre possibilité est de les ajouter en même temps, ce qui demande plusieurs ports d'écriture. Le port de lecture sert à émettre une instruction. On part du principe que la fenêtre d'instruction ne peut émettre qu'une seule instruction à la fois, car les processeurs que nous avons vu précédemment sont de ce type. Mais nous verrons dans quelques chapitre qu'il existe des processeurs dits superscalaires, qui sont capables d'émettre plusieurs instructions par cycle. Dans ce cas, la fenêtre d'instruction a un seul port de lecture. Un processeur superscalaire, quant à lui, doit avoir un port de lecture par unité de calcul, ce qui fait beaucoup plus. Les fenêtres d'instruction sont composées d''''entrées''', des mots mémoire qui stockent une instruction. Une instruction réserve une entrée après son décodage et la libère dès qu'elle est envoyée aux unités de calcul. Une entrée contient l'opcode (les signaux de commande à envoyer à l'ALU), le registre de destination du résultat, les registres de chaque opérande, et éventuellement des signaux de commande en plus. De plus, chaque opérande est couplée à un bit de disponibilité, qui indique si elle est disponible. Quand un opérande est écrit dans les registres, le bit de présence correspondant est mis à jour. Enfin, chaque entrée possède un bit ''empty'' qui indique si elle est vide, cette information étant utile pour réserver des entrées. [[File:Entrée d'une station de réservation - sans les tags.png|centre|vignette|upright=3|Entrée d'une fenêtre d'instruction]] ===Les stations de réservation=== Les '''stations de réservation''' sont des fenêtres d'instruction particulières, qui sont capables de mémoriser les opérandes des instructions. Les entrées des stations de réservation sont identiques à celle des autres fenêtres d'instruction, si ce n'est que les opérandes de l'instruction sont enregistrées directement dans des champs séparés. Il y a deux champs, un par opérande, pour stocker l'opérande elle-même, lue depuis les registres ou obtenue via le réseau de contournement. Notons que les champs pour les opérandes viennent en plus des champs pour les noms de registres, encore que les deux peuvent être fusionnés si on veut optimiser le tout. [[File:Entrée d'une station de réservation.png|centre|vignette|upright=3|Entrée d'une station de réservation.]] Précisons que la terminologie n'est pas très fiable. Les termes "fenêtre d'instruction" et "station de réservation" ne regroupent pas du tout la même chose d'un papier de recherche à l'autre, d'un bouquin à l'autre, d'un chercheur à l'autre, d'un ingénieur à l'autre, d'un professeur à l'autre. Le terme initial vient pourtant de l'article original sur l'algorithme de Tomasulo, où il désignait une fenêtre d'instruction associée à une unité de calcul précise. Mais le terme a ensuite été réutilisé, ce qui fait que certains processeurs avec plusieurs unités de calcul sont décrit comme ayant une unique station de réservation. En bref : c'est le bazar ! Mais nous en reparlerons dans le chapitre sur le renommage de registres, car c'est la place idéale pour les aborder. Toujours est-il que j'ai fait le choix de confondre les concepts de fenêtre d'instruction et de station de réservation avec les concepts de '''lecture avant émission''' et de '''lecture après émission'''. La différence entre les deux est que les registres sont lus après émission avec une fenêtre d'instruction, avant avec des stations de réservation. Dans le cas "avant émission", les opérandes sont mémorisées dans la station de réservation. Et cette différence a une influence sur le pipeline du processeur, le banc de registres et tout ce qui s'en suit. Un désavantage de la lecture avant émission est qu'il faut stocker les opérandes après lecture, ici dans les stations de réservation. Mais un avantage est que le banc de registre a besoin de moins de ports de lecture, car une bonne partie des opérandes sont fournies par le système de contournement. Nous verrons cela dans le détail dans le chapitre sur les processeurs superscalaires. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Lecture après émission.]] [[File:Read Before Issue.png|centre|vignette|upright=2.5|Lecture avant émission.]] ===La logique d'éveil et de sélection=== Dans le cas qui va suivre, on suppose que le processeur ne peut émettre qu'une instruction à la fois. Chaque cycle, une instruction est sélectionnée et est envoyée dans le chemin de données, soit à une ALU, soit à une unité d'accès mémoire. La sélection d'une instruction est effectuée par l'unité d'émission, qui est aussi appelée le '''''scheduler'''''. Elle gère la disponibilité des opérandes et la disponibilité des unités de calcul adéquate. Le choix de l'instruction émise doit être le plus pertinent possible, pour des raisons de performances. Pour le premier point, l'unité d'émission détermine quelles instructions sont candidates pour l'émission. Les ''instructions candidates'' sont celles dont tous les opérandes sont prêts. Le processeur contient un circuit qui détecte les instructions candidates : la '''logique d’éveil''' (''wake-up logic''). Une fois que la logique d'éveil a fait son travail, une instruction est choisie pour s’exécuter en fonction de la disponibilité des unités de calcul adéquates. Ce rôle est dévolu à un circuit qu'on appelle la '''logique de sélection''', ou ''select logic''. [[File:Fonctionnement complet de la logique d’émission.jpg|centre|vignette|upright=1.5|Fonctionnement complet de la logique d’émission.]] La logique de sélection doit gérer le fait que les unités de calcul du processeur ne sont pas toutes identiques. Déjà, un processeur a généralement des unités séparées pour les instructions entières et flottantes, des unités spécialisées dans les accès mémoire, parfois des unités spécialisées pour les branchements. Une instruction doit être attribuée à la bonne unité de calcul, on ne doit pas envoyer une instruction entière dans une unité de calcul flottante. De plus, parmi les unités de calcul entières, toutes ne sont pas identiques. Par exemple, il est fréquent d'avoir plusieurs unités de calcul spécialisées dans les opérations simples (additions, soustractions, opérations logiques) avec une unité pour les multiplications/divisions séparées, parfois une unité spécialisée pour les décalages/rotations, etc. Là encore, allouer la bonne instruction à la bonne ALU est complexe. Plus les unités de calcul sont hétérogènes, plus la logique de sélection est compliquée. Les logiques d'éveil comme de sélection sont assez complexes. Comme on le verra plus bas, la logique de sélection la plus simple, qui gère une seule unité de calcul, est basée sur un encodeur à priorité couplé à d'autres circuits. Et pour gérer plusieurs ALUs, il faut mettre des encodeurs en cascade. Le résultat est que même en prenant une logique de sélection simple, elle sera assez lente et gourmande en circuits. Aussi, la logique de sélection met souvent un cycle d'horloge entier pour faire son travail, elle a son propre étage de pipeline attribué. La logique d'éveil est dans le même cas, ce qui fait qu'émettre une micro-opération demande deux cycles d'horloge. Le défaut est que cela rajoute des cycles d'horloges entre la fenêtre d'instruction et l'ALU, ce qui complique la gestion du pipeline. Ces cycles de retard sont à prendre en compte au moment d'émettre les instructions, les ''scheduler'' doit en tenir compte pour des performances optimales. Sans tenir compte de ces cycles de retard, les instructions arrivent en retard de quelques cycles à l'ALU, cycles de retard durant lesquels l'ALU n'a pas fait de calcul et a été sous-utilisée, sans compter que le système de contournement n'est pas utilisé au mieux. Et le problème est encore plus important sur les processeur avec des stations de réservation, qui utilisent la "lecture après émission" : cela rajoute un cycle d'horloge en plus, un temps de retard en plus. ===La logique d'éveil : l'émission anticipée=== La logique d'éveil doit tenir compte du fait qu'il y a plusieurs étages entre l'émission et l'exécution sur une unité de calcul. Par exemple, un processeur a souvent entre un et à cinq étages entre la file d'attente et les unités de calcul. Il faut lire les registres, gérer le contournement, et cela peut prendre quelques cycles d'horloge. Sur le Pentium 4, on trouve 6 étages entre la fenêtre d’instruction et l'entrée de l'ALU. Si les micro-opérations sont émises quand les opérandes sont disponibles, il y aura un délai de quelques cycles avant qu'elles atteignent l'ALU. Alors qu'idéalement, on souhaiterait que la micro-opération atteigne l'ALU dès que ses opérandes sont disponibles, pour profiter des techniques de contournement. Pour cela, la logique d'éveil émet les instructions quelques cycles en avance pour qu'elles arrivent au bon moment. Il s'agit d'une technique d''''émission anticipée''', dont nous avions parlé dans le chapitre sur le contournement. : Il faut noter que le problème se pose plus avec des fenêtres d'instruction qu'avec des stations de réservation. Les premières ont un étage en plus entre émission et ALU, vu qu'il faut lire des registres après l'émission. L'émission anticipée demande d'émettre un signal d'éveil en avance de quelques cycles, pile au bon moment. Par exemples, si on a deux étages entre l'ALU et l'unité d'émission, le signal de réveil sera généré deux cycles avant que le résultat soit effectivement calculé. L'implémentation varie, mais deux solutions sont possibles. La première est de générer le signal d'éveil dans l'ALU, ce qui n'a de sens que pour les opérations comme les multiplications ou les divisions, qui prennent plusieurs cycles. Une autre technique génère le signal de réveil dans une structure centralisée, spécialisée dans la génération des signaux d'éveil. L'unité de composée d'un registre à décalage par registre. Imaginons qu'une instruction est émise, que cette instruction mette N cycles à s'exécuter, et qu'elle écrive dans un registre de destination. L'unité sélectionne alors le registre à décalage associé au registre de destination, et met le bit numéro N à 1. Le registre décalé d'un cran à chaque cycle. Quand le bit sortant est un 1, alors le signal de validité pour l'opérande est généré. L'émission anticipée marche bien si l'instruction a une durée fixe, connue à l'avance. Et autant c'est le cas pour les instructions arithmétiques et logiques, autant ce n'est pas le cas pour les accès mémoire. Les accès mémoire ont une latence variable : quelques cycles pour un succès de cache, plusieurs dizaines de cycles pour un défaut de cache L1, pas loin de la centaine pour un défaut de cache L2, etc. Et cela pose des problèmes pour l'émission anticipée. L'émission en avance pour les accès mémoire est purement spéculative : le processeur émet des instructions en supposant que la lecture entrainera un succès de cache, quitte à annuler l'instruction en cas de défaut de cache. Mais faire ainsi demande non seulement d'annuler les instructions émises en avance, mais aussi de ne pas retirer les instructions émises en avance de la fenêtre d'instruction. Elles sont émises, mais une copie de sauvegarde est conservée dans la fenêtre d'instruction. Si le processeur détecte un défaut de cache, il peut alors ré-exécuter l'instruction. S'il détecte un succès de cache, les instructions lecture-dépendante sont retirées de la fenêtre d'instruction, la copie de sauvegarde est devenue inutile et est donc jetée. ===La logique de sélection : âge ou position ?=== La logique de sélection est primordiale pour de bonnes performances. Il existe deux méthodes principales pour sélectionner l'instruction à exécuter. La première est la plus simple : elle se base sur lé numéro de l'entrée. En effet, une fenêtre d'instruction est avant tout une sorte de mémoire, un mix entre mémoire associative, mémoire RAM, et FIFO. Et chaque entrée a un numéro, une adresse mémoire. Nous parlerons de numéro dans ce qui suit, car ce sera plus simple, le terme d'adresse mémoire étant peut-être un peu exagéré dans le contexte des fenêtres d'instruction. Toujours est-il que la fenêtre d'instruction est adressable dans le sens où on peut lui envoyer le numéro de l'entrée voulue, et la fenêtre d’instruction renvoie le contenu de l'entrée sur son port de lecture. Et c'est ce que fait la logique de sélection : elle génère le numéro de l'entrée à lire. Le numéro est alors envoyé sur l'entrée d'adresse de la fenêtre d’instruction, et elle fournit la micro-opération associée sur son port de lecture, son '''port d'émission'''. La première méthode de sélection, donc. Elle est basée sur sur le numéro de l'entrée. Si plusieurs entrées sont éveillées, la logique de sélection prend celle avec le plus petit numéro. Elle porte le nom de '''sélection par position''', sous-entendu position dans la fenêtre d'instruction. Vous l'avez peut-être deviné, mais la logique de sélection est alors un encodeur à priorité. Le circuit de sélection ne se résume donc pas seulement à un encodeur à priorité, mais c'est le circuit central. L'avantage d'une telle méthode de sélection est qu'elle est simple à implémenter : un encodeur à priorité est un circuit connu, facile à implémenter. Mais on remarque un défaut : un encodeur est un circuit assez rapide, mais qui utilise beaucoup de transistors, beaucoup de portes logiques, surtout si on veut qu'il soit rapide. Ce qui explique que la logique de sélection ait son propre étage de pipeline rien que pour elle. La seconde méthode s'appelle la '''sélection par âge''', au nom assez transparent. L'idée est de privilégier l'émission de l'instruction la plus ancienne. Elle demande que la fenêtre d'instruction trie les micro-opérations par ordre d'insertion dans la fenêtre d'instruction, ce qui en fait une pseudo-FIFO. Le tri est partiel, car les instructions peuvent sortir de la fenêtre d’instruction à tout moment. Compacter la fenêtre d'instruction, à savoir regrouper toutes les entrées valides est une idée, mais elle est compliquée à implémenter. Aussi, elles préfèrent encoder des informations sur l'ordre d'émission dans chaque entrée. L'encodeur à priorité doit alors travailler non pas sur des nombres entiers liés à l'ordre d'insertion dans la pseudo-FIFO. Elle est encore plus gourmande en circuits que la méthode précédente. Les processeurs haute performance utilisent souvent des méthodes hybrides. Par exemple, les processeurs AMD de microarchitecture Bulldozer utilisaient une méthode intermédiaire. Ils utilisaient une fenêtre d'instruction couplée à un encodeur à priorité pour la sélection par position, mais complémentaient le tout avec une unité qui mémorisait l'instruction la plus ancienne dans la fenêtre d’instruction. Le mécanisme de sélection par âge était utilisé en priorité. Mais si l'instruction la plus ancienne n'était pas prête, le processeur basculait sur le mécanisme de sélection par position. ===La compaction des fenêtres d'instruction=== À chaque cycle, les instructions décodées sont ajoutées dans la fenêtre d'instruction, dans des entrées vides. Vu que les instructions quittent celle-ci dans le désordre, ces vides sont dispersés dans la fenêtre d'instruction, ce qui pose problème pour déterminer où placer les nouvelles instructions. La solution la plus triviale consiste à conserver une liste des vides, mise à jour à chaque insertion ou émission d'instruction. Une autre solution consiste à éliminer les vides en compactant la fenêtre d'instruction à chaque cycle d'horloge. Des circuits se chargent de détecter les vides et de regrouper les instructions en un unique bloc. Il faut signaler que certaines processeurs arrivent à se passer de cette étape de compactage, mais au prix de fenêtres d'instruction nettement plus complexes. Autre problème : quand il faut choisir quelle instruction émettre, il y a toujours plusieurs candidats. Si on choisit mal, des instructions restent en attente trop longtemps parce que d'autres instructions plus jeunes leur passent devant. Pour éviter cela, les instructions les plus vielles, les plus anciennes, sont prioritaires. Pour cela, on peut utiliser une FIFO un peu spéciale pour la fenêtre d'instruction. Si les ajouts d'instruction se font dans l'ordre, les instructions ne quittent pas forcément la fenêtre d'instruction dans l'ordre imposé par une FIFO : les instructions restent triées dans leur ordre d'ajout, même s'il y a des vides entre elles. Dans ces condition, il est préférable que le compactage conserve l'ordre FIFO des instructions. Dans ces conditions, l'instruction la plus ancienne est celle qui est située à l'adresse la plus faible : le circuit de sélection peut donc être fabriqué avec des encodeurs, et est relativement simple. ==Les fenêtres d'instruction basées sur une matrice de dépendances== L'implémentation la plus simple étend le fonctionnement d'un pipeline dynamique usuel. Rappelez-vous le chapitre sur les pipeline dynamiques. Nous avions vu que de tels pipelines émettaient une instruction par cycle, quitte à émettre des bulles de pipeline en cas de dépendance bloquante. Et il est possible d'améliorer leur unité d'émission pour qu'elle soit compatible avec l'exécution dans le désordre. ===Rappels sur le registre de réservation/disponibilité=== L'émission d'une instruction est gouvernée par un ''registre de réservation'' qui indique quels registres sont réservés par une instruction, et ceux qui sont libres. Un registre réservé est un registre qui sera écrit par une instruction en cours d'exécution, mais qui n'a pas encore écrit son résultat. Les instructions candidates doivent avoir leurs opérandes dans des registres libres. Sinon, c'est signe que leurs opérandes sont réservées en écriture, donc pas encore écrites, donc pas disponibles. Si une instruction candidate veut lire ce registre, c'est signe qu'il y a une dépendance RAW : elle veut lire un registre réservé, qui est destiné à être écrit par une instruction en vol. Si elle veut écrire, c'est signe qu'elle veut écrire dans un registre où une autre instruction veut écrire : c'est une dépendance WAW. Dans les deux cas, l'instruction n'est pas émise. Le registre de réservation encode les registres réservés comme suit : chaque bit est associé à un registre. Le bit numéro 0 est associé au registre numéro 0, le bit numéro 1 au registre numéro 1, etc. Là, En clair, les numéros de registres réservés sont encodés en représentation non pas binaire, mais en représentation ''one-hot'' (vue au premier chapitre). {|class="wikitable" |+ Registre de réservation |- ! Registre 7 !! Registre 6 !! Registre 5 !! Registre 4 !! Registre 3 !! Registre 2 !! Registre 1 !! Registre 0 |- | 0 || 0 || 1 || 0 || 0 || 1 || 0 || 0 |} Avant d'émettre une instruction, l'unité d'émission extrait les registres opérande/destination et les convertis dans la même représentation que le registre de réservation, à savoir en représentation ''one-hot''. Le circuit de traduction binaire vers ''one-hot'' est, pour rappel, un simple décodeur. Puis, on fait un OU logique entre les sorties des décodeurs. Le résultat est un masque qui indique quels registres sont lus par l'instruction, encodé en représentation ''one-hot''. Appelons-le le '''masque d'opérandes'''. Le masque est alors comparé au registre de réservation pour vérifier si l'instruction peut être émise. [[File:Unité d'émission simple, dans l'ordre.png|centre|vignette|upright=2|Unité d'émission simple, dans l'ordre]] Si l'émission est autorisée, le registres de réservation est là aussi mis à jour. Le registre de réservation est aussi mis à jour dès qu'une instruction enregistre son résultat dans les registres, ou alors dès qu'il est disponible pour le contournement. Le bit associé au registre repasse alors à 0 (ou à 1). Sans contournement, la mise à jour se fait alors à la toute fin de l'instruction, quand elle se termine, lors de la dernière étape d'enregistrement, à la fin de son pipeline. Avec, elle se fait quand l'instruction quitte l'unité de calcul. ===L'extension à l'exécution dans le désordre : l'éveil par matrice de bits=== La différence entre un pipeline dynamique et l'exécution dans le désordre est que l'on passe d'une instruction à émettre à plusieurs. Plusieurs instructions sont mises en attente dans une fenêtre d’instruction, et y attendent leur tour. L'idée est alors d'envoyer le registre de disponibilité à toutes les entrées, à toutes les instructions en attente. Ainsi, on sait quelles sont les instructions qui peuvent s'exécuter et celles qui ne le peuvent pas. L'implémentation est assez simple, elle ressemble beaucoup à l'implémentation d'un pipeline dynamique simple, si ce n'est que des circuits sont dupliqués. L'implémentation utilise des fenêtres d'instruction légèrement différentes de celles introduites plus haut. Elles n'utilisent notamment pas de bits de disponibilité, mais autre chose. Lorsqu'une instruction est ajoutée à la fenêtre d'instruction, le masque de disponibilité des opérandes est stocké dans la fenêtre d'instruction. A chaque cycle, le registre de disponibilité est envoyée à toutes les entrées, et est comparé avec tous les masques de disponibilité des opérandes. Si une comparaison renvoie un 1, alors l'instruction de l'entrée est une instruction candidate à l'émission. [[File:Unité d'émission dans le désordre basée sur un registre de disponibilité.png|centre|vignette|upright=2.5|Unité d'émission dans le désordre basée sur un registre de disponibilité]] L'ensemble est implémenté avec l'aide d'une '''matrice de bits''', où chaque ligne correspond à une entrée et chaque colonne à un registre. À chaque croisement entre une ligne et une colonne, on trouve un bit. Si le bit de la ligne n et de la colonne m est à 1, cela veut dire : l'instruction dans l'entrée n a besoin de lire le registre m. S’il est à 0, alors cela veut dire que l'instruction stockée dans la ligne n n'a pas besoin de la donnée dans le registre m. [[File:Planificateur à matrice de bits.jpg|centre|vignette|upright=2|Planificateur à matrice de bits.]] Lorsqu'une instruction réserve une entrée, elle initialise la ligne en fonction des registres qu'elle souhaite lire. Pour vérifier si une instruction a ses opérandes prêts, le processeur compare le registre de disponibilité à la ligne associée à l'instruction/entrée. A chaque intersection ligne-colonne, se trouve un comparateur de 1 bit, qui détecte si le registre est demandé et disponible. Les résultats de cette porte sont ensuite envoyés à une porte ET, qui fait le gros du travail. [[File:Logique de détection de la disponibilité d'une instruction.jpg|centre|vignette|upright=2|Logique de détection de la disponibilité d'une instruction.]] ==Les fenêtres d'instruction basées sur une mémoire associative== Les processeurs modernes utilisent une mémoire associative pour la fenêtre d'instruction. Les mémoires associatives ont été abordées il y a quelques chapitres, mais faisons quelques rappels. Les mémoires associatives servent à accélérer la recherche de données dans un ensemble. Or, une fenêtre d'instruction vérifie régulièrement si chaque entrée est prête. Il s'agit d'un processus de recherche d'une instruction qui respecte une condition bien précise dans la mémoire, ce qui fait que les mémoires associatives sont donc tout indiquées. Comme vous le savez, les signaux de commande d'une instruction sont propagés avec celle-ci dans le pipeline, le nom du registre de destination ne faisant pas exception. Le nom de registre est envoyé à la fenêtre d'instruction lors de l'écriture du résultat dans les registres. S'il y a correspondance, l'opérande est disponible et son bit de disponibilité est mis à 1. On peut adapter cette méthode pour tenir compte du contournement assez simplement. [[File:Détection des dépendances par propagation du registre de destination.png|centre|vignette|upright=2|Détection des dépendances par propagation du registre de destination.]] En conséquence, le circuit de détection des dépendances est constitué d'un grand nombre de comparateurs : un par champ « nom de registre » dans chaque entrée. La logique d'éveil/''wake up'' regroupe tous les comparateurs, la logique de sélection est un circuit situé en-dehors de la mémoire associative. Les entrées sont dans la mémoire associative elle-même. [[File:Gestion des bits de validité.png|centre|vignette|upright=2|Gestion des bits de validité.]] L'implémentation la plus simple est celle du schéma précédent, où on utilise une mémoire associative unique. Une version plus élaborée sépare la fenêtre d'instruction en deux parties : une mémoire qui mémorise les registres des opérandes, une autre mémoire pour le reste. La mémoire pour les registres opérandes est la mémoire associative proprement dite, c'est elle qui est associées aux comparateurs, à la logique de ''wake-up''/réveil, etc. Par contre, l'autre mémoire est une mémoire RAM simplifiée, qui mémorise les informations qui n'ont pas besoin des comparateurs. L'opcode de l'instruction est là-dedans, par exemple. La fenêtre d'instruction est donc une sorte de mémoire associative améliorée. Il se trouve que c'est aussi le cas du ROB. Et il est possible de fusionner le tampon de ré-ordonnancement avec la fenêtre d'instruction dans une structure unique. La différence avec une fenêtre d’instruction normale est que les entrées sont libérées non pas quand l'instruction est exécutée/émise, mais quand elle termine son exécution et quitte le ROB. La fenêtre d'instruction incorpore des bits dans chaque entrée, pour savoir si la µops associée a été émise et est en cours de traitement dans les ALUs. La méthode a notamment été utilisée sur les processeurs d'architecture K6 d'AMD. Le tout donnait une structure appelée le '''DRIS''' (''deferred scheduling register renaming instruction shelf''). Les processeurs PA 8000 de HP étaient aussi vraisemblabment dans ce cas, aussi. ===Les optimisations de la consommation d'énergie : la désactivation des portions inutilisées=== Le problème avec des fenêtres d'instruction de ce type est leur forte consommation énergétique, ainsi que le grand nombre de portes logiques utilisées, qui deviennent prohibitif pour des fenêtres d'instruction un peu grosses. Pour résoudre ce problème, certains ont optimisé les comparateurs. D'autres ont tenté de profiter du fait que la majorité des bits dans les entrées sont composés de zéros. Bref, les optimisations purement matérielles sont légion. Une première solution est de désactiver les entrées qui sont inutilisées, vides, sans instruction. Pour cela, on fait précéder les comparateurs par un circuit qui les connecte ou déconnecte des lignes de bit. Le circuit est commandé par le bit ''empty'' qui indique si une entrée est vide ou non. L'avantage est que la consommation d'énergie de la fenêtre d'instruction devient alors proportionnelle au nombre d'entrées non-vides, et non au nombre d'entrées total. Du moins, en apparence, les entrées non-utilisées doivent quand même être alimentées pour fonctionner, mais l'activité de comparaison disparait dans les entrées vides. Il est possible d'étendre cette technique aux entrées dont les opérandes sont prêtes. Les gains sont généralement assez bons, avec une réduction de consommation variant entre 30 et 50%, avec une implémentation très simple et très économe en circuits. Une autre solution, assez simple à mettre en place, consiste à désactiver une partie de la fenêtre d'instruction sin elle est inutilisée. Pour cela, il faut segmenter la fenêtre d'instruction avec la technique du ''wire partitionning''. Pour rappel, une fenêtre d'instruction est une mémoire associative. Et comme toute mémoire associative, elle contient des fils, les lignes de bit, qui relient les entrées/sorties à toutes les cellules mémoire. Plus une ligne de bit est longue, plus elle consomme d'énergie et plus le temps de lecture/écriture est long. L'idée est de segmenter les lignes de bits en plaçant des répéteurs qui recopient la tension d'un segment au suivant. Les répéteurs sont des tampons trois-états, ce qui permet de déconnecter les portions inutilisées de la ligne de bit. Ce faisant, la fenêtre d'instruction est découpée en segments, qui peuvent être désactivés si besoin. Si il y a peu d'instructions chargées dans la fenêtre d'instruction, les portions inutilisées sont désactivées. La technique marche d'autan mieux si les instructions sont compactées au début de la fenêtre d'instruction. [[File:Wire partitionning.png|centre|vignette|upright=2|Wire partitionning]] Tout le problème est de savoir quelles portions désactiver. La technique est assez simple si la fenêtre d'instruction est compactée, à savoir si toutes les instructions sont régulièrement regroupées au début de la mémoire CAM. Mais même avec cette optimisation, la décision de désactiver une portion de la fenêtre d'instruction n'est pas à prendre à la légère. Il ne faut pas désactiver une portion contenant des instructions pouvant être émise sous peu. La décision dépend de paramètres variés : proportion d'entrée vides, quantité d'entrées récemment activées/désactivées récemment, présences d'entrées avec un ''match'' d'opérandes récent, etc. Il est important de préciser que les techniques en question fonctionnent aussi sur les autres types de fenêtre d'instruction, qui ne sont pas basées sur des mémoires associatives. Nous allons voir celles-ci dans la suite du chapitre, mais gardez à l'esprit que ces optimisations, à savoir désactiver les entrées vides/prêts et partitionner la fenêtre d'instruction, sont des optimisations générales qui marchent avec presque tout. ===L'ajout d'une FIFO pour les instructions déjà prêtes à l'émission=== D'autres techniques permettent de réduire aussi bien le cout en circuits que la consommation d'énergie de la fenêtre d'instruction. L'idée est d'utiliser une mémoire associative quand elle est réellement nécessaire, mais d'utiliser une fenêtre d'instruction "normale" dès que possible. La méthode la plus simple tient compte du fait que certaines instructions ont déjà toutes leurs opérandes de disponibles à l'émission, mais doivent quand même être mises en attente, parce que l'ALU adéquate est occupée, parce que des dépendances WAW/WAR sont encore là, ou pour tout autre raison. Dans ce cas, elles sont mises en attente non pas dans la fenêtre d'instruction, mais dans une mémoire FIFO toute simple. L'idée est qu'au lieu d'avoir une énorme mémoire associative pour la fenêtre d'instruction, on déplace quelques entrées dans une petite FIFO annexe. Le résultat est un gain en terme d'énergie et de circuits, au prix d'une perte de performance mineure. La perte de performance en question se manifeste si aucune instruction n'a ses opérandes de prêtes à l'émission : le programme n'utilise pas la FIFO et voit alors une fenêtre d'instruction plus petite. Une amélioration de cette technique tient compte du fait que certaines instructions sont dans un cas intermédiaire. Elles ont déjà une opérande de prête lors de l'émission, mais pas l'autre. Le nombre d'opérandes varie suivant l’instruction : certaines n'ont besoin que d'un seul opérande. De plus, il arrive qu'une opération tout juste décodée ait déjà un ou plusieurs de ses opérandes de prêts. Cette constatation permet d'éviter d'utiliser des comparateurs pour les opérandes déjà prêts. Par exemple, on peut parfaitement utiliser trois fenêtres d'instruction : * une pour les instructions dont tous les opérandes sont prêts, mais qui sont quand même mises en attente, sans comparateur ; * une pour les instructions dont un seul opérande manque, qui n'utilise qu'un comparateur par entrée ; * une pour les instructions dont deux opérandes manquent à l'appel, qui utilise deux comparateurs par entrée. C'est beaucoup plus économique que d'utiliser une seule grosse fenêtre d'instruction qui contiendrait autant d'entrées que les trois précédentes réunies, avec deux comparateurs par entrée. Certains sont même allés plus loin, et ont proposé de supprimer la fenêtre d'instruction avec deux opérandes par entrée. Les instructions dont deux opérandes sont inconnus au décodage sont stockées dans la fenêtre d'instruction pour instructions avec un comparateur par entrée. Un circuit de prédiction se charge alors de prédire l'opérande manquant, cette prédiction étant vérifiée plus loin dans le pipeline. Il serait cependant étonnant qu'une telle proposition ait donné lieu à la moindre implémentation réelle. ===Les optimisations de la consommation d'énergie avancées=== D'autres chercheurs ont conservé une fenêtre d'instruction unique, avec autant de comparateurs par entrée qu'il y a d'opérandes possibles par instruction. Simplement, le processus de détection des opérandes prêts est légèrement ralenti : on ne vérifie qu'un opérande par cycle. Pour vérifier les deux opérandes d'une entrée, on doit attendre deux cycles. Enfin, certains chercheurs ont proposé des fenêtres d'instruction segmentées. Les instructions circulent à chaque cycle d'un segment vers le suivant : en conséquence, certains segments conservent les instructions les plus anciennes, un autre les instructions les plus jeunes, etc. Seul le denier segment, celui qui contient les instructions les plus vielles, peut émettre une instruction : la détection des opérandes se fait seulement dans le dernier segment, qui contient les instructions les plus anciennes. On économise ainsi beaucoup de comparateurs. Certains chercheurs ont tenté de pipeliner l'étape de sélection des opérandes, ainsi que l'étage d'arbitrage. Mais en faisant cela, il faut plusieurs cycles pour détecter qu'une instruction a ses opérandes prêts, ce qui pose problème face à de nombreuses dépendances RAW. Pour éviter de trop perdre en performances, certains chercheurs ont décidé d'utiliser des techniques pour prédire quelles seront les instructions dont les opérandes seront bientôt prêts. Si détecter qu'une instruction est prête prend n cycles, le processeur devra tenter de prédire la future disponibilité des opérandes n cycles en avance pour obtenir des performances optimales. ===Remplacer la mémoire associative par une RAM=== Une autre optimisation possible est de remplacer la fenêtre d'instruction par une mémoire RAM, dont chaque mot mémoire correspondrait à une entrée. Une telle optimisation permet en théorie de se passer des comparateurs associés à chaque entrée, mais au prix de l'ajout de circuits annexes potentiellement couteux. La première de ces techniques, la '''recherche directe par étiquette''' (direct tag search) fut créée par Weiss et son collègue Smith. Ils cherchaient à améliorer l'algorithme de Tomasulo, un algorithme qu'on expliquera dans quelques chapitres. Rappelons que chaque instruction produit un résultat, qui devra être rapatrié dans une ou plusieurs entrées de la fenêtre d'instruction. L'optimisation de la recherche directe par étiquette fonctionne dans le cas où le résultat de l'instruction n'est utilisé que par une seule entrée, et pas plusieurs. Le principe est simple : chaque champ « opérande » d'une entrée est adressable via le nom de registre de cette opérande. Pour faire le lien entre entrée et nom de registre, la recherche directe par étiquette ajoute une table de correspondances matérielle, une mémoire RAM qui mémorise les adresses des champs « opérande » des entrées. Les adresses envoyées dans cette mémoire sont les noms de registres des résultats. Lors de l'émission, la table de correspondances est mise à jour. Les numéros des champs « opérande » réservés lors de l'émission sont mémorisés dans les mots mémoire qui correspondent aux deux registres sources. Toutefois, une petite vérification est faite lors de l'émission : si il y a déjà une correspondance dans la table pour un registre source, alors une autre instruction compte lire ce registre. Pour éviter d'écraser les données de l'instruction précédente dans la table de correspondances, l'émission de l'instruction est bloquée. [[File:Recherche directe par étiquette.png|centre|vignette|upright=2|Recherche directe par étiquette.]] ==Les fenêtres d’instruction avec préplanification== Avec la '''préplanification''' (''prescheduling''), la fenêtre d’instruction est composée de mémoires FIFO dans lesquelles les instructions sont triées dans l'ordre d'émission. Il n'y a pas de logique d’émission proprement dite, celle-ci se bornant à vérifier si l'instruction située au début de la FIFO peut s’exécuter. Par contre, le préplanificateur détecte les dépendances et en déduit où insérer les instructions dans le tampon d'émission, à l'endroit le plus adéquat. [[File:Préplanification.jpg|centre|vignette|upright=2|Préplanification.]] ===L'usage de FIFO multiples=== La technique de préplanification la plus simple utilise plusieurs FIFO. Quand une instruction a une dépendance avec une autre instruction, les deux sont placées dans la même FIFO. Pour cela, le préplanificateur détecte les chaines d'instructions dépendantes, et place les instructions dans la FIFO adéquate. A chaque cycle, l'unité d'émission lit une micro-opération dans chaque FIFO et vérifie si elle peut l'émettre. Si la micro-opération n'a pas ses opérandes disponibles, ou qu'une dépendance structurelle survient, alors la FIFO est bloquée. La micro-opération attend que la dépendance soit résolue, bloquant toutes les instructions précédentes. Mais les autres FIFO ne sont pas bloquées, laissant de la marge de manœuvre. [[File:Préplanification par FIFO multiples.png|centre|vignette|upright=1.5|Préplanification par FIFO multiples.]] ===La technique du tampon trié=== La technique du '''tampon trié''' trie les instructions selon le temps d'attente avant leur exécution. Les instructions qui sont censées s’exécuter bientôt sont insérées au tout début de la FIFO, tandis que les instructions qui s’exécuteront dans un long moment sont insérées vers la fin. Là encore, l'unité d'émission lit une micro-opération dans la FIFO, et détermine si elle peut être émise. Si une dépendance survient, l'émission est retardée, et la FIFO est bloquée. [[File:Préplanification par tampon trié.png|centre|vignette|upright=1.5|Préplanification par tampon trié.]] La technique a cependant quelques problèmes assez importants. Le premier problème est que la FIFO est bloquée lorsqu'une micro-opération ne peut être émise. Le second problème est que le temps avant exécution n'est pas toujours connu, notamment pour les instructions d'accès mémoire. Et cela se répercute sur les instructions dépendantes de celles-ci. Pour résoudre ce genre de problèmes, l'usage d'un pipeline à ''replay'' est possible, et est même l'une des meilleures solution possible, malgré ses défauts. L'idée est que les lecture sont pré-planifiées en supposant qu'elles font un succès de cache L1. Si la prédiction est fausse, la lecture est ré-exécutée plusieurs cycles plus tard, en supposant qu'elle fait un succès dans le cache L2, et ainsi de suite. Elle est alors ré-insérée dans la FIFO, elle est pré-planifiée une seconde fois. Il en est de même si une micro-opération ne peut pas être émise : il suffit de la réinsérer dans la FIFO au bon endroit, en attendant que ses dépendances soient résolus. Ainsi, l'instruction fautive ne bloque pas la fenêtre d’instruction, et retente sa chance autant de fois qu'il le faut. [[File:Préplanification par fenêtre d’instruction scorebarodée.png|centre|vignette|upright=1.5|Préplanification par fenêtre d’instruction scorebarodée.]] Une autre solution utilise deux fenêtres d’instruction : une FIFO gérée par la préplanification, et une vraie fenêtre d'instruction pour les instructions dont le temps d'attente ne peut pas être déterminé. Il est possible de mettre cette dernière avant la préplanification, afin de gérer les temps d'attente des instructions d'accès mémoire. Quand le temps d'attente d'une lecture devient connu, ses instructions dépendantes sont gérées avec préplanification. [[File:Préplanification avec fenêtre d’instruction.png|centre|vignette|upright=2.5|Préplanification avec fenêtre d’instruction.]] ===Les fenêtres d'instruction avec allocation temporelle statique=== L''''allocation temporelle statique''' correspond à une technique utilisée sur les processeurs Cuzco de l'entreprise Condor. La technique en question a été présenté en 2025, mais des idées similaires ont été présentées dans la littérature académique. Elle ressemble beaucoup aux techniques de pré-planification, avec cependant quelques différences. L'idée est simple : le processeur dispose de plusieurs fenêtres d'instruction, qui mettent en attente les micro-opérations. Lors de l'étape de renommage de registres, le processeur détermine dans combien de cycles d'horloge la micro-opération sera prête pour exécution. La micro-opération est alors mise en attente durant ce nombre de cycles, dans les fenêtres d'instruction, puis est émise une fois ce nombre de cycles écoulés. Ce faisant, les fenêtres d'instruction n'ont pas besoin de détecter la disponibilité des opérandes à chaque cycle, pour chaque micro-opération en attente. Le ''timing'' de l'émission des micro-opérations est décidé à l'avance. L'implémentation exacte n'est pas connue, mais plusieurs solutions sont imaginables. Par exemple, la fenêtre d'instruction peut simplement être composée de plusieurs mémoires de petite taille, chacune contenant les micro-opérations destinées à être exécutées dans N cycles, N étant différent pour chaque mémoire. Une autre solution, plus réaliste, utilise une fenêtre d'instruction dans laquelle la micro-opération est couplée à des champs pour les opérandes, et un champ compteur. Le champ compteur est initialisé avec le nombre de cycles à attendre, et est décrémenté à chaque cycle d'horloge. Quand il atteint zéro, la micro-opération est émise. Vous remarquerez que la méthode ne marche que si toutes les micro-opérations prennent un nombre fixe de cycles d'horloge. Et autant c'est le cas pour les micro-opérations arithmétiques ou logiques, autant les accès mémoire ne rentrent pas dans ce cadre. En théorie, on ne sait pas combien de temps prendra un accès mémoire. Et cette incertitude se répercute sur les instructions dépendantes d'un accès mémoire. Pour éviter cela, le processeur réutilise un pipeline à ''replay'' tel que vu dans le chapitre précédent. L'unité de renommage de registre suppose que tout accès mémoire fait un succès de cache L1, et décide des ''timings'' d'émission sous cette hypothèse. Si une lecture subit un défaut de cache, elle est ré-exécutée, de même que toutes les instructions dépendantes. Pour cela, le registre de destination de la lecture est marqué comme invalide, grâce à un bit spécifique attaché au registre. Toute instruction qui lit une opérande invalide est elle aussi ré-executée de zéro. Pour simplifier, l'unité d'émission ressemble à une unité d'émission dans l'ordre, avec un registre de disponibilité, qu'on aurait amélioré pour aller au-delà de la simple détection des dépendances d'instruction. Pour déterminer les ''timings'' d'émission, à savoir quand émettre une micro-opération, le processeur utilise une unité d'émission à deux étages. Le premier étage est appelé le ''register scoreboard'', le second étage est appelé la ''Time Ressource Matrix''. Les deux étages communiquent entre eux, comme on va le voir, et leurs noms donnent une idée de ce qu'ils font. Le premier étage gère les dépendances de registres, le second gère les dépendances structurelles. Le premier étage est un registre de disponibilité amélioré, qui gère les dépendances de registre. Cet étage sait quand tel registre sera écrit, et donc que l'opérande écrite dedans sera disponible à partir de tel cycle d'horloge. Il le sait car l'étage suivant l'aura prévenu, mais laissons cela de côté pour le moment. Quand une micro-opération rentre dans cet étage, il vérifie les dépendances avec les registres et les micro-opérations antérieures. Vu qu'il sait quand les registres seront disponibles, il peut déterminer quand l'instruction pourra s'exécuter. Par exemple, si une micro-opération lit les deux registres R7 et R15, qui sont disponibles respectivement dans 5 et 7 cycles, le premier étage sait que la micro-opération devra attendre 7 cycles. Mais tout cela ne suffit pas à déterminer quand émettre une micro-opération. En effet, il fait aussi gérer les dépendances structurelles, ce qui est le boulot du second étage. Le second étage utilise pour cela une ''Time Ressource Matrix'', qui mémorise l'occupation de diverses "ressources", pour les 256 cycles d'horloge à venir. Les ressources en question sont les ports de lecture/écriture du banc de registre, les ALUs utilisées, si la micro-opération utilise l'unité mémoire, etc. Le second étage prend en entrée une micro-opération, détermine quelles "ressources" elle utilise, puis regarde leur disponibilité. Elle détecte alors les dépendances structurelles et détermine alors quand peut s'exécuter la micro-opération. Elle peut retarder l'émission de quelques cycles, si une dépendance structurelle est détectée. Une fois sortie du second étage, on sait quand la micro-opération va être émise, à quel cycle précisément. Et vu que la durée de l'instruction est fixe, on sait quand cette micro-opération va se terminer, quand son résultat sera disponible. Cela permet de mettre à jour la ''Time Ressource Matrix'', pour préciser que le port d'écriture sera occupé à tel moment. De plus, cette information est transmise au premier étage, qui sait alors quand est enregistré le résultat dans le registre de destination. C'est comme cela que le premier étage sait quand un registre est disponible : le second étage le prévient, quand il émet une instruction ! La ''Time Ressource Matrix''mémorise l'occupation des "ressources" pour les 256 cycles d'horloge à venir. Cependant, elle ne vérifie pas les dépendances pour les 256 cycles suivants. Quand elle reçoit une micro-opération, elle teste les dépendances structurelles pour seulement les 8 prochains cycles maximum. Si la micro-opération ne peut pas être émise pendant ces 8 cycles, le pipeline est bloqué, un ''pipeline stall'' est émis. Pour être plus précis, vu que le processeur peut décoder 8 micro-opérations en même temps, cela permet de ne consulter que 64 cycles d'horloge sur les 256. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les premiers processeurs Intel | prevText=Les premiers processeurs Intel | next=Le renommage de registres | nextText=Le renommage de registres }} </noinclude> strjr712gcqkbo40e2jwsfb2u6om273 773605 773604 2026-09-29T19:49:19Z Mewtow 31375 773605 wikitext text/x-wiki Dans les chapitres précédents, nous avons parlé des techniques dites d''''émission dans l'ordre'''. L'idée est d’exécuter une nouvelle micro-opération à chaque cycle, dans des unités de calcul séparées. Les instructions sont émises consécutivement, mais les instructions s’exécutent en parallèle dans des unités de calcul séparées. Par contre, quand l'unité d'émission ne peut pas émettre une instruction, elle bloque tout le pipeline. Les instructions qui suivent sont elles aussi bloquées, elle doivent attendre leur tour, même si elles sont en capacité de s'exécuter. Les techniques d'exécution dans le désordre que nous allons voir dans ce chapitre corrigent ce point précis. Elles sont dites à '''émission dans le désordre'''. Elles se distinguent des précédentes sur un point précis : quand l'unité d'émission bloque l'émission d'une instruction, les instructions suivantes peuvent poursuivre. L'émission des instructions peut donc se faire dans le désordre, dans le sens où une instruction peut être émise alors qu'une instruction précédente ne l'est pas encore. L'avantage de l'émission dans le désordre est qu'une instruction s'exécute dès que ses opérandes sont disponibles. Par disponible, on veut dire présent soit dans le réseau de contournement, soit dans les registres. Le processeur détecte automatiquement quand les opérandes d'une instruction sont sont disponibles, et il l’exécute à ce moment là. Dès qu'une instruction a ses opérandes disponibles, elle est émise et exécutée. C'est là la seule contrainte : les dépendances WAR, WAW et autres sont gérées par un ROB ou toute autre technique d'exception précise, seules les dépendances RAW limitent l'exécution. Mais avant de poursuivre, quelques point niveaux terminologie : * L'émission dans le désordre est un terme parlant et assez précis. Malheureusement, la terminologie la plus utilisée par d''''exécution dans le désordre'''. Et nous utiliserons ce terme dans la suite du cours, histoire de ne pas trop dévier de la nomenclature habituelle. * Nous utiliserons parfois l'abréviation OOO pour parler d'exécution dans le désordre. L'abréviation est celle de ''Out Of Order Excution''. * Nous utiliserons aussi l'abréviation ''µop'' pour parler de micro-opération, ''µops'' au pluriels pour parler de plusieurs micro-opérations, ou des micro-opérations en général. L'exécution dans le désordre ne gére en effet que des µops, elle se situe après l'étape de décodage. Mais avant de poursuivre, précisons une chose importante : l'exécution dans le désordre traite les accès mémoire à part. La majorité des processeurs OOO assez anciens exécutent les accès mémoire dans l'ordre, seules les µops entières/flottantes/branchements sont exécutées dans le désordre. Les processeurs datant d'après les années 2010 sont capable d'exécuter les accès mémoire dans le désordre, mais l'implémentation en question est assez particulière. Un chapitre entier sera dédié à l'exécution dans le désordre des µops mémoire. Nous allons volontairement mettre de côté la gestion des accès mémoire dans ce chapitre. ==Les fenêtres d’instruction : généralités== [[File:File de micro-opération.png|vignette|upright=1|File de micro-opérations]] Pour décrire comment est implémentée l'émission dans le désordre, il faut commencer par parler des processeurs sans. Les processeurs sans exécution dans le désordre ont une unité d'émission qui bloque tout le pipeline dès qu'une µop ne peut pas être émise. Pour limiter l'impact de ce blocage, quelques rares processeurs incorporent une '''file de micro-opération''', une mémoire FIFO qui met en attente les µops. Vu que c'est une mémoire FIFO, les µops sont émises dans l'ordre, à savoir l'ordre d'ajout, dans l'ordre de décodage. Le schéma ci-dessous illustre une telle file d'attente couplée à un ''scoreboard''. Sur le principe, l'exécution dans le désordre améliore la file de µops sur un point : ce n'est plus une mémoire FIFO. Les µops sont insérées dans l'ordre, mais peuvent sortir dans le désordre (être émises dans le désordre). La file de µops devient alors une '''fenêtre d'instruction''', terme traduit directement de l'anglais ''instruction Window''. Terme assez trompeur, car elles mettent en attente des µops, pas des instructions. Elles peuvent émettre des µops dans le désordre, ce qui fait que si une µop bloque le pipeline, les µops suivantes peuvent être émises. Si je commence le paragraphe précédent par "sur le principe", c'est car certaines techniques d'OOO utilisent des files de µops normales. Il est par exemple possible d'utiliser une file de µops avec une fenêtre d'instruction, plusieurs files de µops, plusieurs fenêtres d'instructions avec une file de µops annexe, etc. Dasn les grandes lignes, il existe dans les grandes lignes 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! File de µops améliorée |- ! Une seule "file de µops" | ''Scoreboard'' | Fenêtre d'instruction centralisée |- ! Plusieurs "file de µops" | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | Fenêtre d'instruction décentralisée |} ===La fenêtre d'instruction centralisée=== L'implémentation la plus simple de l'OOO utilise une unique fenêtre d'instruction, appelée une '''fenêtre d'instruction centralisée'''. Les µops décodées sont accumulées dans la fenêtre d'instruction, où elles attendent que leurs opérandes soient disponibles. La fenêtre d'instruction sert donc de file d'attente. Mais elle contient aussi une unité d'émission, qui détecte quelles µops sont prêtes à être émises. L'unité d'émission et la fenêtre d'instruction sont fusionnées ensemble, elles forment un seul circuit. Mais nous allons dire qu'elles sont conceptuellement séparées pour le moment. A chaque cycle, l'unité d'émission consulte la fenêtre d'instruction pour voir quelles µops peuvent s'exécuter, lesquelles ont leur opérandes de disponibles. La fenêtre d'instruction doit spécialement être conçue pour, c'est une sorte de mémoire associative très complexe, comme on le verra dans ce qui suit. [[File:OOO Issue.png|centre|vignette|upright=2.5|Exécution dans le désordre avec une fenêtre d'instruction]] Une fois qu'une µop sort du décodeur d'instructions, elle est ajoutée en parallèle dans la fenêtre d'instruction et le ROB. La raison est que les µops quittent la fenêtre d'instruction dans le désordre, et qu'elles doivent être remises en ordre par la suite. Le ROB s'occupe de cette remise en ordre, mais il a besoin de savoir dans quel ordre les µops sont censées être, et cet ordre est celui du décodage. Aussi, pour remplir le ROB, la seule opportunité est en sortie de l'unité de décodage. Dans le cas où une instruction est décodée en plusieurs micro-opérations, elles sont toutes insérées en même temps dans la fenêtre d'instruction et le ROB, en tenant compte de leur ordre. [[File:Fenêtre d'instruction.png|centre|vignette|upright=2|Fenêtre d'instruction.]] Les micro-opérations mémoire sont à part des autres, pour diverses raisons. Une de ces raisons est que les dépendances de données sont classées en deux types : les dépendances de registre et les dépendances d'adresse. Et les deux sont fondamentalement différentes. Autant on peut détecter les dépendances de registre lors de l'émission, autant c'est plus compliqué avec les dépendances d'adresse. De plus, rappelons que si les lectures peuvent s'exécuter dans le désordre, les écritures doivent s'exécuter dans l'ordre, ou du moins en donner l'illusion. Pour cela, le processeur remet les écritures dans l'ordre avec une sorte de mini-ROB intégré à l'unité mémoire, appelée la file d'écriture. Elle complémente le ROB, qui lui ne gère que les écritures dans les registres, mais les deux collaborent. La file d'écriture envoie une écriture à la mémoire RAM quand le ROB lui dit que c'est bon, les instructions précédentes sont terminées ''dans l'ordre du programme''. Les processeurs modernes ajoutent des techniques d'exécution dans le désordre des accès mémoire, mais nous les verrons dans un chapitre dédié. Elles permettent d'utiliser une fenêtre d'instruction unique, qui mémorise aussi les µops mémoire. Si elles sont mises en place, l'unité mémoire n'a pas besoin de file de µops séparée. L'idée est que les dépendances de registre sont traitées par la fenêtre d'instruction, mais que l'unité mémoire gére les dépendances d'adresse. Les dépendances d'adresse sont gérées par des techniques de ''désambiguation mémoire'', qui auront droit à un chapitre dédié. [[File:Processeur avec exécution dans le désodre des accès mémoire.png|centre|vignette|upright=2|Processeur avec exécution dans le désodre des accès mémoire]] Les processeurs assez anciens n'autorisaient pas d'exécution dans le désordre des accès mémoire. Concrétement, les accs mémoire devaient se faire dans l'ordre, mais les autres µops pouvaient être exécutées dans le désordre. Il s'agit donc d'un ordre entre µops mémoire, pas entre µops mémoire et autres µops. Les µops entières et flottantes pouvaient être exécutées avant une µops mémoire qui est avant elle dans l'ordre du programme, ce n'est pas un problème. Pour garantir l'ordre desd µops mémoire, l'unité mémoire est précédée par une file de micro-opérations séparée, pour forcer l'exécution dans l'ordre des accès mémoire. De plus, les µops mémoire ne peuvent pas utiliser la fenêtre d'instruction. Dit autrement, la fenêtre d'instruction ne mémorise pas de µops mémoire. Après le décodage, les µops sont réparties soit dans la file de µops mémoire, soit dans la fenêtre d'instruction. Le décodeur classe les µops suivant que ce sont des µops mémoire ou non, et les envoient à la bonne destination. Dans ce chapitre, on supposera que c'est cette solution qui est utilisée. [[File:Processeur avec émission dans l'ordre des accès mémoire.png|centre|vignette|upright=2|Processeur avec émission dans l'ordre des accès mémoire]] La solution précédente revient à scinder la fenêtre d'instruction en deux : une file de µops pour les µops mémoire, une fenêtre d'instruction pour les autres µops. Et cette scission peut aller plus loin, à savoir qu'on peut scinder une fenêtre d'instruction encore et encore. Ce qui nous amène à la section suivante. ===Les fenêtres d'instruction décentralisées=== Nous venons de voir qu'il est possible de scinder la fenêtre d'instruction en une fenêtre d'instruction pour les µops mémoire (simplifiée en une file de µops classique), et une autre pour les autres µops. Sachez qu'il est possible d'aller plus loin, par exemple en séparant la fenêtre d'instruction en une fenêtre spécialisée dans les µops flottantes et une autre pour les µops entières. Et ce n'est là qu'un exemple parmi de nombreuses autres possibilités. Pour faire la différence avec une fenêtre d'instruction unique, nous allons parler de fenêtre d'instruction centralisée s'il n'y en a qu'une, de '''fenêtre d'instruction décentralisée''' s'il y en a plusieurs. Il est possible d'associer chaque fenêtre d'instruction à un type précis de µops. Par exemple, avec une fenêtre d'instruction pour les µops de calcul entières, une autre pour les µops flottantes, une autre pour les µops mémoire. Il s'agit d'un choix simple et efficace, mais quelques processeurs font autrement, pour répondre à des contraintes très diverses. [[File:Processeur avec des fenêtres d'instruction décentralisées.png|centre|vignette|upright=2|Processeur avec des fenêtres d'instruction décentralisées]] Reste à scinder la fenêtre d'instruction pour trier les µops suivant leur type. Si le processeur exécute les accès mémoire dans l'ordre, la méthode la plus simple utilise une fenêtre d'instruction pour les opérations flottantes et une autre pour les autres µops (µops entières et parfois mémoire avec). L'avantage est que cela simplifie grandement le processeur. Les flottants sont gérés à part des entiers. Ils ont leurs propres registres, des FPU séparées des ALU entières, bref : la séparation est complète. Utiliser une fenêtre d'instruction séparée va dans ce sens. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Il est possible de faire pareil sur les processeurs avec exécution dans le désordre des accès mémoire. Par exemple : les processeurs Intel de microarchitecture Skylake utilisent une fenêtre d'instruction pour les opérations entières/flottantes, et une fenêtre d'instruction séparée pour les µops mémoire. Un avantage est que les deux fenêtres d'instructions sont plus spécialisées, ce qui entraine des économies de circuit. Les opérations entières/flottantes ont besoin de deux registres pour les opérandes et d'un autre résultat, alors que les µops mémoire n'ont besoin que de deux registres maximum. En utilisant une fenêtre d'instruction unique, chaque entrée doit mémoriser l'opcode et trois registres, dont un est inutilisé pour les µops mémoire et les branchements. En utilisant des fenêtres d’instructions séparées, celle pour les µops entières/flottantes a trois registres par entrée, contre seulement deux registres par entrée pour celle des µops mémoire. Un cas extrême est celui où chaque ALU/FPU a sa propre fenêtre d'instruction. Nous parlerons alors de '''fenêtres d'instruction totalement décentralisées'''. Par exemple, il y a une fenêtre d'instruction pour l'ALU entière, une autre pour le multiplieur entier, une autre pour le ''barrel shifter'', une autre pour l'unité mémoire, une autre pour l'unitéé de branchements, une autre pour l'additionneur flottant, une dernière pour le multiplier flottant, etc. Un exemple historique est celui de la FPU de l'IBM 360 modèle 90. Elle disposait d'un additionneur flottant, d'un multiplieur flottant, et d'une unité mémoire pour les lectures/écritures flottantes. Les trois unités avaient leur propre fenêtre d'instruction. Les processeurs AMD utilisent beaucoup cette technique, contrairement à Intel qui préfère utiliser des fenêtres centralisées sur les anciens processeurs, deux ou trois fenêtres sur les processeurs récents (2020 et plus). Les processeurs AMD utilisaient précisément une fenêtre d'instruction par ALU entière, alors que les FPUs partagent une fenêtre d’instructions flottantes unique. Mais nous verrons cela en détail dans le chapitre sur les processeurs superscalaires x86. Un point important est qu'avec des fenêtres d'instruction décentralisées, l'émission est découpée en deux étages. La première étape envoie une µops vers la fenêtre d'instruction adéquate, la seconde émet la µops depuis la fenêtre d'instruction quand ses opérandes sont prêtes. La première est l'étage de '''''dispatch''''' qui envoie l'instruction dans la fenêtre d’instruction adéquate, selon que c'est une instruction flottante, entière, autre. La seconde est l'étage de '''''scheduling''''', qui gère la disponibilité des opérandes et des unités de calcul. La µop émise est ajoutée au tampon de réordonnancement, s'il existe, lors de l'étape de ''dispatch''. ===L'usage de plusieurs files d'instruction=== Une dernière méthode d'OOO utilise plusieurs files de micro-opération. L'idée est qu'une fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement une file de micro-opération pour les opérations entières, une autre pour les opérations flottantes, une autre pour les accès mémoire. D'autres processeurs utilisent une file pour les accès mémoire et une autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. La présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que la technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si une dépendance bloque une FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans une autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer la disponibilité des registres. Quand un registre est lu ou écrit par une instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. La logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : une pour les instructions d'accès mémoire et une autre pour les autres instructions. Si jamais une instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de la lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'une est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est la file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. ===Avantages et inconvénients de chaque implémentation=== Pour résumer, on a le choix entre une grosse fenêtre d'instruction généraliste et plusieurs fenêtres spécialisées. Le choix entre les deux est un compromis entre économie de circuits et flexibilité. Avec une fenêtre décentralisée, il arrive qu'une fenêtre d'instruction soit remplie, alors que les autres sont sous-utilisées, voire vides. Pour comprendre pourquoi, comparons une fenêtre d'instruction unique, avec une fenêtre décentralisée séparant µops entières et flottantes. La fenêtre centralisée dispose de 64 entrées, la décentralisée a 32 entrées pour chaque fenêtre d'instruction. La fenêtre décentralisée peut mémoriser au maximum 32 µops entières et 32 *ops flottantes. Par contre, la fenêtre centralisée peut mémoriser 64 µops tout court. Si le programme exécuté n'utilise pas de nombres flottants, la différence devient flagrante. La fenêtre décentralisée sera limitée ) 32 µops, alors que la centralisée pourra mémoriser le double. Les performances seront donc meilleurs avec la fenêtre centralisée. Et au-delà de ça, la fenêtre décentralisée de l'exemple est utilisée de manière optimale si la moitié des µops sont des µops entières, et l'autre moitié des µops flottantes. Alors que la fenêtre centralisée se moque de la répartition entre µops entières et flottantes. Une subtilité est que le cout en transistors d'une fenêtre d'instruction n'est pas proportionnel au nombre de µops qu'elle peut mémoriser. Par exemple, si je compare une fenêtre d'instruction de 32 entrées (32 µops max), elle n'utilise pas deux fois plus transistors qu'une fenêtre de 16 entrées. Le cout en circuit n'est pas deux fois plus élevé, mais est approximativement 4 fois plus élevé. Le cout est presque quadratique, à savoir qu'il est proportionnel au carré du nombre d'entrées. Et il en est de même avec la performance, pour des raisons qu'on expliquera plus bas. Les fenêtres décentralisées utilisent plusieurs fenêtres d'instruction de "petite taille", donc plus rapides, économes en circuits et économes en énergie. Le compromis n'est donc pas entre une fenêtre centralisée à 64 entrées versus deux fenêtres de 32 entrées. Le compromis en pratique est entre une fenêtre centralisée de 64 entrées versus 3 fenêtres de 32 entrées. Un exemple pratique est celui de la microarchitecture ''Skylake'' d'Intel. Intel est passé d'une fenêtre centralisée pre-''Skylake'' à deux fenêtres décentralisées sur ''Skylake'',. Le nombre d'entrée était globalement le même entre les deux, même si l'évolution de la finesse de gravure entre les deux biaise un peu les résultats. Un avantage des fenêtres décentralisées est qu'il est possible de démarrer l'exécution de plusieurs µops simultanément : une µops par fenêtre d'instruction. Le fait est que deux fenêtres d'instructions différentes émettent leurs µops sans se synchroniser avec les autres. Deux fenêtres d'instruction peuvent donc émettre chacune une µops, ce qui fait deux µops émises lors du même cycle. Cela permet d'exécuter en même temps deux ou trois instructions 1-cycle, comme des additions, soustractions, décalages, etc. Il devient par exemple possible d'émettre une µop entière en même temps qu'une µop flottante, si les µops entières ont une fenêtre séparée de celle des µops flottantes. Il est maintenant temps de voir en quoi sont faites les fenêtres d’instruction, qu'elles soient centralisées ou décentralisées. Nous allons aussi voir quelle est la logique d'émission associée. ==L'implémentation d'une fenêtre d'instruction : généralités== Une fenêtre d'instruction est une mémoire qui mémorise des micro-opérations. Elle est cependant plus complexe qu'une mémoire RAM ou qu'une FIFO et ressemble un petit peu à une mémoire cache. Elle dispose d'un port d'écriture et d'un port de lecture, au minimum. Le port d'écriture permet à l'unité de décodage d'insérer une micro-opération dedans, d'ajouter la micro-opération qui vient d'être décodée. Si une instruction machine est décodée en plusieurs micro-opération, deux possibilités. La première est de les insérer un par un, ce qui fait qu'on peut se contenter d'un seul port d'écriture. L'autre possibilité est de les ajouter en même temps, ce qui demande plusieurs ports d'écriture. Le port de lecture sert à émettre une instruction. On part du principe que la fenêtre d'instruction ne peut émettre qu'une seule instruction à la fois, car les processeurs que nous avons vu précédemment sont de ce type. Mais nous verrons dans quelques chapitre qu'il existe des processeurs dits superscalaires, qui sont capables d'émettre plusieurs instructions par cycle. Dans ce cas, la fenêtre d'instruction a un seul port de lecture. Un processeur superscalaire, quant à lui, doit avoir un port de lecture par unité de calcul, ce qui fait beaucoup plus. Les fenêtres d'instruction sont composées d''''entrées''', des mots mémoire qui stockent une instruction. Une instruction réserve une entrée après son décodage et la libère dès qu'elle est envoyée aux unités de calcul. Une entrée contient l'opcode (les signaux de commande à envoyer à l'ALU), le registre de destination du résultat, les registres de chaque opérande, et éventuellement des signaux de commande en plus. De plus, chaque opérande est couplée à un bit de disponibilité, qui indique si elle est disponible. Quand un opérande est écrit dans les registres, le bit de présence correspondant est mis à jour. Enfin, chaque entrée possède un bit ''empty'' qui indique si elle est vide, cette information étant utile pour réserver des entrées. [[File:Entrée d'une station de réservation - sans les tags.png|centre|vignette|upright=3|Entrée d'une fenêtre d'instruction]] ===Les stations de réservation=== Les '''stations de réservation''' sont des fenêtres d'instruction particulières, qui sont capables de mémoriser les opérandes des instructions. Les entrées des stations de réservation sont identiques à celle des autres fenêtres d'instruction, si ce n'est que les opérandes de l'instruction sont enregistrées directement dans des champs séparés. Il y a deux champs, un par opérande, pour stocker l'opérande elle-même, lue depuis les registres ou obtenue via le réseau de contournement. Notons que les champs pour les opérandes viennent en plus des champs pour les noms de registres, encore que les deux peuvent être fusionnés si on veut optimiser le tout. [[File:Entrée d'une station de réservation.png|centre|vignette|upright=3|Entrée d'une station de réservation.]] Précisons que la terminologie n'est pas très fiable. Les termes "fenêtre d'instruction" et "station de réservation" ne regroupent pas du tout la même chose d'un papier de recherche à l'autre, d'un bouquin à l'autre, d'un chercheur à l'autre, d'un ingénieur à l'autre, d'un professeur à l'autre. Le terme initial vient pourtant de l'article original sur l'algorithme de Tomasulo, où il désignait une fenêtre d'instruction associée à une unité de calcul précise. Mais le terme a ensuite été réutilisé, ce qui fait que certains processeurs avec plusieurs unités de calcul sont décrit comme ayant une unique station de réservation. En bref : c'est le bazar ! Mais nous en reparlerons dans le chapitre sur le renommage de registres, car c'est la place idéale pour les aborder. Toujours est-il que j'ai fait le choix de confondre les concepts de fenêtre d'instruction et de station de réservation avec les concepts de '''lecture avant émission''' et de '''lecture après émission'''. La différence entre les deux est que les registres sont lus après émission avec une fenêtre d'instruction, avant avec des stations de réservation. Dans le cas "avant émission", les opérandes sont mémorisées dans la station de réservation. Et cette différence a une influence sur le pipeline du processeur, le banc de registres et tout ce qui s'en suit. Un désavantage de la lecture avant émission est qu'il faut stocker les opérandes après lecture, ici dans les stations de réservation. Mais un avantage est que le banc de registre a besoin de moins de ports de lecture, car une bonne partie des opérandes sont fournies par le système de contournement. Nous verrons cela dans le détail dans le chapitre sur les processeurs superscalaires. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Lecture après émission.]] [[File:Read Before Issue.png|centre|vignette|upright=2.5|Lecture avant émission.]] ===La logique d'éveil et de sélection=== Dans le cas qui va suivre, on suppose que le processeur ne peut émettre qu'une instruction à la fois. Chaque cycle, une instruction est sélectionnée et est envoyée dans le chemin de données, soit à une ALU, soit à une unité d'accès mémoire. La sélection d'une instruction est effectuée par l'unité d'émission, qui est aussi appelée le '''''scheduler'''''. Elle gère la disponibilité des opérandes et la disponibilité des unités de calcul adéquate. Le choix de l'instruction émise doit être le plus pertinent possible, pour des raisons de performances. Pour le premier point, l'unité d'émission détermine quelles instructions sont candidates pour l'émission. Les ''instructions candidates'' sont celles dont tous les opérandes sont prêts. Le processeur contient un circuit qui détecte les instructions candidates : la '''logique d’éveil''' (''wake-up logic''). Une fois que la logique d'éveil a fait son travail, une instruction est choisie pour s’exécuter en fonction de la disponibilité des unités de calcul adéquates. Ce rôle est dévolu à un circuit qu'on appelle la '''logique de sélection''', ou ''select logic''. [[File:Fonctionnement complet de la logique d’émission.jpg|centre|vignette|upright=1.5|Fonctionnement complet de la logique d’émission.]] La logique de sélection doit gérer le fait que les unités de calcul du processeur ne sont pas toutes identiques. Déjà, un processeur a généralement des unités séparées pour les instructions entières et flottantes, des unités spécialisées dans les accès mémoire, parfois des unités spécialisées pour les branchements. Une instruction doit être attribuée à la bonne unité de calcul, on ne doit pas envoyer une instruction entière dans une unité de calcul flottante. De plus, parmi les unités de calcul entières, toutes ne sont pas identiques. Par exemple, il est fréquent d'avoir plusieurs unités de calcul spécialisées dans les opérations simples (additions, soustractions, opérations logiques) avec une unité pour les multiplications/divisions séparées, parfois une unité spécialisée pour les décalages/rotations, etc. Là encore, allouer la bonne instruction à la bonne ALU est complexe. Plus les unités de calcul sont hétérogènes, plus la logique de sélection est compliquée. Les logiques d'éveil comme de sélection sont assez complexes. Comme on le verra plus bas, la logique de sélection la plus simple, qui gère une seule unité de calcul, est basée sur un encodeur à priorité couplé à d'autres circuits. Et pour gérer plusieurs ALUs, il faut mettre des encodeurs en cascade. Le résultat est que même en prenant une logique de sélection simple, elle sera assez lente et gourmande en circuits. Aussi, la logique de sélection met souvent un cycle d'horloge entier pour faire son travail, elle a son propre étage de pipeline attribué. La logique d'éveil est dans le même cas, ce qui fait qu'émettre une micro-opération demande deux cycles d'horloge. Le défaut est que cela rajoute des cycles d'horloges entre la fenêtre d'instruction et l'ALU, ce qui complique la gestion du pipeline. Ces cycles de retard sont à prendre en compte au moment d'émettre les instructions, les ''scheduler'' doit en tenir compte pour des performances optimales. Sans tenir compte de ces cycles de retard, les instructions arrivent en retard de quelques cycles à l'ALU, cycles de retard durant lesquels l'ALU n'a pas fait de calcul et a été sous-utilisée, sans compter que le système de contournement n'est pas utilisé au mieux. Et le problème est encore plus important sur les processeur avec des stations de réservation, qui utilisent la "lecture après émission" : cela rajoute un cycle d'horloge en plus, un temps de retard en plus. ===La logique d'éveil : l'émission anticipée=== La logique d'éveil doit tenir compte du fait qu'il y a plusieurs étages entre l'émission et l'exécution sur une unité de calcul. Par exemple, un processeur a souvent entre un et à cinq étages entre la file d'attente et les unités de calcul. Il faut lire les registres, gérer le contournement, et cela peut prendre quelques cycles d'horloge. Sur le Pentium 4, on trouve 6 étages entre la fenêtre d’instruction et l'entrée de l'ALU. Si les micro-opérations sont émises quand les opérandes sont disponibles, il y aura un délai de quelques cycles avant qu'elles atteignent l'ALU. Alors qu'idéalement, on souhaiterait que la micro-opération atteigne l'ALU dès que ses opérandes sont disponibles, pour profiter des techniques de contournement. Pour cela, la logique d'éveil émet les instructions quelques cycles en avance pour qu'elles arrivent au bon moment. Il s'agit d'une technique d''''émission anticipée''', dont nous avions parlé dans le chapitre sur le contournement. : Il faut noter que le problème se pose plus avec des fenêtres d'instruction qu'avec des stations de réservation. Les premières ont un étage en plus entre émission et ALU, vu qu'il faut lire des registres après l'émission. L'émission anticipée demande d'émettre un signal d'éveil en avance de quelques cycles, pile au bon moment. Par exemples, si on a deux étages entre l'ALU et l'unité d'émission, le signal de réveil sera généré deux cycles avant que le résultat soit effectivement calculé. L'implémentation varie, mais deux solutions sont possibles. La première est de générer le signal d'éveil dans l'ALU, ce qui n'a de sens que pour les opérations comme les multiplications ou les divisions, qui prennent plusieurs cycles. Une autre technique génère le signal de réveil dans une structure centralisée, spécialisée dans la génération des signaux d'éveil. L'unité de composée d'un registre à décalage par registre. Imaginons qu'une instruction est émise, que cette instruction mette N cycles à s'exécuter, et qu'elle écrive dans un registre de destination. L'unité sélectionne alors le registre à décalage associé au registre de destination, et met le bit numéro N à 1. Le registre décalé d'un cran à chaque cycle. Quand le bit sortant est un 1, alors le signal de validité pour l'opérande est généré. L'émission anticipée marche bien si l'instruction a une durée fixe, connue à l'avance. Et autant c'est le cas pour les instructions arithmétiques et logiques, autant ce n'est pas le cas pour les accès mémoire. Les accès mémoire ont une latence variable : quelques cycles pour un succès de cache, plusieurs dizaines de cycles pour un défaut de cache L1, pas loin de la centaine pour un défaut de cache L2, etc. Et cela pose des problèmes pour l'émission anticipée. L'émission en avance pour les accès mémoire est purement spéculative : le processeur émet des instructions en supposant que la lecture entrainera un succès de cache, quitte à annuler l'instruction en cas de défaut de cache. Mais faire ainsi demande non seulement d'annuler les instructions émises en avance, mais aussi de ne pas retirer les instructions émises en avance de la fenêtre d'instruction. Elles sont émises, mais une copie de sauvegarde est conservée dans la fenêtre d'instruction. Si le processeur détecte un défaut de cache, il peut alors ré-exécuter l'instruction. S'il détecte un succès de cache, les instructions lecture-dépendante sont retirées de la fenêtre d'instruction, la copie de sauvegarde est devenue inutile et est donc jetée. ===La logique de sélection : âge ou position ?=== La logique de sélection est primordiale pour de bonnes performances. Il existe deux méthodes principales pour sélectionner l'instruction à exécuter. La première est la plus simple : elle se base sur lé numéro de l'entrée. En effet, une fenêtre d'instruction est avant tout une sorte de mémoire, un mix entre mémoire associative, mémoire RAM, et FIFO. Et chaque entrée a un numéro, une adresse mémoire. Nous parlerons de numéro dans ce qui suit, car ce sera plus simple, le terme d'adresse mémoire étant peut-être un peu exagéré dans le contexte des fenêtres d'instruction. Toujours est-il que la fenêtre d'instruction est adressable dans le sens où on peut lui envoyer le numéro de l'entrée voulue, et la fenêtre d’instruction renvoie le contenu de l'entrée sur son port de lecture. Et c'est ce que fait la logique de sélection : elle génère le numéro de l'entrée à lire. Le numéro est alors envoyé sur l'entrée d'adresse de la fenêtre d’instruction, et elle fournit la micro-opération associée sur son port de lecture, son '''port d'émission'''. La première méthode de sélection, donc. Elle est basée sur sur le numéro de l'entrée. Si plusieurs entrées sont éveillées, la logique de sélection prend celle avec le plus petit numéro. Elle porte le nom de '''sélection par position''', sous-entendu position dans la fenêtre d'instruction. Vous l'avez peut-être deviné, mais la logique de sélection est alors un encodeur à priorité. Le circuit de sélection ne se résume donc pas seulement à un encodeur à priorité, mais c'est le circuit central. L'avantage d'une telle méthode de sélection est qu'elle est simple à implémenter : un encodeur à priorité est un circuit connu, facile à implémenter. Mais on remarque un défaut : un encodeur est un circuit assez rapide, mais qui utilise beaucoup de transistors, beaucoup de portes logiques, surtout si on veut qu'il soit rapide. Ce qui explique que la logique de sélection ait son propre étage de pipeline rien que pour elle. La seconde méthode s'appelle la '''sélection par âge''', au nom assez transparent. L'idée est de privilégier l'émission de l'instruction la plus ancienne. Elle demande que la fenêtre d'instruction trie les micro-opérations par ordre d'insertion dans la fenêtre d'instruction, ce qui en fait une pseudo-FIFO. Le tri est partiel, car les instructions peuvent sortir de la fenêtre d’instruction à tout moment. Compacter la fenêtre d'instruction, à savoir regrouper toutes les entrées valides est une idée, mais elle est compliquée à implémenter. Aussi, elles préfèrent encoder des informations sur l'ordre d'émission dans chaque entrée. L'encodeur à priorité doit alors travailler non pas sur des nombres entiers liés à l'ordre d'insertion dans la pseudo-FIFO. Elle est encore plus gourmande en circuits que la méthode précédente. Les processeurs haute performance utilisent souvent des méthodes hybrides. Par exemple, les processeurs AMD de microarchitecture Bulldozer utilisaient une méthode intermédiaire. Ils utilisaient une fenêtre d'instruction couplée à un encodeur à priorité pour la sélection par position, mais complémentaient le tout avec une unité qui mémorisait l'instruction la plus ancienne dans la fenêtre d’instruction. Le mécanisme de sélection par âge était utilisé en priorité. Mais si l'instruction la plus ancienne n'était pas prête, le processeur basculait sur le mécanisme de sélection par position. ===La compaction des fenêtres d'instruction=== À chaque cycle, les instructions décodées sont ajoutées dans la fenêtre d'instruction, dans des entrées vides. Vu que les instructions quittent celle-ci dans le désordre, ces vides sont dispersés dans la fenêtre d'instruction, ce qui pose problème pour déterminer où placer les nouvelles instructions. La solution la plus triviale consiste à conserver une liste des vides, mise à jour à chaque insertion ou émission d'instruction. Une autre solution consiste à éliminer les vides en compactant la fenêtre d'instruction à chaque cycle d'horloge. Des circuits se chargent de détecter les vides et de regrouper les instructions en un unique bloc. Il faut signaler que certaines processeurs arrivent à se passer de cette étape de compactage, mais au prix de fenêtres d'instruction nettement plus complexes. Autre problème : quand il faut choisir quelle instruction émettre, il y a toujours plusieurs candidats. Si on choisit mal, des instructions restent en attente trop longtemps parce que d'autres instructions plus jeunes leur passent devant. Pour éviter cela, les instructions les plus vielles, les plus anciennes, sont prioritaires. Pour cela, on peut utiliser une FIFO un peu spéciale pour la fenêtre d'instruction. Si les ajouts d'instruction se font dans l'ordre, les instructions ne quittent pas forcément la fenêtre d'instruction dans l'ordre imposé par une FIFO : les instructions restent triées dans leur ordre d'ajout, même s'il y a des vides entre elles. Dans ces condition, il est préférable que le compactage conserve l'ordre FIFO des instructions. Dans ces conditions, l'instruction la plus ancienne est celle qui est située à l'adresse la plus faible : le circuit de sélection peut donc être fabriqué avec des encodeurs, et est relativement simple. ==Les fenêtres d'instruction basées sur une matrice de dépendances== L'implémentation la plus simple étend le fonctionnement d'un pipeline dynamique usuel. Rappelez-vous le chapitre sur les pipeline dynamiques. Nous avions vu que de tels pipelines émettaient une instruction par cycle, quitte à émettre des bulles de pipeline en cas de dépendance bloquante. Et il est possible d'améliorer leur unité d'émission pour qu'elle soit compatible avec l'exécution dans le désordre. ===Rappels sur le registre de réservation/disponibilité=== L'émission d'une instruction est gouvernée par un ''registre de réservation'' qui indique quels registres sont réservés par une instruction, et ceux qui sont libres. Un registre réservé est un registre qui sera écrit par une instruction en cours d'exécution, mais qui n'a pas encore écrit son résultat. Les instructions candidates doivent avoir leurs opérandes dans des registres libres. Sinon, c'est signe que leurs opérandes sont réservées en écriture, donc pas encore écrites, donc pas disponibles. Si une instruction candidate veut lire ce registre, c'est signe qu'il y a une dépendance RAW : elle veut lire un registre réservé, qui est destiné à être écrit par une instruction en vol. Si elle veut écrire, c'est signe qu'elle veut écrire dans un registre où une autre instruction veut écrire : c'est une dépendance WAW. Dans les deux cas, l'instruction n'est pas émise. Le registre de réservation encode les registres réservés comme suit : chaque bit est associé à un registre. Le bit numéro 0 est associé au registre numéro 0, le bit numéro 1 au registre numéro 1, etc. Là, En clair, les numéros de registres réservés sont encodés en représentation non pas binaire, mais en représentation ''one-hot'' (vue au premier chapitre). {|class="wikitable" |+ Registre de réservation |- ! Registre 7 !! Registre 6 !! Registre 5 !! Registre 4 !! Registre 3 !! Registre 2 !! Registre 1 !! Registre 0 |- | 0 || 0 || 1 || 0 || 0 || 1 || 0 || 0 |} Avant d'émettre une instruction, l'unité d'émission extrait les registres opérande/destination et les convertis dans la même représentation que le registre de réservation, à savoir en représentation ''one-hot''. Le circuit de traduction binaire vers ''one-hot'' est, pour rappel, un simple décodeur. Puis, on fait un OU logique entre les sorties des décodeurs. Le résultat est un masque qui indique quels registres sont lus par l'instruction, encodé en représentation ''one-hot''. Appelons-le le '''masque d'opérandes'''. Le masque est alors comparé au registre de réservation pour vérifier si l'instruction peut être émise. [[File:Unité d'émission simple, dans l'ordre.png|centre|vignette|upright=2|Unité d'émission simple, dans l'ordre]] Si l'émission est autorisée, le registres de réservation est là aussi mis à jour. Le registre de réservation est aussi mis à jour dès qu'une instruction enregistre son résultat dans les registres, ou alors dès qu'il est disponible pour le contournement. Le bit associé au registre repasse alors à 0 (ou à 1). Sans contournement, la mise à jour se fait alors à la toute fin de l'instruction, quand elle se termine, lors de la dernière étape d'enregistrement, à la fin de son pipeline. Avec, elle se fait quand l'instruction quitte l'unité de calcul. ===L'extension à l'exécution dans le désordre : l'éveil par matrice de bits=== La différence entre un pipeline dynamique et l'exécution dans le désordre est que l'on passe d'une instruction à émettre à plusieurs. Plusieurs instructions sont mises en attente dans une fenêtre d’instruction, et y attendent leur tour. L'idée est alors d'envoyer le registre de disponibilité à toutes les entrées, à toutes les instructions en attente. Ainsi, on sait quelles sont les instructions qui peuvent s'exécuter et celles qui ne le peuvent pas. L'implémentation est assez simple, elle ressemble beaucoup à l'implémentation d'un pipeline dynamique simple, si ce n'est que des circuits sont dupliqués. L'implémentation utilise des fenêtres d'instruction légèrement différentes de celles introduites plus haut. Elles n'utilisent notamment pas de bits de disponibilité, mais autre chose. Lorsqu'une instruction est ajoutée à la fenêtre d'instruction, le masque de disponibilité des opérandes est stocké dans la fenêtre d'instruction. A chaque cycle, le registre de disponibilité est envoyée à toutes les entrées, et est comparé avec tous les masques de disponibilité des opérandes. Si une comparaison renvoie un 1, alors l'instruction de l'entrée est une instruction candidate à l'émission. [[File:Unité d'émission dans le désordre basée sur un registre de disponibilité.png|centre|vignette|upright=2.5|Unité d'émission dans le désordre basée sur un registre de disponibilité]] L'ensemble est implémenté avec l'aide d'une '''matrice de bits''', où chaque ligne correspond à une entrée et chaque colonne à un registre. À chaque croisement entre une ligne et une colonne, on trouve un bit. Si le bit de la ligne n et de la colonne m est à 1, cela veut dire : l'instruction dans l'entrée n a besoin de lire le registre m. S’il est à 0, alors cela veut dire que l'instruction stockée dans la ligne n n'a pas besoin de la donnée dans le registre m. [[File:Planificateur à matrice de bits.jpg|centre|vignette|upright=2|Planificateur à matrice de bits.]] Lorsqu'une instruction réserve une entrée, elle initialise la ligne en fonction des registres qu'elle souhaite lire. Pour vérifier si une instruction a ses opérandes prêts, le processeur compare le registre de disponibilité à la ligne associée à l'instruction/entrée. A chaque intersection ligne-colonne, se trouve un comparateur de 1 bit, qui détecte si le registre est demandé et disponible. Les résultats de cette porte sont ensuite envoyés à une porte ET, qui fait le gros du travail. [[File:Logique de détection de la disponibilité d'une instruction.jpg|centre|vignette|upright=2|Logique de détection de la disponibilité d'une instruction.]] ==Les fenêtres d'instruction basées sur une mémoire associative== Les processeurs modernes utilisent une mémoire associative pour la fenêtre d'instruction. Les mémoires associatives ont été abordées il y a quelques chapitres, mais faisons quelques rappels. Les mémoires associatives servent à accélérer la recherche de données dans un ensemble. Or, une fenêtre d'instruction vérifie régulièrement si chaque entrée est prête. Il s'agit d'un processus de recherche d'une instruction qui respecte une condition bien précise dans la mémoire, ce qui fait que les mémoires associatives sont donc tout indiquées. Comme vous le savez, les signaux de commande d'une instruction sont propagés avec celle-ci dans le pipeline, le nom du registre de destination ne faisant pas exception. Le nom de registre est envoyé à la fenêtre d'instruction lors de l'écriture du résultat dans les registres. S'il y a correspondance, l'opérande est disponible et son bit de disponibilité est mis à 1. On peut adapter cette méthode pour tenir compte du contournement assez simplement. [[File:Détection des dépendances par propagation du registre de destination.png|centre|vignette|upright=2|Détection des dépendances par propagation du registre de destination.]] En conséquence, le circuit de détection des dépendances est constitué d'un grand nombre de comparateurs : un par champ « nom de registre » dans chaque entrée. La logique d'éveil/''wake up'' regroupe tous les comparateurs, la logique de sélection est un circuit situé en-dehors de la mémoire associative. Les entrées sont dans la mémoire associative elle-même. [[File:Gestion des bits de validité.png|centre|vignette|upright=2|Gestion des bits de validité.]] L'implémentation la plus simple est celle du schéma précédent, où on utilise une mémoire associative unique. Une version plus élaborée sépare la fenêtre d'instruction en deux parties : une mémoire qui mémorise les registres des opérandes, une autre mémoire pour le reste. La mémoire pour les registres opérandes est la mémoire associative proprement dite, c'est elle qui est associées aux comparateurs, à la logique de ''wake-up''/réveil, etc. Par contre, l'autre mémoire est une mémoire RAM simplifiée, qui mémorise les informations qui n'ont pas besoin des comparateurs. L'opcode de l'instruction est là-dedans, par exemple. La fenêtre d'instruction est donc une sorte de mémoire associative améliorée. Il se trouve que c'est aussi le cas du ROB. Et il est possible de fusionner le tampon de ré-ordonnancement avec la fenêtre d'instruction dans une structure unique. La différence avec une fenêtre d’instruction normale est que les entrées sont libérées non pas quand l'instruction est exécutée/émise, mais quand elle termine son exécution et quitte le ROB. La fenêtre d'instruction incorpore des bits dans chaque entrée, pour savoir si la µops associée a été émise et est en cours de traitement dans les ALUs. La méthode a notamment été utilisée sur les processeurs d'architecture K6 d'AMD. Le tout donnait une structure appelée le '''DRIS''' (''deferred scheduling register renaming instruction shelf''). Les processeurs PA 8000 de HP étaient aussi vraisemblabment dans ce cas, aussi. ===Les optimisations de la consommation d'énergie : la désactivation des portions inutilisées=== Le problème avec des fenêtres d'instruction de ce type est leur forte consommation énergétique, ainsi que le grand nombre de portes logiques utilisées, qui deviennent prohibitif pour des fenêtres d'instruction un peu grosses. Pour résoudre ce problème, certains ont optimisé les comparateurs. D'autres ont tenté de profiter du fait que la majorité des bits dans les entrées sont composés de zéros. Bref, les optimisations purement matérielles sont légion. Une première solution est de désactiver les entrées qui sont inutilisées, vides, sans instruction. Pour cela, on fait précéder les comparateurs par un circuit qui les connecte ou déconnecte des lignes de bit. Le circuit est commandé par le bit ''empty'' qui indique si une entrée est vide ou non. L'avantage est que la consommation d'énergie de la fenêtre d'instruction devient alors proportionnelle au nombre d'entrées non-vides, et non au nombre d'entrées total. Du moins, en apparence, les entrées non-utilisées doivent quand même être alimentées pour fonctionner, mais l'activité de comparaison disparait dans les entrées vides. Il est possible d'étendre cette technique aux entrées dont les opérandes sont prêtes. Les gains sont généralement assez bons, avec une réduction de consommation variant entre 30 et 50%, avec une implémentation très simple et très économe en circuits. Une autre solution, assez simple à mettre en place, consiste à désactiver une partie de la fenêtre d'instruction sin elle est inutilisée. Pour cela, il faut segmenter la fenêtre d'instruction avec la technique du ''wire partitionning''. Pour rappel, une fenêtre d'instruction est une mémoire associative. Et comme toute mémoire associative, elle contient des fils, les lignes de bit, qui relient les entrées/sorties à toutes les cellules mémoire. Plus une ligne de bit est longue, plus elle consomme d'énergie et plus le temps de lecture/écriture est long. L'idée est de segmenter les lignes de bits en plaçant des répéteurs qui recopient la tension d'un segment au suivant. Les répéteurs sont des tampons trois-états, ce qui permet de déconnecter les portions inutilisées de la ligne de bit. Ce faisant, la fenêtre d'instruction est découpée en segments, qui peuvent être désactivés si besoin. Si il y a peu d'instructions chargées dans la fenêtre d'instruction, les portions inutilisées sont désactivées. La technique marche d'autan mieux si les instructions sont compactées au début de la fenêtre d'instruction. [[File:Wire partitionning.png|centre|vignette|upright=2|Wire partitionning]] Tout le problème est de savoir quelles portions désactiver. La technique est assez simple si la fenêtre d'instruction est compactée, à savoir si toutes les instructions sont régulièrement regroupées au début de la mémoire CAM. Mais même avec cette optimisation, la décision de désactiver une portion de la fenêtre d'instruction n'est pas à prendre à la légère. Il ne faut pas désactiver une portion contenant des instructions pouvant être émise sous peu. La décision dépend de paramètres variés : proportion d'entrée vides, quantité d'entrées récemment activées/désactivées récemment, présences d'entrées avec un ''match'' d'opérandes récent, etc. Il est important de préciser que les techniques en question fonctionnent aussi sur les autres types de fenêtre d'instruction, qui ne sont pas basées sur des mémoires associatives. Nous allons voir celles-ci dans la suite du chapitre, mais gardez à l'esprit que ces optimisations, à savoir désactiver les entrées vides/prêts et partitionner la fenêtre d'instruction, sont des optimisations générales qui marchent avec presque tout. ===L'ajout d'une FIFO pour les instructions déjà prêtes à l'émission=== D'autres techniques permettent de réduire aussi bien le cout en circuits que la consommation d'énergie de la fenêtre d'instruction. L'idée est d'utiliser une mémoire associative quand elle est réellement nécessaire, mais d'utiliser une fenêtre d'instruction "normale" dès que possible. La méthode la plus simple tient compte du fait que certaines instructions ont déjà toutes leurs opérandes de disponibles à l'émission, mais doivent quand même être mises en attente, parce que l'ALU adéquate est occupée, parce que des dépendances WAW/WAR sont encore là, ou pour tout autre raison. Dans ce cas, elles sont mises en attente non pas dans la fenêtre d'instruction, mais dans une mémoire FIFO toute simple. L'idée est qu'au lieu d'avoir une énorme mémoire associative pour la fenêtre d'instruction, on déplace quelques entrées dans une petite FIFO annexe. Le résultat est un gain en terme d'énergie et de circuits, au prix d'une perte de performance mineure. La perte de performance en question se manifeste si aucune instruction n'a ses opérandes de prêtes à l'émission : le programme n'utilise pas la FIFO et voit alors une fenêtre d'instruction plus petite. Une amélioration de cette technique tient compte du fait que certaines instructions sont dans un cas intermédiaire. Elles ont déjà une opérande de prête lors de l'émission, mais pas l'autre. Le nombre d'opérandes varie suivant l’instruction : certaines n'ont besoin que d'un seul opérande. De plus, il arrive qu'une opération tout juste décodée ait déjà un ou plusieurs de ses opérandes de prêts. Cette constatation permet d'éviter d'utiliser des comparateurs pour les opérandes déjà prêts. Par exemple, on peut parfaitement utiliser trois fenêtres d'instruction : * une pour les instructions dont tous les opérandes sont prêts, mais qui sont quand même mises en attente, sans comparateur ; * une pour les instructions dont un seul opérande manque, qui n'utilise qu'un comparateur par entrée ; * une pour les instructions dont deux opérandes manquent à l'appel, qui utilise deux comparateurs par entrée. C'est beaucoup plus économique que d'utiliser une seule grosse fenêtre d'instruction qui contiendrait autant d'entrées que les trois précédentes réunies, avec deux comparateurs par entrée. Certains sont même allés plus loin, et ont proposé de supprimer la fenêtre d'instruction avec deux opérandes par entrée. Les instructions dont deux opérandes sont inconnus au décodage sont stockées dans la fenêtre d'instruction pour instructions avec un comparateur par entrée. Un circuit de prédiction se charge alors de prédire l'opérande manquant, cette prédiction étant vérifiée plus loin dans le pipeline. Il serait cependant étonnant qu'une telle proposition ait donné lieu à la moindre implémentation réelle. ===Les optimisations de la consommation d'énergie avancées=== D'autres chercheurs ont conservé une fenêtre d'instruction unique, avec autant de comparateurs par entrée qu'il y a d'opérandes possibles par instruction. Simplement, le processus de détection des opérandes prêts est légèrement ralenti : on ne vérifie qu'un opérande par cycle. Pour vérifier les deux opérandes d'une entrée, on doit attendre deux cycles. Enfin, certains chercheurs ont proposé des fenêtres d'instruction segmentées. Les instructions circulent à chaque cycle d'un segment vers le suivant : en conséquence, certains segments conservent les instructions les plus anciennes, un autre les instructions les plus jeunes, etc. Seul le denier segment, celui qui contient les instructions les plus vielles, peut émettre une instruction : la détection des opérandes se fait seulement dans le dernier segment, qui contient les instructions les plus anciennes. On économise ainsi beaucoup de comparateurs. Certains chercheurs ont tenté de pipeliner l'étape de sélection des opérandes, ainsi que l'étage d'arbitrage. Mais en faisant cela, il faut plusieurs cycles pour détecter qu'une instruction a ses opérandes prêts, ce qui pose problème face à de nombreuses dépendances RAW. Pour éviter de trop perdre en performances, certains chercheurs ont décidé d'utiliser des techniques pour prédire quelles seront les instructions dont les opérandes seront bientôt prêts. Si détecter qu'une instruction est prête prend n cycles, le processeur devra tenter de prédire la future disponibilité des opérandes n cycles en avance pour obtenir des performances optimales. ===Remplacer la mémoire associative par une RAM=== Une autre optimisation possible est de remplacer la fenêtre d'instruction par une mémoire RAM, dont chaque mot mémoire correspondrait à une entrée. Une telle optimisation permet en théorie de se passer des comparateurs associés à chaque entrée, mais au prix de l'ajout de circuits annexes potentiellement couteux. La première de ces techniques, la '''recherche directe par étiquette''' (direct tag search) fut créée par Weiss et son collègue Smith. Ils cherchaient à améliorer l'algorithme de Tomasulo, un algorithme qu'on expliquera dans quelques chapitres. Rappelons que chaque instruction produit un résultat, qui devra être rapatrié dans une ou plusieurs entrées de la fenêtre d'instruction. L'optimisation de la recherche directe par étiquette fonctionne dans le cas où le résultat de l'instruction n'est utilisé que par une seule entrée, et pas plusieurs. Le principe est simple : chaque champ « opérande » d'une entrée est adressable via le nom de registre de cette opérande. Pour faire le lien entre entrée et nom de registre, la recherche directe par étiquette ajoute une table de correspondances matérielle, une mémoire RAM qui mémorise les adresses des champs « opérande » des entrées. Les adresses envoyées dans cette mémoire sont les noms de registres des résultats. Lors de l'émission, la table de correspondances est mise à jour. Les numéros des champs « opérande » réservés lors de l'émission sont mémorisés dans les mots mémoire qui correspondent aux deux registres sources. Toutefois, une petite vérification est faite lors de l'émission : si il y a déjà une correspondance dans la table pour un registre source, alors une autre instruction compte lire ce registre. Pour éviter d'écraser les données de l'instruction précédente dans la table de correspondances, l'émission de l'instruction est bloquée. [[File:Recherche directe par étiquette.png|centre|vignette|upright=2|Recherche directe par étiquette.]] ==Les fenêtres d’instruction avec préplanification== Avec la '''préplanification''' (''prescheduling''), la fenêtre d’instruction est composée de mémoires FIFO dans lesquelles les instructions sont triées dans l'ordre d'émission. Il n'y a pas de logique d’émission proprement dite, celle-ci se bornant à vérifier si l'instruction située au début de la FIFO peut s’exécuter. Par contre, le préplanificateur détecte les dépendances et en déduit où insérer les instructions dans le tampon d'émission, à l'endroit le plus adéquat. [[File:Préplanification.jpg|centre|vignette|upright=2|Préplanification.]] ===L'usage de FIFO multiples=== La technique de préplanification la plus simple utilise plusieurs FIFO. Quand une instruction a une dépendance avec une autre instruction, les deux sont placées dans la même FIFO. Pour cela, le préplanificateur détecte les chaines d'instructions dépendantes, et place les instructions dans la FIFO adéquate. A chaque cycle, l'unité d'émission lit une micro-opération dans chaque FIFO et vérifie si elle peut l'émettre. Si la micro-opération n'a pas ses opérandes disponibles, ou qu'une dépendance structurelle survient, alors la FIFO est bloquée. La micro-opération attend que la dépendance soit résolue, bloquant toutes les instructions précédentes. Mais les autres FIFO ne sont pas bloquées, laissant de la marge de manœuvre. [[File:Préplanification par FIFO multiples.png|centre|vignette|upright=1.5|Préplanification par FIFO multiples.]] ===La technique du tampon trié=== La technique du '''tampon trié''' trie les instructions selon le temps d'attente avant leur exécution. Les instructions qui sont censées s’exécuter bientôt sont insérées au tout début de la FIFO, tandis que les instructions qui s’exécuteront dans un long moment sont insérées vers la fin. Là encore, l'unité d'émission lit une micro-opération dans la FIFO, et détermine si elle peut être émise. Si une dépendance survient, l'émission est retardée, et la FIFO est bloquée. [[File:Préplanification par tampon trié.png|centre|vignette|upright=1.5|Préplanification par tampon trié.]] La technique a cependant quelques problèmes assez importants. Le premier problème est que la FIFO est bloquée lorsqu'une micro-opération ne peut être émise. Le second problème est que le temps avant exécution n'est pas toujours connu, notamment pour les instructions d'accès mémoire. Et cela se répercute sur les instructions dépendantes de celles-ci. Pour résoudre ce genre de problèmes, l'usage d'un pipeline à ''replay'' est possible, et est même l'une des meilleures solution possible, malgré ses défauts. L'idée est que les lecture sont pré-planifiées en supposant qu'elles font un succès de cache L1. Si la prédiction est fausse, la lecture est ré-exécutée plusieurs cycles plus tard, en supposant qu'elle fait un succès dans le cache L2, et ainsi de suite. Elle est alors ré-insérée dans la FIFO, elle est pré-planifiée une seconde fois. Il en est de même si une micro-opération ne peut pas être émise : il suffit de la réinsérer dans la FIFO au bon endroit, en attendant que ses dépendances soient résolus. Ainsi, l'instruction fautive ne bloque pas la fenêtre d’instruction, et retente sa chance autant de fois qu'il le faut. [[File:Préplanification par fenêtre d’instruction scorebarodée.png|centre|vignette|upright=1.5|Préplanification par fenêtre d’instruction scorebarodée.]] Une autre solution utilise deux fenêtres d’instruction : une FIFO gérée par la préplanification, et une vraie fenêtre d'instruction pour les instructions dont le temps d'attente ne peut pas être déterminé. Il est possible de mettre cette dernière avant la préplanification, afin de gérer les temps d'attente des instructions d'accès mémoire. Quand le temps d'attente d'une lecture devient connu, ses instructions dépendantes sont gérées avec préplanification. [[File:Préplanification avec fenêtre d’instruction.png|centre|vignette|upright=2.5|Préplanification avec fenêtre d’instruction.]] ===Les fenêtres d'instruction avec allocation temporelle statique=== L''''allocation temporelle statique''' correspond à une technique utilisée sur les processeurs Cuzco de l'entreprise Condor. La technique en question a été présenté en 2025, mais des idées similaires ont été présentées dans la littérature académique. Elle ressemble beaucoup aux techniques de pré-planification, avec cependant quelques différences. L'idée est simple : le processeur dispose de plusieurs fenêtres d'instruction, qui mettent en attente les micro-opérations. Lors de l'étape de renommage de registres, le processeur détermine dans combien de cycles d'horloge la micro-opération sera prête pour exécution. La micro-opération est alors mise en attente durant ce nombre de cycles, dans les fenêtres d'instruction, puis est émise une fois ce nombre de cycles écoulés. Ce faisant, les fenêtres d'instruction n'ont pas besoin de détecter la disponibilité des opérandes à chaque cycle, pour chaque micro-opération en attente. Le ''timing'' de l'émission des micro-opérations est décidé à l'avance. L'implémentation exacte n'est pas connue, mais plusieurs solutions sont imaginables. Par exemple, la fenêtre d'instruction peut simplement être composée de plusieurs mémoires de petite taille, chacune contenant les micro-opérations destinées à être exécutées dans N cycles, N étant différent pour chaque mémoire. Une autre solution, plus réaliste, utilise une fenêtre d'instruction dans laquelle la micro-opération est couplée à des champs pour les opérandes, et un champ compteur. Le champ compteur est initialisé avec le nombre de cycles à attendre, et est décrémenté à chaque cycle d'horloge. Quand il atteint zéro, la micro-opération est émise. Vous remarquerez que la méthode ne marche que si toutes les micro-opérations prennent un nombre fixe de cycles d'horloge. Et autant c'est le cas pour les micro-opérations arithmétiques ou logiques, autant les accès mémoire ne rentrent pas dans ce cadre. En théorie, on ne sait pas combien de temps prendra un accès mémoire. Et cette incertitude se répercute sur les instructions dépendantes d'un accès mémoire. Pour éviter cela, le processeur réutilise un pipeline à ''replay'' tel que vu dans le chapitre précédent. L'unité de renommage de registre suppose que tout accès mémoire fait un succès de cache L1, et décide des ''timings'' d'émission sous cette hypothèse. Si une lecture subit un défaut de cache, elle est ré-exécutée, de même que toutes les instructions dépendantes. Pour cela, le registre de destination de la lecture est marqué comme invalide, grâce à un bit spécifique attaché au registre. Toute instruction qui lit une opérande invalide est elle aussi ré-executée de zéro. Pour simplifier, l'unité d'émission ressemble à une unité d'émission dans l'ordre, avec un registre de disponibilité, qu'on aurait amélioré pour aller au-delà de la simple détection des dépendances d'instruction. Pour déterminer les ''timings'' d'émission, à savoir quand émettre une micro-opération, le processeur utilise une unité d'émission à deux étages. Le premier étage est appelé le ''register scoreboard'', le second étage est appelé la ''Time Ressource Matrix''. Les deux étages communiquent entre eux, comme on va le voir, et leurs noms donnent une idée de ce qu'ils font. Le premier étage gère les dépendances de registres, le second gère les dépendances structurelles. Le premier étage est un registre de disponibilité amélioré, qui gère les dépendances de registre. Cet étage sait quand tel registre sera écrit, et donc que l'opérande écrite dedans sera disponible à partir de tel cycle d'horloge. Il le sait car l'étage suivant l'aura prévenu, mais laissons cela de côté pour le moment. Quand une micro-opération rentre dans cet étage, il vérifie les dépendances avec les registres et les micro-opérations antérieures. Vu qu'il sait quand les registres seront disponibles, il peut déterminer quand l'instruction pourra s'exécuter. Par exemple, si une micro-opération lit les deux registres R7 et R15, qui sont disponibles respectivement dans 5 et 7 cycles, le premier étage sait que la micro-opération devra attendre 7 cycles. Mais tout cela ne suffit pas à déterminer quand émettre une micro-opération. En effet, il fait aussi gérer les dépendances structurelles, ce qui est le boulot du second étage. Le second étage utilise pour cela une ''Time Ressource Matrix'', qui mémorise l'occupation de diverses "ressources", pour les 256 cycles d'horloge à venir. Les ressources en question sont les ports de lecture/écriture du banc de registre, les ALUs utilisées, si la micro-opération utilise l'unité mémoire, etc. Le second étage prend en entrée une micro-opération, détermine quelles "ressources" elle utilise, puis regarde leur disponibilité. Elle détecte alors les dépendances structurelles et détermine alors quand peut s'exécuter la micro-opération. Elle peut retarder l'émission de quelques cycles, si une dépendance structurelle est détectée. Une fois sortie du second étage, on sait quand la micro-opération va être émise, à quel cycle précisément. Et vu que la durée de l'instruction est fixe, on sait quand cette micro-opération va se terminer, quand son résultat sera disponible. Cela permet de mettre à jour la ''Time Ressource Matrix'', pour préciser que le port d'écriture sera occupé à tel moment. De plus, cette information est transmise au premier étage, qui sait alors quand est enregistré le résultat dans le registre de destination. C'est comme cela que le premier étage sait quand un registre est disponible : le second étage le prévient, quand il émet une instruction ! La ''Time Ressource Matrix''mémorise l'occupation des "ressources" pour les 256 cycles d'horloge à venir. Cependant, elle ne vérifie pas les dépendances pour les 256 cycles suivants. Quand elle reçoit une micro-opération, elle teste les dépendances structurelles pour seulement les 8 prochains cycles maximum. Si la micro-opération ne peut pas être émise pendant ces 8 cycles, le pipeline est bloqué, un ''pipeline stall'' est émis. Pour être plus précis, vu que le processeur peut décoder 8 micro-opérations en même temps, cela permet de ne consulter que 64 cycles d'horloge sur les 256. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les premiers processeurs Intel | prevText=Les premiers processeurs Intel | next=Le renommage de registres | nextText=Le renommage de registres }} </noinclude> 5ldjq07fff1sryjjsryrdqsa97qsvs1 773607 773605 2026-09-29T20:05:26Z Mewtow 31375 /* Les fenêtres d’instruction : généralités */ 773607 wikitext text/x-wiki Dans les chapitres précédents, nous avons parlé des techniques dites d''''émission dans l'ordre'''. L'idée est d’exécuter une nouvelle micro-opération à chaque cycle, dans des unités de calcul séparées. Les instructions sont émises consécutivement, mais les instructions s’exécutent en parallèle dans des unités de calcul séparées. Par contre, quand l'unité d'émission ne peut pas émettre une instruction, elle bloque tout le pipeline. Les instructions qui suivent sont elles aussi bloquées, elle doivent attendre leur tour, même si elles sont en capacité de s'exécuter. Les techniques d'exécution dans le désordre que nous allons voir dans ce chapitre corrigent ce point précis. Elles sont dites à '''émission dans le désordre'''. Elles se distinguent des précédentes sur un point précis : quand l'unité d'émission bloque l'émission d'une instruction, les instructions suivantes peuvent poursuivre. L'émission des instructions peut donc se faire dans le désordre, dans le sens où une instruction peut être émise alors qu'une instruction précédente ne l'est pas encore. L'avantage de l'émission dans le désordre est qu'une instruction s'exécute dès que ses opérandes sont disponibles. Par disponible, on veut dire présent soit dans le réseau de contournement, soit dans les registres. Le processeur détecte automatiquement quand les opérandes d'une instruction sont sont disponibles, et il l’exécute à ce moment là. Dès qu'une instruction a ses opérandes disponibles, elle est émise et exécutée. C'est là la seule contrainte : les dépendances WAR, WAW et autres sont gérées par un ROB ou toute autre technique d'exception précise, seules les dépendances RAW limitent l'exécution. Mais avant de poursuivre, quelques point niveaux terminologie : * L'émission dans le désordre est un terme parlant et assez précis. Malheureusement, la terminologie la plus utilisée par d''''exécution dans le désordre'''. Et nous utiliserons ce terme dans la suite du cours, histoire de ne pas trop dévier de la nomenclature habituelle. * Nous utiliserons parfois l'abréviation OOO pour parler d'exécution dans le désordre. L'abréviation est celle de ''Out Of Order Excution''. * Nous utiliserons aussi l'abréviation ''µop'' pour parler de micro-opération, ''µops'' au pluriels pour parler de plusieurs micro-opérations, ou des micro-opérations en général. L'exécution dans le désordre ne gére en effet que des µops, elle se situe après l'étape de décodage. Mais avant de poursuivre, précisons une chose importante : l'exécution dans le désordre traite les accès mémoire à part. La majorité des processeurs OOO assez anciens exécutent les accès mémoire dans l'ordre, seules les µops entières/flottantes/branchements sont exécutées dans le désordre. Les processeurs datant d'après les années 2010 sont capable d'exécuter les accès mémoire dans le désordre, mais l'implémentation en question est assez particulière. Un chapitre entier sera dédié à l'exécution dans le désordre des µops mémoire. Nous allons volontairement mettre de côté la gestion des accès mémoire dans ce chapitre. ==Les fenêtres d’instruction : généralités== [[File:File de micro-opération.png|vignette|upright=1|File de micro-opérations]] Pour décrire comment est implémentée l'émission dans le désordre, il faut commencer par parler des processeurs sans. Les processeurs sans exécution dans le désordre ont une unité d'émission qui bloque tout le pipeline dès qu'une µop ne peut pas être émise. Pour limiter l'impact de ce blocage, quelques rares processeurs incorporent une '''file de micro-opération''', une mémoire FIFO qui met en attente les µops. Vu que c'est une mémoire FIFO, les µops sont émises dans l'ordre, à savoir l'ordre d'ajout, dans l'ordre de décodage. Le schéma ci-dessous illustre une telle file d'attente couplée à un ''scoreboard''. Sur le principe, l'exécution dans le désordre améliore la file de µops sur un point : ce n'est plus une mémoire FIFO. Les µops sont insérées dans l'ordre, mais peuvent sortir dans le désordre (être émises dans le désordre). La file de µops devient alors une '''fenêtre d'instruction''', terme traduit directement de l'anglais ''instruction Window''. Terme assez trompeur, car elles mettent en attente des µops, pas des instructions. Elles peuvent émettre des µops dans le désordre, ce qui fait que si une µop bloque le pipeline, les µops suivantes peuvent être émises. [[File:Différence file µops et fenêtres instruction.png|centre|vignette|upright=2|Différence file µops et fenêtres instruction]] Si je commence le paragraphe précédent par "sur le principe", c'est car certaines techniques d'OOO utilisent des files de µops normales. Il est par exemple possible d'utiliser une file de µops avec une fenêtre d'instruction, plusieurs files de µops, plusieurs fenêtres d'instructions avec une file de µops annexe, etc. Dasn les grandes lignes, il existe dans les grandes lignes 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! File de µops améliorée |- ! Une seule "file de µops" | ''Scoreboard'' | Fenêtre d'instruction centralisée |- ! Plusieurs "file de µops" | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | Fenêtre d'instruction décentralisée |} ===La fenêtre d'instruction centralisée=== L'implémentation la plus simple de l'OOO utilise une unique fenêtre d'instruction, appelée une '''fenêtre d'instruction centralisée'''. Les µops décodées sont accumulées dans la fenêtre d'instruction, où elles attendent que leurs opérandes soient disponibles. La fenêtre d'instruction sert donc de file d'attente. Mais elle contient aussi une unité d'émission, qui détecte quelles µops sont prêtes à être émises. L'unité d'émission et la fenêtre d'instruction sont fusionnées ensemble, elles forment un seul circuit. Mais nous allons dire qu'elles sont conceptuellement séparées pour le moment. A chaque cycle, l'unité d'émission consulte la fenêtre d'instruction pour voir quelles µops peuvent s'exécuter, lesquelles ont leur opérandes de disponibles. La fenêtre d'instruction doit spécialement être conçue pour, c'est une sorte de mémoire associative très complexe, comme on le verra dans ce qui suit. [[File:OOO Issue.png|centre|vignette|upright=2.5|Exécution dans le désordre avec une fenêtre d'instruction]] Une fois qu'une µop sort du décodeur d'instructions, elle est ajoutée en parallèle dans la fenêtre d'instruction et le ROB. La raison est que les µops quittent la fenêtre d'instruction dans le désordre, et qu'elles doivent être remises en ordre par la suite. Le ROB s'occupe de cette remise en ordre, mais il a besoin de savoir dans quel ordre les µops sont censées être, et cet ordre est celui du décodage. Aussi, pour remplir le ROB, la seule opportunité est en sortie de l'unité de décodage. Dans le cas où une instruction est décodée en plusieurs micro-opérations, elles sont toutes insérées en même temps dans la fenêtre d'instruction et le ROB, en tenant compte de leur ordre. [[File:Fenêtre d'instruction.png|centre|vignette|upright=2|Fenêtre d'instruction.]] Les micro-opérations mémoire sont à part des autres, pour diverses raisons. Une de ces raisons est que les dépendances de données sont classées en deux types : les dépendances de registre et les dépendances d'adresse. Et les deux sont fondamentalement différentes. Autant on peut détecter les dépendances de registre lors de l'émission, autant c'est plus compliqué avec les dépendances d'adresse. De plus, rappelons que si les lectures peuvent s'exécuter dans le désordre, les écritures doivent s'exécuter dans l'ordre, ou du moins en donner l'illusion. Pour cela, le processeur remet les écritures dans l'ordre avec une sorte de mini-ROB intégré à l'unité mémoire, appelée la file d'écriture. Elle complémente le ROB, qui lui ne gère que les écritures dans les registres, mais les deux collaborent. La file d'écriture envoie une écriture à la mémoire RAM quand le ROB lui dit que c'est bon, les instructions précédentes sont terminées ''dans l'ordre du programme''. Les processeurs modernes ajoutent des techniques d'exécution dans le désordre des accès mémoire, mais nous les verrons dans un chapitre dédié. Elles permettent d'utiliser une fenêtre d'instruction unique, qui mémorise aussi les µops mémoire. Si elles sont mises en place, l'unité mémoire n'a pas besoin de file de µops séparée. L'idée est que les dépendances de registre sont traitées par la fenêtre d'instruction, mais que l'unité mémoire gére les dépendances d'adresse. Les dépendances d'adresse sont gérées par des techniques de ''désambiguation mémoire'', qui auront droit à un chapitre dédié. [[File:Processeur avec exécution dans le désodre des accès mémoire.png|centre|vignette|upright=2|Processeur avec exécution dans le désodre des accès mémoire]] Les processeurs assez anciens n'autorisaient pas d'exécution dans le désordre des accès mémoire. Concrétement, les accs mémoire devaient se faire dans l'ordre, mais les autres µops pouvaient être exécutées dans le désordre. Il s'agit donc d'un ordre entre µops mémoire, pas entre µops mémoire et autres µops. Les µops entières et flottantes pouvaient être exécutées avant une µops mémoire qui est avant elle dans l'ordre du programme, ce n'est pas un problème. Pour garantir l'ordre desd µops mémoire, l'unité mémoire est précédée par une file de micro-opérations séparée, pour forcer l'exécution dans l'ordre des accès mémoire. De plus, les µops mémoire ne peuvent pas utiliser la fenêtre d'instruction. Dit autrement, la fenêtre d'instruction ne mémorise pas de µops mémoire. Après le décodage, les µops sont réparties soit dans la file de µops mémoire, soit dans la fenêtre d'instruction. Le décodeur classe les µops suivant que ce sont des µops mémoire ou non, et les envoient à la bonne destination. Dans ce chapitre, on supposera que c'est cette solution qui est utilisée. [[File:Processeur avec émission dans l'ordre des accès mémoire.png|centre|vignette|upright=2|Processeur avec émission dans l'ordre des accès mémoire]] La solution précédente revient à scinder la fenêtre d'instruction en deux : une file de µops pour les µops mémoire, une fenêtre d'instruction pour les autres µops. Et cette scission peut aller plus loin, à savoir qu'on peut scinder une fenêtre d'instruction encore et encore. Ce qui nous amène à la section suivante. ===Les fenêtres d'instruction décentralisées=== Nous venons de voir qu'il est possible de scinder la fenêtre d'instruction en une fenêtre d'instruction pour les µops mémoire (simplifiée en une file de µops classique), et une autre pour les autres µops. Sachez qu'il est possible d'aller plus loin, par exemple en séparant la fenêtre d'instruction en une fenêtre spécialisée dans les µops flottantes et une autre pour les µops entières. Et ce n'est là qu'un exemple parmi de nombreuses autres possibilités. Pour faire la différence avec une fenêtre d'instruction unique, nous allons parler de fenêtre d'instruction centralisée s'il n'y en a qu'une, de '''fenêtre d'instruction décentralisée''' s'il y en a plusieurs. Il est possible d'associer chaque fenêtre d'instruction à un type précis de µops. Par exemple, avec une fenêtre d'instruction pour les µops de calcul entières, une autre pour les µops flottantes, une autre pour les µops mémoire. Il s'agit d'un choix simple et efficace, mais quelques processeurs font autrement, pour répondre à des contraintes très diverses. [[File:Processeur avec des fenêtres d'instruction décentralisées.png|centre|vignette|upright=2|Processeur avec des fenêtres d'instruction décentralisées]] Reste à scinder la fenêtre d'instruction pour trier les µops suivant leur type. Si le processeur exécute les accès mémoire dans l'ordre, la méthode la plus simple utilise une fenêtre d'instruction pour les opérations flottantes et une autre pour les autres µops (µops entières et parfois mémoire avec). L'avantage est que cela simplifie grandement le processeur. Les flottants sont gérés à part des entiers. Ils ont leurs propres registres, des FPU séparées des ALU entières, bref : la séparation est complète. Utiliser une fenêtre d'instruction séparée va dans ce sens. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Il est possible de faire pareil sur les processeurs avec exécution dans le désordre des accès mémoire. Par exemple : les processeurs Intel de microarchitecture Skylake utilisent une fenêtre d'instruction pour les opérations entières/flottantes, et une fenêtre d'instruction séparée pour les µops mémoire. Un avantage est que les deux fenêtres d'instructions sont plus spécialisées, ce qui entraine des économies de circuit. Les opérations entières/flottantes ont besoin de deux registres pour les opérandes et d'un autre résultat, alors que les µops mémoire n'ont besoin que de deux registres maximum. En utilisant une fenêtre d'instruction unique, chaque entrée doit mémoriser l'opcode et trois registres, dont un est inutilisé pour les µops mémoire et les branchements. En utilisant des fenêtres d’instructions séparées, celle pour les µops entières/flottantes a trois registres par entrée, contre seulement deux registres par entrée pour celle des µops mémoire. Un cas extrême est celui où chaque ALU/FPU a sa propre fenêtre d'instruction. Nous parlerons alors de '''fenêtres d'instruction totalement décentralisées'''. Par exemple, il y a une fenêtre d'instruction pour l'ALU entière, une autre pour le multiplieur entier, une autre pour le ''barrel shifter'', une autre pour l'unité mémoire, une autre pour l'unitéé de branchements, une autre pour l'additionneur flottant, une dernière pour le multiplier flottant, etc. Un exemple historique est celui de la FPU de l'IBM 360 modèle 90. Elle disposait d'un additionneur flottant, d'un multiplieur flottant, et d'une unité mémoire pour les lectures/écritures flottantes. Les trois unités avaient leur propre fenêtre d'instruction. Les processeurs AMD utilisent beaucoup cette technique, contrairement à Intel qui préfère utiliser des fenêtres centralisées sur les anciens processeurs, deux ou trois fenêtres sur les processeurs récents (2020 et plus). Les processeurs AMD utilisaient précisément une fenêtre d'instruction par ALU entière, alors que les FPUs partagent une fenêtre d’instructions flottantes unique. Mais nous verrons cela en détail dans le chapitre sur les processeurs superscalaires x86. Un point important est qu'avec des fenêtres d'instruction décentralisées, l'émission est découpée en deux étages. La première étape envoie une µops vers la fenêtre d'instruction adéquate, la seconde émet la µops depuis la fenêtre d'instruction quand ses opérandes sont prêtes. La première est l'étage de '''''dispatch''''' qui envoie l'instruction dans la fenêtre d’instruction adéquate, selon que c'est une instruction flottante, entière, autre. La seconde est l'étage de '''''scheduling''''', qui gère la disponibilité des opérandes et des unités de calcul. La µop émise est ajoutée au tampon de réordonnancement, s'il existe, lors de l'étape de ''dispatch''. ===L'usage de plusieurs files d'instruction=== Une dernière méthode d'OOO utilise plusieurs files de micro-opération. L'idée est qu'une fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement une file de micro-opération pour les opérations entières, une autre pour les opérations flottantes, une autre pour les accès mémoire. D'autres processeurs utilisent une file pour les accès mémoire et une autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. La présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que la technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si une dépendance bloque une FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans une autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer la disponibilité des registres. Quand un registre est lu ou écrit par une instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. La logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : une pour les instructions d'accès mémoire et une autre pour les autres instructions. Si jamais une instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de la lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'une est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est la file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. ===Avantages et inconvénients de chaque implémentation=== Pour résumer, on a le choix entre une grosse fenêtre d'instruction généraliste et plusieurs fenêtres spécialisées. Le choix entre les deux est un compromis entre économie de circuits et flexibilité. Avec une fenêtre décentralisée, il arrive qu'une fenêtre d'instruction soit remplie, alors que les autres sont sous-utilisées, voire vides. Pour comprendre pourquoi, comparons une fenêtre d'instruction unique, avec une fenêtre décentralisée séparant µops entières et flottantes. La fenêtre centralisée dispose de 64 entrées, la décentralisée a 32 entrées pour chaque fenêtre d'instruction. La fenêtre décentralisée peut mémoriser au maximum 32 µops entières et 32 *ops flottantes. Par contre, la fenêtre centralisée peut mémoriser 64 µops tout court. Si le programme exécuté n'utilise pas de nombres flottants, la différence devient flagrante. La fenêtre décentralisée sera limitée ) 32 µops, alors que la centralisée pourra mémoriser le double. Les performances seront donc meilleurs avec la fenêtre centralisée. Et au-delà de ça, la fenêtre décentralisée de l'exemple est utilisée de manière optimale si la moitié des µops sont des µops entières, et l'autre moitié des µops flottantes. Alors que la fenêtre centralisée se moque de la répartition entre µops entières et flottantes. Une subtilité est que le cout en transistors d'une fenêtre d'instruction n'est pas proportionnel au nombre de µops qu'elle peut mémoriser. Par exemple, si je compare une fenêtre d'instruction de 32 entrées (32 µops max), elle n'utilise pas deux fois plus transistors qu'une fenêtre de 16 entrées. Le cout en circuit n'est pas deux fois plus élevé, mais est approximativement 4 fois plus élevé. Le cout est presque quadratique, à savoir qu'il est proportionnel au carré du nombre d'entrées. Et il en est de même avec la performance, pour des raisons qu'on expliquera plus bas. Les fenêtres décentralisées utilisent plusieurs fenêtres d'instruction de "petite taille", donc plus rapides, économes en circuits et économes en énergie. Le compromis n'est donc pas entre une fenêtre centralisée à 64 entrées versus deux fenêtres de 32 entrées. Le compromis en pratique est entre une fenêtre centralisée de 64 entrées versus 3 fenêtres de 32 entrées. Un exemple pratique est celui de la microarchitecture ''Skylake'' d'Intel. Intel est passé d'une fenêtre centralisée pre-''Skylake'' à deux fenêtres décentralisées sur ''Skylake'',. Le nombre d'entrée était globalement le même entre les deux, même si l'évolution de la finesse de gravure entre les deux biaise un peu les résultats. Un avantage des fenêtres décentralisées est qu'il est possible de démarrer l'exécution de plusieurs µops simultanément : une µops par fenêtre d'instruction. Le fait est que deux fenêtres d'instructions différentes émettent leurs µops sans se synchroniser avec les autres. Deux fenêtres d'instruction peuvent donc émettre chacune une µops, ce qui fait deux µops émises lors du même cycle. Cela permet d'exécuter en même temps deux ou trois instructions 1-cycle, comme des additions, soustractions, décalages, etc. Il devient par exemple possible d'émettre une µop entière en même temps qu'une µop flottante, si les µops entières ont une fenêtre séparée de celle des µops flottantes. Il est maintenant temps de voir en quoi sont faites les fenêtres d’instruction, qu'elles soient centralisées ou décentralisées. Nous allons aussi voir quelle est la logique d'émission associée. ==L'implémentation d'une fenêtre d'instruction : généralités== Une fenêtre d'instruction est une mémoire qui mémorise des micro-opérations. Elle est cependant plus complexe qu'une mémoire RAM ou qu'une FIFO et ressemble un petit peu à une mémoire cache. Elle dispose d'un port d'écriture et d'un port de lecture, au minimum. Le port d'écriture permet à l'unité de décodage d'insérer une micro-opération dedans, d'ajouter la micro-opération qui vient d'être décodée. Si une instruction machine est décodée en plusieurs micro-opération, deux possibilités. La première est de les insérer un par un, ce qui fait qu'on peut se contenter d'un seul port d'écriture. L'autre possibilité est de les ajouter en même temps, ce qui demande plusieurs ports d'écriture. Le port de lecture sert à émettre une instruction. On part du principe que la fenêtre d'instruction ne peut émettre qu'une seule instruction à la fois, car les processeurs que nous avons vu précédemment sont de ce type. Mais nous verrons dans quelques chapitre qu'il existe des processeurs dits superscalaires, qui sont capables d'émettre plusieurs instructions par cycle. Dans ce cas, la fenêtre d'instruction a un seul port de lecture. Un processeur superscalaire, quant à lui, doit avoir un port de lecture par unité de calcul, ce qui fait beaucoup plus. Les fenêtres d'instruction sont composées d''''entrées''', des mots mémoire qui stockent une instruction. Une instruction réserve une entrée après son décodage et la libère dès qu'elle est envoyée aux unités de calcul. Une entrée contient l'opcode (les signaux de commande à envoyer à l'ALU), le registre de destination du résultat, les registres de chaque opérande, et éventuellement des signaux de commande en plus. De plus, chaque opérande est couplée à un bit de disponibilité, qui indique si elle est disponible. Quand un opérande est écrit dans les registres, le bit de présence correspondant est mis à jour. Enfin, chaque entrée possède un bit ''empty'' qui indique si elle est vide, cette information étant utile pour réserver des entrées. [[File:Entrée d'une station de réservation - sans les tags.png|centre|vignette|upright=3|Entrée d'une fenêtre d'instruction]] ===Les stations de réservation=== Les '''stations de réservation''' sont des fenêtres d'instruction particulières, qui sont capables de mémoriser les opérandes des instructions. Les entrées des stations de réservation sont identiques à celle des autres fenêtres d'instruction, si ce n'est que les opérandes de l'instruction sont enregistrées directement dans des champs séparés. Il y a deux champs, un par opérande, pour stocker l'opérande elle-même, lue depuis les registres ou obtenue via le réseau de contournement. Notons que les champs pour les opérandes viennent en plus des champs pour les noms de registres, encore que les deux peuvent être fusionnés si on veut optimiser le tout. [[File:Entrée d'une station de réservation.png|centre|vignette|upright=3|Entrée d'une station de réservation.]] Précisons que la terminologie n'est pas très fiable. Les termes "fenêtre d'instruction" et "station de réservation" ne regroupent pas du tout la même chose d'un papier de recherche à l'autre, d'un bouquin à l'autre, d'un chercheur à l'autre, d'un ingénieur à l'autre, d'un professeur à l'autre. Le terme initial vient pourtant de l'article original sur l'algorithme de Tomasulo, où il désignait une fenêtre d'instruction associée à une unité de calcul précise. Mais le terme a ensuite été réutilisé, ce qui fait que certains processeurs avec plusieurs unités de calcul sont décrit comme ayant une unique station de réservation. En bref : c'est le bazar ! Mais nous en reparlerons dans le chapitre sur le renommage de registres, car c'est la place idéale pour les aborder. Toujours est-il que j'ai fait le choix de confondre les concepts de fenêtre d'instruction et de station de réservation avec les concepts de '''lecture avant émission''' et de '''lecture après émission'''. La différence entre les deux est que les registres sont lus après émission avec une fenêtre d'instruction, avant avec des stations de réservation. Dans le cas "avant émission", les opérandes sont mémorisées dans la station de réservation. Et cette différence a une influence sur le pipeline du processeur, le banc de registres et tout ce qui s'en suit. Un désavantage de la lecture avant émission est qu'il faut stocker les opérandes après lecture, ici dans les stations de réservation. Mais un avantage est que le banc de registre a besoin de moins de ports de lecture, car une bonne partie des opérandes sont fournies par le système de contournement. Nous verrons cela dans le détail dans le chapitre sur les processeurs superscalaires. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Lecture après émission.]] [[File:Read Before Issue.png|centre|vignette|upright=2.5|Lecture avant émission.]] ===La logique d'éveil et de sélection=== Dans le cas qui va suivre, on suppose que le processeur ne peut émettre qu'une instruction à la fois. Chaque cycle, une instruction est sélectionnée et est envoyée dans le chemin de données, soit à une ALU, soit à une unité d'accès mémoire. La sélection d'une instruction est effectuée par l'unité d'émission, qui est aussi appelée le '''''scheduler'''''. Elle gère la disponibilité des opérandes et la disponibilité des unités de calcul adéquate. Le choix de l'instruction émise doit être le plus pertinent possible, pour des raisons de performances. Pour le premier point, l'unité d'émission détermine quelles instructions sont candidates pour l'émission. Les ''instructions candidates'' sont celles dont tous les opérandes sont prêts. Le processeur contient un circuit qui détecte les instructions candidates : la '''logique d’éveil''' (''wake-up logic''). Une fois que la logique d'éveil a fait son travail, une instruction est choisie pour s’exécuter en fonction de la disponibilité des unités de calcul adéquates. Ce rôle est dévolu à un circuit qu'on appelle la '''logique de sélection''', ou ''select logic''. [[File:Fonctionnement complet de la logique d’émission.jpg|centre|vignette|upright=1.5|Fonctionnement complet de la logique d’émission.]] La logique de sélection doit gérer le fait que les unités de calcul du processeur ne sont pas toutes identiques. Déjà, un processeur a généralement des unités séparées pour les instructions entières et flottantes, des unités spécialisées dans les accès mémoire, parfois des unités spécialisées pour les branchements. Une instruction doit être attribuée à la bonne unité de calcul, on ne doit pas envoyer une instruction entière dans une unité de calcul flottante. De plus, parmi les unités de calcul entières, toutes ne sont pas identiques. Par exemple, il est fréquent d'avoir plusieurs unités de calcul spécialisées dans les opérations simples (additions, soustractions, opérations logiques) avec une unité pour les multiplications/divisions séparées, parfois une unité spécialisée pour les décalages/rotations, etc. Là encore, allouer la bonne instruction à la bonne ALU est complexe. Plus les unités de calcul sont hétérogènes, plus la logique de sélection est compliquée. Les logiques d'éveil comme de sélection sont assez complexes. Comme on le verra plus bas, la logique de sélection la plus simple, qui gère une seule unité de calcul, est basée sur un encodeur à priorité couplé à d'autres circuits. Et pour gérer plusieurs ALUs, il faut mettre des encodeurs en cascade. Le résultat est que même en prenant une logique de sélection simple, elle sera assez lente et gourmande en circuits. Aussi, la logique de sélection met souvent un cycle d'horloge entier pour faire son travail, elle a son propre étage de pipeline attribué. La logique d'éveil est dans le même cas, ce qui fait qu'émettre une micro-opération demande deux cycles d'horloge. Le défaut est que cela rajoute des cycles d'horloges entre la fenêtre d'instruction et l'ALU, ce qui complique la gestion du pipeline. Ces cycles de retard sont à prendre en compte au moment d'émettre les instructions, les ''scheduler'' doit en tenir compte pour des performances optimales. Sans tenir compte de ces cycles de retard, les instructions arrivent en retard de quelques cycles à l'ALU, cycles de retard durant lesquels l'ALU n'a pas fait de calcul et a été sous-utilisée, sans compter que le système de contournement n'est pas utilisé au mieux. Et le problème est encore plus important sur les processeur avec des stations de réservation, qui utilisent la "lecture après émission" : cela rajoute un cycle d'horloge en plus, un temps de retard en plus. ===La logique d'éveil : l'émission anticipée=== La logique d'éveil doit tenir compte du fait qu'il y a plusieurs étages entre l'émission et l'exécution sur une unité de calcul. Par exemple, un processeur a souvent entre un et à cinq étages entre la file d'attente et les unités de calcul. Il faut lire les registres, gérer le contournement, et cela peut prendre quelques cycles d'horloge. Sur le Pentium 4, on trouve 6 étages entre la fenêtre d’instruction et l'entrée de l'ALU. Si les micro-opérations sont émises quand les opérandes sont disponibles, il y aura un délai de quelques cycles avant qu'elles atteignent l'ALU. Alors qu'idéalement, on souhaiterait que la micro-opération atteigne l'ALU dès que ses opérandes sont disponibles, pour profiter des techniques de contournement. Pour cela, la logique d'éveil émet les instructions quelques cycles en avance pour qu'elles arrivent au bon moment. Il s'agit d'une technique d''''émission anticipée''', dont nous avions parlé dans le chapitre sur le contournement. : Il faut noter que le problème se pose plus avec des fenêtres d'instruction qu'avec des stations de réservation. Les premières ont un étage en plus entre émission et ALU, vu qu'il faut lire des registres après l'émission. L'émission anticipée demande d'émettre un signal d'éveil en avance de quelques cycles, pile au bon moment. Par exemples, si on a deux étages entre l'ALU et l'unité d'émission, le signal de réveil sera généré deux cycles avant que le résultat soit effectivement calculé. L'implémentation varie, mais deux solutions sont possibles. La première est de générer le signal d'éveil dans l'ALU, ce qui n'a de sens que pour les opérations comme les multiplications ou les divisions, qui prennent plusieurs cycles. Une autre technique génère le signal de réveil dans une structure centralisée, spécialisée dans la génération des signaux d'éveil. L'unité de composée d'un registre à décalage par registre. Imaginons qu'une instruction est émise, que cette instruction mette N cycles à s'exécuter, et qu'elle écrive dans un registre de destination. L'unité sélectionne alors le registre à décalage associé au registre de destination, et met le bit numéro N à 1. Le registre décalé d'un cran à chaque cycle. Quand le bit sortant est un 1, alors le signal de validité pour l'opérande est généré. L'émission anticipée marche bien si l'instruction a une durée fixe, connue à l'avance. Et autant c'est le cas pour les instructions arithmétiques et logiques, autant ce n'est pas le cas pour les accès mémoire. Les accès mémoire ont une latence variable : quelques cycles pour un succès de cache, plusieurs dizaines de cycles pour un défaut de cache L1, pas loin de la centaine pour un défaut de cache L2, etc. Et cela pose des problèmes pour l'émission anticipée. L'émission en avance pour les accès mémoire est purement spéculative : le processeur émet des instructions en supposant que la lecture entrainera un succès de cache, quitte à annuler l'instruction en cas de défaut de cache. Mais faire ainsi demande non seulement d'annuler les instructions émises en avance, mais aussi de ne pas retirer les instructions émises en avance de la fenêtre d'instruction. Elles sont émises, mais une copie de sauvegarde est conservée dans la fenêtre d'instruction. Si le processeur détecte un défaut de cache, il peut alors ré-exécuter l'instruction. S'il détecte un succès de cache, les instructions lecture-dépendante sont retirées de la fenêtre d'instruction, la copie de sauvegarde est devenue inutile et est donc jetée. ===La logique de sélection : âge ou position ?=== La logique de sélection est primordiale pour de bonnes performances. Il existe deux méthodes principales pour sélectionner l'instruction à exécuter. La première est la plus simple : elle se base sur lé numéro de l'entrée. En effet, une fenêtre d'instruction est avant tout une sorte de mémoire, un mix entre mémoire associative, mémoire RAM, et FIFO. Et chaque entrée a un numéro, une adresse mémoire. Nous parlerons de numéro dans ce qui suit, car ce sera plus simple, le terme d'adresse mémoire étant peut-être un peu exagéré dans le contexte des fenêtres d'instruction. Toujours est-il que la fenêtre d'instruction est adressable dans le sens où on peut lui envoyer le numéro de l'entrée voulue, et la fenêtre d’instruction renvoie le contenu de l'entrée sur son port de lecture. Et c'est ce que fait la logique de sélection : elle génère le numéro de l'entrée à lire. Le numéro est alors envoyé sur l'entrée d'adresse de la fenêtre d’instruction, et elle fournit la micro-opération associée sur son port de lecture, son '''port d'émission'''. La première méthode de sélection, donc. Elle est basée sur sur le numéro de l'entrée. Si plusieurs entrées sont éveillées, la logique de sélection prend celle avec le plus petit numéro. Elle porte le nom de '''sélection par position''', sous-entendu position dans la fenêtre d'instruction. Vous l'avez peut-être deviné, mais la logique de sélection est alors un encodeur à priorité. Le circuit de sélection ne se résume donc pas seulement à un encodeur à priorité, mais c'est le circuit central. L'avantage d'une telle méthode de sélection est qu'elle est simple à implémenter : un encodeur à priorité est un circuit connu, facile à implémenter. Mais on remarque un défaut : un encodeur est un circuit assez rapide, mais qui utilise beaucoup de transistors, beaucoup de portes logiques, surtout si on veut qu'il soit rapide. Ce qui explique que la logique de sélection ait son propre étage de pipeline rien que pour elle. La seconde méthode s'appelle la '''sélection par âge''', au nom assez transparent. L'idée est de privilégier l'émission de l'instruction la plus ancienne. Elle demande que la fenêtre d'instruction trie les micro-opérations par ordre d'insertion dans la fenêtre d'instruction, ce qui en fait une pseudo-FIFO. Le tri est partiel, car les instructions peuvent sortir de la fenêtre d’instruction à tout moment. Compacter la fenêtre d'instruction, à savoir regrouper toutes les entrées valides est une idée, mais elle est compliquée à implémenter. Aussi, elles préfèrent encoder des informations sur l'ordre d'émission dans chaque entrée. L'encodeur à priorité doit alors travailler non pas sur des nombres entiers liés à l'ordre d'insertion dans la pseudo-FIFO. Elle est encore plus gourmande en circuits que la méthode précédente. Les processeurs haute performance utilisent souvent des méthodes hybrides. Par exemple, les processeurs AMD de microarchitecture Bulldozer utilisaient une méthode intermédiaire. Ils utilisaient une fenêtre d'instruction couplée à un encodeur à priorité pour la sélection par position, mais complémentaient le tout avec une unité qui mémorisait l'instruction la plus ancienne dans la fenêtre d’instruction. Le mécanisme de sélection par âge était utilisé en priorité. Mais si l'instruction la plus ancienne n'était pas prête, le processeur basculait sur le mécanisme de sélection par position. ===La compaction des fenêtres d'instruction=== À chaque cycle, les instructions décodées sont ajoutées dans la fenêtre d'instruction, dans des entrées vides. Vu que les instructions quittent celle-ci dans le désordre, ces vides sont dispersés dans la fenêtre d'instruction, ce qui pose problème pour déterminer où placer les nouvelles instructions. La solution la plus triviale consiste à conserver une liste des vides, mise à jour à chaque insertion ou émission d'instruction. Une autre solution consiste à éliminer les vides en compactant la fenêtre d'instruction à chaque cycle d'horloge. Des circuits se chargent de détecter les vides et de regrouper les instructions en un unique bloc. Il faut signaler que certaines processeurs arrivent à se passer de cette étape de compactage, mais au prix de fenêtres d'instruction nettement plus complexes. Autre problème : quand il faut choisir quelle instruction émettre, il y a toujours plusieurs candidats. Si on choisit mal, des instructions restent en attente trop longtemps parce que d'autres instructions plus jeunes leur passent devant. Pour éviter cela, les instructions les plus vielles, les plus anciennes, sont prioritaires. Pour cela, on peut utiliser une FIFO un peu spéciale pour la fenêtre d'instruction. Si les ajouts d'instruction se font dans l'ordre, les instructions ne quittent pas forcément la fenêtre d'instruction dans l'ordre imposé par une FIFO : les instructions restent triées dans leur ordre d'ajout, même s'il y a des vides entre elles. Dans ces condition, il est préférable que le compactage conserve l'ordre FIFO des instructions. Dans ces conditions, l'instruction la plus ancienne est celle qui est située à l'adresse la plus faible : le circuit de sélection peut donc être fabriqué avec des encodeurs, et est relativement simple. ==Les fenêtres d'instruction basées sur une matrice de dépendances== L'implémentation la plus simple étend le fonctionnement d'un pipeline dynamique usuel. Rappelez-vous le chapitre sur les pipeline dynamiques. Nous avions vu que de tels pipelines émettaient une instruction par cycle, quitte à émettre des bulles de pipeline en cas de dépendance bloquante. Et il est possible d'améliorer leur unité d'émission pour qu'elle soit compatible avec l'exécution dans le désordre. ===Rappels sur le registre de réservation/disponibilité=== L'émission d'une instruction est gouvernée par un ''registre de réservation'' qui indique quels registres sont réservés par une instruction, et ceux qui sont libres. Un registre réservé est un registre qui sera écrit par une instruction en cours d'exécution, mais qui n'a pas encore écrit son résultat. Les instructions candidates doivent avoir leurs opérandes dans des registres libres. Sinon, c'est signe que leurs opérandes sont réservées en écriture, donc pas encore écrites, donc pas disponibles. Si une instruction candidate veut lire ce registre, c'est signe qu'il y a une dépendance RAW : elle veut lire un registre réservé, qui est destiné à être écrit par une instruction en vol. Si elle veut écrire, c'est signe qu'elle veut écrire dans un registre où une autre instruction veut écrire : c'est une dépendance WAW. Dans les deux cas, l'instruction n'est pas émise. Le registre de réservation encode les registres réservés comme suit : chaque bit est associé à un registre. Le bit numéro 0 est associé au registre numéro 0, le bit numéro 1 au registre numéro 1, etc. Là, En clair, les numéros de registres réservés sont encodés en représentation non pas binaire, mais en représentation ''one-hot'' (vue au premier chapitre). {|class="wikitable" |+ Registre de réservation |- ! Registre 7 !! Registre 6 !! Registre 5 !! Registre 4 !! Registre 3 !! Registre 2 !! Registre 1 !! Registre 0 |- | 0 || 0 || 1 || 0 || 0 || 1 || 0 || 0 |} Avant d'émettre une instruction, l'unité d'émission extrait les registres opérande/destination et les convertis dans la même représentation que le registre de réservation, à savoir en représentation ''one-hot''. Le circuit de traduction binaire vers ''one-hot'' est, pour rappel, un simple décodeur. Puis, on fait un OU logique entre les sorties des décodeurs. Le résultat est un masque qui indique quels registres sont lus par l'instruction, encodé en représentation ''one-hot''. Appelons-le le '''masque d'opérandes'''. Le masque est alors comparé au registre de réservation pour vérifier si l'instruction peut être émise. [[File:Unité d'émission simple, dans l'ordre.png|centre|vignette|upright=2|Unité d'émission simple, dans l'ordre]] Si l'émission est autorisée, le registres de réservation est là aussi mis à jour. Le registre de réservation est aussi mis à jour dès qu'une instruction enregistre son résultat dans les registres, ou alors dès qu'il est disponible pour le contournement. Le bit associé au registre repasse alors à 0 (ou à 1). Sans contournement, la mise à jour se fait alors à la toute fin de l'instruction, quand elle se termine, lors de la dernière étape d'enregistrement, à la fin de son pipeline. Avec, elle se fait quand l'instruction quitte l'unité de calcul. ===L'extension à l'exécution dans le désordre : l'éveil par matrice de bits=== La différence entre un pipeline dynamique et l'exécution dans le désordre est que l'on passe d'une instruction à émettre à plusieurs. Plusieurs instructions sont mises en attente dans une fenêtre d’instruction, et y attendent leur tour. L'idée est alors d'envoyer le registre de disponibilité à toutes les entrées, à toutes les instructions en attente. Ainsi, on sait quelles sont les instructions qui peuvent s'exécuter et celles qui ne le peuvent pas. L'implémentation est assez simple, elle ressemble beaucoup à l'implémentation d'un pipeline dynamique simple, si ce n'est que des circuits sont dupliqués. L'implémentation utilise des fenêtres d'instruction légèrement différentes de celles introduites plus haut. Elles n'utilisent notamment pas de bits de disponibilité, mais autre chose. Lorsqu'une instruction est ajoutée à la fenêtre d'instruction, le masque de disponibilité des opérandes est stocké dans la fenêtre d'instruction. A chaque cycle, le registre de disponibilité est envoyée à toutes les entrées, et est comparé avec tous les masques de disponibilité des opérandes. Si une comparaison renvoie un 1, alors l'instruction de l'entrée est une instruction candidate à l'émission. [[File:Unité d'émission dans le désordre basée sur un registre de disponibilité.png|centre|vignette|upright=2.5|Unité d'émission dans le désordre basée sur un registre de disponibilité]] L'ensemble est implémenté avec l'aide d'une '''matrice de bits''', où chaque ligne correspond à une entrée et chaque colonne à un registre. À chaque croisement entre une ligne et une colonne, on trouve un bit. Si le bit de la ligne n et de la colonne m est à 1, cela veut dire : l'instruction dans l'entrée n a besoin de lire le registre m. S’il est à 0, alors cela veut dire que l'instruction stockée dans la ligne n n'a pas besoin de la donnée dans le registre m. [[File:Planificateur à matrice de bits.jpg|centre|vignette|upright=2|Planificateur à matrice de bits.]] Lorsqu'une instruction réserve une entrée, elle initialise la ligne en fonction des registres qu'elle souhaite lire. Pour vérifier si une instruction a ses opérandes prêts, le processeur compare le registre de disponibilité à la ligne associée à l'instruction/entrée. A chaque intersection ligne-colonne, se trouve un comparateur de 1 bit, qui détecte si le registre est demandé et disponible. Les résultats de cette porte sont ensuite envoyés à une porte ET, qui fait le gros du travail. [[File:Logique de détection de la disponibilité d'une instruction.jpg|centre|vignette|upright=2|Logique de détection de la disponibilité d'une instruction.]] ==Les fenêtres d'instruction basées sur une mémoire associative== Les processeurs modernes utilisent une mémoire associative pour la fenêtre d'instruction. Les mémoires associatives ont été abordées il y a quelques chapitres, mais faisons quelques rappels. Les mémoires associatives servent à accélérer la recherche de données dans un ensemble. Or, une fenêtre d'instruction vérifie régulièrement si chaque entrée est prête. Il s'agit d'un processus de recherche d'une instruction qui respecte une condition bien précise dans la mémoire, ce qui fait que les mémoires associatives sont donc tout indiquées. Comme vous le savez, les signaux de commande d'une instruction sont propagés avec celle-ci dans le pipeline, le nom du registre de destination ne faisant pas exception. Le nom de registre est envoyé à la fenêtre d'instruction lors de l'écriture du résultat dans les registres. S'il y a correspondance, l'opérande est disponible et son bit de disponibilité est mis à 1. On peut adapter cette méthode pour tenir compte du contournement assez simplement. [[File:Détection des dépendances par propagation du registre de destination.png|centre|vignette|upright=2|Détection des dépendances par propagation du registre de destination.]] En conséquence, le circuit de détection des dépendances est constitué d'un grand nombre de comparateurs : un par champ « nom de registre » dans chaque entrée. La logique d'éveil/''wake up'' regroupe tous les comparateurs, la logique de sélection est un circuit situé en-dehors de la mémoire associative. Les entrées sont dans la mémoire associative elle-même. [[File:Gestion des bits de validité.png|centre|vignette|upright=2|Gestion des bits de validité.]] L'implémentation la plus simple est celle du schéma précédent, où on utilise une mémoire associative unique. Une version plus élaborée sépare la fenêtre d'instruction en deux parties : une mémoire qui mémorise les registres des opérandes, une autre mémoire pour le reste. La mémoire pour les registres opérandes est la mémoire associative proprement dite, c'est elle qui est associées aux comparateurs, à la logique de ''wake-up''/réveil, etc. Par contre, l'autre mémoire est une mémoire RAM simplifiée, qui mémorise les informations qui n'ont pas besoin des comparateurs. L'opcode de l'instruction est là-dedans, par exemple. La fenêtre d'instruction est donc une sorte de mémoire associative améliorée. Il se trouve que c'est aussi le cas du ROB. Et il est possible de fusionner le tampon de ré-ordonnancement avec la fenêtre d'instruction dans une structure unique. La différence avec une fenêtre d’instruction normale est que les entrées sont libérées non pas quand l'instruction est exécutée/émise, mais quand elle termine son exécution et quitte le ROB. La fenêtre d'instruction incorpore des bits dans chaque entrée, pour savoir si la µops associée a été émise et est en cours de traitement dans les ALUs. La méthode a notamment été utilisée sur les processeurs d'architecture K6 d'AMD. Le tout donnait une structure appelée le '''DRIS''' (''deferred scheduling register renaming instruction shelf''). Les processeurs PA 8000 de HP étaient aussi vraisemblabment dans ce cas, aussi. ===Les optimisations de la consommation d'énergie : la désactivation des portions inutilisées=== Le problème avec des fenêtres d'instruction de ce type est leur forte consommation énergétique, ainsi que le grand nombre de portes logiques utilisées, qui deviennent prohibitif pour des fenêtres d'instruction un peu grosses. Pour résoudre ce problème, certains ont optimisé les comparateurs. D'autres ont tenté de profiter du fait que la majorité des bits dans les entrées sont composés de zéros. Bref, les optimisations purement matérielles sont légion. Une première solution est de désactiver les entrées qui sont inutilisées, vides, sans instruction. Pour cela, on fait précéder les comparateurs par un circuit qui les connecte ou déconnecte des lignes de bit. Le circuit est commandé par le bit ''empty'' qui indique si une entrée est vide ou non. L'avantage est que la consommation d'énergie de la fenêtre d'instruction devient alors proportionnelle au nombre d'entrées non-vides, et non au nombre d'entrées total. Du moins, en apparence, les entrées non-utilisées doivent quand même être alimentées pour fonctionner, mais l'activité de comparaison disparait dans les entrées vides. Il est possible d'étendre cette technique aux entrées dont les opérandes sont prêtes. Les gains sont généralement assez bons, avec une réduction de consommation variant entre 30 et 50%, avec une implémentation très simple et très économe en circuits. Une autre solution, assez simple à mettre en place, consiste à désactiver une partie de la fenêtre d'instruction sin elle est inutilisée. Pour cela, il faut segmenter la fenêtre d'instruction avec la technique du ''wire partitionning''. Pour rappel, une fenêtre d'instruction est une mémoire associative. Et comme toute mémoire associative, elle contient des fils, les lignes de bit, qui relient les entrées/sorties à toutes les cellules mémoire. Plus une ligne de bit est longue, plus elle consomme d'énergie et plus le temps de lecture/écriture est long. L'idée est de segmenter les lignes de bits en plaçant des répéteurs qui recopient la tension d'un segment au suivant. Les répéteurs sont des tampons trois-états, ce qui permet de déconnecter les portions inutilisées de la ligne de bit. Ce faisant, la fenêtre d'instruction est découpée en segments, qui peuvent être désactivés si besoin. Si il y a peu d'instructions chargées dans la fenêtre d'instruction, les portions inutilisées sont désactivées. La technique marche d'autan mieux si les instructions sont compactées au début de la fenêtre d'instruction. [[File:Wire partitionning.png|centre|vignette|upright=2|Wire partitionning]] Tout le problème est de savoir quelles portions désactiver. La technique est assez simple si la fenêtre d'instruction est compactée, à savoir si toutes les instructions sont régulièrement regroupées au début de la mémoire CAM. Mais même avec cette optimisation, la décision de désactiver une portion de la fenêtre d'instruction n'est pas à prendre à la légère. Il ne faut pas désactiver une portion contenant des instructions pouvant être émise sous peu. La décision dépend de paramètres variés : proportion d'entrée vides, quantité d'entrées récemment activées/désactivées récemment, présences d'entrées avec un ''match'' d'opérandes récent, etc. Il est important de préciser que les techniques en question fonctionnent aussi sur les autres types de fenêtre d'instruction, qui ne sont pas basées sur des mémoires associatives. Nous allons voir celles-ci dans la suite du chapitre, mais gardez à l'esprit que ces optimisations, à savoir désactiver les entrées vides/prêts et partitionner la fenêtre d'instruction, sont des optimisations générales qui marchent avec presque tout. ===L'ajout d'une FIFO pour les instructions déjà prêtes à l'émission=== D'autres techniques permettent de réduire aussi bien le cout en circuits que la consommation d'énergie de la fenêtre d'instruction. L'idée est d'utiliser une mémoire associative quand elle est réellement nécessaire, mais d'utiliser une fenêtre d'instruction "normale" dès que possible. La méthode la plus simple tient compte du fait que certaines instructions ont déjà toutes leurs opérandes de disponibles à l'émission, mais doivent quand même être mises en attente, parce que l'ALU adéquate est occupée, parce que des dépendances WAW/WAR sont encore là, ou pour tout autre raison. Dans ce cas, elles sont mises en attente non pas dans la fenêtre d'instruction, mais dans une mémoire FIFO toute simple. L'idée est qu'au lieu d'avoir une énorme mémoire associative pour la fenêtre d'instruction, on déplace quelques entrées dans une petite FIFO annexe. Le résultat est un gain en terme d'énergie et de circuits, au prix d'une perte de performance mineure. La perte de performance en question se manifeste si aucune instruction n'a ses opérandes de prêtes à l'émission : le programme n'utilise pas la FIFO et voit alors une fenêtre d'instruction plus petite. Une amélioration de cette technique tient compte du fait que certaines instructions sont dans un cas intermédiaire. Elles ont déjà une opérande de prête lors de l'émission, mais pas l'autre. Le nombre d'opérandes varie suivant l’instruction : certaines n'ont besoin que d'un seul opérande. De plus, il arrive qu'une opération tout juste décodée ait déjà un ou plusieurs de ses opérandes de prêts. Cette constatation permet d'éviter d'utiliser des comparateurs pour les opérandes déjà prêts. Par exemple, on peut parfaitement utiliser trois fenêtres d'instruction : * une pour les instructions dont tous les opérandes sont prêts, mais qui sont quand même mises en attente, sans comparateur ; * une pour les instructions dont un seul opérande manque, qui n'utilise qu'un comparateur par entrée ; * une pour les instructions dont deux opérandes manquent à l'appel, qui utilise deux comparateurs par entrée. C'est beaucoup plus économique que d'utiliser une seule grosse fenêtre d'instruction qui contiendrait autant d'entrées que les trois précédentes réunies, avec deux comparateurs par entrée. Certains sont même allés plus loin, et ont proposé de supprimer la fenêtre d'instruction avec deux opérandes par entrée. Les instructions dont deux opérandes sont inconnus au décodage sont stockées dans la fenêtre d'instruction pour instructions avec un comparateur par entrée. Un circuit de prédiction se charge alors de prédire l'opérande manquant, cette prédiction étant vérifiée plus loin dans le pipeline. Il serait cependant étonnant qu'une telle proposition ait donné lieu à la moindre implémentation réelle. ===Les optimisations de la consommation d'énergie avancées=== D'autres chercheurs ont conservé une fenêtre d'instruction unique, avec autant de comparateurs par entrée qu'il y a d'opérandes possibles par instruction. Simplement, le processus de détection des opérandes prêts est légèrement ralenti : on ne vérifie qu'un opérande par cycle. Pour vérifier les deux opérandes d'une entrée, on doit attendre deux cycles. Enfin, certains chercheurs ont proposé des fenêtres d'instruction segmentées. Les instructions circulent à chaque cycle d'un segment vers le suivant : en conséquence, certains segments conservent les instructions les plus anciennes, un autre les instructions les plus jeunes, etc. Seul le denier segment, celui qui contient les instructions les plus vielles, peut émettre une instruction : la détection des opérandes se fait seulement dans le dernier segment, qui contient les instructions les plus anciennes. On économise ainsi beaucoup de comparateurs. Certains chercheurs ont tenté de pipeliner l'étape de sélection des opérandes, ainsi que l'étage d'arbitrage. Mais en faisant cela, il faut plusieurs cycles pour détecter qu'une instruction a ses opérandes prêts, ce qui pose problème face à de nombreuses dépendances RAW. Pour éviter de trop perdre en performances, certains chercheurs ont décidé d'utiliser des techniques pour prédire quelles seront les instructions dont les opérandes seront bientôt prêts. Si détecter qu'une instruction est prête prend n cycles, le processeur devra tenter de prédire la future disponibilité des opérandes n cycles en avance pour obtenir des performances optimales. ===Remplacer la mémoire associative par une RAM=== Une autre optimisation possible est de remplacer la fenêtre d'instruction par une mémoire RAM, dont chaque mot mémoire correspondrait à une entrée. Une telle optimisation permet en théorie de se passer des comparateurs associés à chaque entrée, mais au prix de l'ajout de circuits annexes potentiellement couteux. La première de ces techniques, la '''recherche directe par étiquette''' (direct tag search) fut créée par Weiss et son collègue Smith. Ils cherchaient à améliorer l'algorithme de Tomasulo, un algorithme qu'on expliquera dans quelques chapitres. Rappelons que chaque instruction produit un résultat, qui devra être rapatrié dans une ou plusieurs entrées de la fenêtre d'instruction. L'optimisation de la recherche directe par étiquette fonctionne dans le cas où le résultat de l'instruction n'est utilisé que par une seule entrée, et pas plusieurs. Le principe est simple : chaque champ « opérande » d'une entrée est adressable via le nom de registre de cette opérande. Pour faire le lien entre entrée et nom de registre, la recherche directe par étiquette ajoute une table de correspondances matérielle, une mémoire RAM qui mémorise les adresses des champs « opérande » des entrées. Les adresses envoyées dans cette mémoire sont les noms de registres des résultats. Lors de l'émission, la table de correspondances est mise à jour. Les numéros des champs « opérande » réservés lors de l'émission sont mémorisés dans les mots mémoire qui correspondent aux deux registres sources. Toutefois, une petite vérification est faite lors de l'émission : si il y a déjà une correspondance dans la table pour un registre source, alors une autre instruction compte lire ce registre. Pour éviter d'écraser les données de l'instruction précédente dans la table de correspondances, l'émission de l'instruction est bloquée. [[File:Recherche directe par étiquette.png|centre|vignette|upright=2|Recherche directe par étiquette.]] ==Les fenêtres d’instruction avec préplanification== Avec la '''préplanification''' (''prescheduling''), la fenêtre d’instruction est composée de mémoires FIFO dans lesquelles les instructions sont triées dans l'ordre d'émission. Il n'y a pas de logique d’émission proprement dite, celle-ci se bornant à vérifier si l'instruction située au début de la FIFO peut s’exécuter. Par contre, le préplanificateur détecte les dépendances et en déduit où insérer les instructions dans le tampon d'émission, à l'endroit le plus adéquat. [[File:Préplanification.jpg|centre|vignette|upright=2|Préplanification.]] ===L'usage de FIFO multiples=== La technique de préplanification la plus simple utilise plusieurs FIFO. Quand une instruction a une dépendance avec une autre instruction, les deux sont placées dans la même FIFO. Pour cela, le préplanificateur détecte les chaines d'instructions dépendantes, et place les instructions dans la FIFO adéquate. A chaque cycle, l'unité d'émission lit une micro-opération dans chaque FIFO et vérifie si elle peut l'émettre. Si la micro-opération n'a pas ses opérandes disponibles, ou qu'une dépendance structurelle survient, alors la FIFO est bloquée. La micro-opération attend que la dépendance soit résolue, bloquant toutes les instructions précédentes. Mais les autres FIFO ne sont pas bloquées, laissant de la marge de manœuvre. [[File:Préplanification par FIFO multiples.png|centre|vignette|upright=1.5|Préplanification par FIFO multiples.]] ===La technique du tampon trié=== La technique du '''tampon trié''' trie les instructions selon le temps d'attente avant leur exécution. Les instructions qui sont censées s’exécuter bientôt sont insérées au tout début de la FIFO, tandis que les instructions qui s’exécuteront dans un long moment sont insérées vers la fin. Là encore, l'unité d'émission lit une micro-opération dans la FIFO, et détermine si elle peut être émise. Si une dépendance survient, l'émission est retardée, et la FIFO est bloquée. [[File:Préplanification par tampon trié.png|centre|vignette|upright=1.5|Préplanification par tampon trié.]] La technique a cependant quelques problèmes assez importants. Le premier problème est que la FIFO est bloquée lorsqu'une micro-opération ne peut être émise. Le second problème est que le temps avant exécution n'est pas toujours connu, notamment pour les instructions d'accès mémoire. Et cela se répercute sur les instructions dépendantes de celles-ci. Pour résoudre ce genre de problèmes, l'usage d'un pipeline à ''replay'' est possible, et est même l'une des meilleures solution possible, malgré ses défauts. L'idée est que les lecture sont pré-planifiées en supposant qu'elles font un succès de cache L1. Si la prédiction est fausse, la lecture est ré-exécutée plusieurs cycles plus tard, en supposant qu'elle fait un succès dans le cache L2, et ainsi de suite. Elle est alors ré-insérée dans la FIFO, elle est pré-planifiée une seconde fois. Il en est de même si une micro-opération ne peut pas être émise : il suffit de la réinsérer dans la FIFO au bon endroit, en attendant que ses dépendances soient résolus. Ainsi, l'instruction fautive ne bloque pas la fenêtre d’instruction, et retente sa chance autant de fois qu'il le faut. [[File:Préplanification par fenêtre d’instruction scorebarodée.png|centre|vignette|upright=1.5|Préplanification par fenêtre d’instruction scorebarodée.]] Une autre solution utilise deux fenêtres d’instruction : une FIFO gérée par la préplanification, et une vraie fenêtre d'instruction pour les instructions dont le temps d'attente ne peut pas être déterminé. Il est possible de mettre cette dernière avant la préplanification, afin de gérer les temps d'attente des instructions d'accès mémoire. Quand le temps d'attente d'une lecture devient connu, ses instructions dépendantes sont gérées avec préplanification. [[File:Préplanification avec fenêtre d’instruction.png|centre|vignette|upright=2.5|Préplanification avec fenêtre d’instruction.]] ===Les fenêtres d'instruction avec allocation temporelle statique=== L''''allocation temporelle statique''' correspond à une technique utilisée sur les processeurs Cuzco de l'entreprise Condor. La technique en question a été présenté en 2025, mais des idées similaires ont été présentées dans la littérature académique. Elle ressemble beaucoup aux techniques de pré-planification, avec cependant quelques différences. L'idée est simple : le processeur dispose de plusieurs fenêtres d'instruction, qui mettent en attente les micro-opérations. Lors de l'étape de renommage de registres, le processeur détermine dans combien de cycles d'horloge la micro-opération sera prête pour exécution. La micro-opération est alors mise en attente durant ce nombre de cycles, dans les fenêtres d'instruction, puis est émise une fois ce nombre de cycles écoulés. Ce faisant, les fenêtres d'instruction n'ont pas besoin de détecter la disponibilité des opérandes à chaque cycle, pour chaque micro-opération en attente. Le ''timing'' de l'émission des micro-opérations est décidé à l'avance. L'implémentation exacte n'est pas connue, mais plusieurs solutions sont imaginables. Par exemple, la fenêtre d'instruction peut simplement être composée de plusieurs mémoires de petite taille, chacune contenant les micro-opérations destinées à être exécutées dans N cycles, N étant différent pour chaque mémoire. Une autre solution, plus réaliste, utilise une fenêtre d'instruction dans laquelle la micro-opération est couplée à des champs pour les opérandes, et un champ compteur. Le champ compteur est initialisé avec le nombre de cycles à attendre, et est décrémenté à chaque cycle d'horloge. Quand il atteint zéro, la micro-opération est émise. Vous remarquerez que la méthode ne marche que si toutes les micro-opérations prennent un nombre fixe de cycles d'horloge. Et autant c'est le cas pour les micro-opérations arithmétiques ou logiques, autant les accès mémoire ne rentrent pas dans ce cadre. En théorie, on ne sait pas combien de temps prendra un accès mémoire. Et cette incertitude se répercute sur les instructions dépendantes d'un accès mémoire. Pour éviter cela, le processeur réutilise un pipeline à ''replay'' tel que vu dans le chapitre précédent. L'unité de renommage de registre suppose que tout accès mémoire fait un succès de cache L1, et décide des ''timings'' d'émission sous cette hypothèse. Si une lecture subit un défaut de cache, elle est ré-exécutée, de même que toutes les instructions dépendantes. Pour cela, le registre de destination de la lecture est marqué comme invalide, grâce à un bit spécifique attaché au registre. Toute instruction qui lit une opérande invalide est elle aussi ré-executée de zéro. Pour simplifier, l'unité d'émission ressemble à une unité d'émission dans l'ordre, avec un registre de disponibilité, qu'on aurait amélioré pour aller au-delà de la simple détection des dépendances d'instruction. Pour déterminer les ''timings'' d'émission, à savoir quand émettre une micro-opération, le processeur utilise une unité d'émission à deux étages. Le premier étage est appelé le ''register scoreboard'', le second étage est appelé la ''Time Ressource Matrix''. Les deux étages communiquent entre eux, comme on va le voir, et leurs noms donnent une idée de ce qu'ils font. Le premier étage gère les dépendances de registres, le second gère les dépendances structurelles. Le premier étage est un registre de disponibilité amélioré, qui gère les dépendances de registre. Cet étage sait quand tel registre sera écrit, et donc que l'opérande écrite dedans sera disponible à partir de tel cycle d'horloge. Il le sait car l'étage suivant l'aura prévenu, mais laissons cela de côté pour le moment. Quand une micro-opération rentre dans cet étage, il vérifie les dépendances avec les registres et les micro-opérations antérieures. Vu qu'il sait quand les registres seront disponibles, il peut déterminer quand l'instruction pourra s'exécuter. Par exemple, si une micro-opération lit les deux registres R7 et R15, qui sont disponibles respectivement dans 5 et 7 cycles, le premier étage sait que la micro-opération devra attendre 7 cycles. Mais tout cela ne suffit pas à déterminer quand émettre une micro-opération. En effet, il fait aussi gérer les dépendances structurelles, ce qui est le boulot du second étage. Le second étage utilise pour cela une ''Time Ressource Matrix'', qui mémorise l'occupation de diverses "ressources", pour les 256 cycles d'horloge à venir. Les ressources en question sont les ports de lecture/écriture du banc de registre, les ALUs utilisées, si la micro-opération utilise l'unité mémoire, etc. Le second étage prend en entrée une micro-opération, détermine quelles "ressources" elle utilise, puis regarde leur disponibilité. Elle détecte alors les dépendances structurelles et détermine alors quand peut s'exécuter la micro-opération. Elle peut retarder l'émission de quelques cycles, si une dépendance structurelle est détectée. Une fois sortie du second étage, on sait quand la micro-opération va être émise, à quel cycle précisément. Et vu que la durée de l'instruction est fixe, on sait quand cette micro-opération va se terminer, quand son résultat sera disponible. Cela permet de mettre à jour la ''Time Ressource Matrix'', pour préciser que le port d'écriture sera occupé à tel moment. De plus, cette information est transmise au premier étage, qui sait alors quand est enregistré le résultat dans le registre de destination. C'est comme cela que le premier étage sait quand un registre est disponible : le second étage le prévient, quand il émet une instruction ! La ''Time Ressource Matrix''mémorise l'occupation des "ressources" pour les 256 cycles d'horloge à venir. Cependant, elle ne vérifie pas les dépendances pour les 256 cycles suivants. Quand elle reçoit une micro-opération, elle teste les dépendances structurelles pour seulement les 8 prochains cycles maximum. Si la micro-opération ne peut pas être émise pendant ces 8 cycles, le pipeline est bloqué, un ''pipeline stall'' est émis. Pour être plus précis, vu que le processeur peut décoder 8 micro-opérations en même temps, cela permet de ne consulter que 64 cycles d'horloge sur les 256. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les premiers processeurs Intel | prevText=Les premiers processeurs Intel | next=Le renommage de registres | nextText=Le renommage de registres }} </noinclude> bhpyul1kis1bpskd9n9syovpdhtyhjp 773608 773607 2026-09-29T20:05:51Z Mewtow 31375 /* Les fenêtres d’instruction : généralités */ 773608 wikitext text/x-wiki Dans les chapitres précédents, nous avons parlé des techniques dites d''''émission dans l'ordre'''. L'idée est d’exécuter une nouvelle micro-opération à chaque cycle, dans des unités de calcul séparées. Les instructions sont émises consécutivement, mais les instructions s’exécutent en parallèle dans des unités de calcul séparées. Par contre, quand l'unité d'émission ne peut pas émettre une instruction, elle bloque tout le pipeline. Les instructions qui suivent sont elles aussi bloquées, elle doivent attendre leur tour, même si elles sont en capacité de s'exécuter. Les techniques d'exécution dans le désordre que nous allons voir dans ce chapitre corrigent ce point précis. Elles sont dites à '''émission dans le désordre'''. Elles se distinguent des précédentes sur un point précis : quand l'unité d'émission bloque l'émission d'une instruction, les instructions suivantes peuvent poursuivre. L'émission des instructions peut donc se faire dans le désordre, dans le sens où une instruction peut être émise alors qu'une instruction précédente ne l'est pas encore. L'avantage de l'émission dans le désordre est qu'une instruction s'exécute dès que ses opérandes sont disponibles. Par disponible, on veut dire présent soit dans le réseau de contournement, soit dans les registres. Le processeur détecte automatiquement quand les opérandes d'une instruction sont sont disponibles, et il l’exécute à ce moment là. Dès qu'une instruction a ses opérandes disponibles, elle est émise et exécutée. C'est là la seule contrainte : les dépendances WAR, WAW et autres sont gérées par un ROB ou toute autre technique d'exception précise, seules les dépendances RAW limitent l'exécution. Mais avant de poursuivre, quelques point niveaux terminologie : * L'émission dans le désordre est un terme parlant et assez précis. Malheureusement, la terminologie la plus utilisée par d''''exécution dans le désordre'''. Et nous utiliserons ce terme dans la suite du cours, histoire de ne pas trop dévier de la nomenclature habituelle. * Nous utiliserons parfois l'abréviation OOO pour parler d'exécution dans le désordre. L'abréviation est celle de ''Out Of Order Excution''. * Nous utiliserons aussi l'abréviation ''µop'' pour parler de micro-opération, ''µops'' au pluriels pour parler de plusieurs micro-opérations, ou des micro-opérations en général. L'exécution dans le désordre ne gére en effet que des µops, elle se situe après l'étape de décodage. Mais avant de poursuivre, précisons une chose importante : l'exécution dans le désordre traite les accès mémoire à part. La majorité des processeurs OOO assez anciens exécutent les accès mémoire dans l'ordre, seules les µops entières/flottantes/branchements sont exécutées dans le désordre. Les processeurs datant d'après les années 2010 sont capable d'exécuter les accès mémoire dans le désordre, mais l'implémentation en question est assez particulière. Un chapitre entier sera dédié à l'exécution dans le désordre des µops mémoire. Nous allons volontairement mettre de côté la gestion des accès mémoire dans ce chapitre. ==Les fenêtres d’instruction : généralités== Pour décrire comment est implémentée l'émission dans le désordre, il faut commencer par parler des processeurs sans. Les processeurs sans exécution dans le désordre ont une unité d'émission qui bloque tout le pipeline dès qu'une µop ne peut pas être émise. Pour limiter l'impact de ce blocage, quelques rares processeurs incorporent une '''file de micro-opération''', une mémoire FIFO qui met en attente les µops. Vu que c'est une mémoire FIFO, les µops sont émises dans l'ordre, à savoir l'ordre d'ajout, dans l'ordre de décodage. Le schéma ci-dessous illustre une telle file d'attente couplée à un ''scoreboard''. Sur le principe, l'exécution dans le désordre améliore la file de µops sur un point : ce n'est plus une mémoire FIFO. Les µops sont insérées dans l'ordre, mais peuvent sortir dans le désordre (être émises dans le désordre). La file de µops devient alors une '''fenêtre d'instruction''', terme traduit directement de l'anglais ''instruction Window''. Terme assez trompeur, car elles mettent en attente des µops, pas des instructions. Elles peuvent émettre des µops dans le désordre, ce qui fait que si une µop bloque le pipeline, les µops suivantes peuvent être émises. [[File:Différence file µops et fenêtres instruction.png|centre|vignette|upright=2|Différence file µops et fenêtres instruction]] Si je commence le paragraphe précédent par "sur le principe", c'est car certaines techniques d'OOO utilisent des files de µops normales. Il est par exemple possible d'utiliser une file de µops avec une fenêtre d'instruction, plusieurs files de µops, plusieurs fenêtres d'instructions avec une file de µops annexe, etc. Dasn les grandes lignes, il existe dans les grandes lignes 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! File de µops améliorée |- ! Une seule "file de µops" | ''Scoreboard'' | Fenêtre d'instruction centralisée |- ! Plusieurs "file de µops" | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | Fenêtre d'instruction décentralisée |} ===La fenêtre d'instruction centralisée=== L'implémentation la plus simple de l'OOO utilise une unique fenêtre d'instruction, appelée une '''fenêtre d'instruction centralisée'''. Les µops décodées sont accumulées dans la fenêtre d'instruction, où elles attendent que leurs opérandes soient disponibles. La fenêtre d'instruction sert donc de file d'attente. Mais elle contient aussi une unité d'émission, qui détecte quelles µops sont prêtes à être émises. L'unité d'émission et la fenêtre d'instruction sont fusionnées ensemble, elles forment un seul circuit. Mais nous allons dire qu'elles sont conceptuellement séparées pour le moment. A chaque cycle, l'unité d'émission consulte la fenêtre d'instruction pour voir quelles µops peuvent s'exécuter, lesquelles ont leur opérandes de disponibles. La fenêtre d'instruction doit spécialement être conçue pour, c'est une sorte de mémoire associative très complexe, comme on le verra dans ce qui suit. [[File:OOO Issue.png|centre|vignette|upright=2.5|Exécution dans le désordre avec une fenêtre d'instruction]] Une fois qu'une µop sort du décodeur d'instructions, elle est ajoutée en parallèle dans la fenêtre d'instruction et le ROB. La raison est que les µops quittent la fenêtre d'instruction dans le désordre, et qu'elles doivent être remises en ordre par la suite. Le ROB s'occupe de cette remise en ordre, mais il a besoin de savoir dans quel ordre les µops sont censées être, et cet ordre est celui du décodage. Aussi, pour remplir le ROB, la seule opportunité est en sortie de l'unité de décodage. Dans le cas où une instruction est décodée en plusieurs micro-opérations, elles sont toutes insérées en même temps dans la fenêtre d'instruction et le ROB, en tenant compte de leur ordre. [[File:Fenêtre d'instruction.png|centre|vignette|upright=2|Fenêtre d'instruction.]] Les micro-opérations mémoire sont à part des autres, pour diverses raisons. Une de ces raisons est que les dépendances de données sont classées en deux types : les dépendances de registre et les dépendances d'adresse. Et les deux sont fondamentalement différentes. Autant on peut détecter les dépendances de registre lors de l'émission, autant c'est plus compliqué avec les dépendances d'adresse. De plus, rappelons que si les lectures peuvent s'exécuter dans le désordre, les écritures doivent s'exécuter dans l'ordre, ou du moins en donner l'illusion. Pour cela, le processeur remet les écritures dans l'ordre avec une sorte de mini-ROB intégré à l'unité mémoire, appelée la file d'écriture. Elle complémente le ROB, qui lui ne gère que les écritures dans les registres, mais les deux collaborent. La file d'écriture envoie une écriture à la mémoire RAM quand le ROB lui dit que c'est bon, les instructions précédentes sont terminées ''dans l'ordre du programme''. Les processeurs modernes ajoutent des techniques d'exécution dans le désordre des accès mémoire, mais nous les verrons dans un chapitre dédié. Elles permettent d'utiliser une fenêtre d'instruction unique, qui mémorise aussi les µops mémoire. Si elles sont mises en place, l'unité mémoire n'a pas besoin de file de µops séparée. L'idée est que les dépendances de registre sont traitées par la fenêtre d'instruction, mais que l'unité mémoire gére les dépendances d'adresse. Les dépendances d'adresse sont gérées par des techniques de ''désambiguation mémoire'', qui auront droit à un chapitre dédié. [[File:Processeur avec exécution dans le désodre des accès mémoire.png|centre|vignette|upright=2|Processeur avec exécution dans le désodre des accès mémoire]] Les processeurs assez anciens n'autorisaient pas d'exécution dans le désordre des accès mémoire. Concrétement, les accs mémoire devaient se faire dans l'ordre, mais les autres µops pouvaient être exécutées dans le désordre. Il s'agit donc d'un ordre entre µops mémoire, pas entre µops mémoire et autres µops. Les µops entières et flottantes pouvaient être exécutées avant une µops mémoire qui est avant elle dans l'ordre du programme, ce n'est pas un problème. Pour garantir l'ordre desd µops mémoire, l'unité mémoire est précédée par une file de micro-opérations séparée, pour forcer l'exécution dans l'ordre des accès mémoire. De plus, les µops mémoire ne peuvent pas utiliser la fenêtre d'instruction. Dit autrement, la fenêtre d'instruction ne mémorise pas de µops mémoire. Après le décodage, les µops sont réparties soit dans la file de µops mémoire, soit dans la fenêtre d'instruction. Le décodeur classe les µops suivant que ce sont des µops mémoire ou non, et les envoient à la bonne destination. Dans ce chapitre, on supposera que c'est cette solution qui est utilisée. [[File:Processeur avec émission dans l'ordre des accès mémoire.png|centre|vignette|upright=2|Processeur avec émission dans l'ordre des accès mémoire]] La solution précédente revient à scinder la fenêtre d'instruction en deux : une file de µops pour les µops mémoire, une fenêtre d'instruction pour les autres µops. Et cette scission peut aller plus loin, à savoir qu'on peut scinder une fenêtre d'instruction encore et encore. Ce qui nous amène à la section suivante. ===Les fenêtres d'instruction décentralisées=== Nous venons de voir qu'il est possible de scinder la fenêtre d'instruction en une fenêtre d'instruction pour les µops mémoire (simplifiée en une file de µops classique), et une autre pour les autres µops. Sachez qu'il est possible d'aller plus loin, par exemple en séparant la fenêtre d'instruction en une fenêtre spécialisée dans les µops flottantes et une autre pour les µops entières. Et ce n'est là qu'un exemple parmi de nombreuses autres possibilités. Pour faire la différence avec une fenêtre d'instruction unique, nous allons parler de fenêtre d'instruction centralisée s'il n'y en a qu'une, de '''fenêtre d'instruction décentralisée''' s'il y en a plusieurs. Il est possible d'associer chaque fenêtre d'instruction à un type précis de µops. Par exemple, avec une fenêtre d'instruction pour les µops de calcul entières, une autre pour les µops flottantes, une autre pour les µops mémoire. Il s'agit d'un choix simple et efficace, mais quelques processeurs font autrement, pour répondre à des contraintes très diverses. [[File:Processeur avec des fenêtres d'instruction décentralisées.png|centre|vignette|upright=2|Processeur avec des fenêtres d'instruction décentralisées]] Reste à scinder la fenêtre d'instruction pour trier les µops suivant leur type. Si le processeur exécute les accès mémoire dans l'ordre, la méthode la plus simple utilise une fenêtre d'instruction pour les opérations flottantes et une autre pour les autres µops (µops entières et parfois mémoire avec). L'avantage est que cela simplifie grandement le processeur. Les flottants sont gérés à part des entiers. Ils ont leurs propres registres, des FPU séparées des ALU entières, bref : la séparation est complète. Utiliser une fenêtre d'instruction séparée va dans ce sens. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Il est possible de faire pareil sur les processeurs avec exécution dans le désordre des accès mémoire. Par exemple : les processeurs Intel de microarchitecture Skylake utilisent une fenêtre d'instruction pour les opérations entières/flottantes, et une fenêtre d'instruction séparée pour les µops mémoire. Un avantage est que les deux fenêtres d'instructions sont plus spécialisées, ce qui entraine des économies de circuit. Les opérations entières/flottantes ont besoin de deux registres pour les opérandes et d'un autre résultat, alors que les µops mémoire n'ont besoin que de deux registres maximum. En utilisant une fenêtre d'instruction unique, chaque entrée doit mémoriser l'opcode et trois registres, dont un est inutilisé pour les µops mémoire et les branchements. En utilisant des fenêtres d’instructions séparées, celle pour les µops entières/flottantes a trois registres par entrée, contre seulement deux registres par entrée pour celle des µops mémoire. Un cas extrême est celui où chaque ALU/FPU a sa propre fenêtre d'instruction. Nous parlerons alors de '''fenêtres d'instruction totalement décentralisées'''. Par exemple, il y a une fenêtre d'instruction pour l'ALU entière, une autre pour le multiplieur entier, une autre pour le ''barrel shifter'', une autre pour l'unité mémoire, une autre pour l'unitéé de branchements, une autre pour l'additionneur flottant, une dernière pour le multiplier flottant, etc. Un exemple historique est celui de la FPU de l'IBM 360 modèle 90. Elle disposait d'un additionneur flottant, d'un multiplieur flottant, et d'une unité mémoire pour les lectures/écritures flottantes. Les trois unités avaient leur propre fenêtre d'instruction. Les processeurs AMD utilisent beaucoup cette technique, contrairement à Intel qui préfère utiliser des fenêtres centralisées sur les anciens processeurs, deux ou trois fenêtres sur les processeurs récents (2020 et plus). Les processeurs AMD utilisaient précisément une fenêtre d'instruction par ALU entière, alors que les FPUs partagent une fenêtre d’instructions flottantes unique. Mais nous verrons cela en détail dans le chapitre sur les processeurs superscalaires x86. Un point important est qu'avec des fenêtres d'instruction décentralisées, l'émission est découpée en deux étages. La première étape envoie une µops vers la fenêtre d'instruction adéquate, la seconde émet la µops depuis la fenêtre d'instruction quand ses opérandes sont prêtes. La première est l'étage de '''''dispatch''''' qui envoie l'instruction dans la fenêtre d’instruction adéquate, selon que c'est une instruction flottante, entière, autre. La seconde est l'étage de '''''scheduling''''', qui gère la disponibilité des opérandes et des unités de calcul. La µop émise est ajoutée au tampon de réordonnancement, s'il existe, lors de l'étape de ''dispatch''. ===L'usage de plusieurs files d'instruction=== Une dernière méthode d'OOO utilise plusieurs files de micro-opération. L'idée est qu'une fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement une file de micro-opération pour les opérations entières, une autre pour les opérations flottantes, une autre pour les accès mémoire. D'autres processeurs utilisent une file pour les accès mémoire et une autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. La présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que la technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si une dépendance bloque une FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans une autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer la disponibilité des registres. Quand un registre est lu ou écrit par une instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. La logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : une pour les instructions d'accès mémoire et une autre pour les autres instructions. Si jamais une instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de la lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'une est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est la file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. ===Avantages et inconvénients de chaque implémentation=== Pour résumer, on a le choix entre une grosse fenêtre d'instruction généraliste et plusieurs fenêtres spécialisées. Le choix entre les deux est un compromis entre économie de circuits et flexibilité. Avec une fenêtre décentralisée, il arrive qu'une fenêtre d'instruction soit remplie, alors que les autres sont sous-utilisées, voire vides. Pour comprendre pourquoi, comparons une fenêtre d'instruction unique, avec une fenêtre décentralisée séparant µops entières et flottantes. La fenêtre centralisée dispose de 64 entrées, la décentralisée a 32 entrées pour chaque fenêtre d'instruction. La fenêtre décentralisée peut mémoriser au maximum 32 µops entières et 32 *ops flottantes. Par contre, la fenêtre centralisée peut mémoriser 64 µops tout court. Si le programme exécuté n'utilise pas de nombres flottants, la différence devient flagrante. La fenêtre décentralisée sera limitée ) 32 µops, alors que la centralisée pourra mémoriser le double. Les performances seront donc meilleurs avec la fenêtre centralisée. Et au-delà de ça, la fenêtre décentralisée de l'exemple est utilisée de manière optimale si la moitié des µops sont des µops entières, et l'autre moitié des µops flottantes. Alors que la fenêtre centralisée se moque de la répartition entre µops entières et flottantes. Une subtilité est que le cout en transistors d'une fenêtre d'instruction n'est pas proportionnel au nombre de µops qu'elle peut mémoriser. Par exemple, si je compare une fenêtre d'instruction de 32 entrées (32 µops max), elle n'utilise pas deux fois plus transistors qu'une fenêtre de 16 entrées. Le cout en circuit n'est pas deux fois plus élevé, mais est approximativement 4 fois plus élevé. Le cout est presque quadratique, à savoir qu'il est proportionnel au carré du nombre d'entrées. Et il en est de même avec la performance, pour des raisons qu'on expliquera plus bas. Les fenêtres décentralisées utilisent plusieurs fenêtres d'instruction de "petite taille", donc plus rapides, économes en circuits et économes en énergie. Le compromis n'est donc pas entre une fenêtre centralisée à 64 entrées versus deux fenêtres de 32 entrées. Le compromis en pratique est entre une fenêtre centralisée de 64 entrées versus 3 fenêtres de 32 entrées. Un exemple pratique est celui de la microarchitecture ''Skylake'' d'Intel. Intel est passé d'une fenêtre centralisée pre-''Skylake'' à deux fenêtres décentralisées sur ''Skylake'',. Le nombre d'entrée était globalement le même entre les deux, même si l'évolution de la finesse de gravure entre les deux biaise un peu les résultats. Un avantage des fenêtres décentralisées est qu'il est possible de démarrer l'exécution de plusieurs µops simultanément : une µops par fenêtre d'instruction. Le fait est que deux fenêtres d'instructions différentes émettent leurs µops sans se synchroniser avec les autres. Deux fenêtres d'instruction peuvent donc émettre chacune une µops, ce qui fait deux µops émises lors du même cycle. Cela permet d'exécuter en même temps deux ou trois instructions 1-cycle, comme des additions, soustractions, décalages, etc. Il devient par exemple possible d'émettre une µop entière en même temps qu'une µop flottante, si les µops entières ont une fenêtre séparée de celle des µops flottantes. Il est maintenant temps de voir en quoi sont faites les fenêtres d’instruction, qu'elles soient centralisées ou décentralisées. Nous allons aussi voir quelle est la logique d'émission associée. ==L'implémentation d'une fenêtre d'instruction : généralités== Une fenêtre d'instruction est une mémoire qui mémorise des micro-opérations. Elle est cependant plus complexe qu'une mémoire RAM ou qu'une FIFO et ressemble un petit peu à une mémoire cache. Elle dispose d'un port d'écriture et d'un port de lecture, au minimum. Le port d'écriture permet à l'unité de décodage d'insérer une micro-opération dedans, d'ajouter la micro-opération qui vient d'être décodée. Si une instruction machine est décodée en plusieurs micro-opération, deux possibilités. La première est de les insérer un par un, ce qui fait qu'on peut se contenter d'un seul port d'écriture. L'autre possibilité est de les ajouter en même temps, ce qui demande plusieurs ports d'écriture. Le port de lecture sert à émettre une instruction. On part du principe que la fenêtre d'instruction ne peut émettre qu'une seule instruction à la fois, car les processeurs que nous avons vu précédemment sont de ce type. Mais nous verrons dans quelques chapitre qu'il existe des processeurs dits superscalaires, qui sont capables d'émettre plusieurs instructions par cycle. Dans ce cas, la fenêtre d'instruction a un seul port de lecture. Un processeur superscalaire, quant à lui, doit avoir un port de lecture par unité de calcul, ce qui fait beaucoup plus. Les fenêtres d'instruction sont composées d''''entrées''', des mots mémoire qui stockent une instruction. Une instruction réserve une entrée après son décodage et la libère dès qu'elle est envoyée aux unités de calcul. Une entrée contient l'opcode (les signaux de commande à envoyer à l'ALU), le registre de destination du résultat, les registres de chaque opérande, et éventuellement des signaux de commande en plus. De plus, chaque opérande est couplée à un bit de disponibilité, qui indique si elle est disponible. Quand un opérande est écrit dans les registres, le bit de présence correspondant est mis à jour. Enfin, chaque entrée possède un bit ''empty'' qui indique si elle est vide, cette information étant utile pour réserver des entrées. [[File:Entrée d'une station de réservation - sans les tags.png|centre|vignette|upright=3|Entrée d'une fenêtre d'instruction]] ===Les stations de réservation=== Les '''stations de réservation''' sont des fenêtres d'instruction particulières, qui sont capables de mémoriser les opérandes des instructions. Les entrées des stations de réservation sont identiques à celle des autres fenêtres d'instruction, si ce n'est que les opérandes de l'instruction sont enregistrées directement dans des champs séparés. Il y a deux champs, un par opérande, pour stocker l'opérande elle-même, lue depuis les registres ou obtenue via le réseau de contournement. Notons que les champs pour les opérandes viennent en plus des champs pour les noms de registres, encore que les deux peuvent être fusionnés si on veut optimiser le tout. [[File:Entrée d'une station de réservation.png|centre|vignette|upright=3|Entrée d'une station de réservation.]] Précisons que la terminologie n'est pas très fiable. Les termes "fenêtre d'instruction" et "station de réservation" ne regroupent pas du tout la même chose d'un papier de recherche à l'autre, d'un bouquin à l'autre, d'un chercheur à l'autre, d'un ingénieur à l'autre, d'un professeur à l'autre. Le terme initial vient pourtant de l'article original sur l'algorithme de Tomasulo, où il désignait une fenêtre d'instruction associée à une unité de calcul précise. Mais le terme a ensuite été réutilisé, ce qui fait que certains processeurs avec plusieurs unités de calcul sont décrit comme ayant une unique station de réservation. En bref : c'est le bazar ! Mais nous en reparlerons dans le chapitre sur le renommage de registres, car c'est la place idéale pour les aborder. Toujours est-il que j'ai fait le choix de confondre les concepts de fenêtre d'instruction et de station de réservation avec les concepts de '''lecture avant émission''' et de '''lecture après émission'''. La différence entre les deux est que les registres sont lus après émission avec une fenêtre d'instruction, avant avec des stations de réservation. Dans le cas "avant émission", les opérandes sont mémorisées dans la station de réservation. Et cette différence a une influence sur le pipeline du processeur, le banc de registres et tout ce qui s'en suit. Un désavantage de la lecture avant émission est qu'il faut stocker les opérandes après lecture, ici dans les stations de réservation. Mais un avantage est que le banc de registre a besoin de moins de ports de lecture, car une bonne partie des opérandes sont fournies par le système de contournement. Nous verrons cela dans le détail dans le chapitre sur les processeurs superscalaires. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Lecture après émission.]] [[File:Read Before Issue.png|centre|vignette|upright=2.5|Lecture avant émission.]] ===La logique d'éveil et de sélection=== Dans le cas qui va suivre, on suppose que le processeur ne peut émettre qu'une instruction à la fois. Chaque cycle, une instruction est sélectionnée et est envoyée dans le chemin de données, soit à une ALU, soit à une unité d'accès mémoire. La sélection d'une instruction est effectuée par l'unité d'émission, qui est aussi appelée le '''''scheduler'''''. Elle gère la disponibilité des opérandes et la disponibilité des unités de calcul adéquate. Le choix de l'instruction émise doit être le plus pertinent possible, pour des raisons de performances. Pour le premier point, l'unité d'émission détermine quelles instructions sont candidates pour l'émission. Les ''instructions candidates'' sont celles dont tous les opérandes sont prêts. Le processeur contient un circuit qui détecte les instructions candidates : la '''logique d’éveil''' (''wake-up logic''). Une fois que la logique d'éveil a fait son travail, une instruction est choisie pour s’exécuter en fonction de la disponibilité des unités de calcul adéquates. Ce rôle est dévolu à un circuit qu'on appelle la '''logique de sélection''', ou ''select logic''. [[File:Fonctionnement complet de la logique d’émission.jpg|centre|vignette|upright=1.5|Fonctionnement complet de la logique d’émission.]] La logique de sélection doit gérer le fait que les unités de calcul du processeur ne sont pas toutes identiques. Déjà, un processeur a généralement des unités séparées pour les instructions entières et flottantes, des unités spécialisées dans les accès mémoire, parfois des unités spécialisées pour les branchements. Une instruction doit être attribuée à la bonne unité de calcul, on ne doit pas envoyer une instruction entière dans une unité de calcul flottante. De plus, parmi les unités de calcul entières, toutes ne sont pas identiques. Par exemple, il est fréquent d'avoir plusieurs unités de calcul spécialisées dans les opérations simples (additions, soustractions, opérations logiques) avec une unité pour les multiplications/divisions séparées, parfois une unité spécialisée pour les décalages/rotations, etc. Là encore, allouer la bonne instruction à la bonne ALU est complexe. Plus les unités de calcul sont hétérogènes, plus la logique de sélection est compliquée. Les logiques d'éveil comme de sélection sont assez complexes. Comme on le verra plus bas, la logique de sélection la plus simple, qui gère une seule unité de calcul, est basée sur un encodeur à priorité couplé à d'autres circuits. Et pour gérer plusieurs ALUs, il faut mettre des encodeurs en cascade. Le résultat est que même en prenant une logique de sélection simple, elle sera assez lente et gourmande en circuits. Aussi, la logique de sélection met souvent un cycle d'horloge entier pour faire son travail, elle a son propre étage de pipeline attribué. La logique d'éveil est dans le même cas, ce qui fait qu'émettre une micro-opération demande deux cycles d'horloge. Le défaut est que cela rajoute des cycles d'horloges entre la fenêtre d'instruction et l'ALU, ce qui complique la gestion du pipeline. Ces cycles de retard sont à prendre en compte au moment d'émettre les instructions, les ''scheduler'' doit en tenir compte pour des performances optimales. Sans tenir compte de ces cycles de retard, les instructions arrivent en retard de quelques cycles à l'ALU, cycles de retard durant lesquels l'ALU n'a pas fait de calcul et a été sous-utilisée, sans compter que le système de contournement n'est pas utilisé au mieux. Et le problème est encore plus important sur les processeur avec des stations de réservation, qui utilisent la "lecture après émission" : cela rajoute un cycle d'horloge en plus, un temps de retard en plus. ===La logique d'éveil : l'émission anticipée=== La logique d'éveil doit tenir compte du fait qu'il y a plusieurs étages entre l'émission et l'exécution sur une unité de calcul. Par exemple, un processeur a souvent entre un et à cinq étages entre la file d'attente et les unités de calcul. Il faut lire les registres, gérer le contournement, et cela peut prendre quelques cycles d'horloge. Sur le Pentium 4, on trouve 6 étages entre la fenêtre d’instruction et l'entrée de l'ALU. Si les micro-opérations sont émises quand les opérandes sont disponibles, il y aura un délai de quelques cycles avant qu'elles atteignent l'ALU. Alors qu'idéalement, on souhaiterait que la micro-opération atteigne l'ALU dès que ses opérandes sont disponibles, pour profiter des techniques de contournement. Pour cela, la logique d'éveil émet les instructions quelques cycles en avance pour qu'elles arrivent au bon moment. Il s'agit d'une technique d''''émission anticipée''', dont nous avions parlé dans le chapitre sur le contournement. : Il faut noter que le problème se pose plus avec des fenêtres d'instruction qu'avec des stations de réservation. Les premières ont un étage en plus entre émission et ALU, vu qu'il faut lire des registres après l'émission. L'émission anticipée demande d'émettre un signal d'éveil en avance de quelques cycles, pile au bon moment. Par exemples, si on a deux étages entre l'ALU et l'unité d'émission, le signal de réveil sera généré deux cycles avant que le résultat soit effectivement calculé. L'implémentation varie, mais deux solutions sont possibles. La première est de générer le signal d'éveil dans l'ALU, ce qui n'a de sens que pour les opérations comme les multiplications ou les divisions, qui prennent plusieurs cycles. Une autre technique génère le signal de réveil dans une structure centralisée, spécialisée dans la génération des signaux d'éveil. L'unité de composée d'un registre à décalage par registre. Imaginons qu'une instruction est émise, que cette instruction mette N cycles à s'exécuter, et qu'elle écrive dans un registre de destination. L'unité sélectionne alors le registre à décalage associé au registre de destination, et met le bit numéro N à 1. Le registre décalé d'un cran à chaque cycle. Quand le bit sortant est un 1, alors le signal de validité pour l'opérande est généré. L'émission anticipée marche bien si l'instruction a une durée fixe, connue à l'avance. Et autant c'est le cas pour les instructions arithmétiques et logiques, autant ce n'est pas le cas pour les accès mémoire. Les accès mémoire ont une latence variable : quelques cycles pour un succès de cache, plusieurs dizaines de cycles pour un défaut de cache L1, pas loin de la centaine pour un défaut de cache L2, etc. Et cela pose des problèmes pour l'émission anticipée. L'émission en avance pour les accès mémoire est purement spéculative : le processeur émet des instructions en supposant que la lecture entrainera un succès de cache, quitte à annuler l'instruction en cas de défaut de cache. Mais faire ainsi demande non seulement d'annuler les instructions émises en avance, mais aussi de ne pas retirer les instructions émises en avance de la fenêtre d'instruction. Elles sont émises, mais une copie de sauvegarde est conservée dans la fenêtre d'instruction. Si le processeur détecte un défaut de cache, il peut alors ré-exécuter l'instruction. S'il détecte un succès de cache, les instructions lecture-dépendante sont retirées de la fenêtre d'instruction, la copie de sauvegarde est devenue inutile et est donc jetée. ===La logique de sélection : âge ou position ?=== La logique de sélection est primordiale pour de bonnes performances. Il existe deux méthodes principales pour sélectionner l'instruction à exécuter. La première est la plus simple : elle se base sur lé numéro de l'entrée. En effet, une fenêtre d'instruction est avant tout une sorte de mémoire, un mix entre mémoire associative, mémoire RAM, et FIFO. Et chaque entrée a un numéro, une adresse mémoire. Nous parlerons de numéro dans ce qui suit, car ce sera plus simple, le terme d'adresse mémoire étant peut-être un peu exagéré dans le contexte des fenêtres d'instruction. Toujours est-il que la fenêtre d'instruction est adressable dans le sens où on peut lui envoyer le numéro de l'entrée voulue, et la fenêtre d’instruction renvoie le contenu de l'entrée sur son port de lecture. Et c'est ce que fait la logique de sélection : elle génère le numéro de l'entrée à lire. Le numéro est alors envoyé sur l'entrée d'adresse de la fenêtre d’instruction, et elle fournit la micro-opération associée sur son port de lecture, son '''port d'émission'''. La première méthode de sélection, donc. Elle est basée sur sur le numéro de l'entrée. Si plusieurs entrées sont éveillées, la logique de sélection prend celle avec le plus petit numéro. Elle porte le nom de '''sélection par position''', sous-entendu position dans la fenêtre d'instruction. Vous l'avez peut-être deviné, mais la logique de sélection est alors un encodeur à priorité. Le circuit de sélection ne se résume donc pas seulement à un encodeur à priorité, mais c'est le circuit central. L'avantage d'une telle méthode de sélection est qu'elle est simple à implémenter : un encodeur à priorité est un circuit connu, facile à implémenter. Mais on remarque un défaut : un encodeur est un circuit assez rapide, mais qui utilise beaucoup de transistors, beaucoup de portes logiques, surtout si on veut qu'il soit rapide. Ce qui explique que la logique de sélection ait son propre étage de pipeline rien que pour elle. La seconde méthode s'appelle la '''sélection par âge''', au nom assez transparent. L'idée est de privilégier l'émission de l'instruction la plus ancienne. Elle demande que la fenêtre d'instruction trie les micro-opérations par ordre d'insertion dans la fenêtre d'instruction, ce qui en fait une pseudo-FIFO. Le tri est partiel, car les instructions peuvent sortir de la fenêtre d’instruction à tout moment. Compacter la fenêtre d'instruction, à savoir regrouper toutes les entrées valides est une idée, mais elle est compliquée à implémenter. Aussi, elles préfèrent encoder des informations sur l'ordre d'émission dans chaque entrée. L'encodeur à priorité doit alors travailler non pas sur des nombres entiers liés à l'ordre d'insertion dans la pseudo-FIFO. Elle est encore plus gourmande en circuits que la méthode précédente. Les processeurs haute performance utilisent souvent des méthodes hybrides. Par exemple, les processeurs AMD de microarchitecture Bulldozer utilisaient une méthode intermédiaire. Ils utilisaient une fenêtre d'instruction couplée à un encodeur à priorité pour la sélection par position, mais complémentaient le tout avec une unité qui mémorisait l'instruction la plus ancienne dans la fenêtre d’instruction. Le mécanisme de sélection par âge était utilisé en priorité. Mais si l'instruction la plus ancienne n'était pas prête, le processeur basculait sur le mécanisme de sélection par position. ===La compaction des fenêtres d'instruction=== À chaque cycle, les instructions décodées sont ajoutées dans la fenêtre d'instruction, dans des entrées vides. Vu que les instructions quittent celle-ci dans le désordre, ces vides sont dispersés dans la fenêtre d'instruction, ce qui pose problème pour déterminer où placer les nouvelles instructions. La solution la plus triviale consiste à conserver une liste des vides, mise à jour à chaque insertion ou émission d'instruction. Une autre solution consiste à éliminer les vides en compactant la fenêtre d'instruction à chaque cycle d'horloge. Des circuits se chargent de détecter les vides et de regrouper les instructions en un unique bloc. Il faut signaler que certaines processeurs arrivent à se passer de cette étape de compactage, mais au prix de fenêtres d'instruction nettement plus complexes. Autre problème : quand il faut choisir quelle instruction émettre, il y a toujours plusieurs candidats. Si on choisit mal, des instructions restent en attente trop longtemps parce que d'autres instructions plus jeunes leur passent devant. Pour éviter cela, les instructions les plus vielles, les plus anciennes, sont prioritaires. Pour cela, on peut utiliser une FIFO un peu spéciale pour la fenêtre d'instruction. Si les ajouts d'instruction se font dans l'ordre, les instructions ne quittent pas forcément la fenêtre d'instruction dans l'ordre imposé par une FIFO : les instructions restent triées dans leur ordre d'ajout, même s'il y a des vides entre elles. Dans ces condition, il est préférable que le compactage conserve l'ordre FIFO des instructions. Dans ces conditions, l'instruction la plus ancienne est celle qui est située à l'adresse la plus faible : le circuit de sélection peut donc être fabriqué avec des encodeurs, et est relativement simple. ==Les fenêtres d'instruction basées sur une matrice de dépendances== L'implémentation la plus simple étend le fonctionnement d'un pipeline dynamique usuel. Rappelez-vous le chapitre sur les pipeline dynamiques. Nous avions vu que de tels pipelines émettaient une instruction par cycle, quitte à émettre des bulles de pipeline en cas de dépendance bloquante. Et il est possible d'améliorer leur unité d'émission pour qu'elle soit compatible avec l'exécution dans le désordre. ===Rappels sur le registre de réservation/disponibilité=== L'émission d'une instruction est gouvernée par un ''registre de réservation'' qui indique quels registres sont réservés par une instruction, et ceux qui sont libres. Un registre réservé est un registre qui sera écrit par une instruction en cours d'exécution, mais qui n'a pas encore écrit son résultat. Les instructions candidates doivent avoir leurs opérandes dans des registres libres. Sinon, c'est signe que leurs opérandes sont réservées en écriture, donc pas encore écrites, donc pas disponibles. Si une instruction candidate veut lire ce registre, c'est signe qu'il y a une dépendance RAW : elle veut lire un registre réservé, qui est destiné à être écrit par une instruction en vol. Si elle veut écrire, c'est signe qu'elle veut écrire dans un registre où une autre instruction veut écrire : c'est une dépendance WAW. Dans les deux cas, l'instruction n'est pas émise. Le registre de réservation encode les registres réservés comme suit : chaque bit est associé à un registre. Le bit numéro 0 est associé au registre numéro 0, le bit numéro 1 au registre numéro 1, etc. Là, En clair, les numéros de registres réservés sont encodés en représentation non pas binaire, mais en représentation ''one-hot'' (vue au premier chapitre). {|class="wikitable" |+ Registre de réservation |- ! Registre 7 !! Registre 6 !! Registre 5 !! Registre 4 !! Registre 3 !! Registre 2 !! Registre 1 !! Registre 0 |- | 0 || 0 || 1 || 0 || 0 || 1 || 0 || 0 |} Avant d'émettre une instruction, l'unité d'émission extrait les registres opérande/destination et les convertis dans la même représentation que le registre de réservation, à savoir en représentation ''one-hot''. Le circuit de traduction binaire vers ''one-hot'' est, pour rappel, un simple décodeur. Puis, on fait un OU logique entre les sorties des décodeurs. Le résultat est un masque qui indique quels registres sont lus par l'instruction, encodé en représentation ''one-hot''. Appelons-le le '''masque d'opérandes'''. Le masque est alors comparé au registre de réservation pour vérifier si l'instruction peut être émise. [[File:Unité d'émission simple, dans l'ordre.png|centre|vignette|upright=2|Unité d'émission simple, dans l'ordre]] Si l'émission est autorisée, le registres de réservation est là aussi mis à jour. Le registre de réservation est aussi mis à jour dès qu'une instruction enregistre son résultat dans les registres, ou alors dès qu'il est disponible pour le contournement. Le bit associé au registre repasse alors à 0 (ou à 1). Sans contournement, la mise à jour se fait alors à la toute fin de l'instruction, quand elle se termine, lors de la dernière étape d'enregistrement, à la fin de son pipeline. Avec, elle se fait quand l'instruction quitte l'unité de calcul. ===L'extension à l'exécution dans le désordre : l'éveil par matrice de bits=== La différence entre un pipeline dynamique et l'exécution dans le désordre est que l'on passe d'une instruction à émettre à plusieurs. Plusieurs instructions sont mises en attente dans une fenêtre d’instruction, et y attendent leur tour. L'idée est alors d'envoyer le registre de disponibilité à toutes les entrées, à toutes les instructions en attente. Ainsi, on sait quelles sont les instructions qui peuvent s'exécuter et celles qui ne le peuvent pas. L'implémentation est assez simple, elle ressemble beaucoup à l'implémentation d'un pipeline dynamique simple, si ce n'est que des circuits sont dupliqués. L'implémentation utilise des fenêtres d'instruction légèrement différentes de celles introduites plus haut. Elles n'utilisent notamment pas de bits de disponibilité, mais autre chose. Lorsqu'une instruction est ajoutée à la fenêtre d'instruction, le masque de disponibilité des opérandes est stocké dans la fenêtre d'instruction. A chaque cycle, le registre de disponibilité est envoyée à toutes les entrées, et est comparé avec tous les masques de disponibilité des opérandes. Si une comparaison renvoie un 1, alors l'instruction de l'entrée est une instruction candidate à l'émission. [[File:Unité d'émission dans le désordre basée sur un registre de disponibilité.png|centre|vignette|upright=2.5|Unité d'émission dans le désordre basée sur un registre de disponibilité]] L'ensemble est implémenté avec l'aide d'une '''matrice de bits''', où chaque ligne correspond à une entrée et chaque colonne à un registre. À chaque croisement entre une ligne et une colonne, on trouve un bit. Si le bit de la ligne n et de la colonne m est à 1, cela veut dire : l'instruction dans l'entrée n a besoin de lire le registre m. S’il est à 0, alors cela veut dire que l'instruction stockée dans la ligne n n'a pas besoin de la donnée dans le registre m. [[File:Planificateur à matrice de bits.jpg|centre|vignette|upright=2|Planificateur à matrice de bits.]] Lorsqu'une instruction réserve une entrée, elle initialise la ligne en fonction des registres qu'elle souhaite lire. Pour vérifier si une instruction a ses opérandes prêts, le processeur compare le registre de disponibilité à la ligne associée à l'instruction/entrée. A chaque intersection ligne-colonne, se trouve un comparateur de 1 bit, qui détecte si le registre est demandé et disponible. Les résultats de cette porte sont ensuite envoyés à une porte ET, qui fait le gros du travail. [[File:Logique de détection de la disponibilité d'une instruction.jpg|centre|vignette|upright=2|Logique de détection de la disponibilité d'une instruction.]] ==Les fenêtres d'instruction basées sur une mémoire associative== Les processeurs modernes utilisent une mémoire associative pour la fenêtre d'instruction. Les mémoires associatives ont été abordées il y a quelques chapitres, mais faisons quelques rappels. Les mémoires associatives servent à accélérer la recherche de données dans un ensemble. Or, une fenêtre d'instruction vérifie régulièrement si chaque entrée est prête. Il s'agit d'un processus de recherche d'une instruction qui respecte une condition bien précise dans la mémoire, ce qui fait que les mémoires associatives sont donc tout indiquées. Comme vous le savez, les signaux de commande d'une instruction sont propagés avec celle-ci dans le pipeline, le nom du registre de destination ne faisant pas exception. Le nom de registre est envoyé à la fenêtre d'instruction lors de l'écriture du résultat dans les registres. S'il y a correspondance, l'opérande est disponible et son bit de disponibilité est mis à 1. On peut adapter cette méthode pour tenir compte du contournement assez simplement. [[File:Détection des dépendances par propagation du registre de destination.png|centre|vignette|upright=2|Détection des dépendances par propagation du registre de destination.]] En conséquence, le circuit de détection des dépendances est constitué d'un grand nombre de comparateurs : un par champ « nom de registre » dans chaque entrée. La logique d'éveil/''wake up'' regroupe tous les comparateurs, la logique de sélection est un circuit situé en-dehors de la mémoire associative. Les entrées sont dans la mémoire associative elle-même. [[File:Gestion des bits de validité.png|centre|vignette|upright=2|Gestion des bits de validité.]] L'implémentation la plus simple est celle du schéma précédent, où on utilise une mémoire associative unique. Une version plus élaborée sépare la fenêtre d'instruction en deux parties : une mémoire qui mémorise les registres des opérandes, une autre mémoire pour le reste. La mémoire pour les registres opérandes est la mémoire associative proprement dite, c'est elle qui est associées aux comparateurs, à la logique de ''wake-up''/réveil, etc. Par contre, l'autre mémoire est une mémoire RAM simplifiée, qui mémorise les informations qui n'ont pas besoin des comparateurs. L'opcode de l'instruction est là-dedans, par exemple. La fenêtre d'instruction est donc une sorte de mémoire associative améliorée. Il se trouve que c'est aussi le cas du ROB. Et il est possible de fusionner le tampon de ré-ordonnancement avec la fenêtre d'instruction dans une structure unique. La différence avec une fenêtre d’instruction normale est que les entrées sont libérées non pas quand l'instruction est exécutée/émise, mais quand elle termine son exécution et quitte le ROB. La fenêtre d'instruction incorpore des bits dans chaque entrée, pour savoir si la µops associée a été émise et est en cours de traitement dans les ALUs. La méthode a notamment été utilisée sur les processeurs d'architecture K6 d'AMD. Le tout donnait une structure appelée le '''DRIS''' (''deferred scheduling register renaming instruction shelf''). Les processeurs PA 8000 de HP étaient aussi vraisemblabment dans ce cas, aussi. ===Les optimisations de la consommation d'énergie : la désactivation des portions inutilisées=== Le problème avec des fenêtres d'instruction de ce type est leur forte consommation énergétique, ainsi que le grand nombre de portes logiques utilisées, qui deviennent prohibitif pour des fenêtres d'instruction un peu grosses. Pour résoudre ce problème, certains ont optimisé les comparateurs. D'autres ont tenté de profiter du fait que la majorité des bits dans les entrées sont composés de zéros. Bref, les optimisations purement matérielles sont légion. Une première solution est de désactiver les entrées qui sont inutilisées, vides, sans instruction. Pour cela, on fait précéder les comparateurs par un circuit qui les connecte ou déconnecte des lignes de bit. Le circuit est commandé par le bit ''empty'' qui indique si une entrée est vide ou non. L'avantage est que la consommation d'énergie de la fenêtre d'instruction devient alors proportionnelle au nombre d'entrées non-vides, et non au nombre d'entrées total. Du moins, en apparence, les entrées non-utilisées doivent quand même être alimentées pour fonctionner, mais l'activité de comparaison disparait dans les entrées vides. Il est possible d'étendre cette technique aux entrées dont les opérandes sont prêtes. Les gains sont généralement assez bons, avec une réduction de consommation variant entre 30 et 50%, avec une implémentation très simple et très économe en circuits. Une autre solution, assez simple à mettre en place, consiste à désactiver une partie de la fenêtre d'instruction sin elle est inutilisée. Pour cela, il faut segmenter la fenêtre d'instruction avec la technique du ''wire partitionning''. Pour rappel, une fenêtre d'instruction est une mémoire associative. Et comme toute mémoire associative, elle contient des fils, les lignes de bit, qui relient les entrées/sorties à toutes les cellules mémoire. Plus une ligne de bit est longue, plus elle consomme d'énergie et plus le temps de lecture/écriture est long. L'idée est de segmenter les lignes de bits en plaçant des répéteurs qui recopient la tension d'un segment au suivant. Les répéteurs sont des tampons trois-états, ce qui permet de déconnecter les portions inutilisées de la ligne de bit. Ce faisant, la fenêtre d'instruction est découpée en segments, qui peuvent être désactivés si besoin. Si il y a peu d'instructions chargées dans la fenêtre d'instruction, les portions inutilisées sont désactivées. La technique marche d'autan mieux si les instructions sont compactées au début de la fenêtre d'instruction. [[File:Wire partitionning.png|centre|vignette|upright=2|Wire partitionning]] Tout le problème est de savoir quelles portions désactiver. La technique est assez simple si la fenêtre d'instruction est compactée, à savoir si toutes les instructions sont régulièrement regroupées au début de la mémoire CAM. Mais même avec cette optimisation, la décision de désactiver une portion de la fenêtre d'instruction n'est pas à prendre à la légère. Il ne faut pas désactiver une portion contenant des instructions pouvant être émise sous peu. La décision dépend de paramètres variés : proportion d'entrée vides, quantité d'entrées récemment activées/désactivées récemment, présences d'entrées avec un ''match'' d'opérandes récent, etc. Il est important de préciser que les techniques en question fonctionnent aussi sur les autres types de fenêtre d'instruction, qui ne sont pas basées sur des mémoires associatives. Nous allons voir celles-ci dans la suite du chapitre, mais gardez à l'esprit que ces optimisations, à savoir désactiver les entrées vides/prêts et partitionner la fenêtre d'instruction, sont des optimisations générales qui marchent avec presque tout. ===L'ajout d'une FIFO pour les instructions déjà prêtes à l'émission=== D'autres techniques permettent de réduire aussi bien le cout en circuits que la consommation d'énergie de la fenêtre d'instruction. L'idée est d'utiliser une mémoire associative quand elle est réellement nécessaire, mais d'utiliser une fenêtre d'instruction "normale" dès que possible. La méthode la plus simple tient compte du fait que certaines instructions ont déjà toutes leurs opérandes de disponibles à l'émission, mais doivent quand même être mises en attente, parce que l'ALU adéquate est occupée, parce que des dépendances WAW/WAR sont encore là, ou pour tout autre raison. Dans ce cas, elles sont mises en attente non pas dans la fenêtre d'instruction, mais dans une mémoire FIFO toute simple. L'idée est qu'au lieu d'avoir une énorme mémoire associative pour la fenêtre d'instruction, on déplace quelques entrées dans une petite FIFO annexe. Le résultat est un gain en terme d'énergie et de circuits, au prix d'une perte de performance mineure. La perte de performance en question se manifeste si aucune instruction n'a ses opérandes de prêtes à l'émission : le programme n'utilise pas la FIFO et voit alors une fenêtre d'instruction plus petite. Une amélioration de cette technique tient compte du fait que certaines instructions sont dans un cas intermédiaire. Elles ont déjà une opérande de prête lors de l'émission, mais pas l'autre. Le nombre d'opérandes varie suivant l’instruction : certaines n'ont besoin que d'un seul opérande. De plus, il arrive qu'une opération tout juste décodée ait déjà un ou plusieurs de ses opérandes de prêts. Cette constatation permet d'éviter d'utiliser des comparateurs pour les opérandes déjà prêts. Par exemple, on peut parfaitement utiliser trois fenêtres d'instruction : * une pour les instructions dont tous les opérandes sont prêts, mais qui sont quand même mises en attente, sans comparateur ; * une pour les instructions dont un seul opérande manque, qui n'utilise qu'un comparateur par entrée ; * une pour les instructions dont deux opérandes manquent à l'appel, qui utilise deux comparateurs par entrée. C'est beaucoup plus économique que d'utiliser une seule grosse fenêtre d'instruction qui contiendrait autant d'entrées que les trois précédentes réunies, avec deux comparateurs par entrée. Certains sont même allés plus loin, et ont proposé de supprimer la fenêtre d'instruction avec deux opérandes par entrée. Les instructions dont deux opérandes sont inconnus au décodage sont stockées dans la fenêtre d'instruction pour instructions avec un comparateur par entrée. Un circuit de prédiction se charge alors de prédire l'opérande manquant, cette prédiction étant vérifiée plus loin dans le pipeline. Il serait cependant étonnant qu'une telle proposition ait donné lieu à la moindre implémentation réelle. ===Les optimisations de la consommation d'énergie avancées=== D'autres chercheurs ont conservé une fenêtre d'instruction unique, avec autant de comparateurs par entrée qu'il y a d'opérandes possibles par instruction. Simplement, le processus de détection des opérandes prêts est légèrement ralenti : on ne vérifie qu'un opérande par cycle. Pour vérifier les deux opérandes d'une entrée, on doit attendre deux cycles. Enfin, certains chercheurs ont proposé des fenêtres d'instruction segmentées. Les instructions circulent à chaque cycle d'un segment vers le suivant : en conséquence, certains segments conservent les instructions les plus anciennes, un autre les instructions les plus jeunes, etc. Seul le denier segment, celui qui contient les instructions les plus vielles, peut émettre une instruction : la détection des opérandes se fait seulement dans le dernier segment, qui contient les instructions les plus anciennes. On économise ainsi beaucoup de comparateurs. Certains chercheurs ont tenté de pipeliner l'étape de sélection des opérandes, ainsi que l'étage d'arbitrage. Mais en faisant cela, il faut plusieurs cycles pour détecter qu'une instruction a ses opérandes prêts, ce qui pose problème face à de nombreuses dépendances RAW. Pour éviter de trop perdre en performances, certains chercheurs ont décidé d'utiliser des techniques pour prédire quelles seront les instructions dont les opérandes seront bientôt prêts. Si détecter qu'une instruction est prête prend n cycles, le processeur devra tenter de prédire la future disponibilité des opérandes n cycles en avance pour obtenir des performances optimales. ===Remplacer la mémoire associative par une RAM=== Une autre optimisation possible est de remplacer la fenêtre d'instruction par une mémoire RAM, dont chaque mot mémoire correspondrait à une entrée. Une telle optimisation permet en théorie de se passer des comparateurs associés à chaque entrée, mais au prix de l'ajout de circuits annexes potentiellement couteux. La première de ces techniques, la '''recherche directe par étiquette''' (direct tag search) fut créée par Weiss et son collègue Smith. Ils cherchaient à améliorer l'algorithme de Tomasulo, un algorithme qu'on expliquera dans quelques chapitres. Rappelons que chaque instruction produit un résultat, qui devra être rapatrié dans une ou plusieurs entrées de la fenêtre d'instruction. L'optimisation de la recherche directe par étiquette fonctionne dans le cas où le résultat de l'instruction n'est utilisé que par une seule entrée, et pas plusieurs. Le principe est simple : chaque champ « opérande » d'une entrée est adressable via le nom de registre de cette opérande. Pour faire le lien entre entrée et nom de registre, la recherche directe par étiquette ajoute une table de correspondances matérielle, une mémoire RAM qui mémorise les adresses des champs « opérande » des entrées. Les adresses envoyées dans cette mémoire sont les noms de registres des résultats. Lors de l'émission, la table de correspondances est mise à jour. Les numéros des champs « opérande » réservés lors de l'émission sont mémorisés dans les mots mémoire qui correspondent aux deux registres sources. Toutefois, une petite vérification est faite lors de l'émission : si il y a déjà une correspondance dans la table pour un registre source, alors une autre instruction compte lire ce registre. Pour éviter d'écraser les données de l'instruction précédente dans la table de correspondances, l'émission de l'instruction est bloquée. [[File:Recherche directe par étiquette.png|centre|vignette|upright=2|Recherche directe par étiquette.]] ==Les fenêtres d’instruction avec préplanification== Avec la '''préplanification''' (''prescheduling''), la fenêtre d’instruction est composée de mémoires FIFO dans lesquelles les instructions sont triées dans l'ordre d'émission. Il n'y a pas de logique d’émission proprement dite, celle-ci se bornant à vérifier si l'instruction située au début de la FIFO peut s’exécuter. Par contre, le préplanificateur détecte les dépendances et en déduit où insérer les instructions dans le tampon d'émission, à l'endroit le plus adéquat. [[File:Préplanification.jpg|centre|vignette|upright=2|Préplanification.]] ===L'usage de FIFO multiples=== La technique de préplanification la plus simple utilise plusieurs FIFO. Quand une instruction a une dépendance avec une autre instruction, les deux sont placées dans la même FIFO. Pour cela, le préplanificateur détecte les chaines d'instructions dépendantes, et place les instructions dans la FIFO adéquate. A chaque cycle, l'unité d'émission lit une micro-opération dans chaque FIFO et vérifie si elle peut l'émettre. Si la micro-opération n'a pas ses opérandes disponibles, ou qu'une dépendance structurelle survient, alors la FIFO est bloquée. La micro-opération attend que la dépendance soit résolue, bloquant toutes les instructions précédentes. Mais les autres FIFO ne sont pas bloquées, laissant de la marge de manœuvre. [[File:Préplanification par FIFO multiples.png|centre|vignette|upright=1.5|Préplanification par FIFO multiples.]] ===La technique du tampon trié=== La technique du '''tampon trié''' trie les instructions selon le temps d'attente avant leur exécution. Les instructions qui sont censées s’exécuter bientôt sont insérées au tout début de la FIFO, tandis que les instructions qui s’exécuteront dans un long moment sont insérées vers la fin. Là encore, l'unité d'émission lit une micro-opération dans la FIFO, et détermine si elle peut être émise. Si une dépendance survient, l'émission est retardée, et la FIFO est bloquée. [[File:Préplanification par tampon trié.png|centre|vignette|upright=1.5|Préplanification par tampon trié.]] La technique a cependant quelques problèmes assez importants. Le premier problème est que la FIFO est bloquée lorsqu'une micro-opération ne peut être émise. Le second problème est que le temps avant exécution n'est pas toujours connu, notamment pour les instructions d'accès mémoire. Et cela se répercute sur les instructions dépendantes de celles-ci. Pour résoudre ce genre de problèmes, l'usage d'un pipeline à ''replay'' est possible, et est même l'une des meilleures solution possible, malgré ses défauts. L'idée est que les lecture sont pré-planifiées en supposant qu'elles font un succès de cache L1. Si la prédiction est fausse, la lecture est ré-exécutée plusieurs cycles plus tard, en supposant qu'elle fait un succès dans le cache L2, et ainsi de suite. Elle est alors ré-insérée dans la FIFO, elle est pré-planifiée une seconde fois. Il en est de même si une micro-opération ne peut pas être émise : il suffit de la réinsérer dans la FIFO au bon endroit, en attendant que ses dépendances soient résolus. Ainsi, l'instruction fautive ne bloque pas la fenêtre d’instruction, et retente sa chance autant de fois qu'il le faut. [[File:Préplanification par fenêtre d’instruction scorebarodée.png|centre|vignette|upright=1.5|Préplanification par fenêtre d’instruction scorebarodée.]] Une autre solution utilise deux fenêtres d’instruction : une FIFO gérée par la préplanification, et une vraie fenêtre d'instruction pour les instructions dont le temps d'attente ne peut pas être déterminé. Il est possible de mettre cette dernière avant la préplanification, afin de gérer les temps d'attente des instructions d'accès mémoire. Quand le temps d'attente d'une lecture devient connu, ses instructions dépendantes sont gérées avec préplanification. [[File:Préplanification avec fenêtre d’instruction.png|centre|vignette|upright=2.5|Préplanification avec fenêtre d’instruction.]] ===Les fenêtres d'instruction avec allocation temporelle statique=== L''''allocation temporelle statique''' correspond à une technique utilisée sur les processeurs Cuzco de l'entreprise Condor. La technique en question a été présenté en 2025, mais des idées similaires ont été présentées dans la littérature académique. Elle ressemble beaucoup aux techniques de pré-planification, avec cependant quelques différences. L'idée est simple : le processeur dispose de plusieurs fenêtres d'instruction, qui mettent en attente les micro-opérations. Lors de l'étape de renommage de registres, le processeur détermine dans combien de cycles d'horloge la micro-opération sera prête pour exécution. La micro-opération est alors mise en attente durant ce nombre de cycles, dans les fenêtres d'instruction, puis est émise une fois ce nombre de cycles écoulés. Ce faisant, les fenêtres d'instruction n'ont pas besoin de détecter la disponibilité des opérandes à chaque cycle, pour chaque micro-opération en attente. Le ''timing'' de l'émission des micro-opérations est décidé à l'avance. L'implémentation exacte n'est pas connue, mais plusieurs solutions sont imaginables. Par exemple, la fenêtre d'instruction peut simplement être composée de plusieurs mémoires de petite taille, chacune contenant les micro-opérations destinées à être exécutées dans N cycles, N étant différent pour chaque mémoire. Une autre solution, plus réaliste, utilise une fenêtre d'instruction dans laquelle la micro-opération est couplée à des champs pour les opérandes, et un champ compteur. Le champ compteur est initialisé avec le nombre de cycles à attendre, et est décrémenté à chaque cycle d'horloge. Quand il atteint zéro, la micro-opération est émise. Vous remarquerez que la méthode ne marche que si toutes les micro-opérations prennent un nombre fixe de cycles d'horloge. Et autant c'est le cas pour les micro-opérations arithmétiques ou logiques, autant les accès mémoire ne rentrent pas dans ce cadre. En théorie, on ne sait pas combien de temps prendra un accès mémoire. Et cette incertitude se répercute sur les instructions dépendantes d'un accès mémoire. Pour éviter cela, le processeur réutilise un pipeline à ''replay'' tel que vu dans le chapitre précédent. L'unité de renommage de registre suppose que tout accès mémoire fait un succès de cache L1, et décide des ''timings'' d'émission sous cette hypothèse. Si une lecture subit un défaut de cache, elle est ré-exécutée, de même que toutes les instructions dépendantes. Pour cela, le registre de destination de la lecture est marqué comme invalide, grâce à un bit spécifique attaché au registre. Toute instruction qui lit une opérande invalide est elle aussi ré-executée de zéro. Pour simplifier, l'unité d'émission ressemble à une unité d'émission dans l'ordre, avec un registre de disponibilité, qu'on aurait amélioré pour aller au-delà de la simple détection des dépendances d'instruction. Pour déterminer les ''timings'' d'émission, à savoir quand émettre une micro-opération, le processeur utilise une unité d'émission à deux étages. Le premier étage est appelé le ''register scoreboard'', le second étage est appelé la ''Time Ressource Matrix''. Les deux étages communiquent entre eux, comme on va le voir, et leurs noms donnent une idée de ce qu'ils font. Le premier étage gère les dépendances de registres, le second gère les dépendances structurelles. Le premier étage est un registre de disponibilité amélioré, qui gère les dépendances de registre. Cet étage sait quand tel registre sera écrit, et donc que l'opérande écrite dedans sera disponible à partir de tel cycle d'horloge. Il le sait car l'étage suivant l'aura prévenu, mais laissons cela de côté pour le moment. Quand une micro-opération rentre dans cet étage, il vérifie les dépendances avec les registres et les micro-opérations antérieures. Vu qu'il sait quand les registres seront disponibles, il peut déterminer quand l'instruction pourra s'exécuter. Par exemple, si une micro-opération lit les deux registres R7 et R15, qui sont disponibles respectivement dans 5 et 7 cycles, le premier étage sait que la micro-opération devra attendre 7 cycles. Mais tout cela ne suffit pas à déterminer quand émettre une micro-opération. En effet, il fait aussi gérer les dépendances structurelles, ce qui est le boulot du second étage. Le second étage utilise pour cela une ''Time Ressource Matrix'', qui mémorise l'occupation de diverses "ressources", pour les 256 cycles d'horloge à venir. Les ressources en question sont les ports de lecture/écriture du banc de registre, les ALUs utilisées, si la micro-opération utilise l'unité mémoire, etc. Le second étage prend en entrée une micro-opération, détermine quelles "ressources" elle utilise, puis regarde leur disponibilité. Elle détecte alors les dépendances structurelles et détermine alors quand peut s'exécuter la micro-opération. Elle peut retarder l'émission de quelques cycles, si une dépendance structurelle est détectée. Une fois sortie du second étage, on sait quand la micro-opération va être émise, à quel cycle précisément. Et vu que la durée de l'instruction est fixe, on sait quand cette micro-opération va se terminer, quand son résultat sera disponible. Cela permet de mettre à jour la ''Time Ressource Matrix'', pour préciser que le port d'écriture sera occupé à tel moment. De plus, cette information est transmise au premier étage, qui sait alors quand est enregistré le résultat dans le registre de destination. C'est comme cela que le premier étage sait quand un registre est disponible : le second étage le prévient, quand il émet une instruction ! La ''Time Ressource Matrix''mémorise l'occupation des "ressources" pour les 256 cycles d'horloge à venir. Cependant, elle ne vérifie pas les dépendances pour les 256 cycles suivants. Quand elle reçoit une micro-opération, elle teste les dépendances structurelles pour seulement les 8 prochains cycles maximum. Si la micro-opération ne peut pas être émise pendant ces 8 cycles, le pipeline est bloqué, un ''pipeline stall'' est émis. Pour être plus précis, vu que le processeur peut décoder 8 micro-opérations en même temps, cela permet de ne consulter que 64 cycles d'horloge sur les 256. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les premiers processeurs Intel | prevText=Les premiers processeurs Intel | next=Le renommage de registres | nextText=Le renommage de registres }} </noinclude> apzj668vb424jyij9v9zhbnxux44mln 773609 773608 2026-09-29T20:14:47Z Mewtow 31375 773609 wikitext text/x-wiki Dans les chapitres précédents, nous avons parlé des techniques dites d''''émission dans l'ordre'''. L'idée est d’exécuter une nouvelle micro-opération à chaque cycle, dans des unités de calcul séparées. Les instructions sont émises consécutivement, mais les instructions s’exécutent en parallèle dans des unités de calcul séparées. Par contre, quand l'unité d'émission ne peut pas émettre une instruction, elle bloque tout le pipeline. Les instructions qui suivent sont elles aussi bloquées, elles doivent attendre leur tour, même si elles sont en capacité de s'exécuter. Les techniques d'exécution dans le désordre que nous allons voir dans ce chapitre corrigent ce point précis. Elles sont dites à '''émission dans le désordre'''. Elles se distinguent des précédentes sur un point précis : quand l'unité d'émission bloque l'émission d'une instruction, les instructions suivantes peuvent poursuivre. L'émission des instructions peut donc se faire dans le désordre, dans le sens où une instruction peut être émise alors qu'une instruction précédente ne l'est pas encore. L'avantage de l'émission dans le désordre est qu'une instruction s'exécute dès que ses opérandes sont disponibles. Par disponible, on veut dire présent soit dans le réseau de contournement, soit dans les registres. Le processeur détecte automatiquement quand les opérandes d'une instruction sont disponibles, et il l’exécute à ce moment-là. Dès qu'une instruction a ses opérandes disponibles, elle est émise et exécutée. C'est là la seule contrainte : les dépendances WAR, WAW et autres sont gérées par un ROB ou toute autre technique d'exception précise, seules les dépendances RAW limitent l'exécution. Mais avant de poursuivre, quelques point niveaux terminologie : * L'émission dans le désordre est un terme parlant et assez précis. Malheureusement, la terminologie la plus utilisée par d''''exécution dans le désordre'''. Et nous utiliserons ce terme dans la suite du cours, histoire de ne pas trop dévier de la nomenclature habituelle. * Nous utiliserons parfois l'abréviation OOO pour parler d'exécution dans le désordre. L'abréviation est celle de ''Out Of Order Excution''. * Nous utiliserons aussi l'abréviation ''µop'' pour parler de micro-opération, ''µops'' au pluriel pour parler de plusieurs micro-opérations, ou des micro-opérations en général. L'exécution dans le désordre ne gère en effet que des µops, elle se situe après l'étape de décodage. Mais avant de poursuivre, précisons une chose importante : l'exécution dans le désordre traite les accès mémoire à part. La majorité des processeurs OOO assez anciens exécutent les accès mémoire dans l'ordre, seules les µops entières/flottantes/branchements sont exécutées dans le désordre. Les processeurs datant d'après les années 2010 sont capable d'exécuter les accès mémoire dans le désordre, mais l'implémentation en question est assez particulière. Un chapitre entier sera dédié à l'exécution dans le désordre des µops mémoire. Nous allons volontairement mettre de côté la gestion des accès mémoire dans ce chapitre. ==Les fenêtres d’instruction : généralités== Pour décrire comment est implémentée l'émission dans le désordre, il faut commencer par parler des processeurs sans. Les processeurs sans exécution dans le désordre ont une unité d'émission qui bloque tout le pipeline dès qu'une µop ne peut pas être émise. Pour limiter l'impact de ce blocage, quelques rares processeurs incorporent une '''file de micro-opération''', une mémoire FIFO qui met en attente les µops. Vu que c'est une mémoire FIFO, les µops sont émises dans l'ordre, à savoir l'ordre d'ajout, dans l'ordre de décodage. Le schéma ci-dessous illustre une telle file d'attente couplée à un ''scoreboard''. Sur le principe, l'exécution dans le désordre améliore la file de µops sur un point : ce n'est plus une mémoire FIFO. Les µops sont insérées dans l'ordre, mais peuvent sortir dans le désordre (être émises dans le désordre). La file de µops devient alors une '''fenêtre d'instruction''', terme traduit directement de l'anglais ''instruction Window''. Terme assez trompeur, car elles mettent en attente des µops, pas des instructions. Elles peuvent émettre des µops dans le désordre, ce qui fait que si une µop bloque le pipeline, les µops suivantes peuvent être émises. [[File:Différence file µops et fenêtres instruction.png|centre|vignette|upright=2|Différence file µops et fenêtres instruction]] Je commence le paragraphe précédent par "sur le principe", car certaines techniques d'OOO utilisent des files de µops normales. Il est par exemple possible d'utiliser une file de µops avec une fenêtre d'instruction, plusieurs files de µops, plusieurs fenêtres d'instructions avec une file de µops annexe, etc. Dasn les grandes lignes, il existe dans les grandes lignes 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! File de µops améliorée |- ! Une seule "file de µops" | ''Scoreboard'' | Fenêtre d'instruction centralisée |- ! Plusieurs "file de µops" | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | Fenêtre d'instruction décentralisée |} ===La fenêtre d'instruction centralisée=== L'implémentation la plus simple de l'OOO utilise une unique fenêtre d'instruction, appelée une '''fenêtre d'instruction centralisée'''. Les µops décodées sont accumulées dans la fenêtre d'instruction, où elles attendent que leurs opérandes soient disponibles. La fenêtre d'instruction sert donc de file d'attente. Mais elle contient aussi une unité d'émission, qui détecte quelles µops sont prêtes à être émises. L'unité d'émission et la fenêtre d'instruction sont fusionnées ensemble, elles forment un seul circuit. Mais nous allons dire qu'elles sont conceptuellement séparées pour le moment. A chaque cycle, l'unité d'émission consulte la fenêtre d'instruction pour voir quelles µops peuvent s'exécuter, lesquelles ont leurs opérandes de disponibles. La fenêtre d'instruction doit spécialement être conçue pour, c'est une sorte de mémoire associative très complexe, comme on le verra dans ce qui suit. [[File:OOO Issue.png|centre|vignette|upright=2.5|Exécution dans le désordre avec une fenêtre d'instruction]] Une fois qu'une µop sort du décodeur d'instructions, elle est ajoutée en parallèle dans la fenêtre d'instruction et le ROB. La raison est que les µops quittent la fenêtre d'instruction dans le désordre, et qu'elles doivent être remises en ordre par la suite. Le ROB s'occupe de cette remise en ordre, mais il a besoin de savoir dans quel ordre les µops sont censées être, et cet ordre est celui du décodage. Aussi, pour remplir le ROB, la seule opportunité est en sortie de l'unité de décodage. Dans le cas où une instruction est décodée en plusieurs micro-opérations, elles sont toutes insérées en même temps dans la fenêtre d'instruction et le ROB, en tenant compte de leur ordre. [[File:Fenêtre d'instruction.png|centre|vignette|upright=2|Fenêtre d'instruction.]] Les micro-opérations mémoire sont à part des autres, pour diverses raisons. Une de ces raisons est que les dépendances de données sont classées en deux types : les dépendances de registre et les dépendances d'adresse. Et les deux sont fondamentalement différentes. Autant on peut détecter les dépendances de registre lors de l'émission, autant c'est plus compliqué avec les dépendances d'adresse. De plus, rappelons que si les lectures peuvent s'exécuter dans le désordre, les écritures doivent s'exécuter dans l'ordre, ou du moins en donner l'illusion. Pour cela, le processeur remet les écritures dans l'ordre avec une sorte de mini-ROB intégré à l'unité mémoire, appelée la file d'écriture. Elle complémente le ROB, qui lui ne gère que les écritures dans les registres, mais les deux collaborent. La file d'écriture envoie une écriture à la mémoire RAM quand le ROB lui dit que c'est bon, les instructions précédentes sont terminées ''dans l'ordre du programme''. Les processeurs modernes ajoutent des techniques d'exécution dans le désordre des accès mémoire, mais nous les verrons dans un chapitre dédié. Elles permettent d'utiliser une fenêtre d'instruction unique, qui mémorise aussi les µops mémoire. Si elles sont mises en place, l'unité mémoire n'a pas besoin de file de µops séparée. L'idée est que les dépendances de registre sont traitées par la fenêtre d'instruction, mais que l'unité mémoire gére les dépendances d'adresse. Les dépendances d'adresse sont gérées par des techniques de ''désambiguation mémoire'', qui auront droit à un chapitre dédié. [[File:Processeur avec exécution dans le désodre des accès mémoire.png|centre|vignette|upright=2|Processeur avec exécution dans le désodre des accès mémoire]] Les processeurs assez anciens n'autorisaient pas d'exécution dans le désordre des accès mémoire. Concrétement, les accs mémoire devaient se faire dans l'ordre, mais les autres µops pouvaient être exécutées dans le désordre. Il s'agit donc d'un ordre entre µops mémoire, pas entre µops mémoire et autres µops. Les µops entières et flottantes pouvaient être exécutées avant une µops mémoire qui est avant elle dans l'ordre du programme, ce n'est pas un problème. Pour garantir l'ordre desd µops mémoire, l'unité mémoire est précédée par une file de micro-opérations séparée, pour forcer l'exécution dans l'ordre des accès mémoire. De plus, les µops mémoire ne peuvent pas utiliser la fenêtre d'instruction. Dit autrement, la fenêtre d'instruction ne mémorise pas de µops mémoire. Après le décodage, les µops sont réparties soit dans la file de µops mémoire, soit dans la fenêtre d'instruction. Le décodeur classe les µops suivant que ce sont des µops mémoire ou non, et les envoient à la bonne destination. Dans ce chapitre, on supposera que c'est cette solution qui est utilisée. [[File:Processeur avec émission dans l'ordre des accès mémoire.png|centre|vignette|upright=2|Processeur avec émission dans l'ordre des accès mémoire]] La solution précédente revient à scinder la fenêtre d'instruction en deux : une file de µops pour les µops mémoire, une fenêtre d'instruction pour les autres µops. Et cette scission peut aller plus loin, à savoir qu'on peut scinder une fenêtre d'instruction encore et encore. Ce qui nous amène à la section suivante. ===Les fenêtres d'instruction décentralisées=== Nous venons de voir qu'il est possible de scinder la fenêtre d'instruction en une fenêtre d'instruction pour les µops mémoire (simplifiée en une file de µops classique), et une autre pour les autres µops. Sachez qu'il est possible d'aller plus loin, par exemple en séparant la fenêtre d'instruction en une fenêtre spécialisée dans les µops flottantes et une autre pour les µops entières. Et ce n'est là qu'un exemple parmi de nombreuses autres possibilités. Pour faire la différence avec une fenêtre d'instruction unique, nous allons parler de fenêtre d'instruction centralisée s'il n'y en a qu'une, de '''fenêtre d'instruction décentralisée''' s'il y en a plusieurs. Il est possible d'associer chaque fenêtre d'instruction à un type précis de µops. Par exemple, avec une fenêtre d'instruction pour les µops de calcul entières, une autre pour les µops flottantes, une autre pour les µops mémoire. Il s'agit d'un choix simple et efficace, mais quelques processeurs font autrement, pour répondre à des contraintes très diverses. [[File:Processeur avec des fenêtres d'instruction décentralisées.png|centre|vignette|upright=2|Processeur avec des fenêtres d'instruction décentralisées]] Reste à scinder la fenêtre d'instruction pour trier les µops suivant leur type. Si le processeur exécute les accès mémoire dans l'ordre, la méthode la plus simple utilise une fenêtre d'instruction pour les opérations flottantes et une autre pour les autres µops (µops entières et parfois mémoire avec). L'avantage est que cela simplifie grandement le processeur. Les flottants sont gérés à part des entiers. Ils ont leurs propres registres, des FPU séparées des ALU entières, bref : la séparation est complète. Utiliser une fenêtre d'instruction séparée va dans ce sens. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Il est possible de faire pareil sur les processeurs avec exécution dans le désordre des accès mémoire. Par exemple : les processeurs Intel de microarchitecture Skylake utilisent une fenêtre d'instruction pour les opérations entières/flottantes, et une fenêtre d'instruction séparée pour les µops mémoire. Un avantage est que les deux fenêtres d'instructions sont plus spécialisées, ce qui entraine des économies de circuit. Les opérations entières/flottantes ont besoin de deux registres pour les opérandes et d'un autre résultat, alors que les µops mémoire n'ont besoin que de deux registres maximum. En utilisant une fenêtre d'instruction unique, chaque entrée doit mémoriser l'opcode et trois registres, dont un est inutilisé pour les µops mémoire et les branchements. En utilisant des fenêtres d’instructions séparées, celle pour les µops entières/flottantes a trois registres par entrée, contre seulement deux registres par entrée pour celle des µops mémoire. Un cas extrême est celui où chaque ALU/FPU a sa propre fenêtre d'instruction. Nous parlerons alors de '''fenêtres d'instruction totalement décentralisées'''. Par exemple, il y a une fenêtre d'instruction pour l'ALU entière, une autre pour le multiplieur entier, une autre pour le ''barrel shifter'', une autre pour l'unité mémoire, une autre pour l'unitéé de branchements, une autre pour l'additionneur flottant, une dernière pour le multiplier flottant, etc. Un exemple historique est celui de la FPU de l'IBM 360 modèle 90. Elle disposait d'un additionneur flottant, d'un multiplieur flottant, et d'une unité mémoire pour les lectures/écritures flottantes. Les trois unités avaient leur propre fenêtre d'instruction. Les processeurs AMD utilisent beaucoup cette technique, contrairement à Intel qui préfère utiliser des fenêtres centralisées sur les anciens processeurs, deux ou trois fenêtres sur les processeurs récents (2020 et plus). Les processeurs AMD utilisaient précisément une fenêtre d'instruction par ALU entière, alors que les FPUs partagent une fenêtre d’instructions flottantes unique. Mais nous verrons cela en détail dans le chapitre sur les processeurs superscalaires x86. Un point important est qu'avec des fenêtres d'instruction décentralisées, l'émission est découpée en deux étages. La première étape envoie une µops vers la fenêtre d'instruction adéquate, la seconde émet la µops depuis la fenêtre d'instruction quand ses opérandes sont prêts. La première est l'étage de '''''dispatch''''' qui envoie l'instruction dans la fenêtre d’instruction adéquate, selon que c'est une instruction flottante, entière, autre. La seconde est l'étage de '''''scheduling''''', qui gère la disponibilité des opérandes et des unités de calcul. La µop émise est ajoutée au tampon de réordonnancement, s'il existe, lors de l'étape de ''dispatch''. ===L'usage de plusieurs files d'instruction=== Une dernière méthode d'OOO utilise plusieurs files de micro-opération. L'idée est qu'une fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement une file de micro-opération pour les opérations entières, une autre pour les opérations flottantes, une autre pour les accès mémoire. D'autres processeurs utilisent une file pour les accès mémoire et une autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. La présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que la technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si une dépendance bloque une FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans une autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer la disponibilité des registres. Quand un registre est lu ou écrit par une instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. La logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : une pour les instructions d'accès mémoire et une autre pour les autres instructions. Si jamais une instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de la lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'une est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est la file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. ===Avantages et inconvénients de chaque implémentation=== Pour résumer, on a le choix entre une grosse fenêtre d'instruction généraliste et plusieurs fenêtres spécialisées. Le choix entre les deux est un compromis entre économie de circuits et flexibilité. Avec une fenêtre décentralisée, il arrive qu'une fenêtre d'instruction soit remplie, alors que les autres sont sous-utilisées, voire vides. Pour comprendre pourquoi, comparons une fenêtre d'instruction unique, avec une fenêtre décentralisée séparant µops entières et flottantes. La fenêtre centralisée dispose de 64 entrées, la décentralisée a 32 entrées pour chaque fenêtre d'instruction. La fenêtre décentralisée peut mémoriser au maximum 32 µops entières et 32 *ops flottantes. Par contre, la fenêtre centralisée peut mémoriser 64 µops tout court. Si le programme exécuté n'utilise pas de nombres flottants, la différence devient flagrante. La fenêtre décentralisée sera limitée ) 32 µops, alors que la centralisée pourra mémoriser le double. Les performances seront donc meilleures avec la fenêtre centralisée. Et au-delà de ça, la fenêtre décentralisée de l'exemple est utilisée de manière optimale si la moitié des µops sont des µops entières, et l'autre moitié des µops flottantes. Alors que la fenêtre centralisée se moque de la répartition entre µops entières et flottantes. Une subtilité est que le cout en transistors d'une fenêtre d'instruction n'est pas proportionnel au nombre de µops qu'elle peut mémoriser. Par exemple, si je compare une fenêtre d'instruction de 32 entrées (32 µops max), elle n'utilise pas deux fois plus transistors qu'une fenêtre de 16 entrées. Le cout en circuit n'est pas deux fois plus élevé, mais est approximativement 4 fois plus élevé. Le cout est presque quadratique, à savoir qu'il est proportionnel au carré du nombre d'entrées. Et il en est de même avec la performance, pour des raisons qu'on expliquera plus bas. Les fenêtres décentralisées utilisent plusieurs fenêtres d'instruction de "petite taille", donc plus rapides, économes en circuits et économes en énergie. Le compromis n'est donc pas entre une fenêtre centralisée à 64 entrées versus deux fenêtres de 32 entrées. Le compromis en pratique est entre une fenêtre centralisée de 64 entrées versus 3 fenêtres de 32 entrées. Un exemple pratique est celui de la microarchitecture ''Skylake'' d'Intel. Intel est passé d'une fenêtre centralisée pre-''Skylake'' à deux fenêtres décentralisées sur ''Skylake'',. Le nombre d'entrée était globalement le même entre les deux, même si l'évolution de la finesse de gravure entre les deux biaise un peu les résultats. Un avantage des fenêtres décentralisées est qu'il est possible de démarrer l'exécution de plusieurs µops simultanément : une µops par fenêtre d'instruction. Le fait est que deux fenêtres d'instructions différentes émettent leurs µops sans se synchroniser avec les autres. Deux fenêtres d'instruction peuvent donc émettre chacune une µops, ce qui fait deux µops émises lors du même cycle. Cela permet d'exécuter en même temps deux ou trois instructions 1-cycle, comme des additions, soustractions, décalages, etc. Il devient par exemple possible d'émettre une µop entière en même temps qu'une µop flottante, si les µops entières ont une fenêtre séparée de celle des µops flottantes. Il est maintenant temps de voir en quoi sont faites les fenêtres d’instruction, qu'elles soient centralisées ou décentralisées. Nous allons aussi voir quelle est la logique d'émission associée. ==L'implémentation d'une fenêtre d'instruction : généralités== Une fenêtre d'instruction est une mémoire qui mémorise des micro-opérations. Elle est cependant plus complexe qu'une mémoire RAM ou qu'une FIFO et ressemble un petit peu à une mémoire cache. Elle dispose d'un port d'écriture et d'un port de lecture, au minimum. Le port d'écriture permet à l'unité de décodage d'insérer une micro-opération dedans, d'ajouter la micro-opération qui vient d'être décodée. Si une instruction machine est décodée en plusieurs micro-opération, deux possibilités. La première est de les insérer un par un, ce qui fait qu'on peut se contenter d'un seul port d'écriture. L'autre possibilité est de les ajouter en même temps, ce qui demande plusieurs ports d'écriture. Le port de lecture sert à émettre une instruction. On part du principe que la fenêtre d'instruction ne peut émettre qu'une seule instruction à la fois, car les processeurs que nous avons vu précédemment sont de ce type. Mais nous verrons dans quelques chapitres qu'il existe des processeurs dits superscalaires, qui sont capables d'émettre plusieurs instructions par cycle. Dans ce cas, la fenêtre d'instruction a un seul port de lecture. Un processeur superscalaire, quant à lui, doit avoir un port de lecture par unité de calcul, ce qui fait beaucoup plus. Les fenêtres d'instruction sont composées d''''entrées''', des mots mémoire qui stockent une instruction. Une instruction réserve une entrée après son décodage et la libère dès qu'elle est envoyée aux unités de calcul. Une entrée contient l'opcode (les signaux de commande à envoyer à l'ALU), le registre de destination du résultat, les registres de chaque opérande, et éventuellement des signaux de commande en plus. De plus, chaque opérande est couplée à un bit de disponibilité, qui indique si elle est disponible. Quand un opérande est écrit dans les registres, le bit de présence correspondant est mis à jour. Enfin, chaque entrée possède un bit ''empty'' qui indique si elle est vide, cette information étant utile pour réserver des entrées. [[File:Entrée d'une station de réservation - sans les tags.png|centre|vignette|upright=3|Entrée d'une fenêtre d'instruction]] ===Les stations de réservation=== Les '''stations de réservation''' sont des fenêtres d'instruction particulières, qui sont capables de mémoriser les opérandes des instructions. Les entrées des stations de réservation sont identiques à celle des autres fenêtres d'instruction, si ce n'est que les opérandes de l'instruction sont enregistrés directement dans des champs séparés. Il y a deux champs, un par opérande, pour stocker l'opérande elle-même, lue depuis les registres ou obtenue via le réseau de contournement. Notons que les champs pour les opérandes viennent en plus des champs pour les noms de registres, encore que les deux peuvent être fusionnés si on veut optimiser le tout. [[File:Entrée d'une station de réservation.png|centre|vignette|upright=3|Entrée d'une station de réservation.]] Précisons que la terminologie n'est pas très fiable. Les termes "fenêtre d'instruction" et "station de réservation" ne regroupent pas du tout la même chose d'un papier de recherche à l'autre, d'un bouquin à l'autre, d'un chercheur à l'autre, d'un ingénieur à l'autre, d'un professeur à l'autre. Le terme initial vient pourtant de l'article original sur l'algorithme de Tomasulo, où il désignait une fenêtre d'instruction associée à une unité de calcul précise. Mais le terme a ensuite été réutilisé, ce qui fait que certains processeurs avec plusieurs unités de calcul sont décrits comme ayant une unique station de réservation. En bref : c'est le bazar ! Mais nous en reparlerons dans le chapitre sur le renommage de registres, car c'est la place idéale pour les aborder. Toujours est-il que j'ai fait le choix de confondre les concepts de fenêtre d'instruction et de station de réservation avec les concepts de '''lecture avant émission''' et de '''lecture après émission'''. La différence entre les deux est que les registres sont lus après émission avec une fenêtre d'instruction, avant avec des stations de réservation. Dans le cas "avant émission", les opérandes sont mémorisés dans la station de réservation. Et cette différence a une influence sur le pipeline du processeur, le banc de registres et tout ce qui s'en suit. Un désavantage de la lecture avant émission est qu'il faut stocker les opérandes après lecture, ici dans les stations de réservation. Mais un avantage est que le banc de registre a besoin de moins de ports de lecture, car une bonne partie des opérandes sont fournies par le système de contournement. Nous verrons cela dans le détail dans le chapitre sur les processeurs superscalaires. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Lecture après émission.]] [[File:Read Before Issue.png|centre|vignette|upright=2.5|Lecture avant émission.]] ===La logique d'éveil et de sélection=== Dans le cas qui va suivre, on suppose que le processeur ne peut émettre qu'une instruction à la fois. Chaque cycle, une instruction est sélectionnée et est envoyée dans le chemin de données, soit à une ALU, soit à une unité d'accès mémoire. La sélection d'une instruction est effectuée par l'unité d'émission, qui est aussi appelée le '''''scheduler'''''. Elle gère la disponibilité des opérandes et la disponibilité des unités de calcul adéquate. Le choix de l'instruction émise doit être le plus pertinent possible, pour des raisons de performances. Pour le premier point, l'unité d'émission détermine quelles instructions sont candidates pour l'émission. Les ''instructions candidates'' sont celles dont tous les opérandes sont prêts. Le processeur contient un circuit qui détecte les instructions candidates : la '''logique d’éveil''' (''wake-up logic''). Une fois que la logique d'éveil a fait son travail, une instruction est choisie pour s’exécuter en fonction de la disponibilité des unités de calcul adéquates. Ce rôle est dévolu à un circuit qu'on appelle la '''logique de sélection''', ou ''select logic''. [[File:Fonctionnement complet de la logique d’émission.jpg|centre|vignette|upright=1.5|Fonctionnement complet de la logique d’émission.]] La logique de sélection doit gérer le fait que les unités de calcul du processeur ne sont pas toutes identiques. Déjà, un processeur a généralement des unités séparées pour les instructions entières et flottantes, des unités spécialisées dans les accès mémoire, parfois des unités spécialisées pour les branchements. Une instruction doit être attribuée à la bonne unité de calcul, on ne doit pas envoyer une instruction entière dans une unité de calcul flottante. De plus, parmi les unités de calcul entières, toutes ne sont pas identiques. Par exemple, il est fréquent d'avoir plusieurs unités de calcul spécialisées dans les opérations simples (additions, soustractions, opérations logiques) avec une unité pour les multiplications/divisions séparées, parfois une unité spécialisée pour les décalages/rotations, etc. Là encore, allouer la bonne instruction à la bonne ALU est complexe. Plus les unités de calcul sont hétérogènes, plus la logique de sélection est compliquée. Les logiques d'éveil comme de sélection sont assez complexes. Comme on le verra plus bas, la logique de sélection la plus simple, qui gère une seule unité de calcul, est basée sur un encodeur à priorité couplé à d'autres circuits. Et pour gérer plusieurs ALUs, il faut mettre des encodeurs en cascade. Le résultat est que même en prenant une logique de sélection simple, elle sera assez lente et gourmande en circuits. Aussi, la logique de sélection met souvent un cycle d'horloge entier pour faire son travail, elle a son propre étage de pipeline attribué. La logique d'éveil est dans le même cas, ce qui fait qu'émettre une micro-opération demande deux cycles d'horloge. Le défaut est que cela rajoute des cycles d'horloges entre la fenêtre d'instruction et l'ALU, ce qui complique la gestion du pipeline. Ces cycles de retard sont à prendre en compte au moment d'émettre les instructions, les ''scheduler'' doit en tenir compte pour des performances optimales. Sans tenir compte de ces cycles de retard, les instructions arrivent en retard de quelques cycles à l'ALU, cycles de retard durant lesquels l'ALU n'a pas fait de calcul et a été sous-utilisée, sans compter que le système de contournement n'est pas utilisé au mieux. Et le problème est encore plus important sur les processeurs avec des stations de réservation, qui utilisent la "lecture après émission" : cela rajoute un cycle d'horloge en plus, un temps de retard en plus. ===La logique d'éveil : l'émission anticipée=== La logique d'éveil doit tenir compte du fait qu'il y a plusieurs étages entre l'émission et l'exécution sur une unité de calcul. Par exemple, un processeur a souvent entre un et à cinq étages entre la file d'attente et les unités de calcul. Il faut lire les registres, gérer le contournement, et cela peut prendre quelques cycles d'horloge. Sur le Pentium 4, on trouve 6 étages entre la fenêtre d’instruction et l'entrée de l'ALU. Si les micro-opérations sont émises quand les opérandes sont disponibles, il y aura un délai de quelques cycles avant qu'elles atteignent l'ALU. Alors qu'idéalement, on souhaiterait que la micro-opération atteigne l'ALU dès que ses opérandes sont disponibles, pour profiter des techniques de contournement. Pour cela, la logique d'éveil émet les instructions quelques cycles en avance pour qu'elles arrivent au bon moment. Il s'agit d'une technique d''''émission anticipée''', dont nous avions parlé dans le chapitre sur le contournement. : Il faut noter que le problème se pose plus avec des fenêtres d'instruction qu'avec des stations de réservation. Les premières ont un étage en plus entre émission et ALU, vu qu'il faut lire des registres après l'émission. L'émission anticipée demande d'émettre un signal d'éveil en avance de quelques cycles, pile au bon moment. Par exemples, si on a deux étages entre l'ALU et l'unité d'émission, le signal de réveil sera généré deux cycles avant que le résultat soit effectivement calculé. L'implémentation varie, mais deux solutions sont possibles. La première est de générer le signal d'éveil dans l'ALU, ce qui n'a de sens que pour les opérations comme les multiplications ou les divisions, qui prennent plusieurs cycles. Une autre technique génère le signal de réveil dans une structure centralisée, spécialisée dans la génération des signaux d'éveil. L'unité de composée d'un registre à décalage par registre. Imaginons qu'une instruction est émise, que cette instruction mette N cycles à s'exécuter, et qu'elle écrive dans un registre de destination. L'unité sélectionne alors le registre à décalage associé au registre de destination, et met le bit numéro N à 1. Le registre décalé d'un cran à chaque cycle. Quand le bit sortant est un 1, alors le signal de validité pour l'opérande est généré. L'émission anticipée marche bien si l'instruction a une durée fixe, connue à l'avance. Et autant c'est le cas pour les instructions arithmétiques et logiques, autant ce n'est pas le cas pour les accès mémoire. Les accès mémoire ont une latence variable : quelques cycles pour un succès de cache, plusieurs dizaines de cycles pour un défaut de cache L1, pas loin de la centaine pour un défaut de cache L2, etc. Et cela pose des problèmes pour l'émission anticipée. L'émission en avance pour les accès mémoire est purement spéculative : le processeur émet des instructions en supposant que la lecture entrainera un succès de cache, quitte à annuler l'instruction en cas de défaut de cache. Mais faire ainsi demande non seulement d'annuler les instructions émises en avance, mais aussi de ne pas retirer les instructions émises en avance de la fenêtre d'instruction. Elles sont émises, mais une copie de sauvegarde est conservée dans la fenêtre d'instruction. Si le processeur détecte un défaut de cache, il peut alors ré-exécuter l'instruction. S'il détecte un succès de cache, les instructions lecture-dépendante sont retirées de la fenêtre d'instruction, la copie de sauvegarde est devenue inutile et est donc jetée. ===La logique de sélection : âge ou position ?=== La logique de sélection est primordiale pour de bonnes performances. Il existe deux méthodes principales pour sélectionner l'instruction à exécuter. La première est la plus simple : elle se base sur lé numéro de l'entrée. En effet, une fenêtre d'instruction est avant tout une sorte de mémoire, un mix entre mémoire associative, mémoire RAM, et FIFO. Et chaque entrée a un numéro, une adresse mémoire. Nous parlerons de numéro dans ce qui suit, car ce sera plus simple, le terme d'adresse mémoire étant peut-être un peu exagéré dans le contexte des fenêtres d'instruction. Toujours est-il que la fenêtre d'instruction est adressable dans le sens où on peut lui envoyer le numéro de l'entrée voulue, et la fenêtre d’instruction renvoie le contenu de l'entrée sur son port de lecture. Et c'est ce que fait la logique de sélection : elle génère le numéro de l'entrée à lire. Le numéro est alors envoyé sur l'entrée d'adresse de la fenêtre d’instruction, et elle fournit la micro-opération associée sur son port de lecture, son '''port d'émission'''. La première méthode de sélection, donc. Elle est basée sur le numéro de l'entrée. Si plusieurs entrées sont éveillées, la logique de sélection prend celle avec le plus petit numéro. Elle porte le nom de '''sélection par position''', sous-entendu position dans la fenêtre d'instruction. Vous l'avez peut-être deviné, mais la logique de sélection est alors un encodeur à priorité. Le circuit de sélection ne se résume donc pas seulement à un encodeur à priorité, mais c'est le circuit central. L'avantage d'une telle méthode de sélection est qu'elle est simple à implémenter : un encodeur à priorité est un circuit connu, facile à implémenter. Mais on remarque un défaut : un encodeur est un circuit assez rapide, mais qui utilise beaucoup de transistors, beaucoup de portes logiques, surtout si on veut qu'il soit rapide. Ce qui explique que la logique de sélection ait son propre étage de pipeline rien que pour elle. La seconde méthode s'appelle la '''sélection par âge''', au nom assez transparent. L'idée est de privilégier l'émission de l'instruction la plus ancienne. Elle demande que la fenêtre d'instruction trie les micro-opérations par ordre d'insertion dans la fenêtre d'instruction, ce qui en fait une pseudo-FIFO. Le tri est partiel, car les instructions peuvent sortir de la fenêtre d’instruction à tout moment. Compacter la fenêtre d'instruction, à savoir regrouper toutes les entrées valides est une idée, mais elle est compliquée à implémenter. Aussi, elles préfèrent encoder des informations sur l'ordre d'émission dans chaque entrée. L'encodeur à priorité doit alors travailler non pas sur des nombres entiers liés à l'ordre d'insertion dans la pseudo-FIFO. Elle est encore plus gourmande en circuits que la méthode précédente. Les processeurs haute performance utilisent souvent des méthodes hybrides. Par exemple, les processeurs AMD de microarchitecture Bulldozer utilisaient une méthode intermédiaire. Ils utilisaient une fenêtre d'instruction couplée à un encodeur à priorité pour la sélection par position, mais complémentaient le tout avec une unité qui mémorisait l'instruction la plus ancienne dans la fenêtre d’instruction. Le mécanisme de sélection par âge était utilisé en priorité. Mais si l'instruction la plus ancienne n'était pas prête, le processeur basculait sur le mécanisme de sélection par position. ===La compaction des fenêtres d'instruction=== À chaque cycle, les instructions décodées sont ajoutées dans la fenêtre d'instruction, dans des entrées vides. Vu que les instructions quittent celle-ci dans le désordre, ces vides sont dispersés dans la fenêtre d'instruction, ce qui pose problème pour déterminer où placer les nouvelles instructions. La solution la plus triviale consiste à conserver une liste des vides, mise à jour à chaque insertion ou émission d'instruction. Une autre solution consiste à éliminer les vides en compactant la fenêtre d'instruction à chaque cycle d'horloge. Des circuits se chargent de détecter les vides et de regrouper les instructions en un unique bloc. Il faut signaler que certains processeurs arrivent à se passer de cette étape de compactage, mais au prix de fenêtres d'instruction nettement plus complexes. Autre problème : quand il faut choisir quelle instruction émettre, il y a toujours plusieurs candidats. Si on choisit mal, des instructions restent en attente trop longtemps parce que d'autres instructions plus jeunes leur passent devant. Pour éviter cela, les instructions les plus vielles, les plus anciennes, sont prioritaires. Pour cela, on peut utiliser une FIFO un peu spéciale pour la fenêtre d'instruction. Si les ajouts d'instruction se font dans l'ordre, les instructions ne quittent pas forcément la fenêtre d'instruction dans l'ordre imposé par une FIFO : les instructions restent triées dans leur ordre d'ajout, même s'il y a des vides entre elles. Dans ces conditions, il est préférable que le compactage conserve l'ordre FIFO des instructions. Dans ces conditions, l'instruction la plus ancienne est celle qui est située à l'adresse la plus faible : le circuit de sélection peut donc être fabriqué avec des encodeurs, et est relativement simple. ==Les fenêtres d'instruction basées sur une matrice de dépendances== L'implémentation la plus simple étend le fonctionnement d'un pipeline dynamique usuel. Rappelez-vous le chapitre sur les pipelines dynamiques. Nous avions vu que de tels pipelines émettaient une instruction par cycle, quitte à émettre des bulles de pipeline en cas de dépendance bloquante. Et il est possible d'améliorer leur unité d'émission pour qu'elle soit compatible avec l'exécution dans le désordre. ===Rappels sur le registre de réservation/disponibilité=== L'émission d'une instruction est gouvernée par un ''registre de réservation'' qui indique quels registres sont réservés par une instruction, et ceux qui sont libres. Un registre réservé est un registre qui sera écrit par une instruction en cours d'exécution, mais qui n'a pas encore écrit son résultat. Les instructions candidates doivent avoir leurs opérandes dans des registres libres. Sinon, c'est signe que leurs opérandes sont réservés en écriture, donc pas encore écrites, donc pas disponibles. Si une instruction candidate veut lire ce registre, c'est signe qu'il y a une dépendance RAW : elle veut lire un registre réservé, qui est destiné à être écrit par une instruction en vol. Si elle veut écrire, c'est signe qu'elle veut écrire dans un registre où une autre instruction veut écrire : c'est une dépendance WAW. Dans les deux cas, l'instruction n'est pas émise. Le registre de réservation encode les registres réservés comme suit : chaque bit est associé à un registre. Le bit numéro 0 est associé au registre numéro 0, le bit numéro 1 au registre numéro 1, etc. Là, En clair, les numéros de registres réservés sont encodés en représentation non pas binaire, mais en représentation ''one-hot'' (vue au premier chapitre). {|class="wikitable" |+ Registre de réservation |- ! Registre 7 !! Registre 6 !! Registre 5 !! Registre 4 !! Registre 3 !! Registre 2 !! Registre 1 !! Registre 0 |- | 0 || 0 || 1 || 0 || 0 || 1 || 0 || 0 |} Avant d'émettre une instruction, l'unité d'émission extrait les registres opérande/destination et les convertis dans la même représentation que le registre de réservation, à savoir en représentation ''one-hot''. Le circuit de traduction binaire vers ''one-hot'' est, pour rappel, un simple décodeur. Puis, on fait un OU logique entre les sorties des décodeurs. Le résultat est un masque qui indique quels registres sont lus par l'instruction, encodé en représentation ''one-hot''. Appelons-le le '''masque d'opérandes'''. Le masque est alors comparé au registre de réservation pour vérifier si l'instruction peut être émise. [[File:Unité d'émission simple, dans l'ordre.png|centre|vignette|upright=2|Unité d'émission simple, dans l'ordre]] Si l'émission est autorisée, le registre de réservation est là aussi mis à jour. Le registre de réservation est aussi mis à jour dès qu'une instruction enregistre son résultat dans les registres, ou alors dès qu'il est disponible pour le contournement. Le bit associé au registre repasse alors à 0 (ou à 1). Sans contournement, la mise à jour se fait alors à la toute fin de l'instruction, quand elle se termine, lors de la dernière étape d'enregistrement, à la fin de son pipeline. Avec, elle se fait quand l'instruction quitte l'unité de calcul. ===L'extension à l'exécution dans le désordre : l'éveil par matrice de bits=== La différence entre un pipeline dynamique et l'exécution dans le désordre est que l'on passe d'une instruction à émettre à plusieurs. Plusieurs instructions sont mises en attente dans une fenêtre d’instruction, et y attendent leur tour. L'idée est alors d'envoyer le registre de disponibilité à toutes les entrées, à toutes les instructions en attente. Ainsi, on sait quelles sont les instructions qui peuvent s'exécuter et celles qui ne le peuvent pas. L'implémentation est assez simple, elle ressemble beaucoup à l'implémentation d'un pipeline dynamique simple, si ce n'est que des circuits sont dupliqués. L'implémentation utilise des fenêtres d'instruction légèrement différentes de celles introduites plus haut. Elles n'utilisent notamment pas de bits de disponibilité, mais autre chose. Lorsqu'une instruction est ajoutée à la fenêtre d'instruction, le masque de disponibilité des opérandes est stocké dans la fenêtre d'instruction. A chaque cycle, le registre de disponibilité est envoyé à toutes les entrées, et est comparé avec tous les masques de disponibilité des opérandes. Si une comparaison renvoie un 1, alors l'instruction de l'entrée est une instruction candidate à l'émission. [[File:Unité d'émission dans le désordre basée sur un registre de disponibilité.png|centre|vignette|upright=2.5|Unité d'émission dans le désordre basée sur un registre de disponibilité]] L'ensemble est implémenté avec l'aide d'une '''matrice de bits''', où chaque ligne correspond à une entrée et chaque colonne à un registre. À chaque croisement entre une ligne et une colonne, on trouve un bit. Si le bit de la ligne n et de la colonne m est à 1, cela veut dire : l'instruction dans l'entrée n a besoin de lire le registre m. S’il est à 0, alors cela veut dire que l'instruction stockée dans la ligne n'a pas besoin de la donnée dans le registre m. [[File:Planificateur à matrice de bits.jpg|centre|vignette|upright=2|Planificateur à matrice de bits.]] Lorsqu'une instruction réserve une entrée, elle initialise la ligne en fonction des registres qu'elle souhaite lire. Pour vérifier si une instruction a ses opérandes prêts, le processeur compare le registre de disponibilité à la ligne associée à l'instruction/entrée. A chaque intersection ligne-colonne, se trouve un comparateur de 1 bit, qui détecte si le registre est demandé et disponible. Les résultats de cette porte sont ensuite envoyés à une porte ET, qui fait le gros du travail. [[File:Logique de détection de la disponibilité d'une instruction.jpg|centre|vignette|upright=2|Logique de détection de la disponibilité d'une instruction.]] ==Les fenêtres d'instruction basées sur une mémoire associative== Les processeurs modernes utilisent une mémoire associative pour la fenêtre d'instruction. Les mémoires associatives ont été abordées il y a quelques chapitres, mais faisons quelques rappels. Les mémoires associatives servent à accélérer la recherche de données dans un ensemble. Or, une fenêtre d'instruction vérifie régulièrement si chaque entrée est prête. Il s'agit d'un processus de recherche d'une instruction qui respecte une condition bien précise dans la mémoire, ce qui fait que les mémoires associatives sont donc tout indiquées. Comme vous le savez, les signaux de commande d'une instruction sont propagés avec celle-ci dans le pipeline, le nom du registre de destination ne faisant pas exception. Le nom de registre est envoyé à la fenêtre d'instruction lors de l'écriture du résultat dans les registres. S'il y a correspondance, l'opérande est disponible et son bit de disponibilité est mis à 1. On peut adapter cette méthode pour tenir compte du contournement assez simplement. [[File:Détection des dépendances par propagation du registre de destination.png|centre|vignette|upright=2|Détection des dépendances par propagation du registre de destination.]] En conséquence, le circuit de détection des dépendances est constitué d'un grand nombre de comparateurs : un par champ « nom de registre » dans chaque entrée. La logique d'éveil/''wake up'' regroupe tous les comparateurs, la logique de sélection est un circuit situé en-dehors de la mémoire associative. Les entrées sont dans la mémoire associative elle-même. [[File:Gestion des bits de validité.png|centre|vignette|upright=2|Gestion des bits de validité.]] L'implémentation la plus simple est celle du schéma précédent, où on utilise une mémoire associative unique. Une version plus élaborée sépare la fenêtre d'instruction en deux parties : une mémoire qui mémorise les registres des opérandes, une autre mémoire pour le reste. La mémoire pour les registres opérandes est la mémoire associative proprement dite, c'est elle qui est associée aux comparateurs, à la logique de ''wake-up''/réveil, etc. Par contre, l'autre mémoire est une mémoire RAM simplifiée, qui mémorise les informations qui n'ont pas besoin des comparateurs. L'opcode de l'instruction est là-dedans, par exemple. La fenêtre d'instruction est donc une sorte de mémoire associative améliorée. Il se trouve que c'est aussi le cas du ROB. Et il est possible de fusionner le tampon de ré-ordonnancement avec la fenêtre d'instruction dans une structure unique. La différence avec une fenêtre d’instruction normale est que les entrées sont libérées non pas quand l'instruction est exécutée/émise, mais quand elle termine son exécution et quitte le ROB. La fenêtre d'instruction incorpore des bits dans chaque entrée, pour savoir si la µops associée a été émise et est en cours de traitement dans les ALUs. La méthode a notamment été utilisée sur les processeurs d'architecture K6 d'AMD. Le tout donnait une structure appelée le '''DRIS''' (''deferred scheduling register renaming instruction shelf''). Les processeurs PA 8000 de HP étaient aussi vraisemblabment dans ce cas, aussi. ===Les optimisations de la consommation d'énergie : la désactivation des portions inutilisées=== Le problème avec des fenêtres d'instruction de ce type est leur forte consommation énergétique, ainsi que le grand nombre de portes logiques utilisées, qui deviennent prohibitifs pour des fenêtres d'instruction un peu grosses. Pour résoudre ce problème, certains ont optimisé les comparateurs. D'autres ont tenté de profiter du fait que la majorité des bits dans les entrées sont composés de zéros. Bref, les optimisations purement matérielles sont légion. Une première solution est de désactiver les entrées qui sont inutilisées, vides, sans instruction. Pour cela, on fait précéder les comparateurs par un circuit qui les connecte ou déconnecte des lignes de bit. Le circuit est commandé par le bit ''empty'' qui indique si une entrée est vide ou non. L'avantage est que la consommation d'énergie de la fenêtre d'instruction devient alors proportionnelle au nombre d'entrées non-vides, et non au nombre d'entrées total. Du moins, en apparence, les entrées non-utilisées doivent quand même être alimentées pour fonctionner, mais l'activité de comparaison disparait dans les entrées vides. Il est possible d'étendre cette technique aux entrées dont les opérandes sont prêts. Les gains sont généralement assez bons, avec une réduction de consommation variant entre 30 et 50%, avec une implémentation très simple et très économe en circuits. Une autre solution, assez simple à mettre en place, consiste à désactiver une partie de la fenêtre d'instruction sin elle est inutilisée. Pour cela, il faut segmenter la fenêtre d'instruction avec la technique du ''wire partitionning''. Pour rappel, une fenêtre d'instruction est une mémoire associative. Et comme toute mémoire associative, elle contient des fils, les lignes de bit, qui relient les entrées/sorties à toutes les cellules mémoire. Plus une ligne de bit est longue, plus elle consomme d'énergie et plus le temps de lecture/écriture est long. L'idée est de segmenter les lignes de bits en plaçant des répéteurs qui recopient la tension d'un segment au suivant. Les répéteurs sont des tampons trois-états, ce qui permet de déconnecter les portions inutilisées de la ligne de bit. Ce faisant, la fenêtre d'instruction est découpée en segments, qui peuvent être désactivés si besoin. S'il y a peu d'instructions chargées dans la fenêtre d'instruction, les portions inutilisées sont désactivées. La technique marche d'autan mieux si les instructions sont compactées au début de la fenêtre d'instruction. [[File:Wire partitionning.png|centre|vignette|upright=2|Wire partitionning]] Tout le problème est de savoir quelles portions désactiver. La technique est assez simple si la fenêtre d'instruction est compactée, à savoir si toutes les instructions sont régulièrement regroupées au début de la mémoire CAM. Mais même avec cette optimisation, la décision de désactiver une portion de la fenêtre d'instruction n'est pas à prendre à la légère. Il ne faut pas désactiver une portion contenant des instructions pouvant être émise sous peu. La décision dépend de paramètres variés : proportion d'entrée vides, quantité d'entrées récemment activées/désactivées récemment, présences d'entrées avec un ''match'' d'opérandes récent, etc. Il est important de préciser que les techniques en question fonctionnent aussi sur les autres types de fenêtre d'instruction, qui ne sont pas basées sur des mémoires associatives. Nous allons voir celles-ci dans la suite du chapitre, mais gardez à l'esprit que ces optimisations, à savoir désactiver les entrées vides/prêts et partitionner la fenêtre d'instruction, sont des optimisations générales qui marchent avec presque tout. ===L'ajout d'une FIFO pour les instructions déjà prêtes à l'émission=== D'autres techniques permettent de réduire aussi bien le cout en circuits que la consommation d'énergie de la fenêtre d'instruction. L'idée est d'utiliser une mémoire associative quand elle est réellement nécessaire, mais d'utiliser une fenêtre d'instruction "normale" dès que possible. La méthode la plus simple tient compte du fait que certaines µopsont déjà toutes leurs opérandes de disponibles à l'émission, mais doivent quand même être mises en attente, parce que l'ALU adéquate est occupée, parce que des dépendances WAW/WAR sont encore là, ou pour tout autre raison. Dans ce cas, elles sont mises en attente non pas dans la fenêtre d'instruction, mais dans une mémoire FIFO toute simple. L'idée est qu'au lieu d'avoir une énorme mémoire associative pour la fenêtre d'instruction, on déplace quelques entrées dans une petite FIFO annexe. Le résultat est un gain d'énergie et de circuits, au prix d'une perte de performance mineure. La perte de performance en question se manifeste si aucune instruction n'a ses opérandes de prêtes à l'émission : le programme n'utilise pas la FIFO et voit alors une fenêtre d'instruction plus petite. Une amélioration de cette technique tient compte du fait que certaines instructions sont dans un cas intermédiaire. Elles ont déjà un opérande de prête lors de l'émission, mais pas l'autre. Le nombre d'opérandes varie suivant l’instruction : certaines n'ont besoin que d'un seul opérande. De plus, il arrive qu'une opération tout juste décodée ait déjà un ou plusieurs de ses opérandes de prêts. Cette constatation permet d'éviter d'utiliser des comparateurs pour les opérandes déjà prêts. Par exemple, on peut parfaitement utiliser trois fenêtres d'instruction : * une pour les instructions dont tous les opérandes sont prêts, mais qui sont quand même mises en attente, sans comparateur ; * une pour les instructions dont un seul opérande manque, qui n'utilise qu'un comparateur par entrée ; * une pour les instructions dont deux opérandes manquent à l'appel, qui utilise deux comparateurs par entrée. C'est beaucoup plus économique que d'utiliser une seule grosse fenêtre d'instruction qui contiendrait autant d'entrées que les trois précédentes réunies, avec deux comparateurs par entrée. Certains sont même allés plus loin, et ont proposé de supprimer la fenêtre d'instruction avec deux opérandes par entrée. Les instructions dont deux opérandes sont inconnus au décodage sont stockées dans la fenêtre d'instruction pour instructions avec un comparateur par entrée. Un circuit de prédiction se charge alors de prédire l'opérande manquant, cette prédiction étant vérifiée plus loin dans le pipeline. Il serait cependant étonnant qu'une telle proposition ait donné lieu à la moindre implémentation réelle. ===Les optimisations de la consommation d'énergie avancées=== D'autres chercheurs ont conservé une fenêtre d'instruction unique, avec autant de comparateurs par entrée qu'il y a d'opérandes possibles par instruction. Simplement, le processus de détection des opérandes prêts est légèrement ralenti : on ne vérifie qu'un opérande par cycle. Pour vérifier les deux opérandes d'une entrée, on doit attendre deux cycles. Enfin, certains chercheurs ont proposé des fenêtres d'instruction segmentées. Les instructions circulent à chaque cycle d'un segment vers le suivant : en conséquence, certains segments conservent les instructions les plus anciennes, un autre les instructions les plus jeunes, etc. Seul le denier segment, celui qui contient les instructions les plus vielles, peut émettre une instruction : la détection des opérandes se fait seulement dans le dernier segment, qui contient les instructions les plus anciennes. On économise ainsi beaucoup de comparateurs. Certains chercheurs ont tenté de pipeliner l'étape de sélection des opérandes, ainsi que l'étage d'arbitrage. Mais en faisant cela, il faut plusieurs cycles pour détecter qu'une instruction a ses opérandes prêts, ce qui pose problème face à de nombreuses dépendances RAW. Pour éviter de trop perdre en performances, certains chercheurs ont décidé d'utiliser des techniques pour prédire quelles seront les instructions dont les opérandes seront bientôt prêts. Si détecter qu'une instruction est prête prend n cycles, le processeur devra tenter de prédire la future disponibilité des opérandes n cycles en avance pour obtenir des performances optimales. ===Remplacer la mémoire associative par une RAM=== Une autre optimisation possible est de remplacer la fenêtre d'instruction par une mémoire RAM, dont chaque mot mémoire correspondrait à une entrée. Une telle optimisation permet en théorie de se passer des comparateurs associés à chaque entrée, mais au prix de l'ajout de circuits annexes potentiellement couteux. La première de ces techniques, la '''recherche directe par étiquette''' (direct tag search) fut créée par Weiss et son collègue Smith. Ils cherchaient à améliorer l'algorithme de Tomasulo, un algorithme qu'on expliquera dans quelques chapitres. Rappelons que chaque instruction produit un résultat, qui devra être rapatrié dans une ou plusieurs entrées de la fenêtre d'instruction. L'optimisation de la recherche directe par étiquette fonctionne dans le cas où le résultat de l'instruction n'est utilisé que par une seule entrée, et pas plusieurs. Le principe est simple : chaque champ « opérande » d'une entrée est adressable via le nom de registre de cet opérande. Pour faire le lien entre entrée et nom de registre, la recherche directe par étiquette ajoute une table de correspondances matérielle, une mémoire RAM qui mémorise les adresses des champs « opérande » des entrées. Les adresses envoyées dans cette mémoire sont les noms de registres des résultats. Lors de l'émission, la table de correspondances est mise à jour. Les numéros des champs « opérande » réservés lors de l'émission sont mémorisés dans les mots mémoire qui correspondent aux deux registres sources. Toutefois, une petite vérification est faite lors de l'émission : s'il y a déjà une correspondance dans la table pour un registre source, alors une autre instruction compte lire ce registre. Pour éviter d'écraser les données de l'instruction précédente dans la table de correspondances, l'émission de l'instruction est bloquée. [[File:Recherche directe par étiquette.png|centre|vignette|upright=2|Recherche directe par étiquette.]] ==Les fenêtres d’instruction avec préplanification== Avec la '''préplanification''' (''prescheduling''), la fenêtre d’instruction est composée de mémoires FIFO dans lesquelles les instructions sont triées dans l'ordre d'émission. Il n'y a pas de logique d’émission proprement dite, celle-ci se bornant à vérifier si l'instruction située au début de la FIFO peut s’exécuter. Par contre, le préplanificateur détecte les dépendances et en déduit où insérer les instructions dans le tampon d'émission, à l'endroit le plus adéquat. [[File:Préplanification.jpg|centre|vignette|upright=2|Préplanification.]] ===L'usage de FIFO multiples=== La technique de préplanification la plus simple utilise plusieurs FIFO. Quand une instruction a une dépendance avec une autre instruction, les deux sont placées dans la même FIFO. Pour cela, le préplanificateur détecte les chaines d'instructions dépendantes, et place les instructions dans la FIFO adéquate. A chaque cycle, l'unité d'émission lit une micro-opération dans chaque FIFO et vérifie si elle peut l'émettre. Si la micro-opération n'a pas ses opérandes disponibles, ou qu'une dépendance structurelle survient, alors la FIFO est bloquée. La micro-opération attend que la dépendance soit résolue, bloquant toutes les instructions précédentes. Mais les autres FIFO ne sont pas bloquées, laissant de la marge de manœuvre. [[File:Préplanification par FIFO multiples.png|centre|vignette|upright=1.5|Préplanification par FIFO multiples.]] ===La technique du tampon trié=== La technique du '''tampon trié''' trie les instructions selon le temps d'attente avant leur exécution. Les instructions qui sont censées s’exécuter bientôt sont insérées au tout début de la FIFO, tandis que les instructions qui s’exécuteront dans un long moment sont insérées vers la fin. Là encore, l'unité d'émission lit une micro-opération dans la FIFO, et détermine si elle peut être émise. Si une dépendance survient, l'émission est retardée, et la FIFO est bloquée. [[File:Préplanification par tampon trié.png|centre|vignette|upright=1.5|Préplanification par tampon trié.]] La technique a cependant quelques problèmes assez importants. Le premier problème est que la FIFO est bloquée lorsqu'une micro-opération ne peut être émise. Le second problème est que le temps avant exécution n'est pas toujours connu, notamment pour les instructions d'accès mémoire. Et cela se répercute sur les instructions dépendantes de celles-ci. Pour résoudre ce genre de problèmes, l'usage d'un pipeline à ''replay'' est possible, et est même l'une des meilleures solutions possible, malgré ses défauts. L'idée est que les lectures sont pré-planifiées en supposant qu'elles font un succès de cache L1. Si la prédiction est fausse, la lecture est ré-exécutée plusieurs cycles plus tard, en supposant qu'elle fait un succès dans le cache L2, et ainsi de suite. Elle est alors ré-insérée dans la FIFO, elle est pré-planifiée une seconde fois. Il en est de même si une micro-opération ne peut pas être émise : il suffit de la réinsérer dans la FIFO au bon endroit, en attendant que ses dépendances soient résolues. Ainsi, l'instruction fautive ne bloque pas la fenêtre d’instruction, et retente sa chance autant de fois qu'il le faut. [[File:Préplanification par fenêtre d’instruction scorebarodée.png|centre|vignette|upright=1.5|Préplanification par fenêtre d’instruction scorebarodée.]] Une autre solution utilise deux fenêtres d’instruction : une FIFO gérée par la préplanification, et une vraie fenêtre d'instruction pour les instructions dont le temps d'attente ne peut pas être déterminé. Il est possible de mettre cette dernière avant la préplanification, afin de gérer les temps d'attente des instructions d'accès mémoire. Quand le temps d'attente d'une lecture devient connu, ses instructions dépendantes sont gérées avec préplanification. [[File:Préplanification avec fenêtre d’instruction.png|centre|vignette|upright=2.5|Préplanification avec fenêtre d’instruction.]] ===Les fenêtres d'instruction avec allocation temporelle statique=== L''''allocation temporelle statique''' correspond à une technique utilisée sur les processeurs Cuzco de l'entreprise Condor. La technique en question a été présenté en 2025, mais des idées similaires ont été présentées dans la littérature académique. Elle ressemble beaucoup aux techniques de pré-planification, avec cependant quelques différences. L'idée est simple : le processeur dispose de plusieurs fenêtres d'instruction, qui mettent en attente les micro-opérations. Lors de l'étape de renommage de registres, le processeur détermine dans combien de cycles d'horloge la micro-opération sera prête pour exécution. La micro-opération est alors mise en attente durant ce nombre de cycles, dans les fenêtres d'instruction, puis est émise une fois ce nombre de cycles écoulés. Ce faisant, les fenêtres d'instruction n'ont pas besoin de détecter la disponibilité des opérandes à chaque cycle, pour chaque micro-opération en attente. Le ''timing'' de l'émission des micro-opérations est décidé à l'avance. L'implémentation exacte n'est pas connue, mais plusieurs solutions sont imaginables. Par exemple, la fenêtre d'instruction peut simplement être composée de plusieurs mémoires de petite taille, chacune contenant les micro-opérations destinées à être exécutées dans N cycles, N étant différent pour chaque mémoire. Une autre solution, plus réaliste, utilise une fenêtre d'instruction dans laquelle la micro-opération est couplée à des champs pour les opérandes, et un champ compteur. Le champ compteur est initialisé avec le nombre de cycles à attendre, et est décrémenté à chaque cycle d'horloge. Quand il atteint zéro, la micro-opération est émise. Vous remarquerez que la méthode ne marche que si toutes les micro-opérations prennent un nombre fixe de cycles d'horloge. Et autant c'est le cas pour les micro-opérations arithmétiques ou logiques, autant les accès mémoire ne rentrent pas dans ce cadre. En théorie, on ne sait pas combien de temps prendra un accès mémoire. Et cette incertitude se répercute sur les instructions dépendantes d'un accès mémoire. Pour éviter cela, le processeur réutilise un pipeline à ''replay'' tel que vu dans le chapitre précédent. L'unité de renommage de registre suppose que tout accès mémoire fait un succès de cache L1, et décide des ''timings'' d'émission sous cette hypothèse. Si une lecture subit un défaut de cache, elle est ré-exécutée, de même que toutes les instructions dépendantes. Pour cela, le registre de destination de la lecture est marqué comme invalide, grâce à un bit spécifique attaché au registre. Toute instruction qui lit un opérande invalide est elle aussi ré-executée de zéro. Pour simplifier, l'unité d'émission ressemble à une unité d'émission dans l'ordre, avec un registre de disponibilité, qu'on aurait amélioré pour aller au-delà de la simple détection des dépendances d'instruction. Pour déterminer les ''timings'' d'émission, à savoir quand émettre une micro-opération, le processeur utilise une unité d'émission à deux étages. Le premier étage est appelé le ''register scoreboard'', le second étage est appelé la ''Time Ressource Matrix''. Les deux étages communiquent entre eux, comme on va le voir, et leurs noms donnent une idée de ce qu'ils font. Le premier étage gère les dépendances de registres, le second gère les dépendances structurelles. Le premier étage est un registre de disponibilité amélioré, qui gère les dépendances de registre. Cet étage sait quand tel registre sera écrit, et donc que l'opérande écrit dedans sera disponible à partir de tel cycle d'horloge. Il le sait car l'étage suivant l'aura prévenu, mais laissons cela de côté pour le moment. Quand une micro-opération rentre dans cet étage, il vérifie les dépendances avec les registres et les micro-opérations antérieures. Vu qu'il sait quand les registres seront disponibles, il peut déterminer quand l'instruction pourra s'exécuter. Par exemple, si une micro-opération lit les deux registres R7 et R15, qui sont disponibles respectivement dans 5 et 7 cycles, le premier étage sait que la micro-opération devra attendre 7 cycles. Mais tout cela ne suffit pas à déterminer quand émettre une micro-opération. En effet, il fait aussi gérer les dépendances structurelles, ce qui est le boulot du second étage. Le second étage utilise pour cela une ''Time Ressource Matrix'', qui mémorise l'occupation de diverses "ressources", pour les 256 cycles d'horloge à venir. Les ressources en question sont les ports de lecture/écriture du banc de registre, les ALUs utilisées, si la micro-opération utilise l'unité mémoire, etc. Le second étage prend en entrée une micro-opération, détermine quelles "ressources" elle utilise, puis regarde leur disponibilité. Elle détecte alors les dépendances structurelles et détermine alors quand peut s'exécuter la micro-opération. Elle peut retarder l'émission de quelques cycles, si une dépendance structurelle est détectée. Une fois sortie du second étage, on sait quand la micro-opération va être émise, à quel cycle précisément. Et vu que la durée de l'instruction est fixe, on sait quand cette micro-opération va se terminer, quand son résultat sera disponible. Cela permet de mettre à jour la ''Time Ressource Matrix'', pour préciser que le port d'écriture sera occupé à tel moment. De plus, cette information est transmise au premier étage, qui sait alors quand est enregistré le résultat dans le registre de destination. C'est comme cela que le premier étage sait quand un registre est disponible : le second étage le prévient, quand il émet une instruction ! La ''Time Ressource Matrix''mémorise l'occupation des "ressources" pour les 256 cycles d'horloge à venir. Cependant, elle ne vérifie pas les dépendances pour les 256 cycles suivants. Quand elle reçoit une micro-opération, elle teste les dépendances structurelles pour seulement les 8 prochains cycles maximum. Si la micro-opération ne peut pas être émise pendant ces 8 cycles, le pipeline est bloqué, un ''pipeline stall'' est émis. Pour être plus précis, vu que le processeur peut décoder 8 micro-opérations en même temps, cela permet de ne consulter que 64 cycles d'horloge sur les 256. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les premiers processeurs Intel | prevText=Les premiers processeurs Intel | next=Le renommage de registres | nextText=Le renommage de registres }} </noinclude> 1l40r8zhw15ipl63dhajjzizf3s4bzf 773610 773609 2026-09-29T20:15:43Z Mewtow 31375 /* Les fenêtres d’instruction : généralités */ 773610 wikitext text/x-wiki Dans les chapitres précédents, nous avons parlé des techniques dites d''''émission dans l'ordre'''. L'idée est d’exécuter une nouvelle micro-opération à chaque cycle, dans des unités de calcul séparées. Les instructions sont émises consécutivement, mais les instructions s’exécutent en parallèle dans des unités de calcul séparées. Par contre, quand l'unité d'émission ne peut pas émettre une instruction, elle bloque tout le pipeline. Les instructions qui suivent sont elles aussi bloquées, elles doivent attendre leur tour, même si elles sont en capacité de s'exécuter. Les techniques d'exécution dans le désordre que nous allons voir dans ce chapitre corrigent ce point précis. Elles sont dites à '''émission dans le désordre'''. Elles se distinguent des précédentes sur un point précis : quand l'unité d'émission bloque l'émission d'une instruction, les instructions suivantes peuvent poursuivre. L'émission des instructions peut donc se faire dans le désordre, dans le sens où une instruction peut être émise alors qu'une instruction précédente ne l'est pas encore. L'avantage de l'émission dans le désordre est qu'une instruction s'exécute dès que ses opérandes sont disponibles. Par disponible, on veut dire présent soit dans le réseau de contournement, soit dans les registres. Le processeur détecte automatiquement quand les opérandes d'une instruction sont disponibles, et il l’exécute à ce moment-là. Dès qu'une instruction a ses opérandes disponibles, elle est émise et exécutée. C'est là la seule contrainte : les dépendances WAR, WAW et autres sont gérées par un ROB ou toute autre technique d'exception précise, seules les dépendances RAW limitent l'exécution. Mais avant de poursuivre, quelques point niveaux terminologie : * L'émission dans le désordre est un terme parlant et assez précis. Malheureusement, la terminologie la plus utilisée par d''''exécution dans le désordre'''. Et nous utiliserons ce terme dans la suite du cours, histoire de ne pas trop dévier de la nomenclature habituelle. * Nous utiliserons parfois l'abréviation OOO pour parler d'exécution dans le désordre. L'abréviation est celle de ''Out Of Order Excution''. * Nous utiliserons aussi l'abréviation ''µop'' pour parler de micro-opération, ''µops'' au pluriel pour parler de plusieurs micro-opérations, ou des micro-opérations en général. L'exécution dans le désordre ne gère en effet que des µops, elle se situe après l'étape de décodage. Mais avant de poursuivre, précisons une chose importante : l'exécution dans le désordre traite les accès mémoire à part. La majorité des processeurs OOO assez anciens exécutent les accès mémoire dans l'ordre, seules les µops entières/flottantes/branchements sont exécutées dans le désordre. Les processeurs datant d'après les années 2010 sont capable d'exécuter les accès mémoire dans le désordre, mais l'implémentation en question est assez particulière. Un chapitre entier sera dédié à l'exécution dans le désordre des µops mémoire. Nous allons volontairement mettre de côté la gestion des accès mémoire dans ce chapitre. ==Les fenêtres d’instruction : généralités== Pour décrire comment est implémentée l'émission dans le désordre, il faut commencer par parler des processeurs sans. Les processeurs sans exécution dans le désordre ont une unité d'émission qui bloque tout le pipeline dès qu'une µop ne peut pas être émise. Pour limiter l'impact de ce blocage, quelques rares processeurs incorporent une '''file de micro-opération''', une mémoire FIFO qui met en attente les µops. Vu que c'est une mémoire FIFO, les µops sont émises dans l'ordre, à savoir l'ordre d'ajout, dans l'ordre de décodage. Le schéma ci-dessous illustre une telle file d'attente couplée à un ''scoreboard''. Sur le principe, l'exécution dans le désordre améliore la file de µops sur un point : ce n'est plus une mémoire FIFO. Les µops sont insérées dans l'ordre, mais peuvent sortir dans le désordre (être émises dans le désordre). La file de µops devient alors une '''fenêtre d'instruction''', terme traduit directement de l'anglais ''instruction Window''. Terme assez trompeur, car elles mettent en attente des µops, pas des instructions. Elles peuvent émettre des µops dans le désordre, ce qui fait que si une µop bloque le pipeline, les µops suivantes peuvent être émises. [[File:Différence file µops et fenêtres instruction.png|centre|vignette|upright=2|Différence file µops et fenêtres instruction]] Je commence le paragraphe précédent par "sur le principe", car certaines techniques d'OOO n'utilisent pas de fenêtre d'instrruction. Dans les grandes lignes, il existe dans les grandes lignes 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! File de µops améliorée |- ! Une seule "file de µops" | ''Scoreboard'' | Fenêtre d'instruction centralisée |- ! Plusieurs "file de µops" | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | Fenêtre d'instruction décentralisée |} Voyons les dans le détail. ===La fenêtre d'instruction centralisée=== L'implémentation la plus simple de l'OOO utilise une unique fenêtre d'instruction, appelée une '''fenêtre d'instruction centralisée'''. Les µops décodées sont accumulées dans la fenêtre d'instruction, où elles attendent que leurs opérandes soient disponibles. La fenêtre d'instruction sert donc de file d'attente. Mais elle contient aussi une unité d'émission, qui détecte quelles µops sont prêtes à être émises. L'unité d'émission et la fenêtre d'instruction sont fusionnées ensemble, elles forment un seul circuit. Mais nous allons dire qu'elles sont conceptuellement séparées pour le moment. A chaque cycle, l'unité d'émission consulte la fenêtre d'instruction pour voir quelles µops peuvent s'exécuter, lesquelles ont leurs opérandes de disponibles. La fenêtre d'instruction doit spécialement être conçue pour, c'est une sorte de mémoire associative très complexe, comme on le verra dans ce qui suit. [[File:OOO Issue.png|centre|vignette|upright=2.5|Exécution dans le désordre avec une fenêtre d'instruction]] Une fois qu'une µop sort du décodeur d'instructions, elle est ajoutée en parallèle dans la fenêtre d'instruction et le ROB. La raison est que les µops quittent la fenêtre d'instruction dans le désordre, et qu'elles doivent être remises en ordre par la suite. Le ROB s'occupe de cette remise en ordre, mais il a besoin de savoir dans quel ordre les µops sont censées être, et cet ordre est celui du décodage. Aussi, pour remplir le ROB, la seule opportunité est en sortie de l'unité de décodage. Dans le cas où une instruction est décodée en plusieurs micro-opérations, elles sont toutes insérées en même temps dans la fenêtre d'instruction et le ROB, en tenant compte de leur ordre. [[File:Fenêtre d'instruction.png|centre|vignette|upright=2|Fenêtre d'instruction.]] Les micro-opérations mémoire sont à part des autres, pour diverses raisons. Une de ces raisons est que les dépendances de données sont classées en deux types : les dépendances de registre et les dépendances d'adresse. Et les deux sont fondamentalement différentes. Autant on peut détecter les dépendances de registre lors de l'émission, autant c'est plus compliqué avec les dépendances d'adresse. De plus, rappelons que si les lectures peuvent s'exécuter dans le désordre, les écritures doivent s'exécuter dans l'ordre, ou du moins en donner l'illusion. Pour cela, le processeur remet les écritures dans l'ordre avec une sorte de mini-ROB intégré à l'unité mémoire, appelée la file d'écriture. Elle complémente le ROB, qui lui ne gère que les écritures dans les registres, mais les deux collaborent. La file d'écriture envoie une écriture à la mémoire RAM quand le ROB lui dit que c'est bon, les instructions précédentes sont terminées ''dans l'ordre du programme''. Les processeurs modernes ajoutent des techniques d'exécution dans le désordre des accès mémoire, mais nous les verrons dans un chapitre dédié. Elles permettent d'utiliser une fenêtre d'instruction unique, qui mémorise aussi les µops mémoire. Si elles sont mises en place, l'unité mémoire n'a pas besoin de file de µops séparée. L'idée est que les dépendances de registre sont traitées par la fenêtre d'instruction, mais que l'unité mémoire gére les dépendances d'adresse. Les dépendances d'adresse sont gérées par des techniques de ''désambiguation mémoire'', qui auront droit à un chapitre dédié. [[File:Processeur avec exécution dans le désodre des accès mémoire.png|centre|vignette|upright=2|Processeur avec exécution dans le désodre des accès mémoire]] Les processeurs assez anciens n'autorisaient pas d'exécution dans le désordre des accès mémoire. Concrétement, les accs mémoire devaient se faire dans l'ordre, mais les autres µops pouvaient être exécutées dans le désordre. Il s'agit donc d'un ordre entre µops mémoire, pas entre µops mémoire et autres µops. Les µops entières et flottantes pouvaient être exécutées avant une µops mémoire qui est avant elle dans l'ordre du programme, ce n'est pas un problème. Pour garantir l'ordre desd µops mémoire, l'unité mémoire est précédée par une file de micro-opérations séparée, pour forcer l'exécution dans l'ordre des accès mémoire. De plus, les µops mémoire ne peuvent pas utiliser la fenêtre d'instruction. Dit autrement, la fenêtre d'instruction ne mémorise pas de µops mémoire. Après le décodage, les µops sont réparties soit dans la file de µops mémoire, soit dans la fenêtre d'instruction. Le décodeur classe les µops suivant que ce sont des µops mémoire ou non, et les envoient à la bonne destination. Dans ce chapitre, on supposera que c'est cette solution qui est utilisée. [[File:Processeur avec émission dans l'ordre des accès mémoire.png|centre|vignette|upright=2|Processeur avec émission dans l'ordre des accès mémoire]] La solution précédente revient à scinder la fenêtre d'instruction en deux : une file de µops pour les µops mémoire, une fenêtre d'instruction pour les autres µops. Et cette scission peut aller plus loin, à savoir qu'on peut scinder une fenêtre d'instruction encore et encore. Ce qui nous amène à la section suivante. ===Les fenêtres d'instruction décentralisées=== Nous venons de voir qu'il est possible de scinder la fenêtre d'instruction en une fenêtre d'instruction pour les µops mémoire (simplifiée en une file de µops classique), et une autre pour les autres µops. Sachez qu'il est possible d'aller plus loin, par exemple en séparant la fenêtre d'instruction en une fenêtre spécialisée dans les µops flottantes et une autre pour les µops entières. Et ce n'est là qu'un exemple parmi de nombreuses autres possibilités. Pour faire la différence avec une fenêtre d'instruction unique, nous allons parler de fenêtre d'instruction centralisée s'il n'y en a qu'une, de '''fenêtre d'instruction décentralisée''' s'il y en a plusieurs. Il est possible d'associer chaque fenêtre d'instruction à un type précis de µops. Par exemple, avec une fenêtre d'instruction pour les µops de calcul entières, une autre pour les µops flottantes, une autre pour les µops mémoire. Il s'agit d'un choix simple et efficace, mais quelques processeurs font autrement, pour répondre à des contraintes très diverses. [[File:Processeur avec des fenêtres d'instruction décentralisées.png|centre|vignette|upright=2|Processeur avec des fenêtres d'instruction décentralisées]] Reste à scinder la fenêtre d'instruction pour trier les µops suivant leur type. Si le processeur exécute les accès mémoire dans l'ordre, la méthode la plus simple utilise une fenêtre d'instruction pour les opérations flottantes et une autre pour les autres µops (µops entières et parfois mémoire avec). L'avantage est que cela simplifie grandement le processeur. Les flottants sont gérés à part des entiers. Ils ont leurs propres registres, des FPU séparées des ALU entières, bref : la séparation est complète. Utiliser une fenêtre d'instruction séparée va dans ce sens. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Il est possible de faire pareil sur les processeurs avec exécution dans le désordre des accès mémoire. Par exemple : les processeurs Intel de microarchitecture Skylake utilisent une fenêtre d'instruction pour les opérations entières/flottantes, et une fenêtre d'instruction séparée pour les µops mémoire. Un avantage est que les deux fenêtres d'instructions sont plus spécialisées, ce qui entraine des économies de circuit. Les opérations entières/flottantes ont besoin de deux registres pour les opérandes et d'un autre résultat, alors que les µops mémoire n'ont besoin que de deux registres maximum. En utilisant une fenêtre d'instruction unique, chaque entrée doit mémoriser l'opcode et trois registres, dont un est inutilisé pour les µops mémoire et les branchements. En utilisant des fenêtres d’instructions séparées, celle pour les µops entières/flottantes a trois registres par entrée, contre seulement deux registres par entrée pour celle des µops mémoire. Un cas extrême est celui où chaque ALU/FPU a sa propre fenêtre d'instruction. Nous parlerons alors de '''fenêtres d'instruction totalement décentralisées'''. Par exemple, il y a une fenêtre d'instruction pour l'ALU entière, une autre pour le multiplieur entier, une autre pour le ''barrel shifter'', une autre pour l'unité mémoire, une autre pour l'unitéé de branchements, une autre pour l'additionneur flottant, une dernière pour le multiplier flottant, etc. Un exemple historique est celui de la FPU de l'IBM 360 modèle 90. Elle disposait d'un additionneur flottant, d'un multiplieur flottant, et d'une unité mémoire pour les lectures/écritures flottantes. Les trois unités avaient leur propre fenêtre d'instruction. Les processeurs AMD utilisent beaucoup cette technique, contrairement à Intel qui préfère utiliser des fenêtres centralisées sur les anciens processeurs, deux ou trois fenêtres sur les processeurs récents (2020 et plus). Les processeurs AMD utilisaient précisément une fenêtre d'instruction par ALU entière, alors que les FPUs partagent une fenêtre d’instructions flottantes unique. Mais nous verrons cela en détail dans le chapitre sur les processeurs superscalaires x86. Un point important est qu'avec des fenêtres d'instruction décentralisées, l'émission est découpée en deux étages. La première étape envoie une µops vers la fenêtre d'instruction adéquate, la seconde émet la µops depuis la fenêtre d'instruction quand ses opérandes sont prêts. La première est l'étage de '''''dispatch''''' qui envoie l'instruction dans la fenêtre d’instruction adéquate, selon que c'est une instruction flottante, entière, autre. La seconde est l'étage de '''''scheduling''''', qui gère la disponibilité des opérandes et des unités de calcul. La µop émise est ajoutée au tampon de réordonnancement, s'il existe, lors de l'étape de ''dispatch''. ===L'usage de plusieurs files d'instruction=== Une dernière méthode d'OOO utilise plusieurs files de micro-opération. L'idée est qu'une fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement une file de micro-opération pour les opérations entières, une autre pour les opérations flottantes, une autre pour les accès mémoire. D'autres processeurs utilisent une file pour les accès mémoire et une autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. La présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que la technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si une dépendance bloque une FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans une autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer la disponibilité des registres. Quand un registre est lu ou écrit par une instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. La logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : une pour les instructions d'accès mémoire et une autre pour les autres instructions. Si jamais une instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de la lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'une est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est la file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. ===Avantages et inconvénients de chaque implémentation=== Pour résumer, on a le choix entre une grosse fenêtre d'instruction généraliste et plusieurs fenêtres spécialisées. Le choix entre les deux est un compromis entre économie de circuits et flexibilité. Avec une fenêtre décentralisée, il arrive qu'une fenêtre d'instruction soit remplie, alors que les autres sont sous-utilisées, voire vides. Pour comprendre pourquoi, comparons une fenêtre d'instruction unique, avec une fenêtre décentralisée séparant µops entières et flottantes. La fenêtre centralisée dispose de 64 entrées, la décentralisée a 32 entrées pour chaque fenêtre d'instruction. La fenêtre décentralisée peut mémoriser au maximum 32 µops entières et 32 *ops flottantes. Par contre, la fenêtre centralisée peut mémoriser 64 µops tout court. Si le programme exécuté n'utilise pas de nombres flottants, la différence devient flagrante. La fenêtre décentralisée sera limitée ) 32 µops, alors que la centralisée pourra mémoriser le double. Les performances seront donc meilleures avec la fenêtre centralisée. Et au-delà de ça, la fenêtre décentralisée de l'exemple est utilisée de manière optimale si la moitié des µops sont des µops entières, et l'autre moitié des µops flottantes. Alors que la fenêtre centralisée se moque de la répartition entre µops entières et flottantes. Une subtilité est que le cout en transistors d'une fenêtre d'instruction n'est pas proportionnel au nombre de µops qu'elle peut mémoriser. Par exemple, si je compare une fenêtre d'instruction de 32 entrées (32 µops max), elle n'utilise pas deux fois plus transistors qu'une fenêtre de 16 entrées. Le cout en circuit n'est pas deux fois plus élevé, mais est approximativement 4 fois plus élevé. Le cout est presque quadratique, à savoir qu'il est proportionnel au carré du nombre d'entrées. Et il en est de même avec la performance, pour des raisons qu'on expliquera plus bas. Les fenêtres décentralisées utilisent plusieurs fenêtres d'instruction de "petite taille", donc plus rapides, économes en circuits et économes en énergie. Le compromis n'est donc pas entre une fenêtre centralisée à 64 entrées versus deux fenêtres de 32 entrées. Le compromis en pratique est entre une fenêtre centralisée de 64 entrées versus 3 fenêtres de 32 entrées. Un exemple pratique est celui de la microarchitecture ''Skylake'' d'Intel. Intel est passé d'une fenêtre centralisée pre-''Skylake'' à deux fenêtres décentralisées sur ''Skylake'',. Le nombre d'entrée était globalement le même entre les deux, même si l'évolution de la finesse de gravure entre les deux biaise un peu les résultats. Un avantage des fenêtres décentralisées est qu'il est possible de démarrer l'exécution de plusieurs µops simultanément : une µops par fenêtre d'instruction. Le fait est que deux fenêtres d'instructions différentes émettent leurs µops sans se synchroniser avec les autres. Deux fenêtres d'instruction peuvent donc émettre chacune une µops, ce qui fait deux µops émises lors du même cycle. Cela permet d'exécuter en même temps deux ou trois instructions 1-cycle, comme des additions, soustractions, décalages, etc. Il devient par exemple possible d'émettre une µop entière en même temps qu'une µop flottante, si les µops entières ont une fenêtre séparée de celle des µops flottantes. Il est maintenant temps de voir en quoi sont faites les fenêtres d’instruction, qu'elles soient centralisées ou décentralisées. Nous allons aussi voir quelle est la logique d'émission associée. ==L'implémentation d'une fenêtre d'instruction : généralités== Une fenêtre d'instruction est une mémoire qui mémorise des micro-opérations. Elle est cependant plus complexe qu'une mémoire RAM ou qu'une FIFO et ressemble un petit peu à une mémoire cache. Elle dispose d'un port d'écriture et d'un port de lecture, au minimum. Le port d'écriture permet à l'unité de décodage d'insérer une micro-opération dedans, d'ajouter la micro-opération qui vient d'être décodée. Si une instruction machine est décodée en plusieurs micro-opération, deux possibilités. La première est de les insérer un par un, ce qui fait qu'on peut se contenter d'un seul port d'écriture. L'autre possibilité est de les ajouter en même temps, ce qui demande plusieurs ports d'écriture. Le port de lecture sert à émettre une instruction. On part du principe que la fenêtre d'instruction ne peut émettre qu'une seule instruction à la fois, car les processeurs que nous avons vu précédemment sont de ce type. Mais nous verrons dans quelques chapitres qu'il existe des processeurs dits superscalaires, qui sont capables d'émettre plusieurs instructions par cycle. Dans ce cas, la fenêtre d'instruction a un seul port de lecture. Un processeur superscalaire, quant à lui, doit avoir un port de lecture par unité de calcul, ce qui fait beaucoup plus. Les fenêtres d'instruction sont composées d''''entrées''', des mots mémoire qui stockent une instruction. Une instruction réserve une entrée après son décodage et la libère dès qu'elle est envoyée aux unités de calcul. Une entrée contient l'opcode (les signaux de commande à envoyer à l'ALU), le registre de destination du résultat, les registres de chaque opérande, et éventuellement des signaux de commande en plus. De plus, chaque opérande est couplée à un bit de disponibilité, qui indique si elle est disponible. Quand un opérande est écrit dans les registres, le bit de présence correspondant est mis à jour. Enfin, chaque entrée possède un bit ''empty'' qui indique si elle est vide, cette information étant utile pour réserver des entrées. [[File:Entrée d'une station de réservation - sans les tags.png|centre|vignette|upright=3|Entrée d'une fenêtre d'instruction]] ===Les stations de réservation=== Les '''stations de réservation''' sont des fenêtres d'instruction particulières, qui sont capables de mémoriser les opérandes des instructions. Les entrées des stations de réservation sont identiques à celle des autres fenêtres d'instruction, si ce n'est que les opérandes de l'instruction sont enregistrés directement dans des champs séparés. Il y a deux champs, un par opérande, pour stocker l'opérande elle-même, lue depuis les registres ou obtenue via le réseau de contournement. Notons que les champs pour les opérandes viennent en plus des champs pour les noms de registres, encore que les deux peuvent être fusionnés si on veut optimiser le tout. [[File:Entrée d'une station de réservation.png|centre|vignette|upright=3|Entrée d'une station de réservation.]] Précisons que la terminologie n'est pas très fiable. Les termes "fenêtre d'instruction" et "station de réservation" ne regroupent pas du tout la même chose d'un papier de recherche à l'autre, d'un bouquin à l'autre, d'un chercheur à l'autre, d'un ingénieur à l'autre, d'un professeur à l'autre. Le terme initial vient pourtant de l'article original sur l'algorithme de Tomasulo, où il désignait une fenêtre d'instruction associée à une unité de calcul précise. Mais le terme a ensuite été réutilisé, ce qui fait que certains processeurs avec plusieurs unités de calcul sont décrits comme ayant une unique station de réservation. En bref : c'est le bazar ! Mais nous en reparlerons dans le chapitre sur le renommage de registres, car c'est la place idéale pour les aborder. Toujours est-il que j'ai fait le choix de confondre les concepts de fenêtre d'instruction et de station de réservation avec les concepts de '''lecture avant émission''' et de '''lecture après émission'''. La différence entre les deux est que les registres sont lus après émission avec une fenêtre d'instruction, avant avec des stations de réservation. Dans le cas "avant émission", les opérandes sont mémorisés dans la station de réservation. Et cette différence a une influence sur le pipeline du processeur, le banc de registres et tout ce qui s'en suit. Un désavantage de la lecture avant émission est qu'il faut stocker les opérandes après lecture, ici dans les stations de réservation. Mais un avantage est que le banc de registre a besoin de moins de ports de lecture, car une bonne partie des opérandes sont fournies par le système de contournement. Nous verrons cela dans le détail dans le chapitre sur les processeurs superscalaires. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Lecture après émission.]] [[File:Read Before Issue.png|centre|vignette|upright=2.5|Lecture avant émission.]] ===La logique d'éveil et de sélection=== Dans le cas qui va suivre, on suppose que le processeur ne peut émettre qu'une instruction à la fois. Chaque cycle, une instruction est sélectionnée et est envoyée dans le chemin de données, soit à une ALU, soit à une unité d'accès mémoire. La sélection d'une instruction est effectuée par l'unité d'émission, qui est aussi appelée le '''''scheduler'''''. Elle gère la disponibilité des opérandes et la disponibilité des unités de calcul adéquate. Le choix de l'instruction émise doit être le plus pertinent possible, pour des raisons de performances. Pour le premier point, l'unité d'émission détermine quelles instructions sont candidates pour l'émission. Les ''instructions candidates'' sont celles dont tous les opérandes sont prêts. Le processeur contient un circuit qui détecte les instructions candidates : la '''logique d’éveil''' (''wake-up logic''). Une fois que la logique d'éveil a fait son travail, une instruction est choisie pour s’exécuter en fonction de la disponibilité des unités de calcul adéquates. Ce rôle est dévolu à un circuit qu'on appelle la '''logique de sélection''', ou ''select logic''. [[File:Fonctionnement complet de la logique d’émission.jpg|centre|vignette|upright=1.5|Fonctionnement complet de la logique d’émission.]] La logique de sélection doit gérer le fait que les unités de calcul du processeur ne sont pas toutes identiques. Déjà, un processeur a généralement des unités séparées pour les instructions entières et flottantes, des unités spécialisées dans les accès mémoire, parfois des unités spécialisées pour les branchements. Une instruction doit être attribuée à la bonne unité de calcul, on ne doit pas envoyer une instruction entière dans une unité de calcul flottante. De plus, parmi les unités de calcul entières, toutes ne sont pas identiques. Par exemple, il est fréquent d'avoir plusieurs unités de calcul spécialisées dans les opérations simples (additions, soustractions, opérations logiques) avec une unité pour les multiplications/divisions séparées, parfois une unité spécialisée pour les décalages/rotations, etc. Là encore, allouer la bonne instruction à la bonne ALU est complexe. Plus les unités de calcul sont hétérogènes, plus la logique de sélection est compliquée. Les logiques d'éveil comme de sélection sont assez complexes. Comme on le verra plus bas, la logique de sélection la plus simple, qui gère une seule unité de calcul, est basée sur un encodeur à priorité couplé à d'autres circuits. Et pour gérer plusieurs ALUs, il faut mettre des encodeurs en cascade. Le résultat est que même en prenant une logique de sélection simple, elle sera assez lente et gourmande en circuits. Aussi, la logique de sélection met souvent un cycle d'horloge entier pour faire son travail, elle a son propre étage de pipeline attribué. La logique d'éveil est dans le même cas, ce qui fait qu'émettre une micro-opération demande deux cycles d'horloge. Le défaut est que cela rajoute des cycles d'horloges entre la fenêtre d'instruction et l'ALU, ce qui complique la gestion du pipeline. Ces cycles de retard sont à prendre en compte au moment d'émettre les instructions, les ''scheduler'' doit en tenir compte pour des performances optimales. Sans tenir compte de ces cycles de retard, les instructions arrivent en retard de quelques cycles à l'ALU, cycles de retard durant lesquels l'ALU n'a pas fait de calcul et a été sous-utilisée, sans compter que le système de contournement n'est pas utilisé au mieux. Et le problème est encore plus important sur les processeurs avec des stations de réservation, qui utilisent la "lecture après émission" : cela rajoute un cycle d'horloge en plus, un temps de retard en plus. ===La logique d'éveil : l'émission anticipée=== La logique d'éveil doit tenir compte du fait qu'il y a plusieurs étages entre l'émission et l'exécution sur une unité de calcul. Par exemple, un processeur a souvent entre un et à cinq étages entre la file d'attente et les unités de calcul. Il faut lire les registres, gérer le contournement, et cela peut prendre quelques cycles d'horloge. Sur le Pentium 4, on trouve 6 étages entre la fenêtre d’instruction et l'entrée de l'ALU. Si les micro-opérations sont émises quand les opérandes sont disponibles, il y aura un délai de quelques cycles avant qu'elles atteignent l'ALU. Alors qu'idéalement, on souhaiterait que la micro-opération atteigne l'ALU dès que ses opérandes sont disponibles, pour profiter des techniques de contournement. Pour cela, la logique d'éveil émet les instructions quelques cycles en avance pour qu'elles arrivent au bon moment. Il s'agit d'une technique d''''émission anticipée''', dont nous avions parlé dans le chapitre sur le contournement. : Il faut noter que le problème se pose plus avec des fenêtres d'instruction qu'avec des stations de réservation. Les premières ont un étage en plus entre émission et ALU, vu qu'il faut lire des registres après l'émission. L'émission anticipée demande d'émettre un signal d'éveil en avance de quelques cycles, pile au bon moment. Par exemples, si on a deux étages entre l'ALU et l'unité d'émission, le signal de réveil sera généré deux cycles avant que le résultat soit effectivement calculé. L'implémentation varie, mais deux solutions sont possibles. La première est de générer le signal d'éveil dans l'ALU, ce qui n'a de sens que pour les opérations comme les multiplications ou les divisions, qui prennent plusieurs cycles. Une autre technique génère le signal de réveil dans une structure centralisée, spécialisée dans la génération des signaux d'éveil. L'unité de composée d'un registre à décalage par registre. Imaginons qu'une instruction est émise, que cette instruction mette N cycles à s'exécuter, et qu'elle écrive dans un registre de destination. L'unité sélectionne alors le registre à décalage associé au registre de destination, et met le bit numéro N à 1. Le registre décalé d'un cran à chaque cycle. Quand le bit sortant est un 1, alors le signal de validité pour l'opérande est généré. L'émission anticipée marche bien si l'instruction a une durée fixe, connue à l'avance. Et autant c'est le cas pour les instructions arithmétiques et logiques, autant ce n'est pas le cas pour les accès mémoire. Les accès mémoire ont une latence variable : quelques cycles pour un succès de cache, plusieurs dizaines de cycles pour un défaut de cache L1, pas loin de la centaine pour un défaut de cache L2, etc. Et cela pose des problèmes pour l'émission anticipée. L'émission en avance pour les accès mémoire est purement spéculative : le processeur émet des instructions en supposant que la lecture entrainera un succès de cache, quitte à annuler l'instruction en cas de défaut de cache. Mais faire ainsi demande non seulement d'annuler les instructions émises en avance, mais aussi de ne pas retirer les instructions émises en avance de la fenêtre d'instruction. Elles sont émises, mais une copie de sauvegarde est conservée dans la fenêtre d'instruction. Si le processeur détecte un défaut de cache, il peut alors ré-exécuter l'instruction. S'il détecte un succès de cache, les instructions lecture-dépendante sont retirées de la fenêtre d'instruction, la copie de sauvegarde est devenue inutile et est donc jetée. ===La logique de sélection : âge ou position ?=== La logique de sélection est primordiale pour de bonnes performances. Il existe deux méthodes principales pour sélectionner l'instruction à exécuter. La première est la plus simple : elle se base sur lé numéro de l'entrée. En effet, une fenêtre d'instruction est avant tout une sorte de mémoire, un mix entre mémoire associative, mémoire RAM, et FIFO. Et chaque entrée a un numéro, une adresse mémoire. Nous parlerons de numéro dans ce qui suit, car ce sera plus simple, le terme d'adresse mémoire étant peut-être un peu exagéré dans le contexte des fenêtres d'instruction. Toujours est-il que la fenêtre d'instruction est adressable dans le sens où on peut lui envoyer le numéro de l'entrée voulue, et la fenêtre d’instruction renvoie le contenu de l'entrée sur son port de lecture. Et c'est ce que fait la logique de sélection : elle génère le numéro de l'entrée à lire. Le numéro est alors envoyé sur l'entrée d'adresse de la fenêtre d’instruction, et elle fournit la micro-opération associée sur son port de lecture, son '''port d'émission'''. La première méthode de sélection, donc. Elle est basée sur le numéro de l'entrée. Si plusieurs entrées sont éveillées, la logique de sélection prend celle avec le plus petit numéro. Elle porte le nom de '''sélection par position''', sous-entendu position dans la fenêtre d'instruction. Vous l'avez peut-être deviné, mais la logique de sélection est alors un encodeur à priorité. Le circuit de sélection ne se résume donc pas seulement à un encodeur à priorité, mais c'est le circuit central. L'avantage d'une telle méthode de sélection est qu'elle est simple à implémenter : un encodeur à priorité est un circuit connu, facile à implémenter. Mais on remarque un défaut : un encodeur est un circuit assez rapide, mais qui utilise beaucoup de transistors, beaucoup de portes logiques, surtout si on veut qu'il soit rapide. Ce qui explique que la logique de sélection ait son propre étage de pipeline rien que pour elle. La seconde méthode s'appelle la '''sélection par âge''', au nom assez transparent. L'idée est de privilégier l'émission de l'instruction la plus ancienne. Elle demande que la fenêtre d'instruction trie les micro-opérations par ordre d'insertion dans la fenêtre d'instruction, ce qui en fait une pseudo-FIFO. Le tri est partiel, car les instructions peuvent sortir de la fenêtre d’instruction à tout moment. Compacter la fenêtre d'instruction, à savoir regrouper toutes les entrées valides est une idée, mais elle est compliquée à implémenter. Aussi, elles préfèrent encoder des informations sur l'ordre d'émission dans chaque entrée. L'encodeur à priorité doit alors travailler non pas sur des nombres entiers liés à l'ordre d'insertion dans la pseudo-FIFO. Elle est encore plus gourmande en circuits que la méthode précédente. Les processeurs haute performance utilisent souvent des méthodes hybrides. Par exemple, les processeurs AMD de microarchitecture Bulldozer utilisaient une méthode intermédiaire. Ils utilisaient une fenêtre d'instruction couplée à un encodeur à priorité pour la sélection par position, mais complémentaient le tout avec une unité qui mémorisait l'instruction la plus ancienne dans la fenêtre d’instruction. Le mécanisme de sélection par âge était utilisé en priorité. Mais si l'instruction la plus ancienne n'était pas prête, le processeur basculait sur le mécanisme de sélection par position. ===La compaction des fenêtres d'instruction=== À chaque cycle, les instructions décodées sont ajoutées dans la fenêtre d'instruction, dans des entrées vides. Vu que les instructions quittent celle-ci dans le désordre, ces vides sont dispersés dans la fenêtre d'instruction, ce qui pose problème pour déterminer où placer les nouvelles instructions. La solution la plus triviale consiste à conserver une liste des vides, mise à jour à chaque insertion ou émission d'instruction. Une autre solution consiste à éliminer les vides en compactant la fenêtre d'instruction à chaque cycle d'horloge. Des circuits se chargent de détecter les vides et de regrouper les instructions en un unique bloc. Il faut signaler que certains processeurs arrivent à se passer de cette étape de compactage, mais au prix de fenêtres d'instruction nettement plus complexes. Autre problème : quand il faut choisir quelle instruction émettre, il y a toujours plusieurs candidats. Si on choisit mal, des instructions restent en attente trop longtemps parce que d'autres instructions plus jeunes leur passent devant. Pour éviter cela, les instructions les plus vielles, les plus anciennes, sont prioritaires. Pour cela, on peut utiliser une FIFO un peu spéciale pour la fenêtre d'instruction. Si les ajouts d'instruction se font dans l'ordre, les instructions ne quittent pas forcément la fenêtre d'instruction dans l'ordre imposé par une FIFO : les instructions restent triées dans leur ordre d'ajout, même s'il y a des vides entre elles. Dans ces conditions, il est préférable que le compactage conserve l'ordre FIFO des instructions. Dans ces conditions, l'instruction la plus ancienne est celle qui est située à l'adresse la plus faible : le circuit de sélection peut donc être fabriqué avec des encodeurs, et est relativement simple. ==Les fenêtres d'instruction basées sur une matrice de dépendances== L'implémentation la plus simple étend le fonctionnement d'un pipeline dynamique usuel. Rappelez-vous le chapitre sur les pipelines dynamiques. Nous avions vu que de tels pipelines émettaient une instruction par cycle, quitte à émettre des bulles de pipeline en cas de dépendance bloquante. Et il est possible d'améliorer leur unité d'émission pour qu'elle soit compatible avec l'exécution dans le désordre. ===Rappels sur le registre de réservation/disponibilité=== L'émission d'une instruction est gouvernée par un ''registre de réservation'' qui indique quels registres sont réservés par une instruction, et ceux qui sont libres. Un registre réservé est un registre qui sera écrit par une instruction en cours d'exécution, mais qui n'a pas encore écrit son résultat. Les instructions candidates doivent avoir leurs opérandes dans des registres libres. Sinon, c'est signe que leurs opérandes sont réservés en écriture, donc pas encore écrites, donc pas disponibles. Si une instruction candidate veut lire ce registre, c'est signe qu'il y a une dépendance RAW : elle veut lire un registre réservé, qui est destiné à être écrit par une instruction en vol. Si elle veut écrire, c'est signe qu'elle veut écrire dans un registre où une autre instruction veut écrire : c'est une dépendance WAW. Dans les deux cas, l'instruction n'est pas émise. Le registre de réservation encode les registres réservés comme suit : chaque bit est associé à un registre. Le bit numéro 0 est associé au registre numéro 0, le bit numéro 1 au registre numéro 1, etc. Là, En clair, les numéros de registres réservés sont encodés en représentation non pas binaire, mais en représentation ''one-hot'' (vue au premier chapitre). {|class="wikitable" |+ Registre de réservation |- ! Registre 7 !! Registre 6 !! Registre 5 !! Registre 4 !! Registre 3 !! Registre 2 !! Registre 1 !! Registre 0 |- | 0 || 0 || 1 || 0 || 0 || 1 || 0 || 0 |} Avant d'émettre une instruction, l'unité d'émission extrait les registres opérande/destination et les convertis dans la même représentation que le registre de réservation, à savoir en représentation ''one-hot''. Le circuit de traduction binaire vers ''one-hot'' est, pour rappel, un simple décodeur. Puis, on fait un OU logique entre les sorties des décodeurs. Le résultat est un masque qui indique quels registres sont lus par l'instruction, encodé en représentation ''one-hot''. Appelons-le le '''masque d'opérandes'''. Le masque est alors comparé au registre de réservation pour vérifier si l'instruction peut être émise. [[File:Unité d'émission simple, dans l'ordre.png|centre|vignette|upright=2|Unité d'émission simple, dans l'ordre]] Si l'émission est autorisée, le registre de réservation est là aussi mis à jour. Le registre de réservation est aussi mis à jour dès qu'une instruction enregistre son résultat dans les registres, ou alors dès qu'il est disponible pour le contournement. Le bit associé au registre repasse alors à 0 (ou à 1). Sans contournement, la mise à jour se fait alors à la toute fin de l'instruction, quand elle se termine, lors de la dernière étape d'enregistrement, à la fin de son pipeline. Avec, elle se fait quand l'instruction quitte l'unité de calcul. ===L'extension à l'exécution dans le désordre : l'éveil par matrice de bits=== La différence entre un pipeline dynamique et l'exécution dans le désordre est que l'on passe d'une instruction à émettre à plusieurs. Plusieurs instructions sont mises en attente dans une fenêtre d’instruction, et y attendent leur tour. L'idée est alors d'envoyer le registre de disponibilité à toutes les entrées, à toutes les instructions en attente. Ainsi, on sait quelles sont les instructions qui peuvent s'exécuter et celles qui ne le peuvent pas. L'implémentation est assez simple, elle ressemble beaucoup à l'implémentation d'un pipeline dynamique simple, si ce n'est que des circuits sont dupliqués. L'implémentation utilise des fenêtres d'instruction légèrement différentes de celles introduites plus haut. Elles n'utilisent notamment pas de bits de disponibilité, mais autre chose. Lorsqu'une instruction est ajoutée à la fenêtre d'instruction, le masque de disponibilité des opérandes est stocké dans la fenêtre d'instruction. A chaque cycle, le registre de disponibilité est envoyé à toutes les entrées, et est comparé avec tous les masques de disponibilité des opérandes. Si une comparaison renvoie un 1, alors l'instruction de l'entrée est une instruction candidate à l'émission. [[File:Unité d'émission dans le désordre basée sur un registre de disponibilité.png|centre|vignette|upright=2.5|Unité d'émission dans le désordre basée sur un registre de disponibilité]] L'ensemble est implémenté avec l'aide d'une '''matrice de bits''', où chaque ligne correspond à une entrée et chaque colonne à un registre. À chaque croisement entre une ligne et une colonne, on trouve un bit. Si le bit de la ligne n et de la colonne m est à 1, cela veut dire : l'instruction dans l'entrée n a besoin de lire le registre m. S’il est à 0, alors cela veut dire que l'instruction stockée dans la ligne n'a pas besoin de la donnée dans le registre m. [[File:Planificateur à matrice de bits.jpg|centre|vignette|upright=2|Planificateur à matrice de bits.]] Lorsqu'une instruction réserve une entrée, elle initialise la ligne en fonction des registres qu'elle souhaite lire. Pour vérifier si une instruction a ses opérandes prêts, le processeur compare le registre de disponibilité à la ligne associée à l'instruction/entrée. A chaque intersection ligne-colonne, se trouve un comparateur de 1 bit, qui détecte si le registre est demandé et disponible. Les résultats de cette porte sont ensuite envoyés à une porte ET, qui fait le gros du travail. [[File:Logique de détection de la disponibilité d'une instruction.jpg|centre|vignette|upright=2|Logique de détection de la disponibilité d'une instruction.]] ==Les fenêtres d'instruction basées sur une mémoire associative== Les processeurs modernes utilisent une mémoire associative pour la fenêtre d'instruction. Les mémoires associatives ont été abordées il y a quelques chapitres, mais faisons quelques rappels. Les mémoires associatives servent à accélérer la recherche de données dans un ensemble. Or, une fenêtre d'instruction vérifie régulièrement si chaque entrée est prête. Il s'agit d'un processus de recherche d'une instruction qui respecte une condition bien précise dans la mémoire, ce qui fait que les mémoires associatives sont donc tout indiquées. Comme vous le savez, les signaux de commande d'une instruction sont propagés avec celle-ci dans le pipeline, le nom du registre de destination ne faisant pas exception. Le nom de registre est envoyé à la fenêtre d'instruction lors de l'écriture du résultat dans les registres. S'il y a correspondance, l'opérande est disponible et son bit de disponibilité est mis à 1. On peut adapter cette méthode pour tenir compte du contournement assez simplement. [[File:Détection des dépendances par propagation du registre de destination.png|centre|vignette|upright=2|Détection des dépendances par propagation du registre de destination.]] En conséquence, le circuit de détection des dépendances est constitué d'un grand nombre de comparateurs : un par champ « nom de registre » dans chaque entrée. La logique d'éveil/''wake up'' regroupe tous les comparateurs, la logique de sélection est un circuit situé en-dehors de la mémoire associative. Les entrées sont dans la mémoire associative elle-même. [[File:Gestion des bits de validité.png|centre|vignette|upright=2|Gestion des bits de validité.]] L'implémentation la plus simple est celle du schéma précédent, où on utilise une mémoire associative unique. Une version plus élaborée sépare la fenêtre d'instruction en deux parties : une mémoire qui mémorise les registres des opérandes, une autre mémoire pour le reste. La mémoire pour les registres opérandes est la mémoire associative proprement dite, c'est elle qui est associée aux comparateurs, à la logique de ''wake-up''/réveil, etc. Par contre, l'autre mémoire est une mémoire RAM simplifiée, qui mémorise les informations qui n'ont pas besoin des comparateurs. L'opcode de l'instruction est là-dedans, par exemple. La fenêtre d'instruction est donc une sorte de mémoire associative améliorée. Il se trouve que c'est aussi le cas du ROB. Et il est possible de fusionner le tampon de ré-ordonnancement avec la fenêtre d'instruction dans une structure unique. La différence avec une fenêtre d’instruction normale est que les entrées sont libérées non pas quand l'instruction est exécutée/émise, mais quand elle termine son exécution et quitte le ROB. La fenêtre d'instruction incorpore des bits dans chaque entrée, pour savoir si la µops associée a été émise et est en cours de traitement dans les ALUs. La méthode a notamment été utilisée sur les processeurs d'architecture K6 d'AMD. Le tout donnait une structure appelée le '''DRIS''' (''deferred scheduling register renaming instruction shelf''). Les processeurs PA 8000 de HP étaient aussi vraisemblabment dans ce cas, aussi. ===Les optimisations de la consommation d'énergie : la désactivation des portions inutilisées=== Le problème avec des fenêtres d'instruction de ce type est leur forte consommation énergétique, ainsi que le grand nombre de portes logiques utilisées, qui deviennent prohibitifs pour des fenêtres d'instruction un peu grosses. Pour résoudre ce problème, certains ont optimisé les comparateurs. D'autres ont tenté de profiter du fait que la majorité des bits dans les entrées sont composés de zéros. Bref, les optimisations purement matérielles sont légion. Une première solution est de désactiver les entrées qui sont inutilisées, vides, sans instruction. Pour cela, on fait précéder les comparateurs par un circuit qui les connecte ou déconnecte des lignes de bit. Le circuit est commandé par le bit ''empty'' qui indique si une entrée est vide ou non. L'avantage est que la consommation d'énergie de la fenêtre d'instruction devient alors proportionnelle au nombre d'entrées non-vides, et non au nombre d'entrées total. Du moins, en apparence, les entrées non-utilisées doivent quand même être alimentées pour fonctionner, mais l'activité de comparaison disparait dans les entrées vides. Il est possible d'étendre cette technique aux entrées dont les opérandes sont prêts. Les gains sont généralement assez bons, avec une réduction de consommation variant entre 30 et 50%, avec une implémentation très simple et très économe en circuits. Une autre solution, assez simple à mettre en place, consiste à désactiver une partie de la fenêtre d'instruction sin elle est inutilisée. Pour cela, il faut segmenter la fenêtre d'instruction avec la technique du ''wire partitionning''. Pour rappel, une fenêtre d'instruction est une mémoire associative. Et comme toute mémoire associative, elle contient des fils, les lignes de bit, qui relient les entrées/sorties à toutes les cellules mémoire. Plus une ligne de bit est longue, plus elle consomme d'énergie et plus le temps de lecture/écriture est long. L'idée est de segmenter les lignes de bits en plaçant des répéteurs qui recopient la tension d'un segment au suivant. Les répéteurs sont des tampons trois-états, ce qui permet de déconnecter les portions inutilisées de la ligne de bit. Ce faisant, la fenêtre d'instruction est découpée en segments, qui peuvent être désactivés si besoin. S'il y a peu d'instructions chargées dans la fenêtre d'instruction, les portions inutilisées sont désactivées. La technique marche d'autan mieux si les instructions sont compactées au début de la fenêtre d'instruction. [[File:Wire partitionning.png|centre|vignette|upright=2|Wire partitionning]] Tout le problème est de savoir quelles portions désactiver. La technique est assez simple si la fenêtre d'instruction est compactée, à savoir si toutes les instructions sont régulièrement regroupées au début de la mémoire CAM. Mais même avec cette optimisation, la décision de désactiver une portion de la fenêtre d'instruction n'est pas à prendre à la légère. Il ne faut pas désactiver une portion contenant des instructions pouvant être émise sous peu. La décision dépend de paramètres variés : proportion d'entrée vides, quantité d'entrées récemment activées/désactivées récemment, présences d'entrées avec un ''match'' d'opérandes récent, etc. Il est important de préciser que les techniques en question fonctionnent aussi sur les autres types de fenêtre d'instruction, qui ne sont pas basées sur des mémoires associatives. Nous allons voir celles-ci dans la suite du chapitre, mais gardez à l'esprit que ces optimisations, à savoir désactiver les entrées vides/prêts et partitionner la fenêtre d'instruction, sont des optimisations générales qui marchent avec presque tout. ===L'ajout d'une FIFO pour les instructions déjà prêtes à l'émission=== D'autres techniques permettent de réduire aussi bien le cout en circuits que la consommation d'énergie de la fenêtre d'instruction. L'idée est d'utiliser une mémoire associative quand elle est réellement nécessaire, mais d'utiliser une fenêtre d'instruction "normale" dès que possible. La méthode la plus simple tient compte du fait que certaines µopsont déjà toutes leurs opérandes de disponibles à l'émission, mais doivent quand même être mises en attente, parce que l'ALU adéquate est occupée, parce que des dépendances WAW/WAR sont encore là, ou pour tout autre raison. Dans ce cas, elles sont mises en attente non pas dans la fenêtre d'instruction, mais dans une mémoire FIFO toute simple. L'idée est qu'au lieu d'avoir une énorme mémoire associative pour la fenêtre d'instruction, on déplace quelques entrées dans une petite FIFO annexe. Le résultat est un gain d'énergie et de circuits, au prix d'une perte de performance mineure. La perte de performance en question se manifeste si aucune instruction n'a ses opérandes de prêtes à l'émission : le programme n'utilise pas la FIFO et voit alors une fenêtre d'instruction plus petite. Une amélioration de cette technique tient compte du fait que certaines instructions sont dans un cas intermédiaire. Elles ont déjà un opérande de prête lors de l'émission, mais pas l'autre. Le nombre d'opérandes varie suivant l’instruction : certaines n'ont besoin que d'un seul opérande. De plus, il arrive qu'une opération tout juste décodée ait déjà un ou plusieurs de ses opérandes de prêts. Cette constatation permet d'éviter d'utiliser des comparateurs pour les opérandes déjà prêts. Par exemple, on peut parfaitement utiliser trois fenêtres d'instruction : * une pour les instructions dont tous les opérandes sont prêts, mais qui sont quand même mises en attente, sans comparateur ; * une pour les instructions dont un seul opérande manque, qui n'utilise qu'un comparateur par entrée ; * une pour les instructions dont deux opérandes manquent à l'appel, qui utilise deux comparateurs par entrée. C'est beaucoup plus économique que d'utiliser une seule grosse fenêtre d'instruction qui contiendrait autant d'entrées que les trois précédentes réunies, avec deux comparateurs par entrée. Certains sont même allés plus loin, et ont proposé de supprimer la fenêtre d'instruction avec deux opérandes par entrée. Les instructions dont deux opérandes sont inconnus au décodage sont stockées dans la fenêtre d'instruction pour instructions avec un comparateur par entrée. Un circuit de prédiction se charge alors de prédire l'opérande manquant, cette prédiction étant vérifiée plus loin dans le pipeline. Il serait cependant étonnant qu'une telle proposition ait donné lieu à la moindre implémentation réelle. ===Les optimisations de la consommation d'énergie avancées=== D'autres chercheurs ont conservé une fenêtre d'instruction unique, avec autant de comparateurs par entrée qu'il y a d'opérandes possibles par instruction. Simplement, le processus de détection des opérandes prêts est légèrement ralenti : on ne vérifie qu'un opérande par cycle. Pour vérifier les deux opérandes d'une entrée, on doit attendre deux cycles. Enfin, certains chercheurs ont proposé des fenêtres d'instruction segmentées. Les instructions circulent à chaque cycle d'un segment vers le suivant : en conséquence, certains segments conservent les instructions les plus anciennes, un autre les instructions les plus jeunes, etc. Seul le denier segment, celui qui contient les instructions les plus vielles, peut émettre une instruction : la détection des opérandes se fait seulement dans le dernier segment, qui contient les instructions les plus anciennes. On économise ainsi beaucoup de comparateurs. Certains chercheurs ont tenté de pipeliner l'étape de sélection des opérandes, ainsi que l'étage d'arbitrage. Mais en faisant cela, il faut plusieurs cycles pour détecter qu'une instruction a ses opérandes prêts, ce qui pose problème face à de nombreuses dépendances RAW. Pour éviter de trop perdre en performances, certains chercheurs ont décidé d'utiliser des techniques pour prédire quelles seront les instructions dont les opérandes seront bientôt prêts. Si détecter qu'une instruction est prête prend n cycles, le processeur devra tenter de prédire la future disponibilité des opérandes n cycles en avance pour obtenir des performances optimales. ===Remplacer la mémoire associative par une RAM=== Une autre optimisation possible est de remplacer la fenêtre d'instruction par une mémoire RAM, dont chaque mot mémoire correspondrait à une entrée. Une telle optimisation permet en théorie de se passer des comparateurs associés à chaque entrée, mais au prix de l'ajout de circuits annexes potentiellement couteux. La première de ces techniques, la '''recherche directe par étiquette''' (direct tag search) fut créée par Weiss et son collègue Smith. Ils cherchaient à améliorer l'algorithme de Tomasulo, un algorithme qu'on expliquera dans quelques chapitres. Rappelons que chaque instruction produit un résultat, qui devra être rapatrié dans une ou plusieurs entrées de la fenêtre d'instruction. L'optimisation de la recherche directe par étiquette fonctionne dans le cas où le résultat de l'instruction n'est utilisé que par une seule entrée, et pas plusieurs. Le principe est simple : chaque champ « opérande » d'une entrée est adressable via le nom de registre de cet opérande. Pour faire le lien entre entrée et nom de registre, la recherche directe par étiquette ajoute une table de correspondances matérielle, une mémoire RAM qui mémorise les adresses des champs « opérande » des entrées. Les adresses envoyées dans cette mémoire sont les noms de registres des résultats. Lors de l'émission, la table de correspondances est mise à jour. Les numéros des champs « opérande » réservés lors de l'émission sont mémorisés dans les mots mémoire qui correspondent aux deux registres sources. Toutefois, une petite vérification est faite lors de l'émission : s'il y a déjà une correspondance dans la table pour un registre source, alors une autre instruction compte lire ce registre. Pour éviter d'écraser les données de l'instruction précédente dans la table de correspondances, l'émission de l'instruction est bloquée. [[File:Recherche directe par étiquette.png|centre|vignette|upright=2|Recherche directe par étiquette.]] ==Les fenêtres d’instruction avec préplanification== Avec la '''préplanification''' (''prescheduling''), la fenêtre d’instruction est composée de mémoires FIFO dans lesquelles les instructions sont triées dans l'ordre d'émission. Il n'y a pas de logique d’émission proprement dite, celle-ci se bornant à vérifier si l'instruction située au début de la FIFO peut s’exécuter. Par contre, le préplanificateur détecte les dépendances et en déduit où insérer les instructions dans le tampon d'émission, à l'endroit le plus adéquat. [[File:Préplanification.jpg|centre|vignette|upright=2|Préplanification.]] ===L'usage de FIFO multiples=== La technique de préplanification la plus simple utilise plusieurs FIFO. Quand une instruction a une dépendance avec une autre instruction, les deux sont placées dans la même FIFO. Pour cela, le préplanificateur détecte les chaines d'instructions dépendantes, et place les instructions dans la FIFO adéquate. A chaque cycle, l'unité d'émission lit une micro-opération dans chaque FIFO et vérifie si elle peut l'émettre. Si la micro-opération n'a pas ses opérandes disponibles, ou qu'une dépendance structurelle survient, alors la FIFO est bloquée. La micro-opération attend que la dépendance soit résolue, bloquant toutes les instructions précédentes. Mais les autres FIFO ne sont pas bloquées, laissant de la marge de manœuvre. [[File:Préplanification par FIFO multiples.png|centre|vignette|upright=1.5|Préplanification par FIFO multiples.]] ===La technique du tampon trié=== La technique du '''tampon trié''' trie les instructions selon le temps d'attente avant leur exécution. Les instructions qui sont censées s’exécuter bientôt sont insérées au tout début de la FIFO, tandis que les instructions qui s’exécuteront dans un long moment sont insérées vers la fin. Là encore, l'unité d'émission lit une micro-opération dans la FIFO, et détermine si elle peut être émise. Si une dépendance survient, l'émission est retardée, et la FIFO est bloquée. [[File:Préplanification par tampon trié.png|centre|vignette|upright=1.5|Préplanification par tampon trié.]] La technique a cependant quelques problèmes assez importants. Le premier problème est que la FIFO est bloquée lorsqu'une micro-opération ne peut être émise. Le second problème est que le temps avant exécution n'est pas toujours connu, notamment pour les instructions d'accès mémoire. Et cela se répercute sur les instructions dépendantes de celles-ci. Pour résoudre ce genre de problèmes, l'usage d'un pipeline à ''replay'' est possible, et est même l'une des meilleures solutions possible, malgré ses défauts. L'idée est que les lectures sont pré-planifiées en supposant qu'elles font un succès de cache L1. Si la prédiction est fausse, la lecture est ré-exécutée plusieurs cycles plus tard, en supposant qu'elle fait un succès dans le cache L2, et ainsi de suite. Elle est alors ré-insérée dans la FIFO, elle est pré-planifiée une seconde fois. Il en est de même si une micro-opération ne peut pas être émise : il suffit de la réinsérer dans la FIFO au bon endroit, en attendant que ses dépendances soient résolues. Ainsi, l'instruction fautive ne bloque pas la fenêtre d’instruction, et retente sa chance autant de fois qu'il le faut. [[File:Préplanification par fenêtre d’instruction scorebarodée.png|centre|vignette|upright=1.5|Préplanification par fenêtre d’instruction scorebarodée.]] Une autre solution utilise deux fenêtres d’instruction : une FIFO gérée par la préplanification, et une vraie fenêtre d'instruction pour les instructions dont le temps d'attente ne peut pas être déterminé. Il est possible de mettre cette dernière avant la préplanification, afin de gérer les temps d'attente des instructions d'accès mémoire. Quand le temps d'attente d'une lecture devient connu, ses instructions dépendantes sont gérées avec préplanification. [[File:Préplanification avec fenêtre d’instruction.png|centre|vignette|upright=2.5|Préplanification avec fenêtre d’instruction.]] ===Les fenêtres d'instruction avec allocation temporelle statique=== L''''allocation temporelle statique''' correspond à une technique utilisée sur les processeurs Cuzco de l'entreprise Condor. La technique en question a été présenté en 2025, mais des idées similaires ont été présentées dans la littérature académique. Elle ressemble beaucoup aux techniques de pré-planification, avec cependant quelques différences. L'idée est simple : le processeur dispose de plusieurs fenêtres d'instruction, qui mettent en attente les micro-opérations. Lors de l'étape de renommage de registres, le processeur détermine dans combien de cycles d'horloge la micro-opération sera prête pour exécution. La micro-opération est alors mise en attente durant ce nombre de cycles, dans les fenêtres d'instruction, puis est émise une fois ce nombre de cycles écoulés. Ce faisant, les fenêtres d'instruction n'ont pas besoin de détecter la disponibilité des opérandes à chaque cycle, pour chaque micro-opération en attente. Le ''timing'' de l'émission des micro-opérations est décidé à l'avance. L'implémentation exacte n'est pas connue, mais plusieurs solutions sont imaginables. Par exemple, la fenêtre d'instruction peut simplement être composée de plusieurs mémoires de petite taille, chacune contenant les micro-opérations destinées à être exécutées dans N cycles, N étant différent pour chaque mémoire. Une autre solution, plus réaliste, utilise une fenêtre d'instruction dans laquelle la micro-opération est couplée à des champs pour les opérandes, et un champ compteur. Le champ compteur est initialisé avec le nombre de cycles à attendre, et est décrémenté à chaque cycle d'horloge. Quand il atteint zéro, la micro-opération est émise. Vous remarquerez que la méthode ne marche que si toutes les micro-opérations prennent un nombre fixe de cycles d'horloge. Et autant c'est le cas pour les micro-opérations arithmétiques ou logiques, autant les accès mémoire ne rentrent pas dans ce cadre. En théorie, on ne sait pas combien de temps prendra un accès mémoire. Et cette incertitude se répercute sur les instructions dépendantes d'un accès mémoire. Pour éviter cela, le processeur réutilise un pipeline à ''replay'' tel que vu dans le chapitre précédent. L'unité de renommage de registre suppose que tout accès mémoire fait un succès de cache L1, et décide des ''timings'' d'émission sous cette hypothèse. Si une lecture subit un défaut de cache, elle est ré-exécutée, de même que toutes les instructions dépendantes. Pour cela, le registre de destination de la lecture est marqué comme invalide, grâce à un bit spécifique attaché au registre. Toute instruction qui lit un opérande invalide est elle aussi ré-executée de zéro. Pour simplifier, l'unité d'émission ressemble à une unité d'émission dans l'ordre, avec un registre de disponibilité, qu'on aurait amélioré pour aller au-delà de la simple détection des dépendances d'instruction. Pour déterminer les ''timings'' d'émission, à savoir quand émettre une micro-opération, le processeur utilise une unité d'émission à deux étages. Le premier étage est appelé le ''register scoreboard'', le second étage est appelé la ''Time Ressource Matrix''. Les deux étages communiquent entre eux, comme on va le voir, et leurs noms donnent une idée de ce qu'ils font. Le premier étage gère les dépendances de registres, le second gère les dépendances structurelles. Le premier étage est un registre de disponibilité amélioré, qui gère les dépendances de registre. Cet étage sait quand tel registre sera écrit, et donc que l'opérande écrit dedans sera disponible à partir de tel cycle d'horloge. Il le sait car l'étage suivant l'aura prévenu, mais laissons cela de côté pour le moment. Quand une micro-opération rentre dans cet étage, il vérifie les dépendances avec les registres et les micro-opérations antérieures. Vu qu'il sait quand les registres seront disponibles, il peut déterminer quand l'instruction pourra s'exécuter. Par exemple, si une micro-opération lit les deux registres R7 et R15, qui sont disponibles respectivement dans 5 et 7 cycles, le premier étage sait que la micro-opération devra attendre 7 cycles. Mais tout cela ne suffit pas à déterminer quand émettre une micro-opération. En effet, il fait aussi gérer les dépendances structurelles, ce qui est le boulot du second étage. Le second étage utilise pour cela une ''Time Ressource Matrix'', qui mémorise l'occupation de diverses "ressources", pour les 256 cycles d'horloge à venir. Les ressources en question sont les ports de lecture/écriture du banc de registre, les ALUs utilisées, si la micro-opération utilise l'unité mémoire, etc. Le second étage prend en entrée une micro-opération, détermine quelles "ressources" elle utilise, puis regarde leur disponibilité. Elle détecte alors les dépendances structurelles et détermine alors quand peut s'exécuter la micro-opération. Elle peut retarder l'émission de quelques cycles, si une dépendance structurelle est détectée. Une fois sortie du second étage, on sait quand la micro-opération va être émise, à quel cycle précisément. Et vu que la durée de l'instruction est fixe, on sait quand cette micro-opération va se terminer, quand son résultat sera disponible. Cela permet de mettre à jour la ''Time Ressource Matrix'', pour préciser que le port d'écriture sera occupé à tel moment. De plus, cette information est transmise au premier étage, qui sait alors quand est enregistré le résultat dans le registre de destination. C'est comme cela que le premier étage sait quand un registre est disponible : le second étage le prévient, quand il émet une instruction ! La ''Time Ressource Matrix''mémorise l'occupation des "ressources" pour les 256 cycles d'horloge à venir. Cependant, elle ne vérifie pas les dépendances pour les 256 cycles suivants. Quand elle reçoit une micro-opération, elle teste les dépendances structurelles pour seulement les 8 prochains cycles maximum. Si la micro-opération ne peut pas être émise pendant ces 8 cycles, le pipeline est bloqué, un ''pipeline stall'' est émis. Pour être plus précis, vu que le processeur peut décoder 8 micro-opérations en même temps, cela permet de ne consulter que 64 cycles d'horloge sur les 256. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les premiers processeurs Intel | prevText=Les premiers processeurs Intel | next=Le renommage de registres | nextText=Le renommage de registres }} </noinclude> fhv18wfx926sfihayyt1p4zp3wobo5s 773611 773610 2026-09-29T20:16:08Z Mewtow 31375 /* Les fenêtres d’instruction : généralités */ 773611 wikitext text/x-wiki Dans les chapitres précédents, nous avons parlé des techniques dites d''''émission dans l'ordre'''. L'idée est d’exécuter une nouvelle micro-opération à chaque cycle, dans des unités de calcul séparées. Les instructions sont émises consécutivement, mais les instructions s’exécutent en parallèle dans des unités de calcul séparées. Par contre, quand l'unité d'émission ne peut pas émettre une instruction, elle bloque tout le pipeline. Les instructions qui suivent sont elles aussi bloquées, elles doivent attendre leur tour, même si elles sont en capacité de s'exécuter. Les techniques d'exécution dans le désordre que nous allons voir dans ce chapitre corrigent ce point précis. Elles sont dites à '''émission dans le désordre'''. Elles se distinguent des précédentes sur un point précis : quand l'unité d'émission bloque l'émission d'une instruction, les instructions suivantes peuvent poursuivre. L'émission des instructions peut donc se faire dans le désordre, dans le sens où une instruction peut être émise alors qu'une instruction précédente ne l'est pas encore. L'avantage de l'émission dans le désordre est qu'une instruction s'exécute dès que ses opérandes sont disponibles. Par disponible, on veut dire présent soit dans le réseau de contournement, soit dans les registres. Le processeur détecte automatiquement quand les opérandes d'une instruction sont disponibles, et il l’exécute à ce moment-là. Dès qu'une instruction a ses opérandes disponibles, elle est émise et exécutée. C'est là la seule contrainte : les dépendances WAR, WAW et autres sont gérées par un ROB ou toute autre technique d'exception précise, seules les dépendances RAW limitent l'exécution. Mais avant de poursuivre, quelques point niveaux terminologie : * L'émission dans le désordre est un terme parlant et assez précis. Malheureusement, la terminologie la plus utilisée par d''''exécution dans le désordre'''. Et nous utiliserons ce terme dans la suite du cours, histoire de ne pas trop dévier de la nomenclature habituelle. * Nous utiliserons parfois l'abréviation OOO pour parler d'exécution dans le désordre. L'abréviation est celle de ''Out Of Order Excution''. * Nous utiliserons aussi l'abréviation ''µop'' pour parler de micro-opération, ''µops'' au pluriel pour parler de plusieurs micro-opérations, ou des micro-opérations en général. L'exécution dans le désordre ne gère en effet que des µops, elle se situe après l'étape de décodage. Mais avant de poursuivre, précisons une chose importante : l'exécution dans le désordre traite les accès mémoire à part. La majorité des processeurs OOO assez anciens exécutent les accès mémoire dans l'ordre, seules les µops entières/flottantes/branchements sont exécutées dans le désordre. Les processeurs datant d'après les années 2010 sont capable d'exécuter les accès mémoire dans le désordre, mais l'implémentation en question est assez particulière. Un chapitre entier sera dédié à l'exécution dans le désordre des µops mémoire. Nous allons volontairement mettre de côté la gestion des accès mémoire dans ce chapitre. ==Les fenêtres d’instruction : généralités== Pour décrire comment est implémentée l'émission dans le désordre, il faut commencer par parler des processeurs sans. Les processeurs sans exécution dans le désordre ont une unité d'émission qui bloque tout le pipeline dès qu'une µop ne peut pas être émise. Pour limiter l'impact de ce blocage, quelques rares processeurs incorporent une '''file de micro-opération''', une mémoire FIFO qui met en attente les µops. Vu que c'est une mémoire FIFO, les µops sont émises dans l'ordre, à savoir l'ordre d'ajout, dans l'ordre de décodage. Le schéma ci-dessous illustre une telle file d'attente couplée à un ''scoreboard''. Sur le principe, l'exécution dans le désordre améliore la file de µops sur un point : ce n'est plus une mémoire FIFO. Les µops sont insérées dans l'ordre, mais peuvent sortir dans le désordre (être émises dans le désordre). La file de µops devient alors une '''fenêtre d'instruction''', terme traduit directement de l'anglais ''instruction Window''. Terme assez trompeur, car elles mettent en attente des µops, pas des instructions. Elles peuvent émettre des µops dans le désordre, ce qui fait que si une µop bloque le pipeline, les µops suivantes peuvent être émises. [[File:Différence file µops et fenêtres instruction.png|centre|vignette|upright=2|Différence file µops et fenêtres instruction]] Je commence le paragraphe précédent par "sur le principe", car certaines techniques d'OOO n'utilisent pas de fenêtre d'instrruction. Dans les grandes lignes, il existe dans les grandes lignes 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! Fenêtre d'instruction |- ! Une seule | ''Scoreboard'' | Fenêtre d'instruction centralisée |- ! Plusieurs | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | Fenêtre d'instruction décentralisée |} Voyons les dans le détail. ===La fenêtre d'instruction centralisée=== L'implémentation la plus simple de l'OOO utilise une unique fenêtre d'instruction, appelée une '''fenêtre d'instruction centralisée'''. Les µops décodées sont accumulées dans la fenêtre d'instruction, où elles attendent que leurs opérandes soient disponibles. La fenêtre d'instruction sert donc de file d'attente. Mais elle contient aussi une unité d'émission, qui détecte quelles µops sont prêtes à être émises. L'unité d'émission et la fenêtre d'instruction sont fusionnées ensemble, elles forment un seul circuit. Mais nous allons dire qu'elles sont conceptuellement séparées pour le moment. A chaque cycle, l'unité d'émission consulte la fenêtre d'instruction pour voir quelles µops peuvent s'exécuter, lesquelles ont leurs opérandes de disponibles. La fenêtre d'instruction doit spécialement être conçue pour, c'est une sorte de mémoire associative très complexe, comme on le verra dans ce qui suit. [[File:OOO Issue.png|centre|vignette|upright=2.5|Exécution dans le désordre avec une fenêtre d'instruction]] Une fois qu'une µop sort du décodeur d'instructions, elle est ajoutée en parallèle dans la fenêtre d'instruction et le ROB. La raison est que les µops quittent la fenêtre d'instruction dans le désordre, et qu'elles doivent être remises en ordre par la suite. Le ROB s'occupe de cette remise en ordre, mais il a besoin de savoir dans quel ordre les µops sont censées être, et cet ordre est celui du décodage. Aussi, pour remplir le ROB, la seule opportunité est en sortie de l'unité de décodage. Dans le cas où une instruction est décodée en plusieurs micro-opérations, elles sont toutes insérées en même temps dans la fenêtre d'instruction et le ROB, en tenant compte de leur ordre. [[File:Fenêtre d'instruction.png|centre|vignette|upright=2|Fenêtre d'instruction.]] Les micro-opérations mémoire sont à part des autres, pour diverses raisons. Une de ces raisons est que les dépendances de données sont classées en deux types : les dépendances de registre et les dépendances d'adresse. Et les deux sont fondamentalement différentes. Autant on peut détecter les dépendances de registre lors de l'émission, autant c'est plus compliqué avec les dépendances d'adresse. De plus, rappelons que si les lectures peuvent s'exécuter dans le désordre, les écritures doivent s'exécuter dans l'ordre, ou du moins en donner l'illusion. Pour cela, le processeur remet les écritures dans l'ordre avec une sorte de mini-ROB intégré à l'unité mémoire, appelée la file d'écriture. Elle complémente le ROB, qui lui ne gère que les écritures dans les registres, mais les deux collaborent. La file d'écriture envoie une écriture à la mémoire RAM quand le ROB lui dit que c'est bon, les instructions précédentes sont terminées ''dans l'ordre du programme''. Les processeurs modernes ajoutent des techniques d'exécution dans le désordre des accès mémoire, mais nous les verrons dans un chapitre dédié. Elles permettent d'utiliser une fenêtre d'instruction unique, qui mémorise aussi les µops mémoire. Si elles sont mises en place, l'unité mémoire n'a pas besoin de file de µops séparée. L'idée est que les dépendances de registre sont traitées par la fenêtre d'instruction, mais que l'unité mémoire gére les dépendances d'adresse. Les dépendances d'adresse sont gérées par des techniques de ''désambiguation mémoire'', qui auront droit à un chapitre dédié. [[File:Processeur avec exécution dans le désodre des accès mémoire.png|centre|vignette|upright=2|Processeur avec exécution dans le désodre des accès mémoire]] Les processeurs assez anciens n'autorisaient pas d'exécution dans le désordre des accès mémoire. Concrétement, les accs mémoire devaient se faire dans l'ordre, mais les autres µops pouvaient être exécutées dans le désordre. Il s'agit donc d'un ordre entre µops mémoire, pas entre µops mémoire et autres µops. Les µops entières et flottantes pouvaient être exécutées avant une µops mémoire qui est avant elle dans l'ordre du programme, ce n'est pas un problème. Pour garantir l'ordre desd µops mémoire, l'unité mémoire est précédée par une file de micro-opérations séparée, pour forcer l'exécution dans l'ordre des accès mémoire. De plus, les µops mémoire ne peuvent pas utiliser la fenêtre d'instruction. Dit autrement, la fenêtre d'instruction ne mémorise pas de µops mémoire. Après le décodage, les µops sont réparties soit dans la file de µops mémoire, soit dans la fenêtre d'instruction. Le décodeur classe les µops suivant que ce sont des µops mémoire ou non, et les envoient à la bonne destination. Dans ce chapitre, on supposera que c'est cette solution qui est utilisée. [[File:Processeur avec émission dans l'ordre des accès mémoire.png|centre|vignette|upright=2|Processeur avec émission dans l'ordre des accès mémoire]] La solution précédente revient à scinder la fenêtre d'instruction en deux : une file de µops pour les µops mémoire, une fenêtre d'instruction pour les autres µops. Et cette scission peut aller plus loin, à savoir qu'on peut scinder une fenêtre d'instruction encore et encore. Ce qui nous amène à la section suivante. ===Les fenêtres d'instruction décentralisées=== Nous venons de voir qu'il est possible de scinder la fenêtre d'instruction en une fenêtre d'instruction pour les µops mémoire (simplifiée en une file de µops classique), et une autre pour les autres µops. Sachez qu'il est possible d'aller plus loin, par exemple en séparant la fenêtre d'instruction en une fenêtre spécialisée dans les µops flottantes et une autre pour les µops entières. Et ce n'est là qu'un exemple parmi de nombreuses autres possibilités. Pour faire la différence avec une fenêtre d'instruction unique, nous allons parler de fenêtre d'instruction centralisée s'il n'y en a qu'une, de '''fenêtre d'instruction décentralisée''' s'il y en a plusieurs. Il est possible d'associer chaque fenêtre d'instruction à un type précis de µops. Par exemple, avec une fenêtre d'instruction pour les µops de calcul entières, une autre pour les µops flottantes, une autre pour les µops mémoire. Il s'agit d'un choix simple et efficace, mais quelques processeurs font autrement, pour répondre à des contraintes très diverses. [[File:Processeur avec des fenêtres d'instruction décentralisées.png|centre|vignette|upright=2|Processeur avec des fenêtres d'instruction décentralisées]] Reste à scinder la fenêtre d'instruction pour trier les µops suivant leur type. Si le processeur exécute les accès mémoire dans l'ordre, la méthode la plus simple utilise une fenêtre d'instruction pour les opérations flottantes et une autre pour les autres µops (µops entières et parfois mémoire avec). L'avantage est que cela simplifie grandement le processeur. Les flottants sont gérés à part des entiers. Ils ont leurs propres registres, des FPU séparées des ALU entières, bref : la séparation est complète. Utiliser une fenêtre d'instruction séparée va dans ce sens. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Il est possible de faire pareil sur les processeurs avec exécution dans le désordre des accès mémoire. Par exemple : les processeurs Intel de microarchitecture Skylake utilisent une fenêtre d'instruction pour les opérations entières/flottantes, et une fenêtre d'instruction séparée pour les µops mémoire. Un avantage est que les deux fenêtres d'instructions sont plus spécialisées, ce qui entraine des économies de circuit. Les opérations entières/flottantes ont besoin de deux registres pour les opérandes et d'un autre résultat, alors que les µops mémoire n'ont besoin que de deux registres maximum. En utilisant une fenêtre d'instruction unique, chaque entrée doit mémoriser l'opcode et trois registres, dont un est inutilisé pour les µops mémoire et les branchements. En utilisant des fenêtres d’instructions séparées, celle pour les µops entières/flottantes a trois registres par entrée, contre seulement deux registres par entrée pour celle des µops mémoire. Un cas extrême est celui où chaque ALU/FPU a sa propre fenêtre d'instruction. Nous parlerons alors de '''fenêtres d'instruction totalement décentralisées'''. Par exemple, il y a une fenêtre d'instruction pour l'ALU entière, une autre pour le multiplieur entier, une autre pour le ''barrel shifter'', une autre pour l'unité mémoire, une autre pour l'unitéé de branchements, une autre pour l'additionneur flottant, une dernière pour le multiplier flottant, etc. Un exemple historique est celui de la FPU de l'IBM 360 modèle 90. Elle disposait d'un additionneur flottant, d'un multiplieur flottant, et d'une unité mémoire pour les lectures/écritures flottantes. Les trois unités avaient leur propre fenêtre d'instruction. Les processeurs AMD utilisent beaucoup cette technique, contrairement à Intel qui préfère utiliser des fenêtres centralisées sur les anciens processeurs, deux ou trois fenêtres sur les processeurs récents (2020 et plus). Les processeurs AMD utilisaient précisément une fenêtre d'instruction par ALU entière, alors que les FPUs partagent une fenêtre d’instructions flottantes unique. Mais nous verrons cela en détail dans le chapitre sur les processeurs superscalaires x86. Un point important est qu'avec des fenêtres d'instruction décentralisées, l'émission est découpée en deux étages. La première étape envoie une µops vers la fenêtre d'instruction adéquate, la seconde émet la µops depuis la fenêtre d'instruction quand ses opérandes sont prêts. La première est l'étage de '''''dispatch''''' qui envoie l'instruction dans la fenêtre d’instruction adéquate, selon que c'est une instruction flottante, entière, autre. La seconde est l'étage de '''''scheduling''''', qui gère la disponibilité des opérandes et des unités de calcul. La µop émise est ajoutée au tampon de réordonnancement, s'il existe, lors de l'étape de ''dispatch''. ===L'usage de plusieurs files d'instruction=== Une dernière méthode d'OOO utilise plusieurs files de micro-opération. L'idée est qu'une fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement une file de micro-opération pour les opérations entières, une autre pour les opérations flottantes, une autre pour les accès mémoire. D'autres processeurs utilisent une file pour les accès mémoire et une autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. La présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que la technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si une dépendance bloque une FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans une autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer la disponibilité des registres. Quand un registre est lu ou écrit par une instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. La logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : une pour les instructions d'accès mémoire et une autre pour les autres instructions. Si jamais une instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de la lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'une est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est la file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. ===Avantages et inconvénients de chaque implémentation=== Pour résumer, on a le choix entre une grosse fenêtre d'instruction généraliste et plusieurs fenêtres spécialisées. Le choix entre les deux est un compromis entre économie de circuits et flexibilité. Avec une fenêtre décentralisée, il arrive qu'une fenêtre d'instruction soit remplie, alors que les autres sont sous-utilisées, voire vides. Pour comprendre pourquoi, comparons une fenêtre d'instruction unique, avec une fenêtre décentralisée séparant µops entières et flottantes. La fenêtre centralisée dispose de 64 entrées, la décentralisée a 32 entrées pour chaque fenêtre d'instruction. La fenêtre décentralisée peut mémoriser au maximum 32 µops entières et 32 *ops flottantes. Par contre, la fenêtre centralisée peut mémoriser 64 µops tout court. Si le programme exécuté n'utilise pas de nombres flottants, la différence devient flagrante. La fenêtre décentralisée sera limitée ) 32 µops, alors que la centralisée pourra mémoriser le double. Les performances seront donc meilleures avec la fenêtre centralisée. Et au-delà de ça, la fenêtre décentralisée de l'exemple est utilisée de manière optimale si la moitié des µops sont des µops entières, et l'autre moitié des µops flottantes. Alors que la fenêtre centralisée se moque de la répartition entre µops entières et flottantes. Une subtilité est que le cout en transistors d'une fenêtre d'instruction n'est pas proportionnel au nombre de µops qu'elle peut mémoriser. Par exemple, si je compare une fenêtre d'instruction de 32 entrées (32 µops max), elle n'utilise pas deux fois plus transistors qu'une fenêtre de 16 entrées. Le cout en circuit n'est pas deux fois plus élevé, mais est approximativement 4 fois plus élevé. Le cout est presque quadratique, à savoir qu'il est proportionnel au carré du nombre d'entrées. Et il en est de même avec la performance, pour des raisons qu'on expliquera plus bas. Les fenêtres décentralisées utilisent plusieurs fenêtres d'instruction de "petite taille", donc plus rapides, économes en circuits et économes en énergie. Le compromis n'est donc pas entre une fenêtre centralisée à 64 entrées versus deux fenêtres de 32 entrées. Le compromis en pratique est entre une fenêtre centralisée de 64 entrées versus 3 fenêtres de 32 entrées. Un exemple pratique est celui de la microarchitecture ''Skylake'' d'Intel. Intel est passé d'une fenêtre centralisée pre-''Skylake'' à deux fenêtres décentralisées sur ''Skylake'',. Le nombre d'entrée était globalement le même entre les deux, même si l'évolution de la finesse de gravure entre les deux biaise un peu les résultats. Un avantage des fenêtres décentralisées est qu'il est possible de démarrer l'exécution de plusieurs µops simultanément : une µops par fenêtre d'instruction. Le fait est que deux fenêtres d'instructions différentes émettent leurs µops sans se synchroniser avec les autres. Deux fenêtres d'instruction peuvent donc émettre chacune une µops, ce qui fait deux µops émises lors du même cycle. Cela permet d'exécuter en même temps deux ou trois instructions 1-cycle, comme des additions, soustractions, décalages, etc. Il devient par exemple possible d'émettre une µop entière en même temps qu'une µop flottante, si les µops entières ont une fenêtre séparée de celle des µops flottantes. Il est maintenant temps de voir en quoi sont faites les fenêtres d’instruction, qu'elles soient centralisées ou décentralisées. Nous allons aussi voir quelle est la logique d'émission associée. ==L'implémentation d'une fenêtre d'instruction : généralités== Une fenêtre d'instruction est une mémoire qui mémorise des micro-opérations. Elle est cependant plus complexe qu'une mémoire RAM ou qu'une FIFO et ressemble un petit peu à une mémoire cache. Elle dispose d'un port d'écriture et d'un port de lecture, au minimum. Le port d'écriture permet à l'unité de décodage d'insérer une micro-opération dedans, d'ajouter la micro-opération qui vient d'être décodée. Si une instruction machine est décodée en plusieurs micro-opération, deux possibilités. La première est de les insérer un par un, ce qui fait qu'on peut se contenter d'un seul port d'écriture. L'autre possibilité est de les ajouter en même temps, ce qui demande plusieurs ports d'écriture. Le port de lecture sert à émettre une instruction. On part du principe que la fenêtre d'instruction ne peut émettre qu'une seule instruction à la fois, car les processeurs que nous avons vu précédemment sont de ce type. Mais nous verrons dans quelques chapitres qu'il existe des processeurs dits superscalaires, qui sont capables d'émettre plusieurs instructions par cycle. Dans ce cas, la fenêtre d'instruction a un seul port de lecture. Un processeur superscalaire, quant à lui, doit avoir un port de lecture par unité de calcul, ce qui fait beaucoup plus. Les fenêtres d'instruction sont composées d''''entrées''', des mots mémoire qui stockent une instruction. Une instruction réserve une entrée après son décodage et la libère dès qu'elle est envoyée aux unités de calcul. Une entrée contient l'opcode (les signaux de commande à envoyer à l'ALU), le registre de destination du résultat, les registres de chaque opérande, et éventuellement des signaux de commande en plus. De plus, chaque opérande est couplée à un bit de disponibilité, qui indique si elle est disponible. Quand un opérande est écrit dans les registres, le bit de présence correspondant est mis à jour. Enfin, chaque entrée possède un bit ''empty'' qui indique si elle est vide, cette information étant utile pour réserver des entrées. [[File:Entrée d'une station de réservation - sans les tags.png|centre|vignette|upright=3|Entrée d'une fenêtre d'instruction]] ===Les stations de réservation=== Les '''stations de réservation''' sont des fenêtres d'instruction particulières, qui sont capables de mémoriser les opérandes des instructions. Les entrées des stations de réservation sont identiques à celle des autres fenêtres d'instruction, si ce n'est que les opérandes de l'instruction sont enregistrés directement dans des champs séparés. Il y a deux champs, un par opérande, pour stocker l'opérande elle-même, lue depuis les registres ou obtenue via le réseau de contournement. Notons que les champs pour les opérandes viennent en plus des champs pour les noms de registres, encore que les deux peuvent être fusionnés si on veut optimiser le tout. [[File:Entrée d'une station de réservation.png|centre|vignette|upright=3|Entrée d'une station de réservation.]] Précisons que la terminologie n'est pas très fiable. Les termes "fenêtre d'instruction" et "station de réservation" ne regroupent pas du tout la même chose d'un papier de recherche à l'autre, d'un bouquin à l'autre, d'un chercheur à l'autre, d'un ingénieur à l'autre, d'un professeur à l'autre. Le terme initial vient pourtant de l'article original sur l'algorithme de Tomasulo, où il désignait une fenêtre d'instruction associée à une unité de calcul précise. Mais le terme a ensuite été réutilisé, ce qui fait que certains processeurs avec plusieurs unités de calcul sont décrits comme ayant une unique station de réservation. En bref : c'est le bazar ! Mais nous en reparlerons dans le chapitre sur le renommage de registres, car c'est la place idéale pour les aborder. Toujours est-il que j'ai fait le choix de confondre les concepts de fenêtre d'instruction et de station de réservation avec les concepts de '''lecture avant émission''' et de '''lecture après émission'''. La différence entre les deux est que les registres sont lus après émission avec une fenêtre d'instruction, avant avec des stations de réservation. Dans le cas "avant émission", les opérandes sont mémorisés dans la station de réservation. Et cette différence a une influence sur le pipeline du processeur, le banc de registres et tout ce qui s'en suit. Un désavantage de la lecture avant émission est qu'il faut stocker les opérandes après lecture, ici dans les stations de réservation. Mais un avantage est que le banc de registre a besoin de moins de ports de lecture, car une bonne partie des opérandes sont fournies par le système de contournement. Nous verrons cela dans le détail dans le chapitre sur les processeurs superscalaires. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Lecture après émission.]] [[File:Read Before Issue.png|centre|vignette|upright=2.5|Lecture avant émission.]] ===La logique d'éveil et de sélection=== Dans le cas qui va suivre, on suppose que le processeur ne peut émettre qu'une instruction à la fois. Chaque cycle, une instruction est sélectionnée et est envoyée dans le chemin de données, soit à une ALU, soit à une unité d'accès mémoire. La sélection d'une instruction est effectuée par l'unité d'émission, qui est aussi appelée le '''''scheduler'''''. Elle gère la disponibilité des opérandes et la disponibilité des unités de calcul adéquate. Le choix de l'instruction émise doit être le plus pertinent possible, pour des raisons de performances. Pour le premier point, l'unité d'émission détermine quelles instructions sont candidates pour l'émission. Les ''instructions candidates'' sont celles dont tous les opérandes sont prêts. Le processeur contient un circuit qui détecte les instructions candidates : la '''logique d’éveil''' (''wake-up logic''). Une fois que la logique d'éveil a fait son travail, une instruction est choisie pour s’exécuter en fonction de la disponibilité des unités de calcul adéquates. Ce rôle est dévolu à un circuit qu'on appelle la '''logique de sélection''', ou ''select logic''. [[File:Fonctionnement complet de la logique d’émission.jpg|centre|vignette|upright=1.5|Fonctionnement complet de la logique d’émission.]] La logique de sélection doit gérer le fait que les unités de calcul du processeur ne sont pas toutes identiques. Déjà, un processeur a généralement des unités séparées pour les instructions entières et flottantes, des unités spécialisées dans les accès mémoire, parfois des unités spécialisées pour les branchements. Une instruction doit être attribuée à la bonne unité de calcul, on ne doit pas envoyer une instruction entière dans une unité de calcul flottante. De plus, parmi les unités de calcul entières, toutes ne sont pas identiques. Par exemple, il est fréquent d'avoir plusieurs unités de calcul spécialisées dans les opérations simples (additions, soustractions, opérations logiques) avec une unité pour les multiplications/divisions séparées, parfois une unité spécialisée pour les décalages/rotations, etc. Là encore, allouer la bonne instruction à la bonne ALU est complexe. Plus les unités de calcul sont hétérogènes, plus la logique de sélection est compliquée. Les logiques d'éveil comme de sélection sont assez complexes. Comme on le verra plus bas, la logique de sélection la plus simple, qui gère une seule unité de calcul, est basée sur un encodeur à priorité couplé à d'autres circuits. Et pour gérer plusieurs ALUs, il faut mettre des encodeurs en cascade. Le résultat est que même en prenant une logique de sélection simple, elle sera assez lente et gourmande en circuits. Aussi, la logique de sélection met souvent un cycle d'horloge entier pour faire son travail, elle a son propre étage de pipeline attribué. La logique d'éveil est dans le même cas, ce qui fait qu'émettre une micro-opération demande deux cycles d'horloge. Le défaut est que cela rajoute des cycles d'horloges entre la fenêtre d'instruction et l'ALU, ce qui complique la gestion du pipeline. Ces cycles de retard sont à prendre en compte au moment d'émettre les instructions, les ''scheduler'' doit en tenir compte pour des performances optimales. Sans tenir compte de ces cycles de retard, les instructions arrivent en retard de quelques cycles à l'ALU, cycles de retard durant lesquels l'ALU n'a pas fait de calcul et a été sous-utilisée, sans compter que le système de contournement n'est pas utilisé au mieux. Et le problème est encore plus important sur les processeurs avec des stations de réservation, qui utilisent la "lecture après émission" : cela rajoute un cycle d'horloge en plus, un temps de retard en plus. ===La logique d'éveil : l'émission anticipée=== La logique d'éveil doit tenir compte du fait qu'il y a plusieurs étages entre l'émission et l'exécution sur une unité de calcul. Par exemple, un processeur a souvent entre un et à cinq étages entre la file d'attente et les unités de calcul. Il faut lire les registres, gérer le contournement, et cela peut prendre quelques cycles d'horloge. Sur le Pentium 4, on trouve 6 étages entre la fenêtre d’instruction et l'entrée de l'ALU. Si les micro-opérations sont émises quand les opérandes sont disponibles, il y aura un délai de quelques cycles avant qu'elles atteignent l'ALU. Alors qu'idéalement, on souhaiterait que la micro-opération atteigne l'ALU dès que ses opérandes sont disponibles, pour profiter des techniques de contournement. Pour cela, la logique d'éveil émet les instructions quelques cycles en avance pour qu'elles arrivent au bon moment. Il s'agit d'une technique d''''émission anticipée''', dont nous avions parlé dans le chapitre sur le contournement. : Il faut noter que le problème se pose plus avec des fenêtres d'instruction qu'avec des stations de réservation. Les premières ont un étage en plus entre émission et ALU, vu qu'il faut lire des registres après l'émission. L'émission anticipée demande d'émettre un signal d'éveil en avance de quelques cycles, pile au bon moment. Par exemples, si on a deux étages entre l'ALU et l'unité d'émission, le signal de réveil sera généré deux cycles avant que le résultat soit effectivement calculé. L'implémentation varie, mais deux solutions sont possibles. La première est de générer le signal d'éveil dans l'ALU, ce qui n'a de sens que pour les opérations comme les multiplications ou les divisions, qui prennent plusieurs cycles. Une autre technique génère le signal de réveil dans une structure centralisée, spécialisée dans la génération des signaux d'éveil. L'unité de composée d'un registre à décalage par registre. Imaginons qu'une instruction est émise, que cette instruction mette N cycles à s'exécuter, et qu'elle écrive dans un registre de destination. L'unité sélectionne alors le registre à décalage associé au registre de destination, et met le bit numéro N à 1. Le registre décalé d'un cran à chaque cycle. Quand le bit sortant est un 1, alors le signal de validité pour l'opérande est généré. L'émission anticipée marche bien si l'instruction a une durée fixe, connue à l'avance. Et autant c'est le cas pour les instructions arithmétiques et logiques, autant ce n'est pas le cas pour les accès mémoire. Les accès mémoire ont une latence variable : quelques cycles pour un succès de cache, plusieurs dizaines de cycles pour un défaut de cache L1, pas loin de la centaine pour un défaut de cache L2, etc. Et cela pose des problèmes pour l'émission anticipée. L'émission en avance pour les accès mémoire est purement spéculative : le processeur émet des instructions en supposant que la lecture entrainera un succès de cache, quitte à annuler l'instruction en cas de défaut de cache. Mais faire ainsi demande non seulement d'annuler les instructions émises en avance, mais aussi de ne pas retirer les instructions émises en avance de la fenêtre d'instruction. Elles sont émises, mais une copie de sauvegarde est conservée dans la fenêtre d'instruction. Si le processeur détecte un défaut de cache, il peut alors ré-exécuter l'instruction. S'il détecte un succès de cache, les instructions lecture-dépendante sont retirées de la fenêtre d'instruction, la copie de sauvegarde est devenue inutile et est donc jetée. ===La logique de sélection : âge ou position ?=== La logique de sélection est primordiale pour de bonnes performances. Il existe deux méthodes principales pour sélectionner l'instruction à exécuter. La première est la plus simple : elle se base sur lé numéro de l'entrée. En effet, une fenêtre d'instruction est avant tout une sorte de mémoire, un mix entre mémoire associative, mémoire RAM, et FIFO. Et chaque entrée a un numéro, une adresse mémoire. Nous parlerons de numéro dans ce qui suit, car ce sera plus simple, le terme d'adresse mémoire étant peut-être un peu exagéré dans le contexte des fenêtres d'instruction. Toujours est-il que la fenêtre d'instruction est adressable dans le sens où on peut lui envoyer le numéro de l'entrée voulue, et la fenêtre d’instruction renvoie le contenu de l'entrée sur son port de lecture. Et c'est ce que fait la logique de sélection : elle génère le numéro de l'entrée à lire. Le numéro est alors envoyé sur l'entrée d'adresse de la fenêtre d’instruction, et elle fournit la micro-opération associée sur son port de lecture, son '''port d'émission'''. La première méthode de sélection, donc. Elle est basée sur le numéro de l'entrée. Si plusieurs entrées sont éveillées, la logique de sélection prend celle avec le plus petit numéro. Elle porte le nom de '''sélection par position''', sous-entendu position dans la fenêtre d'instruction. Vous l'avez peut-être deviné, mais la logique de sélection est alors un encodeur à priorité. Le circuit de sélection ne se résume donc pas seulement à un encodeur à priorité, mais c'est le circuit central. L'avantage d'une telle méthode de sélection est qu'elle est simple à implémenter : un encodeur à priorité est un circuit connu, facile à implémenter. Mais on remarque un défaut : un encodeur est un circuit assez rapide, mais qui utilise beaucoup de transistors, beaucoup de portes logiques, surtout si on veut qu'il soit rapide. Ce qui explique que la logique de sélection ait son propre étage de pipeline rien que pour elle. La seconde méthode s'appelle la '''sélection par âge''', au nom assez transparent. L'idée est de privilégier l'émission de l'instruction la plus ancienne. Elle demande que la fenêtre d'instruction trie les micro-opérations par ordre d'insertion dans la fenêtre d'instruction, ce qui en fait une pseudo-FIFO. Le tri est partiel, car les instructions peuvent sortir de la fenêtre d’instruction à tout moment. Compacter la fenêtre d'instruction, à savoir regrouper toutes les entrées valides est une idée, mais elle est compliquée à implémenter. Aussi, elles préfèrent encoder des informations sur l'ordre d'émission dans chaque entrée. L'encodeur à priorité doit alors travailler non pas sur des nombres entiers liés à l'ordre d'insertion dans la pseudo-FIFO. Elle est encore plus gourmande en circuits que la méthode précédente. Les processeurs haute performance utilisent souvent des méthodes hybrides. Par exemple, les processeurs AMD de microarchitecture Bulldozer utilisaient une méthode intermédiaire. Ils utilisaient une fenêtre d'instruction couplée à un encodeur à priorité pour la sélection par position, mais complémentaient le tout avec une unité qui mémorisait l'instruction la plus ancienne dans la fenêtre d’instruction. Le mécanisme de sélection par âge était utilisé en priorité. Mais si l'instruction la plus ancienne n'était pas prête, le processeur basculait sur le mécanisme de sélection par position. ===La compaction des fenêtres d'instruction=== À chaque cycle, les instructions décodées sont ajoutées dans la fenêtre d'instruction, dans des entrées vides. Vu que les instructions quittent celle-ci dans le désordre, ces vides sont dispersés dans la fenêtre d'instruction, ce qui pose problème pour déterminer où placer les nouvelles instructions. La solution la plus triviale consiste à conserver une liste des vides, mise à jour à chaque insertion ou émission d'instruction. Une autre solution consiste à éliminer les vides en compactant la fenêtre d'instruction à chaque cycle d'horloge. Des circuits se chargent de détecter les vides et de regrouper les instructions en un unique bloc. Il faut signaler que certains processeurs arrivent à se passer de cette étape de compactage, mais au prix de fenêtres d'instruction nettement plus complexes. Autre problème : quand il faut choisir quelle instruction émettre, il y a toujours plusieurs candidats. Si on choisit mal, des instructions restent en attente trop longtemps parce que d'autres instructions plus jeunes leur passent devant. Pour éviter cela, les instructions les plus vielles, les plus anciennes, sont prioritaires. Pour cela, on peut utiliser une FIFO un peu spéciale pour la fenêtre d'instruction. Si les ajouts d'instruction se font dans l'ordre, les instructions ne quittent pas forcément la fenêtre d'instruction dans l'ordre imposé par une FIFO : les instructions restent triées dans leur ordre d'ajout, même s'il y a des vides entre elles. Dans ces conditions, il est préférable que le compactage conserve l'ordre FIFO des instructions. Dans ces conditions, l'instruction la plus ancienne est celle qui est située à l'adresse la plus faible : le circuit de sélection peut donc être fabriqué avec des encodeurs, et est relativement simple. ==Les fenêtres d'instruction basées sur une matrice de dépendances== L'implémentation la plus simple étend le fonctionnement d'un pipeline dynamique usuel. Rappelez-vous le chapitre sur les pipelines dynamiques. Nous avions vu que de tels pipelines émettaient une instruction par cycle, quitte à émettre des bulles de pipeline en cas de dépendance bloquante. Et il est possible d'améliorer leur unité d'émission pour qu'elle soit compatible avec l'exécution dans le désordre. ===Rappels sur le registre de réservation/disponibilité=== L'émission d'une instruction est gouvernée par un ''registre de réservation'' qui indique quels registres sont réservés par une instruction, et ceux qui sont libres. Un registre réservé est un registre qui sera écrit par une instruction en cours d'exécution, mais qui n'a pas encore écrit son résultat. Les instructions candidates doivent avoir leurs opérandes dans des registres libres. Sinon, c'est signe que leurs opérandes sont réservés en écriture, donc pas encore écrites, donc pas disponibles. Si une instruction candidate veut lire ce registre, c'est signe qu'il y a une dépendance RAW : elle veut lire un registre réservé, qui est destiné à être écrit par une instruction en vol. Si elle veut écrire, c'est signe qu'elle veut écrire dans un registre où une autre instruction veut écrire : c'est une dépendance WAW. Dans les deux cas, l'instruction n'est pas émise. Le registre de réservation encode les registres réservés comme suit : chaque bit est associé à un registre. Le bit numéro 0 est associé au registre numéro 0, le bit numéro 1 au registre numéro 1, etc. Là, En clair, les numéros de registres réservés sont encodés en représentation non pas binaire, mais en représentation ''one-hot'' (vue au premier chapitre). {|class="wikitable" |+ Registre de réservation |- ! Registre 7 !! Registre 6 !! Registre 5 !! Registre 4 !! Registre 3 !! Registre 2 !! Registre 1 !! Registre 0 |- | 0 || 0 || 1 || 0 || 0 || 1 || 0 || 0 |} Avant d'émettre une instruction, l'unité d'émission extrait les registres opérande/destination et les convertis dans la même représentation que le registre de réservation, à savoir en représentation ''one-hot''. Le circuit de traduction binaire vers ''one-hot'' est, pour rappel, un simple décodeur. Puis, on fait un OU logique entre les sorties des décodeurs. Le résultat est un masque qui indique quels registres sont lus par l'instruction, encodé en représentation ''one-hot''. Appelons-le le '''masque d'opérandes'''. Le masque est alors comparé au registre de réservation pour vérifier si l'instruction peut être émise. [[File:Unité d'émission simple, dans l'ordre.png|centre|vignette|upright=2|Unité d'émission simple, dans l'ordre]] Si l'émission est autorisée, le registre de réservation est là aussi mis à jour. Le registre de réservation est aussi mis à jour dès qu'une instruction enregistre son résultat dans les registres, ou alors dès qu'il est disponible pour le contournement. Le bit associé au registre repasse alors à 0 (ou à 1). Sans contournement, la mise à jour se fait alors à la toute fin de l'instruction, quand elle se termine, lors de la dernière étape d'enregistrement, à la fin de son pipeline. Avec, elle se fait quand l'instruction quitte l'unité de calcul. ===L'extension à l'exécution dans le désordre : l'éveil par matrice de bits=== La différence entre un pipeline dynamique et l'exécution dans le désordre est que l'on passe d'une instruction à émettre à plusieurs. Plusieurs instructions sont mises en attente dans une fenêtre d’instruction, et y attendent leur tour. L'idée est alors d'envoyer le registre de disponibilité à toutes les entrées, à toutes les instructions en attente. Ainsi, on sait quelles sont les instructions qui peuvent s'exécuter et celles qui ne le peuvent pas. L'implémentation est assez simple, elle ressemble beaucoup à l'implémentation d'un pipeline dynamique simple, si ce n'est que des circuits sont dupliqués. L'implémentation utilise des fenêtres d'instruction légèrement différentes de celles introduites plus haut. Elles n'utilisent notamment pas de bits de disponibilité, mais autre chose. Lorsqu'une instruction est ajoutée à la fenêtre d'instruction, le masque de disponibilité des opérandes est stocké dans la fenêtre d'instruction. A chaque cycle, le registre de disponibilité est envoyé à toutes les entrées, et est comparé avec tous les masques de disponibilité des opérandes. Si une comparaison renvoie un 1, alors l'instruction de l'entrée est une instruction candidate à l'émission. [[File:Unité d'émission dans le désordre basée sur un registre de disponibilité.png|centre|vignette|upright=2.5|Unité d'émission dans le désordre basée sur un registre de disponibilité]] L'ensemble est implémenté avec l'aide d'une '''matrice de bits''', où chaque ligne correspond à une entrée et chaque colonne à un registre. À chaque croisement entre une ligne et une colonne, on trouve un bit. Si le bit de la ligne n et de la colonne m est à 1, cela veut dire : l'instruction dans l'entrée n a besoin de lire le registre m. S’il est à 0, alors cela veut dire que l'instruction stockée dans la ligne n'a pas besoin de la donnée dans le registre m. [[File:Planificateur à matrice de bits.jpg|centre|vignette|upright=2|Planificateur à matrice de bits.]] Lorsqu'une instruction réserve une entrée, elle initialise la ligne en fonction des registres qu'elle souhaite lire. Pour vérifier si une instruction a ses opérandes prêts, le processeur compare le registre de disponibilité à la ligne associée à l'instruction/entrée. A chaque intersection ligne-colonne, se trouve un comparateur de 1 bit, qui détecte si le registre est demandé et disponible. Les résultats de cette porte sont ensuite envoyés à une porte ET, qui fait le gros du travail. [[File:Logique de détection de la disponibilité d'une instruction.jpg|centre|vignette|upright=2|Logique de détection de la disponibilité d'une instruction.]] ==Les fenêtres d'instruction basées sur une mémoire associative== Les processeurs modernes utilisent une mémoire associative pour la fenêtre d'instruction. Les mémoires associatives ont été abordées il y a quelques chapitres, mais faisons quelques rappels. Les mémoires associatives servent à accélérer la recherche de données dans un ensemble. Or, une fenêtre d'instruction vérifie régulièrement si chaque entrée est prête. Il s'agit d'un processus de recherche d'une instruction qui respecte une condition bien précise dans la mémoire, ce qui fait que les mémoires associatives sont donc tout indiquées. Comme vous le savez, les signaux de commande d'une instruction sont propagés avec celle-ci dans le pipeline, le nom du registre de destination ne faisant pas exception. Le nom de registre est envoyé à la fenêtre d'instruction lors de l'écriture du résultat dans les registres. S'il y a correspondance, l'opérande est disponible et son bit de disponibilité est mis à 1. On peut adapter cette méthode pour tenir compte du contournement assez simplement. [[File:Détection des dépendances par propagation du registre de destination.png|centre|vignette|upright=2|Détection des dépendances par propagation du registre de destination.]] En conséquence, le circuit de détection des dépendances est constitué d'un grand nombre de comparateurs : un par champ « nom de registre » dans chaque entrée. La logique d'éveil/''wake up'' regroupe tous les comparateurs, la logique de sélection est un circuit situé en-dehors de la mémoire associative. Les entrées sont dans la mémoire associative elle-même. [[File:Gestion des bits de validité.png|centre|vignette|upright=2|Gestion des bits de validité.]] L'implémentation la plus simple est celle du schéma précédent, où on utilise une mémoire associative unique. Une version plus élaborée sépare la fenêtre d'instruction en deux parties : une mémoire qui mémorise les registres des opérandes, une autre mémoire pour le reste. La mémoire pour les registres opérandes est la mémoire associative proprement dite, c'est elle qui est associée aux comparateurs, à la logique de ''wake-up''/réveil, etc. Par contre, l'autre mémoire est une mémoire RAM simplifiée, qui mémorise les informations qui n'ont pas besoin des comparateurs. L'opcode de l'instruction est là-dedans, par exemple. La fenêtre d'instruction est donc une sorte de mémoire associative améliorée. Il se trouve que c'est aussi le cas du ROB. Et il est possible de fusionner le tampon de ré-ordonnancement avec la fenêtre d'instruction dans une structure unique. La différence avec une fenêtre d’instruction normale est que les entrées sont libérées non pas quand l'instruction est exécutée/émise, mais quand elle termine son exécution et quitte le ROB. La fenêtre d'instruction incorpore des bits dans chaque entrée, pour savoir si la µops associée a été émise et est en cours de traitement dans les ALUs. La méthode a notamment été utilisée sur les processeurs d'architecture K6 d'AMD. Le tout donnait une structure appelée le '''DRIS''' (''deferred scheduling register renaming instruction shelf''). Les processeurs PA 8000 de HP étaient aussi vraisemblabment dans ce cas, aussi. ===Les optimisations de la consommation d'énergie : la désactivation des portions inutilisées=== Le problème avec des fenêtres d'instruction de ce type est leur forte consommation énergétique, ainsi que le grand nombre de portes logiques utilisées, qui deviennent prohibitifs pour des fenêtres d'instruction un peu grosses. Pour résoudre ce problème, certains ont optimisé les comparateurs. D'autres ont tenté de profiter du fait que la majorité des bits dans les entrées sont composés de zéros. Bref, les optimisations purement matérielles sont légion. Une première solution est de désactiver les entrées qui sont inutilisées, vides, sans instruction. Pour cela, on fait précéder les comparateurs par un circuit qui les connecte ou déconnecte des lignes de bit. Le circuit est commandé par le bit ''empty'' qui indique si une entrée est vide ou non. L'avantage est que la consommation d'énergie de la fenêtre d'instruction devient alors proportionnelle au nombre d'entrées non-vides, et non au nombre d'entrées total. Du moins, en apparence, les entrées non-utilisées doivent quand même être alimentées pour fonctionner, mais l'activité de comparaison disparait dans les entrées vides. Il est possible d'étendre cette technique aux entrées dont les opérandes sont prêts. Les gains sont généralement assez bons, avec une réduction de consommation variant entre 30 et 50%, avec une implémentation très simple et très économe en circuits. Une autre solution, assez simple à mettre en place, consiste à désactiver une partie de la fenêtre d'instruction sin elle est inutilisée. Pour cela, il faut segmenter la fenêtre d'instruction avec la technique du ''wire partitionning''. Pour rappel, une fenêtre d'instruction est une mémoire associative. Et comme toute mémoire associative, elle contient des fils, les lignes de bit, qui relient les entrées/sorties à toutes les cellules mémoire. Plus une ligne de bit est longue, plus elle consomme d'énergie et plus le temps de lecture/écriture est long. L'idée est de segmenter les lignes de bits en plaçant des répéteurs qui recopient la tension d'un segment au suivant. Les répéteurs sont des tampons trois-états, ce qui permet de déconnecter les portions inutilisées de la ligne de bit. Ce faisant, la fenêtre d'instruction est découpée en segments, qui peuvent être désactivés si besoin. S'il y a peu d'instructions chargées dans la fenêtre d'instruction, les portions inutilisées sont désactivées. La technique marche d'autan mieux si les instructions sont compactées au début de la fenêtre d'instruction. [[File:Wire partitionning.png|centre|vignette|upright=2|Wire partitionning]] Tout le problème est de savoir quelles portions désactiver. La technique est assez simple si la fenêtre d'instruction est compactée, à savoir si toutes les instructions sont régulièrement regroupées au début de la mémoire CAM. Mais même avec cette optimisation, la décision de désactiver une portion de la fenêtre d'instruction n'est pas à prendre à la légère. Il ne faut pas désactiver une portion contenant des instructions pouvant être émise sous peu. La décision dépend de paramètres variés : proportion d'entrée vides, quantité d'entrées récemment activées/désactivées récemment, présences d'entrées avec un ''match'' d'opérandes récent, etc. Il est important de préciser que les techniques en question fonctionnent aussi sur les autres types de fenêtre d'instruction, qui ne sont pas basées sur des mémoires associatives. Nous allons voir celles-ci dans la suite du chapitre, mais gardez à l'esprit que ces optimisations, à savoir désactiver les entrées vides/prêts et partitionner la fenêtre d'instruction, sont des optimisations générales qui marchent avec presque tout. ===L'ajout d'une FIFO pour les instructions déjà prêtes à l'émission=== D'autres techniques permettent de réduire aussi bien le cout en circuits que la consommation d'énergie de la fenêtre d'instruction. L'idée est d'utiliser une mémoire associative quand elle est réellement nécessaire, mais d'utiliser une fenêtre d'instruction "normale" dès que possible. La méthode la plus simple tient compte du fait que certaines µopsont déjà toutes leurs opérandes de disponibles à l'émission, mais doivent quand même être mises en attente, parce que l'ALU adéquate est occupée, parce que des dépendances WAW/WAR sont encore là, ou pour tout autre raison. Dans ce cas, elles sont mises en attente non pas dans la fenêtre d'instruction, mais dans une mémoire FIFO toute simple. L'idée est qu'au lieu d'avoir une énorme mémoire associative pour la fenêtre d'instruction, on déplace quelques entrées dans une petite FIFO annexe. Le résultat est un gain d'énergie et de circuits, au prix d'une perte de performance mineure. La perte de performance en question se manifeste si aucune instruction n'a ses opérandes de prêtes à l'émission : le programme n'utilise pas la FIFO et voit alors une fenêtre d'instruction plus petite. Une amélioration de cette technique tient compte du fait que certaines instructions sont dans un cas intermédiaire. Elles ont déjà un opérande de prête lors de l'émission, mais pas l'autre. Le nombre d'opérandes varie suivant l’instruction : certaines n'ont besoin que d'un seul opérande. De plus, il arrive qu'une opération tout juste décodée ait déjà un ou plusieurs de ses opérandes de prêts. Cette constatation permet d'éviter d'utiliser des comparateurs pour les opérandes déjà prêts. Par exemple, on peut parfaitement utiliser trois fenêtres d'instruction : * une pour les instructions dont tous les opérandes sont prêts, mais qui sont quand même mises en attente, sans comparateur ; * une pour les instructions dont un seul opérande manque, qui n'utilise qu'un comparateur par entrée ; * une pour les instructions dont deux opérandes manquent à l'appel, qui utilise deux comparateurs par entrée. C'est beaucoup plus économique que d'utiliser une seule grosse fenêtre d'instruction qui contiendrait autant d'entrées que les trois précédentes réunies, avec deux comparateurs par entrée. Certains sont même allés plus loin, et ont proposé de supprimer la fenêtre d'instruction avec deux opérandes par entrée. Les instructions dont deux opérandes sont inconnus au décodage sont stockées dans la fenêtre d'instruction pour instructions avec un comparateur par entrée. Un circuit de prédiction se charge alors de prédire l'opérande manquant, cette prédiction étant vérifiée plus loin dans le pipeline. Il serait cependant étonnant qu'une telle proposition ait donné lieu à la moindre implémentation réelle. ===Les optimisations de la consommation d'énergie avancées=== D'autres chercheurs ont conservé une fenêtre d'instruction unique, avec autant de comparateurs par entrée qu'il y a d'opérandes possibles par instruction. Simplement, le processus de détection des opérandes prêts est légèrement ralenti : on ne vérifie qu'un opérande par cycle. Pour vérifier les deux opérandes d'une entrée, on doit attendre deux cycles. Enfin, certains chercheurs ont proposé des fenêtres d'instruction segmentées. Les instructions circulent à chaque cycle d'un segment vers le suivant : en conséquence, certains segments conservent les instructions les plus anciennes, un autre les instructions les plus jeunes, etc. Seul le denier segment, celui qui contient les instructions les plus vielles, peut émettre une instruction : la détection des opérandes se fait seulement dans le dernier segment, qui contient les instructions les plus anciennes. On économise ainsi beaucoup de comparateurs. Certains chercheurs ont tenté de pipeliner l'étape de sélection des opérandes, ainsi que l'étage d'arbitrage. Mais en faisant cela, il faut plusieurs cycles pour détecter qu'une instruction a ses opérandes prêts, ce qui pose problème face à de nombreuses dépendances RAW. Pour éviter de trop perdre en performances, certains chercheurs ont décidé d'utiliser des techniques pour prédire quelles seront les instructions dont les opérandes seront bientôt prêts. Si détecter qu'une instruction est prête prend n cycles, le processeur devra tenter de prédire la future disponibilité des opérandes n cycles en avance pour obtenir des performances optimales. ===Remplacer la mémoire associative par une RAM=== Une autre optimisation possible est de remplacer la fenêtre d'instruction par une mémoire RAM, dont chaque mot mémoire correspondrait à une entrée. Une telle optimisation permet en théorie de se passer des comparateurs associés à chaque entrée, mais au prix de l'ajout de circuits annexes potentiellement couteux. La première de ces techniques, la '''recherche directe par étiquette''' (direct tag search) fut créée par Weiss et son collègue Smith. Ils cherchaient à améliorer l'algorithme de Tomasulo, un algorithme qu'on expliquera dans quelques chapitres. Rappelons que chaque instruction produit un résultat, qui devra être rapatrié dans une ou plusieurs entrées de la fenêtre d'instruction. L'optimisation de la recherche directe par étiquette fonctionne dans le cas où le résultat de l'instruction n'est utilisé que par une seule entrée, et pas plusieurs. Le principe est simple : chaque champ « opérande » d'une entrée est adressable via le nom de registre de cet opérande. Pour faire le lien entre entrée et nom de registre, la recherche directe par étiquette ajoute une table de correspondances matérielle, une mémoire RAM qui mémorise les adresses des champs « opérande » des entrées. Les adresses envoyées dans cette mémoire sont les noms de registres des résultats. Lors de l'émission, la table de correspondances est mise à jour. Les numéros des champs « opérande » réservés lors de l'émission sont mémorisés dans les mots mémoire qui correspondent aux deux registres sources. Toutefois, une petite vérification est faite lors de l'émission : s'il y a déjà une correspondance dans la table pour un registre source, alors une autre instruction compte lire ce registre. Pour éviter d'écraser les données de l'instruction précédente dans la table de correspondances, l'émission de l'instruction est bloquée. [[File:Recherche directe par étiquette.png|centre|vignette|upright=2|Recherche directe par étiquette.]] ==Les fenêtres d’instruction avec préplanification== Avec la '''préplanification''' (''prescheduling''), la fenêtre d’instruction est composée de mémoires FIFO dans lesquelles les instructions sont triées dans l'ordre d'émission. Il n'y a pas de logique d’émission proprement dite, celle-ci se bornant à vérifier si l'instruction située au début de la FIFO peut s’exécuter. Par contre, le préplanificateur détecte les dépendances et en déduit où insérer les instructions dans le tampon d'émission, à l'endroit le plus adéquat. [[File:Préplanification.jpg|centre|vignette|upright=2|Préplanification.]] ===L'usage de FIFO multiples=== La technique de préplanification la plus simple utilise plusieurs FIFO. Quand une instruction a une dépendance avec une autre instruction, les deux sont placées dans la même FIFO. Pour cela, le préplanificateur détecte les chaines d'instructions dépendantes, et place les instructions dans la FIFO adéquate. A chaque cycle, l'unité d'émission lit une micro-opération dans chaque FIFO et vérifie si elle peut l'émettre. Si la micro-opération n'a pas ses opérandes disponibles, ou qu'une dépendance structurelle survient, alors la FIFO est bloquée. La micro-opération attend que la dépendance soit résolue, bloquant toutes les instructions précédentes. Mais les autres FIFO ne sont pas bloquées, laissant de la marge de manœuvre. [[File:Préplanification par FIFO multiples.png|centre|vignette|upright=1.5|Préplanification par FIFO multiples.]] ===La technique du tampon trié=== La technique du '''tampon trié''' trie les instructions selon le temps d'attente avant leur exécution. Les instructions qui sont censées s’exécuter bientôt sont insérées au tout début de la FIFO, tandis que les instructions qui s’exécuteront dans un long moment sont insérées vers la fin. Là encore, l'unité d'émission lit une micro-opération dans la FIFO, et détermine si elle peut être émise. Si une dépendance survient, l'émission est retardée, et la FIFO est bloquée. [[File:Préplanification par tampon trié.png|centre|vignette|upright=1.5|Préplanification par tampon trié.]] La technique a cependant quelques problèmes assez importants. Le premier problème est que la FIFO est bloquée lorsqu'une micro-opération ne peut être émise. Le second problème est que le temps avant exécution n'est pas toujours connu, notamment pour les instructions d'accès mémoire. Et cela se répercute sur les instructions dépendantes de celles-ci. Pour résoudre ce genre de problèmes, l'usage d'un pipeline à ''replay'' est possible, et est même l'une des meilleures solutions possible, malgré ses défauts. L'idée est que les lectures sont pré-planifiées en supposant qu'elles font un succès de cache L1. Si la prédiction est fausse, la lecture est ré-exécutée plusieurs cycles plus tard, en supposant qu'elle fait un succès dans le cache L2, et ainsi de suite. Elle est alors ré-insérée dans la FIFO, elle est pré-planifiée une seconde fois. Il en est de même si une micro-opération ne peut pas être émise : il suffit de la réinsérer dans la FIFO au bon endroit, en attendant que ses dépendances soient résolues. Ainsi, l'instruction fautive ne bloque pas la fenêtre d’instruction, et retente sa chance autant de fois qu'il le faut. [[File:Préplanification par fenêtre d’instruction scorebarodée.png|centre|vignette|upright=1.5|Préplanification par fenêtre d’instruction scorebarodée.]] Une autre solution utilise deux fenêtres d’instruction : une FIFO gérée par la préplanification, et une vraie fenêtre d'instruction pour les instructions dont le temps d'attente ne peut pas être déterminé. Il est possible de mettre cette dernière avant la préplanification, afin de gérer les temps d'attente des instructions d'accès mémoire. Quand le temps d'attente d'une lecture devient connu, ses instructions dépendantes sont gérées avec préplanification. [[File:Préplanification avec fenêtre d’instruction.png|centre|vignette|upright=2.5|Préplanification avec fenêtre d’instruction.]] ===Les fenêtres d'instruction avec allocation temporelle statique=== L''''allocation temporelle statique''' correspond à une technique utilisée sur les processeurs Cuzco de l'entreprise Condor. La technique en question a été présenté en 2025, mais des idées similaires ont été présentées dans la littérature académique. Elle ressemble beaucoup aux techniques de pré-planification, avec cependant quelques différences. L'idée est simple : le processeur dispose de plusieurs fenêtres d'instruction, qui mettent en attente les micro-opérations. Lors de l'étape de renommage de registres, le processeur détermine dans combien de cycles d'horloge la micro-opération sera prête pour exécution. La micro-opération est alors mise en attente durant ce nombre de cycles, dans les fenêtres d'instruction, puis est émise une fois ce nombre de cycles écoulés. Ce faisant, les fenêtres d'instruction n'ont pas besoin de détecter la disponibilité des opérandes à chaque cycle, pour chaque micro-opération en attente. Le ''timing'' de l'émission des micro-opérations est décidé à l'avance. L'implémentation exacte n'est pas connue, mais plusieurs solutions sont imaginables. Par exemple, la fenêtre d'instruction peut simplement être composée de plusieurs mémoires de petite taille, chacune contenant les micro-opérations destinées à être exécutées dans N cycles, N étant différent pour chaque mémoire. Une autre solution, plus réaliste, utilise une fenêtre d'instruction dans laquelle la micro-opération est couplée à des champs pour les opérandes, et un champ compteur. Le champ compteur est initialisé avec le nombre de cycles à attendre, et est décrémenté à chaque cycle d'horloge. Quand il atteint zéro, la micro-opération est émise. Vous remarquerez que la méthode ne marche que si toutes les micro-opérations prennent un nombre fixe de cycles d'horloge. Et autant c'est le cas pour les micro-opérations arithmétiques ou logiques, autant les accès mémoire ne rentrent pas dans ce cadre. En théorie, on ne sait pas combien de temps prendra un accès mémoire. Et cette incertitude se répercute sur les instructions dépendantes d'un accès mémoire. Pour éviter cela, le processeur réutilise un pipeline à ''replay'' tel que vu dans le chapitre précédent. L'unité de renommage de registre suppose que tout accès mémoire fait un succès de cache L1, et décide des ''timings'' d'émission sous cette hypothèse. Si une lecture subit un défaut de cache, elle est ré-exécutée, de même que toutes les instructions dépendantes. Pour cela, le registre de destination de la lecture est marqué comme invalide, grâce à un bit spécifique attaché au registre. Toute instruction qui lit un opérande invalide est elle aussi ré-executée de zéro. Pour simplifier, l'unité d'émission ressemble à une unité d'émission dans l'ordre, avec un registre de disponibilité, qu'on aurait amélioré pour aller au-delà de la simple détection des dépendances d'instruction. Pour déterminer les ''timings'' d'émission, à savoir quand émettre une micro-opération, le processeur utilise une unité d'émission à deux étages. Le premier étage est appelé le ''register scoreboard'', le second étage est appelé la ''Time Ressource Matrix''. Les deux étages communiquent entre eux, comme on va le voir, et leurs noms donnent une idée de ce qu'ils font. Le premier étage gère les dépendances de registres, le second gère les dépendances structurelles. Le premier étage est un registre de disponibilité amélioré, qui gère les dépendances de registre. Cet étage sait quand tel registre sera écrit, et donc que l'opérande écrit dedans sera disponible à partir de tel cycle d'horloge. Il le sait car l'étage suivant l'aura prévenu, mais laissons cela de côté pour le moment. Quand une micro-opération rentre dans cet étage, il vérifie les dépendances avec les registres et les micro-opérations antérieures. Vu qu'il sait quand les registres seront disponibles, il peut déterminer quand l'instruction pourra s'exécuter. Par exemple, si une micro-opération lit les deux registres R7 et R15, qui sont disponibles respectivement dans 5 et 7 cycles, le premier étage sait que la micro-opération devra attendre 7 cycles. Mais tout cela ne suffit pas à déterminer quand émettre une micro-opération. En effet, il fait aussi gérer les dépendances structurelles, ce qui est le boulot du second étage. Le second étage utilise pour cela une ''Time Ressource Matrix'', qui mémorise l'occupation de diverses "ressources", pour les 256 cycles d'horloge à venir. Les ressources en question sont les ports de lecture/écriture du banc de registre, les ALUs utilisées, si la micro-opération utilise l'unité mémoire, etc. Le second étage prend en entrée une micro-opération, détermine quelles "ressources" elle utilise, puis regarde leur disponibilité. Elle détecte alors les dépendances structurelles et détermine alors quand peut s'exécuter la micro-opération. Elle peut retarder l'émission de quelques cycles, si une dépendance structurelle est détectée. Une fois sortie du second étage, on sait quand la micro-opération va être émise, à quel cycle précisément. Et vu que la durée de l'instruction est fixe, on sait quand cette micro-opération va se terminer, quand son résultat sera disponible. Cela permet de mettre à jour la ''Time Ressource Matrix'', pour préciser que le port d'écriture sera occupé à tel moment. De plus, cette information est transmise au premier étage, qui sait alors quand est enregistré le résultat dans le registre de destination. C'est comme cela que le premier étage sait quand un registre est disponible : le second étage le prévient, quand il émet une instruction ! La ''Time Ressource Matrix''mémorise l'occupation des "ressources" pour les 256 cycles d'horloge à venir. Cependant, elle ne vérifie pas les dépendances pour les 256 cycles suivants. Quand elle reçoit une micro-opération, elle teste les dépendances structurelles pour seulement les 8 prochains cycles maximum. Si la micro-opération ne peut pas être émise pendant ces 8 cycles, le pipeline est bloqué, un ''pipeline stall'' est émis. Pour être plus précis, vu que le processeur peut décoder 8 micro-opérations en même temps, cela permet de ne consulter que 64 cycles d'horloge sur les 256. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les premiers processeurs Intel | prevText=Les premiers processeurs Intel | next=Le renommage de registres | nextText=Le renommage de registres }} </noinclude> etxr5hx1grjzdwdzl5swzx9sdx8tqbn 773612 773611 2026-09-29T20:18:23Z Mewtow 31375 773612 wikitext text/x-wiki Dans les chapitres précédents, nous avons parlé des techniques dites d''''émission dans l'ordre'''. L'idée est d’exécuter une nouvelle micro-opération à chaque cycle, dans des unités de calcul séparées. Les instructions sont émises consécutivement, mais les instructions s’exécutent en parallèle dans des unités de calcul séparées. Par contre, quand l'unité d'émission ne peut pas émettre une instruction, elle bloque tout le pipeline. Les instructions qui suivent sont elles aussi bloquées, elles doivent attendre leur tour, même si elles sont en capacité de s'exécuter. Les techniques d'exécution dans le désordre que nous allons voir dans ce chapitre corrigent ce point précis. Elles sont dites à '''émission dans le désordre'''. Elles se distinguent des précédentes sur un point précis : quand l'unité d'émission bloque l'émission d'une instruction, les instructions suivantes peuvent poursuivre. L'émission des instructions peut donc se faire dans le désordre, dans le sens où une instruction peut être émise alors qu'une instruction précédente ne l'est pas encore. L'avantage de l'émission dans le désordre est qu'une instruction s'exécute dès que ses opérandes sont disponibles. Par disponible, on veut dire présent soit dans le réseau de contournement, soit dans les registres. Le processeur détecte automatiquement quand les opérandes d'une instruction sont disponibles, et il l’exécute à ce moment-là. Dès qu'une instruction a ses opérandes disponibles, elle est émise et exécutée. C'est là la seule contrainte : les dépendances WAR, WAW et autres sont gérées par un ROB ou toute autre technique d'exception précise, seules les dépendances RAW limitent l'exécution. Mais avant de poursuivre, quelques point niveaux terminologie : * L'émission dans le désordre est un terme parlant et assez précis. Malheureusement, la terminologie la plus utilisée par d''''exécution dans le désordre'''. Et nous utiliserons ce terme dans la suite du cours, histoire de ne pas trop dévier de la nomenclature habituelle. * Nous utiliserons parfois l'abréviation OOO pour parler d'exécution dans le désordre. L'abréviation est celle de ''Out Of Order Excution''. * Nous utiliserons aussi l'abréviation ''µop'' pour parler de micro-opération, ''µops'' au pluriel pour parler de plusieurs micro-opérations, ou des micro-opérations en général. L'exécution dans le désordre ne gère en effet que des µops, elle se situe après l'étape de décodage. ==Les fenêtres d’instruction : généralités== Pour décrire comment est implémentée l'émission dans le désordre, il faut commencer par parler des processeurs sans. Les processeurs sans exécution dans le désordre ont une unité d'émission qui bloque tout le pipeline dès qu'une µop ne peut pas être émise. Pour limiter l'impact de ce blocage, quelques rares processeurs incorporent une '''file de micro-opération''', une mémoire FIFO qui met en attente les µops. Vu que c'est une mémoire FIFO, les µops sont émises dans l'ordre, à savoir l'ordre d'ajout, dans l'ordre de décodage. Le schéma ci-dessous illustre une telle file d'attente couplée à un ''scoreboard''. Sur le principe, l'exécution dans le désordre améliore la file de µops sur un point : ce n'est plus une mémoire FIFO. Les µops sont insérées dans l'ordre, mais peuvent sortir dans le désordre (être émises dans le désordre). La file de µops devient alors une '''fenêtre d'instruction''', terme traduit directement de l'anglais ''instruction Window''. Terme assez trompeur, car elles mettent en attente des µops, pas des instructions. Elles peuvent émettre des µops dans le désordre, ce qui fait que si une µop bloque le pipeline, les µops suivantes peuvent être émises. [[File:Différence file µops et fenêtres instruction.png|centre|vignette|upright=2|Différence file µops et fenêtres instruction]] Je commence le paragraphe précédent par "sur le principe", car certaines techniques d'OOO n'utilisent pas de fenêtre d'instrruction. Dans les grandes lignes, il existe dans les grandes lignes 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! Fenêtre d'instruction |- ! Une seule | ''Scoreboard'' | Fenêtre d'instruction centralisée |- ! Plusieurs | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | Fenêtre d'instruction décentralisée |} Voyons les dans le détail. ===La fenêtre d'instruction centralisée=== L'implémentation la plus simple de l'OOO utilise une unique fenêtre d'instruction, appelée une '''fenêtre d'instruction centralisée'''. Les µops décodées sont accumulées dans la fenêtre d'instruction, où elles attendent que leurs opérandes soient disponibles. La fenêtre d'instruction sert donc de file d'attente. Mais elle contient aussi une unité d'émission, qui détecte quelles µops sont prêtes à être émises. L'unité d'émission et la fenêtre d'instruction sont fusionnées ensemble, elles forment un seul circuit. Mais nous allons dire qu'elles sont conceptuellement séparées pour le moment. A chaque cycle, l'unité d'émission consulte la fenêtre d'instruction pour voir quelles µops peuvent s'exécuter, lesquelles ont leurs opérandes de disponibles. La fenêtre d'instruction doit spécialement être conçue pour, c'est une sorte de mémoire associative très complexe, comme on le verra dans ce qui suit. [[File:OOO Issue.png|centre|vignette|upright=2.5|Exécution dans le désordre avec une fenêtre d'instruction]] Une fois qu'une µop sort du décodeur d'instructions, elle est ajoutée en parallèle dans la fenêtre d'instruction et le ROB. La raison est que les µops quittent la fenêtre d'instruction dans le désordre, et qu'elles doivent être remises en ordre par la suite. Le ROB s'occupe de cette remise en ordre, mais il a besoin de savoir dans quel ordre les µops sont censées être, et cet ordre est celui du décodage. Aussi, pour remplir le ROB, la seule opportunité est en sortie de l'unité de décodage. Dans le cas où une instruction est décodée en plusieurs micro-opérations, elles sont toutes insérées en même temps dans la fenêtre d'instruction et le ROB, en tenant compte de leur ordre. [[File:Fenêtre d'instruction.png|centre|vignette|upright=2|Fenêtre d'instruction.]] Les micro-opérations mémoire sont à part des autres, pour diverses raisons. Une de ces raisons est que les dépendances de données sont classées en deux types : les dépendances de registre et les dépendances d'adresse. Et les deux sont fondamentalement différentes. Autant on peut détecter les dépendances de registre lors de l'émission, autant c'est plus compliqué avec les dépendances d'adresse. De plus, rappelons que si les lectures peuvent s'exécuter dans le désordre, les écritures doivent s'exécuter dans l'ordre, ou du moins en donner l'illusion. Pour cela, le processeur remet les écritures dans l'ordre avec une sorte de mini-ROB intégré à l'unité mémoire, appelée la file d'écriture. Elle complémente le ROB, qui lui ne gère que les écritures dans les registres, mais les deux collaborent. La file d'écriture envoie une écriture à la mémoire RAM quand le ROB lui dit que c'est bon, les instructions précédentes sont terminées ''dans l'ordre du programme''. Les processeurs modernes ajoutent des techniques d'exécution dans le désordre des accès mémoire, mais nous les verrons dans un chapitre dédié. Elles permettent d'utiliser une fenêtre d'instruction unique, qui mémorise aussi les µops mémoire. Si elles sont mises en place, l'unité mémoire n'a pas besoin de file de µops séparée. L'idée est que les dépendances de registre sont traitées par la fenêtre d'instruction, mais que l'unité mémoire gére les dépendances d'adresse. Les dépendances d'adresse sont gérées par des techniques de ''désambiguation mémoire'', qui auront droit à un chapitre dédié. [[File:Processeur avec exécution dans le désodre des accès mémoire.png|centre|vignette|upright=2|Processeur avec exécution dans le désodre des accès mémoire]] Les processeurs assez anciens n'autorisaient pas d'exécution dans le désordre des accès mémoire. Concrétement, les accs mémoire devaient se faire dans l'ordre, mais les autres µops pouvaient être exécutées dans le désordre. Il s'agit donc d'un ordre entre µops mémoire, pas entre µops mémoire et autres µops. Les µops entières et flottantes pouvaient être exécutées avant une µops mémoire qui est avant elle dans l'ordre du programme, ce n'est pas un problème. Pour garantir l'ordre desd µops mémoire, l'unité mémoire est précédée par une file de micro-opérations séparée, pour forcer l'exécution dans l'ordre des accès mémoire. De plus, les µops mémoire ne peuvent pas utiliser la fenêtre d'instruction. Dit autrement, la fenêtre d'instruction ne mémorise pas de µops mémoire. Après le décodage, les µops sont réparties soit dans la file de µops mémoire, soit dans la fenêtre d'instruction. Le décodeur classe les µops suivant que ce sont des µops mémoire ou non, et les envoient à la bonne destination. Dans ce chapitre, on supposera que c'est cette solution qui est utilisée. [[File:Processeur avec émission dans l'ordre des accès mémoire.png|centre|vignette|upright=2|Processeur avec émission dans l'ordre des accès mémoire]] La solution précédente revient à scinder la fenêtre d'instruction en deux : une file de µops pour les µops mémoire, une fenêtre d'instruction pour les autres µops. Et cette scission peut aller plus loin, à savoir qu'on peut scinder une fenêtre d'instruction encore et encore. Ce qui nous amène à la section suivante. ===Les fenêtres d'instruction décentralisées=== Nous venons de voir qu'il est possible de scinder la fenêtre d'instruction en une fenêtre d'instruction pour les µops mémoire (simplifiée en une file de µops classique), et une autre pour les autres µops. Sachez qu'il est possible d'aller plus loin, par exemple en séparant la fenêtre d'instruction en une fenêtre spécialisée dans les µops flottantes et une autre pour les µops entières. Et ce n'est là qu'un exemple parmi de nombreuses autres possibilités. Pour faire la différence avec une fenêtre d'instruction unique, nous allons parler de fenêtre d'instruction centralisée s'il n'y en a qu'une, de '''fenêtre d'instruction décentralisée''' s'il y en a plusieurs. Il est possible d'associer chaque fenêtre d'instruction à un type précis de µops. Par exemple, avec une fenêtre d'instruction pour les µops de calcul entières, une autre pour les µops flottantes, une autre pour les µops mémoire. Il s'agit d'un choix simple et efficace, mais quelques processeurs font autrement, pour répondre à des contraintes très diverses. [[File:Processeur avec des fenêtres d'instruction décentralisées.png|centre|vignette|upright=2|Processeur avec des fenêtres d'instruction décentralisées]] Reste à scinder la fenêtre d'instruction pour trier les µops suivant leur type. Si le processeur exécute les accès mémoire dans l'ordre, la méthode la plus simple utilise une fenêtre d'instruction pour les opérations flottantes et une autre pour les autres µops (µops entières et parfois mémoire avec). L'avantage est que cela simplifie grandement le processeur. Les flottants sont gérés à part des entiers. Ils ont leurs propres registres, des FPU séparées des ALU entières, bref : la séparation est complète. Utiliser une fenêtre d'instruction séparée va dans ce sens. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Il est possible de faire pareil sur les processeurs avec exécution dans le désordre des accès mémoire. Par exemple : les processeurs Intel de microarchitecture Skylake utilisent une fenêtre d'instruction pour les opérations entières/flottantes, et une fenêtre d'instruction séparée pour les µops mémoire. Un avantage est que les deux fenêtres d'instructions sont plus spécialisées, ce qui entraine des économies de circuit. Les opérations entières/flottantes ont besoin de deux registres pour les opérandes et d'un autre résultat, alors que les µops mémoire n'ont besoin que de deux registres maximum. En utilisant une fenêtre d'instruction unique, chaque entrée doit mémoriser l'opcode et trois registres, dont un est inutilisé pour les µops mémoire et les branchements. En utilisant des fenêtres d’instructions séparées, celle pour les µops entières/flottantes a trois registres par entrée, contre seulement deux registres par entrée pour celle des µops mémoire. Un cas extrême est celui où chaque ALU/FPU a sa propre fenêtre d'instruction. Nous parlerons alors de '''fenêtres d'instruction totalement décentralisées'''. Par exemple, il y a une fenêtre d'instruction pour l'ALU entière, une autre pour le multiplieur entier, une autre pour le ''barrel shifter'', une autre pour l'unité mémoire, une autre pour l'unitéé de branchements, une autre pour l'additionneur flottant, une dernière pour le multiplier flottant, etc. Un exemple historique est celui de la FPU de l'IBM 360 modèle 90. Elle disposait d'un additionneur flottant, d'un multiplieur flottant, et d'une unité mémoire pour les lectures/écritures flottantes. Les trois unités avaient leur propre fenêtre d'instruction. Les processeurs AMD utilisent beaucoup cette technique, contrairement à Intel qui préfère utiliser des fenêtres centralisées sur les anciens processeurs, deux ou trois fenêtres sur les processeurs récents (2020 et plus). Les processeurs AMD utilisaient précisément une fenêtre d'instruction par ALU entière, alors que les FPUs partagent une fenêtre d’instructions flottantes unique. Mais nous verrons cela en détail dans le chapitre sur les processeurs superscalaires x86. Un point important est qu'avec des fenêtres d'instruction décentralisées, l'émission est découpée en deux étages. La première étape envoie une µops vers la fenêtre d'instruction adéquate, la seconde émet la µops depuis la fenêtre d'instruction quand ses opérandes sont prêts. La première est l'étage de '''''dispatch''''' qui envoie l'instruction dans la fenêtre d’instruction adéquate, selon que c'est une instruction flottante, entière, autre. La seconde est l'étage de '''''scheduling''''', qui gère la disponibilité des opérandes et des unités de calcul. La µop émise est ajoutée au tampon de réordonnancement, s'il existe, lors de l'étape de ''dispatch''. ===L'usage de plusieurs files d'instruction=== Une dernière méthode d'OOO utilise plusieurs files de micro-opération. L'idée est qu'une fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement une file de micro-opération pour les opérations entières, une autre pour les opérations flottantes, une autre pour les accès mémoire. D'autres processeurs utilisent une file pour les accès mémoire et une autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. La présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que la technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si une dépendance bloque une FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans une autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer la disponibilité des registres. Quand un registre est lu ou écrit par une instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. La logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : une pour les instructions d'accès mémoire et une autre pour les autres instructions. Si jamais une instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de la lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'une est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est la file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. ===Avantages et inconvénients de chaque implémentation=== Pour résumer, on a le choix entre une grosse fenêtre d'instruction généraliste et plusieurs fenêtres spécialisées. Le choix entre les deux est un compromis entre économie de circuits et flexibilité. Avec une fenêtre décentralisée, il arrive qu'une fenêtre d'instruction soit remplie, alors que les autres sont sous-utilisées, voire vides. Pour comprendre pourquoi, comparons une fenêtre d'instruction unique, avec une fenêtre décentralisée séparant µops entières et flottantes. La fenêtre centralisée dispose de 64 entrées, la décentralisée a 32 entrées pour chaque fenêtre d'instruction. La fenêtre décentralisée peut mémoriser au maximum 32 µops entières et 32 *ops flottantes. Par contre, la fenêtre centralisée peut mémoriser 64 µops tout court. Si le programme exécuté n'utilise pas de nombres flottants, la différence devient flagrante. La fenêtre décentralisée sera limitée ) 32 µops, alors que la centralisée pourra mémoriser le double. Les performances seront donc meilleures avec la fenêtre centralisée. Et au-delà de ça, la fenêtre décentralisée de l'exemple est utilisée de manière optimale si la moitié des µops sont des µops entières, et l'autre moitié des µops flottantes. Alors que la fenêtre centralisée se moque de la répartition entre µops entières et flottantes. Une subtilité est que le cout en transistors d'une fenêtre d'instruction n'est pas proportionnel au nombre de µops qu'elle peut mémoriser. Par exemple, si je compare une fenêtre d'instruction de 32 entrées (32 µops max), elle n'utilise pas deux fois plus transistors qu'une fenêtre de 16 entrées. Le cout en circuit n'est pas deux fois plus élevé, mais est approximativement 4 fois plus élevé. Le cout est presque quadratique, à savoir qu'il est proportionnel au carré du nombre d'entrées. Et il en est de même avec la performance, pour des raisons qu'on expliquera plus bas. Les fenêtres décentralisées utilisent plusieurs fenêtres d'instruction de "petite taille", donc plus rapides, économes en circuits et économes en énergie. Le compromis n'est donc pas entre une fenêtre centralisée à 64 entrées versus deux fenêtres de 32 entrées. Le compromis en pratique est entre une fenêtre centralisée de 64 entrées versus 3 fenêtres de 32 entrées. Un exemple pratique est celui de la microarchitecture ''Skylake'' d'Intel. Intel est passé d'une fenêtre centralisée pre-''Skylake'' à deux fenêtres décentralisées sur ''Skylake'',. Le nombre d'entrée était globalement le même entre les deux, même si l'évolution de la finesse de gravure entre les deux biaise un peu les résultats. Un avantage des fenêtres décentralisées est qu'il est possible de démarrer l'exécution de plusieurs µops simultanément : une µops par fenêtre d'instruction. Le fait est que deux fenêtres d'instructions différentes émettent leurs µops sans se synchroniser avec les autres. Deux fenêtres d'instruction peuvent donc émettre chacune une µops, ce qui fait deux µops émises lors du même cycle. Cela permet d'exécuter en même temps deux ou trois instructions 1-cycle, comme des additions, soustractions, décalages, etc. Il devient par exemple possible d'émettre une µop entière en même temps qu'une µop flottante, si les µops entières ont une fenêtre séparée de celle des µops flottantes. Il est maintenant temps de voir en quoi sont faites les fenêtres d’instruction, qu'elles soient centralisées ou décentralisées. Nous allons aussi voir quelle est la logique d'émission associée. ==L'implémentation d'une fenêtre d'instruction : généralités== Une fenêtre d'instruction est une mémoire qui mémorise des micro-opérations. Elle est cependant plus complexe qu'une mémoire RAM ou qu'une FIFO et ressemble un petit peu à une mémoire cache. Elle dispose d'un port d'écriture et d'un port de lecture, au minimum. Le port d'écriture permet à l'unité de décodage d'insérer une micro-opération dedans, d'ajouter la micro-opération qui vient d'être décodée. Si une instruction machine est décodée en plusieurs micro-opération, deux possibilités. La première est de les insérer un par un, ce qui fait qu'on peut se contenter d'un seul port d'écriture. L'autre possibilité est de les ajouter en même temps, ce qui demande plusieurs ports d'écriture. Le port de lecture sert à émettre une instruction. On part du principe que la fenêtre d'instruction ne peut émettre qu'une seule instruction à la fois, car les processeurs que nous avons vu précédemment sont de ce type. Mais nous verrons dans quelques chapitres qu'il existe des processeurs dits superscalaires, qui sont capables d'émettre plusieurs instructions par cycle. Dans ce cas, la fenêtre d'instruction a un seul port de lecture. Un processeur superscalaire, quant à lui, doit avoir un port de lecture par unité de calcul, ce qui fait beaucoup plus. Les fenêtres d'instruction sont composées d''''entrées''', des mots mémoire qui stockent une instruction. Une instruction réserve une entrée après son décodage et la libère dès qu'elle est envoyée aux unités de calcul. Une entrée contient l'opcode (les signaux de commande à envoyer à l'ALU), le registre de destination du résultat, les registres de chaque opérande, et éventuellement des signaux de commande en plus. De plus, chaque opérande est couplée à un bit de disponibilité, qui indique si elle est disponible. Quand un opérande est écrit dans les registres, le bit de présence correspondant est mis à jour. Enfin, chaque entrée possède un bit ''empty'' qui indique si elle est vide, cette information étant utile pour réserver des entrées. [[File:Entrée d'une station de réservation - sans les tags.png|centre|vignette|upright=3|Entrée d'une fenêtre d'instruction]] ===Les stations de réservation=== Les '''stations de réservation''' sont des fenêtres d'instruction particulières, qui sont capables de mémoriser les opérandes des instructions. Les entrées des stations de réservation sont identiques à celle des autres fenêtres d'instruction, si ce n'est que les opérandes de l'instruction sont enregistrés directement dans des champs séparés. Il y a deux champs, un par opérande, pour stocker l'opérande elle-même, lue depuis les registres ou obtenue via le réseau de contournement. Notons que les champs pour les opérandes viennent en plus des champs pour les noms de registres, encore que les deux peuvent être fusionnés si on veut optimiser le tout. [[File:Entrée d'une station de réservation.png|centre|vignette|upright=3|Entrée d'une station de réservation.]] Précisons que la terminologie n'est pas très fiable. Les termes "fenêtre d'instruction" et "station de réservation" ne regroupent pas du tout la même chose d'un papier de recherche à l'autre, d'un bouquin à l'autre, d'un chercheur à l'autre, d'un ingénieur à l'autre, d'un professeur à l'autre. Le terme initial vient pourtant de l'article original sur l'algorithme de Tomasulo, où il désignait une fenêtre d'instruction associée à une unité de calcul précise. Mais le terme a ensuite été réutilisé, ce qui fait que certains processeurs avec plusieurs unités de calcul sont décrits comme ayant une unique station de réservation. En bref : c'est le bazar ! Mais nous en reparlerons dans le chapitre sur le renommage de registres, car c'est la place idéale pour les aborder. Toujours est-il que j'ai fait le choix de confondre les concepts de fenêtre d'instruction et de station de réservation avec les concepts de '''lecture avant émission''' et de '''lecture après émission'''. La différence entre les deux est que les registres sont lus après émission avec une fenêtre d'instruction, avant avec des stations de réservation. Dans le cas "avant émission", les opérandes sont mémorisés dans la station de réservation. Et cette différence a une influence sur le pipeline du processeur, le banc de registres et tout ce qui s'en suit. Un désavantage de la lecture avant émission est qu'il faut stocker les opérandes après lecture, ici dans les stations de réservation. Mais un avantage est que le banc de registre a besoin de moins de ports de lecture, car une bonne partie des opérandes sont fournies par le système de contournement. Nous verrons cela dans le détail dans le chapitre sur les processeurs superscalaires. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Lecture après émission.]] [[File:Read Before Issue.png|centre|vignette|upright=2.5|Lecture avant émission.]] ===La logique d'éveil et de sélection=== Dans le cas qui va suivre, on suppose que le processeur ne peut émettre qu'une instruction à la fois. Chaque cycle, une instruction est sélectionnée et est envoyée dans le chemin de données, soit à une ALU, soit à une unité d'accès mémoire. La sélection d'une instruction est effectuée par l'unité d'émission, qui est aussi appelée le '''''scheduler'''''. Elle gère la disponibilité des opérandes et la disponibilité des unités de calcul adéquate. Le choix de l'instruction émise doit être le plus pertinent possible, pour des raisons de performances. Pour le premier point, l'unité d'émission détermine quelles instructions sont candidates pour l'émission. Les ''instructions candidates'' sont celles dont tous les opérandes sont prêts. Le processeur contient un circuit qui détecte les instructions candidates : la '''logique d’éveil''' (''wake-up logic''). Une fois que la logique d'éveil a fait son travail, une instruction est choisie pour s’exécuter en fonction de la disponibilité des unités de calcul adéquates. Ce rôle est dévolu à un circuit qu'on appelle la '''logique de sélection''', ou ''select logic''. [[File:Fonctionnement complet de la logique d’émission.jpg|centre|vignette|upright=1.5|Fonctionnement complet de la logique d’émission.]] La logique de sélection doit gérer le fait que les unités de calcul du processeur ne sont pas toutes identiques. Déjà, un processeur a généralement des unités séparées pour les instructions entières et flottantes, des unités spécialisées dans les accès mémoire, parfois des unités spécialisées pour les branchements. Une instruction doit être attribuée à la bonne unité de calcul, on ne doit pas envoyer une instruction entière dans une unité de calcul flottante. De plus, parmi les unités de calcul entières, toutes ne sont pas identiques. Par exemple, il est fréquent d'avoir plusieurs unités de calcul spécialisées dans les opérations simples (additions, soustractions, opérations logiques) avec une unité pour les multiplications/divisions séparées, parfois une unité spécialisée pour les décalages/rotations, etc. Là encore, allouer la bonne instruction à la bonne ALU est complexe. Plus les unités de calcul sont hétérogènes, plus la logique de sélection est compliquée. Les logiques d'éveil comme de sélection sont assez complexes. Comme on le verra plus bas, la logique de sélection la plus simple, qui gère une seule unité de calcul, est basée sur un encodeur à priorité couplé à d'autres circuits. Et pour gérer plusieurs ALUs, il faut mettre des encodeurs en cascade. Le résultat est que même en prenant une logique de sélection simple, elle sera assez lente et gourmande en circuits. Aussi, la logique de sélection met souvent un cycle d'horloge entier pour faire son travail, elle a son propre étage de pipeline attribué. La logique d'éveil est dans le même cas, ce qui fait qu'émettre une micro-opération demande deux cycles d'horloge. Le défaut est que cela rajoute des cycles d'horloges entre la fenêtre d'instruction et l'ALU, ce qui complique la gestion du pipeline. Ces cycles de retard sont à prendre en compte au moment d'émettre les instructions, les ''scheduler'' doit en tenir compte pour des performances optimales. Sans tenir compte de ces cycles de retard, les instructions arrivent en retard de quelques cycles à l'ALU, cycles de retard durant lesquels l'ALU n'a pas fait de calcul et a été sous-utilisée, sans compter que le système de contournement n'est pas utilisé au mieux. Et le problème est encore plus important sur les processeurs avec des stations de réservation, qui utilisent la "lecture après émission" : cela rajoute un cycle d'horloge en plus, un temps de retard en plus. ===La logique d'éveil : l'émission anticipée=== La logique d'éveil doit tenir compte du fait qu'il y a plusieurs étages entre l'émission et l'exécution sur une unité de calcul. Par exemple, un processeur a souvent entre un et à cinq étages entre la file d'attente et les unités de calcul. Il faut lire les registres, gérer le contournement, et cela peut prendre quelques cycles d'horloge. Sur le Pentium 4, on trouve 6 étages entre la fenêtre d’instruction et l'entrée de l'ALU. Si les micro-opérations sont émises quand les opérandes sont disponibles, il y aura un délai de quelques cycles avant qu'elles atteignent l'ALU. Alors qu'idéalement, on souhaiterait que la micro-opération atteigne l'ALU dès que ses opérandes sont disponibles, pour profiter des techniques de contournement. Pour cela, la logique d'éveil émet les instructions quelques cycles en avance pour qu'elles arrivent au bon moment. Il s'agit d'une technique d''''émission anticipée''', dont nous avions parlé dans le chapitre sur le contournement. : Il faut noter que le problème se pose plus avec des fenêtres d'instruction qu'avec des stations de réservation. Les premières ont un étage en plus entre émission et ALU, vu qu'il faut lire des registres après l'émission. L'émission anticipée demande d'émettre un signal d'éveil en avance de quelques cycles, pile au bon moment. Par exemples, si on a deux étages entre l'ALU et l'unité d'émission, le signal de réveil sera généré deux cycles avant que le résultat soit effectivement calculé. L'implémentation varie, mais deux solutions sont possibles. La première est de générer le signal d'éveil dans l'ALU, ce qui n'a de sens que pour les opérations comme les multiplications ou les divisions, qui prennent plusieurs cycles. Une autre technique génère le signal de réveil dans une structure centralisée, spécialisée dans la génération des signaux d'éveil. L'unité de composée d'un registre à décalage par registre. Imaginons qu'une instruction est émise, que cette instruction mette N cycles à s'exécuter, et qu'elle écrive dans un registre de destination. L'unité sélectionne alors le registre à décalage associé au registre de destination, et met le bit numéro N à 1. Le registre décalé d'un cran à chaque cycle. Quand le bit sortant est un 1, alors le signal de validité pour l'opérande est généré. L'émission anticipée marche bien si l'instruction a une durée fixe, connue à l'avance. Et autant c'est le cas pour les instructions arithmétiques et logiques, autant ce n'est pas le cas pour les accès mémoire. Les accès mémoire ont une latence variable : quelques cycles pour un succès de cache, plusieurs dizaines de cycles pour un défaut de cache L1, pas loin de la centaine pour un défaut de cache L2, etc. Et cela pose des problèmes pour l'émission anticipée. L'émission en avance pour les accès mémoire est purement spéculative : le processeur émet des instructions en supposant que la lecture entrainera un succès de cache, quitte à annuler l'instruction en cas de défaut de cache. Mais faire ainsi demande non seulement d'annuler les instructions émises en avance, mais aussi de ne pas retirer les instructions émises en avance de la fenêtre d'instruction. Elles sont émises, mais une copie de sauvegarde est conservée dans la fenêtre d'instruction. Si le processeur détecte un défaut de cache, il peut alors ré-exécuter l'instruction. S'il détecte un succès de cache, les instructions lecture-dépendante sont retirées de la fenêtre d'instruction, la copie de sauvegarde est devenue inutile et est donc jetée. ===La logique de sélection : âge ou position ?=== La logique de sélection est primordiale pour de bonnes performances. Il existe deux méthodes principales pour sélectionner l'instruction à exécuter. La première est la plus simple : elle se base sur lé numéro de l'entrée. En effet, une fenêtre d'instruction est avant tout une sorte de mémoire, un mix entre mémoire associative, mémoire RAM, et FIFO. Et chaque entrée a un numéro, une adresse mémoire. Nous parlerons de numéro dans ce qui suit, car ce sera plus simple, le terme d'adresse mémoire étant peut-être un peu exagéré dans le contexte des fenêtres d'instruction. Toujours est-il que la fenêtre d'instruction est adressable dans le sens où on peut lui envoyer le numéro de l'entrée voulue, et la fenêtre d’instruction renvoie le contenu de l'entrée sur son port de lecture. Et c'est ce que fait la logique de sélection : elle génère le numéro de l'entrée à lire. Le numéro est alors envoyé sur l'entrée d'adresse de la fenêtre d’instruction, et elle fournit la micro-opération associée sur son port de lecture, son '''port d'émission'''. La première méthode de sélection, donc. Elle est basée sur le numéro de l'entrée. Si plusieurs entrées sont éveillées, la logique de sélection prend celle avec le plus petit numéro. Elle porte le nom de '''sélection par position''', sous-entendu position dans la fenêtre d'instruction. Vous l'avez peut-être deviné, mais la logique de sélection est alors un encodeur à priorité. Le circuit de sélection ne se résume donc pas seulement à un encodeur à priorité, mais c'est le circuit central. L'avantage d'une telle méthode de sélection est qu'elle est simple à implémenter : un encodeur à priorité est un circuit connu, facile à implémenter. Mais on remarque un défaut : un encodeur est un circuit assez rapide, mais qui utilise beaucoup de transistors, beaucoup de portes logiques, surtout si on veut qu'il soit rapide. Ce qui explique que la logique de sélection ait son propre étage de pipeline rien que pour elle. La seconde méthode s'appelle la '''sélection par âge''', au nom assez transparent. L'idée est de privilégier l'émission de l'instruction la plus ancienne. Elle demande que la fenêtre d'instruction trie les micro-opérations par ordre d'insertion dans la fenêtre d'instruction, ce qui en fait une pseudo-FIFO. Le tri est partiel, car les instructions peuvent sortir de la fenêtre d’instruction à tout moment. Compacter la fenêtre d'instruction, à savoir regrouper toutes les entrées valides est une idée, mais elle est compliquée à implémenter. Aussi, elles préfèrent encoder des informations sur l'ordre d'émission dans chaque entrée. L'encodeur à priorité doit alors travailler non pas sur des nombres entiers liés à l'ordre d'insertion dans la pseudo-FIFO. Elle est encore plus gourmande en circuits que la méthode précédente. Les processeurs haute performance utilisent souvent des méthodes hybrides. Par exemple, les processeurs AMD de microarchitecture Bulldozer utilisaient une méthode intermédiaire. Ils utilisaient une fenêtre d'instruction couplée à un encodeur à priorité pour la sélection par position, mais complémentaient le tout avec une unité qui mémorisait l'instruction la plus ancienne dans la fenêtre d’instruction. Le mécanisme de sélection par âge était utilisé en priorité. Mais si l'instruction la plus ancienne n'était pas prête, le processeur basculait sur le mécanisme de sélection par position. ===La compaction des fenêtres d'instruction=== À chaque cycle, les instructions décodées sont ajoutées dans la fenêtre d'instruction, dans des entrées vides. Vu que les instructions quittent celle-ci dans le désordre, ces vides sont dispersés dans la fenêtre d'instruction, ce qui pose problème pour déterminer où placer les nouvelles instructions. La solution la plus triviale consiste à conserver une liste des vides, mise à jour à chaque insertion ou émission d'instruction. Une autre solution consiste à éliminer les vides en compactant la fenêtre d'instruction à chaque cycle d'horloge. Des circuits se chargent de détecter les vides et de regrouper les instructions en un unique bloc. Il faut signaler que certains processeurs arrivent à se passer de cette étape de compactage, mais au prix de fenêtres d'instruction nettement plus complexes. Autre problème : quand il faut choisir quelle instruction émettre, il y a toujours plusieurs candidats. Si on choisit mal, des instructions restent en attente trop longtemps parce que d'autres instructions plus jeunes leur passent devant. Pour éviter cela, les instructions les plus vielles, les plus anciennes, sont prioritaires. Pour cela, on peut utiliser une FIFO un peu spéciale pour la fenêtre d'instruction. Si les ajouts d'instruction se font dans l'ordre, les instructions ne quittent pas forcément la fenêtre d'instruction dans l'ordre imposé par une FIFO : les instructions restent triées dans leur ordre d'ajout, même s'il y a des vides entre elles. Dans ces conditions, il est préférable que le compactage conserve l'ordre FIFO des instructions. Dans ces conditions, l'instruction la plus ancienne est celle qui est située à l'adresse la plus faible : le circuit de sélection peut donc être fabriqué avec des encodeurs, et est relativement simple. ==Les fenêtres d'instruction basées sur une matrice de dépendances== L'implémentation la plus simple étend le fonctionnement d'un pipeline dynamique usuel. Rappelez-vous le chapitre sur les pipelines dynamiques. Nous avions vu que de tels pipelines émettaient une instruction par cycle, quitte à émettre des bulles de pipeline en cas de dépendance bloquante. Et il est possible d'améliorer leur unité d'émission pour qu'elle soit compatible avec l'exécution dans le désordre. ===Rappels sur le registre de réservation/disponibilité=== L'émission d'une instruction est gouvernée par un ''registre de réservation'' qui indique quels registres sont réservés par une instruction, et ceux qui sont libres. Un registre réservé est un registre qui sera écrit par une instruction en cours d'exécution, mais qui n'a pas encore écrit son résultat. Les instructions candidates doivent avoir leurs opérandes dans des registres libres. Sinon, c'est signe que leurs opérandes sont réservés en écriture, donc pas encore écrites, donc pas disponibles. Si une instruction candidate veut lire ce registre, c'est signe qu'il y a une dépendance RAW : elle veut lire un registre réservé, qui est destiné à être écrit par une instruction en vol. Si elle veut écrire, c'est signe qu'elle veut écrire dans un registre où une autre instruction veut écrire : c'est une dépendance WAW. Dans les deux cas, l'instruction n'est pas émise. Le registre de réservation encode les registres réservés comme suit : chaque bit est associé à un registre. Le bit numéro 0 est associé au registre numéro 0, le bit numéro 1 au registre numéro 1, etc. Là, En clair, les numéros de registres réservés sont encodés en représentation non pas binaire, mais en représentation ''one-hot'' (vue au premier chapitre). {|class="wikitable" |+ Registre de réservation |- ! Registre 7 !! Registre 6 !! Registre 5 !! Registre 4 !! Registre 3 !! Registre 2 !! Registre 1 !! Registre 0 |- | 0 || 0 || 1 || 0 || 0 || 1 || 0 || 0 |} Avant d'émettre une instruction, l'unité d'émission extrait les registres opérande/destination et les convertis dans la même représentation que le registre de réservation, à savoir en représentation ''one-hot''. Le circuit de traduction binaire vers ''one-hot'' est, pour rappel, un simple décodeur. Puis, on fait un OU logique entre les sorties des décodeurs. Le résultat est un masque qui indique quels registres sont lus par l'instruction, encodé en représentation ''one-hot''. Appelons-le le '''masque d'opérandes'''. Le masque est alors comparé au registre de réservation pour vérifier si l'instruction peut être émise. [[File:Unité d'émission simple, dans l'ordre.png|centre|vignette|upright=2|Unité d'émission simple, dans l'ordre]] Si l'émission est autorisée, le registre de réservation est là aussi mis à jour. Le registre de réservation est aussi mis à jour dès qu'une instruction enregistre son résultat dans les registres, ou alors dès qu'il est disponible pour le contournement. Le bit associé au registre repasse alors à 0 (ou à 1). Sans contournement, la mise à jour se fait alors à la toute fin de l'instruction, quand elle se termine, lors de la dernière étape d'enregistrement, à la fin de son pipeline. Avec, elle se fait quand l'instruction quitte l'unité de calcul. ===L'extension à l'exécution dans le désordre : l'éveil par matrice de bits=== La différence entre un pipeline dynamique et l'exécution dans le désordre est que l'on passe d'une instruction à émettre à plusieurs. Plusieurs instructions sont mises en attente dans une fenêtre d’instruction, et y attendent leur tour. L'idée est alors d'envoyer le registre de disponibilité à toutes les entrées, à toutes les instructions en attente. Ainsi, on sait quelles sont les instructions qui peuvent s'exécuter et celles qui ne le peuvent pas. L'implémentation est assez simple, elle ressemble beaucoup à l'implémentation d'un pipeline dynamique simple, si ce n'est que des circuits sont dupliqués. L'implémentation utilise des fenêtres d'instruction légèrement différentes de celles introduites plus haut. Elles n'utilisent notamment pas de bits de disponibilité, mais autre chose. Lorsqu'une instruction est ajoutée à la fenêtre d'instruction, le masque de disponibilité des opérandes est stocké dans la fenêtre d'instruction. A chaque cycle, le registre de disponibilité est envoyé à toutes les entrées, et est comparé avec tous les masques de disponibilité des opérandes. Si une comparaison renvoie un 1, alors l'instruction de l'entrée est une instruction candidate à l'émission. [[File:Unité d'émission dans le désordre basée sur un registre de disponibilité.png|centre|vignette|upright=2.5|Unité d'émission dans le désordre basée sur un registre de disponibilité]] L'ensemble est implémenté avec l'aide d'une '''matrice de bits''', où chaque ligne correspond à une entrée et chaque colonne à un registre. À chaque croisement entre une ligne et une colonne, on trouve un bit. Si le bit de la ligne n et de la colonne m est à 1, cela veut dire : l'instruction dans l'entrée n a besoin de lire le registre m. S’il est à 0, alors cela veut dire que l'instruction stockée dans la ligne n'a pas besoin de la donnée dans le registre m. [[File:Planificateur à matrice de bits.jpg|centre|vignette|upright=2|Planificateur à matrice de bits.]] Lorsqu'une instruction réserve une entrée, elle initialise la ligne en fonction des registres qu'elle souhaite lire. Pour vérifier si une instruction a ses opérandes prêts, le processeur compare le registre de disponibilité à la ligne associée à l'instruction/entrée. A chaque intersection ligne-colonne, se trouve un comparateur de 1 bit, qui détecte si le registre est demandé et disponible. Les résultats de cette porte sont ensuite envoyés à une porte ET, qui fait le gros du travail. [[File:Logique de détection de la disponibilité d'une instruction.jpg|centre|vignette|upright=2|Logique de détection de la disponibilité d'une instruction.]] ==Les fenêtres d'instruction basées sur une mémoire associative== Les processeurs modernes utilisent une mémoire associative pour la fenêtre d'instruction. Les mémoires associatives ont été abordées il y a quelques chapitres, mais faisons quelques rappels. Les mémoires associatives servent à accélérer la recherche de données dans un ensemble. Or, une fenêtre d'instruction vérifie régulièrement si chaque entrée est prête. Il s'agit d'un processus de recherche d'une instruction qui respecte une condition bien précise dans la mémoire, ce qui fait que les mémoires associatives sont donc tout indiquées. Comme vous le savez, les signaux de commande d'une instruction sont propagés avec celle-ci dans le pipeline, le nom du registre de destination ne faisant pas exception. Le nom de registre est envoyé à la fenêtre d'instruction lors de l'écriture du résultat dans les registres. S'il y a correspondance, l'opérande est disponible et son bit de disponibilité est mis à 1. On peut adapter cette méthode pour tenir compte du contournement assez simplement. [[File:Détection des dépendances par propagation du registre de destination.png|centre|vignette|upright=2|Détection des dépendances par propagation du registre de destination.]] En conséquence, le circuit de détection des dépendances est constitué d'un grand nombre de comparateurs : un par champ « nom de registre » dans chaque entrée. La logique d'éveil/''wake up'' regroupe tous les comparateurs, la logique de sélection est un circuit situé en-dehors de la mémoire associative. Les entrées sont dans la mémoire associative elle-même. [[File:Gestion des bits de validité.png|centre|vignette|upright=2|Gestion des bits de validité.]] L'implémentation la plus simple est celle du schéma précédent, où on utilise une mémoire associative unique. Une version plus élaborée sépare la fenêtre d'instruction en deux parties : une mémoire qui mémorise les registres des opérandes, une autre mémoire pour le reste. La mémoire pour les registres opérandes est la mémoire associative proprement dite, c'est elle qui est associée aux comparateurs, à la logique de ''wake-up''/réveil, etc. Par contre, l'autre mémoire est une mémoire RAM simplifiée, qui mémorise les informations qui n'ont pas besoin des comparateurs. L'opcode de l'instruction est là-dedans, par exemple. La fenêtre d'instruction est donc une sorte de mémoire associative améliorée. Il se trouve que c'est aussi le cas du ROB. Et il est possible de fusionner le tampon de ré-ordonnancement avec la fenêtre d'instruction dans une structure unique. La différence avec une fenêtre d’instruction normale est que les entrées sont libérées non pas quand l'instruction est exécutée/émise, mais quand elle termine son exécution et quitte le ROB. La fenêtre d'instruction incorpore des bits dans chaque entrée, pour savoir si la µops associée a été émise et est en cours de traitement dans les ALUs. La méthode a notamment été utilisée sur les processeurs d'architecture K6 d'AMD. Le tout donnait une structure appelée le '''DRIS''' (''deferred scheduling register renaming instruction shelf''). Les processeurs PA 8000 de HP étaient aussi vraisemblabment dans ce cas, aussi. ===Les optimisations de la consommation d'énergie : la désactivation des portions inutilisées=== Le problème avec des fenêtres d'instruction de ce type est leur forte consommation énergétique, ainsi que le grand nombre de portes logiques utilisées, qui deviennent prohibitifs pour des fenêtres d'instruction un peu grosses. Pour résoudre ce problème, certains ont optimisé les comparateurs. D'autres ont tenté de profiter du fait que la majorité des bits dans les entrées sont composés de zéros. Bref, les optimisations purement matérielles sont légion. Une première solution est de désactiver les entrées qui sont inutilisées, vides, sans instruction. Pour cela, on fait précéder les comparateurs par un circuit qui les connecte ou déconnecte des lignes de bit. Le circuit est commandé par le bit ''empty'' qui indique si une entrée est vide ou non. L'avantage est que la consommation d'énergie de la fenêtre d'instruction devient alors proportionnelle au nombre d'entrées non-vides, et non au nombre d'entrées total. Du moins, en apparence, les entrées non-utilisées doivent quand même être alimentées pour fonctionner, mais l'activité de comparaison disparait dans les entrées vides. Il est possible d'étendre cette technique aux entrées dont les opérandes sont prêts. Les gains sont généralement assez bons, avec une réduction de consommation variant entre 30 et 50%, avec une implémentation très simple et très économe en circuits. Une autre solution, assez simple à mettre en place, consiste à désactiver une partie de la fenêtre d'instruction sin elle est inutilisée. Pour cela, il faut segmenter la fenêtre d'instruction avec la technique du ''wire partitionning''. Pour rappel, une fenêtre d'instruction est une mémoire associative. Et comme toute mémoire associative, elle contient des fils, les lignes de bit, qui relient les entrées/sorties à toutes les cellules mémoire. Plus une ligne de bit est longue, plus elle consomme d'énergie et plus le temps de lecture/écriture est long. L'idée est de segmenter les lignes de bits en plaçant des répéteurs qui recopient la tension d'un segment au suivant. Les répéteurs sont des tampons trois-états, ce qui permet de déconnecter les portions inutilisées de la ligne de bit. Ce faisant, la fenêtre d'instruction est découpée en segments, qui peuvent être désactivés si besoin. S'il y a peu d'instructions chargées dans la fenêtre d'instruction, les portions inutilisées sont désactivées. La technique marche d'autan mieux si les instructions sont compactées au début de la fenêtre d'instruction. [[File:Wire partitionning.png|centre|vignette|upright=2|Wire partitionning]] Tout le problème est de savoir quelles portions désactiver. La technique est assez simple si la fenêtre d'instruction est compactée, à savoir si toutes les instructions sont régulièrement regroupées au début de la mémoire CAM. Mais même avec cette optimisation, la décision de désactiver une portion de la fenêtre d'instruction n'est pas à prendre à la légère. Il ne faut pas désactiver une portion contenant des instructions pouvant être émise sous peu. La décision dépend de paramètres variés : proportion d'entrée vides, quantité d'entrées récemment activées/désactivées récemment, présences d'entrées avec un ''match'' d'opérandes récent, etc. Il est important de préciser que les techniques en question fonctionnent aussi sur les autres types de fenêtre d'instruction, qui ne sont pas basées sur des mémoires associatives. Nous allons voir celles-ci dans la suite du chapitre, mais gardez à l'esprit que ces optimisations, à savoir désactiver les entrées vides/prêts et partitionner la fenêtre d'instruction, sont des optimisations générales qui marchent avec presque tout. ===L'ajout d'une FIFO pour les instructions déjà prêtes à l'émission=== D'autres techniques permettent de réduire aussi bien le cout en circuits que la consommation d'énergie de la fenêtre d'instruction. L'idée est d'utiliser une mémoire associative quand elle est réellement nécessaire, mais d'utiliser une fenêtre d'instruction "normale" dès que possible. La méthode la plus simple tient compte du fait que certaines µopsont déjà toutes leurs opérandes de disponibles à l'émission, mais doivent quand même être mises en attente, parce que l'ALU adéquate est occupée, parce que des dépendances WAW/WAR sont encore là, ou pour tout autre raison. Dans ce cas, elles sont mises en attente non pas dans la fenêtre d'instruction, mais dans une mémoire FIFO toute simple. L'idée est qu'au lieu d'avoir une énorme mémoire associative pour la fenêtre d'instruction, on déplace quelques entrées dans une petite FIFO annexe. Le résultat est un gain d'énergie et de circuits, au prix d'une perte de performance mineure. La perte de performance en question se manifeste si aucune instruction n'a ses opérandes de prêtes à l'émission : le programme n'utilise pas la FIFO et voit alors une fenêtre d'instruction plus petite. Une amélioration de cette technique tient compte du fait que certaines instructions sont dans un cas intermédiaire. Elles ont déjà un opérande de prête lors de l'émission, mais pas l'autre. Le nombre d'opérandes varie suivant l’instruction : certaines n'ont besoin que d'un seul opérande. De plus, il arrive qu'une opération tout juste décodée ait déjà un ou plusieurs de ses opérandes de prêts. Cette constatation permet d'éviter d'utiliser des comparateurs pour les opérandes déjà prêts. Par exemple, on peut parfaitement utiliser trois fenêtres d'instruction : * une pour les instructions dont tous les opérandes sont prêts, mais qui sont quand même mises en attente, sans comparateur ; * une pour les instructions dont un seul opérande manque, qui n'utilise qu'un comparateur par entrée ; * une pour les instructions dont deux opérandes manquent à l'appel, qui utilise deux comparateurs par entrée. C'est beaucoup plus économique que d'utiliser une seule grosse fenêtre d'instruction qui contiendrait autant d'entrées que les trois précédentes réunies, avec deux comparateurs par entrée. Certains sont même allés plus loin, et ont proposé de supprimer la fenêtre d'instruction avec deux opérandes par entrée. Les instructions dont deux opérandes sont inconnus au décodage sont stockées dans la fenêtre d'instruction pour instructions avec un comparateur par entrée. Un circuit de prédiction se charge alors de prédire l'opérande manquant, cette prédiction étant vérifiée plus loin dans le pipeline. Il serait cependant étonnant qu'une telle proposition ait donné lieu à la moindre implémentation réelle. ===Les optimisations de la consommation d'énergie avancées=== D'autres chercheurs ont conservé une fenêtre d'instruction unique, avec autant de comparateurs par entrée qu'il y a d'opérandes possibles par instruction. Simplement, le processus de détection des opérandes prêts est légèrement ralenti : on ne vérifie qu'un opérande par cycle. Pour vérifier les deux opérandes d'une entrée, on doit attendre deux cycles. Enfin, certains chercheurs ont proposé des fenêtres d'instruction segmentées. Les instructions circulent à chaque cycle d'un segment vers le suivant : en conséquence, certains segments conservent les instructions les plus anciennes, un autre les instructions les plus jeunes, etc. Seul le denier segment, celui qui contient les instructions les plus vielles, peut émettre une instruction : la détection des opérandes se fait seulement dans le dernier segment, qui contient les instructions les plus anciennes. On économise ainsi beaucoup de comparateurs. Certains chercheurs ont tenté de pipeliner l'étape de sélection des opérandes, ainsi que l'étage d'arbitrage. Mais en faisant cela, il faut plusieurs cycles pour détecter qu'une instruction a ses opérandes prêts, ce qui pose problème face à de nombreuses dépendances RAW. Pour éviter de trop perdre en performances, certains chercheurs ont décidé d'utiliser des techniques pour prédire quelles seront les instructions dont les opérandes seront bientôt prêts. Si détecter qu'une instruction est prête prend n cycles, le processeur devra tenter de prédire la future disponibilité des opérandes n cycles en avance pour obtenir des performances optimales. ===Remplacer la mémoire associative par une RAM=== Une autre optimisation possible est de remplacer la fenêtre d'instruction par une mémoire RAM, dont chaque mot mémoire correspondrait à une entrée. Une telle optimisation permet en théorie de se passer des comparateurs associés à chaque entrée, mais au prix de l'ajout de circuits annexes potentiellement couteux. La première de ces techniques, la '''recherche directe par étiquette''' (direct tag search) fut créée par Weiss et son collègue Smith. Ils cherchaient à améliorer l'algorithme de Tomasulo, un algorithme qu'on expliquera dans quelques chapitres. Rappelons que chaque instruction produit un résultat, qui devra être rapatrié dans une ou plusieurs entrées de la fenêtre d'instruction. L'optimisation de la recherche directe par étiquette fonctionne dans le cas où le résultat de l'instruction n'est utilisé que par une seule entrée, et pas plusieurs. Le principe est simple : chaque champ « opérande » d'une entrée est adressable via le nom de registre de cet opérande. Pour faire le lien entre entrée et nom de registre, la recherche directe par étiquette ajoute une table de correspondances matérielle, une mémoire RAM qui mémorise les adresses des champs « opérande » des entrées. Les adresses envoyées dans cette mémoire sont les noms de registres des résultats. Lors de l'émission, la table de correspondances est mise à jour. Les numéros des champs « opérande » réservés lors de l'émission sont mémorisés dans les mots mémoire qui correspondent aux deux registres sources. Toutefois, une petite vérification est faite lors de l'émission : s'il y a déjà une correspondance dans la table pour un registre source, alors une autre instruction compte lire ce registre. Pour éviter d'écraser les données de l'instruction précédente dans la table de correspondances, l'émission de l'instruction est bloquée. [[File:Recherche directe par étiquette.png|centre|vignette|upright=2|Recherche directe par étiquette.]] ==Les fenêtres d’instruction avec préplanification== Avec la '''préplanification''' (''prescheduling''), la fenêtre d’instruction est composée de mémoires FIFO dans lesquelles les instructions sont triées dans l'ordre d'émission. Il n'y a pas de logique d’émission proprement dite, celle-ci se bornant à vérifier si l'instruction située au début de la FIFO peut s’exécuter. Par contre, le préplanificateur détecte les dépendances et en déduit où insérer les instructions dans le tampon d'émission, à l'endroit le plus adéquat. [[File:Préplanification.jpg|centre|vignette|upright=2|Préplanification.]] ===L'usage de FIFO multiples=== La technique de préplanification la plus simple utilise plusieurs FIFO. Quand une instruction a une dépendance avec une autre instruction, les deux sont placées dans la même FIFO. Pour cela, le préplanificateur détecte les chaines d'instructions dépendantes, et place les instructions dans la FIFO adéquate. A chaque cycle, l'unité d'émission lit une micro-opération dans chaque FIFO et vérifie si elle peut l'émettre. Si la micro-opération n'a pas ses opérandes disponibles, ou qu'une dépendance structurelle survient, alors la FIFO est bloquée. La micro-opération attend que la dépendance soit résolue, bloquant toutes les instructions précédentes. Mais les autres FIFO ne sont pas bloquées, laissant de la marge de manœuvre. [[File:Préplanification par FIFO multiples.png|centre|vignette|upright=1.5|Préplanification par FIFO multiples.]] ===La technique du tampon trié=== La technique du '''tampon trié''' trie les instructions selon le temps d'attente avant leur exécution. Les instructions qui sont censées s’exécuter bientôt sont insérées au tout début de la FIFO, tandis que les instructions qui s’exécuteront dans un long moment sont insérées vers la fin. Là encore, l'unité d'émission lit une micro-opération dans la FIFO, et détermine si elle peut être émise. Si une dépendance survient, l'émission est retardée, et la FIFO est bloquée. [[File:Préplanification par tampon trié.png|centre|vignette|upright=1.5|Préplanification par tampon trié.]] La technique a cependant quelques problèmes assez importants. Le premier problème est que la FIFO est bloquée lorsqu'une micro-opération ne peut être émise. Le second problème est que le temps avant exécution n'est pas toujours connu, notamment pour les instructions d'accès mémoire. Et cela se répercute sur les instructions dépendantes de celles-ci. Pour résoudre ce genre de problèmes, l'usage d'un pipeline à ''replay'' est possible, et est même l'une des meilleures solutions possible, malgré ses défauts. L'idée est que les lectures sont pré-planifiées en supposant qu'elles font un succès de cache L1. Si la prédiction est fausse, la lecture est ré-exécutée plusieurs cycles plus tard, en supposant qu'elle fait un succès dans le cache L2, et ainsi de suite. Elle est alors ré-insérée dans la FIFO, elle est pré-planifiée une seconde fois. Il en est de même si une micro-opération ne peut pas être émise : il suffit de la réinsérer dans la FIFO au bon endroit, en attendant que ses dépendances soient résolues. Ainsi, l'instruction fautive ne bloque pas la fenêtre d’instruction, et retente sa chance autant de fois qu'il le faut. [[File:Préplanification par fenêtre d’instruction scorebarodée.png|centre|vignette|upright=1.5|Préplanification par fenêtre d’instruction scorebarodée.]] Une autre solution utilise deux fenêtres d’instruction : une FIFO gérée par la préplanification, et une vraie fenêtre d'instruction pour les instructions dont le temps d'attente ne peut pas être déterminé. Il est possible de mettre cette dernière avant la préplanification, afin de gérer les temps d'attente des instructions d'accès mémoire. Quand le temps d'attente d'une lecture devient connu, ses instructions dépendantes sont gérées avec préplanification. [[File:Préplanification avec fenêtre d’instruction.png|centre|vignette|upright=2.5|Préplanification avec fenêtre d’instruction.]] ===Les fenêtres d'instruction avec allocation temporelle statique=== L''''allocation temporelle statique''' correspond à une technique utilisée sur les processeurs Cuzco de l'entreprise Condor. La technique en question a été présenté en 2025, mais des idées similaires ont été présentées dans la littérature académique. Elle ressemble beaucoup aux techniques de pré-planification, avec cependant quelques différences. L'idée est simple : le processeur dispose de plusieurs fenêtres d'instruction, qui mettent en attente les micro-opérations. Lors de l'étape de renommage de registres, le processeur détermine dans combien de cycles d'horloge la micro-opération sera prête pour exécution. La micro-opération est alors mise en attente durant ce nombre de cycles, dans les fenêtres d'instruction, puis est émise une fois ce nombre de cycles écoulés. Ce faisant, les fenêtres d'instruction n'ont pas besoin de détecter la disponibilité des opérandes à chaque cycle, pour chaque micro-opération en attente. Le ''timing'' de l'émission des micro-opérations est décidé à l'avance. L'implémentation exacte n'est pas connue, mais plusieurs solutions sont imaginables. Par exemple, la fenêtre d'instruction peut simplement être composée de plusieurs mémoires de petite taille, chacune contenant les micro-opérations destinées à être exécutées dans N cycles, N étant différent pour chaque mémoire. Une autre solution, plus réaliste, utilise une fenêtre d'instruction dans laquelle la micro-opération est couplée à des champs pour les opérandes, et un champ compteur. Le champ compteur est initialisé avec le nombre de cycles à attendre, et est décrémenté à chaque cycle d'horloge. Quand il atteint zéro, la micro-opération est émise. Vous remarquerez que la méthode ne marche que si toutes les micro-opérations prennent un nombre fixe de cycles d'horloge. Et autant c'est le cas pour les micro-opérations arithmétiques ou logiques, autant les accès mémoire ne rentrent pas dans ce cadre. En théorie, on ne sait pas combien de temps prendra un accès mémoire. Et cette incertitude se répercute sur les instructions dépendantes d'un accès mémoire. Pour éviter cela, le processeur réutilise un pipeline à ''replay'' tel que vu dans le chapitre précédent. L'unité de renommage de registre suppose que tout accès mémoire fait un succès de cache L1, et décide des ''timings'' d'émission sous cette hypothèse. Si une lecture subit un défaut de cache, elle est ré-exécutée, de même que toutes les instructions dépendantes. Pour cela, le registre de destination de la lecture est marqué comme invalide, grâce à un bit spécifique attaché au registre. Toute instruction qui lit un opérande invalide est elle aussi ré-executée de zéro. Pour simplifier, l'unité d'émission ressemble à une unité d'émission dans l'ordre, avec un registre de disponibilité, qu'on aurait amélioré pour aller au-delà de la simple détection des dépendances d'instruction. Pour déterminer les ''timings'' d'émission, à savoir quand émettre une micro-opération, le processeur utilise une unité d'émission à deux étages. Le premier étage est appelé le ''register scoreboard'', le second étage est appelé la ''Time Ressource Matrix''. Les deux étages communiquent entre eux, comme on va le voir, et leurs noms donnent une idée de ce qu'ils font. Le premier étage gère les dépendances de registres, le second gère les dépendances structurelles. Le premier étage est un registre de disponibilité amélioré, qui gère les dépendances de registre. Cet étage sait quand tel registre sera écrit, et donc que l'opérande écrit dedans sera disponible à partir de tel cycle d'horloge. Il le sait car l'étage suivant l'aura prévenu, mais laissons cela de côté pour le moment. Quand une micro-opération rentre dans cet étage, il vérifie les dépendances avec les registres et les micro-opérations antérieures. Vu qu'il sait quand les registres seront disponibles, il peut déterminer quand l'instruction pourra s'exécuter. Par exemple, si une micro-opération lit les deux registres R7 et R15, qui sont disponibles respectivement dans 5 et 7 cycles, le premier étage sait que la micro-opération devra attendre 7 cycles. Mais tout cela ne suffit pas à déterminer quand émettre une micro-opération. En effet, il fait aussi gérer les dépendances structurelles, ce qui est le boulot du second étage. Le second étage utilise pour cela une ''Time Ressource Matrix'', qui mémorise l'occupation de diverses "ressources", pour les 256 cycles d'horloge à venir. Les ressources en question sont les ports de lecture/écriture du banc de registre, les ALUs utilisées, si la micro-opération utilise l'unité mémoire, etc. Le second étage prend en entrée une micro-opération, détermine quelles "ressources" elle utilise, puis regarde leur disponibilité. Elle détecte alors les dépendances structurelles et détermine alors quand peut s'exécuter la micro-opération. Elle peut retarder l'émission de quelques cycles, si une dépendance structurelle est détectée. Une fois sortie du second étage, on sait quand la micro-opération va être émise, à quel cycle précisément. Et vu que la durée de l'instruction est fixe, on sait quand cette micro-opération va se terminer, quand son résultat sera disponible. Cela permet de mettre à jour la ''Time Ressource Matrix'', pour préciser que le port d'écriture sera occupé à tel moment. De plus, cette information est transmise au premier étage, qui sait alors quand est enregistré le résultat dans le registre de destination. C'est comme cela que le premier étage sait quand un registre est disponible : le second étage le prévient, quand il émet une instruction ! La ''Time Ressource Matrix''mémorise l'occupation des "ressources" pour les 256 cycles d'horloge à venir. Cependant, elle ne vérifie pas les dépendances pour les 256 cycles suivants. Quand elle reçoit une micro-opération, elle teste les dépendances structurelles pour seulement les 8 prochains cycles maximum. Si la micro-opération ne peut pas être émise pendant ces 8 cycles, le pipeline est bloqué, un ''pipeline stall'' est émis. Pour être plus précis, vu que le processeur peut décoder 8 micro-opérations en même temps, cela permet de ne consulter que 64 cycles d'horloge sur les 256. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les premiers processeurs Intel | prevText=Les premiers processeurs Intel | next=Le renommage de registres | nextText=Le renommage de registres }} </noinclude> bdn0l4udlsgz0y8x8yrbd3zhxz4qilu 773615 773612 2026-09-29T20:47:03Z Mewtow 31375 Scission du chapitre en deux chapitres 773615 wikitext text/x-wiki Dans les chapitres précédents, nous avons parlé des techniques dites d''''émission dans l'ordre'''. L'idée est d’exécuter une nouvelle micro-opération à chaque cycle, dans des unités de calcul séparées. Les instructions sont émises consécutivement, mais les instructions s’exécutent en parallèle dans des unités de calcul séparées. Par contre, quand l'unité d'émission ne peut pas émettre une instruction, elle bloque tout le pipeline. Les instructions qui suivent sont elles aussi bloquées, elles doivent attendre leur tour, même si elles sont en capacité de s'exécuter. Les techniques d'exécution dans le désordre que nous allons voir dans ce chapitre corrigent ce point précis. Elles sont dites à '''émission dans le désordre'''. Elles se distinguent des précédentes sur un point précis : quand l'unité d'émission bloque l'émission d'une instruction, les instructions suivantes peuvent poursuivre. L'émission des instructions peut donc se faire dans le désordre, dans le sens où une instruction peut être émise alors qu'une instruction précédente ne l'est pas encore. Mais avant de poursuivre, quelques point niveaux terminologie : * L'émission dans le désordre est un terme parlant et assez précis. Malheureusement, la terminologie la plus utilisée par d''''exécution dans le désordre'''. Et nous utiliserons ce terme dans la suite du cours, histoire de ne pas trop dévier de la nomenclature habituelle. * Nous utiliserons parfois l'abréviation OOO pour parler d'exécution dans le désordre. L'abréviation est celle de ''Out Of Order Excution''. * Nous utiliserons aussi l'abréviation ''µop'' pour parler de micro-opération, ''µops'' au pluriel pour parler de plusieurs micro-opérations, ou des micro-opérations en général. L'exécution dans le désordre ne gère en effet que des µops, elle se situe après l'étape de décodage. Pour décrire comment est implémentée l'émission dans le désordre, il faut commencer par parler des processeurs sans. Les processeurs sans exécution dans le désordre ont une unité d'émission qui bloque tout le pipeline dès qu'une µop ne peut pas être émise. Pour limiter l'impact de ce blocage, quelques rares processeurs incorporent une '''file de micro-opération''', une mémoire FIFO qui met en attente les µops. Vu que c'est une mémoire FIFO, les µops sont émises dans l'ordre, à savoir l'ordre d'ajout, dans l'ordre de décodage. Le schéma ci-dessous illustre une telle file d'attente couplée à un ''scoreboard''. L'exécution dans le désordre améliore la file de µops sur un point : ce n'est plus une mémoire FIFO. Les µops sont insérées dans l'ordre, mais peuvent sortir dans le désordre (être émises dans le désordre). La file de µops devient alors un '''''scheduler''''', terme anglais que je ne compte pas traduire. Un terme équivalent est '''fenêtre d'instruction''', terme traduit directement de l'anglais ''instruction Window''. Terme assez trompeur, car elles mettent en attente des µops, pas des instructions. [[File:Différence file µops et fenêtres instruction.png|centre|vignette|upright=2|Différence file µops et fenêtres instruction]] L'implémentation la plus simple de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Les µops décodées sont accumulées dans le ''scheduler'', où elles attendent leur tour. La fenêtre d'instruction sert donc de file d'attente. Le ''scheduler'' émet une µop dès que ses opérandes sont disponibles. Par disponible, on veut dire présent soit dans le réseau de contournement, soit dans les registres. Le ''scheduler'' détecte automatiquement quand les opérandes d'une µop sont disponibles, et il l'exécute à ce moment-là. Pour détecter la disponibilité des opérandes, le ''scheduler'' contient une unité d'émission, qui détecte quelles µops sont prêtes à être émises. L'unité d'émission et le ''scheduler'' sont fusionnées ensemble, ils forment un seul circuit. Mais nous allons dire qu'ils sont conceptuellement séparées pour le moment. A chaque cycle, l'unité d'émission consulte les µops en attente pour détecter les quelles peuvent s'exécuter, celles qui ont leurs opérandes de disponibles. Le ''scheduler'' est spécialement être conçue pour, c'est une sorte de mémoire associative très complexe, comme on le verra dans ce qui suit. [[File:OOO Issue.png|centre|vignette|upright=2.5|Exécution dans le désordre avec une fenêtre d'instruction]] Une fois qu'une µop sort du décodeur d'instructions, elle est ajoutée en parallèle dans la fenêtre d'instruction et le ROB. La raison est que les µops quittent la fenêtre d'instruction dans le désordre, et qu'elles doivent être remises en ordre par la suite. Le ROB s'occupe de cette remise en ordre, mais il a besoin de savoir dans quel ordre les µops sont censées être, et cet ordre est celui du décodage. Aussi, pour remplir le ROB, la seule opportunité est en sortie de l'unité de décodage. Dans le cas où une instruction est décodée en plusieurs micro-opérations, elles sont toutes insérées en même temps dans la fenêtre d'instruction et le ROB, en tenant compte de leur ordre. [[File:Fenêtre d'instruction.png|centre|vignette|upright=2|Fenêtre d'instruction.]] Avant de poursuivre, précisons que les micro-opérations mémoire sont à part des autres, pour diverses raisons. Une de ces raisons est que les dépendances de données sont classées en deux types : les dépendances de registre et les dépendances d'adresse. Et les deux sont fondamentalement différentes. Autant on peut détecter les dépendances de registre lors de l'émission, autant c'est plus compliqué avec les dépendances d'adresse. De plus, rappelons que si les lectures peuvent s'exécuter dans le désordre, les écritures doivent s'exécuter dans l'ordre, ou du moins en donner l'illusion. Pour cela, le processeur remet les écritures dans l'ordre avec une sorte de mini-ROB intégré à l'unité mémoire, appelée la file d'écriture. Elle complémente le ROB, qui lui ne gère que les écritures dans les registres, mais les deux collaborent. La file d'écriture envoie une écriture à la mémoire RAM quand le ROB lui dit que c'est bon, les instructions précédentes sont terminées ''dans l'ordre du programme''. Les processeurs modernes ajoutent des techniques d'exécution dans le désordre des accès mémoire, mais nous les verrons dans un chapitre dédié. Elles permettent d'utiliser une fenêtre d'instruction unique, qui mémorise aussi les µops mémoire. Si elles sont mises en place, l'unité mémoire n'a pas besoin de file de µops séparée. L'idée est que les dépendances de registre sont traitées par la fenêtre d'instruction, mais que l'unité mémoire gére les dépendances d'adresse. Les dépendances d'adresse sont gérées par des techniques de ''désambiguation mémoire'', qui auront droit à un chapitre dédié. [[File:Processeur avec exécution dans le désodre des accès mémoire.png|centre|vignette|upright=2|Processeur avec exécution dans le désodre des accès mémoire]] Les processeurs assez anciens n'autorisaient pas d'exécution dans le désordre des accès mémoire. Concrétement, les accs mémoire devaient se faire dans l'ordre, mais les autres µops pouvaient être exécutées dans le désordre. Il s'agit donc d'un ordre entre µops mémoire, pas entre µops mémoire et autres µops. Les µops entières et flottantes pouvaient être exécutées avant une µops mémoire qui est avant elle dans l'ordre du programme, ce n'est pas un problème. Pour garantir l'ordre des µops mémoire, l'unité mémoire est précédée par une file de micro-opérations séparée, pour forcer l'exécution dans l'ordre des accès mémoire. De plus, les µops mémoire ne peuvent pas utiliser la fenêtre d'instruction. Dit autrement, la fenêtre d'instruction ne mémorise pas de µops mémoire. Après le décodage, les µops sont réparties soit dans la file de µops mémoire, soit dans la fenêtre d'instruction. Le décodeur classe les µops suivant que ce sont des µops mémoire ou non, et les envoient à la bonne destination. Dans ce chapitre, on supposera que c'est cette solution qui est utilisée. [[File:Processeur avec émission dans l'ordre des accès mémoire.png|centre|vignette|upright=2|Processeur avec émission dans l'ordre des accès mémoire]] ==L'implémentation d'une fenêtre d'instruction : généralités== Une fenêtre d'instruction est une mémoire qui mémorise des micro-opérations. Elle est cependant plus complexe qu'une mémoire RAM ou qu'une FIFO et ressemble un petit peu à une mémoire cache. Elle dispose d'un port d'écriture et d'un port de lecture, au minimum. Le port d'écriture permet à l'unité de décodage d'insérer une micro-opération dedans, d'ajouter la micro-opération qui vient d'être décodée. Si une instruction machine est décodée en plusieurs micro-opération, deux possibilités. La première est de les insérer un par un, ce qui fait qu'on peut se contenter d'un seul port d'écriture. L'autre possibilité est de les ajouter en même temps, ce qui demande plusieurs ports d'écriture. Le port de lecture sert à émettre une instruction. On part du principe que la fenêtre d'instruction ne peut émettre qu'une seule instruction à la fois, car les processeurs que nous avons vu précédemment sont de ce type. Mais nous verrons dans quelques chapitres qu'il existe des processeurs dits superscalaires, qui sont capables d'émettre plusieurs instructions par cycle. Dans ce cas, la fenêtre d'instruction a un seul port de lecture. Un processeur superscalaire, quant à lui, doit avoir un port de lecture par unité de calcul, ce qui fait beaucoup plus. Les fenêtres d'instruction sont composées d''''entrées''', des mots mémoire qui stockent une instruction. Une instruction réserve une entrée après son décodage et la libère dès qu'elle est envoyée aux unités de calcul. Une entrée contient l'opcode (les signaux de commande à envoyer à l'ALU), le registre de destination du résultat, les registres de chaque opérande, et éventuellement des signaux de commande en plus. De plus, chaque opérande est couplée à un bit de disponibilité, qui indique si elle est disponible. Quand un opérande est écrit dans les registres, le bit de présence correspondant est mis à jour. Enfin, chaque entrée possède un bit ''empty'' qui indique si elle est vide, cette information étant utile pour réserver des entrées. [[File:Entrée d'une station de réservation - sans les tags.png|centre|vignette|upright=3|Entrée d'une fenêtre d'instruction]] ===Les stations de réservation=== Les '''stations de réservation''' sont des fenêtres d'instruction particulières, qui sont capables de mémoriser les opérandes des instructions. Les entrées des stations de réservation sont identiques à celle des autres fenêtres d'instruction, si ce n'est que les opérandes de l'instruction sont enregistrés directement dans des champs séparés. Il y a deux champs, un par opérande, pour stocker l'opérande elle-même, lue depuis les registres ou obtenue via le réseau de contournement. Notons que les champs pour les opérandes viennent en plus des champs pour les noms de registres, encore que les deux peuvent être fusionnés si on veut optimiser le tout. [[File:Entrée d'une station de réservation.png|centre|vignette|upright=3|Entrée d'une station de réservation.]] Précisons que la terminologie n'est pas très fiable. Les termes "fenêtre d'instruction" et "station de réservation" ne regroupent pas du tout la même chose d'un papier de recherche à l'autre, d'un bouquin à l'autre, d'un chercheur à l'autre, d'un ingénieur à l'autre, d'un professeur à l'autre. Le terme initial vient pourtant de l'article original sur l'algorithme de Tomasulo, où il désignait une fenêtre d'instruction associée à une unité de calcul précise. Mais le terme a ensuite été réutilisé, ce qui fait que certains processeurs avec plusieurs unités de calcul sont décrits comme ayant une unique station de réservation. En bref : c'est le bazar ! Mais nous en reparlerons dans le chapitre sur le renommage de registres, car c'est la place idéale pour les aborder. Toujours est-il que j'ai fait le choix de confondre les concepts de fenêtre d'instruction et de station de réservation avec les concepts de '''lecture avant émission''' et de '''lecture après émission'''. La différence entre les deux est que les registres sont lus après émission avec une fenêtre d'instruction, avant avec des stations de réservation. Dans le cas "avant émission", les opérandes sont mémorisés dans la station de réservation. Et cette différence a une influence sur le pipeline du processeur, le banc de registres et tout ce qui s'en suit. Un désavantage de la lecture avant émission est qu'il faut stocker les opérandes après lecture, ici dans les stations de réservation. Mais un avantage est que le banc de registre a besoin de moins de ports de lecture, car une bonne partie des opérandes sont fournies par le système de contournement. Nous verrons cela dans le détail dans le chapitre sur les processeurs superscalaires. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Lecture après émission.]] [[File:Read Before Issue.png|centre|vignette|upright=2.5|Lecture avant émission.]] ===La logique d'éveil et de sélection=== Dans le cas qui va suivre, on suppose que le processeur ne peut émettre qu'une instruction à la fois. Chaque cycle, une instruction est sélectionnée et est envoyée dans le chemin de données, soit à une ALU, soit à une unité d'accès mémoire. La sélection d'une instruction est effectuée par l'unité d'émission, qui est aussi appelée le '''''scheduler'''''. Elle gère la disponibilité des opérandes et la disponibilité des unités de calcul adéquate. Le choix de l'instruction émise doit être le plus pertinent possible, pour des raisons de performances. Pour le premier point, l'unité d'émission détermine quelles instructions sont candidates pour l'émission. Les ''instructions candidates'' sont celles dont tous les opérandes sont prêts. Le processeur contient un circuit qui détecte les instructions candidates : la '''logique d’éveil''' (''wake-up logic''). Une fois que la logique d'éveil a fait son travail, une instruction est choisie pour s’exécuter en fonction de la disponibilité des unités de calcul adéquates. Ce rôle est dévolu à un circuit qu'on appelle la '''logique de sélection''', ou ''select logic''. [[File:Fonctionnement complet de la logique d’émission.jpg|centre|vignette|upright=1.5|Fonctionnement complet de la logique d’émission.]] La logique de sélection doit gérer le fait que les unités de calcul du processeur ne sont pas toutes identiques. Déjà, un processeur a généralement des unités séparées pour les instructions entières et flottantes, des unités spécialisées dans les accès mémoire, parfois des unités spécialisées pour les branchements. Une instruction doit être attribuée à la bonne unité de calcul, on ne doit pas envoyer une instruction entière dans une unité de calcul flottante. De plus, parmi les unités de calcul entières, toutes ne sont pas identiques. Par exemple, il est fréquent d'avoir plusieurs unités de calcul spécialisées dans les opérations simples (additions, soustractions, opérations logiques) avec une unité pour les multiplications/divisions séparées, parfois une unité spécialisée pour les décalages/rotations, etc. Là encore, allouer la bonne instruction à la bonne ALU est complexe. Plus les unités de calcul sont hétérogènes, plus la logique de sélection est compliquée. Les logiques d'éveil comme de sélection sont assez complexes. Comme on le verra plus bas, la logique de sélection la plus simple, qui gère une seule unité de calcul, est basée sur un encodeur à priorité couplé à d'autres circuits. Et pour gérer plusieurs ALUs, il faut mettre des encodeurs en cascade. Le résultat est que même en prenant une logique de sélection simple, elle sera assez lente et gourmande en circuits. Aussi, la logique de sélection met souvent un cycle d'horloge entier pour faire son travail, elle a son propre étage de pipeline attribué. La logique d'éveil est dans le même cas, ce qui fait qu'émettre une micro-opération demande deux cycles d'horloge. Le défaut est que cela rajoute des cycles d'horloges entre la fenêtre d'instruction et l'ALU, ce qui complique la gestion du pipeline. Ces cycles de retard sont à prendre en compte au moment d'émettre les instructions, les ''scheduler'' doit en tenir compte pour des performances optimales. Sans tenir compte de ces cycles de retard, les instructions arrivent en retard de quelques cycles à l'ALU, cycles de retard durant lesquels l'ALU n'a pas fait de calcul et a été sous-utilisée, sans compter que le système de contournement n'est pas utilisé au mieux. Et le problème est encore plus important sur les processeurs avec des stations de réservation, qui utilisent la "lecture après émission" : cela rajoute un cycle d'horloge en plus, un temps de retard en plus. ===La logique d'éveil : l'émission anticipée=== La logique d'éveil doit tenir compte du fait qu'il y a plusieurs étages entre l'émission et l'exécution sur une unité de calcul. Par exemple, un processeur a souvent entre un et à cinq étages entre la file d'attente et les unités de calcul. Il faut lire les registres, gérer le contournement, et cela peut prendre quelques cycles d'horloge. Sur le Pentium 4, on trouve 6 étages entre la fenêtre d’instruction et l'entrée de l'ALU. Si les micro-opérations sont émises quand les opérandes sont disponibles, il y aura un délai de quelques cycles avant qu'elles atteignent l'ALU. Alors qu'idéalement, on souhaiterait que la micro-opération atteigne l'ALU dès que ses opérandes sont disponibles, pour profiter des techniques de contournement. Pour cela, la logique d'éveil émet les instructions quelques cycles en avance pour qu'elles arrivent au bon moment. Il s'agit d'une technique d''''émission anticipée''', dont nous avions parlé dans le chapitre sur le contournement. : Il faut noter que le problème se pose plus avec des fenêtres d'instruction qu'avec des stations de réservation. Les premières ont un étage en plus entre émission et ALU, vu qu'il faut lire des registres après l'émission. L'émission anticipée demande d'émettre un signal d'éveil en avance de quelques cycles, pile au bon moment. Par exemples, si on a deux étages entre l'ALU et l'unité d'émission, le signal de réveil sera généré deux cycles avant que le résultat soit effectivement calculé. L'implémentation varie, mais deux solutions sont possibles. La première est de générer le signal d'éveil dans l'ALU, ce qui n'a de sens que pour les opérations comme les multiplications ou les divisions, qui prennent plusieurs cycles. Une autre technique génère le signal de réveil dans une structure centralisée, spécialisée dans la génération des signaux d'éveil. L'unité de composée d'un registre à décalage par registre. Imaginons qu'une instruction est émise, que cette instruction mette N cycles à s'exécuter, et qu'elle écrive dans un registre de destination. L'unité sélectionne alors le registre à décalage associé au registre de destination, et met le bit numéro N à 1. Le registre décalé d'un cran à chaque cycle. Quand le bit sortant est un 1, alors le signal de validité pour l'opérande est généré. L'émission anticipée marche bien si l'instruction a une durée fixe, connue à l'avance. Et autant c'est le cas pour les instructions arithmétiques et logiques, autant ce n'est pas le cas pour les accès mémoire. Les accès mémoire ont une latence variable : quelques cycles pour un succès de cache, plusieurs dizaines de cycles pour un défaut de cache L1, pas loin de la centaine pour un défaut de cache L2, etc. Et cela pose des problèmes pour l'émission anticipée. L'émission en avance pour les accès mémoire est purement spéculative : le processeur émet des instructions en supposant que la lecture entrainera un succès de cache, quitte à annuler l'instruction en cas de défaut de cache. Mais faire ainsi demande non seulement d'annuler les instructions émises en avance, mais aussi de ne pas retirer les instructions émises en avance de la fenêtre d'instruction. Elles sont émises, mais une copie de sauvegarde est conservée dans la fenêtre d'instruction. Si le processeur détecte un défaut de cache, il peut alors ré-exécuter l'instruction. S'il détecte un succès de cache, les instructions lecture-dépendante sont retirées de la fenêtre d'instruction, la copie de sauvegarde est devenue inutile et est donc jetée. ===La logique de sélection : âge ou position ?=== La logique de sélection est primordiale pour de bonnes performances. Il existe deux méthodes principales pour sélectionner l'instruction à exécuter. La première est la plus simple : elle se base sur lé numéro de l'entrée. En effet, une fenêtre d'instruction est avant tout une sorte de mémoire, un mix entre mémoire associative, mémoire RAM, et FIFO. Et chaque entrée a un numéro, une adresse mémoire. Nous parlerons de numéro dans ce qui suit, car ce sera plus simple, le terme d'adresse mémoire étant peut-être un peu exagéré dans le contexte des fenêtres d'instruction. Toujours est-il que la fenêtre d'instruction est adressable dans le sens où on peut lui envoyer le numéro de l'entrée voulue, et la fenêtre d’instruction renvoie le contenu de l'entrée sur son port de lecture. Et c'est ce que fait la logique de sélection : elle génère le numéro de l'entrée à lire. Le numéro est alors envoyé sur l'entrée d'adresse de la fenêtre d’instruction, et elle fournit la micro-opération associée sur son port de lecture, son '''port d'émission'''. La première méthode de sélection, donc. Elle est basée sur le numéro de l'entrée. Si plusieurs entrées sont éveillées, la logique de sélection prend celle avec le plus petit numéro. Elle porte le nom de '''sélection par position''', sous-entendu position dans la fenêtre d'instruction. Vous l'avez peut-être deviné, mais la logique de sélection est alors un encodeur à priorité. Le circuit de sélection ne se résume donc pas seulement à un encodeur à priorité, mais c'est le circuit central. L'avantage d'une telle méthode de sélection est qu'elle est simple à implémenter : un encodeur à priorité est un circuit connu, facile à implémenter. Mais on remarque un défaut : un encodeur est un circuit assez rapide, mais qui utilise beaucoup de transistors, beaucoup de portes logiques, surtout si on veut qu'il soit rapide. Ce qui explique que la logique de sélection ait son propre étage de pipeline rien que pour elle. La seconde méthode s'appelle la '''sélection par âge''', au nom assez transparent. L'idée est de privilégier l'émission de l'instruction la plus ancienne. Elle demande que la fenêtre d'instruction trie les micro-opérations par ordre d'insertion dans la fenêtre d'instruction, ce qui en fait une pseudo-FIFO. Le tri est partiel, car les instructions peuvent sortir de la fenêtre d’instruction à tout moment. Compacter la fenêtre d'instruction, à savoir regrouper toutes les entrées valides est une idée, mais elle est compliquée à implémenter. Aussi, elles préfèrent encoder des informations sur l'ordre d'émission dans chaque entrée. L'encodeur à priorité doit alors travailler non pas sur des nombres entiers liés à l'ordre d'insertion dans la pseudo-FIFO. Elle est encore plus gourmande en circuits que la méthode précédente. Les processeurs haute performance utilisent souvent des méthodes hybrides. Par exemple, les processeurs AMD de microarchitecture Bulldozer utilisaient une méthode intermédiaire. Ils utilisaient une fenêtre d'instruction couplée à un encodeur à priorité pour la sélection par position, mais complémentaient le tout avec une unité qui mémorisait l'instruction la plus ancienne dans la fenêtre d’instruction. Le mécanisme de sélection par âge était utilisé en priorité. Mais si l'instruction la plus ancienne n'était pas prête, le processeur basculait sur le mécanisme de sélection par position. ===La compaction des fenêtres d'instruction=== À chaque cycle, les instructions décodées sont ajoutées dans la fenêtre d'instruction, dans des entrées vides. Vu que les instructions quittent celle-ci dans le désordre, ces vides sont dispersés dans la fenêtre d'instruction, ce qui pose problème pour déterminer où placer les nouvelles instructions. La solution la plus triviale consiste à conserver une liste des vides, mise à jour à chaque insertion ou émission d'instruction. Une autre solution consiste à éliminer les vides en compactant la fenêtre d'instruction à chaque cycle d'horloge. Des circuits se chargent de détecter les vides et de regrouper les instructions en un unique bloc. Il faut signaler que certains processeurs arrivent à se passer de cette étape de compactage, mais au prix de fenêtres d'instruction nettement plus complexes. Autre problème : quand il faut choisir quelle instruction émettre, il y a toujours plusieurs candidats. Si on choisit mal, des instructions restent en attente trop longtemps parce que d'autres instructions plus jeunes leur passent devant. Pour éviter cela, les instructions les plus vielles, les plus anciennes, sont prioritaires. Pour cela, on peut utiliser une FIFO un peu spéciale pour la fenêtre d'instruction. Si les ajouts d'instruction se font dans l'ordre, les instructions ne quittent pas forcément la fenêtre d'instruction dans l'ordre imposé par une FIFO : les instructions restent triées dans leur ordre d'ajout, même s'il y a des vides entre elles. Dans ces conditions, il est préférable que le compactage conserve l'ordre FIFO des instructions. Dans ces conditions, l'instruction la plus ancienne est celle qui est située à l'adresse la plus faible : le circuit de sélection peut donc être fabriqué avec des encodeurs, et est relativement simple. ==Les fenêtres d'instruction basées sur une matrice de dépendances== L'implémentation la plus simple étend le fonctionnement d'un pipeline dynamique usuel. Rappelez-vous le chapitre sur les pipelines dynamiques. Nous avions vu que de tels pipelines émettaient une instruction par cycle, quitte à émettre des bulles de pipeline en cas de dépendance bloquante. Et il est possible d'améliorer leur unité d'émission pour qu'elle soit compatible avec l'exécution dans le désordre. ===Rappels sur le registre de réservation/disponibilité=== L'émission d'une instruction est gouvernée par un ''registre de réservation'' qui indique quels registres sont réservés par une instruction, et ceux qui sont libres. Un registre réservé est un registre qui sera écrit par une instruction en cours d'exécution, mais qui n'a pas encore écrit son résultat. Les instructions candidates doivent avoir leurs opérandes dans des registres libres. Sinon, c'est signe que leurs opérandes sont réservés en écriture, donc pas encore écrites, donc pas disponibles. Si une instruction candidate veut lire ce registre, c'est signe qu'il y a une dépendance RAW : elle veut lire un registre réservé, qui est destiné à être écrit par une instruction en vol. Si elle veut écrire, c'est signe qu'elle veut écrire dans un registre où une autre instruction veut écrire : c'est une dépendance WAW. Dans les deux cas, l'instruction n'est pas émise. Le registre de réservation encode les registres réservés comme suit : chaque bit est associé à un registre. Le bit numéro 0 est associé au registre numéro 0, le bit numéro 1 au registre numéro 1, etc. Là, En clair, les numéros de registres réservés sont encodés en représentation non pas binaire, mais en représentation ''one-hot'' (vue au premier chapitre). {|class="wikitable" |+ Registre de réservation |- ! Registre 7 !! Registre 6 !! Registre 5 !! Registre 4 !! Registre 3 !! Registre 2 !! Registre 1 !! Registre 0 |- | 0 || 0 || 1 || 0 || 0 || 1 || 0 || 0 |} Avant d'émettre une instruction, l'unité d'émission extrait les registres opérande/destination et les convertis dans la même représentation que le registre de réservation, à savoir en représentation ''one-hot''. Le circuit de traduction binaire vers ''one-hot'' est, pour rappel, un simple décodeur. Puis, on fait un OU logique entre les sorties des décodeurs. Le résultat est un masque qui indique quels registres sont lus par l'instruction, encodé en représentation ''one-hot''. Appelons-le le '''masque d'opérandes'''. Le masque est alors comparé au registre de réservation pour vérifier si l'instruction peut être émise. [[File:Unité d'émission simple, dans l'ordre.png|centre|vignette|upright=2|Unité d'émission simple, dans l'ordre]] Si l'émission est autorisée, le registre de réservation est là aussi mis à jour. Le registre de réservation est aussi mis à jour dès qu'une instruction enregistre son résultat dans les registres, ou alors dès qu'il est disponible pour le contournement. Le bit associé au registre repasse alors à 0 (ou à 1). Sans contournement, la mise à jour se fait alors à la toute fin de l'instruction, quand elle se termine, lors de la dernière étape d'enregistrement, à la fin de son pipeline. Avec, elle se fait quand l'instruction quitte l'unité de calcul. ===L'extension à l'exécution dans le désordre : l'éveil par matrice de bits=== La différence entre un pipeline dynamique et l'exécution dans le désordre est que l'on passe d'une instruction à émettre à plusieurs. Plusieurs instructions sont mises en attente dans une fenêtre d’instruction, et y attendent leur tour. L'idée est alors d'envoyer le registre de disponibilité à toutes les entrées, à toutes les instructions en attente. Ainsi, on sait quelles sont les instructions qui peuvent s'exécuter et celles qui ne le peuvent pas. L'implémentation est assez simple, elle ressemble beaucoup à l'implémentation d'un pipeline dynamique simple, si ce n'est que des circuits sont dupliqués. L'implémentation utilise des fenêtres d'instruction légèrement différentes de celles introduites plus haut. Elles n'utilisent notamment pas de bits de disponibilité, mais autre chose. Lorsqu'une instruction est ajoutée à la fenêtre d'instruction, le masque de disponibilité des opérandes est stocké dans la fenêtre d'instruction. A chaque cycle, le registre de disponibilité est envoyé à toutes les entrées, et est comparé avec tous les masques de disponibilité des opérandes. Si une comparaison renvoie un 1, alors l'instruction de l'entrée est une instruction candidate à l'émission. [[File:Unité d'émission dans le désordre basée sur un registre de disponibilité.png|centre|vignette|upright=2.5|Unité d'émission dans le désordre basée sur un registre de disponibilité]] L'ensemble est implémenté avec l'aide d'une '''matrice de bits''', où chaque ligne correspond à une entrée et chaque colonne à un registre. À chaque croisement entre une ligne et une colonne, on trouve un bit. Si le bit de la ligne n et de la colonne m est à 1, cela veut dire : l'instruction dans l'entrée n a besoin de lire le registre m. S’il est à 0, alors cela veut dire que l'instruction stockée dans la ligne n'a pas besoin de la donnée dans le registre m. [[File:Planificateur à matrice de bits.jpg|centre|vignette|upright=2|Planificateur à matrice de bits.]] Lorsqu'une instruction réserve une entrée, elle initialise la ligne en fonction des registres qu'elle souhaite lire. Pour vérifier si une instruction a ses opérandes prêts, le processeur compare le registre de disponibilité à la ligne associée à l'instruction/entrée. A chaque intersection ligne-colonne, se trouve un comparateur de 1 bit, qui détecte si le registre est demandé et disponible. Les résultats de cette porte sont ensuite envoyés à une porte ET, qui fait le gros du travail. [[File:Logique de détection de la disponibilité d'une instruction.jpg|centre|vignette|upright=2|Logique de détection de la disponibilité d'une instruction.]] ==Les fenêtres d'instruction basées sur une mémoire associative== Les processeurs modernes utilisent une mémoire associative pour la fenêtre d'instruction. Les mémoires associatives ont été abordées il y a quelques chapitres, mais faisons quelques rappels. Les mémoires associatives servent à accélérer la recherche de données dans un ensemble. Or, une fenêtre d'instruction vérifie régulièrement si chaque entrée est prête. Il s'agit d'un processus de recherche d'une instruction qui respecte une condition bien précise dans la mémoire, ce qui fait que les mémoires associatives sont donc tout indiquées. Comme vous le savez, les signaux de commande d'une instruction sont propagés avec celle-ci dans le pipeline, le nom du registre de destination ne faisant pas exception. Le nom de registre est envoyé à la fenêtre d'instruction lors de l'écriture du résultat dans les registres. S'il y a correspondance, l'opérande est disponible et son bit de disponibilité est mis à 1. On peut adapter cette méthode pour tenir compte du contournement assez simplement. [[File:Détection des dépendances par propagation du registre de destination.png|centre|vignette|upright=2|Détection des dépendances par propagation du registre de destination.]] En conséquence, le circuit de détection des dépendances est constitué d'un grand nombre de comparateurs : un par champ « nom de registre » dans chaque entrée. La logique d'éveil/''wake up'' regroupe tous les comparateurs, la logique de sélection est un circuit situé en-dehors de la mémoire associative. Les entrées sont dans la mémoire associative elle-même. [[File:Gestion des bits de validité.png|centre|vignette|upright=2|Gestion des bits de validité.]] L'implémentation la plus simple est celle du schéma précédent, où on utilise une mémoire associative unique. Une version plus élaborée sépare la fenêtre d'instruction en deux parties : une mémoire qui mémorise les registres des opérandes, une autre mémoire pour le reste. La mémoire pour les registres opérandes est la mémoire associative proprement dite, c'est elle qui est associée aux comparateurs, à la logique de ''wake-up''/réveil, etc. Par contre, l'autre mémoire est une mémoire RAM simplifiée, qui mémorise les informations qui n'ont pas besoin des comparateurs. L'opcode de l'instruction est là-dedans, par exemple. La fenêtre d'instruction est donc une sorte de mémoire associative améliorée. Il se trouve que c'est aussi le cas du ROB. Et il est possible de fusionner le tampon de ré-ordonnancement avec la fenêtre d'instruction dans une structure unique. La différence avec une fenêtre d’instruction normale est que les entrées sont libérées non pas quand l'instruction est exécutée/émise, mais quand elle termine son exécution et quitte le ROB. La fenêtre d'instruction incorpore des bits dans chaque entrée, pour savoir si la µops associée a été émise et est en cours de traitement dans les ALUs. La méthode a notamment été utilisée sur les processeurs d'architecture K6 d'AMD. Le tout donnait une structure appelée le '''DRIS''' (''deferred scheduling register renaming instruction shelf''). Les processeurs PA 8000 de HP étaient aussi vraisemblabment dans ce cas, aussi. ===Les optimisations de la consommation d'énergie : la désactivation des portions inutilisées=== Le problème avec des fenêtres d'instruction de ce type est leur forte consommation énergétique, ainsi que le grand nombre de portes logiques utilisées, qui deviennent prohibitifs pour des fenêtres d'instruction un peu grosses. Pour résoudre ce problème, certains ont optimisé les comparateurs. D'autres ont tenté de profiter du fait que la majorité des bits dans les entrées sont composés de zéros. Bref, les optimisations purement matérielles sont légion. Une première solution est de désactiver les entrées qui sont inutilisées, vides, sans instruction. Pour cela, on fait précéder les comparateurs par un circuit qui les connecte ou déconnecte des lignes de bit. Le circuit est commandé par le bit ''empty'' qui indique si une entrée est vide ou non. L'avantage est que la consommation d'énergie de la fenêtre d'instruction devient alors proportionnelle au nombre d'entrées non-vides, et non au nombre d'entrées total. Du moins, en apparence, les entrées non-utilisées doivent quand même être alimentées pour fonctionner, mais l'activité de comparaison disparait dans les entrées vides. Il est possible d'étendre cette technique aux entrées dont les opérandes sont prêts. Les gains sont généralement assez bons, avec une réduction de consommation variant entre 30 et 50%, avec une implémentation très simple et très économe en circuits. Une autre solution, assez simple à mettre en place, consiste à désactiver une partie de la fenêtre d'instruction sin elle est inutilisée. Pour cela, il faut segmenter la fenêtre d'instruction avec la technique du ''wire partitionning''. Pour rappel, une fenêtre d'instruction est une mémoire associative. Et comme toute mémoire associative, elle contient des fils, les lignes de bit, qui relient les entrées/sorties à toutes les cellules mémoire. Plus une ligne de bit est longue, plus elle consomme d'énergie et plus le temps de lecture/écriture est long. L'idée est de segmenter les lignes de bits en plaçant des répéteurs qui recopient la tension d'un segment au suivant. Les répéteurs sont des tampons trois-états, ce qui permet de déconnecter les portions inutilisées de la ligne de bit. Ce faisant, la fenêtre d'instruction est découpée en segments, qui peuvent être désactivés si besoin. S'il y a peu d'instructions chargées dans la fenêtre d'instruction, les portions inutilisées sont désactivées. La technique marche d'autan mieux si les instructions sont compactées au début de la fenêtre d'instruction. [[File:Wire partitionning.png|centre|vignette|upright=2|Wire partitionning]] Tout le problème est de savoir quelles portions désactiver. La technique est assez simple si la fenêtre d'instruction est compactée, à savoir si toutes les instructions sont régulièrement regroupées au début de la mémoire CAM. Mais même avec cette optimisation, la décision de désactiver une portion de la fenêtre d'instruction n'est pas à prendre à la légère. Il ne faut pas désactiver une portion contenant des instructions pouvant être émise sous peu. La décision dépend de paramètres variés : proportion d'entrée vides, quantité d'entrées récemment activées/désactivées récemment, présences d'entrées avec un ''match'' d'opérandes récent, etc. Il est important de préciser que les techniques en question fonctionnent aussi sur les autres types de fenêtre d'instruction, qui ne sont pas basées sur des mémoires associatives. Nous allons voir celles-ci dans la suite du chapitre, mais gardez à l'esprit que ces optimisations, à savoir désactiver les entrées vides/prêts et partitionner la fenêtre d'instruction, sont des optimisations générales qui marchent avec presque tout. ===L'ajout d'une FIFO pour les instructions déjà prêtes à l'émission=== D'autres techniques permettent de réduire aussi bien le cout en circuits que la consommation d'énergie de la fenêtre d'instruction. L'idée est d'utiliser une mémoire associative quand elle est réellement nécessaire, mais d'utiliser une fenêtre d'instruction "normale" dès que possible. La méthode la plus simple tient compte du fait que certaines µopsont déjà toutes leurs opérandes de disponibles à l'émission, mais doivent quand même être mises en attente, parce que l'ALU adéquate est occupée, parce que des dépendances WAW/WAR sont encore là, ou pour tout autre raison. Dans ce cas, elles sont mises en attente non pas dans la fenêtre d'instruction, mais dans une mémoire FIFO toute simple. L'idée est qu'au lieu d'avoir une énorme mémoire associative pour la fenêtre d'instruction, on déplace quelques entrées dans une petite FIFO annexe. Le résultat est un gain d'énergie et de circuits, au prix d'une perte de performance mineure. La perte de performance en question se manifeste si aucune instruction n'a ses opérandes de prêtes à l'émission : le programme n'utilise pas la FIFO et voit alors une fenêtre d'instruction plus petite. Une amélioration de cette technique tient compte du fait que certaines instructions sont dans un cas intermédiaire. Elles ont déjà un opérande de prête lors de l'émission, mais pas l'autre. Le nombre d'opérandes varie suivant l’instruction : certaines n'ont besoin que d'un seul opérande. De plus, il arrive qu'une opération tout juste décodée ait déjà un ou plusieurs de ses opérandes de prêts. Cette constatation permet d'éviter d'utiliser des comparateurs pour les opérandes déjà prêts. Par exemple, on peut parfaitement utiliser trois fenêtres d'instruction : * une pour les instructions dont tous les opérandes sont prêts, mais qui sont quand même mises en attente, sans comparateur ; * une pour les instructions dont un seul opérande manque, qui n'utilise qu'un comparateur par entrée ; * une pour les instructions dont deux opérandes manquent à l'appel, qui utilise deux comparateurs par entrée. C'est beaucoup plus économique que d'utiliser une seule grosse fenêtre d'instruction qui contiendrait autant d'entrées que les trois précédentes réunies, avec deux comparateurs par entrée. Certains sont même allés plus loin, et ont proposé de supprimer la fenêtre d'instruction avec deux opérandes par entrée. Les instructions dont deux opérandes sont inconnus au décodage sont stockées dans la fenêtre d'instruction pour instructions avec un comparateur par entrée. Un circuit de prédiction se charge alors de prédire l'opérande manquant, cette prédiction étant vérifiée plus loin dans le pipeline. Il serait cependant étonnant qu'une telle proposition ait donné lieu à la moindre implémentation réelle. ===Les optimisations de la consommation d'énergie avancées=== D'autres chercheurs ont conservé une fenêtre d'instruction unique, avec autant de comparateurs par entrée qu'il y a d'opérandes possibles par instruction. Simplement, le processus de détection des opérandes prêts est légèrement ralenti : on ne vérifie qu'un opérande par cycle. Pour vérifier les deux opérandes d'une entrée, on doit attendre deux cycles. Enfin, certains chercheurs ont proposé des fenêtres d'instruction segmentées. Les instructions circulent à chaque cycle d'un segment vers le suivant : en conséquence, certains segments conservent les instructions les plus anciennes, un autre les instructions les plus jeunes, etc. Seul le denier segment, celui qui contient les instructions les plus vielles, peut émettre une instruction : la détection des opérandes se fait seulement dans le dernier segment, qui contient les instructions les plus anciennes. On économise ainsi beaucoup de comparateurs. Certains chercheurs ont tenté de pipeliner l'étape de sélection des opérandes, ainsi que l'étage d'arbitrage. Mais en faisant cela, il faut plusieurs cycles pour détecter qu'une instruction a ses opérandes prêts, ce qui pose problème face à de nombreuses dépendances RAW. Pour éviter de trop perdre en performances, certains chercheurs ont décidé d'utiliser des techniques pour prédire quelles seront les instructions dont les opérandes seront bientôt prêts. Si détecter qu'une instruction est prête prend n cycles, le processeur devra tenter de prédire la future disponibilité des opérandes n cycles en avance pour obtenir des performances optimales. ===Remplacer la mémoire associative par une RAM=== Une autre optimisation possible est de remplacer la fenêtre d'instruction par une mémoire RAM, dont chaque mot mémoire correspondrait à une entrée. Une telle optimisation permet en théorie de se passer des comparateurs associés à chaque entrée, mais au prix de l'ajout de circuits annexes potentiellement couteux. La première de ces techniques, la '''recherche directe par étiquette''' (direct tag search) fut créée par Weiss et son collègue Smith. Ils cherchaient à améliorer l'algorithme de Tomasulo, un algorithme qu'on expliquera dans quelques chapitres. Rappelons que chaque instruction produit un résultat, qui devra être rapatrié dans une ou plusieurs entrées de la fenêtre d'instruction. L'optimisation de la recherche directe par étiquette fonctionne dans le cas où le résultat de l'instruction n'est utilisé que par une seule entrée, et pas plusieurs. Le principe est simple : chaque champ « opérande » d'une entrée est adressable via le nom de registre de cet opérande. Pour faire le lien entre entrée et nom de registre, la recherche directe par étiquette ajoute une table de correspondances matérielle, une mémoire RAM qui mémorise les adresses des champs « opérande » des entrées. Les adresses envoyées dans cette mémoire sont les noms de registres des résultats. Lors de l'émission, la table de correspondances est mise à jour. Les numéros des champs « opérande » réservés lors de l'émission sont mémorisés dans les mots mémoire qui correspondent aux deux registres sources. Toutefois, une petite vérification est faite lors de l'émission : s'il y a déjà une correspondance dans la table pour un registre source, alors une autre instruction compte lire ce registre. Pour éviter d'écraser les données de l'instruction précédente dans la table de correspondances, l'émission de l'instruction est bloquée. [[File:Recherche directe par étiquette.png|centre|vignette|upright=2|Recherche directe par étiquette.]] ==Les fenêtres d’instruction avec préplanification== Avec la '''préplanification''' (''prescheduling''), la fenêtre d’instruction est composée de mémoires FIFO dans lesquelles les instructions sont triées dans l'ordre d'émission. Il n'y a pas de logique d’émission proprement dite, celle-ci se bornant à vérifier si l'instruction située au début de la FIFO peut s’exécuter. Par contre, le préplanificateur détecte les dépendances et en déduit où insérer les instructions dans le tampon d'émission, à l'endroit le plus adéquat. [[File:Préplanification.jpg|centre|vignette|upright=2|Préplanification.]] ===L'usage de FIFO multiples=== La technique de préplanification la plus simple utilise plusieurs FIFO. Quand une instruction a une dépendance avec une autre instruction, les deux sont placées dans la même FIFO. Pour cela, le préplanificateur détecte les chaines d'instructions dépendantes, et place les instructions dans la FIFO adéquate. A chaque cycle, l'unité d'émission lit une micro-opération dans chaque FIFO et vérifie si elle peut l'émettre. Si la micro-opération n'a pas ses opérandes disponibles, ou qu'une dépendance structurelle survient, alors la FIFO est bloquée. La micro-opération attend que la dépendance soit résolue, bloquant toutes les instructions précédentes. Mais les autres FIFO ne sont pas bloquées, laissant de la marge de manœuvre. [[File:Préplanification par FIFO multiples.png|centre|vignette|upright=1.5|Préplanification par FIFO multiples.]] ===La technique du tampon trié=== La technique du '''tampon trié''' trie les instructions selon le temps d'attente avant leur exécution. Les instructions qui sont censées s’exécuter bientôt sont insérées au tout début de la FIFO, tandis que les instructions qui s’exécuteront dans un long moment sont insérées vers la fin. Là encore, l'unité d'émission lit une micro-opération dans la FIFO, et détermine si elle peut être émise. Si une dépendance survient, l'émission est retardée, et la FIFO est bloquée. [[File:Préplanification par tampon trié.png|centre|vignette|upright=1.5|Préplanification par tampon trié.]] La technique a cependant quelques problèmes assez importants. Le premier problème est que la FIFO est bloquée lorsqu'une micro-opération ne peut être émise. Le second problème est que le temps avant exécution n'est pas toujours connu, notamment pour les instructions d'accès mémoire. Et cela se répercute sur les instructions dépendantes de celles-ci. Pour résoudre ce genre de problèmes, l'usage d'un pipeline à ''replay'' est possible, et est même l'une des meilleures solutions possible, malgré ses défauts. L'idée est que les lectures sont pré-planifiées en supposant qu'elles font un succès de cache L1. Si la prédiction est fausse, la lecture est ré-exécutée plusieurs cycles plus tard, en supposant qu'elle fait un succès dans le cache L2, et ainsi de suite. Elle est alors ré-insérée dans la FIFO, elle est pré-planifiée une seconde fois. Il en est de même si une micro-opération ne peut pas être émise : il suffit de la réinsérer dans la FIFO au bon endroit, en attendant que ses dépendances soient résolues. Ainsi, l'instruction fautive ne bloque pas la fenêtre d’instruction, et retente sa chance autant de fois qu'il le faut. [[File:Préplanification par fenêtre d’instruction scorebarodée.png|centre|vignette|upright=1.5|Préplanification par fenêtre d’instruction scorebarodée.]] Une autre solution utilise deux fenêtres d’instruction : une FIFO gérée par la préplanification, et une vraie fenêtre d'instruction pour les instructions dont le temps d'attente ne peut pas être déterminé. Il est possible de mettre cette dernière avant la préplanification, afin de gérer les temps d'attente des instructions d'accès mémoire. Quand le temps d'attente d'une lecture devient connu, ses instructions dépendantes sont gérées avec préplanification. [[File:Préplanification avec fenêtre d’instruction.png|centre|vignette|upright=2.5|Préplanification avec fenêtre d’instruction.]] ===Les fenêtres d'instruction avec allocation temporelle statique=== L''''allocation temporelle statique''' correspond à une technique utilisée sur les processeurs Cuzco de l'entreprise Condor. La technique en question a été présenté en 2025, mais des idées similaires ont été présentées dans la littérature académique. Elle ressemble beaucoup aux techniques de pré-planification, avec cependant quelques différences. L'idée est simple : le processeur dispose de plusieurs fenêtres d'instruction, qui mettent en attente les micro-opérations. Lors de l'étape de renommage de registres, le processeur détermine dans combien de cycles d'horloge la micro-opération sera prête pour exécution. La micro-opération est alors mise en attente durant ce nombre de cycles, dans les fenêtres d'instruction, puis est émise une fois ce nombre de cycles écoulés. Ce faisant, les fenêtres d'instruction n'ont pas besoin de détecter la disponibilité des opérandes à chaque cycle, pour chaque micro-opération en attente. Le ''timing'' de l'émission des micro-opérations est décidé à l'avance. L'implémentation exacte n'est pas connue, mais plusieurs solutions sont imaginables. Par exemple, la fenêtre d'instruction peut simplement être composée de plusieurs mémoires de petite taille, chacune contenant les micro-opérations destinées à être exécutées dans N cycles, N étant différent pour chaque mémoire. Une autre solution, plus réaliste, utilise une fenêtre d'instruction dans laquelle la micro-opération est couplée à des champs pour les opérandes, et un champ compteur. Le champ compteur est initialisé avec le nombre de cycles à attendre, et est décrémenté à chaque cycle d'horloge. Quand il atteint zéro, la micro-opération est émise. Vous remarquerez que la méthode ne marche que si toutes les micro-opérations prennent un nombre fixe de cycles d'horloge. Et autant c'est le cas pour les micro-opérations arithmétiques ou logiques, autant les accès mémoire ne rentrent pas dans ce cadre. En théorie, on ne sait pas combien de temps prendra un accès mémoire. Et cette incertitude se répercute sur les instructions dépendantes d'un accès mémoire. Pour éviter cela, le processeur réutilise un pipeline à ''replay'' tel que vu dans le chapitre précédent. L'unité de renommage de registre suppose que tout accès mémoire fait un succès de cache L1, et décide des ''timings'' d'émission sous cette hypothèse. Si une lecture subit un défaut de cache, elle est ré-exécutée, de même que toutes les instructions dépendantes. Pour cela, le registre de destination de la lecture est marqué comme invalide, grâce à un bit spécifique attaché au registre. Toute instruction qui lit un opérande invalide est elle aussi ré-executée de zéro. Pour simplifier, l'unité d'émission ressemble à une unité d'émission dans l'ordre, avec un registre de disponibilité, qu'on aurait amélioré pour aller au-delà de la simple détection des dépendances d'instruction. Pour déterminer les ''timings'' d'émission, à savoir quand émettre une micro-opération, le processeur utilise une unité d'émission à deux étages. Le premier étage est appelé le ''register scoreboard'', le second étage est appelé la ''Time Ressource Matrix''. Les deux étages communiquent entre eux, comme on va le voir, et leurs noms donnent une idée de ce qu'ils font. Le premier étage gère les dépendances de registres, le second gère les dépendances structurelles. Le premier étage est un registre de disponibilité amélioré, qui gère les dépendances de registre. Cet étage sait quand tel registre sera écrit, et donc que l'opérande écrit dedans sera disponible à partir de tel cycle d'horloge. Il le sait car l'étage suivant l'aura prévenu, mais laissons cela de côté pour le moment. Quand une micro-opération rentre dans cet étage, il vérifie les dépendances avec les registres et les micro-opérations antérieures. Vu qu'il sait quand les registres seront disponibles, il peut déterminer quand l'instruction pourra s'exécuter. Par exemple, si une micro-opération lit les deux registres R7 et R15, qui sont disponibles respectivement dans 5 et 7 cycles, le premier étage sait que la micro-opération devra attendre 7 cycles. Mais tout cela ne suffit pas à déterminer quand émettre une micro-opération. En effet, il fait aussi gérer les dépendances structurelles, ce qui est le boulot du second étage. Le second étage utilise pour cela une ''Time Ressource Matrix'', qui mémorise l'occupation de diverses "ressources", pour les 256 cycles d'horloge à venir. Les ressources en question sont les ports de lecture/écriture du banc de registre, les ALUs utilisées, si la micro-opération utilise l'unité mémoire, etc. Le second étage prend en entrée une micro-opération, détermine quelles "ressources" elle utilise, puis regarde leur disponibilité. Elle détecte alors les dépendances structurelles et détermine alors quand peut s'exécuter la micro-opération. Elle peut retarder l'émission de quelques cycles, si une dépendance structurelle est détectée. Une fois sortie du second étage, on sait quand la micro-opération va être émise, à quel cycle précisément. Et vu que la durée de l'instruction est fixe, on sait quand cette micro-opération va se terminer, quand son résultat sera disponible. Cela permet de mettre à jour la ''Time Ressource Matrix'', pour préciser que le port d'écriture sera occupé à tel moment. De plus, cette information est transmise au premier étage, qui sait alors quand est enregistré le résultat dans le registre de destination. C'est comme cela que le premier étage sait quand un registre est disponible : le second étage le prévient, quand il émet une instruction ! La ''Time Ressource Matrix''mémorise l'occupation des "ressources" pour les 256 cycles d'horloge à venir. Cependant, elle ne vérifie pas les dépendances pour les 256 cycles suivants. Quand elle reçoit une micro-opération, elle teste les dépendances structurelles pour seulement les 8 prochains cycles maximum. Si la micro-opération ne peut pas être émise pendant ces 8 cycles, le pipeline est bloqué, un ''pipeline stall'' est émis. Pour être plus précis, vu que le processeur peut décoder 8 micro-opérations en même temps, cela permet de ne consulter que 64 cycles d'horloge sur les 256. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les premiers processeurs Intel | prevText=Les premiers processeurs Intel | next=Le renommage de registres | nextText=Le renommage de registres }} </noinclude> tvfwpo8xzo4wwcq92e2tylf7tfp8shq 773619 773615 2026-09-29T20:54:09Z Mewtow 31375 773619 wikitext text/x-wiki Dans les chapitres précédents, nous avons parlé des techniques dites d''''émission dans l'ordre'''. L'idée est d’exécuter une nouvelle micro-opération à chaque cycle, dans des unités de calcul séparées. Les instructions sont émises consécutivement, mais les instructions s’exécutent en parallèle dans des unités de calcul séparées. Par contre, quand l'unité d'émission ne peut pas émettre une instruction, elle bloque tout le pipeline. Les instructions qui suivent sont elles aussi bloquées, elles doivent attendre leur tour, même si elles sont en capacité de s'exécuter. Les techniques d'exécution dans le désordre que nous allons voir dans ce chapitre corrigent ce point précis. Elles sont dites à '''émission dans le désordre'''. Elles se distinguent des précédentes sur un point précis : quand l'unité d'émission bloque l'émission d'une instruction, les instructions suivantes peuvent poursuivre. L'émission des instructions peut donc se faire dans le désordre, dans le sens où une instruction peut être émise alors qu'une instruction précédente ne l'est pas encore. Mais avant de poursuivre, quelques point niveaux terminologie : * L'émission dans le désordre est un terme parlant et assez précis. Malheureusement, la terminologie la plus utilisée par d''''exécution dans le désordre'''. Et nous utiliserons ce terme dans la suite du cours, histoire de ne pas trop dévier de la nomenclature habituelle. * Nous utiliserons parfois l'abréviation OOO pour parler d'exécution dans le désordre. L'abréviation est celle de ''Out Of Order Excution''. * Nous utiliserons aussi l'abréviation ''µop'' pour parler de micro-opération, ''µops'' au pluriel pour parler de plusieurs micro-opérations, ou des micro-opérations en général. L'exécution dans le désordre ne gère en effet que des µops, elle se situe après l'étape de décodage. Pour décrire comment est implémentée l'émission dans le désordre, il faut commencer par parler des processeurs sans. Les processeurs sans exécution dans le désordre ont une unité d'émission qui bloque tout le pipeline dès qu'une µop ne peut pas être émise. Pour limiter l'impact de ce blocage, quelques rares processeurs incorporent une '''file de micro-opération''', une mémoire FIFO qui met en attente les µops. Vu que c'est une mémoire FIFO, les µops sont émises dans l'ordre, à savoir l'ordre d'ajout, dans l'ordre de décodage. Le schéma ci-dessous illustre une telle file d'attente couplée à un ''scoreboard''. L'exécution dans le désordre améliore la file de µops sur un point : ce n'est plus une mémoire FIFO. Les µops sont insérées dans l'ordre, mais peuvent sortir dans le désordre (être émises dans le désordre). La file de µops devient alors un '''''scheduler''''', terme anglais que je ne compte pas traduire. Un terme équivalent est '''fenêtre d'instruction''', terme traduit directement de l'anglais ''instruction Window''. Terme assez trompeur, car elles mettent en attente des µops, pas des instructions. [[File:Différence file µops et fenêtres instruction.png|centre|vignette|upright=2|Différence file µops et fenêtres instruction]] L'implémentation la plus simple de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Les µops décodées sont accumulées dans le ''scheduler'', où elles attendent leur tour. La fenêtre d'instruction sert donc de file d'attente. Le ''scheduler'' émet une µop dès que ses opérandes sont disponibles. Par disponible, on veut dire présent soit dans le réseau de contournement, soit dans les registres. Le ''scheduler'' détecte automatiquement quand les opérandes d'une µop sont disponibles, grâce à une unité d'émission intégrée. L'unité d'émission et le ''scheduler'' sont fusionnés ensemble, dans un seul circuit, mais nous allons dire qu'ils sont conceptuellement séparés pour le moment. A chaque cycle, l'unité d'émission consulte les µops en attente pour détecter lesquelles peuvent s'exécuter. Le ''scheduler'' est spécialement être conçue pour, c'est une sorte de mémoire associative très complexe, comme on le verra dans ce qui suit. [[File:OOO Issue.png|centre|vignette|upright=2.5|Exécution dans le désordre avec une fenêtre d'instruction]] Une fois qu'une µop sort du décodeur d'instructions, elle est ajoutée en parallèle dans la fenêtre d'instruction et le ROB. La raison est que les µops quittent la fenêtre d'instruction dans le désordre, et qu'elles doivent être remises en ordre par la suite. Le ROB s'occupe de cette remise en ordre, mais il a besoin de savoir dans quel ordre les µops sont censées être, et cet ordre est celui du décodage. Aussi, pour remplir le ROB, la seule opportunité est en sortie de l'unité de décodage. Dans le cas où une instruction est décodée en plusieurs micro-opérations, elles sont toutes insérées en même temps dans la fenêtre d'instruction et le ROB, en tenant compte de leur ordre. [[File:Fenêtre d'instruction.png|centre|vignette|upright=2|Fenêtre d'instruction.]] Avant de poursuivre, précisons que les micro-opérations mémoire sont à part des autres, pour diverses raisons. Une de ces raisons est que les dépendances de données sont classées en deux types : les dépendances de registre et les dépendances d'adresse. Et les deux sont fondamentalement différentes. Autant on peut détecter les dépendances de registre lors de l'émission, autant c'est plus compliqué avec les dépendances d'adresse. De plus, rappelons que si les lectures peuvent s'exécuter dans le désordre, les écritures doivent s'exécuter dans l'ordre, ou du moins en donner l'illusion. Pour cela, le processeur remet les écritures dans l'ordre avec une sorte de mini-ROB intégré à l'unité mémoire, appelée la file d'écriture. Elle complémente le ROB, qui lui ne gère que les écritures dans les registres, mais les deux collaborent. La file d'écriture envoie une écriture à la mémoire RAM quand le ROB lui dit que c'est bon, les instructions précédentes sont terminées ''dans l'ordre du programme''. Les processeurs modernes ajoutent des techniques d'exécution dans le désordre des accès mémoire, mais nous les verrons dans un chapitre dédié. Elles permettent d'utiliser une fenêtre d'instruction unique, qui mémorise aussi les µops mémoire. Si elles sont mises en place, l'unité mémoire n'a pas besoin de file de µops séparée. L'idée est que les dépendances de registre sont traitées par la fenêtre d'instruction, mais que l'unité mémoire gére les dépendances d'adresse. Les dépendances d'adresse sont gérées par des techniques de ''désambiguation mémoire'', qui auront droit à un chapitre dédié. [[File:Processeur avec exécution dans le désodre des accès mémoire.png|centre|vignette|upright=2|Processeur avec exécution dans le désodre des accès mémoire]] Les processeurs assez anciens n'autorisaient pas d'exécution dans le désordre des accès mémoire. Concrétement, les accs mémoire devaient se faire dans l'ordre, mais les autres µops pouvaient être exécutées dans le désordre. Il s'agit donc d'un ordre entre µops mémoire, pas entre µops mémoire et autres µops. Les µops entières et flottantes pouvaient être exécutées avant une µops mémoire qui est avant elle dans l'ordre du programme, ce n'est pas un problème. Pour garantir l'ordre des µops mémoire, l'unité mémoire est précédée par une file de micro-opérations séparée, pour forcer l'exécution dans l'ordre des accès mémoire. De plus, les µops mémoire ne peuvent pas utiliser la fenêtre d'instruction. Dit autrement, la fenêtre d'instruction ne mémorise pas de µops mémoire. Après le décodage, les µops sont réparties soit dans la file de µops mémoire, soit dans la fenêtre d'instruction. Le décodeur classe les µops suivant que ce sont des µops mémoire ou non, et les envoient à la bonne destination. Dans ce chapitre, on supposera que c'est cette solution qui est utilisée. [[File:Processeur avec émission dans l'ordre des accès mémoire.png|centre|vignette|upright=2|Processeur avec émission dans l'ordre des accès mémoire]] ==L'implémentation d'une fenêtre d'instruction : généralités== Une fenêtre d'instruction est une mémoire qui mémorise des micro-opérations. Elle est cependant plus complexe qu'une mémoire RAM ou qu'une FIFO et ressemble un petit peu à une mémoire cache. Elle dispose d'un port d'écriture et d'un port de lecture, au minimum. Le port d'écriture permet à l'unité de décodage d'insérer une micro-opération dedans, d'ajouter la micro-opération qui vient d'être décodée. Si une instruction machine est décodée en plusieurs micro-opération, deux possibilités. La première est de les insérer un par un, ce qui fait qu'on peut se contenter d'un seul port d'écriture. L'autre possibilité est de les ajouter en même temps, ce qui demande plusieurs ports d'écriture. Le port de lecture sert à émettre une instruction. On part du principe que la fenêtre d'instruction ne peut émettre qu'une seule instruction à la fois, car les processeurs que nous avons vu précédemment sont de ce type. Mais nous verrons dans quelques chapitres qu'il existe des processeurs dits superscalaires, qui sont capables d'émettre plusieurs instructions par cycle. Dans ce cas, la fenêtre d'instruction a un seul port de lecture. Un processeur superscalaire, quant à lui, doit avoir un port de lecture par unité de calcul, ce qui fait beaucoup plus. Les fenêtres d'instruction sont composées d''''entrées''', des mots mémoire qui stockent une instruction. Une instruction réserve une entrée après son décodage et la libère dès qu'elle est envoyée aux unités de calcul. Une entrée contient l'opcode (les signaux de commande à envoyer à l'ALU), le registre de destination du résultat, les registres de chaque opérande, et éventuellement des signaux de commande en plus. De plus, chaque opérande est couplée à un bit de disponibilité, qui indique si elle est disponible. Quand un opérande est écrit dans les registres, le bit de présence correspondant est mis à jour. Enfin, chaque entrée possède un bit ''empty'' qui indique si elle est vide, cette information étant utile pour réserver des entrées. [[File:Entrée d'une station de réservation - sans les tags.png|centre|vignette|upright=3|Entrée d'une fenêtre d'instruction]] ===Les stations de réservation=== Les '''stations de réservation''' sont des fenêtres d'instruction particulières, qui sont capables de mémoriser les opérandes des instructions. Les entrées des stations de réservation sont identiques à celle des autres fenêtres d'instruction, si ce n'est que les opérandes de l'instruction sont enregistrés directement dans des champs séparés. Il y a deux champs, un par opérande, pour stocker l'opérande elle-même, lue depuis les registres ou obtenue via le réseau de contournement. Notons que les champs pour les opérandes viennent en plus des champs pour les noms de registres, encore que les deux peuvent être fusionnés si on veut optimiser le tout. [[File:Entrée d'une station de réservation.png|centre|vignette|upright=3|Entrée d'une station de réservation.]] Précisons que la terminologie n'est pas très fiable. Les termes "fenêtre d'instruction" et "station de réservation" ne regroupent pas du tout la même chose d'un papier de recherche à l'autre, d'un bouquin à l'autre, d'un chercheur à l'autre, d'un ingénieur à l'autre, d'un professeur à l'autre. Le terme initial vient pourtant de l'article original sur l'algorithme de Tomasulo, où il désignait une fenêtre d'instruction associée à une unité de calcul précise. Mais le terme a ensuite été réutilisé, ce qui fait que certains processeurs avec plusieurs unités de calcul sont décrits comme ayant une unique station de réservation. En bref : c'est le bazar ! Mais nous en reparlerons dans le chapitre sur le renommage de registres, car c'est la place idéale pour les aborder. Toujours est-il que j'ai fait le choix de confondre les concepts de fenêtre d'instruction et de station de réservation avec les concepts de '''lecture avant émission''' et de '''lecture après émission'''. La différence entre les deux est que les registres sont lus après émission avec une fenêtre d'instruction, avant avec des stations de réservation. Dans le cas "avant émission", les opérandes sont mémorisés dans la station de réservation. Et cette différence a une influence sur le pipeline du processeur, le banc de registres et tout ce qui s'en suit. Un désavantage de la lecture avant émission est qu'il faut stocker les opérandes après lecture, ici dans les stations de réservation. Mais un avantage est que le banc de registre a besoin de moins de ports de lecture, car une bonne partie des opérandes sont fournies par le système de contournement. Nous verrons cela dans le détail dans le chapitre sur les processeurs superscalaires. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Lecture après émission.]] [[File:Read Before Issue.png|centre|vignette|upright=2.5|Lecture avant émission.]] ===La logique d'éveil et de sélection=== Dans le cas qui va suivre, on suppose que le processeur ne peut émettre qu'une instruction à la fois. Chaque cycle, une instruction est sélectionnée et est envoyée dans le chemin de données, soit à une ALU, soit à une unité d'accès mémoire. La sélection d'une instruction est effectuée par l'unité d'émission, qui est aussi appelée le '''''scheduler'''''. Elle gère la disponibilité des opérandes et la disponibilité des unités de calcul adéquate. Le choix de l'instruction émise doit être le plus pertinent possible, pour des raisons de performances. Pour le premier point, l'unité d'émission détermine quelles instructions sont candidates pour l'émission. Les ''instructions candidates'' sont celles dont tous les opérandes sont prêts. Le processeur contient un circuit qui détecte les instructions candidates : la '''logique d’éveil''' (''wake-up logic''). Une fois que la logique d'éveil a fait son travail, une instruction est choisie pour s’exécuter en fonction de la disponibilité des unités de calcul adéquates. Ce rôle est dévolu à un circuit qu'on appelle la '''logique de sélection''', ou ''select logic''. [[File:Fonctionnement complet de la logique d’émission.jpg|centre|vignette|upright=1.5|Fonctionnement complet de la logique d’émission.]] La logique de sélection doit gérer le fait que les unités de calcul du processeur ne sont pas toutes identiques. Déjà, un processeur a généralement des unités séparées pour les instructions entières et flottantes, des unités spécialisées dans les accès mémoire, parfois des unités spécialisées pour les branchements. Une instruction doit être attribuée à la bonne unité de calcul, on ne doit pas envoyer une instruction entière dans une unité de calcul flottante. De plus, parmi les unités de calcul entières, toutes ne sont pas identiques. Par exemple, il est fréquent d'avoir plusieurs unités de calcul spécialisées dans les opérations simples (additions, soustractions, opérations logiques) avec une unité pour les multiplications/divisions séparées, parfois une unité spécialisée pour les décalages/rotations, etc. Là encore, allouer la bonne instruction à la bonne ALU est complexe. Plus les unités de calcul sont hétérogènes, plus la logique de sélection est compliquée. Les logiques d'éveil comme de sélection sont assez complexes. Comme on le verra plus bas, la logique de sélection la plus simple, qui gère une seule unité de calcul, est basée sur un encodeur à priorité couplé à d'autres circuits. Et pour gérer plusieurs ALUs, il faut mettre des encodeurs en cascade. Le résultat est que même en prenant une logique de sélection simple, elle sera assez lente et gourmande en circuits. Aussi, la logique de sélection met souvent un cycle d'horloge entier pour faire son travail, elle a son propre étage de pipeline attribué. La logique d'éveil est dans le même cas, ce qui fait qu'émettre une micro-opération demande deux cycles d'horloge. Le défaut est que cela rajoute des cycles d'horloges entre la fenêtre d'instruction et l'ALU, ce qui complique la gestion du pipeline. Ces cycles de retard sont à prendre en compte au moment d'émettre les instructions, les ''scheduler'' doit en tenir compte pour des performances optimales. Sans tenir compte de ces cycles de retard, les instructions arrivent en retard de quelques cycles à l'ALU, cycles de retard durant lesquels l'ALU n'a pas fait de calcul et a été sous-utilisée, sans compter que le système de contournement n'est pas utilisé au mieux. Et le problème est encore plus important sur les processeurs avec des stations de réservation, qui utilisent la "lecture après émission" : cela rajoute un cycle d'horloge en plus, un temps de retard en plus. ===La logique d'éveil : l'émission anticipée=== La logique d'éveil doit tenir compte du fait qu'il y a plusieurs étages entre l'émission et l'exécution sur une unité de calcul. Par exemple, un processeur a souvent entre un et à cinq étages entre la file d'attente et les unités de calcul. Il faut lire les registres, gérer le contournement, et cela peut prendre quelques cycles d'horloge. Sur le Pentium 4, on trouve 6 étages entre la fenêtre d’instruction et l'entrée de l'ALU. Si les micro-opérations sont émises quand les opérandes sont disponibles, il y aura un délai de quelques cycles avant qu'elles atteignent l'ALU. Alors qu'idéalement, on souhaiterait que la micro-opération atteigne l'ALU dès que ses opérandes sont disponibles, pour profiter des techniques de contournement. Pour cela, la logique d'éveil émet les instructions quelques cycles en avance pour qu'elles arrivent au bon moment. Il s'agit d'une technique d''''émission anticipée''', dont nous avions parlé dans le chapitre sur le contournement. : Il faut noter que le problème se pose plus avec des fenêtres d'instruction qu'avec des stations de réservation. Les premières ont un étage en plus entre émission et ALU, vu qu'il faut lire des registres après l'émission. L'émission anticipée demande d'émettre un signal d'éveil en avance de quelques cycles, pile au bon moment. Par exemples, si on a deux étages entre l'ALU et l'unité d'émission, le signal de réveil sera généré deux cycles avant que le résultat soit effectivement calculé. L'implémentation varie, mais deux solutions sont possibles. La première est de générer le signal d'éveil dans l'ALU, ce qui n'a de sens que pour les opérations comme les multiplications ou les divisions, qui prennent plusieurs cycles. Une autre technique génère le signal de réveil dans une structure centralisée, spécialisée dans la génération des signaux d'éveil. L'unité de composée d'un registre à décalage par registre. Imaginons qu'une instruction est émise, que cette instruction mette N cycles à s'exécuter, et qu'elle écrive dans un registre de destination. L'unité sélectionne alors le registre à décalage associé au registre de destination, et met le bit numéro N à 1. Le registre décalé d'un cran à chaque cycle. Quand le bit sortant est un 1, alors le signal de validité pour l'opérande est généré. L'émission anticipée marche bien si l'instruction a une durée fixe, connue à l'avance. Et autant c'est le cas pour les instructions arithmétiques et logiques, autant ce n'est pas le cas pour les accès mémoire. Les accès mémoire ont une latence variable : quelques cycles pour un succès de cache, plusieurs dizaines de cycles pour un défaut de cache L1, pas loin de la centaine pour un défaut de cache L2, etc. Et cela pose des problèmes pour l'émission anticipée. L'émission en avance pour les accès mémoire est purement spéculative : le processeur émet des instructions en supposant que la lecture entrainera un succès de cache, quitte à annuler l'instruction en cas de défaut de cache. Mais faire ainsi demande non seulement d'annuler les instructions émises en avance, mais aussi de ne pas retirer les instructions émises en avance de la fenêtre d'instruction. Elles sont émises, mais une copie de sauvegarde est conservée dans la fenêtre d'instruction. Si le processeur détecte un défaut de cache, il peut alors ré-exécuter l'instruction. S'il détecte un succès de cache, les instructions lecture-dépendante sont retirées de la fenêtre d'instruction, la copie de sauvegarde est devenue inutile et est donc jetée. ===La logique de sélection : âge ou position ?=== La logique de sélection est primordiale pour de bonnes performances. Il existe deux méthodes principales pour sélectionner l'instruction à exécuter. La première est la plus simple : elle se base sur lé numéro de l'entrée. En effet, une fenêtre d'instruction est avant tout une sorte de mémoire, un mix entre mémoire associative, mémoire RAM, et FIFO. Et chaque entrée a un numéro, une adresse mémoire. Nous parlerons de numéro dans ce qui suit, car ce sera plus simple, le terme d'adresse mémoire étant peut-être un peu exagéré dans le contexte des fenêtres d'instruction. Toujours est-il que la fenêtre d'instruction est adressable dans le sens où on peut lui envoyer le numéro de l'entrée voulue, et la fenêtre d’instruction renvoie le contenu de l'entrée sur son port de lecture. Et c'est ce que fait la logique de sélection : elle génère le numéro de l'entrée à lire. Le numéro est alors envoyé sur l'entrée d'adresse de la fenêtre d’instruction, et elle fournit la micro-opération associée sur son port de lecture, son '''port d'émission'''. La première méthode de sélection, donc. Elle est basée sur le numéro de l'entrée. Si plusieurs entrées sont éveillées, la logique de sélection prend celle avec le plus petit numéro. Elle porte le nom de '''sélection par position''', sous-entendu position dans la fenêtre d'instruction. Vous l'avez peut-être deviné, mais la logique de sélection est alors un encodeur à priorité. Le circuit de sélection ne se résume donc pas seulement à un encodeur à priorité, mais c'est le circuit central. L'avantage d'une telle méthode de sélection est qu'elle est simple à implémenter : un encodeur à priorité est un circuit connu, facile à implémenter. Mais on remarque un défaut : un encodeur est un circuit assez rapide, mais qui utilise beaucoup de transistors, beaucoup de portes logiques, surtout si on veut qu'il soit rapide. Ce qui explique que la logique de sélection ait son propre étage de pipeline rien que pour elle. La seconde méthode s'appelle la '''sélection par âge''', au nom assez transparent. L'idée est de privilégier l'émission de l'instruction la plus ancienne. Elle demande que la fenêtre d'instruction trie les micro-opérations par ordre d'insertion dans la fenêtre d'instruction, ce qui en fait une pseudo-FIFO. Le tri est partiel, car les instructions peuvent sortir de la fenêtre d’instruction à tout moment. Compacter la fenêtre d'instruction, à savoir regrouper toutes les entrées valides est une idée, mais elle est compliquée à implémenter. Aussi, elles préfèrent encoder des informations sur l'ordre d'émission dans chaque entrée. L'encodeur à priorité doit alors travailler non pas sur des nombres entiers liés à l'ordre d'insertion dans la pseudo-FIFO. Elle est encore plus gourmande en circuits que la méthode précédente. Les processeurs haute performance utilisent souvent des méthodes hybrides. Par exemple, les processeurs AMD de microarchitecture Bulldozer utilisaient une méthode intermédiaire. Ils utilisaient une fenêtre d'instruction couplée à un encodeur à priorité pour la sélection par position, mais complémentaient le tout avec une unité qui mémorisait l'instruction la plus ancienne dans la fenêtre d’instruction. Le mécanisme de sélection par âge était utilisé en priorité. Mais si l'instruction la plus ancienne n'était pas prête, le processeur basculait sur le mécanisme de sélection par position. ===La compaction des fenêtres d'instruction=== À chaque cycle, les instructions décodées sont ajoutées dans la fenêtre d'instruction, dans des entrées vides. Vu que les instructions quittent celle-ci dans le désordre, ces vides sont dispersés dans la fenêtre d'instruction, ce qui pose problème pour déterminer où placer les nouvelles instructions. La solution la plus triviale consiste à conserver une liste des vides, mise à jour à chaque insertion ou émission d'instruction. Une autre solution consiste à éliminer les vides en compactant la fenêtre d'instruction à chaque cycle d'horloge. Des circuits se chargent de détecter les vides et de regrouper les instructions en un unique bloc. Il faut signaler que certains processeurs arrivent à se passer de cette étape de compactage, mais au prix de fenêtres d'instruction nettement plus complexes. Autre problème : quand il faut choisir quelle instruction émettre, il y a toujours plusieurs candidats. Si on choisit mal, des instructions restent en attente trop longtemps parce que d'autres instructions plus jeunes leur passent devant. Pour éviter cela, les instructions les plus vielles, les plus anciennes, sont prioritaires. Pour cela, on peut utiliser une FIFO un peu spéciale pour la fenêtre d'instruction. Si les ajouts d'instruction se font dans l'ordre, les instructions ne quittent pas forcément la fenêtre d'instruction dans l'ordre imposé par une FIFO : les instructions restent triées dans leur ordre d'ajout, même s'il y a des vides entre elles. Dans ces conditions, il est préférable que le compactage conserve l'ordre FIFO des instructions. Dans ces conditions, l'instruction la plus ancienne est celle qui est située à l'adresse la plus faible : le circuit de sélection peut donc être fabriqué avec des encodeurs, et est relativement simple. ==Les fenêtres d'instruction basées sur une matrice de dépendances== L'implémentation la plus simple étend le fonctionnement d'un pipeline dynamique usuel. Rappelez-vous le chapitre sur les pipelines dynamiques. Nous avions vu que de tels pipelines émettaient une instruction par cycle, quitte à émettre des bulles de pipeline en cas de dépendance bloquante. Et il est possible d'améliorer leur unité d'émission pour qu'elle soit compatible avec l'exécution dans le désordre. ===Rappels sur le registre de réservation/disponibilité=== L'émission d'une instruction est gouvernée par un ''registre de réservation'' qui indique quels registres sont réservés par une instruction, et ceux qui sont libres. Un registre réservé est un registre qui sera écrit par une instruction en cours d'exécution, mais qui n'a pas encore écrit son résultat. Les instructions candidates doivent avoir leurs opérandes dans des registres libres. Sinon, c'est signe que leurs opérandes sont réservés en écriture, donc pas encore écrites, donc pas disponibles. Si une instruction candidate veut lire ce registre, c'est signe qu'il y a une dépendance RAW : elle veut lire un registre réservé, qui est destiné à être écrit par une instruction en vol. Si elle veut écrire, c'est signe qu'elle veut écrire dans un registre où une autre instruction veut écrire : c'est une dépendance WAW. Dans les deux cas, l'instruction n'est pas émise. Le registre de réservation encode les registres réservés comme suit : chaque bit est associé à un registre. Le bit numéro 0 est associé au registre numéro 0, le bit numéro 1 au registre numéro 1, etc. Là, En clair, les numéros de registres réservés sont encodés en représentation non pas binaire, mais en représentation ''one-hot'' (vue au premier chapitre). {|class="wikitable" |+ Registre de réservation |- ! Registre 7 !! Registre 6 !! Registre 5 !! Registre 4 !! Registre 3 !! Registre 2 !! Registre 1 !! Registre 0 |- | 0 || 0 || 1 || 0 || 0 || 1 || 0 || 0 |} Avant d'émettre une instruction, l'unité d'émission extrait les registres opérande/destination et les convertis dans la même représentation que le registre de réservation, à savoir en représentation ''one-hot''. Le circuit de traduction binaire vers ''one-hot'' est, pour rappel, un simple décodeur. Puis, on fait un OU logique entre les sorties des décodeurs. Le résultat est un masque qui indique quels registres sont lus par l'instruction, encodé en représentation ''one-hot''. Appelons-le le '''masque d'opérandes'''. Le masque est alors comparé au registre de réservation pour vérifier si l'instruction peut être émise. [[File:Unité d'émission simple, dans l'ordre.png|centre|vignette|upright=2|Unité d'émission simple, dans l'ordre]] Si l'émission est autorisée, le registre de réservation est là aussi mis à jour. Le registre de réservation est aussi mis à jour dès qu'une instruction enregistre son résultat dans les registres, ou alors dès qu'il est disponible pour le contournement. Le bit associé au registre repasse alors à 0 (ou à 1). Sans contournement, la mise à jour se fait alors à la toute fin de l'instruction, quand elle se termine, lors de la dernière étape d'enregistrement, à la fin de son pipeline. Avec, elle se fait quand l'instruction quitte l'unité de calcul. ===L'extension à l'exécution dans le désordre : l'éveil par matrice de bits=== La différence entre un pipeline dynamique et l'exécution dans le désordre est que l'on passe d'une instruction à émettre à plusieurs. Plusieurs instructions sont mises en attente dans une fenêtre d’instruction, et y attendent leur tour. L'idée est alors d'envoyer le registre de disponibilité à toutes les entrées, à toutes les instructions en attente. Ainsi, on sait quelles sont les instructions qui peuvent s'exécuter et celles qui ne le peuvent pas. L'implémentation est assez simple, elle ressemble beaucoup à l'implémentation d'un pipeline dynamique simple, si ce n'est que des circuits sont dupliqués. L'implémentation utilise des fenêtres d'instruction légèrement différentes de celles introduites plus haut. Elles n'utilisent notamment pas de bits de disponibilité, mais autre chose. Lorsqu'une instruction est ajoutée à la fenêtre d'instruction, le masque de disponibilité des opérandes est stocké dans la fenêtre d'instruction. A chaque cycle, le registre de disponibilité est envoyé à toutes les entrées, et est comparé avec tous les masques de disponibilité des opérandes. Si une comparaison renvoie un 1, alors l'instruction de l'entrée est une instruction candidate à l'émission. [[File:Unité d'émission dans le désordre basée sur un registre de disponibilité.png|centre|vignette|upright=2.5|Unité d'émission dans le désordre basée sur un registre de disponibilité]] L'ensemble est implémenté avec l'aide d'une '''matrice de bits''', où chaque ligne correspond à une entrée et chaque colonne à un registre. À chaque croisement entre une ligne et une colonne, on trouve un bit. Si le bit de la ligne n et de la colonne m est à 1, cela veut dire : l'instruction dans l'entrée n a besoin de lire le registre m. S’il est à 0, alors cela veut dire que l'instruction stockée dans la ligne n'a pas besoin de la donnée dans le registre m. [[File:Planificateur à matrice de bits.jpg|centre|vignette|upright=2|Planificateur à matrice de bits.]] Lorsqu'une instruction réserve une entrée, elle initialise la ligne en fonction des registres qu'elle souhaite lire. Pour vérifier si une instruction a ses opérandes prêts, le processeur compare le registre de disponibilité à la ligne associée à l'instruction/entrée. A chaque intersection ligne-colonne, se trouve un comparateur de 1 bit, qui détecte si le registre est demandé et disponible. Les résultats de cette porte sont ensuite envoyés à une porte ET, qui fait le gros du travail. [[File:Logique de détection de la disponibilité d'une instruction.jpg|centre|vignette|upright=2|Logique de détection de la disponibilité d'une instruction.]] ==Les fenêtres d'instruction basées sur une mémoire associative== Les processeurs modernes utilisent une mémoire associative pour la fenêtre d'instruction. Les mémoires associatives ont été abordées il y a quelques chapitres, mais faisons quelques rappels. Les mémoires associatives servent à accélérer la recherche de données dans un ensemble. Or, une fenêtre d'instruction vérifie régulièrement si chaque entrée est prête. Il s'agit d'un processus de recherche d'une instruction qui respecte une condition bien précise dans la mémoire, ce qui fait que les mémoires associatives sont donc tout indiquées. Comme vous le savez, les signaux de commande d'une instruction sont propagés avec celle-ci dans le pipeline, le nom du registre de destination ne faisant pas exception. Le nom de registre est envoyé à la fenêtre d'instruction lors de l'écriture du résultat dans les registres. S'il y a correspondance, l'opérande est disponible et son bit de disponibilité est mis à 1. On peut adapter cette méthode pour tenir compte du contournement assez simplement. [[File:Détection des dépendances par propagation du registre de destination.png|centre|vignette|upright=2|Détection des dépendances par propagation du registre de destination.]] En conséquence, le circuit de détection des dépendances est constitué d'un grand nombre de comparateurs : un par champ « nom de registre » dans chaque entrée. La logique d'éveil/''wake up'' regroupe tous les comparateurs, la logique de sélection est un circuit situé en-dehors de la mémoire associative. Les entrées sont dans la mémoire associative elle-même. [[File:Gestion des bits de validité.png|centre|vignette|upright=2|Gestion des bits de validité.]] L'implémentation la plus simple est celle du schéma précédent, où on utilise une mémoire associative unique. Une version plus élaborée sépare la fenêtre d'instruction en deux parties : une mémoire qui mémorise les registres des opérandes, une autre mémoire pour le reste. La mémoire pour les registres opérandes est la mémoire associative proprement dite, c'est elle qui est associée aux comparateurs, à la logique de ''wake-up''/réveil, etc. Par contre, l'autre mémoire est une mémoire RAM simplifiée, qui mémorise les informations qui n'ont pas besoin des comparateurs. L'opcode de l'instruction est là-dedans, par exemple. La fenêtre d'instruction est donc une sorte de mémoire associative améliorée. Il se trouve que c'est aussi le cas du ROB. Et il est possible de fusionner le tampon de ré-ordonnancement avec la fenêtre d'instruction dans une structure unique. La différence avec une fenêtre d’instruction normale est que les entrées sont libérées non pas quand l'instruction est exécutée/émise, mais quand elle termine son exécution et quitte le ROB. La fenêtre d'instruction incorpore des bits dans chaque entrée, pour savoir si la µops associée a été émise et est en cours de traitement dans les ALUs. La méthode a notamment été utilisée sur les processeurs d'architecture K6 d'AMD. Le tout donnait une structure appelée le '''DRIS''' (''deferred scheduling register renaming instruction shelf''). Les processeurs PA 8000 de HP étaient aussi vraisemblabment dans ce cas, aussi. ===Les optimisations de la consommation d'énergie : la désactivation des portions inutilisées=== Le problème avec des fenêtres d'instruction de ce type est leur forte consommation énergétique, ainsi que le grand nombre de portes logiques utilisées, qui deviennent prohibitifs pour des fenêtres d'instruction un peu grosses. Pour résoudre ce problème, certains ont optimisé les comparateurs. D'autres ont tenté de profiter du fait que la majorité des bits dans les entrées sont composés de zéros. Bref, les optimisations purement matérielles sont légion. Une première solution est de désactiver les entrées qui sont inutilisées, vides, sans instruction. Pour cela, on fait précéder les comparateurs par un circuit qui les connecte ou déconnecte des lignes de bit. Le circuit est commandé par le bit ''empty'' qui indique si une entrée est vide ou non. L'avantage est que la consommation d'énergie de la fenêtre d'instruction devient alors proportionnelle au nombre d'entrées non-vides, et non au nombre d'entrées total. Du moins, en apparence, les entrées non-utilisées doivent quand même être alimentées pour fonctionner, mais l'activité de comparaison disparait dans les entrées vides. Il est possible d'étendre cette technique aux entrées dont les opérandes sont prêts. Les gains sont généralement assez bons, avec une réduction de consommation variant entre 30 et 50%, avec une implémentation très simple et très économe en circuits. Une autre solution, assez simple à mettre en place, consiste à désactiver une partie de la fenêtre d'instruction sin elle est inutilisée. Pour cela, il faut segmenter la fenêtre d'instruction avec la technique du ''wire partitionning''. Pour rappel, une fenêtre d'instruction est une mémoire associative. Et comme toute mémoire associative, elle contient des fils, les lignes de bit, qui relient les entrées/sorties à toutes les cellules mémoire. Plus une ligne de bit est longue, plus elle consomme d'énergie et plus le temps de lecture/écriture est long. L'idée est de segmenter les lignes de bits en plaçant des répéteurs qui recopient la tension d'un segment au suivant. Les répéteurs sont des tampons trois-états, ce qui permet de déconnecter les portions inutilisées de la ligne de bit. Ce faisant, la fenêtre d'instruction est découpée en segments, qui peuvent être désactivés si besoin. S'il y a peu d'instructions chargées dans la fenêtre d'instruction, les portions inutilisées sont désactivées. La technique marche d'autan mieux si les instructions sont compactées au début de la fenêtre d'instruction. [[File:Wire partitionning.png|centre|vignette|upright=2|Wire partitionning]] Tout le problème est de savoir quelles portions désactiver. La technique est assez simple si la fenêtre d'instruction est compactée, à savoir si toutes les instructions sont régulièrement regroupées au début de la mémoire CAM. Mais même avec cette optimisation, la décision de désactiver une portion de la fenêtre d'instruction n'est pas à prendre à la légère. Il ne faut pas désactiver une portion contenant des instructions pouvant être émise sous peu. La décision dépend de paramètres variés : proportion d'entrée vides, quantité d'entrées récemment activées/désactivées récemment, présences d'entrées avec un ''match'' d'opérandes récent, etc. Il est important de préciser que les techniques en question fonctionnent aussi sur les autres types de fenêtre d'instruction, qui ne sont pas basées sur des mémoires associatives. Nous allons voir celles-ci dans la suite du chapitre, mais gardez à l'esprit que ces optimisations, à savoir désactiver les entrées vides/prêts et partitionner la fenêtre d'instruction, sont des optimisations générales qui marchent avec presque tout. ===L'ajout d'une FIFO pour les instructions déjà prêtes à l'émission=== D'autres techniques permettent de réduire aussi bien le cout en circuits que la consommation d'énergie de la fenêtre d'instruction. L'idée est d'utiliser une mémoire associative quand elle est réellement nécessaire, mais d'utiliser une fenêtre d'instruction "normale" dès que possible. La méthode la plus simple tient compte du fait que certaines µopsont déjà toutes leurs opérandes de disponibles à l'émission, mais doivent quand même être mises en attente, parce que l'ALU adéquate est occupée, parce que des dépendances WAW/WAR sont encore là, ou pour tout autre raison. Dans ce cas, elles sont mises en attente non pas dans la fenêtre d'instruction, mais dans une mémoire FIFO toute simple. L'idée est qu'au lieu d'avoir une énorme mémoire associative pour la fenêtre d'instruction, on déplace quelques entrées dans une petite FIFO annexe. Le résultat est un gain d'énergie et de circuits, au prix d'une perte de performance mineure. La perte de performance en question se manifeste si aucune instruction n'a ses opérandes de prêtes à l'émission : le programme n'utilise pas la FIFO et voit alors une fenêtre d'instruction plus petite. Une amélioration de cette technique tient compte du fait que certaines instructions sont dans un cas intermédiaire. Elles ont déjà un opérande de prête lors de l'émission, mais pas l'autre. Le nombre d'opérandes varie suivant l’instruction : certaines n'ont besoin que d'un seul opérande. De plus, il arrive qu'une opération tout juste décodée ait déjà un ou plusieurs de ses opérandes de prêts. Cette constatation permet d'éviter d'utiliser des comparateurs pour les opérandes déjà prêts. Par exemple, on peut parfaitement utiliser trois fenêtres d'instruction : * une pour les instructions dont tous les opérandes sont prêts, mais qui sont quand même mises en attente, sans comparateur ; * une pour les instructions dont un seul opérande manque, qui n'utilise qu'un comparateur par entrée ; * une pour les instructions dont deux opérandes manquent à l'appel, qui utilise deux comparateurs par entrée. C'est beaucoup plus économique que d'utiliser une seule grosse fenêtre d'instruction qui contiendrait autant d'entrées que les trois précédentes réunies, avec deux comparateurs par entrée. Certains sont même allés plus loin, et ont proposé de supprimer la fenêtre d'instruction avec deux opérandes par entrée. Les instructions dont deux opérandes sont inconnus au décodage sont stockées dans la fenêtre d'instruction pour instructions avec un comparateur par entrée. Un circuit de prédiction se charge alors de prédire l'opérande manquant, cette prédiction étant vérifiée plus loin dans le pipeline. Il serait cependant étonnant qu'une telle proposition ait donné lieu à la moindre implémentation réelle. ===Les optimisations de la consommation d'énergie avancées=== D'autres chercheurs ont conservé une fenêtre d'instruction unique, avec autant de comparateurs par entrée qu'il y a d'opérandes possibles par instruction. Simplement, le processus de détection des opérandes prêts est légèrement ralenti : on ne vérifie qu'un opérande par cycle. Pour vérifier les deux opérandes d'une entrée, on doit attendre deux cycles. Enfin, certains chercheurs ont proposé des fenêtres d'instruction segmentées. Les instructions circulent à chaque cycle d'un segment vers le suivant : en conséquence, certains segments conservent les instructions les plus anciennes, un autre les instructions les plus jeunes, etc. Seul le denier segment, celui qui contient les instructions les plus vielles, peut émettre une instruction : la détection des opérandes se fait seulement dans le dernier segment, qui contient les instructions les plus anciennes. On économise ainsi beaucoup de comparateurs. Certains chercheurs ont tenté de pipeliner l'étape de sélection des opérandes, ainsi que l'étage d'arbitrage. Mais en faisant cela, il faut plusieurs cycles pour détecter qu'une instruction a ses opérandes prêts, ce qui pose problème face à de nombreuses dépendances RAW. Pour éviter de trop perdre en performances, certains chercheurs ont décidé d'utiliser des techniques pour prédire quelles seront les instructions dont les opérandes seront bientôt prêts. Si détecter qu'une instruction est prête prend n cycles, le processeur devra tenter de prédire la future disponibilité des opérandes n cycles en avance pour obtenir des performances optimales. ===Remplacer la mémoire associative par une RAM=== Une autre optimisation possible est de remplacer la fenêtre d'instruction par une mémoire RAM, dont chaque mot mémoire correspondrait à une entrée. Une telle optimisation permet en théorie de se passer des comparateurs associés à chaque entrée, mais au prix de l'ajout de circuits annexes potentiellement couteux. La première de ces techniques, la '''recherche directe par étiquette''' (direct tag search) fut créée par Weiss et son collègue Smith. Ils cherchaient à améliorer l'algorithme de Tomasulo, un algorithme qu'on expliquera dans quelques chapitres. Rappelons que chaque instruction produit un résultat, qui devra être rapatrié dans une ou plusieurs entrées de la fenêtre d'instruction. L'optimisation de la recherche directe par étiquette fonctionne dans le cas où le résultat de l'instruction n'est utilisé que par une seule entrée, et pas plusieurs. Le principe est simple : chaque champ « opérande » d'une entrée est adressable via le nom de registre de cet opérande. Pour faire le lien entre entrée et nom de registre, la recherche directe par étiquette ajoute une table de correspondances matérielle, une mémoire RAM qui mémorise les adresses des champs « opérande » des entrées. Les adresses envoyées dans cette mémoire sont les noms de registres des résultats. Lors de l'émission, la table de correspondances est mise à jour. Les numéros des champs « opérande » réservés lors de l'émission sont mémorisés dans les mots mémoire qui correspondent aux deux registres sources. Toutefois, une petite vérification est faite lors de l'émission : s'il y a déjà une correspondance dans la table pour un registre source, alors une autre instruction compte lire ce registre. Pour éviter d'écraser les données de l'instruction précédente dans la table de correspondances, l'émission de l'instruction est bloquée. [[File:Recherche directe par étiquette.png|centre|vignette|upright=2|Recherche directe par étiquette.]] ==Les fenêtres d’instruction avec préplanification== Avec la '''préplanification''' (''prescheduling''), la fenêtre d’instruction est composée de mémoires FIFO dans lesquelles les instructions sont triées dans l'ordre d'émission. Il n'y a pas de logique d’émission proprement dite, celle-ci se bornant à vérifier si l'instruction située au début de la FIFO peut s’exécuter. Par contre, le préplanificateur détecte les dépendances et en déduit où insérer les instructions dans le tampon d'émission, à l'endroit le plus adéquat. [[File:Préplanification.jpg|centre|vignette|upright=2|Préplanification.]] ===L'usage de FIFO multiples=== La technique de préplanification la plus simple utilise plusieurs FIFO. Quand une instruction a une dépendance avec une autre instruction, les deux sont placées dans la même FIFO. Pour cela, le préplanificateur détecte les chaines d'instructions dépendantes, et place les instructions dans la FIFO adéquate. A chaque cycle, l'unité d'émission lit une micro-opération dans chaque FIFO et vérifie si elle peut l'émettre. Si la micro-opération n'a pas ses opérandes disponibles, ou qu'une dépendance structurelle survient, alors la FIFO est bloquée. La micro-opération attend que la dépendance soit résolue, bloquant toutes les instructions précédentes. Mais les autres FIFO ne sont pas bloquées, laissant de la marge de manœuvre. [[File:Préplanification par FIFO multiples.png|centre|vignette|upright=1.5|Préplanification par FIFO multiples.]] ===La technique du tampon trié=== La technique du '''tampon trié''' trie les instructions selon le temps d'attente avant leur exécution. Les instructions qui sont censées s’exécuter bientôt sont insérées au tout début de la FIFO, tandis que les instructions qui s’exécuteront dans un long moment sont insérées vers la fin. Là encore, l'unité d'émission lit une micro-opération dans la FIFO, et détermine si elle peut être émise. Si une dépendance survient, l'émission est retardée, et la FIFO est bloquée. [[File:Préplanification par tampon trié.png|centre|vignette|upright=1.5|Préplanification par tampon trié.]] La technique a cependant quelques problèmes assez importants. Le premier problème est que la FIFO est bloquée lorsqu'une micro-opération ne peut être émise. Le second problème est que le temps avant exécution n'est pas toujours connu, notamment pour les instructions d'accès mémoire. Et cela se répercute sur les instructions dépendantes de celles-ci. Pour résoudre ce genre de problèmes, l'usage d'un pipeline à ''replay'' est possible, et est même l'une des meilleures solutions possible, malgré ses défauts. L'idée est que les lectures sont pré-planifiées en supposant qu'elles font un succès de cache L1. Si la prédiction est fausse, la lecture est ré-exécutée plusieurs cycles plus tard, en supposant qu'elle fait un succès dans le cache L2, et ainsi de suite. Elle est alors ré-insérée dans la FIFO, elle est pré-planifiée une seconde fois. Il en est de même si une micro-opération ne peut pas être émise : il suffit de la réinsérer dans la FIFO au bon endroit, en attendant que ses dépendances soient résolues. Ainsi, l'instruction fautive ne bloque pas la fenêtre d’instruction, et retente sa chance autant de fois qu'il le faut. [[File:Préplanification par fenêtre d’instruction scorebarodée.png|centre|vignette|upright=1.5|Préplanification par fenêtre d’instruction scorebarodée.]] Une autre solution utilise deux fenêtres d’instruction : une FIFO gérée par la préplanification, et une vraie fenêtre d'instruction pour les instructions dont le temps d'attente ne peut pas être déterminé. Il est possible de mettre cette dernière avant la préplanification, afin de gérer les temps d'attente des instructions d'accès mémoire. Quand le temps d'attente d'une lecture devient connu, ses instructions dépendantes sont gérées avec préplanification. [[File:Préplanification avec fenêtre d’instruction.png|centre|vignette|upright=2.5|Préplanification avec fenêtre d’instruction.]] ===Les fenêtres d'instruction avec allocation temporelle statique=== L''''allocation temporelle statique''' correspond à une technique utilisée sur les processeurs Cuzco de l'entreprise Condor. La technique en question a été présenté en 2025, mais des idées similaires ont été présentées dans la littérature académique. Elle ressemble beaucoup aux techniques de pré-planification, avec cependant quelques différences. L'idée est simple : le processeur dispose de plusieurs fenêtres d'instruction, qui mettent en attente les micro-opérations. Lors de l'étape de renommage de registres, le processeur détermine dans combien de cycles d'horloge la micro-opération sera prête pour exécution. La micro-opération est alors mise en attente durant ce nombre de cycles, dans les fenêtres d'instruction, puis est émise une fois ce nombre de cycles écoulés. Ce faisant, les fenêtres d'instruction n'ont pas besoin de détecter la disponibilité des opérandes à chaque cycle, pour chaque micro-opération en attente. Le ''timing'' de l'émission des micro-opérations est décidé à l'avance. L'implémentation exacte n'est pas connue, mais plusieurs solutions sont imaginables. Par exemple, la fenêtre d'instruction peut simplement être composée de plusieurs mémoires de petite taille, chacune contenant les micro-opérations destinées à être exécutées dans N cycles, N étant différent pour chaque mémoire. Une autre solution, plus réaliste, utilise une fenêtre d'instruction dans laquelle la micro-opération est couplée à des champs pour les opérandes, et un champ compteur. Le champ compteur est initialisé avec le nombre de cycles à attendre, et est décrémenté à chaque cycle d'horloge. Quand il atteint zéro, la micro-opération est émise. Vous remarquerez que la méthode ne marche que si toutes les micro-opérations prennent un nombre fixe de cycles d'horloge. Et autant c'est le cas pour les micro-opérations arithmétiques ou logiques, autant les accès mémoire ne rentrent pas dans ce cadre. En théorie, on ne sait pas combien de temps prendra un accès mémoire. Et cette incertitude se répercute sur les instructions dépendantes d'un accès mémoire. Pour éviter cela, le processeur réutilise un pipeline à ''replay'' tel que vu dans le chapitre précédent. L'unité de renommage de registre suppose que tout accès mémoire fait un succès de cache L1, et décide des ''timings'' d'émission sous cette hypothèse. Si une lecture subit un défaut de cache, elle est ré-exécutée, de même que toutes les instructions dépendantes. Pour cela, le registre de destination de la lecture est marqué comme invalide, grâce à un bit spécifique attaché au registre. Toute instruction qui lit un opérande invalide est elle aussi ré-executée de zéro. Pour simplifier, l'unité d'émission ressemble à une unité d'émission dans l'ordre, avec un registre de disponibilité, qu'on aurait amélioré pour aller au-delà de la simple détection des dépendances d'instruction. Pour déterminer les ''timings'' d'émission, à savoir quand émettre une micro-opération, le processeur utilise une unité d'émission à deux étages. Le premier étage est appelé le ''register scoreboard'', le second étage est appelé la ''Time Ressource Matrix''. Les deux étages communiquent entre eux, comme on va le voir, et leurs noms donnent une idée de ce qu'ils font. Le premier étage gère les dépendances de registres, le second gère les dépendances structurelles. Le premier étage est un registre de disponibilité amélioré, qui gère les dépendances de registre. Cet étage sait quand tel registre sera écrit, et donc que l'opérande écrit dedans sera disponible à partir de tel cycle d'horloge. Il le sait car l'étage suivant l'aura prévenu, mais laissons cela de côté pour le moment. Quand une micro-opération rentre dans cet étage, il vérifie les dépendances avec les registres et les micro-opérations antérieures. Vu qu'il sait quand les registres seront disponibles, il peut déterminer quand l'instruction pourra s'exécuter. Par exemple, si une micro-opération lit les deux registres R7 et R15, qui sont disponibles respectivement dans 5 et 7 cycles, le premier étage sait que la micro-opération devra attendre 7 cycles. Mais tout cela ne suffit pas à déterminer quand émettre une micro-opération. En effet, il fait aussi gérer les dépendances structurelles, ce qui est le boulot du second étage. Le second étage utilise pour cela une ''Time Ressource Matrix'', qui mémorise l'occupation de diverses "ressources", pour les 256 cycles d'horloge à venir. Les ressources en question sont les ports de lecture/écriture du banc de registre, les ALUs utilisées, si la micro-opération utilise l'unité mémoire, etc. Le second étage prend en entrée une micro-opération, détermine quelles "ressources" elle utilise, puis regarde leur disponibilité. Elle détecte alors les dépendances structurelles et détermine alors quand peut s'exécuter la micro-opération. Elle peut retarder l'émission de quelques cycles, si une dépendance structurelle est détectée. Une fois sortie du second étage, on sait quand la micro-opération va être émise, à quel cycle précisément. Et vu que la durée de l'instruction est fixe, on sait quand cette micro-opération va se terminer, quand son résultat sera disponible. Cela permet de mettre à jour la ''Time Ressource Matrix'', pour préciser que le port d'écriture sera occupé à tel moment. De plus, cette information est transmise au premier étage, qui sait alors quand est enregistré le résultat dans le registre de destination. C'est comme cela que le premier étage sait quand un registre est disponible : le second étage le prévient, quand il émet une instruction ! La ''Time Ressource Matrix''mémorise l'occupation des "ressources" pour les 256 cycles d'horloge à venir. Cependant, elle ne vérifie pas les dépendances pour les 256 cycles suivants. Quand elle reçoit une micro-opération, elle teste les dépendances structurelles pour seulement les 8 prochains cycles maximum. Si la micro-opération ne peut pas être émise pendant ces 8 cycles, le pipeline est bloqué, un ''pipeline stall'' est émis. Pour être plus précis, vu que le processeur peut décoder 8 micro-opérations en même temps, cela permet de ne consulter que 64 cycles d'horloge sur les 256. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les premiers processeurs Intel | prevText=Les premiers processeurs Intel | next=Le renommage de registres | nextText=Le renommage de registres }} </noinclude> i1qtomrwz62r9jauft2gad7eaptt6t7 773620 773619 2026-09-29T20:58:09Z Mewtow 31375 773620 wikitext text/x-wiki Dans les chapitres précédents, nous avons parlé des techniques dites d''''émission dans l'ordre'''. L'idée est d’exécuter une nouvelle micro-opération à chaque cycle, dans des unités de calcul séparées. Les instructions sont émises consécutivement, mais les instructions s’exécutent en parallèle dans des unités de calcul séparées. Par contre, quand l'unité d'émission ne peut pas émettre une instruction, elle bloque tout le pipeline. Les instructions qui suivent sont elles aussi bloquées, elles doivent attendre leur tour, même si elles sont en capacité de s'exécuter. Les techniques d'exécution dans le désordre que nous allons voir dans ce chapitre corrigent ce point précis. Elles sont dites à '''émission dans le désordre'''. Elles se distinguent des précédentes sur un point précis : quand l'unité d'émission bloque l'émission d'une instruction, les instructions suivantes peuvent poursuivre. L'émission des instructions peut donc se faire dans le désordre, dans le sens où une instruction peut être émise alors qu'une instruction précédente ne l'est pas encore. Mais avant de poursuivre, quelques point niveaux terminologie : * L'émission dans le désordre est un terme parlant et assez précis. Malheureusement, la terminologie la plus utilisée par d''''exécution dans le désordre'''. Et nous utiliserons ce terme dans la suite du cours, histoire de ne pas trop dévier de la nomenclature habituelle. * Nous utiliserons parfois l'abréviation OOO pour parler d'exécution dans le désordre. L'abréviation est celle de ''Out Of Order Excution''. * Nous utiliserons aussi l'abréviation ''µop'' pour parler de micro-opération, ''µops'' au pluriel pour parler de plusieurs micro-opérations, ou des micro-opérations en général. L'exécution dans le désordre ne gère en effet que des µops, elle se situe après l'étape de décodage. Pour décrire comment est implémentée l'émission dans le désordre, il faut commencer par parler des processeurs sans. Les processeurs sans exécution dans le désordre ont une unité d'émission qui bloque tout le pipeline dès qu'une µop ne peut pas être émise. Pour limiter l'impact de ce blocage, quelques rares processeurs incorporent une '''file de micro-opération''', une mémoire FIFO qui met en attente les µops. Vu que c'est une mémoire FIFO, les µops sont émises dans l'ordre, à savoir l'ordre d'ajout, dans l'ordre de décodage. Le schéma ci-dessous illustre une telle file d'attente couplée à un ''scoreboard''. L'exécution dans le désordre améliore la file de µops sur un point : ce n'est plus une mémoire FIFO. Les µops sont insérées dans l'ordre, mais peuvent sortir dans le désordre (être émises dans le désordre). La file de µops devient alors un '''''scheduler''''', terme anglais que je ne compte pas traduire. Un terme équivalent est '''fenêtre d'instruction''', terme traduit directement de l'anglais ''instruction Window''. Terme assez trompeur, car elles mettent en attente des µops, pas des instructions. [[File:Différence file µops et fenêtres instruction.png|centre|vignette|upright=2|Différence file µops et fenêtres instruction]] Le ''scheduler'' émet une µop dès que ses opérandes sont disponibles. Par disponible, on veut dire présent soit dans le réseau de contournement, soit dans les registres. Le ''scheduler'' détecte automatiquement quand les opérandes d'une µop sont disponibles, grâce à une unité d'émission intégrée. L'unité d'émission et le ''scheduler'' sont fusionnés ensemble, dans un seul circuit, mais nous allons dire qu'ils sont conceptuellement séparés pour le moment. A chaque cycle, l'unité d'émission consulte les µops en attente pour détecter lesquelles peuvent s'exécuter. Le ''scheduler'' est spécialement être conçue pour, c'est une sorte de mémoire associative très complexe, comme on le verra dans ce qui suit. [[File:OOO Issue.png|centre|vignette|upright=2.5|Exécution dans le désordre avec une fenêtre d'instruction]] Une fois qu'une µop sort du décodeur d'instructions, elle est ajoutée en parallèle dans la fenêtre d'instruction et le ROB. La raison est que les µops quittent la fenêtre d'instruction dans le désordre, et qu'elles doivent être remises en ordre par la suite. Le ROB s'occupe de cette remise en ordre, mais il a besoin de savoir dans quel ordre les µops sont censées être, et cet ordre est celui du décodage. Aussi, pour remplir le ROB, la seule opportunité est en sortie de l'unité de décodage. Dans le cas où une instruction est décodée en plusieurs micro-opérations, elles sont toutes insérées en même temps dans la fenêtre d'instruction et le ROB, en tenant compte de leur ordre. L'implémentation la plus simple de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Les µops décodées sont accumulées dans le ''scheduler'', où elles attendent leur tour. La fenêtre d'instruction sert donc de file d'attente. Avant de poursuivre, précisons que les micro-opérations mémoire sont à part des autres, pour diverses raisons. Une de ces raisons est que les dépendances de données sont classées en deux types : les dépendances de registre et les dépendances d'adresse. Et les deux sont fondamentalement différentes. Autant on peut détecter les dépendances de registre lors de l'émission, autant c'est plus compliqué avec les dépendances d'adresse. De plus, rappelons que si les lectures peuvent s'exécuter dans le désordre, les écritures doivent s'exécuter dans l'ordre, ou du moins en donner l'illusion. Pour cela, le processeur remet les écritures dans l'ordre avec une sorte de mini-ROB intégré à l'unité mémoire, appelée la file d'écriture. Elle complémente le ROB, qui lui ne gère que les écritures dans les registres, mais les deux collaborent. La file d'écriture envoie une écriture à la mémoire RAM quand le ROB lui dit que c'est bon, les instructions précédentes sont terminées ''dans l'ordre du programme''. Les processeurs modernes ajoutent des techniques d'exécution dans le désordre des accès mémoire, mais nous les verrons dans un chapitre dédié. Elles permettent d'utiliser une fenêtre d'instruction unique, qui mémorise aussi les µops mémoire. Si elles sont mises en place, l'unité mémoire n'a pas besoin de file de µops séparée. L'idée est que les dépendances de registre sont traitées par la fenêtre d'instruction, mais que l'unité mémoire gére les dépendances d'adresse. Les dépendances d'adresse sont gérées par des techniques de ''désambiguation mémoire'', qui auront droit à un chapitre dédié. [[File:Processeur avec exécution dans le désodre des accès mémoire.png|centre|vignette|upright=2|Processeur avec exécution dans le désodre des accès mémoire]] Les processeurs assez anciens n'autorisaient pas d'exécution dans le désordre des accès mémoire. Concrétement, les accs mémoire devaient se faire dans l'ordre, mais les autres µops pouvaient être exécutées dans le désordre. Il s'agit donc d'un ordre entre µops mémoire, pas entre µops mémoire et autres µops. Les µops entières et flottantes pouvaient être exécutées avant une µops mémoire qui est avant elle dans l'ordre du programme, ce n'est pas un problème. Pour garantir l'ordre des µops mémoire, l'unité mémoire est précédée par une file de micro-opérations séparée, pour forcer l'exécution dans l'ordre des accès mémoire. De plus, les µops mémoire ne peuvent pas utiliser la fenêtre d'instruction. Dit autrement, la fenêtre d'instruction ne mémorise pas de µops mémoire. Après le décodage, les µops sont réparties soit dans la file de µops mémoire, soit dans la fenêtre d'instruction. Le décodeur classe les µops suivant que ce sont des µops mémoire ou non, et les envoient à la bonne destination. Dans ce chapitre, on supposera que c'est cette solution qui est utilisée. [[File:Processeur avec émission dans l'ordre des accès mémoire.png|centre|vignette|upright=2|Processeur avec émission dans l'ordre des accès mémoire]] ==L'implémentation d'une fenêtre d'instruction : généralités== Une fenêtre d'instruction est une mémoire qui mémorise des micro-opérations. Elle est cependant plus complexe qu'une mémoire RAM ou qu'une FIFO et ressemble un petit peu à une mémoire cache. Elle dispose d'un port d'écriture et d'un port de lecture, au minimum. Le port d'écriture permet à l'unité de décodage d'insérer une micro-opération dedans, d'ajouter la micro-opération qui vient d'être décodée. Si une instruction machine est décodée en plusieurs micro-opération, deux possibilités. La première est de les insérer un par un, ce qui fait qu'on peut se contenter d'un seul port d'écriture. L'autre possibilité est de les ajouter en même temps, ce qui demande plusieurs ports d'écriture. Le port de lecture sert à émettre une instruction. On part du principe que la fenêtre d'instruction ne peut émettre qu'une seule instruction à la fois, car les processeurs que nous avons vu précédemment sont de ce type. Mais nous verrons dans quelques chapitres qu'il existe des processeurs dits superscalaires, qui sont capables d'émettre plusieurs instructions par cycle. Dans ce cas, la fenêtre d'instruction a un seul port de lecture. Un processeur superscalaire, quant à lui, doit avoir un port de lecture par unité de calcul, ce qui fait beaucoup plus. Les fenêtres d'instruction sont composées d''''entrées''', des mots mémoire qui stockent une instruction. Une instruction réserve une entrée après son décodage et la libère dès qu'elle est envoyée aux unités de calcul. Une entrée contient l'opcode (les signaux de commande à envoyer à l'ALU), le registre de destination du résultat, les registres de chaque opérande, et éventuellement des signaux de commande en plus. De plus, chaque opérande est couplée à un bit de disponibilité, qui indique si elle est disponible. Quand un opérande est écrit dans les registres, le bit de présence correspondant est mis à jour. Enfin, chaque entrée possède un bit ''empty'' qui indique si elle est vide, cette information étant utile pour réserver des entrées. [[File:Entrée d'une station de réservation - sans les tags.png|centre|vignette|upright=3|Entrée d'une fenêtre d'instruction]] ===Les stations de réservation=== Les '''stations de réservation''' sont des fenêtres d'instruction particulières, qui sont capables de mémoriser les opérandes des instructions. Les entrées des stations de réservation sont identiques à celle des autres fenêtres d'instruction, si ce n'est que les opérandes de l'instruction sont enregistrés directement dans des champs séparés. Il y a deux champs, un par opérande, pour stocker l'opérande elle-même, lue depuis les registres ou obtenue via le réseau de contournement. Notons que les champs pour les opérandes viennent en plus des champs pour les noms de registres, encore que les deux peuvent être fusionnés si on veut optimiser le tout. [[File:Entrée d'une station de réservation.png|centre|vignette|upright=3|Entrée d'une station de réservation.]] Précisons que la terminologie n'est pas très fiable. Les termes "fenêtre d'instruction" et "station de réservation" ne regroupent pas du tout la même chose d'un papier de recherche à l'autre, d'un bouquin à l'autre, d'un chercheur à l'autre, d'un ingénieur à l'autre, d'un professeur à l'autre. Le terme initial vient pourtant de l'article original sur l'algorithme de Tomasulo, où il désignait une fenêtre d'instruction associée à une unité de calcul précise. Mais le terme a ensuite été réutilisé, ce qui fait que certains processeurs avec plusieurs unités de calcul sont décrits comme ayant une unique station de réservation. En bref : c'est le bazar ! Mais nous en reparlerons dans le chapitre sur le renommage de registres, car c'est la place idéale pour les aborder. Toujours est-il que j'ai fait le choix de confondre les concepts de fenêtre d'instruction et de station de réservation avec les concepts de '''lecture avant émission''' et de '''lecture après émission'''. La différence entre les deux est que les registres sont lus après émission avec une fenêtre d'instruction, avant avec des stations de réservation. Dans le cas "avant émission", les opérandes sont mémorisés dans la station de réservation. Et cette différence a une influence sur le pipeline du processeur, le banc de registres et tout ce qui s'en suit. Un désavantage de la lecture avant émission est qu'il faut stocker les opérandes après lecture, ici dans les stations de réservation. Mais un avantage est que le banc de registre a besoin de moins de ports de lecture, car une bonne partie des opérandes sont fournies par le système de contournement. Nous verrons cela dans le détail dans le chapitre sur les processeurs superscalaires. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Lecture après émission.]] [[File:Read Before Issue.png|centre|vignette|upright=2.5|Lecture avant émission.]] ===La logique d'éveil et de sélection=== Dans le cas qui va suivre, on suppose que le processeur ne peut émettre qu'une instruction à la fois. Chaque cycle, une instruction est sélectionnée et est envoyée dans le chemin de données, soit à une ALU, soit à une unité d'accès mémoire. La sélection d'une instruction est effectuée par l'unité d'émission, qui est aussi appelée le '''''scheduler'''''. Elle gère la disponibilité des opérandes et la disponibilité des unités de calcul adéquate. Le choix de l'instruction émise doit être le plus pertinent possible, pour des raisons de performances. Pour le premier point, l'unité d'émission détermine quelles instructions sont candidates pour l'émission. Les ''instructions candidates'' sont celles dont tous les opérandes sont prêts. Le processeur contient un circuit qui détecte les instructions candidates : la '''logique d’éveil''' (''wake-up logic''). Une fois que la logique d'éveil a fait son travail, une instruction est choisie pour s’exécuter en fonction de la disponibilité des unités de calcul adéquates. Ce rôle est dévolu à un circuit qu'on appelle la '''logique de sélection''', ou ''select logic''. [[File:Fonctionnement complet de la logique d’émission.jpg|centre|vignette|upright=1.5|Fonctionnement complet de la logique d’émission.]] La logique de sélection doit gérer le fait que les unités de calcul du processeur ne sont pas toutes identiques. Déjà, un processeur a généralement des unités séparées pour les instructions entières et flottantes, des unités spécialisées dans les accès mémoire, parfois des unités spécialisées pour les branchements. Une instruction doit être attribuée à la bonne unité de calcul, on ne doit pas envoyer une instruction entière dans une unité de calcul flottante. De plus, parmi les unités de calcul entières, toutes ne sont pas identiques. Par exemple, il est fréquent d'avoir plusieurs unités de calcul spécialisées dans les opérations simples (additions, soustractions, opérations logiques) avec une unité pour les multiplications/divisions séparées, parfois une unité spécialisée pour les décalages/rotations, etc. Là encore, allouer la bonne instruction à la bonne ALU est complexe. Plus les unités de calcul sont hétérogènes, plus la logique de sélection est compliquée. Les logiques d'éveil comme de sélection sont assez complexes. Comme on le verra plus bas, la logique de sélection la plus simple, qui gère une seule unité de calcul, est basée sur un encodeur à priorité couplé à d'autres circuits. Et pour gérer plusieurs ALUs, il faut mettre des encodeurs en cascade. Le résultat est que même en prenant une logique de sélection simple, elle sera assez lente et gourmande en circuits. Aussi, la logique de sélection met souvent un cycle d'horloge entier pour faire son travail, elle a son propre étage de pipeline attribué. La logique d'éveil est dans le même cas, ce qui fait qu'émettre une micro-opération demande deux cycles d'horloge. Le défaut est que cela rajoute des cycles d'horloges entre la fenêtre d'instruction et l'ALU, ce qui complique la gestion du pipeline. Ces cycles de retard sont à prendre en compte au moment d'émettre les instructions, les ''scheduler'' doit en tenir compte pour des performances optimales. Sans tenir compte de ces cycles de retard, les instructions arrivent en retard de quelques cycles à l'ALU, cycles de retard durant lesquels l'ALU n'a pas fait de calcul et a été sous-utilisée, sans compter que le système de contournement n'est pas utilisé au mieux. Et le problème est encore plus important sur les processeurs avec des stations de réservation, qui utilisent la "lecture après émission" : cela rajoute un cycle d'horloge en plus, un temps de retard en plus. ===La logique d'éveil : l'émission anticipée=== La logique d'éveil doit tenir compte du fait qu'il y a plusieurs étages entre l'émission et l'exécution sur une unité de calcul. Par exemple, un processeur a souvent entre un et à cinq étages entre la file d'attente et les unités de calcul. Il faut lire les registres, gérer le contournement, et cela peut prendre quelques cycles d'horloge. Sur le Pentium 4, on trouve 6 étages entre la fenêtre d’instruction et l'entrée de l'ALU. Si les micro-opérations sont émises quand les opérandes sont disponibles, il y aura un délai de quelques cycles avant qu'elles atteignent l'ALU. Alors qu'idéalement, on souhaiterait que la micro-opération atteigne l'ALU dès que ses opérandes sont disponibles, pour profiter des techniques de contournement. Pour cela, la logique d'éveil émet les instructions quelques cycles en avance pour qu'elles arrivent au bon moment. Il s'agit d'une technique d''''émission anticipée''', dont nous avions parlé dans le chapitre sur le contournement. : Il faut noter que le problème se pose plus avec des fenêtres d'instruction qu'avec des stations de réservation. Les premières ont un étage en plus entre émission et ALU, vu qu'il faut lire des registres après l'émission. L'émission anticipée demande d'émettre un signal d'éveil en avance de quelques cycles, pile au bon moment. Par exemples, si on a deux étages entre l'ALU et l'unité d'émission, le signal de réveil sera généré deux cycles avant que le résultat soit effectivement calculé. L'implémentation varie, mais deux solutions sont possibles. La première est de générer le signal d'éveil dans l'ALU, ce qui n'a de sens que pour les opérations comme les multiplications ou les divisions, qui prennent plusieurs cycles. Une autre technique génère le signal de réveil dans une structure centralisée, spécialisée dans la génération des signaux d'éveil. L'unité de composée d'un registre à décalage par registre. Imaginons qu'une instruction est émise, que cette instruction mette N cycles à s'exécuter, et qu'elle écrive dans un registre de destination. L'unité sélectionne alors le registre à décalage associé au registre de destination, et met le bit numéro N à 1. Le registre décalé d'un cran à chaque cycle. Quand le bit sortant est un 1, alors le signal de validité pour l'opérande est généré. L'émission anticipée marche bien si l'instruction a une durée fixe, connue à l'avance. Et autant c'est le cas pour les instructions arithmétiques et logiques, autant ce n'est pas le cas pour les accès mémoire. Les accès mémoire ont une latence variable : quelques cycles pour un succès de cache, plusieurs dizaines de cycles pour un défaut de cache L1, pas loin de la centaine pour un défaut de cache L2, etc. Et cela pose des problèmes pour l'émission anticipée. L'émission en avance pour les accès mémoire est purement spéculative : le processeur émet des instructions en supposant que la lecture entrainera un succès de cache, quitte à annuler l'instruction en cas de défaut de cache. Mais faire ainsi demande non seulement d'annuler les instructions émises en avance, mais aussi de ne pas retirer les instructions émises en avance de la fenêtre d'instruction. Elles sont émises, mais une copie de sauvegarde est conservée dans la fenêtre d'instruction. Si le processeur détecte un défaut de cache, il peut alors ré-exécuter l'instruction. S'il détecte un succès de cache, les instructions lecture-dépendante sont retirées de la fenêtre d'instruction, la copie de sauvegarde est devenue inutile et est donc jetée. ===La logique de sélection : âge ou position ?=== La logique de sélection est primordiale pour de bonnes performances. Il existe deux méthodes principales pour sélectionner l'instruction à exécuter. La première est la plus simple : elle se base sur lé numéro de l'entrée. En effet, une fenêtre d'instruction est avant tout une sorte de mémoire, un mix entre mémoire associative, mémoire RAM, et FIFO. Et chaque entrée a un numéro, une adresse mémoire. Nous parlerons de numéro dans ce qui suit, car ce sera plus simple, le terme d'adresse mémoire étant peut-être un peu exagéré dans le contexte des fenêtres d'instruction. Toujours est-il que la fenêtre d'instruction est adressable dans le sens où on peut lui envoyer le numéro de l'entrée voulue, et la fenêtre d’instruction renvoie le contenu de l'entrée sur son port de lecture. Et c'est ce que fait la logique de sélection : elle génère le numéro de l'entrée à lire. Le numéro est alors envoyé sur l'entrée d'adresse de la fenêtre d’instruction, et elle fournit la micro-opération associée sur son port de lecture, son '''port d'émission'''. La première méthode de sélection, donc. Elle est basée sur le numéro de l'entrée. Si plusieurs entrées sont éveillées, la logique de sélection prend celle avec le plus petit numéro. Elle porte le nom de '''sélection par position''', sous-entendu position dans la fenêtre d'instruction. Vous l'avez peut-être deviné, mais la logique de sélection est alors un encodeur à priorité. Le circuit de sélection ne se résume donc pas seulement à un encodeur à priorité, mais c'est le circuit central. L'avantage d'une telle méthode de sélection est qu'elle est simple à implémenter : un encodeur à priorité est un circuit connu, facile à implémenter. Mais on remarque un défaut : un encodeur est un circuit assez rapide, mais qui utilise beaucoup de transistors, beaucoup de portes logiques, surtout si on veut qu'il soit rapide. Ce qui explique que la logique de sélection ait son propre étage de pipeline rien que pour elle. La seconde méthode s'appelle la '''sélection par âge''', au nom assez transparent. L'idée est de privilégier l'émission de l'instruction la plus ancienne. Elle demande que la fenêtre d'instruction trie les micro-opérations par ordre d'insertion dans la fenêtre d'instruction, ce qui en fait une pseudo-FIFO. Le tri est partiel, car les instructions peuvent sortir de la fenêtre d’instruction à tout moment. Compacter la fenêtre d'instruction, à savoir regrouper toutes les entrées valides est une idée, mais elle est compliquée à implémenter. Aussi, elles préfèrent encoder des informations sur l'ordre d'émission dans chaque entrée. L'encodeur à priorité doit alors travailler non pas sur des nombres entiers liés à l'ordre d'insertion dans la pseudo-FIFO. Elle est encore plus gourmande en circuits que la méthode précédente. Les processeurs haute performance utilisent souvent des méthodes hybrides. Par exemple, les processeurs AMD de microarchitecture Bulldozer utilisaient une méthode intermédiaire. Ils utilisaient une fenêtre d'instruction couplée à un encodeur à priorité pour la sélection par position, mais complémentaient le tout avec une unité qui mémorisait l'instruction la plus ancienne dans la fenêtre d’instruction. Le mécanisme de sélection par âge était utilisé en priorité. Mais si l'instruction la plus ancienne n'était pas prête, le processeur basculait sur le mécanisme de sélection par position. ===La compaction des fenêtres d'instruction=== À chaque cycle, les instructions décodées sont ajoutées dans la fenêtre d'instruction, dans des entrées vides. Vu que les instructions quittent celle-ci dans le désordre, ces vides sont dispersés dans la fenêtre d'instruction, ce qui pose problème pour déterminer où placer les nouvelles instructions. La solution la plus triviale consiste à conserver une liste des vides, mise à jour à chaque insertion ou émission d'instruction. Une autre solution consiste à éliminer les vides en compactant la fenêtre d'instruction à chaque cycle d'horloge. Des circuits se chargent de détecter les vides et de regrouper les instructions en un unique bloc. Il faut signaler que certains processeurs arrivent à se passer de cette étape de compactage, mais au prix de fenêtres d'instruction nettement plus complexes. Autre problème : quand il faut choisir quelle instruction émettre, il y a toujours plusieurs candidats. Si on choisit mal, des instructions restent en attente trop longtemps parce que d'autres instructions plus jeunes leur passent devant. Pour éviter cela, les instructions les plus vielles, les plus anciennes, sont prioritaires. Pour cela, on peut utiliser une FIFO un peu spéciale pour la fenêtre d'instruction. Si les ajouts d'instruction se font dans l'ordre, les instructions ne quittent pas forcément la fenêtre d'instruction dans l'ordre imposé par une FIFO : les instructions restent triées dans leur ordre d'ajout, même s'il y a des vides entre elles. Dans ces conditions, il est préférable que le compactage conserve l'ordre FIFO des instructions. Dans ces conditions, l'instruction la plus ancienne est celle qui est située à l'adresse la plus faible : le circuit de sélection peut donc être fabriqué avec des encodeurs, et est relativement simple. ==Les fenêtres d'instruction basées sur une matrice de dépendances== L'implémentation la plus simple étend le fonctionnement d'un pipeline dynamique usuel. Rappelez-vous le chapitre sur les pipelines dynamiques. Nous avions vu que de tels pipelines émettaient une instruction par cycle, quitte à émettre des bulles de pipeline en cas de dépendance bloquante. Et il est possible d'améliorer leur unité d'émission pour qu'elle soit compatible avec l'exécution dans le désordre. ===Rappels sur le registre de réservation/disponibilité=== L'émission d'une instruction est gouvernée par un ''registre de réservation'' qui indique quels registres sont réservés par une instruction, et ceux qui sont libres. Un registre réservé est un registre qui sera écrit par une instruction en cours d'exécution, mais qui n'a pas encore écrit son résultat. Les instructions candidates doivent avoir leurs opérandes dans des registres libres. Sinon, c'est signe que leurs opérandes sont réservés en écriture, donc pas encore écrites, donc pas disponibles. Si une instruction candidate veut lire ce registre, c'est signe qu'il y a une dépendance RAW : elle veut lire un registre réservé, qui est destiné à être écrit par une instruction en vol. Si elle veut écrire, c'est signe qu'elle veut écrire dans un registre où une autre instruction veut écrire : c'est une dépendance WAW. Dans les deux cas, l'instruction n'est pas émise. Le registre de réservation encode les registres réservés comme suit : chaque bit est associé à un registre. Le bit numéro 0 est associé au registre numéro 0, le bit numéro 1 au registre numéro 1, etc. Là, En clair, les numéros de registres réservés sont encodés en représentation non pas binaire, mais en représentation ''one-hot'' (vue au premier chapitre). {|class="wikitable" |+ Registre de réservation |- ! Registre 7 !! Registre 6 !! Registre 5 !! Registre 4 !! Registre 3 !! Registre 2 !! Registre 1 !! Registre 0 |- | 0 || 0 || 1 || 0 || 0 || 1 || 0 || 0 |} Avant d'émettre une instruction, l'unité d'émission extrait les registres opérande/destination et les convertis dans la même représentation que le registre de réservation, à savoir en représentation ''one-hot''. Le circuit de traduction binaire vers ''one-hot'' est, pour rappel, un simple décodeur. Puis, on fait un OU logique entre les sorties des décodeurs. Le résultat est un masque qui indique quels registres sont lus par l'instruction, encodé en représentation ''one-hot''. Appelons-le le '''masque d'opérandes'''. Le masque est alors comparé au registre de réservation pour vérifier si l'instruction peut être émise. [[File:Unité d'émission simple, dans l'ordre.png|centre|vignette|upright=2|Unité d'émission simple, dans l'ordre]] Si l'émission est autorisée, le registre de réservation est là aussi mis à jour. Le registre de réservation est aussi mis à jour dès qu'une instruction enregistre son résultat dans les registres, ou alors dès qu'il est disponible pour le contournement. Le bit associé au registre repasse alors à 0 (ou à 1). Sans contournement, la mise à jour se fait alors à la toute fin de l'instruction, quand elle se termine, lors de la dernière étape d'enregistrement, à la fin de son pipeline. Avec, elle se fait quand l'instruction quitte l'unité de calcul. ===L'extension à l'exécution dans le désordre : l'éveil par matrice de bits=== La différence entre un pipeline dynamique et l'exécution dans le désordre est que l'on passe d'une instruction à émettre à plusieurs. Plusieurs instructions sont mises en attente dans une fenêtre d’instruction, et y attendent leur tour. L'idée est alors d'envoyer le registre de disponibilité à toutes les entrées, à toutes les instructions en attente. Ainsi, on sait quelles sont les instructions qui peuvent s'exécuter et celles qui ne le peuvent pas. L'implémentation est assez simple, elle ressemble beaucoup à l'implémentation d'un pipeline dynamique simple, si ce n'est que des circuits sont dupliqués. L'implémentation utilise des fenêtres d'instruction légèrement différentes de celles introduites plus haut. Elles n'utilisent notamment pas de bits de disponibilité, mais autre chose. Lorsqu'une instruction est ajoutée à la fenêtre d'instruction, le masque de disponibilité des opérandes est stocké dans la fenêtre d'instruction. A chaque cycle, le registre de disponibilité est envoyé à toutes les entrées, et est comparé avec tous les masques de disponibilité des opérandes. Si une comparaison renvoie un 1, alors l'instruction de l'entrée est une instruction candidate à l'émission. [[File:Unité d'émission dans le désordre basée sur un registre de disponibilité.png|centre|vignette|upright=2.5|Unité d'émission dans le désordre basée sur un registre de disponibilité]] L'ensemble est implémenté avec l'aide d'une '''matrice de bits''', où chaque ligne correspond à une entrée et chaque colonne à un registre. À chaque croisement entre une ligne et une colonne, on trouve un bit. Si le bit de la ligne n et de la colonne m est à 1, cela veut dire : l'instruction dans l'entrée n a besoin de lire le registre m. S’il est à 0, alors cela veut dire que l'instruction stockée dans la ligne n'a pas besoin de la donnée dans le registre m. [[File:Planificateur à matrice de bits.jpg|centre|vignette|upright=2|Planificateur à matrice de bits.]] Lorsqu'une instruction réserve une entrée, elle initialise la ligne en fonction des registres qu'elle souhaite lire. Pour vérifier si une instruction a ses opérandes prêts, le processeur compare le registre de disponibilité à la ligne associée à l'instruction/entrée. A chaque intersection ligne-colonne, se trouve un comparateur de 1 bit, qui détecte si le registre est demandé et disponible. Les résultats de cette porte sont ensuite envoyés à une porte ET, qui fait le gros du travail. [[File:Logique de détection de la disponibilité d'une instruction.jpg|centre|vignette|upright=2|Logique de détection de la disponibilité d'une instruction.]] ==Les fenêtres d'instruction basées sur une mémoire associative== Les processeurs modernes utilisent une mémoire associative pour la fenêtre d'instruction. Les mémoires associatives ont été abordées il y a quelques chapitres, mais faisons quelques rappels. Les mémoires associatives servent à accélérer la recherche de données dans un ensemble. Or, une fenêtre d'instruction vérifie régulièrement si chaque entrée est prête. Il s'agit d'un processus de recherche d'une instruction qui respecte une condition bien précise dans la mémoire, ce qui fait que les mémoires associatives sont donc tout indiquées. Comme vous le savez, les signaux de commande d'une instruction sont propagés avec celle-ci dans le pipeline, le nom du registre de destination ne faisant pas exception. Le nom de registre est envoyé à la fenêtre d'instruction lors de l'écriture du résultat dans les registres. S'il y a correspondance, l'opérande est disponible et son bit de disponibilité est mis à 1. On peut adapter cette méthode pour tenir compte du contournement assez simplement. [[File:Détection des dépendances par propagation du registre de destination.png|centre|vignette|upright=2|Détection des dépendances par propagation du registre de destination.]] En conséquence, le circuit de détection des dépendances est constitué d'un grand nombre de comparateurs : un par champ « nom de registre » dans chaque entrée. La logique d'éveil/''wake up'' regroupe tous les comparateurs, la logique de sélection est un circuit situé en-dehors de la mémoire associative. Les entrées sont dans la mémoire associative elle-même. [[File:Gestion des bits de validité.png|centre|vignette|upright=2|Gestion des bits de validité.]] L'implémentation la plus simple est celle du schéma précédent, où on utilise une mémoire associative unique. Une version plus élaborée sépare la fenêtre d'instruction en deux parties : une mémoire qui mémorise les registres des opérandes, une autre mémoire pour le reste. La mémoire pour les registres opérandes est la mémoire associative proprement dite, c'est elle qui est associée aux comparateurs, à la logique de ''wake-up''/réveil, etc. Par contre, l'autre mémoire est une mémoire RAM simplifiée, qui mémorise les informations qui n'ont pas besoin des comparateurs. L'opcode de l'instruction est là-dedans, par exemple. La fenêtre d'instruction est donc une sorte de mémoire associative améliorée. Il se trouve que c'est aussi le cas du ROB. Et il est possible de fusionner le tampon de ré-ordonnancement avec la fenêtre d'instruction dans une structure unique. La différence avec une fenêtre d’instruction normale est que les entrées sont libérées non pas quand l'instruction est exécutée/émise, mais quand elle termine son exécution et quitte le ROB. La fenêtre d'instruction incorpore des bits dans chaque entrée, pour savoir si la µops associée a été émise et est en cours de traitement dans les ALUs. La méthode a notamment été utilisée sur les processeurs d'architecture K6 d'AMD. Le tout donnait une structure appelée le '''DRIS''' (''deferred scheduling register renaming instruction shelf''). Les processeurs PA 8000 de HP étaient aussi vraisemblabment dans ce cas, aussi. ===Les optimisations de la consommation d'énergie : la désactivation des portions inutilisées=== Le problème avec des fenêtres d'instruction de ce type est leur forte consommation énergétique, ainsi que le grand nombre de portes logiques utilisées, qui deviennent prohibitifs pour des fenêtres d'instruction un peu grosses. Pour résoudre ce problème, certains ont optimisé les comparateurs. D'autres ont tenté de profiter du fait que la majorité des bits dans les entrées sont composés de zéros. Bref, les optimisations purement matérielles sont légion. Une première solution est de désactiver les entrées qui sont inutilisées, vides, sans instruction. Pour cela, on fait précéder les comparateurs par un circuit qui les connecte ou déconnecte des lignes de bit. Le circuit est commandé par le bit ''empty'' qui indique si une entrée est vide ou non. L'avantage est que la consommation d'énergie de la fenêtre d'instruction devient alors proportionnelle au nombre d'entrées non-vides, et non au nombre d'entrées total. Du moins, en apparence, les entrées non-utilisées doivent quand même être alimentées pour fonctionner, mais l'activité de comparaison disparait dans les entrées vides. Il est possible d'étendre cette technique aux entrées dont les opérandes sont prêts. Les gains sont généralement assez bons, avec une réduction de consommation variant entre 30 et 50%, avec une implémentation très simple et très économe en circuits. Une autre solution, assez simple à mettre en place, consiste à désactiver une partie de la fenêtre d'instruction sin elle est inutilisée. Pour cela, il faut segmenter la fenêtre d'instruction avec la technique du ''wire partitionning''. Pour rappel, une fenêtre d'instruction est une mémoire associative. Et comme toute mémoire associative, elle contient des fils, les lignes de bit, qui relient les entrées/sorties à toutes les cellules mémoire. Plus une ligne de bit est longue, plus elle consomme d'énergie et plus le temps de lecture/écriture est long. L'idée est de segmenter les lignes de bits en plaçant des répéteurs qui recopient la tension d'un segment au suivant. Les répéteurs sont des tampons trois-états, ce qui permet de déconnecter les portions inutilisées de la ligne de bit. Ce faisant, la fenêtre d'instruction est découpée en segments, qui peuvent être désactivés si besoin. S'il y a peu d'instructions chargées dans la fenêtre d'instruction, les portions inutilisées sont désactivées. La technique marche d'autan mieux si les instructions sont compactées au début de la fenêtre d'instruction. [[File:Wire partitionning.png|centre|vignette|upright=2|Wire partitionning]] Tout le problème est de savoir quelles portions désactiver. La technique est assez simple si la fenêtre d'instruction est compactée, à savoir si toutes les instructions sont régulièrement regroupées au début de la mémoire CAM. Mais même avec cette optimisation, la décision de désactiver une portion de la fenêtre d'instruction n'est pas à prendre à la légère. Il ne faut pas désactiver une portion contenant des instructions pouvant être émise sous peu. La décision dépend de paramètres variés : proportion d'entrée vides, quantité d'entrées récemment activées/désactivées récemment, présences d'entrées avec un ''match'' d'opérandes récent, etc. Il est important de préciser que les techniques en question fonctionnent aussi sur les autres types de fenêtre d'instruction, qui ne sont pas basées sur des mémoires associatives. Nous allons voir celles-ci dans la suite du chapitre, mais gardez à l'esprit que ces optimisations, à savoir désactiver les entrées vides/prêts et partitionner la fenêtre d'instruction, sont des optimisations générales qui marchent avec presque tout. ===L'ajout d'une FIFO pour les instructions déjà prêtes à l'émission=== D'autres techniques permettent de réduire aussi bien le cout en circuits que la consommation d'énergie de la fenêtre d'instruction. L'idée est d'utiliser une mémoire associative quand elle est réellement nécessaire, mais d'utiliser une fenêtre d'instruction "normale" dès que possible. La méthode la plus simple tient compte du fait que certaines µopsont déjà toutes leurs opérandes de disponibles à l'émission, mais doivent quand même être mises en attente, parce que l'ALU adéquate est occupée, parce que des dépendances WAW/WAR sont encore là, ou pour tout autre raison. Dans ce cas, elles sont mises en attente non pas dans la fenêtre d'instruction, mais dans une mémoire FIFO toute simple. L'idée est qu'au lieu d'avoir une énorme mémoire associative pour la fenêtre d'instruction, on déplace quelques entrées dans une petite FIFO annexe. Le résultat est un gain d'énergie et de circuits, au prix d'une perte de performance mineure. La perte de performance en question se manifeste si aucune instruction n'a ses opérandes de prêtes à l'émission : le programme n'utilise pas la FIFO et voit alors une fenêtre d'instruction plus petite. Une amélioration de cette technique tient compte du fait que certaines instructions sont dans un cas intermédiaire. Elles ont déjà un opérande de prête lors de l'émission, mais pas l'autre. Le nombre d'opérandes varie suivant l’instruction : certaines n'ont besoin que d'un seul opérande. De plus, il arrive qu'une opération tout juste décodée ait déjà un ou plusieurs de ses opérandes de prêts. Cette constatation permet d'éviter d'utiliser des comparateurs pour les opérandes déjà prêts. Par exemple, on peut parfaitement utiliser trois fenêtres d'instruction : * une pour les instructions dont tous les opérandes sont prêts, mais qui sont quand même mises en attente, sans comparateur ; * une pour les instructions dont un seul opérande manque, qui n'utilise qu'un comparateur par entrée ; * une pour les instructions dont deux opérandes manquent à l'appel, qui utilise deux comparateurs par entrée. C'est beaucoup plus économique que d'utiliser une seule grosse fenêtre d'instruction qui contiendrait autant d'entrées que les trois précédentes réunies, avec deux comparateurs par entrée. Certains sont même allés plus loin, et ont proposé de supprimer la fenêtre d'instruction avec deux opérandes par entrée. Les instructions dont deux opérandes sont inconnus au décodage sont stockées dans la fenêtre d'instruction pour instructions avec un comparateur par entrée. Un circuit de prédiction se charge alors de prédire l'opérande manquant, cette prédiction étant vérifiée plus loin dans le pipeline. Il serait cependant étonnant qu'une telle proposition ait donné lieu à la moindre implémentation réelle. ===Les optimisations de la consommation d'énergie avancées=== D'autres chercheurs ont conservé une fenêtre d'instruction unique, avec autant de comparateurs par entrée qu'il y a d'opérandes possibles par instruction. Simplement, le processus de détection des opérandes prêts est légèrement ralenti : on ne vérifie qu'un opérande par cycle. Pour vérifier les deux opérandes d'une entrée, on doit attendre deux cycles. Enfin, certains chercheurs ont proposé des fenêtres d'instruction segmentées. Les instructions circulent à chaque cycle d'un segment vers le suivant : en conséquence, certains segments conservent les instructions les plus anciennes, un autre les instructions les plus jeunes, etc. Seul le denier segment, celui qui contient les instructions les plus vielles, peut émettre une instruction : la détection des opérandes se fait seulement dans le dernier segment, qui contient les instructions les plus anciennes. On économise ainsi beaucoup de comparateurs. Certains chercheurs ont tenté de pipeliner l'étape de sélection des opérandes, ainsi que l'étage d'arbitrage. Mais en faisant cela, il faut plusieurs cycles pour détecter qu'une instruction a ses opérandes prêts, ce qui pose problème face à de nombreuses dépendances RAW. Pour éviter de trop perdre en performances, certains chercheurs ont décidé d'utiliser des techniques pour prédire quelles seront les instructions dont les opérandes seront bientôt prêts. Si détecter qu'une instruction est prête prend n cycles, le processeur devra tenter de prédire la future disponibilité des opérandes n cycles en avance pour obtenir des performances optimales. ===Remplacer la mémoire associative par une RAM=== Une autre optimisation possible est de remplacer la fenêtre d'instruction par une mémoire RAM, dont chaque mot mémoire correspondrait à une entrée. Une telle optimisation permet en théorie de se passer des comparateurs associés à chaque entrée, mais au prix de l'ajout de circuits annexes potentiellement couteux. La première de ces techniques, la '''recherche directe par étiquette''' (direct tag search) fut créée par Weiss et son collègue Smith. Ils cherchaient à améliorer l'algorithme de Tomasulo, un algorithme qu'on expliquera dans quelques chapitres. Rappelons que chaque instruction produit un résultat, qui devra être rapatrié dans une ou plusieurs entrées de la fenêtre d'instruction. L'optimisation de la recherche directe par étiquette fonctionne dans le cas où le résultat de l'instruction n'est utilisé que par une seule entrée, et pas plusieurs. Le principe est simple : chaque champ « opérande » d'une entrée est adressable via le nom de registre de cet opérande. Pour faire le lien entre entrée et nom de registre, la recherche directe par étiquette ajoute une table de correspondances matérielle, une mémoire RAM qui mémorise les adresses des champs « opérande » des entrées. Les adresses envoyées dans cette mémoire sont les noms de registres des résultats. Lors de l'émission, la table de correspondances est mise à jour. Les numéros des champs « opérande » réservés lors de l'émission sont mémorisés dans les mots mémoire qui correspondent aux deux registres sources. Toutefois, une petite vérification est faite lors de l'émission : s'il y a déjà une correspondance dans la table pour un registre source, alors une autre instruction compte lire ce registre. Pour éviter d'écraser les données de l'instruction précédente dans la table de correspondances, l'émission de l'instruction est bloquée. [[File:Recherche directe par étiquette.png|centre|vignette|upright=2|Recherche directe par étiquette.]] ==Les fenêtres d’instruction avec préplanification== Avec la '''préplanification''' (''prescheduling''), la fenêtre d’instruction est composée de mémoires FIFO dans lesquelles les instructions sont triées dans l'ordre d'émission. Il n'y a pas de logique d’émission proprement dite, celle-ci se bornant à vérifier si l'instruction située au début de la FIFO peut s’exécuter. Par contre, le préplanificateur détecte les dépendances et en déduit où insérer les instructions dans le tampon d'émission, à l'endroit le plus adéquat. [[File:Préplanification.jpg|centre|vignette|upright=2|Préplanification.]] ===L'usage de FIFO multiples=== La technique de préplanification la plus simple utilise plusieurs FIFO. Quand une instruction a une dépendance avec une autre instruction, les deux sont placées dans la même FIFO. Pour cela, le préplanificateur détecte les chaines d'instructions dépendantes, et place les instructions dans la FIFO adéquate. A chaque cycle, l'unité d'émission lit une micro-opération dans chaque FIFO et vérifie si elle peut l'émettre. Si la micro-opération n'a pas ses opérandes disponibles, ou qu'une dépendance structurelle survient, alors la FIFO est bloquée. La micro-opération attend que la dépendance soit résolue, bloquant toutes les instructions précédentes. Mais les autres FIFO ne sont pas bloquées, laissant de la marge de manœuvre. [[File:Préplanification par FIFO multiples.png|centre|vignette|upright=1.5|Préplanification par FIFO multiples.]] ===La technique du tampon trié=== La technique du '''tampon trié''' trie les instructions selon le temps d'attente avant leur exécution. Les instructions qui sont censées s’exécuter bientôt sont insérées au tout début de la FIFO, tandis que les instructions qui s’exécuteront dans un long moment sont insérées vers la fin. Là encore, l'unité d'émission lit une micro-opération dans la FIFO, et détermine si elle peut être émise. Si une dépendance survient, l'émission est retardée, et la FIFO est bloquée. [[File:Préplanification par tampon trié.png|centre|vignette|upright=1.5|Préplanification par tampon trié.]] La technique a cependant quelques problèmes assez importants. Le premier problème est que la FIFO est bloquée lorsqu'une micro-opération ne peut être émise. Le second problème est que le temps avant exécution n'est pas toujours connu, notamment pour les instructions d'accès mémoire. Et cela se répercute sur les instructions dépendantes de celles-ci. Pour résoudre ce genre de problèmes, l'usage d'un pipeline à ''replay'' est possible, et est même l'une des meilleures solutions possible, malgré ses défauts. L'idée est que les lectures sont pré-planifiées en supposant qu'elles font un succès de cache L1. Si la prédiction est fausse, la lecture est ré-exécutée plusieurs cycles plus tard, en supposant qu'elle fait un succès dans le cache L2, et ainsi de suite. Elle est alors ré-insérée dans la FIFO, elle est pré-planifiée une seconde fois. Il en est de même si une micro-opération ne peut pas être émise : il suffit de la réinsérer dans la FIFO au bon endroit, en attendant que ses dépendances soient résolues. Ainsi, l'instruction fautive ne bloque pas la fenêtre d’instruction, et retente sa chance autant de fois qu'il le faut. [[File:Préplanification par fenêtre d’instruction scorebarodée.png|centre|vignette|upright=1.5|Préplanification par fenêtre d’instruction scorebarodée.]] Une autre solution utilise deux fenêtres d’instruction : une FIFO gérée par la préplanification, et une vraie fenêtre d'instruction pour les instructions dont le temps d'attente ne peut pas être déterminé. Il est possible de mettre cette dernière avant la préplanification, afin de gérer les temps d'attente des instructions d'accès mémoire. Quand le temps d'attente d'une lecture devient connu, ses instructions dépendantes sont gérées avec préplanification. [[File:Préplanification avec fenêtre d’instruction.png|centre|vignette|upright=2.5|Préplanification avec fenêtre d’instruction.]] ===Les fenêtres d'instruction avec allocation temporelle statique=== L''''allocation temporelle statique''' correspond à une technique utilisée sur les processeurs Cuzco de l'entreprise Condor. La technique en question a été présenté en 2025, mais des idées similaires ont été présentées dans la littérature académique. Elle ressemble beaucoup aux techniques de pré-planification, avec cependant quelques différences. L'idée est simple : le processeur dispose de plusieurs fenêtres d'instruction, qui mettent en attente les micro-opérations. Lors de l'étape de renommage de registres, le processeur détermine dans combien de cycles d'horloge la micro-opération sera prête pour exécution. La micro-opération est alors mise en attente durant ce nombre de cycles, dans les fenêtres d'instruction, puis est émise une fois ce nombre de cycles écoulés. Ce faisant, les fenêtres d'instruction n'ont pas besoin de détecter la disponibilité des opérandes à chaque cycle, pour chaque micro-opération en attente. Le ''timing'' de l'émission des micro-opérations est décidé à l'avance. L'implémentation exacte n'est pas connue, mais plusieurs solutions sont imaginables. Par exemple, la fenêtre d'instruction peut simplement être composée de plusieurs mémoires de petite taille, chacune contenant les micro-opérations destinées à être exécutées dans N cycles, N étant différent pour chaque mémoire. Une autre solution, plus réaliste, utilise une fenêtre d'instruction dans laquelle la micro-opération est couplée à des champs pour les opérandes, et un champ compteur. Le champ compteur est initialisé avec le nombre de cycles à attendre, et est décrémenté à chaque cycle d'horloge. Quand il atteint zéro, la micro-opération est émise. Vous remarquerez que la méthode ne marche que si toutes les micro-opérations prennent un nombre fixe de cycles d'horloge. Et autant c'est le cas pour les micro-opérations arithmétiques ou logiques, autant les accès mémoire ne rentrent pas dans ce cadre. En théorie, on ne sait pas combien de temps prendra un accès mémoire. Et cette incertitude se répercute sur les instructions dépendantes d'un accès mémoire. Pour éviter cela, le processeur réutilise un pipeline à ''replay'' tel que vu dans le chapitre précédent. L'unité de renommage de registre suppose que tout accès mémoire fait un succès de cache L1, et décide des ''timings'' d'émission sous cette hypothèse. Si une lecture subit un défaut de cache, elle est ré-exécutée, de même que toutes les instructions dépendantes. Pour cela, le registre de destination de la lecture est marqué comme invalide, grâce à un bit spécifique attaché au registre. Toute instruction qui lit un opérande invalide est elle aussi ré-executée de zéro. Pour simplifier, l'unité d'émission ressemble à une unité d'émission dans l'ordre, avec un registre de disponibilité, qu'on aurait amélioré pour aller au-delà de la simple détection des dépendances d'instruction. Pour déterminer les ''timings'' d'émission, à savoir quand émettre une micro-opération, le processeur utilise une unité d'émission à deux étages. Le premier étage est appelé le ''register scoreboard'', le second étage est appelé la ''Time Ressource Matrix''. Les deux étages communiquent entre eux, comme on va le voir, et leurs noms donnent une idée de ce qu'ils font. Le premier étage gère les dépendances de registres, le second gère les dépendances structurelles. Le premier étage est un registre de disponibilité amélioré, qui gère les dépendances de registre. Cet étage sait quand tel registre sera écrit, et donc que l'opérande écrit dedans sera disponible à partir de tel cycle d'horloge. Il le sait car l'étage suivant l'aura prévenu, mais laissons cela de côté pour le moment. Quand une micro-opération rentre dans cet étage, il vérifie les dépendances avec les registres et les micro-opérations antérieures. Vu qu'il sait quand les registres seront disponibles, il peut déterminer quand l'instruction pourra s'exécuter. Par exemple, si une micro-opération lit les deux registres R7 et R15, qui sont disponibles respectivement dans 5 et 7 cycles, le premier étage sait que la micro-opération devra attendre 7 cycles. Mais tout cela ne suffit pas à déterminer quand émettre une micro-opération. En effet, il fait aussi gérer les dépendances structurelles, ce qui est le boulot du second étage. Le second étage utilise pour cela une ''Time Ressource Matrix'', qui mémorise l'occupation de diverses "ressources", pour les 256 cycles d'horloge à venir. Les ressources en question sont les ports de lecture/écriture du banc de registre, les ALUs utilisées, si la micro-opération utilise l'unité mémoire, etc. Le second étage prend en entrée une micro-opération, détermine quelles "ressources" elle utilise, puis regarde leur disponibilité. Elle détecte alors les dépendances structurelles et détermine alors quand peut s'exécuter la micro-opération. Elle peut retarder l'émission de quelques cycles, si une dépendance structurelle est détectée. Une fois sortie du second étage, on sait quand la micro-opération va être émise, à quel cycle précisément. Et vu que la durée de l'instruction est fixe, on sait quand cette micro-opération va se terminer, quand son résultat sera disponible. Cela permet de mettre à jour la ''Time Ressource Matrix'', pour préciser que le port d'écriture sera occupé à tel moment. De plus, cette information est transmise au premier étage, qui sait alors quand est enregistré le résultat dans le registre de destination. C'est comme cela que le premier étage sait quand un registre est disponible : le second étage le prévient, quand il émet une instruction ! La ''Time Ressource Matrix''mémorise l'occupation des "ressources" pour les 256 cycles d'horloge à venir. Cependant, elle ne vérifie pas les dépendances pour les 256 cycles suivants. Quand elle reçoit une micro-opération, elle teste les dépendances structurelles pour seulement les 8 prochains cycles maximum. Si la micro-opération ne peut pas être émise pendant ces 8 cycles, le pipeline est bloqué, un ''pipeline stall'' est émis. Pour être plus précis, vu que le processeur peut décoder 8 micro-opérations en même temps, cela permet de ne consulter que 64 cycles d'horloge sur les 256. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les premiers processeurs Intel | prevText=Les premiers processeurs Intel | next=Le renommage de registres | nextText=Le renommage de registres }} </noinclude> pwbe62t2xt0wipnuhyh4n7y3q3r84se 773621 773620 2026-09-29T20:58:54Z Mewtow 31375 /* L'implémentation d'une fenêtre d'instruction : généralités */ 773621 wikitext text/x-wiki Dans les chapitres précédents, nous avons parlé des techniques dites d''''émission dans l'ordre'''. L'idée est d’exécuter une nouvelle micro-opération à chaque cycle, dans des unités de calcul séparées. Les instructions sont émises consécutivement, mais les instructions s’exécutent en parallèle dans des unités de calcul séparées. Par contre, quand l'unité d'émission ne peut pas émettre une instruction, elle bloque tout le pipeline. Les instructions qui suivent sont elles aussi bloquées, elles doivent attendre leur tour, même si elles sont en capacité de s'exécuter. Les techniques d'exécution dans le désordre que nous allons voir dans ce chapitre corrigent ce point précis. Elles sont dites à '''émission dans le désordre'''. Elles se distinguent des précédentes sur un point précis : quand l'unité d'émission bloque l'émission d'une instruction, les instructions suivantes peuvent poursuivre. L'émission des instructions peut donc se faire dans le désordre, dans le sens où une instruction peut être émise alors qu'une instruction précédente ne l'est pas encore. Mais avant de poursuivre, quelques point niveaux terminologie : * L'émission dans le désordre est un terme parlant et assez précis. Malheureusement, la terminologie la plus utilisée par d''''exécution dans le désordre'''. Et nous utiliserons ce terme dans la suite du cours, histoire de ne pas trop dévier de la nomenclature habituelle. * Nous utiliserons parfois l'abréviation OOO pour parler d'exécution dans le désordre. L'abréviation est celle de ''Out Of Order Excution''. * Nous utiliserons aussi l'abréviation ''µop'' pour parler de micro-opération, ''µops'' au pluriel pour parler de plusieurs micro-opérations, ou des micro-opérations en général. L'exécution dans le désordre ne gère en effet que des µops, elle se situe après l'étape de décodage. Pour décrire comment est implémentée l'émission dans le désordre, il faut commencer par parler des processeurs sans. Les processeurs sans exécution dans le désordre ont une unité d'émission qui bloque tout le pipeline dès qu'une µop ne peut pas être émise. Pour limiter l'impact de ce blocage, quelques rares processeurs incorporent une '''file de micro-opération''', une mémoire FIFO qui met en attente les µops. Vu que c'est une mémoire FIFO, les µops sont émises dans l'ordre, à savoir l'ordre d'ajout, dans l'ordre de décodage. Le schéma ci-dessous illustre une telle file d'attente couplée à un ''scoreboard''. L'exécution dans le désordre améliore la file de µops sur un point : ce n'est plus une mémoire FIFO. Les µops sont insérées dans l'ordre, mais peuvent sortir dans le désordre (être émises dans le désordre). La file de µops devient alors un '''''scheduler''''', terme anglais que je ne compte pas traduire. Un terme équivalent est '''fenêtre d'instruction''', terme traduit directement de l'anglais ''instruction Window''. Terme assez trompeur, car elles mettent en attente des µops, pas des instructions. [[File:Différence file µops et fenêtres instruction.png|centre|vignette|upright=2|Différence file µops et fenêtres instruction]] Le ''scheduler'' émet une µop dès que ses opérandes sont disponibles. Par disponible, on veut dire présent soit dans le réseau de contournement, soit dans les registres. Le ''scheduler'' détecte automatiquement quand les opérandes d'une µop sont disponibles, grâce à une unité d'émission intégrée. L'unité d'émission et le ''scheduler'' sont fusionnés ensemble, dans un seul circuit, mais nous allons dire qu'ils sont conceptuellement séparés pour le moment. A chaque cycle, l'unité d'émission consulte les µops en attente pour détecter lesquelles peuvent s'exécuter. Le ''scheduler'' est spécialement être conçue pour, c'est une sorte de mémoire associative très complexe, comme on le verra dans ce qui suit. [[File:OOO Issue.png|centre|vignette|upright=2.5|Exécution dans le désordre avec une fenêtre d'instruction]] Une fois qu'une µop sort du décodeur d'instructions, elle est ajoutée en parallèle dans la fenêtre d'instruction et le ROB. La raison est que les µops quittent la fenêtre d'instruction dans le désordre, et qu'elles doivent être remises en ordre par la suite. Le ROB s'occupe de cette remise en ordre, mais il a besoin de savoir dans quel ordre les µops sont censées être, et cet ordre est celui du décodage. Aussi, pour remplir le ROB, la seule opportunité est en sortie de l'unité de décodage. Dans le cas où une instruction est décodée en plusieurs micro-opérations, elles sont toutes insérées en même temps dans la fenêtre d'instruction et le ROB, en tenant compte de leur ordre. L'implémentation la plus simple de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Les µops décodées sont accumulées dans le ''scheduler'', où elles attendent leur tour. La fenêtre d'instruction sert donc de file d'attente. Avant de poursuivre, précisons que les micro-opérations mémoire sont à part des autres, pour diverses raisons. Une de ces raisons est que les dépendances de données sont classées en deux types : les dépendances de registre et les dépendances d'adresse. Et les deux sont fondamentalement différentes. Autant on peut détecter les dépendances de registre lors de l'émission, autant c'est plus compliqué avec les dépendances d'adresse. De plus, rappelons que si les lectures peuvent s'exécuter dans le désordre, les écritures doivent s'exécuter dans l'ordre, ou du moins en donner l'illusion. Pour cela, le processeur remet les écritures dans l'ordre avec une sorte de mini-ROB intégré à l'unité mémoire, appelée la file d'écriture. Elle complémente le ROB, qui lui ne gère que les écritures dans les registres, mais les deux collaborent. La file d'écriture envoie une écriture à la mémoire RAM quand le ROB lui dit que c'est bon, les instructions précédentes sont terminées ''dans l'ordre du programme''. Les processeurs modernes ajoutent des techniques d'exécution dans le désordre des accès mémoire, mais nous les verrons dans un chapitre dédié. Elles permettent d'utiliser une fenêtre d'instruction unique, qui mémorise aussi les µops mémoire. Si elles sont mises en place, l'unité mémoire n'a pas besoin de file de µops séparée. L'idée est que les dépendances de registre sont traitées par la fenêtre d'instruction, mais que l'unité mémoire gére les dépendances d'adresse. Les dépendances d'adresse sont gérées par des techniques de ''désambiguation mémoire'', qui auront droit à un chapitre dédié. [[File:Processeur avec exécution dans le désodre des accès mémoire.png|centre|vignette|upright=2|Processeur avec exécution dans le désodre des accès mémoire]] Les processeurs assez anciens n'autorisaient pas d'exécution dans le désordre des accès mémoire. Concrétement, les accs mémoire devaient se faire dans l'ordre, mais les autres µops pouvaient être exécutées dans le désordre. Il s'agit donc d'un ordre entre µops mémoire, pas entre µops mémoire et autres µops. Les µops entières et flottantes pouvaient être exécutées avant une µops mémoire qui est avant elle dans l'ordre du programme, ce n'est pas un problème. Pour garantir l'ordre des µops mémoire, l'unité mémoire est précédée par une file de micro-opérations séparée, pour forcer l'exécution dans l'ordre des accès mémoire. De plus, les µops mémoire ne peuvent pas utiliser la fenêtre d'instruction. Dit autrement, la fenêtre d'instruction ne mémorise pas de µops mémoire. Après le décodage, les µops sont réparties soit dans la file de µops mémoire, soit dans la fenêtre d'instruction. Le décodeur classe les µops suivant que ce sont des µops mémoire ou non, et les envoient à la bonne destination. Dans ce chapitre, on supposera que c'est cette solution qui est utilisée. [[File:Processeur avec émission dans l'ordre des accès mémoire.png|centre|vignette|upright=2|Processeur avec émission dans l'ordre des accès mémoire]] ==L'implémentation d'une fenêtre d'instruction : généralités== Un ''scheduler'' est une mémoire qui mémorise des micro-opérations. Elle est cependant plus complexe qu'une mémoire RAM ou qu'une FIFO et ressemble un petit peu à une mémoire cache. Elle dispose d'un port d'écriture et d'un port de lecture, au minimum. Le port d'écriture permet à l'unité de décodage d'insérer une micro-opération dedans, d'ajouter la micro-opération qui vient d'être décodée. Si une instruction machine est décodée en plusieurs micro-opération, deux possibilités. La première est de les insérer un par un, ce qui fait qu'on peut se contenter d'un seul port d'écriture. L'autre possibilité est de les ajouter en même temps, ce qui demande plusieurs ports d'écriture. Le port de lecture sert à émettre une instruction. On part du principe que la fenêtre d'instruction ne peut émettre qu'une seule instruction à la fois, car les processeurs que nous avons vu précédemment sont de ce type. Mais nous verrons dans quelques chapitres qu'il existe des processeurs dits superscalaires, qui sont capables d'émettre plusieurs instructions par cycle. Dans ce cas, la fenêtre d'instruction a un seul port de lecture. Un processeur superscalaire, quant à lui, doit avoir un port de lecture par unité de calcul, ce qui fait beaucoup plus. Les ''schedulers'' sont composées d''''entrées''', des mots mémoire qui stockent une instruction. Une instruction réserve une entrée après son décodage et la libère dès qu'elle est envoyée aux unités de calcul. Une entrée contient l'opcode (les signaux de commande à envoyer à l'ALU), le registre de destination du résultat, les registres de chaque opérande, et éventuellement des signaux de commande en plus. De plus, chaque opérande est couplée à un bit de disponibilité, qui indique si elle est disponible. Quand un opérande est écrit dans les registres, le bit de présence correspondant est mis à jour. Enfin, chaque entrée possède un bit ''empty'' qui indique si elle est vide, cette information étant utile pour réserver des entrées. [[File:Entrée d'une station de réservation - sans les tags.png|centre|vignette|upright=3|Entrée d'une fenêtre d'instruction]] ===Les stations de réservation=== Les '''stations de réservation''' sont des fenêtres d'instruction particulières, qui sont capables de mémoriser les opérandes des instructions. Les entrées des stations de réservation sont identiques à celle des autres fenêtres d'instruction, si ce n'est que les opérandes de l'instruction sont enregistrés directement dans des champs séparés. Il y a deux champs, un par opérande, pour stocker l'opérande elle-même, lue depuis les registres ou obtenue via le réseau de contournement. Notons que les champs pour les opérandes viennent en plus des champs pour les noms de registres, encore que les deux peuvent être fusionnés si on veut optimiser le tout. [[File:Entrée d'une station de réservation.png|centre|vignette|upright=3|Entrée d'une station de réservation.]] Précisons que la terminologie n'est pas très fiable. Les termes "fenêtre d'instruction" et "station de réservation" ne regroupent pas du tout la même chose d'un papier de recherche à l'autre, d'un bouquin à l'autre, d'un chercheur à l'autre, d'un ingénieur à l'autre, d'un professeur à l'autre. Le terme initial vient pourtant de l'article original sur l'algorithme de Tomasulo, où il désignait une fenêtre d'instruction associée à une unité de calcul précise. Mais le terme a ensuite été réutilisé, ce qui fait que certains processeurs avec plusieurs unités de calcul sont décrits comme ayant une unique station de réservation. En bref : c'est le bazar ! Mais nous en reparlerons dans le chapitre sur le renommage de registres, car c'est la place idéale pour les aborder. Toujours est-il que j'ai fait le choix de confondre les concepts de fenêtre d'instruction et de station de réservation avec les concepts de '''lecture avant émission''' et de '''lecture après émission'''. La différence entre les deux est que les registres sont lus après émission avec une fenêtre d'instruction, avant avec des stations de réservation. Dans le cas "avant émission", les opérandes sont mémorisés dans la station de réservation. Et cette différence a une influence sur le pipeline du processeur, le banc de registres et tout ce qui s'en suit. Un désavantage de la lecture avant émission est qu'il faut stocker les opérandes après lecture, ici dans les stations de réservation. Mais un avantage est que le banc de registre a besoin de moins de ports de lecture, car une bonne partie des opérandes sont fournies par le système de contournement. Nous verrons cela dans le détail dans le chapitre sur les processeurs superscalaires. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Lecture après émission.]] [[File:Read Before Issue.png|centre|vignette|upright=2.5|Lecture avant émission.]] ===La logique d'éveil et de sélection=== Dans le cas qui va suivre, on suppose que le processeur ne peut émettre qu'une instruction à la fois. Chaque cycle, une instruction est sélectionnée et est envoyée dans le chemin de données, soit à une ALU, soit à une unité d'accès mémoire. La sélection d'une instruction est effectuée par l'unité d'émission, qui est aussi appelée le '''''scheduler'''''. Elle gère la disponibilité des opérandes et la disponibilité des unités de calcul adéquate. Le choix de l'instruction émise doit être le plus pertinent possible, pour des raisons de performances. Pour le premier point, l'unité d'émission détermine quelles instructions sont candidates pour l'émission. Les ''instructions candidates'' sont celles dont tous les opérandes sont prêts. Le processeur contient un circuit qui détecte les instructions candidates : la '''logique d’éveil''' (''wake-up logic''). Une fois que la logique d'éveil a fait son travail, une instruction est choisie pour s’exécuter en fonction de la disponibilité des unités de calcul adéquates. Ce rôle est dévolu à un circuit qu'on appelle la '''logique de sélection''', ou ''select logic''. [[File:Fonctionnement complet de la logique d’émission.jpg|centre|vignette|upright=1.5|Fonctionnement complet de la logique d’émission.]] La logique de sélection doit gérer le fait que les unités de calcul du processeur ne sont pas toutes identiques. Déjà, un processeur a généralement des unités séparées pour les instructions entières et flottantes, des unités spécialisées dans les accès mémoire, parfois des unités spécialisées pour les branchements. Une instruction doit être attribuée à la bonne unité de calcul, on ne doit pas envoyer une instruction entière dans une unité de calcul flottante. De plus, parmi les unités de calcul entières, toutes ne sont pas identiques. Par exemple, il est fréquent d'avoir plusieurs unités de calcul spécialisées dans les opérations simples (additions, soustractions, opérations logiques) avec une unité pour les multiplications/divisions séparées, parfois une unité spécialisée pour les décalages/rotations, etc. Là encore, allouer la bonne instruction à la bonne ALU est complexe. Plus les unités de calcul sont hétérogènes, plus la logique de sélection est compliquée. Les logiques d'éveil comme de sélection sont assez complexes. Comme on le verra plus bas, la logique de sélection la plus simple, qui gère une seule unité de calcul, est basée sur un encodeur à priorité couplé à d'autres circuits. Et pour gérer plusieurs ALUs, il faut mettre des encodeurs en cascade. Le résultat est que même en prenant une logique de sélection simple, elle sera assez lente et gourmande en circuits. Aussi, la logique de sélection met souvent un cycle d'horloge entier pour faire son travail, elle a son propre étage de pipeline attribué. La logique d'éveil est dans le même cas, ce qui fait qu'émettre une micro-opération demande deux cycles d'horloge. Le défaut est que cela rajoute des cycles d'horloges entre la fenêtre d'instruction et l'ALU, ce qui complique la gestion du pipeline. Ces cycles de retard sont à prendre en compte au moment d'émettre les instructions, les ''scheduler'' doit en tenir compte pour des performances optimales. Sans tenir compte de ces cycles de retard, les instructions arrivent en retard de quelques cycles à l'ALU, cycles de retard durant lesquels l'ALU n'a pas fait de calcul et a été sous-utilisée, sans compter que le système de contournement n'est pas utilisé au mieux. Et le problème est encore plus important sur les processeurs avec des stations de réservation, qui utilisent la "lecture après émission" : cela rajoute un cycle d'horloge en plus, un temps de retard en plus. ===La logique d'éveil : l'émission anticipée=== La logique d'éveil doit tenir compte du fait qu'il y a plusieurs étages entre l'émission et l'exécution sur une unité de calcul. Par exemple, un processeur a souvent entre un et à cinq étages entre la file d'attente et les unités de calcul. Il faut lire les registres, gérer le contournement, et cela peut prendre quelques cycles d'horloge. Sur le Pentium 4, on trouve 6 étages entre la fenêtre d’instruction et l'entrée de l'ALU. Si les micro-opérations sont émises quand les opérandes sont disponibles, il y aura un délai de quelques cycles avant qu'elles atteignent l'ALU. Alors qu'idéalement, on souhaiterait que la micro-opération atteigne l'ALU dès que ses opérandes sont disponibles, pour profiter des techniques de contournement. Pour cela, la logique d'éveil émet les instructions quelques cycles en avance pour qu'elles arrivent au bon moment. Il s'agit d'une technique d''''émission anticipée''', dont nous avions parlé dans le chapitre sur le contournement. : Il faut noter que le problème se pose plus avec des fenêtres d'instruction qu'avec des stations de réservation. Les premières ont un étage en plus entre émission et ALU, vu qu'il faut lire des registres après l'émission. L'émission anticipée demande d'émettre un signal d'éveil en avance de quelques cycles, pile au bon moment. Par exemples, si on a deux étages entre l'ALU et l'unité d'émission, le signal de réveil sera généré deux cycles avant que le résultat soit effectivement calculé. L'implémentation varie, mais deux solutions sont possibles. La première est de générer le signal d'éveil dans l'ALU, ce qui n'a de sens que pour les opérations comme les multiplications ou les divisions, qui prennent plusieurs cycles. Une autre technique génère le signal de réveil dans une structure centralisée, spécialisée dans la génération des signaux d'éveil. L'unité de composée d'un registre à décalage par registre. Imaginons qu'une instruction est émise, que cette instruction mette N cycles à s'exécuter, et qu'elle écrive dans un registre de destination. L'unité sélectionne alors le registre à décalage associé au registre de destination, et met le bit numéro N à 1. Le registre décalé d'un cran à chaque cycle. Quand le bit sortant est un 1, alors le signal de validité pour l'opérande est généré. L'émission anticipée marche bien si l'instruction a une durée fixe, connue à l'avance. Et autant c'est le cas pour les instructions arithmétiques et logiques, autant ce n'est pas le cas pour les accès mémoire. Les accès mémoire ont une latence variable : quelques cycles pour un succès de cache, plusieurs dizaines de cycles pour un défaut de cache L1, pas loin de la centaine pour un défaut de cache L2, etc. Et cela pose des problèmes pour l'émission anticipée. L'émission en avance pour les accès mémoire est purement spéculative : le processeur émet des instructions en supposant que la lecture entrainera un succès de cache, quitte à annuler l'instruction en cas de défaut de cache. Mais faire ainsi demande non seulement d'annuler les instructions émises en avance, mais aussi de ne pas retirer les instructions émises en avance de la fenêtre d'instruction. Elles sont émises, mais une copie de sauvegarde est conservée dans la fenêtre d'instruction. Si le processeur détecte un défaut de cache, il peut alors ré-exécuter l'instruction. S'il détecte un succès de cache, les instructions lecture-dépendante sont retirées de la fenêtre d'instruction, la copie de sauvegarde est devenue inutile et est donc jetée. ===La logique de sélection : âge ou position ?=== La logique de sélection est primordiale pour de bonnes performances. Il existe deux méthodes principales pour sélectionner l'instruction à exécuter. La première est la plus simple : elle se base sur lé numéro de l'entrée. En effet, une fenêtre d'instruction est avant tout une sorte de mémoire, un mix entre mémoire associative, mémoire RAM, et FIFO. Et chaque entrée a un numéro, une adresse mémoire. Nous parlerons de numéro dans ce qui suit, car ce sera plus simple, le terme d'adresse mémoire étant peut-être un peu exagéré dans le contexte des fenêtres d'instruction. Toujours est-il que la fenêtre d'instruction est adressable dans le sens où on peut lui envoyer le numéro de l'entrée voulue, et la fenêtre d’instruction renvoie le contenu de l'entrée sur son port de lecture. Et c'est ce que fait la logique de sélection : elle génère le numéro de l'entrée à lire. Le numéro est alors envoyé sur l'entrée d'adresse de la fenêtre d’instruction, et elle fournit la micro-opération associée sur son port de lecture, son '''port d'émission'''. La première méthode de sélection, donc. Elle est basée sur le numéro de l'entrée. Si plusieurs entrées sont éveillées, la logique de sélection prend celle avec le plus petit numéro. Elle porte le nom de '''sélection par position''', sous-entendu position dans la fenêtre d'instruction. Vous l'avez peut-être deviné, mais la logique de sélection est alors un encodeur à priorité. Le circuit de sélection ne se résume donc pas seulement à un encodeur à priorité, mais c'est le circuit central. L'avantage d'une telle méthode de sélection est qu'elle est simple à implémenter : un encodeur à priorité est un circuit connu, facile à implémenter. Mais on remarque un défaut : un encodeur est un circuit assez rapide, mais qui utilise beaucoup de transistors, beaucoup de portes logiques, surtout si on veut qu'il soit rapide. Ce qui explique que la logique de sélection ait son propre étage de pipeline rien que pour elle. La seconde méthode s'appelle la '''sélection par âge''', au nom assez transparent. L'idée est de privilégier l'émission de l'instruction la plus ancienne. Elle demande que la fenêtre d'instruction trie les micro-opérations par ordre d'insertion dans la fenêtre d'instruction, ce qui en fait une pseudo-FIFO. Le tri est partiel, car les instructions peuvent sortir de la fenêtre d’instruction à tout moment. Compacter la fenêtre d'instruction, à savoir regrouper toutes les entrées valides est une idée, mais elle est compliquée à implémenter. Aussi, elles préfèrent encoder des informations sur l'ordre d'émission dans chaque entrée. L'encodeur à priorité doit alors travailler non pas sur des nombres entiers liés à l'ordre d'insertion dans la pseudo-FIFO. Elle est encore plus gourmande en circuits que la méthode précédente. Les processeurs haute performance utilisent souvent des méthodes hybrides. Par exemple, les processeurs AMD de microarchitecture Bulldozer utilisaient une méthode intermédiaire. Ils utilisaient une fenêtre d'instruction couplée à un encodeur à priorité pour la sélection par position, mais complémentaient le tout avec une unité qui mémorisait l'instruction la plus ancienne dans la fenêtre d’instruction. Le mécanisme de sélection par âge était utilisé en priorité. Mais si l'instruction la plus ancienne n'était pas prête, le processeur basculait sur le mécanisme de sélection par position. ===La compaction des fenêtres d'instruction=== À chaque cycle, les instructions décodées sont ajoutées dans la fenêtre d'instruction, dans des entrées vides. Vu que les instructions quittent celle-ci dans le désordre, ces vides sont dispersés dans la fenêtre d'instruction, ce qui pose problème pour déterminer où placer les nouvelles instructions. La solution la plus triviale consiste à conserver une liste des vides, mise à jour à chaque insertion ou émission d'instruction. Une autre solution consiste à éliminer les vides en compactant la fenêtre d'instruction à chaque cycle d'horloge. Des circuits se chargent de détecter les vides et de regrouper les instructions en un unique bloc. Il faut signaler que certains processeurs arrivent à se passer de cette étape de compactage, mais au prix de fenêtres d'instruction nettement plus complexes. Autre problème : quand il faut choisir quelle instruction émettre, il y a toujours plusieurs candidats. Si on choisit mal, des instructions restent en attente trop longtemps parce que d'autres instructions plus jeunes leur passent devant. Pour éviter cela, les instructions les plus vielles, les plus anciennes, sont prioritaires. Pour cela, on peut utiliser une FIFO un peu spéciale pour la fenêtre d'instruction. Si les ajouts d'instruction se font dans l'ordre, les instructions ne quittent pas forcément la fenêtre d'instruction dans l'ordre imposé par une FIFO : les instructions restent triées dans leur ordre d'ajout, même s'il y a des vides entre elles. Dans ces conditions, il est préférable que le compactage conserve l'ordre FIFO des instructions. Dans ces conditions, l'instruction la plus ancienne est celle qui est située à l'adresse la plus faible : le circuit de sélection peut donc être fabriqué avec des encodeurs, et est relativement simple. ==Les fenêtres d'instruction basées sur une matrice de dépendances== L'implémentation la plus simple étend le fonctionnement d'un pipeline dynamique usuel. Rappelez-vous le chapitre sur les pipelines dynamiques. Nous avions vu que de tels pipelines émettaient une instruction par cycle, quitte à émettre des bulles de pipeline en cas de dépendance bloquante. Et il est possible d'améliorer leur unité d'émission pour qu'elle soit compatible avec l'exécution dans le désordre. ===Rappels sur le registre de réservation/disponibilité=== L'émission d'une instruction est gouvernée par un ''registre de réservation'' qui indique quels registres sont réservés par une instruction, et ceux qui sont libres. Un registre réservé est un registre qui sera écrit par une instruction en cours d'exécution, mais qui n'a pas encore écrit son résultat. Les instructions candidates doivent avoir leurs opérandes dans des registres libres. Sinon, c'est signe que leurs opérandes sont réservés en écriture, donc pas encore écrites, donc pas disponibles. Si une instruction candidate veut lire ce registre, c'est signe qu'il y a une dépendance RAW : elle veut lire un registre réservé, qui est destiné à être écrit par une instruction en vol. Si elle veut écrire, c'est signe qu'elle veut écrire dans un registre où une autre instruction veut écrire : c'est une dépendance WAW. Dans les deux cas, l'instruction n'est pas émise. Le registre de réservation encode les registres réservés comme suit : chaque bit est associé à un registre. Le bit numéro 0 est associé au registre numéro 0, le bit numéro 1 au registre numéro 1, etc. Là, En clair, les numéros de registres réservés sont encodés en représentation non pas binaire, mais en représentation ''one-hot'' (vue au premier chapitre). {|class="wikitable" |+ Registre de réservation |- ! Registre 7 !! Registre 6 !! Registre 5 !! Registre 4 !! Registre 3 !! Registre 2 !! Registre 1 !! Registre 0 |- | 0 || 0 || 1 || 0 || 0 || 1 || 0 || 0 |} Avant d'émettre une instruction, l'unité d'émission extrait les registres opérande/destination et les convertis dans la même représentation que le registre de réservation, à savoir en représentation ''one-hot''. Le circuit de traduction binaire vers ''one-hot'' est, pour rappel, un simple décodeur. Puis, on fait un OU logique entre les sorties des décodeurs. Le résultat est un masque qui indique quels registres sont lus par l'instruction, encodé en représentation ''one-hot''. Appelons-le le '''masque d'opérandes'''. Le masque est alors comparé au registre de réservation pour vérifier si l'instruction peut être émise. [[File:Unité d'émission simple, dans l'ordre.png|centre|vignette|upright=2|Unité d'émission simple, dans l'ordre]] Si l'émission est autorisée, le registre de réservation est là aussi mis à jour. Le registre de réservation est aussi mis à jour dès qu'une instruction enregistre son résultat dans les registres, ou alors dès qu'il est disponible pour le contournement. Le bit associé au registre repasse alors à 0 (ou à 1). Sans contournement, la mise à jour se fait alors à la toute fin de l'instruction, quand elle se termine, lors de la dernière étape d'enregistrement, à la fin de son pipeline. Avec, elle se fait quand l'instruction quitte l'unité de calcul. ===L'extension à l'exécution dans le désordre : l'éveil par matrice de bits=== La différence entre un pipeline dynamique et l'exécution dans le désordre est que l'on passe d'une instruction à émettre à plusieurs. Plusieurs instructions sont mises en attente dans une fenêtre d’instruction, et y attendent leur tour. L'idée est alors d'envoyer le registre de disponibilité à toutes les entrées, à toutes les instructions en attente. Ainsi, on sait quelles sont les instructions qui peuvent s'exécuter et celles qui ne le peuvent pas. L'implémentation est assez simple, elle ressemble beaucoup à l'implémentation d'un pipeline dynamique simple, si ce n'est que des circuits sont dupliqués. L'implémentation utilise des fenêtres d'instruction légèrement différentes de celles introduites plus haut. Elles n'utilisent notamment pas de bits de disponibilité, mais autre chose. Lorsqu'une instruction est ajoutée à la fenêtre d'instruction, le masque de disponibilité des opérandes est stocké dans la fenêtre d'instruction. A chaque cycle, le registre de disponibilité est envoyé à toutes les entrées, et est comparé avec tous les masques de disponibilité des opérandes. Si une comparaison renvoie un 1, alors l'instruction de l'entrée est une instruction candidate à l'émission. [[File:Unité d'émission dans le désordre basée sur un registre de disponibilité.png|centre|vignette|upright=2.5|Unité d'émission dans le désordre basée sur un registre de disponibilité]] L'ensemble est implémenté avec l'aide d'une '''matrice de bits''', où chaque ligne correspond à une entrée et chaque colonne à un registre. À chaque croisement entre une ligne et une colonne, on trouve un bit. Si le bit de la ligne n et de la colonne m est à 1, cela veut dire : l'instruction dans l'entrée n a besoin de lire le registre m. S’il est à 0, alors cela veut dire que l'instruction stockée dans la ligne n'a pas besoin de la donnée dans le registre m. [[File:Planificateur à matrice de bits.jpg|centre|vignette|upright=2|Planificateur à matrice de bits.]] Lorsqu'une instruction réserve une entrée, elle initialise la ligne en fonction des registres qu'elle souhaite lire. Pour vérifier si une instruction a ses opérandes prêts, le processeur compare le registre de disponibilité à la ligne associée à l'instruction/entrée. A chaque intersection ligne-colonne, se trouve un comparateur de 1 bit, qui détecte si le registre est demandé et disponible. Les résultats de cette porte sont ensuite envoyés à une porte ET, qui fait le gros du travail. [[File:Logique de détection de la disponibilité d'une instruction.jpg|centre|vignette|upright=2|Logique de détection de la disponibilité d'une instruction.]] ==Les fenêtres d'instruction basées sur une mémoire associative== Les processeurs modernes utilisent une mémoire associative pour la fenêtre d'instruction. Les mémoires associatives ont été abordées il y a quelques chapitres, mais faisons quelques rappels. Les mémoires associatives servent à accélérer la recherche de données dans un ensemble. Or, une fenêtre d'instruction vérifie régulièrement si chaque entrée est prête. Il s'agit d'un processus de recherche d'une instruction qui respecte une condition bien précise dans la mémoire, ce qui fait que les mémoires associatives sont donc tout indiquées. Comme vous le savez, les signaux de commande d'une instruction sont propagés avec celle-ci dans le pipeline, le nom du registre de destination ne faisant pas exception. Le nom de registre est envoyé à la fenêtre d'instruction lors de l'écriture du résultat dans les registres. S'il y a correspondance, l'opérande est disponible et son bit de disponibilité est mis à 1. On peut adapter cette méthode pour tenir compte du contournement assez simplement. [[File:Détection des dépendances par propagation du registre de destination.png|centre|vignette|upright=2|Détection des dépendances par propagation du registre de destination.]] En conséquence, le circuit de détection des dépendances est constitué d'un grand nombre de comparateurs : un par champ « nom de registre » dans chaque entrée. La logique d'éveil/''wake up'' regroupe tous les comparateurs, la logique de sélection est un circuit situé en-dehors de la mémoire associative. Les entrées sont dans la mémoire associative elle-même. [[File:Gestion des bits de validité.png|centre|vignette|upright=2|Gestion des bits de validité.]] L'implémentation la plus simple est celle du schéma précédent, où on utilise une mémoire associative unique. Une version plus élaborée sépare la fenêtre d'instruction en deux parties : une mémoire qui mémorise les registres des opérandes, une autre mémoire pour le reste. La mémoire pour les registres opérandes est la mémoire associative proprement dite, c'est elle qui est associée aux comparateurs, à la logique de ''wake-up''/réveil, etc. Par contre, l'autre mémoire est une mémoire RAM simplifiée, qui mémorise les informations qui n'ont pas besoin des comparateurs. L'opcode de l'instruction est là-dedans, par exemple. La fenêtre d'instruction est donc une sorte de mémoire associative améliorée. Il se trouve que c'est aussi le cas du ROB. Et il est possible de fusionner le tampon de ré-ordonnancement avec la fenêtre d'instruction dans une structure unique. La différence avec une fenêtre d’instruction normale est que les entrées sont libérées non pas quand l'instruction est exécutée/émise, mais quand elle termine son exécution et quitte le ROB. La fenêtre d'instruction incorpore des bits dans chaque entrée, pour savoir si la µops associée a été émise et est en cours de traitement dans les ALUs. La méthode a notamment été utilisée sur les processeurs d'architecture K6 d'AMD. Le tout donnait une structure appelée le '''DRIS''' (''deferred scheduling register renaming instruction shelf''). Les processeurs PA 8000 de HP étaient aussi vraisemblabment dans ce cas, aussi. ===Les optimisations de la consommation d'énergie : la désactivation des portions inutilisées=== Le problème avec des fenêtres d'instruction de ce type est leur forte consommation énergétique, ainsi que le grand nombre de portes logiques utilisées, qui deviennent prohibitifs pour des fenêtres d'instruction un peu grosses. Pour résoudre ce problème, certains ont optimisé les comparateurs. D'autres ont tenté de profiter du fait que la majorité des bits dans les entrées sont composés de zéros. Bref, les optimisations purement matérielles sont légion. Une première solution est de désactiver les entrées qui sont inutilisées, vides, sans instruction. Pour cela, on fait précéder les comparateurs par un circuit qui les connecte ou déconnecte des lignes de bit. Le circuit est commandé par le bit ''empty'' qui indique si une entrée est vide ou non. L'avantage est que la consommation d'énergie de la fenêtre d'instruction devient alors proportionnelle au nombre d'entrées non-vides, et non au nombre d'entrées total. Du moins, en apparence, les entrées non-utilisées doivent quand même être alimentées pour fonctionner, mais l'activité de comparaison disparait dans les entrées vides. Il est possible d'étendre cette technique aux entrées dont les opérandes sont prêts. Les gains sont généralement assez bons, avec une réduction de consommation variant entre 30 et 50%, avec une implémentation très simple et très économe en circuits. Une autre solution, assez simple à mettre en place, consiste à désactiver une partie de la fenêtre d'instruction sin elle est inutilisée. Pour cela, il faut segmenter la fenêtre d'instruction avec la technique du ''wire partitionning''. Pour rappel, une fenêtre d'instruction est une mémoire associative. Et comme toute mémoire associative, elle contient des fils, les lignes de bit, qui relient les entrées/sorties à toutes les cellules mémoire. Plus une ligne de bit est longue, plus elle consomme d'énergie et plus le temps de lecture/écriture est long. L'idée est de segmenter les lignes de bits en plaçant des répéteurs qui recopient la tension d'un segment au suivant. Les répéteurs sont des tampons trois-états, ce qui permet de déconnecter les portions inutilisées de la ligne de bit. Ce faisant, la fenêtre d'instruction est découpée en segments, qui peuvent être désactivés si besoin. S'il y a peu d'instructions chargées dans la fenêtre d'instruction, les portions inutilisées sont désactivées. La technique marche d'autan mieux si les instructions sont compactées au début de la fenêtre d'instruction. [[File:Wire partitionning.png|centre|vignette|upright=2|Wire partitionning]] Tout le problème est de savoir quelles portions désactiver. La technique est assez simple si la fenêtre d'instruction est compactée, à savoir si toutes les instructions sont régulièrement regroupées au début de la mémoire CAM. Mais même avec cette optimisation, la décision de désactiver une portion de la fenêtre d'instruction n'est pas à prendre à la légère. Il ne faut pas désactiver une portion contenant des instructions pouvant être émise sous peu. La décision dépend de paramètres variés : proportion d'entrée vides, quantité d'entrées récemment activées/désactivées récemment, présences d'entrées avec un ''match'' d'opérandes récent, etc. Il est important de préciser que les techniques en question fonctionnent aussi sur les autres types de fenêtre d'instruction, qui ne sont pas basées sur des mémoires associatives. Nous allons voir celles-ci dans la suite du chapitre, mais gardez à l'esprit que ces optimisations, à savoir désactiver les entrées vides/prêts et partitionner la fenêtre d'instruction, sont des optimisations générales qui marchent avec presque tout. ===L'ajout d'une FIFO pour les instructions déjà prêtes à l'émission=== D'autres techniques permettent de réduire aussi bien le cout en circuits que la consommation d'énergie de la fenêtre d'instruction. L'idée est d'utiliser une mémoire associative quand elle est réellement nécessaire, mais d'utiliser une fenêtre d'instruction "normale" dès que possible. La méthode la plus simple tient compte du fait que certaines µopsont déjà toutes leurs opérandes de disponibles à l'émission, mais doivent quand même être mises en attente, parce que l'ALU adéquate est occupée, parce que des dépendances WAW/WAR sont encore là, ou pour tout autre raison. Dans ce cas, elles sont mises en attente non pas dans la fenêtre d'instruction, mais dans une mémoire FIFO toute simple. L'idée est qu'au lieu d'avoir une énorme mémoire associative pour la fenêtre d'instruction, on déplace quelques entrées dans une petite FIFO annexe. Le résultat est un gain d'énergie et de circuits, au prix d'une perte de performance mineure. La perte de performance en question se manifeste si aucune instruction n'a ses opérandes de prêtes à l'émission : le programme n'utilise pas la FIFO et voit alors une fenêtre d'instruction plus petite. Une amélioration de cette technique tient compte du fait que certaines instructions sont dans un cas intermédiaire. Elles ont déjà un opérande de prête lors de l'émission, mais pas l'autre. Le nombre d'opérandes varie suivant l’instruction : certaines n'ont besoin que d'un seul opérande. De plus, il arrive qu'une opération tout juste décodée ait déjà un ou plusieurs de ses opérandes de prêts. Cette constatation permet d'éviter d'utiliser des comparateurs pour les opérandes déjà prêts. Par exemple, on peut parfaitement utiliser trois fenêtres d'instruction : * une pour les instructions dont tous les opérandes sont prêts, mais qui sont quand même mises en attente, sans comparateur ; * une pour les instructions dont un seul opérande manque, qui n'utilise qu'un comparateur par entrée ; * une pour les instructions dont deux opérandes manquent à l'appel, qui utilise deux comparateurs par entrée. C'est beaucoup plus économique que d'utiliser une seule grosse fenêtre d'instruction qui contiendrait autant d'entrées que les trois précédentes réunies, avec deux comparateurs par entrée. Certains sont même allés plus loin, et ont proposé de supprimer la fenêtre d'instruction avec deux opérandes par entrée. Les instructions dont deux opérandes sont inconnus au décodage sont stockées dans la fenêtre d'instruction pour instructions avec un comparateur par entrée. Un circuit de prédiction se charge alors de prédire l'opérande manquant, cette prédiction étant vérifiée plus loin dans le pipeline. Il serait cependant étonnant qu'une telle proposition ait donné lieu à la moindre implémentation réelle. ===Les optimisations de la consommation d'énergie avancées=== D'autres chercheurs ont conservé une fenêtre d'instruction unique, avec autant de comparateurs par entrée qu'il y a d'opérandes possibles par instruction. Simplement, le processus de détection des opérandes prêts est légèrement ralenti : on ne vérifie qu'un opérande par cycle. Pour vérifier les deux opérandes d'une entrée, on doit attendre deux cycles. Enfin, certains chercheurs ont proposé des fenêtres d'instruction segmentées. Les instructions circulent à chaque cycle d'un segment vers le suivant : en conséquence, certains segments conservent les instructions les plus anciennes, un autre les instructions les plus jeunes, etc. Seul le denier segment, celui qui contient les instructions les plus vielles, peut émettre une instruction : la détection des opérandes se fait seulement dans le dernier segment, qui contient les instructions les plus anciennes. On économise ainsi beaucoup de comparateurs. Certains chercheurs ont tenté de pipeliner l'étape de sélection des opérandes, ainsi que l'étage d'arbitrage. Mais en faisant cela, il faut plusieurs cycles pour détecter qu'une instruction a ses opérandes prêts, ce qui pose problème face à de nombreuses dépendances RAW. Pour éviter de trop perdre en performances, certains chercheurs ont décidé d'utiliser des techniques pour prédire quelles seront les instructions dont les opérandes seront bientôt prêts. Si détecter qu'une instruction est prête prend n cycles, le processeur devra tenter de prédire la future disponibilité des opérandes n cycles en avance pour obtenir des performances optimales. ===Remplacer la mémoire associative par une RAM=== Une autre optimisation possible est de remplacer la fenêtre d'instruction par une mémoire RAM, dont chaque mot mémoire correspondrait à une entrée. Une telle optimisation permet en théorie de se passer des comparateurs associés à chaque entrée, mais au prix de l'ajout de circuits annexes potentiellement couteux. La première de ces techniques, la '''recherche directe par étiquette''' (direct tag search) fut créée par Weiss et son collègue Smith. Ils cherchaient à améliorer l'algorithme de Tomasulo, un algorithme qu'on expliquera dans quelques chapitres. Rappelons que chaque instruction produit un résultat, qui devra être rapatrié dans une ou plusieurs entrées de la fenêtre d'instruction. L'optimisation de la recherche directe par étiquette fonctionne dans le cas où le résultat de l'instruction n'est utilisé que par une seule entrée, et pas plusieurs. Le principe est simple : chaque champ « opérande » d'une entrée est adressable via le nom de registre de cet opérande. Pour faire le lien entre entrée et nom de registre, la recherche directe par étiquette ajoute une table de correspondances matérielle, une mémoire RAM qui mémorise les adresses des champs « opérande » des entrées. Les adresses envoyées dans cette mémoire sont les noms de registres des résultats. Lors de l'émission, la table de correspondances est mise à jour. Les numéros des champs « opérande » réservés lors de l'émission sont mémorisés dans les mots mémoire qui correspondent aux deux registres sources. Toutefois, une petite vérification est faite lors de l'émission : s'il y a déjà une correspondance dans la table pour un registre source, alors une autre instruction compte lire ce registre. Pour éviter d'écraser les données de l'instruction précédente dans la table de correspondances, l'émission de l'instruction est bloquée. [[File:Recherche directe par étiquette.png|centre|vignette|upright=2|Recherche directe par étiquette.]] ==Les fenêtres d’instruction avec préplanification== Avec la '''préplanification''' (''prescheduling''), la fenêtre d’instruction est composée de mémoires FIFO dans lesquelles les instructions sont triées dans l'ordre d'émission. Il n'y a pas de logique d’émission proprement dite, celle-ci se bornant à vérifier si l'instruction située au début de la FIFO peut s’exécuter. Par contre, le préplanificateur détecte les dépendances et en déduit où insérer les instructions dans le tampon d'émission, à l'endroit le plus adéquat. [[File:Préplanification.jpg|centre|vignette|upright=2|Préplanification.]] ===L'usage de FIFO multiples=== La technique de préplanification la plus simple utilise plusieurs FIFO. Quand une instruction a une dépendance avec une autre instruction, les deux sont placées dans la même FIFO. Pour cela, le préplanificateur détecte les chaines d'instructions dépendantes, et place les instructions dans la FIFO adéquate. A chaque cycle, l'unité d'émission lit une micro-opération dans chaque FIFO et vérifie si elle peut l'émettre. Si la micro-opération n'a pas ses opérandes disponibles, ou qu'une dépendance structurelle survient, alors la FIFO est bloquée. La micro-opération attend que la dépendance soit résolue, bloquant toutes les instructions précédentes. Mais les autres FIFO ne sont pas bloquées, laissant de la marge de manœuvre. [[File:Préplanification par FIFO multiples.png|centre|vignette|upright=1.5|Préplanification par FIFO multiples.]] ===La technique du tampon trié=== La technique du '''tampon trié''' trie les instructions selon le temps d'attente avant leur exécution. Les instructions qui sont censées s’exécuter bientôt sont insérées au tout début de la FIFO, tandis que les instructions qui s’exécuteront dans un long moment sont insérées vers la fin. Là encore, l'unité d'émission lit une micro-opération dans la FIFO, et détermine si elle peut être émise. Si une dépendance survient, l'émission est retardée, et la FIFO est bloquée. [[File:Préplanification par tampon trié.png|centre|vignette|upright=1.5|Préplanification par tampon trié.]] La technique a cependant quelques problèmes assez importants. Le premier problème est que la FIFO est bloquée lorsqu'une micro-opération ne peut être émise. Le second problème est que le temps avant exécution n'est pas toujours connu, notamment pour les instructions d'accès mémoire. Et cela se répercute sur les instructions dépendantes de celles-ci. Pour résoudre ce genre de problèmes, l'usage d'un pipeline à ''replay'' est possible, et est même l'une des meilleures solutions possible, malgré ses défauts. L'idée est que les lectures sont pré-planifiées en supposant qu'elles font un succès de cache L1. Si la prédiction est fausse, la lecture est ré-exécutée plusieurs cycles plus tard, en supposant qu'elle fait un succès dans le cache L2, et ainsi de suite. Elle est alors ré-insérée dans la FIFO, elle est pré-planifiée une seconde fois. Il en est de même si une micro-opération ne peut pas être émise : il suffit de la réinsérer dans la FIFO au bon endroit, en attendant que ses dépendances soient résolues. Ainsi, l'instruction fautive ne bloque pas la fenêtre d’instruction, et retente sa chance autant de fois qu'il le faut. [[File:Préplanification par fenêtre d’instruction scorebarodée.png|centre|vignette|upright=1.5|Préplanification par fenêtre d’instruction scorebarodée.]] Une autre solution utilise deux fenêtres d’instruction : une FIFO gérée par la préplanification, et une vraie fenêtre d'instruction pour les instructions dont le temps d'attente ne peut pas être déterminé. Il est possible de mettre cette dernière avant la préplanification, afin de gérer les temps d'attente des instructions d'accès mémoire. Quand le temps d'attente d'une lecture devient connu, ses instructions dépendantes sont gérées avec préplanification. [[File:Préplanification avec fenêtre d’instruction.png|centre|vignette|upright=2.5|Préplanification avec fenêtre d’instruction.]] ===Les fenêtres d'instruction avec allocation temporelle statique=== L''''allocation temporelle statique''' correspond à une technique utilisée sur les processeurs Cuzco de l'entreprise Condor. La technique en question a été présenté en 2025, mais des idées similaires ont été présentées dans la littérature académique. Elle ressemble beaucoup aux techniques de pré-planification, avec cependant quelques différences. L'idée est simple : le processeur dispose de plusieurs fenêtres d'instruction, qui mettent en attente les micro-opérations. Lors de l'étape de renommage de registres, le processeur détermine dans combien de cycles d'horloge la micro-opération sera prête pour exécution. La micro-opération est alors mise en attente durant ce nombre de cycles, dans les fenêtres d'instruction, puis est émise une fois ce nombre de cycles écoulés. Ce faisant, les fenêtres d'instruction n'ont pas besoin de détecter la disponibilité des opérandes à chaque cycle, pour chaque micro-opération en attente. Le ''timing'' de l'émission des micro-opérations est décidé à l'avance. L'implémentation exacte n'est pas connue, mais plusieurs solutions sont imaginables. Par exemple, la fenêtre d'instruction peut simplement être composée de plusieurs mémoires de petite taille, chacune contenant les micro-opérations destinées à être exécutées dans N cycles, N étant différent pour chaque mémoire. Une autre solution, plus réaliste, utilise une fenêtre d'instruction dans laquelle la micro-opération est couplée à des champs pour les opérandes, et un champ compteur. Le champ compteur est initialisé avec le nombre de cycles à attendre, et est décrémenté à chaque cycle d'horloge. Quand il atteint zéro, la micro-opération est émise. Vous remarquerez que la méthode ne marche que si toutes les micro-opérations prennent un nombre fixe de cycles d'horloge. Et autant c'est le cas pour les micro-opérations arithmétiques ou logiques, autant les accès mémoire ne rentrent pas dans ce cadre. En théorie, on ne sait pas combien de temps prendra un accès mémoire. Et cette incertitude se répercute sur les instructions dépendantes d'un accès mémoire. Pour éviter cela, le processeur réutilise un pipeline à ''replay'' tel que vu dans le chapitre précédent. L'unité de renommage de registre suppose que tout accès mémoire fait un succès de cache L1, et décide des ''timings'' d'émission sous cette hypothèse. Si une lecture subit un défaut de cache, elle est ré-exécutée, de même que toutes les instructions dépendantes. Pour cela, le registre de destination de la lecture est marqué comme invalide, grâce à un bit spécifique attaché au registre. Toute instruction qui lit un opérande invalide est elle aussi ré-executée de zéro. Pour simplifier, l'unité d'émission ressemble à une unité d'émission dans l'ordre, avec un registre de disponibilité, qu'on aurait amélioré pour aller au-delà de la simple détection des dépendances d'instruction. Pour déterminer les ''timings'' d'émission, à savoir quand émettre une micro-opération, le processeur utilise une unité d'émission à deux étages. Le premier étage est appelé le ''register scoreboard'', le second étage est appelé la ''Time Ressource Matrix''. Les deux étages communiquent entre eux, comme on va le voir, et leurs noms donnent une idée de ce qu'ils font. Le premier étage gère les dépendances de registres, le second gère les dépendances structurelles. Le premier étage est un registre de disponibilité amélioré, qui gère les dépendances de registre. Cet étage sait quand tel registre sera écrit, et donc que l'opérande écrit dedans sera disponible à partir de tel cycle d'horloge. Il le sait car l'étage suivant l'aura prévenu, mais laissons cela de côté pour le moment. Quand une micro-opération rentre dans cet étage, il vérifie les dépendances avec les registres et les micro-opérations antérieures. Vu qu'il sait quand les registres seront disponibles, il peut déterminer quand l'instruction pourra s'exécuter. Par exemple, si une micro-opération lit les deux registres R7 et R15, qui sont disponibles respectivement dans 5 et 7 cycles, le premier étage sait que la micro-opération devra attendre 7 cycles. Mais tout cela ne suffit pas à déterminer quand émettre une micro-opération. En effet, il fait aussi gérer les dépendances structurelles, ce qui est le boulot du second étage. Le second étage utilise pour cela une ''Time Ressource Matrix'', qui mémorise l'occupation de diverses "ressources", pour les 256 cycles d'horloge à venir. Les ressources en question sont les ports de lecture/écriture du banc de registre, les ALUs utilisées, si la micro-opération utilise l'unité mémoire, etc. Le second étage prend en entrée une micro-opération, détermine quelles "ressources" elle utilise, puis regarde leur disponibilité. Elle détecte alors les dépendances structurelles et détermine alors quand peut s'exécuter la micro-opération. Elle peut retarder l'émission de quelques cycles, si une dépendance structurelle est détectée. Une fois sortie du second étage, on sait quand la micro-opération va être émise, à quel cycle précisément. Et vu que la durée de l'instruction est fixe, on sait quand cette micro-opération va se terminer, quand son résultat sera disponible. Cela permet de mettre à jour la ''Time Ressource Matrix'', pour préciser que le port d'écriture sera occupé à tel moment. De plus, cette information est transmise au premier étage, qui sait alors quand est enregistré le résultat dans le registre de destination. C'est comme cela que le premier étage sait quand un registre est disponible : le second étage le prévient, quand il émet une instruction ! La ''Time Ressource Matrix''mémorise l'occupation des "ressources" pour les 256 cycles d'horloge à venir. Cependant, elle ne vérifie pas les dépendances pour les 256 cycles suivants. Quand elle reçoit une micro-opération, elle teste les dépendances structurelles pour seulement les 8 prochains cycles maximum. Si la micro-opération ne peut pas être émise pendant ces 8 cycles, le pipeline est bloqué, un ''pipeline stall'' est émis. Pour être plus précis, vu que le processeur peut décoder 8 micro-opérations en même temps, cela permet de ne consulter que 64 cycles d'horloge sur les 256. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les premiers processeurs Intel | prevText=Les premiers processeurs Intel | next=Le renommage de registres | nextText=Le renommage de registres }} </noinclude> a5z2evlnb46hgvrkmld2uk8bz19ylc0 773622 773621 2026-09-29T21:01:45Z Mewtow 31375 773622 wikitext text/x-wiki Dans les chapitres précédents, nous avons parlé des techniques dites d''''émission dans l'ordre'''. L'idée est d’exécuter une nouvelle micro-opération à chaque cycle, dans des unités de calcul séparées. Les instructions sont émises consécutivement, mais les instructions s’exécutent en parallèle dans des unités de calcul séparées. Par contre, quand l'unité d'émission ne peut pas émettre une instruction, elle bloque tout le pipeline. Les instructions qui suivent sont elles aussi bloquées, elles doivent attendre leur tour, même si elles sont en capacité de s'exécuter. Les techniques d'exécution dans le désordre que nous allons voir dans ce chapitre corrigent ce point précis. Elles sont dites à '''émission dans le désordre'''. Elles se distinguent des précédentes sur un point précis : quand l'unité d'émission bloque l'émission d'une instruction, les instructions suivantes peuvent poursuivre. L'émission des instructions peut donc se faire dans le désordre, dans le sens où une instruction peut être émise alors qu'une instruction précédente ne l'est pas encore. Mais avant de poursuivre, quelques point niveaux terminologie : * L'émission dans le désordre est un terme parlant et assez précis. Malheureusement, la terminologie la plus utilisée par d''''exécution dans le désordre'''. Et nous utiliserons ce terme dans la suite du cours, histoire de ne pas trop dévier de la nomenclature habituelle. * Nous utiliserons parfois l'abréviation OOO pour parler d'exécution dans le désordre. L'abréviation est celle de ''Out Of Order Excution''. * Nous utiliserons aussi l'abréviation ''µop'' pour parler de micro-opération, ''µops'' au pluriel pour parler de plusieurs micro-opérations, ou des micro-opérations en général. L'exécution dans le désordre ne gère en effet que des µops, elle se situe après l'étape de décodage. Pour décrire comment est implémentée l'émission dans le désordre, il faut commencer par parler des processeurs sans. Les processeurs sans exécution dans le désordre ont une unité d'émission qui bloque tout le pipeline dès qu'une µop ne peut pas être émise. Pour limiter l'impact de ce blocage, quelques rares processeurs incorporent une '''file de micro-opération''', une mémoire FIFO qui met en attente les µops. Vu que c'est une mémoire FIFO, les µops sont émises dans l'ordre, à savoir l'ordre d'ajout, dans l'ordre de décodage. Le schéma ci-dessous illustre une telle file d'attente couplée à un ''scoreboard''. L'exécution dans le désordre améliore la file de µops sur un point : ce n'est plus une mémoire FIFO. Les µops sont insérées dans l'ordre, mais peuvent sortir dans le désordre (être émises dans le désordre). La file de µops devient alors un '''''scheduler''''', terme anglais que je ne compte pas traduire. Un terme équivalent est '''''scheduler''''', terme traduit directement de l'anglais ''instruction Window''. Terme assez trompeur, car elles mettent en attente des µops, pas des instructions. [[File:Différence file µops et fenêtres instruction.png|centre|vignette|upright=2|Différence file µops et ''schedulers'' ]] Le ''scheduler'' émet une µop dès que ses opérandes sont disponibles. Par disponible, on veut dire présent soit dans le réseau de contournement, soit dans les registres. Le ''scheduler'' détecte automatiquement quand les opérandes d'une µop sont disponibles, grâce à une unité d'émission intégrée. L'unité d'émission et le ''scheduler'' sont fusionnés ensemble, dans un seul circuit, mais nous allons dire qu'ils sont conceptuellement séparés pour le moment. A chaque cycle, l'unité d'émission consulte les µops en attente pour détecter lesquelles peuvent s'exécuter. Le ''scheduler'' est spécialement être conçue pour, c'est une sorte de mémoire associative très complexe, comme on le verra dans ce qui suit. [[File:OOO Issue.png|centre|vignette|upright=2.5|Exécution dans le désordre avec un ''scheduler'']] Une fois qu'une µop sort du décodeur d'instructions, elle est ajoutée en parallèle dans la ''scheduler'' et le ROB. La raison est que les µops quittent la ''scheduler'' dans le désordre, et qu'elles doivent être remises en ordre par la suite. Le ROB s'occupe de cette remise en ordre, mais il a besoin de savoir dans quel ordre les µops sont censées être, et cet ordre est celui du décodage. Aussi, pour remplir le ROB, la seule opportunité est en sortie de l'unité de décodage. Dans le cas où une instruction est décodée en plusieurs micro-opérations, elles sont toutes insérées en même temps dans la ''scheduler'' et le ROB, en tenant compte de leur ordre. L'implémentation la plus simple de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Les µops décodées sont accumulées dans le ''scheduler'', où elles attendent leur tour. La ''scheduler'' sert donc de file d'attente. Avant de poursuivre, précisons que les micro-opérations mémoire sont à part des autres, pour diverses raisons. Une de ces raisons est que les dépendances de données sont classées en deux types : les dépendances de registre et les dépendances d'adresse. Et les deux sont fondamentalement différentes. Autant on peut détecter les dépendances de registre lors de l'émission, autant c'est plus compliqué avec les dépendances d'adresse. De plus, rappelons que si les lectures peuvent s'exécuter dans le désordre, les écritures doivent s'exécuter dans l'ordre, ou du moins en donner l'illusion. Pour cela, le processeur remet les écritures dans l'ordre avec une sorte de mini-ROB intégré à l'unité mémoire, appelée la file d'écriture. Elle complémente le ROB, qui lui ne gère que les écritures dans les registres, mais les deux collaborent. La file d'écriture envoie une écriture à la mémoire RAM quand le ROB lui dit que c'est bon, les instructions précédentes sont terminées ''dans l'ordre du programme''. Les processeurs modernes ajoutent des techniques d'exécution dans le désordre des accès mémoire, mais nous les verrons dans un chapitre dédié. Elles permettent d'utiliser un ''scheduler'' unique, qui mémorise aussi les µops mémoire. Si elles sont mises en place, l'unité mémoire n'a pas besoin de file de µops séparée. L'idée est que les dépendances de registre sont traitées par la ''scheduler'', mais que l'unité mémoire gére les dépendances d'adresse. Les dépendances d'adresse sont gérées par des techniques de ''désambiguation mémoire'', qui auront droit à un chapitre dédié. [[File:Processeur avec exécution dans le désodre des accès mémoire.png|centre|vignette|upright=2|Processeur avec exécution dans le désodre des accès mémoire]] Les processeurs assez anciens n'autorisaient pas d'exécution dans le désordre des accès mémoire. Concrétement, les accs mémoire devaient se faire dans l'ordre, mais les autres µops pouvaient être exécutées dans le désordre. Il s'agit donc d'un ordre entre µops mémoire, pas entre µops mémoire et autres µops. Les µops entières et flottantes pouvaient être exécutées avant une µops mémoire qui est avant elle dans l'ordre du programme, ce n'est pas un problème. Pour garantir l'ordre des µops mémoire, l'unité mémoire est précédée par une file de micro-opérations séparée, pour forcer l'exécution dans l'ordre des accès mémoire. De plus, les µops mémoire ne peuvent pas utiliser la ''scheduler''. Dit autrement, la ''scheduler'' ne mémorise pas de µops mémoire. Après le décodage, les µops sont réparties soit dans la file de µops mémoire, soit dans la ''scheduler''. Le décodeur classe les µops suivant que ce sont des µops mémoire ou non, et les envoient à la bonne destination. Dans ce chapitre, on supposera que c'est cette solution qui est utilisée. [[File:Processeur avec émission dans l'ordre des accès mémoire.png|centre|vignette|upright=2|Processeur avec émission dans l'ordre des accès mémoire]] ==L'implémentation d'un ''scheduler'' : généralités== Un ''scheduler'' est une mémoire qui mémorise des micro-opérations. Elle est cependant plus complexe qu'une mémoire RAM ou qu'une FIFO et ressemble un petit peu à une mémoire cache. Elle dispose d'un port d'écriture et d'un port de lecture, au minimum. Le port d'écriture permet à l'unité de décodage d'insérer une micro-opération dedans, d'ajouter la micro-opération qui vient d'être décodée. Si une instruction machine est décodée en plusieurs micro-opération, deux possibilités. La première est de les insérer un par un, ce qui fait qu'on peut se contenter d'un seul port d'écriture. L'autre possibilité est de les ajouter en même temps, ce qui demande plusieurs ports d'écriture. Le port de lecture sert à émettre une instruction. On part du principe que la ''scheduler'' ne peut émettre qu'une seule instruction à la fois, car les processeurs que nous avons vu précédemment sont de ce type. Mais nous verrons dans quelques chapitres qu'il existe des processeurs dits superscalaires, qui sont capables d'émettre plusieurs instructions par cycle. Dans ce cas, la ''scheduler'' a un seul port de lecture. Un processeur superscalaire, quant à lui, doit avoir un port de lecture par unité de calcul, ce qui fait beaucoup plus. Les ''schedulers'' sont composées d''''entrées''', des mots mémoire qui stockent une instruction. Une instruction réserve une entrée après son décodage et la libère dès qu'elle est envoyée aux unités de calcul. Une entrée contient l'opcode (les signaux de commande à envoyer à l'ALU), le registre de destination du résultat, les registres de chaque opérande, et éventuellement des signaux de commande en plus. De plus, chaque opérande est couplée à un bit de disponibilité, qui indique si elle est disponible. Quand un opérande est écrit dans les registres, le bit de présence correspondant est mis à jour. Enfin, chaque entrée possède un bit ''empty'' qui indique si elle est vide, cette information étant utile pour réserver des entrées. [[File:Entrée d'une station de réservation - sans les tags.png|centre|vignette|upright=3|Entrée d'un ''scheduler'']] ===Les stations de réservation=== Les '''stations de réservation''' sont des ''scheduler'' particulières, qui sont capables de mémoriser les opérandes des instructions. Les entrées des stations de réservation sont identiques à celle des autres ''scheduler'', si ce n'est que les opérandes de l'instruction sont enregistrés directement dans des champs séparés. Il y a deux champs, un par opérande, pour stocker l'opérande elle-même, lue depuis les registres ou obtenue via le réseau de contournement. Notons que les champs pour les opérandes viennent en plus des champs pour les noms de registres, encore que les deux peuvent être fusionnés si on veut optimiser le tout. [[File:Entrée d'une station de réservation.png|centre|vignette|upright=3|Entrée d'une station de réservation.]] Précisons que la terminologie n'est pas très fiable. Les termes "''scheduler''" et "station de réservation" ne regroupent pas du tout la même chose d'un papier de recherche à l'autre, d'un bouquin à l'autre, d'un chercheur à l'autre, d'un ingénieur à l'autre, d'un professeur à l'autre. Le terme initial vient pourtant de l'article original sur l'algorithme de Tomasulo, où il désignait un ''scheduler'' associée à une unité de calcul précise. Mais le terme a ensuite été réutilisé, ce qui fait que certains processeurs avec plusieurs unités de calcul sont décrits comme ayant une unique station de réservation. En bref : c'est le bazar ! Mais nous en reparlerons dans le chapitre sur le renommage de registres, car c'est la place idéale pour les aborder. Toujours est-il que j'ai fait le choix de confondre les concepts de ''scheduler'' et de station de réservation avec les concepts de '''lecture avant émission''' et de '''lecture après émission'''. La différence entre les deux est que les registres sont lus après émission avec un ''scheduler'', avant avec des stations de réservation. Dans le cas "avant émission", les opérandes sont mémorisés dans la station de réservation. Et cette différence a une influence sur le pipeline du processeur, le banc de registres et tout ce qui s'en suit. Un désavantage de la lecture avant émission est qu'il faut stocker les opérandes après lecture, ici dans les stations de réservation. Mais un avantage est que le banc de registre a besoin de moins de ports de lecture, car une bonne partie des opérandes sont fournies par le système de contournement. Nous verrons cela dans le détail dans le chapitre sur les processeurs superscalaires. [[File:Processeur avec plusieurs ''scheduler''.png|centre|vignette|upright=2.5|Lecture après émission.]] [[File:Read Before Issue.png|centre|vignette|upright=2.5|Lecture avant émission.]] ===La logique d'éveil et de sélection=== Dans le cas qui va suivre, on suppose que le processeur ne peut émettre qu'une instruction à la fois. Chaque cycle, une instruction est sélectionnée et est envoyée dans le chemin de données, soit à une ALU, soit à une unité d'accès mémoire. La sélection d'une instruction est effectuée par l'unité d'émission, qui est aussi appelée le '''''scheduler'''''. Elle gère la disponibilité des opérandes et la disponibilité des unités de calcul adéquate. Le choix de l'instruction émise doit être le plus pertinent possible, pour des raisons de performances. Pour le premier point, l'unité d'émission détermine quelles instructions sont candidates pour l'émission. Les ''instructions candidates'' sont celles dont tous les opérandes sont prêts. Le processeur contient un circuit qui détecte les instructions candidates : la '''logique d’éveil''' (''wake-up logic''). Une fois que la logique d'éveil a fait son travail, une instruction est choisie pour s’exécuter en fonction de la disponibilité des unités de calcul adéquates. Ce rôle est dévolu à un circuit qu'on appelle la '''logique de sélection''', ou ''select logic''. [[File:Fonctionnement complet de la logique d’émission.jpg|centre|vignette|upright=1.5|Fonctionnement complet de la logique d’émission.]] La logique de sélection doit gérer le fait que les unités de calcul du processeur ne sont pas toutes identiques. Déjà, un processeur a généralement des unités séparées pour les instructions entières et flottantes, des unités spécialisées dans les accès mémoire, parfois des unités spécialisées pour les branchements. Une instruction doit être attribuée à la bonne unité de calcul, on ne doit pas envoyer une instruction entière dans une unité de calcul flottante. De plus, parmi les unités de calcul entières, toutes ne sont pas identiques. Par exemple, il est fréquent d'avoir plusieurs unités de calcul spécialisées dans les opérations simples (additions, soustractions, opérations logiques) avec une unité pour les multiplications/divisions séparées, parfois une unité spécialisée pour les décalages/rotations, etc. Là encore, allouer la bonne instruction à la bonne ALU est complexe. Plus les unités de calcul sont hétérogènes, plus la logique de sélection est compliquée. Les logiques d'éveil comme de sélection sont assez complexes. Comme on le verra plus bas, la logique de sélection la plus simple, qui gère une seule unité de calcul, est basée sur un encodeur à priorité couplé à d'autres circuits. Et pour gérer plusieurs ALUs, il faut mettre des encodeurs en cascade. Le résultat est que même en prenant une logique de sélection simple, elle sera assez lente et gourmande en circuits. Aussi, la logique de sélection met souvent un cycle d'horloge entier pour faire son travail, elle a son propre étage de pipeline attribué. La logique d'éveil est dans le même cas, ce qui fait qu'émettre une micro-opération demande deux cycles d'horloge. Le défaut est que cela rajoute des cycles d'horloges entre la ''scheduler'' et l'ALU, ce qui complique la gestion du pipeline. Ces cycles de retard sont à prendre en compte au moment d'émettre les instructions, les ''scheduler'' doit en tenir compte pour des performances optimales. Sans tenir compte de ces cycles de retard, les instructions arrivent en retard de quelques cycles à l'ALU, cycles de retard durant lesquels l'ALU n'a pas fait de calcul et a été sous-utilisée, sans compter que le système de contournement n'est pas utilisé au mieux. Et le problème est encore plus important sur les processeurs avec des stations de réservation, qui utilisent la "lecture après émission" : cela rajoute un cycle d'horloge en plus, un temps de retard en plus. ===La logique d'éveil : l'émission anticipée=== La logique d'éveil doit tenir compte du fait qu'il y a plusieurs étages entre l'émission et l'exécution sur une unité de calcul. Par exemple, un processeur a souvent entre un et à cinq étages entre la file d'attente et les unités de calcul. Il faut lire les registres, gérer le contournement, et cela peut prendre quelques cycles d'horloge. Sur le Pentium 4, on trouve 6 étages entre la fenêtre d’instruction et l'entrée de l'ALU. Si les micro-opérations sont émises quand les opérandes sont disponibles, il y aura un délai de quelques cycles avant qu'elles atteignent l'ALU. Alors qu'idéalement, on souhaiterait que la micro-opération atteigne l'ALU dès que ses opérandes sont disponibles, pour profiter des techniques de contournement. Pour cela, la logique d'éveil émet les instructions quelques cycles en avance pour qu'elles arrivent au bon moment. Il s'agit d'une technique d''''émission anticipée''', dont nous avions parlé dans le chapitre sur le contournement. : Il faut noter que le problème se pose plus avec des ''scheduler'' qu'avec des stations de réservation. Les premières ont un étage en plus entre émission et ALU, vu qu'il faut lire des registres après l'émission. L'émission anticipée demande d'émettre un signal d'éveil en avance de quelques cycles, pile au bon moment. Par exemples, si on a deux étages entre l'ALU et l'unité d'émission, le signal de réveil sera généré deux cycles avant que le résultat soit effectivement calculé. L'implémentation varie, mais deux solutions sont possibles. La première est de générer le signal d'éveil dans l'ALU, ce qui n'a de sens que pour les opérations comme les multiplications ou les divisions, qui prennent plusieurs cycles. Une autre technique génère le signal de réveil dans une structure centralisée, spécialisée dans la génération des signaux d'éveil. L'unité de composée d'un registre à décalage par registre. Imaginons qu'une instruction est émise, que cette instruction mette N cycles à s'exécuter, et qu'elle écrive dans un registre de destination. L'unité sélectionne alors le registre à décalage associé au registre de destination, et met le bit numéro N à 1. Le registre décalé d'un cran à chaque cycle. Quand le bit sortant est un 1, alors le signal de validité pour l'opérande est généré. L'émission anticipée marche bien si l'instruction a une durée fixe, connue à l'avance. Et autant c'est le cas pour les instructions arithmétiques et logiques, autant ce n'est pas le cas pour les accès mémoire. Les accès mémoire ont une latence variable : quelques cycles pour un succès de cache, plusieurs dizaines de cycles pour un défaut de cache L1, pas loin de la centaine pour un défaut de cache L2, etc. Et cela pose des problèmes pour l'émission anticipée. L'émission en avance pour les accès mémoire est purement spéculative : le processeur émet des instructions en supposant que la lecture entrainera un succès de cache, quitte à annuler l'instruction en cas de défaut de cache. Mais faire ainsi demande non seulement d'annuler les instructions émises en avance, mais aussi de ne pas retirer les instructions émises en avance de la ''scheduler''. Elles sont émises, mais une copie de sauvegarde est conservée dans la ''scheduler''. Si le processeur détecte un défaut de cache, il peut alors ré-exécuter l'instruction. S'il détecte un succès de cache, les instructions lecture-dépendante sont retirées de la ''scheduler'', la copie de sauvegarde est devenue inutile et est donc jetée. ===La logique de sélection : âge ou position ?=== La logique de sélection est primordiale pour de bonnes performances. Il existe deux méthodes principales pour sélectionner l'instruction à exécuter. La première est la plus simple : elle se base sur lé numéro de l'entrée. En effet, un ''scheduler'' est avant tout une sorte de mémoire, un mix entre mémoire associative, mémoire RAM, et FIFO. Et chaque entrée a un numéro, une adresse mémoire. Nous parlerons de numéro dans ce qui suit, car ce sera plus simple, le terme d'adresse mémoire étant peut-être un peu exagéré dans le contexte des ''scheduler''. Toujours est-il que la ''scheduler'' est adressable dans le sens où on peut lui envoyer le numéro de l'entrée voulue, et la fenêtre d’instruction renvoie le contenu de l'entrée sur son port de lecture. Et c'est ce que fait la logique de sélection : elle génère le numéro de l'entrée à lire. Le numéro est alors envoyé sur l'entrée d'adresse de la fenêtre d’instruction, et elle fournit la micro-opération associée sur son port de lecture, son '''port d'émission'''. La première méthode de sélection, donc. Elle est basée sur le numéro de l'entrée. Si plusieurs entrées sont éveillées, la logique de sélection prend celle avec le plus petit numéro. Elle porte le nom de '''sélection par position''', sous-entendu position dans la ''scheduler''. Vous l'avez peut-être deviné, mais la logique de sélection est alors un encodeur à priorité. Le circuit de sélection ne se résume donc pas seulement à un encodeur à priorité, mais c'est le circuit central. L'avantage d'une telle méthode de sélection est qu'elle est simple à implémenter : un encodeur à priorité est un circuit connu, facile à implémenter. Mais on remarque un défaut : un encodeur est un circuit assez rapide, mais qui utilise beaucoup de transistors, beaucoup de portes logiques, surtout si on veut qu'il soit rapide. Ce qui explique que la logique de sélection ait son propre étage de pipeline rien que pour elle. La seconde méthode s'appelle la '''sélection par âge''', au nom assez transparent. L'idée est de privilégier l'émission de l'instruction la plus ancienne. Elle demande que la ''scheduler'' trie les micro-opérations par ordre d'insertion dans la ''scheduler'', ce qui en fait une pseudo-FIFO. Le tri est partiel, car les instructions peuvent sortir de la fenêtre d’instruction à tout moment. Compacter la ''scheduler'', à savoir regrouper toutes les entrées valides est une idée, mais elle est compliquée à implémenter. Aussi, elles préfèrent encoder des informations sur l'ordre d'émission dans chaque entrée. L'encodeur à priorité doit alors travailler non pas sur des nombres entiers liés à l'ordre d'insertion dans la pseudo-FIFO. Elle est encore plus gourmande en circuits que la méthode précédente. Les processeurs haute performance utilisent souvent des méthodes hybrides. Par exemple, les processeurs AMD de microarchitecture Bulldozer utilisaient une méthode intermédiaire. Ils utilisaient un ''scheduler'' couplée à un encodeur à priorité pour la sélection par position, mais complémentaient le tout avec une unité qui mémorisait l'instruction la plus ancienne dans la fenêtre d’instruction. Le mécanisme de sélection par âge était utilisé en priorité. Mais si l'instruction la plus ancienne n'était pas prête, le processeur basculait sur le mécanisme de sélection par position. ===La compaction des ''scheduler''=== À chaque cycle, les instructions décodées sont ajoutées dans la ''scheduler'', dans des entrées vides. Vu que les instructions quittent celle-ci dans le désordre, ces vides sont dispersés dans la ''scheduler'', ce qui pose problème pour déterminer où placer les nouvelles instructions. La solution la plus triviale consiste à conserver une liste des vides, mise à jour à chaque insertion ou émission d'instruction. Une autre solution consiste à éliminer les vides en compactant la ''scheduler'' à chaque cycle d'horloge. Des circuits se chargent de détecter les vides et de regrouper les instructions en un unique bloc. Il faut signaler que certains processeurs arrivent à se passer de cette étape de compactage, mais au prix de ''scheduler'' nettement plus complexes. Autre problème : quand il faut choisir quelle instruction émettre, il y a toujours plusieurs candidats. Si on choisit mal, des instructions restent en attente trop longtemps parce que d'autres instructions plus jeunes leur passent devant. Pour éviter cela, les instructions les plus vielles, les plus anciennes, sont prioritaires. Pour cela, on peut utiliser une FIFO un peu spéciale pour la ''scheduler''. Si les ajouts d'instruction se font dans l'ordre, les instructions ne quittent pas forcément la ''scheduler'' dans l'ordre imposé par une FIFO : les instructions restent triées dans leur ordre d'ajout, même s'il y a des vides entre elles. Dans ces conditions, il est préférable que le compactage conserve l'ordre FIFO des instructions. Dans ces conditions, l'instruction la plus ancienne est celle qui est située à l'adresse la plus faible : le circuit de sélection peut donc être fabriqué avec des encodeurs, et est relativement simple. ==Les ''schedulers'' basées sur une matrice de dépendances== L'implémentation la plus simple étend le fonctionnement d'un pipeline dynamique usuel. Rappelez-vous le chapitre sur les pipelines dynamiques. Nous avions vu que de tels pipelines émettaient une instruction par cycle, quitte à émettre des bulles de pipeline en cas de dépendance bloquante. Et il est possible d'améliorer leur unité d'émission pour qu'elle soit compatible avec l'exécution dans le désordre. ===Rappels sur le registre de réservation/disponibilité=== L'émission d'une instruction est gouvernée par un ''registre de réservation'' qui indique quels registres sont réservés par une instruction, et ceux qui sont libres. Un registre réservé est un registre qui sera écrit par une instruction en cours d'exécution, mais qui n'a pas encore écrit son résultat. Les instructions candidates doivent avoir leurs opérandes dans des registres libres. Sinon, c'est signe que leurs opérandes sont réservés en écriture, donc pas encore écrites, donc pas disponibles. Si une instruction candidate veut lire ce registre, c'est signe qu'il y a une dépendance RAW : elle veut lire un registre réservé, qui est destiné à être écrit par une instruction en vol. Si elle veut écrire, c'est signe qu'elle veut écrire dans un registre où une autre instruction veut écrire : c'est une dépendance WAW. Dans les deux cas, l'instruction n'est pas émise. Le registre de réservation encode les registres réservés comme suit : chaque bit est associé à un registre. Le bit numéro 0 est associé au registre numéro 0, le bit numéro 1 au registre numéro 1, etc. Là, En clair, les numéros de registres réservés sont encodés en représentation non pas binaire, mais en représentation ''one-hot'' (vue au premier chapitre). {|class="wikitable" |+ Registre de réservation |- ! Registre 7 !! Registre 6 !! Registre 5 !! Registre 4 !! Registre 3 !! Registre 2 !! Registre 1 !! Registre 0 |- | 0 || 0 || 1 || 0 || 0 || 1 || 0 || 0 |} Avant d'émettre une instruction, l'unité d'émission extrait les registres opérande/destination et les convertis dans la même représentation que le registre de réservation, à savoir en représentation ''one-hot''. Le circuit de traduction binaire vers ''one-hot'' est, pour rappel, un simple décodeur. Puis, on fait un OU logique entre les sorties des décodeurs. Le résultat est un masque qui indique quels registres sont lus par l'instruction, encodé en représentation ''one-hot''. Appelons-le le '''masque d'opérandes'''. Le masque est alors comparé au registre de réservation pour vérifier si l'instruction peut être émise. [[File:Unité d'émission simple, dans l'ordre.png|centre|vignette|upright=2|Unité d'émission simple, dans l'ordre]] Si l'émission est autorisée, le registre de réservation est là aussi mis à jour. Le registre de réservation est aussi mis à jour dès qu'une instruction enregistre son résultat dans les registres, ou alors dès qu'il est disponible pour le contournement. Le bit associé au registre repasse alors à 0 (ou à 1). Sans contournement, la mise à jour se fait alors à la toute fin de l'instruction, quand elle se termine, lors de la dernière étape d'enregistrement, à la fin de son pipeline. Avec, elle se fait quand l'instruction quitte l'unité de calcul. ===L'extension à l'exécution dans le désordre : l'éveil par matrice de bits=== La différence entre un pipeline dynamique et l'exécution dans le désordre est que l'on passe d'une instruction à émettre à plusieurs. Plusieurs instructions sont mises en attente dans un ''scheduler'', et y attendent leur tour. L'idée est alors d'envoyer le registre de disponibilité à toutes les entrées, à toutes les instructions en attente. Ainsi, on sait quelles sont les instructions qui peuvent s'exécuter et celles qui ne le peuvent pas. L'implémentation est assez simple, elle ressemble beaucoup à l'implémentation d'un pipeline dynamique simple, si ce n'est que des circuits sont dupliqués. L'implémentation utilise des ''scheduler'' légèrement différentes de celles introduites plus haut. Elles n'utilisent notamment pas de bits de disponibilité, mais autre chose. Lorsqu'une instruction est ajoutée à la ''scheduler'', le masque de disponibilité des opérandes est stocké dans la ''scheduler''. A chaque cycle, le registre de disponibilité est envoyé à toutes les entrées, et est comparé avec tous les masques de disponibilité des opérandes. Si une comparaison renvoie un 1, alors l'instruction de l'entrée est une instruction candidate à l'émission. [[File:Unité d'émission dans le désordre basée sur un registre de disponibilité.png|centre|vignette|upright=2.5|Unité d'émission dans le désordre basée sur un registre de disponibilité]] L'ensemble est implémenté avec l'aide d'une '''matrice de bits''', où chaque ligne correspond à une entrée et chaque colonne à un registre. À chaque croisement entre une ligne et une colonne, on trouve un bit. Si le bit de la ligne n et de la colonne m est à 1, cela veut dire : l'instruction dans l'entrée n a besoin de lire le registre m. S’il est à 0, alors cela veut dire que l'instruction stockée dans la ligne n'a pas besoin de la donnée dans le registre m. [[File:Planificateur à matrice de bits.jpg|centre|vignette|upright=2|Planificateur à matrice de bits.]] Lorsqu'une instruction réserve une entrée, elle initialise la ligne en fonction des registres qu'elle souhaite lire. Pour vérifier si une instruction a ses opérandes prêts, le processeur compare le registre de disponibilité à la ligne associée à l'instruction/entrée. A chaque intersection ligne-colonne, se trouve un comparateur de 1 bit, qui détecte si le registre est demandé et disponible. Les résultats de cette porte sont ensuite envoyés à une porte ET, qui fait le gros du travail. [[File:Logique de détection de la disponibilité d'une instruction.jpg|centre|vignette|upright=2|Logique de détection de la disponibilité d'une instruction.]] ==Les ''scheduler'' basées sur une mémoire associative== Les processeurs modernes utilisent une mémoire associative pour la ''scheduler''. Les mémoires associatives ont été abordées il y a quelques chapitres, mais faisons quelques rappels. Les mémoires associatives servent à accélérer la recherche de données dans un ensemble. Or, un ''scheduler'' vérifie régulièrement si chaque entrée est prête. Il s'agit d'un processus de recherche d'une instruction qui respecte une condition bien précise dans la mémoire, ce qui fait que les mémoires associatives sont donc tout indiquées. Comme vous le savez, les signaux de commande d'une instruction sont propagés avec celle-ci dans le pipeline, le nom du registre de destination ne faisant pas exception. Le nom de registre est envoyé à la ''scheduler'' lors de l'écriture du résultat dans les registres. S'il y a correspondance, l'opérande est disponible et son bit de disponibilité est mis à 1. On peut adapter cette méthode pour tenir compte du contournement assez simplement. [[File:Détection des dépendances par propagation du registre de destination.png|centre|vignette|upright=2|Détection des dépendances par propagation du registre de destination.]] En conséquence, le circuit de détection des dépendances est constitué d'un grand nombre de comparateurs : un par champ « nom de registre » dans chaque entrée. La logique d'éveil/''wake up'' regroupe tous les comparateurs, la logique de sélection est un circuit situé en-dehors de la mémoire associative. Les entrées sont dans la mémoire associative elle-même. [[File:Gestion des bits de validité.png|centre|vignette|upright=2|Gestion des bits de validité.]] L'implémentation la plus simple est celle du schéma précédent, où on utilise une mémoire associative unique. Une version plus élaborée sépare la ''scheduler'' en deux parties : une mémoire qui mémorise les registres des opérandes, une autre mémoire pour le reste. La mémoire pour les registres opérandes est la mémoire associative proprement dite, c'est elle qui est associée aux comparateurs, à la logique de ''wake-up''/réveil, etc. Par contre, l'autre mémoire est une mémoire RAM simplifiée, qui mémorise les informations qui n'ont pas besoin des comparateurs. L'opcode de l'instruction est là-dedans, par exemple. La ''scheduler'' est donc une sorte de mémoire associative améliorée. Il se trouve que c'est aussi le cas du ROB. Et il est possible de fusionner le tampon de ré-ordonnancement avec la ''scheduler'' dans une structure unique. La différence avec un ''scheduler'' normal est que les entrées sont libérées non pas quand l'instruction est exécutée/émise, mais quand elle termine son exécution et quitte le ROB. La ''scheduler'' incorpore des bits dans chaque entrée, pour savoir si la µops associée a été émise et est en cours de traitement dans les ALUs. La méthode a notamment été utilisée sur les processeurs d'architecture K6 d'AMD. Le tout donnait une structure appelée le '''DRIS''' (''deferred scheduling register renaming instruction shelf''). Les processeurs PA 8000 de HP étaient aussi vraisemblabment dans ce cas, aussi. ===Les optimisations de la consommation d'énergie : la désactivation des portions inutilisées=== Le problème avec des ''scheduler'' de ce type est leur forte consommation énergétique, ainsi que le grand nombre de portes logiques utilisées, qui deviennent prohibitifs pour des ''scheduler'' un peu grosses. Pour résoudre ce problème, certains ont optimisé les comparateurs. D'autres ont tenté de profiter du fait que la majorité des bits dans les entrées sont composés de zéros. Bref, les optimisations purement matérielles sont légion. Une première solution est de désactiver les entrées qui sont inutilisées, vides, sans instruction. Pour cela, on fait précéder les comparateurs par un circuit qui les connecte ou déconnecte des lignes de bit. Le circuit est commandé par le bit ''empty'' qui indique si une entrée est vide ou non. L'avantage est que la consommation d'énergie de la ''scheduler'' devient alors proportionnelle au nombre d'entrées non-vides, et non au nombre d'entrées total. Du moins, en apparence, les entrées non-utilisées doivent quand même être alimentées pour fonctionner, mais l'activité de comparaison disparait dans les entrées vides. Il est possible d'étendre cette technique aux entrées dont les opérandes sont prêts. Les gains sont généralement assez bons, avec une réduction de consommation variant entre 30 et 50%, avec une implémentation très simple et très économe en circuits. Une autre solution, assez simple à mettre en place, consiste à désactiver une partie de la ''scheduler'' sin elle est inutilisée. Pour cela, il faut segmenter la ''scheduler'' avec la technique du ''wire partitionning''. Pour rappel, un ''scheduler'' est une mémoire associative. Et comme toute mémoire associative, elle contient des fils, les lignes de bit, qui relient les entrées/sorties à toutes les cellules mémoire. Plus une ligne de bit est longue, plus elle consomme d'énergie et plus le temps de lecture/écriture est long. L'idée est de segmenter les lignes de bits en plaçant des répéteurs qui recopient la tension d'un segment au suivant. Les répéteurs sont des tampons trois-états, ce qui permet de déconnecter les portions inutilisées de la ligne de bit. Ce faisant, la ''scheduler'' est découpée en segments, qui peuvent être désactivés si besoin. S'il y a peu d'instructions chargées dans la ''scheduler'', les portions inutilisées sont désactivées. La technique marche d'autan mieux si les instructions sont compactées au début de la ''scheduler''. [[File:Wire partitionning.png|centre|vignette|upright=2|Wire partitionning]] Tout le problème est de savoir quelles portions désactiver. La technique est assez simple si la ''scheduler'' est compactée, à savoir si toutes les instructions sont régulièrement regroupées au début de la mémoire CAM. Mais même avec cette optimisation, la décision de désactiver une portion de la ''scheduler'' n'est pas à prendre à la légère. Il ne faut pas désactiver une portion contenant des instructions pouvant être émise sous peu. La décision dépend de paramètres variés : proportion d'entrée vides, quantité d'entrées récemment activées/désactivées récemment, présences d'entrées avec un ''match'' d'opérandes récent, etc. Il est important de préciser que les techniques en question fonctionnent aussi sur les autres types de ''scheduler'', qui ne sont pas basées sur des mémoires associatives. Nous allons voir celles-ci dans la suite du chapitre, mais gardez à l'esprit que ces optimisations, à savoir désactiver les entrées vides/prêts et partitionner la ''scheduler'', sont des optimisations générales qui marchent avec presque tout. ===L'ajout d'une FIFO pour les instructions déjà prêtes à l'émission=== D'autres techniques permettent de réduire aussi bien le cout en circuits que la consommation d'énergie de la ''scheduler''. L'idée est d'utiliser une mémoire associative quand elle est réellement nécessaire, mais d'utiliser un ''scheduler'' "normale" dès que possible. La méthode la plus simple tient compte du fait que certaines µopsont déjà toutes leurs opérandes de disponibles à l'émission, mais doivent quand même être mises en attente, parce que l'ALU adéquate est occupée, parce que des dépendances WAW/WAR sont encore là, ou pour tout autre raison. Dans ce cas, elles sont mises en attente non pas dans la ''scheduler'', mais dans une mémoire FIFO toute simple. L'idée est qu'au lieu d'avoir une énorme mémoire associative pour la ''scheduler'', on déplace quelques entrées dans une petite FIFO annexe. Le résultat est un gain d'énergie et de circuits, au prix d'une perte de performance mineure. La perte de performance en question se manifeste si aucune instruction n'a ses opérandes de prêtes à l'émission : le programme n'utilise pas la FIFO et voit alors un ''scheduler'' plus petite. Une amélioration de cette technique tient compte du fait que certaines instructions sont dans un cas intermédiaire. Elles ont déjà un opérande de prête lors de l'émission, mais pas l'autre. Le nombre d'opérandes varie suivant l’instruction : certaines n'ont besoin que d'un seul opérande. De plus, il arrive qu'une opération tout juste décodée ait déjà un ou plusieurs de ses opérandes de prêts. Cette constatation permet d'éviter d'utiliser des comparateurs pour les opérandes déjà prêts. Par exemple, on peut parfaitement utiliser trois ''scheduler'' : * une pour les instructions dont tous les opérandes sont prêts, mais qui sont quand même mises en attente, sans comparateur ; * une pour les instructions dont un seul opérande manque, qui n'utilise qu'un comparateur par entrée ; * une pour les instructions dont deux opérandes manquent à l'appel, qui utilise deux comparateurs par entrée. C'est beaucoup plus économique que d'utiliser une seule grosse ''scheduler'' qui contiendrait autant d'entrées que les trois précédentes réunies, avec deux comparateurs par entrée. Certains sont même allés plus loin, et ont proposé de supprimer la ''scheduler'' avec deux opérandes par entrée. Les instructions dont deux opérandes sont inconnus au décodage sont stockées dans la ''scheduler'' pour instructions avec un comparateur par entrée. Un circuit de prédiction se charge alors de prédire l'opérande manquant, cette prédiction étant vérifiée plus loin dans le pipeline. Il serait cependant étonnant qu'une telle proposition ait donné lieu à la moindre implémentation réelle. ===Les optimisations de la consommation d'énergie avancées=== D'autres chercheurs ont conservé un ''scheduler'' unique, avec autant de comparateurs par entrée qu'il y a d'opérandes possibles par instruction. Simplement, le processus de détection des opérandes prêts est légèrement ralenti : on ne vérifie qu'un opérande par cycle. Pour vérifier les deux opérandes d'une entrée, on doit attendre deux cycles. Enfin, certains chercheurs ont proposé des ''scheduler'' segmentées. Les instructions circulent à chaque cycle d'un segment vers le suivant : en conséquence, certains segments conservent les instructions les plus anciennes, un autre les instructions les plus jeunes, etc. Seul le denier segment, celui qui contient les instructions les plus vielles, peut émettre une instruction : la détection des opérandes se fait seulement dans le dernier segment, qui contient les instructions les plus anciennes. On économise ainsi beaucoup de comparateurs. Certains chercheurs ont tenté de pipeliner l'étape de sélection des opérandes, ainsi que l'étage d'arbitrage. Mais en faisant cela, il faut plusieurs cycles pour détecter qu'une instruction a ses opérandes prêts, ce qui pose problème face à de nombreuses dépendances RAW. Pour éviter de trop perdre en performances, certains chercheurs ont décidé d'utiliser des techniques pour prédire quelles seront les instructions dont les opérandes seront bientôt prêts. Si détecter qu'une instruction est prête prend n cycles, le processeur devra tenter de prédire la future disponibilité des opérandes n cycles en avance pour obtenir des performances optimales. ===Remplacer la mémoire associative par une RAM=== Une autre optimisation possible est de remplacer la ''scheduler'' par une mémoire RAM, dont chaque mot mémoire correspondrait à une entrée. Une telle optimisation permet en théorie de se passer des comparateurs associés à chaque entrée, mais au prix de l'ajout de circuits annexes potentiellement couteux. La première de ces techniques, la '''recherche directe par étiquette''' (direct tag search) fut créée par Weiss et son collègue Smith. Ils cherchaient à améliorer l'algorithme de Tomasulo, un algorithme qu'on expliquera dans quelques chapitres. Rappelons que chaque instruction produit un résultat, qui devra être rapatrié dans une ou plusieurs entrées de la ''scheduler''. L'optimisation de la recherche directe par étiquette fonctionne dans le cas où le résultat de l'instruction n'est utilisé que par une seule entrée, et pas plusieurs. Le principe est simple : chaque champ « opérande » d'une entrée est adressable via le nom de registre de cet opérande. Pour faire le lien entre entrée et nom de registre, la recherche directe par étiquette ajoute une table de correspondances matérielle, une mémoire RAM qui mémorise les adresses des champs « opérande » des entrées. Les adresses envoyées dans cette mémoire sont les noms de registres des résultats. Lors de l'émission, la table de correspondances est mise à jour. Les numéros des champs « opérande » réservés lors de l'émission sont mémorisés dans les mots mémoire qui correspondent aux deux registres sources. Toutefois, une petite vérification est faite lors de l'émission : s'il y a déjà une correspondance dans la table pour un registre source, alors une autre instruction compte lire ce registre. Pour éviter d'écraser les données de l'instruction précédente dans la table de correspondances, l'émission de l'instruction est bloquée. [[File:Recherche directe par étiquette.png|centre|vignette|upright=2|Recherche directe par étiquette.]] ==Les ''schedulers'' avec préplanification== Avec la '''préplanification''' (''prescheduling''), le ''scheduler'' est composée de mémoires FIFO dans lesquelles les instructions sont triées dans l'ordre d'émission. Il n'y a pas de logique d’émission proprement dite, celle-ci se bornant à vérifier si l'instruction située au début de la FIFO peut s’exécuter. Par contre, le préplanificateur détecte les dépendances et en déduit où insérer les instructions dans le tampon d'émission, à l'endroit le plus adéquat. [[File:Préplanification.jpg|centre|vignette|upright=2|Préplanification.]] ===L'usage de FIFO multiples=== La technique de préplanification la plus simple utilise plusieurs FIFO. Quand une instruction a une dépendance avec une autre instruction, les deux sont placées dans la même FIFO. Pour cela, le préplanificateur détecte les chaines d'instructions dépendantes, et place les instructions dans la FIFO adéquate. A chaque cycle, l'unité d'émission lit une micro-opération dans chaque FIFO et vérifie si elle peut l'émettre. Si la micro-opération n'a pas ses opérandes disponibles, ou qu'une dépendance structurelle survient, alors la FIFO est bloquée. La micro-opération attend que la dépendance soit résolue, bloquant toutes les instructions précédentes. Mais les autres FIFO ne sont pas bloquées, laissant de la marge de manœuvre. [[File:Préplanification par FIFO multiples.png|centre|vignette|upright=1.5|Préplanification par FIFO multiples.]] ===La technique du tampon trié=== La technique du '''tampon trié''' trie les instructions selon le temps d'attente avant leur exécution. Les instructions qui sont censées s’exécuter bientôt sont insérées au tout début de la FIFO, tandis que les instructions qui s’exécuteront dans un long moment sont insérées vers la fin. Là encore, l'unité d'émission lit une micro-opération dans la FIFO, et détermine si elle peut être émise. Si une dépendance survient, l'émission est retardée, et la FIFO est bloquée. [[File:Préplanification par tampon trié.png|centre|vignette|upright=1.5|Préplanification par tampon trié.]] La technique a cependant quelques problèmes assez importants. Le premier problème est que la FIFO est bloquée lorsqu'une micro-opération ne peut être émise. Le second problème est que le temps avant exécution n'est pas toujours connu, notamment pour les instructions d'accès mémoire. Et cela se répercute sur les instructions dépendantes de celles-ci. Pour résoudre ce genre de problèmes, l'usage d'un pipeline à ''replay'' est possible, et est même l'une des meilleures solutions possible, malgré ses défauts. L'idée est que les lectures sont pré-planifiées en supposant qu'elles font un succès de cache L1. Si la prédiction est fausse, la lecture est ré-exécutée plusieurs cycles plus tard, en supposant qu'elle fait un succès dans le cache L2, et ainsi de suite. Elle est alors ré-insérée dans la FIFO, elle est pré-planifiée une seconde fois. Il en est de même si une micro-opération ne peut pas être émise : il suffit de la réinsérer dans la FIFO au bon endroit, en attendant que ses dépendances soient résolues. Ainsi, l'instruction fautive ne bloque pas la fenêtre d’instruction, et retente sa chance autant de fois qu'il le faut. [[File:Préplanification par fenêtre d’instruction scorebarodée.png|centre|vignette|upright=1.5|Préplanification par fenêtre d’instruction scorebarodée.]] Une autre solution utilise deux ''schedulers'' : une FIFO gérée par la préplanification, et une vraie ''scheduler'' pour les instructions dont le temps d'attente ne peut pas être déterminé. Il est possible de mettre cette dernière avant la préplanification, afin de gérer les temps d'attente des instructions d'accès mémoire. Quand le temps d'attente d'une lecture devient connu, ses instructions dépendantes sont gérées avec préplanification. [[File:Préplanification avec fenêtre d’instruction.png|centre|vignette|upright=2.5|Préplanification avec fenêtre d’instruction.]] ===Les ''scheduler'' avec allocation temporelle statique=== L''''allocation temporelle statique''' correspond à une technique utilisée sur les processeurs Cuzco de l'entreprise Condor. La technique en question a été présenté en 2025, mais des idées similaires ont été présentées dans la littérature académique. Elle ressemble beaucoup aux techniques de pré-planification, avec cependant quelques différences. L'idée est simple : le processeur dispose de plusieurs ''scheduler'', qui mettent en attente les micro-opérations. Lors de l'étape de renommage de registres, le processeur détermine dans combien de cycles d'horloge la micro-opération sera prête pour exécution. La micro-opération est alors mise en attente durant ce nombre de cycles, dans les ''scheduler'', puis est émise une fois ce nombre de cycles écoulés. Ce faisant, les ''scheduler'' n'ont pas besoin de détecter la disponibilité des opérandes à chaque cycle, pour chaque micro-opération en attente. Le ''timing'' de l'émission des micro-opérations est décidé à l'avance. L'implémentation exacte n'est pas connue, mais plusieurs solutions sont imaginables. Par exemple, la ''scheduler'' peut simplement être composée de plusieurs mémoires de petite taille, chacune contenant les micro-opérations destinées à être exécutées dans N cycles, N étant différent pour chaque mémoire. Une autre solution, plus réaliste, utilise un ''scheduler'' dans laquelle la micro-opération est couplée à des champs pour les opérandes, et un champ compteur. Le champ compteur est initialisé avec le nombre de cycles à attendre, et est décrémenté à chaque cycle d'horloge. Quand il atteint zéro, la micro-opération est émise. Vous remarquerez que la méthode ne marche que si toutes les micro-opérations prennent un nombre fixe de cycles d'horloge. Et autant c'est le cas pour les micro-opérations arithmétiques ou logiques, autant les accès mémoire ne rentrent pas dans ce cadre. En théorie, on ne sait pas combien de temps prendra un accès mémoire. Et cette incertitude se répercute sur les instructions dépendantes d'un accès mémoire. Pour éviter cela, le processeur réutilise un pipeline à ''replay'' tel que vu dans le chapitre précédent. L'unité de renommage de registre suppose que tout accès mémoire fait un succès de cache L1, et décide des ''timings'' d'émission sous cette hypothèse. Si une lecture subit un défaut de cache, elle est ré-exécutée, de même que toutes les instructions dépendantes. Pour cela, le registre de destination de la lecture est marqué comme invalide, grâce à un bit spécifique attaché au registre. Toute instruction qui lit un opérande invalide est elle aussi ré-executée de zéro. Pour simplifier, l'unité d'émission ressemble à une unité d'émission dans l'ordre, avec un registre de disponibilité, qu'on aurait amélioré pour aller au-delà de la simple détection des dépendances d'instruction. Pour déterminer les ''timings'' d'émission, à savoir quand émettre une micro-opération, le processeur utilise une unité d'émission à deux étages. Le premier étage est appelé le ''register scoreboard'', le second étage est appelé la ''Time Ressource Matrix''. Les deux étages communiquent entre eux, comme on va le voir, et leurs noms donnent une idée de ce qu'ils font. Le premier étage gère les dépendances de registres, le second gère les dépendances structurelles. Le premier étage est un registre de disponibilité amélioré, qui gère les dépendances de registre. Cet étage sait quand tel registre sera écrit, et donc que l'opérande écrit dedans sera disponible à partir de tel cycle d'horloge. Il le sait car l'étage suivant l'aura prévenu, mais laissons cela de côté pour le moment. Quand une micro-opération rentre dans cet étage, il vérifie les dépendances avec les registres et les micro-opérations antérieures. Vu qu'il sait quand les registres seront disponibles, il peut déterminer quand l'instruction pourra s'exécuter. Par exemple, si une micro-opération lit les deux registres R7 et R15, qui sont disponibles respectivement dans 5 et 7 cycles, le premier étage sait que la micro-opération devra attendre 7 cycles. Mais tout cela ne suffit pas à déterminer quand émettre une micro-opération. En effet, il fait aussi gérer les dépendances structurelles, ce qui est le boulot du second étage. Le second étage utilise pour cela une ''Time Ressource Matrix'', qui mémorise l'occupation de diverses "ressources", pour les 256 cycles d'horloge à venir. Les ressources en question sont les ports de lecture/écriture du banc de registre, les ALUs utilisées, si la micro-opération utilise l'unité mémoire, etc. Le second étage prend en entrée une micro-opération, détermine quelles "ressources" elle utilise, puis regarde leur disponibilité. Elle détecte alors les dépendances structurelles et détermine alors quand peut s'exécuter la micro-opération. Elle peut retarder l'émission de quelques cycles, si une dépendance structurelle est détectée. Une fois sortie du second étage, on sait quand la micro-opération va être émise, à quel cycle précisément. Et vu que la durée de l'instruction est fixe, on sait quand cette micro-opération va se terminer, quand son résultat sera disponible. Cela permet de mettre à jour la ''Time Ressource Matrix'', pour préciser que le port d'écriture sera occupé à tel moment. De plus, cette information est transmise au premier étage, qui sait alors quand est enregistré le résultat dans le registre de destination. C'est comme cela que le premier étage sait quand un registre est disponible : le second étage le prévient, quand il émet une instruction ! La ''Time Ressource Matrix''mémorise l'occupation des "ressources" pour les 256 cycles d'horloge à venir. Cependant, elle ne vérifie pas les dépendances pour les 256 cycles suivants. Quand elle reçoit une micro-opération, elle teste les dépendances structurelles pour seulement les 8 prochains cycles maximum. Si la micro-opération ne peut pas être émise pendant ces 8 cycles, le pipeline est bloqué, un ''pipeline stall'' est émis. Pour être plus précis, vu que le processeur peut décoder 8 micro-opérations en même temps, cela permet de ne consulter que 64 cycles d'horloge sur les 256. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les premiers processeurs Intel | prevText=Les premiers processeurs Intel | next=Le renommage de registres | nextText=Le renommage de registres }} </noinclude> a0hjgl6ujc9zzzu6s5lps6rip8q4d97 773623 773622 2026-09-29T21:02:23Z Mewtow 31375 /* La logique d'éveil : l'émission anticipée */ 773623 wikitext text/x-wiki Dans les chapitres précédents, nous avons parlé des techniques dites d''''émission dans l'ordre'''. L'idée est d’exécuter une nouvelle micro-opération à chaque cycle, dans des unités de calcul séparées. Les instructions sont émises consécutivement, mais les instructions s’exécutent en parallèle dans des unités de calcul séparées. Par contre, quand l'unité d'émission ne peut pas émettre une instruction, elle bloque tout le pipeline. Les instructions qui suivent sont elles aussi bloquées, elles doivent attendre leur tour, même si elles sont en capacité de s'exécuter. Les techniques d'exécution dans le désordre que nous allons voir dans ce chapitre corrigent ce point précis. Elles sont dites à '''émission dans le désordre'''. Elles se distinguent des précédentes sur un point précis : quand l'unité d'émission bloque l'émission d'une instruction, les instructions suivantes peuvent poursuivre. L'émission des instructions peut donc se faire dans le désordre, dans le sens où une instruction peut être émise alors qu'une instruction précédente ne l'est pas encore. Mais avant de poursuivre, quelques point niveaux terminologie : * L'émission dans le désordre est un terme parlant et assez précis. Malheureusement, la terminologie la plus utilisée par d''''exécution dans le désordre'''. Et nous utiliserons ce terme dans la suite du cours, histoire de ne pas trop dévier de la nomenclature habituelle. * Nous utiliserons parfois l'abréviation OOO pour parler d'exécution dans le désordre. L'abréviation est celle de ''Out Of Order Excution''. * Nous utiliserons aussi l'abréviation ''µop'' pour parler de micro-opération, ''µops'' au pluriel pour parler de plusieurs micro-opérations, ou des micro-opérations en général. L'exécution dans le désordre ne gère en effet que des µops, elle se situe après l'étape de décodage. Pour décrire comment est implémentée l'émission dans le désordre, il faut commencer par parler des processeurs sans. Les processeurs sans exécution dans le désordre ont une unité d'émission qui bloque tout le pipeline dès qu'une µop ne peut pas être émise. Pour limiter l'impact de ce blocage, quelques rares processeurs incorporent une '''file de micro-opération''', une mémoire FIFO qui met en attente les µops. Vu que c'est une mémoire FIFO, les µops sont émises dans l'ordre, à savoir l'ordre d'ajout, dans l'ordre de décodage. Le schéma ci-dessous illustre une telle file d'attente couplée à un ''scoreboard''. L'exécution dans le désordre améliore la file de µops sur un point : ce n'est plus une mémoire FIFO. Les µops sont insérées dans l'ordre, mais peuvent sortir dans le désordre (être émises dans le désordre). La file de µops devient alors un '''''scheduler''''', terme anglais que je ne compte pas traduire. Un terme équivalent est '''''scheduler''''', terme traduit directement de l'anglais ''instruction Window''. Terme assez trompeur, car elles mettent en attente des µops, pas des instructions. [[File:Différence file µops et fenêtres instruction.png|centre|vignette|upright=2|Différence file µops et ''schedulers'' ]] Le ''scheduler'' émet une µop dès que ses opérandes sont disponibles. Par disponible, on veut dire présent soit dans le réseau de contournement, soit dans les registres. Le ''scheduler'' détecte automatiquement quand les opérandes d'une µop sont disponibles, grâce à une unité d'émission intégrée. L'unité d'émission et le ''scheduler'' sont fusionnés ensemble, dans un seul circuit, mais nous allons dire qu'ils sont conceptuellement séparés pour le moment. A chaque cycle, l'unité d'émission consulte les µops en attente pour détecter lesquelles peuvent s'exécuter. Le ''scheduler'' est spécialement être conçue pour, c'est une sorte de mémoire associative très complexe, comme on le verra dans ce qui suit. [[File:OOO Issue.png|centre|vignette|upright=2.5|Exécution dans le désordre avec un ''scheduler'']] Une fois qu'une µop sort du décodeur d'instructions, elle est ajoutée en parallèle dans la ''scheduler'' et le ROB. La raison est que les µops quittent la ''scheduler'' dans le désordre, et qu'elles doivent être remises en ordre par la suite. Le ROB s'occupe de cette remise en ordre, mais il a besoin de savoir dans quel ordre les µops sont censées être, et cet ordre est celui du décodage. Aussi, pour remplir le ROB, la seule opportunité est en sortie de l'unité de décodage. Dans le cas où une instruction est décodée en plusieurs micro-opérations, elles sont toutes insérées en même temps dans la ''scheduler'' et le ROB, en tenant compte de leur ordre. L'implémentation la plus simple de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Les µops décodées sont accumulées dans le ''scheduler'', où elles attendent leur tour. La ''scheduler'' sert donc de file d'attente. Avant de poursuivre, précisons que les micro-opérations mémoire sont à part des autres, pour diverses raisons. Une de ces raisons est que les dépendances de données sont classées en deux types : les dépendances de registre et les dépendances d'adresse. Et les deux sont fondamentalement différentes. Autant on peut détecter les dépendances de registre lors de l'émission, autant c'est plus compliqué avec les dépendances d'adresse. De plus, rappelons que si les lectures peuvent s'exécuter dans le désordre, les écritures doivent s'exécuter dans l'ordre, ou du moins en donner l'illusion. Pour cela, le processeur remet les écritures dans l'ordre avec une sorte de mini-ROB intégré à l'unité mémoire, appelée la file d'écriture. Elle complémente le ROB, qui lui ne gère que les écritures dans les registres, mais les deux collaborent. La file d'écriture envoie une écriture à la mémoire RAM quand le ROB lui dit que c'est bon, les instructions précédentes sont terminées ''dans l'ordre du programme''. Les processeurs modernes ajoutent des techniques d'exécution dans le désordre des accès mémoire, mais nous les verrons dans un chapitre dédié. Elles permettent d'utiliser un ''scheduler'' unique, qui mémorise aussi les µops mémoire. Si elles sont mises en place, l'unité mémoire n'a pas besoin de file de µops séparée. L'idée est que les dépendances de registre sont traitées par la ''scheduler'', mais que l'unité mémoire gére les dépendances d'adresse. Les dépendances d'adresse sont gérées par des techniques de ''désambiguation mémoire'', qui auront droit à un chapitre dédié. [[File:Processeur avec exécution dans le désodre des accès mémoire.png|centre|vignette|upright=2|Processeur avec exécution dans le désodre des accès mémoire]] Les processeurs assez anciens n'autorisaient pas d'exécution dans le désordre des accès mémoire. Concrétement, les accs mémoire devaient se faire dans l'ordre, mais les autres µops pouvaient être exécutées dans le désordre. Il s'agit donc d'un ordre entre µops mémoire, pas entre µops mémoire et autres µops. Les µops entières et flottantes pouvaient être exécutées avant une µops mémoire qui est avant elle dans l'ordre du programme, ce n'est pas un problème. Pour garantir l'ordre des µops mémoire, l'unité mémoire est précédée par une file de micro-opérations séparée, pour forcer l'exécution dans l'ordre des accès mémoire. De plus, les µops mémoire ne peuvent pas utiliser la ''scheduler''. Dit autrement, la ''scheduler'' ne mémorise pas de µops mémoire. Après le décodage, les µops sont réparties soit dans la file de µops mémoire, soit dans la ''scheduler''. Le décodeur classe les µops suivant que ce sont des µops mémoire ou non, et les envoient à la bonne destination. Dans ce chapitre, on supposera que c'est cette solution qui est utilisée. [[File:Processeur avec émission dans l'ordre des accès mémoire.png|centre|vignette|upright=2|Processeur avec émission dans l'ordre des accès mémoire]] ==L'implémentation d'un ''scheduler'' : généralités== Un ''scheduler'' est une mémoire qui mémorise des micro-opérations. Elle est cependant plus complexe qu'une mémoire RAM ou qu'une FIFO et ressemble un petit peu à une mémoire cache. Elle dispose d'un port d'écriture et d'un port de lecture, au minimum. Le port d'écriture permet à l'unité de décodage d'insérer une micro-opération dedans, d'ajouter la micro-opération qui vient d'être décodée. Si une instruction machine est décodée en plusieurs micro-opération, deux possibilités. La première est de les insérer un par un, ce qui fait qu'on peut se contenter d'un seul port d'écriture. L'autre possibilité est de les ajouter en même temps, ce qui demande plusieurs ports d'écriture. Le port de lecture sert à émettre une instruction. On part du principe que la ''scheduler'' ne peut émettre qu'une seule instruction à la fois, car les processeurs que nous avons vu précédemment sont de ce type. Mais nous verrons dans quelques chapitres qu'il existe des processeurs dits superscalaires, qui sont capables d'émettre plusieurs instructions par cycle. Dans ce cas, la ''scheduler'' a un seul port de lecture. Un processeur superscalaire, quant à lui, doit avoir un port de lecture par unité de calcul, ce qui fait beaucoup plus. Les ''schedulers'' sont composées d''''entrées''', des mots mémoire qui stockent une instruction. Une instruction réserve une entrée après son décodage et la libère dès qu'elle est envoyée aux unités de calcul. Une entrée contient l'opcode (les signaux de commande à envoyer à l'ALU), le registre de destination du résultat, les registres de chaque opérande, et éventuellement des signaux de commande en plus. De plus, chaque opérande est couplée à un bit de disponibilité, qui indique si elle est disponible. Quand un opérande est écrit dans les registres, le bit de présence correspondant est mis à jour. Enfin, chaque entrée possède un bit ''empty'' qui indique si elle est vide, cette information étant utile pour réserver des entrées. [[File:Entrée d'une station de réservation - sans les tags.png|centre|vignette|upright=3|Entrée d'un ''scheduler'']] ===Les stations de réservation=== Les '''stations de réservation''' sont des ''scheduler'' particulières, qui sont capables de mémoriser les opérandes des instructions. Les entrées des stations de réservation sont identiques à celle des autres ''scheduler'', si ce n'est que les opérandes de l'instruction sont enregistrés directement dans des champs séparés. Il y a deux champs, un par opérande, pour stocker l'opérande elle-même, lue depuis les registres ou obtenue via le réseau de contournement. Notons que les champs pour les opérandes viennent en plus des champs pour les noms de registres, encore que les deux peuvent être fusionnés si on veut optimiser le tout. [[File:Entrée d'une station de réservation.png|centre|vignette|upright=3|Entrée d'une station de réservation.]] Précisons que la terminologie n'est pas très fiable. Les termes "''scheduler''" et "station de réservation" ne regroupent pas du tout la même chose d'un papier de recherche à l'autre, d'un bouquin à l'autre, d'un chercheur à l'autre, d'un ingénieur à l'autre, d'un professeur à l'autre. Le terme initial vient pourtant de l'article original sur l'algorithme de Tomasulo, où il désignait un ''scheduler'' associée à une unité de calcul précise. Mais le terme a ensuite été réutilisé, ce qui fait que certains processeurs avec plusieurs unités de calcul sont décrits comme ayant une unique station de réservation. En bref : c'est le bazar ! Mais nous en reparlerons dans le chapitre sur le renommage de registres, car c'est la place idéale pour les aborder. Toujours est-il que j'ai fait le choix de confondre les concepts de ''scheduler'' et de station de réservation avec les concepts de '''lecture avant émission''' et de '''lecture après émission'''. La différence entre les deux est que les registres sont lus après émission avec un ''scheduler'', avant avec des stations de réservation. Dans le cas "avant émission", les opérandes sont mémorisés dans la station de réservation. Et cette différence a une influence sur le pipeline du processeur, le banc de registres et tout ce qui s'en suit. Un désavantage de la lecture avant émission est qu'il faut stocker les opérandes après lecture, ici dans les stations de réservation. Mais un avantage est que le banc de registre a besoin de moins de ports de lecture, car une bonne partie des opérandes sont fournies par le système de contournement. Nous verrons cela dans le détail dans le chapitre sur les processeurs superscalaires. [[File:Processeur avec plusieurs ''scheduler''.png|centre|vignette|upright=2.5|Lecture après émission.]] [[File:Read Before Issue.png|centre|vignette|upright=2.5|Lecture avant émission.]] ===La logique d'éveil et de sélection=== Dans le cas qui va suivre, on suppose que le processeur ne peut émettre qu'une instruction à la fois. Chaque cycle, une instruction est sélectionnée et est envoyée dans le chemin de données, soit à une ALU, soit à une unité d'accès mémoire. La sélection d'une instruction est effectuée par l'unité d'émission, qui est aussi appelée le '''''scheduler'''''. Elle gère la disponibilité des opérandes et la disponibilité des unités de calcul adéquate. Le choix de l'instruction émise doit être le plus pertinent possible, pour des raisons de performances. Pour le premier point, l'unité d'émission détermine quelles instructions sont candidates pour l'émission. Les ''instructions candidates'' sont celles dont tous les opérandes sont prêts. Le processeur contient un circuit qui détecte les instructions candidates : la '''logique d’éveil''' (''wake-up logic''). Une fois que la logique d'éveil a fait son travail, une instruction est choisie pour s’exécuter en fonction de la disponibilité des unités de calcul adéquates. Ce rôle est dévolu à un circuit qu'on appelle la '''logique de sélection''', ou ''select logic''. [[File:Fonctionnement complet de la logique d’émission.jpg|centre|vignette|upright=1.5|Fonctionnement complet de la logique d’émission.]] La logique de sélection doit gérer le fait que les unités de calcul du processeur ne sont pas toutes identiques. Déjà, un processeur a généralement des unités séparées pour les instructions entières et flottantes, des unités spécialisées dans les accès mémoire, parfois des unités spécialisées pour les branchements. Une instruction doit être attribuée à la bonne unité de calcul, on ne doit pas envoyer une instruction entière dans une unité de calcul flottante. De plus, parmi les unités de calcul entières, toutes ne sont pas identiques. Par exemple, il est fréquent d'avoir plusieurs unités de calcul spécialisées dans les opérations simples (additions, soustractions, opérations logiques) avec une unité pour les multiplications/divisions séparées, parfois une unité spécialisée pour les décalages/rotations, etc. Là encore, allouer la bonne instruction à la bonne ALU est complexe. Plus les unités de calcul sont hétérogènes, plus la logique de sélection est compliquée. Les logiques d'éveil comme de sélection sont assez complexes. Comme on le verra plus bas, la logique de sélection la plus simple, qui gère une seule unité de calcul, est basée sur un encodeur à priorité couplé à d'autres circuits. Et pour gérer plusieurs ALUs, il faut mettre des encodeurs en cascade. Le résultat est que même en prenant une logique de sélection simple, elle sera assez lente et gourmande en circuits. Aussi, la logique de sélection met souvent un cycle d'horloge entier pour faire son travail, elle a son propre étage de pipeline attribué. La logique d'éveil est dans le même cas, ce qui fait qu'émettre une micro-opération demande deux cycles d'horloge. Le défaut est que cela rajoute des cycles d'horloges entre la ''scheduler'' et l'ALU, ce qui complique la gestion du pipeline. Ces cycles de retard sont à prendre en compte au moment d'émettre les instructions, les ''scheduler'' doit en tenir compte pour des performances optimales. Sans tenir compte de ces cycles de retard, les instructions arrivent en retard de quelques cycles à l'ALU, cycles de retard durant lesquels l'ALU n'a pas fait de calcul et a été sous-utilisée, sans compter que le système de contournement n'est pas utilisé au mieux. Et le problème est encore plus important sur les processeurs avec des stations de réservation, qui utilisent la "lecture après émission" : cela rajoute un cycle d'horloge en plus, un temps de retard en plus. ===La logique d'éveil : l'émission anticipée=== La logique d'éveil doit tenir compte du fait qu'il y a plusieurs étages entre l'émission et l'exécution sur une unité de calcul. Par exemple, un processeur a souvent entre un et à cinq étages entre la file d'attente et les unités de calcul. Il faut lire les registres, gérer le contournement, et cela peut prendre quelques cycles d'horloge. Sur le Pentium 4, on trouve 6 étages entre le ''scheduler'' et l'entrée de l'ALU. Si les micro-opérations sont émises quand les opérandes sont disponibles, il y aura un délai de quelques cycles avant qu'elles atteignent l'ALU. Alors qu'idéalement, on souhaiterait que la micro-opération atteigne l'ALU dès que ses opérandes sont disponibles, pour profiter des techniques de contournement. Pour cela, la logique d'éveil émet les instructions quelques cycles en avance pour qu'elles arrivent au bon moment. Il s'agit d'une technique d''''émission anticipée''', dont nous avions parlé dans le chapitre sur le contournement. : Il faut noter que le problème se pose plus avec des ''scheduler'' qu'avec des stations de réservation. Les premières ont un étage en plus entre émission et ALU, vu qu'il faut lire des registres après l'émission. L'émission anticipée demande d'émettre un signal d'éveil en avance de quelques cycles, pile au bon moment. Par exemples, si on a deux étages entre l'ALU et l'unité d'émission, le signal de réveil sera généré deux cycles avant que le résultat soit effectivement calculé. L'implémentation varie, mais deux solutions sont possibles. La première est de générer le signal d'éveil dans l'ALU, ce qui n'a de sens que pour les opérations comme les multiplications ou les divisions, qui prennent plusieurs cycles. Une autre technique génère le signal de réveil dans une structure centralisée, spécialisée dans la génération des signaux d'éveil. L'unité de composée d'un registre à décalage par registre. Imaginons qu'une instruction est émise, que cette instruction mette N cycles à s'exécuter, et qu'elle écrive dans un registre de destination. L'unité sélectionne alors le registre à décalage associé au registre de destination, et met le bit numéro N à 1. Le registre décalé d'un cran à chaque cycle. Quand le bit sortant est un 1, alors le signal de validité pour l'opérande est généré. L'émission anticipée marche bien si l'instruction a une durée fixe, connue à l'avance. Et autant c'est le cas pour les instructions arithmétiques et logiques, autant ce n'est pas le cas pour les accès mémoire. Les accès mémoire ont une latence variable : quelques cycles pour un succès de cache, plusieurs dizaines de cycles pour un défaut de cache L1, pas loin de la centaine pour un défaut de cache L2, etc. Et cela pose des problèmes pour l'émission anticipée. L'émission en avance pour les accès mémoire est purement spéculative : le processeur émet des instructions en supposant que la lecture entrainera un succès de cache, quitte à annuler l'instruction en cas de défaut de cache. Mais faire ainsi demande non seulement d'annuler les instructions émises en avance, mais aussi de ne pas retirer les instructions émises en avance de la ''scheduler''. Elles sont émises, mais une copie de sauvegarde est conservée dans la ''scheduler''. Si le processeur détecte un défaut de cache, il peut alors ré-exécuter l'instruction. S'il détecte un succès de cache, les instructions lecture-dépendante sont retirées de la ''scheduler'', la copie de sauvegarde est devenue inutile et est donc jetée. ===La logique de sélection : âge ou position ?=== La logique de sélection est primordiale pour de bonnes performances. Il existe deux méthodes principales pour sélectionner l'instruction à exécuter. La première est la plus simple : elle se base sur lé numéro de l'entrée. En effet, un ''scheduler'' est avant tout une sorte de mémoire, un mix entre mémoire associative, mémoire RAM, et FIFO. Et chaque entrée a un numéro, une adresse mémoire. Nous parlerons de numéro dans ce qui suit, car ce sera plus simple, le terme d'adresse mémoire étant peut-être un peu exagéré dans le contexte des ''scheduler''. Toujours est-il que la ''scheduler'' est adressable dans le sens où on peut lui envoyer le numéro de l'entrée voulue, et la fenêtre d’instruction renvoie le contenu de l'entrée sur son port de lecture. Et c'est ce que fait la logique de sélection : elle génère le numéro de l'entrée à lire. Le numéro est alors envoyé sur l'entrée d'adresse de la fenêtre d’instruction, et elle fournit la micro-opération associée sur son port de lecture, son '''port d'émission'''. La première méthode de sélection, donc. Elle est basée sur le numéro de l'entrée. Si plusieurs entrées sont éveillées, la logique de sélection prend celle avec le plus petit numéro. Elle porte le nom de '''sélection par position''', sous-entendu position dans la ''scheduler''. Vous l'avez peut-être deviné, mais la logique de sélection est alors un encodeur à priorité. Le circuit de sélection ne se résume donc pas seulement à un encodeur à priorité, mais c'est le circuit central. L'avantage d'une telle méthode de sélection est qu'elle est simple à implémenter : un encodeur à priorité est un circuit connu, facile à implémenter. Mais on remarque un défaut : un encodeur est un circuit assez rapide, mais qui utilise beaucoup de transistors, beaucoup de portes logiques, surtout si on veut qu'il soit rapide. Ce qui explique que la logique de sélection ait son propre étage de pipeline rien que pour elle. La seconde méthode s'appelle la '''sélection par âge''', au nom assez transparent. L'idée est de privilégier l'émission de l'instruction la plus ancienne. Elle demande que la ''scheduler'' trie les micro-opérations par ordre d'insertion dans la ''scheduler'', ce qui en fait une pseudo-FIFO. Le tri est partiel, car les instructions peuvent sortir de la fenêtre d’instruction à tout moment. Compacter la ''scheduler'', à savoir regrouper toutes les entrées valides est une idée, mais elle est compliquée à implémenter. Aussi, elles préfèrent encoder des informations sur l'ordre d'émission dans chaque entrée. L'encodeur à priorité doit alors travailler non pas sur des nombres entiers liés à l'ordre d'insertion dans la pseudo-FIFO. Elle est encore plus gourmande en circuits que la méthode précédente. Les processeurs haute performance utilisent souvent des méthodes hybrides. Par exemple, les processeurs AMD de microarchitecture Bulldozer utilisaient une méthode intermédiaire. Ils utilisaient un ''scheduler'' couplée à un encodeur à priorité pour la sélection par position, mais complémentaient le tout avec une unité qui mémorisait l'instruction la plus ancienne dans la fenêtre d’instruction. Le mécanisme de sélection par âge était utilisé en priorité. Mais si l'instruction la plus ancienne n'était pas prête, le processeur basculait sur le mécanisme de sélection par position. ===La compaction des ''scheduler''=== À chaque cycle, les instructions décodées sont ajoutées dans la ''scheduler'', dans des entrées vides. Vu que les instructions quittent celle-ci dans le désordre, ces vides sont dispersés dans la ''scheduler'', ce qui pose problème pour déterminer où placer les nouvelles instructions. La solution la plus triviale consiste à conserver une liste des vides, mise à jour à chaque insertion ou émission d'instruction. Une autre solution consiste à éliminer les vides en compactant la ''scheduler'' à chaque cycle d'horloge. Des circuits se chargent de détecter les vides et de regrouper les instructions en un unique bloc. Il faut signaler que certains processeurs arrivent à se passer de cette étape de compactage, mais au prix de ''scheduler'' nettement plus complexes. Autre problème : quand il faut choisir quelle instruction émettre, il y a toujours plusieurs candidats. Si on choisit mal, des instructions restent en attente trop longtemps parce que d'autres instructions plus jeunes leur passent devant. Pour éviter cela, les instructions les plus vielles, les plus anciennes, sont prioritaires. Pour cela, on peut utiliser une FIFO un peu spéciale pour la ''scheduler''. Si les ajouts d'instruction se font dans l'ordre, les instructions ne quittent pas forcément la ''scheduler'' dans l'ordre imposé par une FIFO : les instructions restent triées dans leur ordre d'ajout, même s'il y a des vides entre elles. Dans ces conditions, il est préférable que le compactage conserve l'ordre FIFO des instructions. Dans ces conditions, l'instruction la plus ancienne est celle qui est située à l'adresse la plus faible : le circuit de sélection peut donc être fabriqué avec des encodeurs, et est relativement simple. ==Les ''schedulers'' basées sur une matrice de dépendances== L'implémentation la plus simple étend le fonctionnement d'un pipeline dynamique usuel. Rappelez-vous le chapitre sur les pipelines dynamiques. Nous avions vu que de tels pipelines émettaient une instruction par cycle, quitte à émettre des bulles de pipeline en cas de dépendance bloquante. Et il est possible d'améliorer leur unité d'émission pour qu'elle soit compatible avec l'exécution dans le désordre. ===Rappels sur le registre de réservation/disponibilité=== L'émission d'une instruction est gouvernée par un ''registre de réservation'' qui indique quels registres sont réservés par une instruction, et ceux qui sont libres. Un registre réservé est un registre qui sera écrit par une instruction en cours d'exécution, mais qui n'a pas encore écrit son résultat. Les instructions candidates doivent avoir leurs opérandes dans des registres libres. Sinon, c'est signe que leurs opérandes sont réservés en écriture, donc pas encore écrites, donc pas disponibles. Si une instruction candidate veut lire ce registre, c'est signe qu'il y a une dépendance RAW : elle veut lire un registre réservé, qui est destiné à être écrit par une instruction en vol. Si elle veut écrire, c'est signe qu'elle veut écrire dans un registre où une autre instruction veut écrire : c'est une dépendance WAW. Dans les deux cas, l'instruction n'est pas émise. Le registre de réservation encode les registres réservés comme suit : chaque bit est associé à un registre. Le bit numéro 0 est associé au registre numéro 0, le bit numéro 1 au registre numéro 1, etc. Là, En clair, les numéros de registres réservés sont encodés en représentation non pas binaire, mais en représentation ''one-hot'' (vue au premier chapitre). {|class="wikitable" |+ Registre de réservation |- ! Registre 7 !! Registre 6 !! Registre 5 !! Registre 4 !! Registre 3 !! Registre 2 !! Registre 1 !! Registre 0 |- | 0 || 0 || 1 || 0 || 0 || 1 || 0 || 0 |} Avant d'émettre une instruction, l'unité d'émission extrait les registres opérande/destination et les convertis dans la même représentation que le registre de réservation, à savoir en représentation ''one-hot''. Le circuit de traduction binaire vers ''one-hot'' est, pour rappel, un simple décodeur. Puis, on fait un OU logique entre les sorties des décodeurs. Le résultat est un masque qui indique quels registres sont lus par l'instruction, encodé en représentation ''one-hot''. Appelons-le le '''masque d'opérandes'''. Le masque est alors comparé au registre de réservation pour vérifier si l'instruction peut être émise. [[File:Unité d'émission simple, dans l'ordre.png|centre|vignette|upright=2|Unité d'émission simple, dans l'ordre]] Si l'émission est autorisée, le registre de réservation est là aussi mis à jour. Le registre de réservation est aussi mis à jour dès qu'une instruction enregistre son résultat dans les registres, ou alors dès qu'il est disponible pour le contournement. Le bit associé au registre repasse alors à 0 (ou à 1). Sans contournement, la mise à jour se fait alors à la toute fin de l'instruction, quand elle se termine, lors de la dernière étape d'enregistrement, à la fin de son pipeline. Avec, elle se fait quand l'instruction quitte l'unité de calcul. ===L'extension à l'exécution dans le désordre : l'éveil par matrice de bits=== La différence entre un pipeline dynamique et l'exécution dans le désordre est que l'on passe d'une instruction à émettre à plusieurs. Plusieurs instructions sont mises en attente dans un ''scheduler'', et y attendent leur tour. L'idée est alors d'envoyer le registre de disponibilité à toutes les entrées, à toutes les instructions en attente. Ainsi, on sait quelles sont les instructions qui peuvent s'exécuter et celles qui ne le peuvent pas. L'implémentation est assez simple, elle ressemble beaucoup à l'implémentation d'un pipeline dynamique simple, si ce n'est que des circuits sont dupliqués. L'implémentation utilise des ''scheduler'' légèrement différentes de celles introduites plus haut. Elles n'utilisent notamment pas de bits de disponibilité, mais autre chose. Lorsqu'une instruction est ajoutée à la ''scheduler'', le masque de disponibilité des opérandes est stocké dans la ''scheduler''. A chaque cycle, le registre de disponibilité est envoyé à toutes les entrées, et est comparé avec tous les masques de disponibilité des opérandes. Si une comparaison renvoie un 1, alors l'instruction de l'entrée est une instruction candidate à l'émission. [[File:Unité d'émission dans le désordre basée sur un registre de disponibilité.png|centre|vignette|upright=2.5|Unité d'émission dans le désordre basée sur un registre de disponibilité]] L'ensemble est implémenté avec l'aide d'une '''matrice de bits''', où chaque ligne correspond à une entrée et chaque colonne à un registre. À chaque croisement entre une ligne et une colonne, on trouve un bit. Si le bit de la ligne n et de la colonne m est à 1, cela veut dire : l'instruction dans l'entrée n a besoin de lire le registre m. S’il est à 0, alors cela veut dire que l'instruction stockée dans la ligne n'a pas besoin de la donnée dans le registre m. [[File:Planificateur à matrice de bits.jpg|centre|vignette|upright=2|Planificateur à matrice de bits.]] Lorsqu'une instruction réserve une entrée, elle initialise la ligne en fonction des registres qu'elle souhaite lire. Pour vérifier si une instruction a ses opérandes prêts, le processeur compare le registre de disponibilité à la ligne associée à l'instruction/entrée. A chaque intersection ligne-colonne, se trouve un comparateur de 1 bit, qui détecte si le registre est demandé et disponible. Les résultats de cette porte sont ensuite envoyés à une porte ET, qui fait le gros du travail. [[File:Logique de détection de la disponibilité d'une instruction.jpg|centre|vignette|upright=2|Logique de détection de la disponibilité d'une instruction.]] ==Les ''scheduler'' basées sur une mémoire associative== Les processeurs modernes utilisent une mémoire associative pour la ''scheduler''. Les mémoires associatives ont été abordées il y a quelques chapitres, mais faisons quelques rappels. Les mémoires associatives servent à accélérer la recherche de données dans un ensemble. Or, un ''scheduler'' vérifie régulièrement si chaque entrée est prête. Il s'agit d'un processus de recherche d'une instruction qui respecte une condition bien précise dans la mémoire, ce qui fait que les mémoires associatives sont donc tout indiquées. Comme vous le savez, les signaux de commande d'une instruction sont propagés avec celle-ci dans le pipeline, le nom du registre de destination ne faisant pas exception. Le nom de registre est envoyé à la ''scheduler'' lors de l'écriture du résultat dans les registres. S'il y a correspondance, l'opérande est disponible et son bit de disponibilité est mis à 1. On peut adapter cette méthode pour tenir compte du contournement assez simplement. [[File:Détection des dépendances par propagation du registre de destination.png|centre|vignette|upright=2|Détection des dépendances par propagation du registre de destination.]] En conséquence, le circuit de détection des dépendances est constitué d'un grand nombre de comparateurs : un par champ « nom de registre » dans chaque entrée. La logique d'éveil/''wake up'' regroupe tous les comparateurs, la logique de sélection est un circuit situé en-dehors de la mémoire associative. Les entrées sont dans la mémoire associative elle-même. [[File:Gestion des bits de validité.png|centre|vignette|upright=2|Gestion des bits de validité.]] L'implémentation la plus simple est celle du schéma précédent, où on utilise une mémoire associative unique. Une version plus élaborée sépare la ''scheduler'' en deux parties : une mémoire qui mémorise les registres des opérandes, une autre mémoire pour le reste. La mémoire pour les registres opérandes est la mémoire associative proprement dite, c'est elle qui est associée aux comparateurs, à la logique de ''wake-up''/réveil, etc. Par contre, l'autre mémoire est une mémoire RAM simplifiée, qui mémorise les informations qui n'ont pas besoin des comparateurs. L'opcode de l'instruction est là-dedans, par exemple. La ''scheduler'' est donc une sorte de mémoire associative améliorée. Il se trouve que c'est aussi le cas du ROB. Et il est possible de fusionner le tampon de ré-ordonnancement avec la ''scheduler'' dans une structure unique. La différence avec un ''scheduler'' normal est que les entrées sont libérées non pas quand l'instruction est exécutée/émise, mais quand elle termine son exécution et quitte le ROB. La ''scheduler'' incorpore des bits dans chaque entrée, pour savoir si la µops associée a été émise et est en cours de traitement dans les ALUs. La méthode a notamment été utilisée sur les processeurs d'architecture K6 d'AMD. Le tout donnait une structure appelée le '''DRIS''' (''deferred scheduling register renaming instruction shelf''). Les processeurs PA 8000 de HP étaient aussi vraisemblabment dans ce cas, aussi. ===Les optimisations de la consommation d'énergie : la désactivation des portions inutilisées=== Le problème avec des ''scheduler'' de ce type est leur forte consommation énergétique, ainsi que le grand nombre de portes logiques utilisées, qui deviennent prohibitifs pour des ''scheduler'' un peu grosses. Pour résoudre ce problème, certains ont optimisé les comparateurs. D'autres ont tenté de profiter du fait que la majorité des bits dans les entrées sont composés de zéros. Bref, les optimisations purement matérielles sont légion. Une première solution est de désactiver les entrées qui sont inutilisées, vides, sans instruction. Pour cela, on fait précéder les comparateurs par un circuit qui les connecte ou déconnecte des lignes de bit. Le circuit est commandé par le bit ''empty'' qui indique si une entrée est vide ou non. L'avantage est que la consommation d'énergie de la ''scheduler'' devient alors proportionnelle au nombre d'entrées non-vides, et non au nombre d'entrées total. Du moins, en apparence, les entrées non-utilisées doivent quand même être alimentées pour fonctionner, mais l'activité de comparaison disparait dans les entrées vides. Il est possible d'étendre cette technique aux entrées dont les opérandes sont prêts. Les gains sont généralement assez bons, avec une réduction de consommation variant entre 30 et 50%, avec une implémentation très simple et très économe en circuits. Une autre solution, assez simple à mettre en place, consiste à désactiver une partie de la ''scheduler'' sin elle est inutilisée. Pour cela, il faut segmenter la ''scheduler'' avec la technique du ''wire partitionning''. Pour rappel, un ''scheduler'' est une mémoire associative. Et comme toute mémoire associative, elle contient des fils, les lignes de bit, qui relient les entrées/sorties à toutes les cellules mémoire. Plus une ligne de bit est longue, plus elle consomme d'énergie et plus le temps de lecture/écriture est long. L'idée est de segmenter les lignes de bits en plaçant des répéteurs qui recopient la tension d'un segment au suivant. Les répéteurs sont des tampons trois-états, ce qui permet de déconnecter les portions inutilisées de la ligne de bit. Ce faisant, la ''scheduler'' est découpée en segments, qui peuvent être désactivés si besoin. S'il y a peu d'instructions chargées dans la ''scheduler'', les portions inutilisées sont désactivées. La technique marche d'autan mieux si les instructions sont compactées au début de la ''scheduler''. [[File:Wire partitionning.png|centre|vignette|upright=2|Wire partitionning]] Tout le problème est de savoir quelles portions désactiver. La technique est assez simple si la ''scheduler'' est compactée, à savoir si toutes les instructions sont régulièrement regroupées au début de la mémoire CAM. Mais même avec cette optimisation, la décision de désactiver une portion de la ''scheduler'' n'est pas à prendre à la légère. Il ne faut pas désactiver une portion contenant des instructions pouvant être émise sous peu. La décision dépend de paramètres variés : proportion d'entrée vides, quantité d'entrées récemment activées/désactivées récemment, présences d'entrées avec un ''match'' d'opérandes récent, etc. Il est important de préciser que les techniques en question fonctionnent aussi sur les autres types de ''scheduler'', qui ne sont pas basées sur des mémoires associatives. Nous allons voir celles-ci dans la suite du chapitre, mais gardez à l'esprit que ces optimisations, à savoir désactiver les entrées vides/prêts et partitionner la ''scheduler'', sont des optimisations générales qui marchent avec presque tout. ===L'ajout d'une FIFO pour les instructions déjà prêtes à l'émission=== D'autres techniques permettent de réduire aussi bien le cout en circuits que la consommation d'énergie de la ''scheduler''. L'idée est d'utiliser une mémoire associative quand elle est réellement nécessaire, mais d'utiliser un ''scheduler'' "normale" dès que possible. La méthode la plus simple tient compte du fait que certaines µopsont déjà toutes leurs opérandes de disponibles à l'émission, mais doivent quand même être mises en attente, parce que l'ALU adéquate est occupée, parce que des dépendances WAW/WAR sont encore là, ou pour tout autre raison. Dans ce cas, elles sont mises en attente non pas dans la ''scheduler'', mais dans une mémoire FIFO toute simple. L'idée est qu'au lieu d'avoir une énorme mémoire associative pour la ''scheduler'', on déplace quelques entrées dans une petite FIFO annexe. Le résultat est un gain d'énergie et de circuits, au prix d'une perte de performance mineure. La perte de performance en question se manifeste si aucune instruction n'a ses opérandes de prêtes à l'émission : le programme n'utilise pas la FIFO et voit alors un ''scheduler'' plus petite. Une amélioration de cette technique tient compte du fait que certaines instructions sont dans un cas intermédiaire. Elles ont déjà un opérande de prête lors de l'émission, mais pas l'autre. Le nombre d'opérandes varie suivant l’instruction : certaines n'ont besoin que d'un seul opérande. De plus, il arrive qu'une opération tout juste décodée ait déjà un ou plusieurs de ses opérandes de prêts. Cette constatation permet d'éviter d'utiliser des comparateurs pour les opérandes déjà prêts. Par exemple, on peut parfaitement utiliser trois ''scheduler'' : * une pour les instructions dont tous les opérandes sont prêts, mais qui sont quand même mises en attente, sans comparateur ; * une pour les instructions dont un seul opérande manque, qui n'utilise qu'un comparateur par entrée ; * une pour les instructions dont deux opérandes manquent à l'appel, qui utilise deux comparateurs par entrée. C'est beaucoup plus économique que d'utiliser une seule grosse ''scheduler'' qui contiendrait autant d'entrées que les trois précédentes réunies, avec deux comparateurs par entrée. Certains sont même allés plus loin, et ont proposé de supprimer la ''scheduler'' avec deux opérandes par entrée. Les instructions dont deux opérandes sont inconnus au décodage sont stockées dans la ''scheduler'' pour instructions avec un comparateur par entrée. Un circuit de prédiction se charge alors de prédire l'opérande manquant, cette prédiction étant vérifiée plus loin dans le pipeline. Il serait cependant étonnant qu'une telle proposition ait donné lieu à la moindre implémentation réelle. ===Les optimisations de la consommation d'énergie avancées=== D'autres chercheurs ont conservé un ''scheduler'' unique, avec autant de comparateurs par entrée qu'il y a d'opérandes possibles par instruction. Simplement, le processus de détection des opérandes prêts est légèrement ralenti : on ne vérifie qu'un opérande par cycle. Pour vérifier les deux opérandes d'une entrée, on doit attendre deux cycles. Enfin, certains chercheurs ont proposé des ''scheduler'' segmentées. Les instructions circulent à chaque cycle d'un segment vers le suivant : en conséquence, certains segments conservent les instructions les plus anciennes, un autre les instructions les plus jeunes, etc. Seul le denier segment, celui qui contient les instructions les plus vielles, peut émettre une instruction : la détection des opérandes se fait seulement dans le dernier segment, qui contient les instructions les plus anciennes. On économise ainsi beaucoup de comparateurs. Certains chercheurs ont tenté de pipeliner l'étape de sélection des opérandes, ainsi que l'étage d'arbitrage. Mais en faisant cela, il faut plusieurs cycles pour détecter qu'une instruction a ses opérandes prêts, ce qui pose problème face à de nombreuses dépendances RAW. Pour éviter de trop perdre en performances, certains chercheurs ont décidé d'utiliser des techniques pour prédire quelles seront les instructions dont les opérandes seront bientôt prêts. Si détecter qu'une instruction est prête prend n cycles, le processeur devra tenter de prédire la future disponibilité des opérandes n cycles en avance pour obtenir des performances optimales. ===Remplacer la mémoire associative par une RAM=== Une autre optimisation possible est de remplacer la ''scheduler'' par une mémoire RAM, dont chaque mot mémoire correspondrait à une entrée. Une telle optimisation permet en théorie de se passer des comparateurs associés à chaque entrée, mais au prix de l'ajout de circuits annexes potentiellement couteux. La première de ces techniques, la '''recherche directe par étiquette''' (direct tag search) fut créée par Weiss et son collègue Smith. Ils cherchaient à améliorer l'algorithme de Tomasulo, un algorithme qu'on expliquera dans quelques chapitres. Rappelons que chaque instruction produit un résultat, qui devra être rapatrié dans une ou plusieurs entrées de la ''scheduler''. L'optimisation de la recherche directe par étiquette fonctionne dans le cas où le résultat de l'instruction n'est utilisé que par une seule entrée, et pas plusieurs. Le principe est simple : chaque champ « opérande » d'une entrée est adressable via le nom de registre de cet opérande. Pour faire le lien entre entrée et nom de registre, la recherche directe par étiquette ajoute une table de correspondances matérielle, une mémoire RAM qui mémorise les adresses des champs « opérande » des entrées. Les adresses envoyées dans cette mémoire sont les noms de registres des résultats. Lors de l'émission, la table de correspondances est mise à jour. Les numéros des champs « opérande » réservés lors de l'émission sont mémorisés dans les mots mémoire qui correspondent aux deux registres sources. Toutefois, une petite vérification est faite lors de l'émission : s'il y a déjà une correspondance dans la table pour un registre source, alors une autre instruction compte lire ce registre. Pour éviter d'écraser les données de l'instruction précédente dans la table de correspondances, l'émission de l'instruction est bloquée. [[File:Recherche directe par étiquette.png|centre|vignette|upright=2|Recherche directe par étiquette.]] ==Les ''schedulers'' avec préplanification== Avec la '''préplanification''' (''prescheduling''), le ''scheduler'' est composée de mémoires FIFO dans lesquelles les instructions sont triées dans l'ordre d'émission. Il n'y a pas de logique d’émission proprement dite, celle-ci se bornant à vérifier si l'instruction située au début de la FIFO peut s’exécuter. Par contre, le préplanificateur détecte les dépendances et en déduit où insérer les instructions dans le tampon d'émission, à l'endroit le plus adéquat. [[File:Préplanification.jpg|centre|vignette|upright=2|Préplanification.]] ===L'usage de FIFO multiples=== La technique de préplanification la plus simple utilise plusieurs FIFO. Quand une instruction a une dépendance avec une autre instruction, les deux sont placées dans la même FIFO. Pour cela, le préplanificateur détecte les chaines d'instructions dépendantes, et place les instructions dans la FIFO adéquate. A chaque cycle, l'unité d'émission lit une micro-opération dans chaque FIFO et vérifie si elle peut l'émettre. Si la micro-opération n'a pas ses opérandes disponibles, ou qu'une dépendance structurelle survient, alors la FIFO est bloquée. La micro-opération attend que la dépendance soit résolue, bloquant toutes les instructions précédentes. Mais les autres FIFO ne sont pas bloquées, laissant de la marge de manœuvre. [[File:Préplanification par FIFO multiples.png|centre|vignette|upright=1.5|Préplanification par FIFO multiples.]] ===La technique du tampon trié=== La technique du '''tampon trié''' trie les instructions selon le temps d'attente avant leur exécution. Les instructions qui sont censées s’exécuter bientôt sont insérées au tout début de la FIFO, tandis que les instructions qui s’exécuteront dans un long moment sont insérées vers la fin. Là encore, l'unité d'émission lit une micro-opération dans la FIFO, et détermine si elle peut être émise. Si une dépendance survient, l'émission est retardée, et la FIFO est bloquée. [[File:Préplanification par tampon trié.png|centre|vignette|upright=1.5|Préplanification par tampon trié.]] La technique a cependant quelques problèmes assez importants. Le premier problème est que la FIFO est bloquée lorsqu'une micro-opération ne peut être émise. Le second problème est que le temps avant exécution n'est pas toujours connu, notamment pour les instructions d'accès mémoire. Et cela se répercute sur les instructions dépendantes de celles-ci. Pour résoudre ce genre de problèmes, l'usage d'un pipeline à ''replay'' est possible, et est même l'une des meilleures solutions possible, malgré ses défauts. L'idée est que les lectures sont pré-planifiées en supposant qu'elles font un succès de cache L1. Si la prédiction est fausse, la lecture est ré-exécutée plusieurs cycles plus tard, en supposant qu'elle fait un succès dans le cache L2, et ainsi de suite. Elle est alors ré-insérée dans la FIFO, elle est pré-planifiée une seconde fois. Il en est de même si une micro-opération ne peut pas être émise : il suffit de la réinsérer dans la FIFO au bon endroit, en attendant que ses dépendances soient résolues. Ainsi, l'instruction fautive ne bloque pas la fenêtre d’instruction, et retente sa chance autant de fois qu'il le faut. [[File:Préplanification par fenêtre d’instruction scorebarodée.png|centre|vignette|upright=1.5|Préplanification par fenêtre d’instruction scorebarodée.]] Une autre solution utilise deux ''schedulers'' : une FIFO gérée par la préplanification, et une vraie ''scheduler'' pour les instructions dont le temps d'attente ne peut pas être déterminé. Il est possible de mettre cette dernière avant la préplanification, afin de gérer les temps d'attente des instructions d'accès mémoire. Quand le temps d'attente d'une lecture devient connu, ses instructions dépendantes sont gérées avec préplanification. [[File:Préplanification avec fenêtre d’instruction.png|centre|vignette|upright=2.5|Préplanification avec fenêtre d’instruction.]] ===Les ''scheduler'' avec allocation temporelle statique=== L''''allocation temporelle statique''' correspond à une technique utilisée sur les processeurs Cuzco de l'entreprise Condor. La technique en question a été présenté en 2025, mais des idées similaires ont été présentées dans la littérature académique. Elle ressemble beaucoup aux techniques de pré-planification, avec cependant quelques différences. L'idée est simple : le processeur dispose de plusieurs ''scheduler'', qui mettent en attente les micro-opérations. Lors de l'étape de renommage de registres, le processeur détermine dans combien de cycles d'horloge la micro-opération sera prête pour exécution. La micro-opération est alors mise en attente durant ce nombre de cycles, dans les ''scheduler'', puis est émise une fois ce nombre de cycles écoulés. Ce faisant, les ''scheduler'' n'ont pas besoin de détecter la disponibilité des opérandes à chaque cycle, pour chaque micro-opération en attente. Le ''timing'' de l'émission des micro-opérations est décidé à l'avance. L'implémentation exacte n'est pas connue, mais plusieurs solutions sont imaginables. Par exemple, la ''scheduler'' peut simplement être composée de plusieurs mémoires de petite taille, chacune contenant les micro-opérations destinées à être exécutées dans N cycles, N étant différent pour chaque mémoire. Une autre solution, plus réaliste, utilise un ''scheduler'' dans laquelle la micro-opération est couplée à des champs pour les opérandes, et un champ compteur. Le champ compteur est initialisé avec le nombre de cycles à attendre, et est décrémenté à chaque cycle d'horloge. Quand il atteint zéro, la micro-opération est émise. Vous remarquerez que la méthode ne marche que si toutes les micro-opérations prennent un nombre fixe de cycles d'horloge. Et autant c'est le cas pour les micro-opérations arithmétiques ou logiques, autant les accès mémoire ne rentrent pas dans ce cadre. En théorie, on ne sait pas combien de temps prendra un accès mémoire. Et cette incertitude se répercute sur les instructions dépendantes d'un accès mémoire. Pour éviter cela, le processeur réutilise un pipeline à ''replay'' tel que vu dans le chapitre précédent. L'unité de renommage de registre suppose que tout accès mémoire fait un succès de cache L1, et décide des ''timings'' d'émission sous cette hypothèse. Si une lecture subit un défaut de cache, elle est ré-exécutée, de même que toutes les instructions dépendantes. Pour cela, le registre de destination de la lecture est marqué comme invalide, grâce à un bit spécifique attaché au registre. Toute instruction qui lit un opérande invalide est elle aussi ré-executée de zéro. Pour simplifier, l'unité d'émission ressemble à une unité d'émission dans l'ordre, avec un registre de disponibilité, qu'on aurait amélioré pour aller au-delà de la simple détection des dépendances d'instruction. Pour déterminer les ''timings'' d'émission, à savoir quand émettre une micro-opération, le processeur utilise une unité d'émission à deux étages. Le premier étage est appelé le ''register scoreboard'', le second étage est appelé la ''Time Ressource Matrix''. Les deux étages communiquent entre eux, comme on va le voir, et leurs noms donnent une idée de ce qu'ils font. Le premier étage gère les dépendances de registres, le second gère les dépendances structurelles. Le premier étage est un registre de disponibilité amélioré, qui gère les dépendances de registre. Cet étage sait quand tel registre sera écrit, et donc que l'opérande écrit dedans sera disponible à partir de tel cycle d'horloge. Il le sait car l'étage suivant l'aura prévenu, mais laissons cela de côté pour le moment. Quand une micro-opération rentre dans cet étage, il vérifie les dépendances avec les registres et les micro-opérations antérieures. Vu qu'il sait quand les registres seront disponibles, il peut déterminer quand l'instruction pourra s'exécuter. Par exemple, si une micro-opération lit les deux registres R7 et R15, qui sont disponibles respectivement dans 5 et 7 cycles, le premier étage sait que la micro-opération devra attendre 7 cycles. Mais tout cela ne suffit pas à déterminer quand émettre une micro-opération. En effet, il fait aussi gérer les dépendances structurelles, ce qui est le boulot du second étage. Le second étage utilise pour cela une ''Time Ressource Matrix'', qui mémorise l'occupation de diverses "ressources", pour les 256 cycles d'horloge à venir. Les ressources en question sont les ports de lecture/écriture du banc de registre, les ALUs utilisées, si la micro-opération utilise l'unité mémoire, etc. Le second étage prend en entrée une micro-opération, détermine quelles "ressources" elle utilise, puis regarde leur disponibilité. Elle détecte alors les dépendances structurelles et détermine alors quand peut s'exécuter la micro-opération. Elle peut retarder l'émission de quelques cycles, si une dépendance structurelle est détectée. Une fois sortie du second étage, on sait quand la micro-opération va être émise, à quel cycle précisément. Et vu que la durée de l'instruction est fixe, on sait quand cette micro-opération va se terminer, quand son résultat sera disponible. Cela permet de mettre à jour la ''Time Ressource Matrix'', pour préciser que le port d'écriture sera occupé à tel moment. De plus, cette information est transmise au premier étage, qui sait alors quand est enregistré le résultat dans le registre de destination. C'est comme cela que le premier étage sait quand un registre est disponible : le second étage le prévient, quand il émet une instruction ! La ''Time Ressource Matrix''mémorise l'occupation des "ressources" pour les 256 cycles d'horloge à venir. Cependant, elle ne vérifie pas les dépendances pour les 256 cycles suivants. Quand elle reçoit une micro-opération, elle teste les dépendances structurelles pour seulement les 8 prochains cycles maximum. Si la micro-opération ne peut pas être émise pendant ces 8 cycles, le pipeline est bloqué, un ''pipeline stall'' est émis. Pour être plus précis, vu que le processeur peut décoder 8 micro-opérations en même temps, cela permet de ne consulter que 64 cycles d'horloge sur les 256. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les premiers processeurs Intel | prevText=Les premiers processeurs Intel | next=Le renommage de registres | nextText=Le renommage de registres }} </noinclude> 4xy9hmdn5d6x4pc8oa8w6is7s6xog5o 773624 773623 2026-09-29T21:02:36Z Mewtow 31375 /* La logique de sélection : âge ou position ? */ 773624 wikitext text/x-wiki Dans les chapitres précédents, nous avons parlé des techniques dites d''''émission dans l'ordre'''. L'idée est d’exécuter une nouvelle micro-opération à chaque cycle, dans des unités de calcul séparées. Les instructions sont émises consécutivement, mais les instructions s’exécutent en parallèle dans des unités de calcul séparées. Par contre, quand l'unité d'émission ne peut pas émettre une instruction, elle bloque tout le pipeline. Les instructions qui suivent sont elles aussi bloquées, elles doivent attendre leur tour, même si elles sont en capacité de s'exécuter. Les techniques d'exécution dans le désordre que nous allons voir dans ce chapitre corrigent ce point précis. Elles sont dites à '''émission dans le désordre'''. Elles se distinguent des précédentes sur un point précis : quand l'unité d'émission bloque l'émission d'une instruction, les instructions suivantes peuvent poursuivre. L'émission des instructions peut donc se faire dans le désordre, dans le sens où une instruction peut être émise alors qu'une instruction précédente ne l'est pas encore. Mais avant de poursuivre, quelques point niveaux terminologie : * L'émission dans le désordre est un terme parlant et assez précis. Malheureusement, la terminologie la plus utilisée par d''''exécution dans le désordre'''. Et nous utiliserons ce terme dans la suite du cours, histoire de ne pas trop dévier de la nomenclature habituelle. * Nous utiliserons parfois l'abréviation OOO pour parler d'exécution dans le désordre. L'abréviation est celle de ''Out Of Order Excution''. * Nous utiliserons aussi l'abréviation ''µop'' pour parler de micro-opération, ''µops'' au pluriel pour parler de plusieurs micro-opérations, ou des micro-opérations en général. L'exécution dans le désordre ne gère en effet que des µops, elle se situe après l'étape de décodage. Pour décrire comment est implémentée l'émission dans le désordre, il faut commencer par parler des processeurs sans. Les processeurs sans exécution dans le désordre ont une unité d'émission qui bloque tout le pipeline dès qu'une µop ne peut pas être émise. Pour limiter l'impact de ce blocage, quelques rares processeurs incorporent une '''file de micro-opération''', une mémoire FIFO qui met en attente les µops. Vu que c'est une mémoire FIFO, les µops sont émises dans l'ordre, à savoir l'ordre d'ajout, dans l'ordre de décodage. Le schéma ci-dessous illustre une telle file d'attente couplée à un ''scoreboard''. L'exécution dans le désordre améliore la file de µops sur un point : ce n'est plus une mémoire FIFO. Les µops sont insérées dans l'ordre, mais peuvent sortir dans le désordre (être émises dans le désordre). La file de µops devient alors un '''''scheduler''''', terme anglais que je ne compte pas traduire. Un terme équivalent est '''''scheduler''''', terme traduit directement de l'anglais ''instruction Window''. Terme assez trompeur, car elles mettent en attente des µops, pas des instructions. [[File:Différence file µops et fenêtres instruction.png|centre|vignette|upright=2|Différence file µops et ''schedulers'' ]] Le ''scheduler'' émet une µop dès que ses opérandes sont disponibles. Par disponible, on veut dire présent soit dans le réseau de contournement, soit dans les registres. Le ''scheduler'' détecte automatiquement quand les opérandes d'une µop sont disponibles, grâce à une unité d'émission intégrée. L'unité d'émission et le ''scheduler'' sont fusionnés ensemble, dans un seul circuit, mais nous allons dire qu'ils sont conceptuellement séparés pour le moment. A chaque cycle, l'unité d'émission consulte les µops en attente pour détecter lesquelles peuvent s'exécuter. Le ''scheduler'' est spécialement être conçue pour, c'est une sorte de mémoire associative très complexe, comme on le verra dans ce qui suit. [[File:OOO Issue.png|centre|vignette|upright=2.5|Exécution dans le désordre avec un ''scheduler'']] Une fois qu'une µop sort du décodeur d'instructions, elle est ajoutée en parallèle dans la ''scheduler'' et le ROB. La raison est que les µops quittent la ''scheduler'' dans le désordre, et qu'elles doivent être remises en ordre par la suite. Le ROB s'occupe de cette remise en ordre, mais il a besoin de savoir dans quel ordre les µops sont censées être, et cet ordre est celui du décodage. Aussi, pour remplir le ROB, la seule opportunité est en sortie de l'unité de décodage. Dans le cas où une instruction est décodée en plusieurs micro-opérations, elles sont toutes insérées en même temps dans la ''scheduler'' et le ROB, en tenant compte de leur ordre. L'implémentation la plus simple de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Les µops décodées sont accumulées dans le ''scheduler'', où elles attendent leur tour. La ''scheduler'' sert donc de file d'attente. Avant de poursuivre, précisons que les micro-opérations mémoire sont à part des autres, pour diverses raisons. Une de ces raisons est que les dépendances de données sont classées en deux types : les dépendances de registre et les dépendances d'adresse. Et les deux sont fondamentalement différentes. Autant on peut détecter les dépendances de registre lors de l'émission, autant c'est plus compliqué avec les dépendances d'adresse. De plus, rappelons que si les lectures peuvent s'exécuter dans le désordre, les écritures doivent s'exécuter dans l'ordre, ou du moins en donner l'illusion. Pour cela, le processeur remet les écritures dans l'ordre avec une sorte de mini-ROB intégré à l'unité mémoire, appelée la file d'écriture. Elle complémente le ROB, qui lui ne gère que les écritures dans les registres, mais les deux collaborent. La file d'écriture envoie une écriture à la mémoire RAM quand le ROB lui dit que c'est bon, les instructions précédentes sont terminées ''dans l'ordre du programme''. Les processeurs modernes ajoutent des techniques d'exécution dans le désordre des accès mémoire, mais nous les verrons dans un chapitre dédié. Elles permettent d'utiliser un ''scheduler'' unique, qui mémorise aussi les µops mémoire. Si elles sont mises en place, l'unité mémoire n'a pas besoin de file de µops séparée. L'idée est que les dépendances de registre sont traitées par la ''scheduler'', mais que l'unité mémoire gére les dépendances d'adresse. Les dépendances d'adresse sont gérées par des techniques de ''désambiguation mémoire'', qui auront droit à un chapitre dédié. [[File:Processeur avec exécution dans le désodre des accès mémoire.png|centre|vignette|upright=2|Processeur avec exécution dans le désodre des accès mémoire]] Les processeurs assez anciens n'autorisaient pas d'exécution dans le désordre des accès mémoire. Concrétement, les accs mémoire devaient se faire dans l'ordre, mais les autres µops pouvaient être exécutées dans le désordre. Il s'agit donc d'un ordre entre µops mémoire, pas entre µops mémoire et autres µops. Les µops entières et flottantes pouvaient être exécutées avant une µops mémoire qui est avant elle dans l'ordre du programme, ce n'est pas un problème. Pour garantir l'ordre des µops mémoire, l'unité mémoire est précédée par une file de micro-opérations séparée, pour forcer l'exécution dans l'ordre des accès mémoire. De plus, les µops mémoire ne peuvent pas utiliser la ''scheduler''. Dit autrement, la ''scheduler'' ne mémorise pas de µops mémoire. Après le décodage, les µops sont réparties soit dans la file de µops mémoire, soit dans la ''scheduler''. Le décodeur classe les µops suivant que ce sont des µops mémoire ou non, et les envoient à la bonne destination. Dans ce chapitre, on supposera que c'est cette solution qui est utilisée. [[File:Processeur avec émission dans l'ordre des accès mémoire.png|centre|vignette|upright=2|Processeur avec émission dans l'ordre des accès mémoire]] ==L'implémentation d'un ''scheduler'' : généralités== Un ''scheduler'' est une mémoire qui mémorise des micro-opérations. Elle est cependant plus complexe qu'une mémoire RAM ou qu'une FIFO et ressemble un petit peu à une mémoire cache. Elle dispose d'un port d'écriture et d'un port de lecture, au minimum. Le port d'écriture permet à l'unité de décodage d'insérer une micro-opération dedans, d'ajouter la micro-opération qui vient d'être décodée. Si une instruction machine est décodée en plusieurs micro-opération, deux possibilités. La première est de les insérer un par un, ce qui fait qu'on peut se contenter d'un seul port d'écriture. L'autre possibilité est de les ajouter en même temps, ce qui demande plusieurs ports d'écriture. Le port de lecture sert à émettre une instruction. On part du principe que la ''scheduler'' ne peut émettre qu'une seule instruction à la fois, car les processeurs que nous avons vu précédemment sont de ce type. Mais nous verrons dans quelques chapitres qu'il existe des processeurs dits superscalaires, qui sont capables d'émettre plusieurs instructions par cycle. Dans ce cas, la ''scheduler'' a un seul port de lecture. Un processeur superscalaire, quant à lui, doit avoir un port de lecture par unité de calcul, ce qui fait beaucoup plus. Les ''schedulers'' sont composées d''''entrées''', des mots mémoire qui stockent une instruction. Une instruction réserve une entrée après son décodage et la libère dès qu'elle est envoyée aux unités de calcul. Une entrée contient l'opcode (les signaux de commande à envoyer à l'ALU), le registre de destination du résultat, les registres de chaque opérande, et éventuellement des signaux de commande en plus. De plus, chaque opérande est couplée à un bit de disponibilité, qui indique si elle est disponible. Quand un opérande est écrit dans les registres, le bit de présence correspondant est mis à jour. Enfin, chaque entrée possède un bit ''empty'' qui indique si elle est vide, cette information étant utile pour réserver des entrées. [[File:Entrée d'une station de réservation - sans les tags.png|centre|vignette|upright=3|Entrée d'un ''scheduler'']] ===Les stations de réservation=== Les '''stations de réservation''' sont des ''scheduler'' particulières, qui sont capables de mémoriser les opérandes des instructions. Les entrées des stations de réservation sont identiques à celle des autres ''scheduler'', si ce n'est que les opérandes de l'instruction sont enregistrés directement dans des champs séparés. Il y a deux champs, un par opérande, pour stocker l'opérande elle-même, lue depuis les registres ou obtenue via le réseau de contournement. Notons que les champs pour les opérandes viennent en plus des champs pour les noms de registres, encore que les deux peuvent être fusionnés si on veut optimiser le tout. [[File:Entrée d'une station de réservation.png|centre|vignette|upright=3|Entrée d'une station de réservation.]] Précisons que la terminologie n'est pas très fiable. Les termes "''scheduler''" et "station de réservation" ne regroupent pas du tout la même chose d'un papier de recherche à l'autre, d'un bouquin à l'autre, d'un chercheur à l'autre, d'un ingénieur à l'autre, d'un professeur à l'autre. Le terme initial vient pourtant de l'article original sur l'algorithme de Tomasulo, où il désignait un ''scheduler'' associée à une unité de calcul précise. Mais le terme a ensuite été réutilisé, ce qui fait que certains processeurs avec plusieurs unités de calcul sont décrits comme ayant une unique station de réservation. En bref : c'est le bazar ! Mais nous en reparlerons dans le chapitre sur le renommage de registres, car c'est la place idéale pour les aborder. Toujours est-il que j'ai fait le choix de confondre les concepts de ''scheduler'' et de station de réservation avec les concepts de '''lecture avant émission''' et de '''lecture après émission'''. La différence entre les deux est que les registres sont lus après émission avec un ''scheduler'', avant avec des stations de réservation. Dans le cas "avant émission", les opérandes sont mémorisés dans la station de réservation. Et cette différence a une influence sur le pipeline du processeur, le banc de registres et tout ce qui s'en suit. Un désavantage de la lecture avant émission est qu'il faut stocker les opérandes après lecture, ici dans les stations de réservation. Mais un avantage est que le banc de registre a besoin de moins de ports de lecture, car une bonne partie des opérandes sont fournies par le système de contournement. Nous verrons cela dans le détail dans le chapitre sur les processeurs superscalaires. [[File:Processeur avec plusieurs ''scheduler''.png|centre|vignette|upright=2.5|Lecture après émission.]] [[File:Read Before Issue.png|centre|vignette|upright=2.5|Lecture avant émission.]] ===La logique d'éveil et de sélection=== Dans le cas qui va suivre, on suppose que le processeur ne peut émettre qu'une instruction à la fois. Chaque cycle, une instruction est sélectionnée et est envoyée dans le chemin de données, soit à une ALU, soit à une unité d'accès mémoire. La sélection d'une instruction est effectuée par l'unité d'émission, qui est aussi appelée le '''''scheduler'''''. Elle gère la disponibilité des opérandes et la disponibilité des unités de calcul adéquate. Le choix de l'instruction émise doit être le plus pertinent possible, pour des raisons de performances. Pour le premier point, l'unité d'émission détermine quelles instructions sont candidates pour l'émission. Les ''instructions candidates'' sont celles dont tous les opérandes sont prêts. Le processeur contient un circuit qui détecte les instructions candidates : la '''logique d’éveil''' (''wake-up logic''). Une fois que la logique d'éveil a fait son travail, une instruction est choisie pour s’exécuter en fonction de la disponibilité des unités de calcul adéquates. Ce rôle est dévolu à un circuit qu'on appelle la '''logique de sélection''', ou ''select logic''. [[File:Fonctionnement complet de la logique d’émission.jpg|centre|vignette|upright=1.5|Fonctionnement complet de la logique d’émission.]] La logique de sélection doit gérer le fait que les unités de calcul du processeur ne sont pas toutes identiques. Déjà, un processeur a généralement des unités séparées pour les instructions entières et flottantes, des unités spécialisées dans les accès mémoire, parfois des unités spécialisées pour les branchements. Une instruction doit être attribuée à la bonne unité de calcul, on ne doit pas envoyer une instruction entière dans une unité de calcul flottante. De plus, parmi les unités de calcul entières, toutes ne sont pas identiques. Par exemple, il est fréquent d'avoir plusieurs unités de calcul spécialisées dans les opérations simples (additions, soustractions, opérations logiques) avec une unité pour les multiplications/divisions séparées, parfois une unité spécialisée pour les décalages/rotations, etc. Là encore, allouer la bonne instruction à la bonne ALU est complexe. Plus les unités de calcul sont hétérogènes, plus la logique de sélection est compliquée. Les logiques d'éveil comme de sélection sont assez complexes. Comme on le verra plus bas, la logique de sélection la plus simple, qui gère une seule unité de calcul, est basée sur un encodeur à priorité couplé à d'autres circuits. Et pour gérer plusieurs ALUs, il faut mettre des encodeurs en cascade. Le résultat est que même en prenant une logique de sélection simple, elle sera assez lente et gourmande en circuits. Aussi, la logique de sélection met souvent un cycle d'horloge entier pour faire son travail, elle a son propre étage de pipeline attribué. La logique d'éveil est dans le même cas, ce qui fait qu'émettre une micro-opération demande deux cycles d'horloge. Le défaut est que cela rajoute des cycles d'horloges entre la ''scheduler'' et l'ALU, ce qui complique la gestion du pipeline. Ces cycles de retard sont à prendre en compte au moment d'émettre les instructions, les ''scheduler'' doit en tenir compte pour des performances optimales. Sans tenir compte de ces cycles de retard, les instructions arrivent en retard de quelques cycles à l'ALU, cycles de retard durant lesquels l'ALU n'a pas fait de calcul et a été sous-utilisée, sans compter que le système de contournement n'est pas utilisé au mieux. Et le problème est encore plus important sur les processeurs avec des stations de réservation, qui utilisent la "lecture après émission" : cela rajoute un cycle d'horloge en plus, un temps de retard en plus. ===La logique d'éveil : l'émission anticipée=== La logique d'éveil doit tenir compte du fait qu'il y a plusieurs étages entre l'émission et l'exécution sur une unité de calcul. Par exemple, un processeur a souvent entre un et à cinq étages entre la file d'attente et les unités de calcul. Il faut lire les registres, gérer le contournement, et cela peut prendre quelques cycles d'horloge. Sur le Pentium 4, on trouve 6 étages entre le ''scheduler'' et l'entrée de l'ALU. Si les micro-opérations sont émises quand les opérandes sont disponibles, il y aura un délai de quelques cycles avant qu'elles atteignent l'ALU. Alors qu'idéalement, on souhaiterait que la micro-opération atteigne l'ALU dès que ses opérandes sont disponibles, pour profiter des techniques de contournement. Pour cela, la logique d'éveil émet les instructions quelques cycles en avance pour qu'elles arrivent au bon moment. Il s'agit d'une technique d''''émission anticipée''', dont nous avions parlé dans le chapitre sur le contournement. : Il faut noter que le problème se pose plus avec des ''scheduler'' qu'avec des stations de réservation. Les premières ont un étage en plus entre émission et ALU, vu qu'il faut lire des registres après l'émission. L'émission anticipée demande d'émettre un signal d'éveil en avance de quelques cycles, pile au bon moment. Par exemples, si on a deux étages entre l'ALU et l'unité d'émission, le signal de réveil sera généré deux cycles avant que le résultat soit effectivement calculé. L'implémentation varie, mais deux solutions sont possibles. La première est de générer le signal d'éveil dans l'ALU, ce qui n'a de sens que pour les opérations comme les multiplications ou les divisions, qui prennent plusieurs cycles. Une autre technique génère le signal de réveil dans une structure centralisée, spécialisée dans la génération des signaux d'éveil. L'unité de composée d'un registre à décalage par registre. Imaginons qu'une instruction est émise, que cette instruction mette N cycles à s'exécuter, et qu'elle écrive dans un registre de destination. L'unité sélectionne alors le registre à décalage associé au registre de destination, et met le bit numéro N à 1. Le registre décalé d'un cran à chaque cycle. Quand le bit sortant est un 1, alors le signal de validité pour l'opérande est généré. L'émission anticipée marche bien si l'instruction a une durée fixe, connue à l'avance. Et autant c'est le cas pour les instructions arithmétiques et logiques, autant ce n'est pas le cas pour les accès mémoire. Les accès mémoire ont une latence variable : quelques cycles pour un succès de cache, plusieurs dizaines de cycles pour un défaut de cache L1, pas loin de la centaine pour un défaut de cache L2, etc. Et cela pose des problèmes pour l'émission anticipée. L'émission en avance pour les accès mémoire est purement spéculative : le processeur émet des instructions en supposant que la lecture entrainera un succès de cache, quitte à annuler l'instruction en cas de défaut de cache. Mais faire ainsi demande non seulement d'annuler les instructions émises en avance, mais aussi de ne pas retirer les instructions émises en avance de la ''scheduler''. Elles sont émises, mais une copie de sauvegarde est conservée dans la ''scheduler''. Si le processeur détecte un défaut de cache, il peut alors ré-exécuter l'instruction. S'il détecte un succès de cache, les instructions lecture-dépendante sont retirées de la ''scheduler'', la copie de sauvegarde est devenue inutile et est donc jetée. ===La logique de sélection : âge ou position ?=== La logique de sélection est primordiale pour de bonnes performances. Il existe deux méthodes principales pour sélectionner l'instruction à exécuter. La première est la plus simple : elle se base sur lé numéro de l'entrée. En effet, un ''scheduler'' est avant tout une sorte de mémoire, un mix entre mémoire associative, mémoire RAM, et FIFO. Et chaque entrée a un numéro, une adresse mémoire. Nous parlerons de numéro dans ce qui suit, car ce sera plus simple, le terme d'adresse mémoire étant peut-être un peu exagéré dans le contexte des ''scheduler''. Toujours est-il que la ''scheduler'' est adressable dans le sens où on peut lui envoyer le numéro de l'entrée voulue, et le ''scheduler'' renvoie le contenu de l'entrée sur son port de lecture. Et c'est ce que fait la logique de sélection : elle génère le numéro de l'entrée à lire. Le numéro est alors envoyé sur l'entrée d'adresse de la fenêtre d’instruction, et elle fournit la micro-opération associée sur son port de lecture, son '''port d'émission'''. La première méthode de sélection, donc. Elle est basée sur le numéro de l'entrée. Si plusieurs entrées sont éveillées, la logique de sélection prend celle avec le plus petit numéro. Elle porte le nom de '''sélection par position''', sous-entendu position dans la ''scheduler''. Vous l'avez peut-être deviné, mais la logique de sélection est alors un encodeur à priorité. Le circuit de sélection ne se résume donc pas seulement à un encodeur à priorité, mais c'est le circuit central. L'avantage d'une telle méthode de sélection est qu'elle est simple à implémenter : un encodeur à priorité est un circuit connu, facile à implémenter. Mais on remarque un défaut : un encodeur est un circuit assez rapide, mais qui utilise beaucoup de transistors, beaucoup de portes logiques, surtout si on veut qu'il soit rapide. Ce qui explique que la logique de sélection ait son propre étage de pipeline rien que pour elle. La seconde méthode s'appelle la '''sélection par âge''', au nom assez transparent. L'idée est de privilégier l'émission de l'instruction la plus ancienne. Elle demande que la ''scheduler'' trie les micro-opérations par ordre d'insertion dans la ''scheduler'', ce qui en fait une pseudo-FIFO. Le tri est partiel, car les instructions peuvent sortir de la fenêtre d’instruction à tout moment. Compacter la ''scheduler'', à savoir regrouper toutes les entrées valides est une idée, mais elle est compliquée à implémenter. Aussi, elles préfèrent encoder des informations sur l'ordre d'émission dans chaque entrée. L'encodeur à priorité doit alors travailler non pas sur des nombres entiers liés à l'ordre d'insertion dans la pseudo-FIFO. Elle est encore plus gourmande en circuits que la méthode précédente. Les processeurs haute performance utilisent souvent des méthodes hybrides. Par exemple, les processeurs AMD de microarchitecture Bulldozer utilisaient une méthode intermédiaire. Ils utilisaient un ''scheduler'' couplée à un encodeur à priorité pour la sélection par position, mais complémentaient le tout avec une unité qui mémorisait l'instruction la plus ancienne dans la fenêtre d’instruction. Le mécanisme de sélection par âge était utilisé en priorité. Mais si l'instruction la plus ancienne n'était pas prête, le processeur basculait sur le mécanisme de sélection par position. ===La compaction des ''scheduler''=== À chaque cycle, les instructions décodées sont ajoutées dans la ''scheduler'', dans des entrées vides. Vu que les instructions quittent celle-ci dans le désordre, ces vides sont dispersés dans la ''scheduler'', ce qui pose problème pour déterminer où placer les nouvelles instructions. La solution la plus triviale consiste à conserver une liste des vides, mise à jour à chaque insertion ou émission d'instruction. Une autre solution consiste à éliminer les vides en compactant la ''scheduler'' à chaque cycle d'horloge. Des circuits se chargent de détecter les vides et de regrouper les instructions en un unique bloc. Il faut signaler que certains processeurs arrivent à se passer de cette étape de compactage, mais au prix de ''scheduler'' nettement plus complexes. Autre problème : quand il faut choisir quelle instruction émettre, il y a toujours plusieurs candidats. Si on choisit mal, des instructions restent en attente trop longtemps parce que d'autres instructions plus jeunes leur passent devant. Pour éviter cela, les instructions les plus vielles, les plus anciennes, sont prioritaires. Pour cela, on peut utiliser une FIFO un peu spéciale pour la ''scheduler''. Si les ajouts d'instruction se font dans l'ordre, les instructions ne quittent pas forcément la ''scheduler'' dans l'ordre imposé par une FIFO : les instructions restent triées dans leur ordre d'ajout, même s'il y a des vides entre elles. Dans ces conditions, il est préférable que le compactage conserve l'ordre FIFO des instructions. Dans ces conditions, l'instruction la plus ancienne est celle qui est située à l'adresse la plus faible : le circuit de sélection peut donc être fabriqué avec des encodeurs, et est relativement simple. ==Les ''schedulers'' basées sur une matrice de dépendances== L'implémentation la plus simple étend le fonctionnement d'un pipeline dynamique usuel. Rappelez-vous le chapitre sur les pipelines dynamiques. Nous avions vu que de tels pipelines émettaient une instruction par cycle, quitte à émettre des bulles de pipeline en cas de dépendance bloquante. Et il est possible d'améliorer leur unité d'émission pour qu'elle soit compatible avec l'exécution dans le désordre. ===Rappels sur le registre de réservation/disponibilité=== L'émission d'une instruction est gouvernée par un ''registre de réservation'' qui indique quels registres sont réservés par une instruction, et ceux qui sont libres. Un registre réservé est un registre qui sera écrit par une instruction en cours d'exécution, mais qui n'a pas encore écrit son résultat. Les instructions candidates doivent avoir leurs opérandes dans des registres libres. Sinon, c'est signe que leurs opérandes sont réservés en écriture, donc pas encore écrites, donc pas disponibles. Si une instruction candidate veut lire ce registre, c'est signe qu'il y a une dépendance RAW : elle veut lire un registre réservé, qui est destiné à être écrit par une instruction en vol. Si elle veut écrire, c'est signe qu'elle veut écrire dans un registre où une autre instruction veut écrire : c'est une dépendance WAW. Dans les deux cas, l'instruction n'est pas émise. Le registre de réservation encode les registres réservés comme suit : chaque bit est associé à un registre. Le bit numéro 0 est associé au registre numéro 0, le bit numéro 1 au registre numéro 1, etc. Là, En clair, les numéros de registres réservés sont encodés en représentation non pas binaire, mais en représentation ''one-hot'' (vue au premier chapitre). {|class="wikitable" |+ Registre de réservation |- ! Registre 7 !! Registre 6 !! Registre 5 !! Registre 4 !! Registre 3 !! Registre 2 !! Registre 1 !! Registre 0 |- | 0 || 0 || 1 || 0 || 0 || 1 || 0 || 0 |} Avant d'émettre une instruction, l'unité d'émission extrait les registres opérande/destination et les convertis dans la même représentation que le registre de réservation, à savoir en représentation ''one-hot''. Le circuit de traduction binaire vers ''one-hot'' est, pour rappel, un simple décodeur. Puis, on fait un OU logique entre les sorties des décodeurs. Le résultat est un masque qui indique quels registres sont lus par l'instruction, encodé en représentation ''one-hot''. Appelons-le le '''masque d'opérandes'''. Le masque est alors comparé au registre de réservation pour vérifier si l'instruction peut être émise. [[File:Unité d'émission simple, dans l'ordre.png|centre|vignette|upright=2|Unité d'émission simple, dans l'ordre]] Si l'émission est autorisée, le registre de réservation est là aussi mis à jour. Le registre de réservation est aussi mis à jour dès qu'une instruction enregistre son résultat dans les registres, ou alors dès qu'il est disponible pour le contournement. Le bit associé au registre repasse alors à 0 (ou à 1). Sans contournement, la mise à jour se fait alors à la toute fin de l'instruction, quand elle se termine, lors de la dernière étape d'enregistrement, à la fin de son pipeline. Avec, elle se fait quand l'instruction quitte l'unité de calcul. ===L'extension à l'exécution dans le désordre : l'éveil par matrice de bits=== La différence entre un pipeline dynamique et l'exécution dans le désordre est que l'on passe d'une instruction à émettre à plusieurs. Plusieurs instructions sont mises en attente dans un ''scheduler'', et y attendent leur tour. L'idée est alors d'envoyer le registre de disponibilité à toutes les entrées, à toutes les instructions en attente. Ainsi, on sait quelles sont les instructions qui peuvent s'exécuter et celles qui ne le peuvent pas. L'implémentation est assez simple, elle ressemble beaucoup à l'implémentation d'un pipeline dynamique simple, si ce n'est que des circuits sont dupliqués. L'implémentation utilise des ''scheduler'' légèrement différentes de celles introduites plus haut. Elles n'utilisent notamment pas de bits de disponibilité, mais autre chose. Lorsqu'une instruction est ajoutée à la ''scheduler'', le masque de disponibilité des opérandes est stocké dans la ''scheduler''. A chaque cycle, le registre de disponibilité est envoyé à toutes les entrées, et est comparé avec tous les masques de disponibilité des opérandes. Si une comparaison renvoie un 1, alors l'instruction de l'entrée est une instruction candidate à l'émission. [[File:Unité d'émission dans le désordre basée sur un registre de disponibilité.png|centre|vignette|upright=2.5|Unité d'émission dans le désordre basée sur un registre de disponibilité]] L'ensemble est implémenté avec l'aide d'une '''matrice de bits''', où chaque ligne correspond à une entrée et chaque colonne à un registre. À chaque croisement entre une ligne et une colonne, on trouve un bit. Si le bit de la ligne n et de la colonne m est à 1, cela veut dire : l'instruction dans l'entrée n a besoin de lire le registre m. S’il est à 0, alors cela veut dire que l'instruction stockée dans la ligne n'a pas besoin de la donnée dans le registre m. [[File:Planificateur à matrice de bits.jpg|centre|vignette|upright=2|Planificateur à matrice de bits.]] Lorsqu'une instruction réserve une entrée, elle initialise la ligne en fonction des registres qu'elle souhaite lire. Pour vérifier si une instruction a ses opérandes prêts, le processeur compare le registre de disponibilité à la ligne associée à l'instruction/entrée. A chaque intersection ligne-colonne, se trouve un comparateur de 1 bit, qui détecte si le registre est demandé et disponible. Les résultats de cette porte sont ensuite envoyés à une porte ET, qui fait le gros du travail. [[File:Logique de détection de la disponibilité d'une instruction.jpg|centre|vignette|upright=2|Logique de détection de la disponibilité d'une instruction.]] ==Les ''scheduler'' basées sur une mémoire associative== Les processeurs modernes utilisent une mémoire associative pour la ''scheduler''. Les mémoires associatives ont été abordées il y a quelques chapitres, mais faisons quelques rappels. Les mémoires associatives servent à accélérer la recherche de données dans un ensemble. Or, un ''scheduler'' vérifie régulièrement si chaque entrée est prête. Il s'agit d'un processus de recherche d'une instruction qui respecte une condition bien précise dans la mémoire, ce qui fait que les mémoires associatives sont donc tout indiquées. Comme vous le savez, les signaux de commande d'une instruction sont propagés avec celle-ci dans le pipeline, le nom du registre de destination ne faisant pas exception. Le nom de registre est envoyé à la ''scheduler'' lors de l'écriture du résultat dans les registres. S'il y a correspondance, l'opérande est disponible et son bit de disponibilité est mis à 1. On peut adapter cette méthode pour tenir compte du contournement assez simplement. [[File:Détection des dépendances par propagation du registre de destination.png|centre|vignette|upright=2|Détection des dépendances par propagation du registre de destination.]] En conséquence, le circuit de détection des dépendances est constitué d'un grand nombre de comparateurs : un par champ « nom de registre » dans chaque entrée. La logique d'éveil/''wake up'' regroupe tous les comparateurs, la logique de sélection est un circuit situé en-dehors de la mémoire associative. Les entrées sont dans la mémoire associative elle-même. [[File:Gestion des bits de validité.png|centre|vignette|upright=2|Gestion des bits de validité.]] L'implémentation la plus simple est celle du schéma précédent, où on utilise une mémoire associative unique. Une version plus élaborée sépare la ''scheduler'' en deux parties : une mémoire qui mémorise les registres des opérandes, une autre mémoire pour le reste. La mémoire pour les registres opérandes est la mémoire associative proprement dite, c'est elle qui est associée aux comparateurs, à la logique de ''wake-up''/réveil, etc. Par contre, l'autre mémoire est une mémoire RAM simplifiée, qui mémorise les informations qui n'ont pas besoin des comparateurs. L'opcode de l'instruction est là-dedans, par exemple. La ''scheduler'' est donc une sorte de mémoire associative améliorée. Il se trouve que c'est aussi le cas du ROB. Et il est possible de fusionner le tampon de ré-ordonnancement avec la ''scheduler'' dans une structure unique. La différence avec un ''scheduler'' normal est que les entrées sont libérées non pas quand l'instruction est exécutée/émise, mais quand elle termine son exécution et quitte le ROB. La ''scheduler'' incorpore des bits dans chaque entrée, pour savoir si la µops associée a été émise et est en cours de traitement dans les ALUs. La méthode a notamment été utilisée sur les processeurs d'architecture K6 d'AMD. Le tout donnait une structure appelée le '''DRIS''' (''deferred scheduling register renaming instruction shelf''). Les processeurs PA 8000 de HP étaient aussi vraisemblabment dans ce cas, aussi. ===Les optimisations de la consommation d'énergie : la désactivation des portions inutilisées=== Le problème avec des ''scheduler'' de ce type est leur forte consommation énergétique, ainsi que le grand nombre de portes logiques utilisées, qui deviennent prohibitifs pour des ''scheduler'' un peu grosses. Pour résoudre ce problème, certains ont optimisé les comparateurs. D'autres ont tenté de profiter du fait que la majorité des bits dans les entrées sont composés de zéros. Bref, les optimisations purement matérielles sont légion. Une première solution est de désactiver les entrées qui sont inutilisées, vides, sans instruction. Pour cela, on fait précéder les comparateurs par un circuit qui les connecte ou déconnecte des lignes de bit. Le circuit est commandé par le bit ''empty'' qui indique si une entrée est vide ou non. L'avantage est que la consommation d'énergie de la ''scheduler'' devient alors proportionnelle au nombre d'entrées non-vides, et non au nombre d'entrées total. Du moins, en apparence, les entrées non-utilisées doivent quand même être alimentées pour fonctionner, mais l'activité de comparaison disparait dans les entrées vides. Il est possible d'étendre cette technique aux entrées dont les opérandes sont prêts. Les gains sont généralement assez bons, avec une réduction de consommation variant entre 30 et 50%, avec une implémentation très simple et très économe en circuits. Une autre solution, assez simple à mettre en place, consiste à désactiver une partie de la ''scheduler'' sin elle est inutilisée. Pour cela, il faut segmenter la ''scheduler'' avec la technique du ''wire partitionning''. Pour rappel, un ''scheduler'' est une mémoire associative. Et comme toute mémoire associative, elle contient des fils, les lignes de bit, qui relient les entrées/sorties à toutes les cellules mémoire. Plus une ligne de bit est longue, plus elle consomme d'énergie et plus le temps de lecture/écriture est long. L'idée est de segmenter les lignes de bits en plaçant des répéteurs qui recopient la tension d'un segment au suivant. Les répéteurs sont des tampons trois-états, ce qui permet de déconnecter les portions inutilisées de la ligne de bit. Ce faisant, la ''scheduler'' est découpée en segments, qui peuvent être désactivés si besoin. S'il y a peu d'instructions chargées dans la ''scheduler'', les portions inutilisées sont désactivées. La technique marche d'autan mieux si les instructions sont compactées au début de la ''scheduler''. [[File:Wire partitionning.png|centre|vignette|upright=2|Wire partitionning]] Tout le problème est de savoir quelles portions désactiver. La technique est assez simple si la ''scheduler'' est compactée, à savoir si toutes les instructions sont régulièrement regroupées au début de la mémoire CAM. Mais même avec cette optimisation, la décision de désactiver une portion de la ''scheduler'' n'est pas à prendre à la légère. Il ne faut pas désactiver une portion contenant des instructions pouvant être émise sous peu. La décision dépend de paramètres variés : proportion d'entrée vides, quantité d'entrées récemment activées/désactivées récemment, présences d'entrées avec un ''match'' d'opérandes récent, etc. Il est important de préciser que les techniques en question fonctionnent aussi sur les autres types de ''scheduler'', qui ne sont pas basées sur des mémoires associatives. Nous allons voir celles-ci dans la suite du chapitre, mais gardez à l'esprit que ces optimisations, à savoir désactiver les entrées vides/prêts et partitionner la ''scheduler'', sont des optimisations générales qui marchent avec presque tout. ===L'ajout d'une FIFO pour les instructions déjà prêtes à l'émission=== D'autres techniques permettent de réduire aussi bien le cout en circuits que la consommation d'énergie de la ''scheduler''. L'idée est d'utiliser une mémoire associative quand elle est réellement nécessaire, mais d'utiliser un ''scheduler'' "normale" dès que possible. La méthode la plus simple tient compte du fait que certaines µopsont déjà toutes leurs opérandes de disponibles à l'émission, mais doivent quand même être mises en attente, parce que l'ALU adéquate est occupée, parce que des dépendances WAW/WAR sont encore là, ou pour tout autre raison. Dans ce cas, elles sont mises en attente non pas dans la ''scheduler'', mais dans une mémoire FIFO toute simple. L'idée est qu'au lieu d'avoir une énorme mémoire associative pour la ''scheduler'', on déplace quelques entrées dans une petite FIFO annexe. Le résultat est un gain d'énergie et de circuits, au prix d'une perte de performance mineure. La perte de performance en question se manifeste si aucune instruction n'a ses opérandes de prêtes à l'émission : le programme n'utilise pas la FIFO et voit alors un ''scheduler'' plus petite. Une amélioration de cette technique tient compte du fait que certaines instructions sont dans un cas intermédiaire. Elles ont déjà un opérande de prête lors de l'émission, mais pas l'autre. Le nombre d'opérandes varie suivant l’instruction : certaines n'ont besoin que d'un seul opérande. De plus, il arrive qu'une opération tout juste décodée ait déjà un ou plusieurs de ses opérandes de prêts. Cette constatation permet d'éviter d'utiliser des comparateurs pour les opérandes déjà prêts. Par exemple, on peut parfaitement utiliser trois ''scheduler'' : * une pour les instructions dont tous les opérandes sont prêts, mais qui sont quand même mises en attente, sans comparateur ; * une pour les instructions dont un seul opérande manque, qui n'utilise qu'un comparateur par entrée ; * une pour les instructions dont deux opérandes manquent à l'appel, qui utilise deux comparateurs par entrée. C'est beaucoup plus économique que d'utiliser une seule grosse ''scheduler'' qui contiendrait autant d'entrées que les trois précédentes réunies, avec deux comparateurs par entrée. Certains sont même allés plus loin, et ont proposé de supprimer la ''scheduler'' avec deux opérandes par entrée. Les instructions dont deux opérandes sont inconnus au décodage sont stockées dans la ''scheduler'' pour instructions avec un comparateur par entrée. Un circuit de prédiction se charge alors de prédire l'opérande manquant, cette prédiction étant vérifiée plus loin dans le pipeline. Il serait cependant étonnant qu'une telle proposition ait donné lieu à la moindre implémentation réelle. ===Les optimisations de la consommation d'énergie avancées=== D'autres chercheurs ont conservé un ''scheduler'' unique, avec autant de comparateurs par entrée qu'il y a d'opérandes possibles par instruction. Simplement, le processus de détection des opérandes prêts est légèrement ralenti : on ne vérifie qu'un opérande par cycle. Pour vérifier les deux opérandes d'une entrée, on doit attendre deux cycles. Enfin, certains chercheurs ont proposé des ''scheduler'' segmentées. Les instructions circulent à chaque cycle d'un segment vers le suivant : en conséquence, certains segments conservent les instructions les plus anciennes, un autre les instructions les plus jeunes, etc. Seul le denier segment, celui qui contient les instructions les plus vielles, peut émettre une instruction : la détection des opérandes se fait seulement dans le dernier segment, qui contient les instructions les plus anciennes. On économise ainsi beaucoup de comparateurs. Certains chercheurs ont tenté de pipeliner l'étape de sélection des opérandes, ainsi que l'étage d'arbitrage. Mais en faisant cela, il faut plusieurs cycles pour détecter qu'une instruction a ses opérandes prêts, ce qui pose problème face à de nombreuses dépendances RAW. Pour éviter de trop perdre en performances, certains chercheurs ont décidé d'utiliser des techniques pour prédire quelles seront les instructions dont les opérandes seront bientôt prêts. Si détecter qu'une instruction est prête prend n cycles, le processeur devra tenter de prédire la future disponibilité des opérandes n cycles en avance pour obtenir des performances optimales. ===Remplacer la mémoire associative par une RAM=== Une autre optimisation possible est de remplacer la ''scheduler'' par une mémoire RAM, dont chaque mot mémoire correspondrait à une entrée. Une telle optimisation permet en théorie de se passer des comparateurs associés à chaque entrée, mais au prix de l'ajout de circuits annexes potentiellement couteux. La première de ces techniques, la '''recherche directe par étiquette''' (direct tag search) fut créée par Weiss et son collègue Smith. Ils cherchaient à améliorer l'algorithme de Tomasulo, un algorithme qu'on expliquera dans quelques chapitres. Rappelons que chaque instruction produit un résultat, qui devra être rapatrié dans une ou plusieurs entrées de la ''scheduler''. L'optimisation de la recherche directe par étiquette fonctionne dans le cas où le résultat de l'instruction n'est utilisé que par une seule entrée, et pas plusieurs. Le principe est simple : chaque champ « opérande » d'une entrée est adressable via le nom de registre de cet opérande. Pour faire le lien entre entrée et nom de registre, la recherche directe par étiquette ajoute une table de correspondances matérielle, une mémoire RAM qui mémorise les adresses des champs « opérande » des entrées. Les adresses envoyées dans cette mémoire sont les noms de registres des résultats. Lors de l'émission, la table de correspondances est mise à jour. Les numéros des champs « opérande » réservés lors de l'émission sont mémorisés dans les mots mémoire qui correspondent aux deux registres sources. Toutefois, une petite vérification est faite lors de l'émission : s'il y a déjà une correspondance dans la table pour un registre source, alors une autre instruction compte lire ce registre. Pour éviter d'écraser les données de l'instruction précédente dans la table de correspondances, l'émission de l'instruction est bloquée. [[File:Recherche directe par étiquette.png|centre|vignette|upright=2|Recherche directe par étiquette.]] ==Les ''schedulers'' avec préplanification== Avec la '''préplanification''' (''prescheduling''), le ''scheduler'' est composée de mémoires FIFO dans lesquelles les instructions sont triées dans l'ordre d'émission. Il n'y a pas de logique d’émission proprement dite, celle-ci se bornant à vérifier si l'instruction située au début de la FIFO peut s’exécuter. Par contre, le préplanificateur détecte les dépendances et en déduit où insérer les instructions dans le tampon d'émission, à l'endroit le plus adéquat. [[File:Préplanification.jpg|centre|vignette|upright=2|Préplanification.]] ===L'usage de FIFO multiples=== La technique de préplanification la plus simple utilise plusieurs FIFO. Quand une instruction a une dépendance avec une autre instruction, les deux sont placées dans la même FIFO. Pour cela, le préplanificateur détecte les chaines d'instructions dépendantes, et place les instructions dans la FIFO adéquate. A chaque cycle, l'unité d'émission lit une micro-opération dans chaque FIFO et vérifie si elle peut l'émettre. Si la micro-opération n'a pas ses opérandes disponibles, ou qu'une dépendance structurelle survient, alors la FIFO est bloquée. La micro-opération attend que la dépendance soit résolue, bloquant toutes les instructions précédentes. Mais les autres FIFO ne sont pas bloquées, laissant de la marge de manœuvre. [[File:Préplanification par FIFO multiples.png|centre|vignette|upright=1.5|Préplanification par FIFO multiples.]] ===La technique du tampon trié=== La technique du '''tampon trié''' trie les instructions selon le temps d'attente avant leur exécution. Les instructions qui sont censées s’exécuter bientôt sont insérées au tout début de la FIFO, tandis que les instructions qui s’exécuteront dans un long moment sont insérées vers la fin. Là encore, l'unité d'émission lit une micro-opération dans la FIFO, et détermine si elle peut être émise. Si une dépendance survient, l'émission est retardée, et la FIFO est bloquée. [[File:Préplanification par tampon trié.png|centre|vignette|upright=1.5|Préplanification par tampon trié.]] La technique a cependant quelques problèmes assez importants. Le premier problème est que la FIFO est bloquée lorsqu'une micro-opération ne peut être émise. Le second problème est que le temps avant exécution n'est pas toujours connu, notamment pour les instructions d'accès mémoire. Et cela se répercute sur les instructions dépendantes de celles-ci. Pour résoudre ce genre de problèmes, l'usage d'un pipeline à ''replay'' est possible, et est même l'une des meilleures solutions possible, malgré ses défauts. L'idée est que les lectures sont pré-planifiées en supposant qu'elles font un succès de cache L1. Si la prédiction est fausse, la lecture est ré-exécutée plusieurs cycles plus tard, en supposant qu'elle fait un succès dans le cache L2, et ainsi de suite. Elle est alors ré-insérée dans la FIFO, elle est pré-planifiée une seconde fois. Il en est de même si une micro-opération ne peut pas être émise : il suffit de la réinsérer dans la FIFO au bon endroit, en attendant que ses dépendances soient résolues. Ainsi, l'instruction fautive ne bloque pas la fenêtre d’instruction, et retente sa chance autant de fois qu'il le faut. [[File:Préplanification par fenêtre d’instruction scorebarodée.png|centre|vignette|upright=1.5|Préplanification par fenêtre d’instruction scorebarodée.]] Une autre solution utilise deux ''schedulers'' : une FIFO gérée par la préplanification, et une vraie ''scheduler'' pour les instructions dont le temps d'attente ne peut pas être déterminé. Il est possible de mettre cette dernière avant la préplanification, afin de gérer les temps d'attente des instructions d'accès mémoire. Quand le temps d'attente d'une lecture devient connu, ses instructions dépendantes sont gérées avec préplanification. [[File:Préplanification avec fenêtre d’instruction.png|centre|vignette|upright=2.5|Préplanification avec fenêtre d’instruction.]] ===Les ''scheduler'' avec allocation temporelle statique=== L''''allocation temporelle statique''' correspond à une technique utilisée sur les processeurs Cuzco de l'entreprise Condor. La technique en question a été présenté en 2025, mais des idées similaires ont été présentées dans la littérature académique. Elle ressemble beaucoup aux techniques de pré-planification, avec cependant quelques différences. L'idée est simple : le processeur dispose de plusieurs ''scheduler'', qui mettent en attente les micro-opérations. Lors de l'étape de renommage de registres, le processeur détermine dans combien de cycles d'horloge la micro-opération sera prête pour exécution. La micro-opération est alors mise en attente durant ce nombre de cycles, dans les ''scheduler'', puis est émise une fois ce nombre de cycles écoulés. Ce faisant, les ''scheduler'' n'ont pas besoin de détecter la disponibilité des opérandes à chaque cycle, pour chaque micro-opération en attente. Le ''timing'' de l'émission des micro-opérations est décidé à l'avance. L'implémentation exacte n'est pas connue, mais plusieurs solutions sont imaginables. Par exemple, la ''scheduler'' peut simplement être composée de plusieurs mémoires de petite taille, chacune contenant les micro-opérations destinées à être exécutées dans N cycles, N étant différent pour chaque mémoire. Une autre solution, plus réaliste, utilise un ''scheduler'' dans laquelle la micro-opération est couplée à des champs pour les opérandes, et un champ compteur. Le champ compteur est initialisé avec le nombre de cycles à attendre, et est décrémenté à chaque cycle d'horloge. Quand il atteint zéro, la micro-opération est émise. Vous remarquerez que la méthode ne marche que si toutes les micro-opérations prennent un nombre fixe de cycles d'horloge. Et autant c'est le cas pour les micro-opérations arithmétiques ou logiques, autant les accès mémoire ne rentrent pas dans ce cadre. En théorie, on ne sait pas combien de temps prendra un accès mémoire. Et cette incertitude se répercute sur les instructions dépendantes d'un accès mémoire. Pour éviter cela, le processeur réutilise un pipeline à ''replay'' tel que vu dans le chapitre précédent. L'unité de renommage de registre suppose que tout accès mémoire fait un succès de cache L1, et décide des ''timings'' d'émission sous cette hypothèse. Si une lecture subit un défaut de cache, elle est ré-exécutée, de même que toutes les instructions dépendantes. Pour cela, le registre de destination de la lecture est marqué comme invalide, grâce à un bit spécifique attaché au registre. Toute instruction qui lit un opérande invalide est elle aussi ré-executée de zéro. Pour simplifier, l'unité d'émission ressemble à une unité d'émission dans l'ordre, avec un registre de disponibilité, qu'on aurait amélioré pour aller au-delà de la simple détection des dépendances d'instruction. Pour déterminer les ''timings'' d'émission, à savoir quand émettre une micro-opération, le processeur utilise une unité d'émission à deux étages. Le premier étage est appelé le ''register scoreboard'', le second étage est appelé la ''Time Ressource Matrix''. Les deux étages communiquent entre eux, comme on va le voir, et leurs noms donnent une idée de ce qu'ils font. Le premier étage gère les dépendances de registres, le second gère les dépendances structurelles. Le premier étage est un registre de disponibilité amélioré, qui gère les dépendances de registre. Cet étage sait quand tel registre sera écrit, et donc que l'opérande écrit dedans sera disponible à partir de tel cycle d'horloge. Il le sait car l'étage suivant l'aura prévenu, mais laissons cela de côté pour le moment. Quand une micro-opération rentre dans cet étage, il vérifie les dépendances avec les registres et les micro-opérations antérieures. Vu qu'il sait quand les registres seront disponibles, il peut déterminer quand l'instruction pourra s'exécuter. Par exemple, si une micro-opération lit les deux registres R7 et R15, qui sont disponibles respectivement dans 5 et 7 cycles, le premier étage sait que la micro-opération devra attendre 7 cycles. Mais tout cela ne suffit pas à déterminer quand émettre une micro-opération. En effet, il fait aussi gérer les dépendances structurelles, ce qui est le boulot du second étage. Le second étage utilise pour cela une ''Time Ressource Matrix'', qui mémorise l'occupation de diverses "ressources", pour les 256 cycles d'horloge à venir. Les ressources en question sont les ports de lecture/écriture du banc de registre, les ALUs utilisées, si la micro-opération utilise l'unité mémoire, etc. Le second étage prend en entrée une micro-opération, détermine quelles "ressources" elle utilise, puis regarde leur disponibilité. Elle détecte alors les dépendances structurelles et détermine alors quand peut s'exécuter la micro-opération. Elle peut retarder l'émission de quelques cycles, si une dépendance structurelle est détectée. Une fois sortie du second étage, on sait quand la micro-opération va être émise, à quel cycle précisément. Et vu que la durée de l'instruction est fixe, on sait quand cette micro-opération va se terminer, quand son résultat sera disponible. Cela permet de mettre à jour la ''Time Ressource Matrix'', pour préciser que le port d'écriture sera occupé à tel moment. De plus, cette information est transmise au premier étage, qui sait alors quand est enregistré le résultat dans le registre de destination. C'est comme cela que le premier étage sait quand un registre est disponible : le second étage le prévient, quand il émet une instruction ! La ''Time Ressource Matrix''mémorise l'occupation des "ressources" pour les 256 cycles d'horloge à venir. Cependant, elle ne vérifie pas les dépendances pour les 256 cycles suivants. Quand elle reçoit une micro-opération, elle teste les dépendances structurelles pour seulement les 8 prochains cycles maximum. Si la micro-opération ne peut pas être émise pendant ces 8 cycles, le pipeline est bloqué, un ''pipeline stall'' est émis. Pour être plus précis, vu que le processeur peut décoder 8 micro-opérations en même temps, cela permet de ne consulter que 64 cycles d'horloge sur les 256. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les premiers processeurs Intel | prevText=Les premiers processeurs Intel | next=Le renommage de registres | nextText=Le renommage de registres }} </noinclude> qmd98mq9xv9vify4ynt2bhnulxls7lp 773625 773624 2026-09-29T21:03:05Z Mewtow 31375 /* La logique de sélection : âge ou position ? */ 773625 wikitext text/x-wiki Dans les chapitres précédents, nous avons parlé des techniques dites d''''émission dans l'ordre'''. L'idée est d’exécuter une nouvelle micro-opération à chaque cycle, dans des unités de calcul séparées. Les instructions sont émises consécutivement, mais les instructions s’exécutent en parallèle dans des unités de calcul séparées. Par contre, quand l'unité d'émission ne peut pas émettre une instruction, elle bloque tout le pipeline. Les instructions qui suivent sont elles aussi bloquées, elles doivent attendre leur tour, même si elles sont en capacité de s'exécuter. Les techniques d'exécution dans le désordre que nous allons voir dans ce chapitre corrigent ce point précis. Elles sont dites à '''émission dans le désordre'''. Elles se distinguent des précédentes sur un point précis : quand l'unité d'émission bloque l'émission d'une instruction, les instructions suivantes peuvent poursuivre. L'émission des instructions peut donc se faire dans le désordre, dans le sens où une instruction peut être émise alors qu'une instruction précédente ne l'est pas encore. Mais avant de poursuivre, quelques point niveaux terminologie : * L'émission dans le désordre est un terme parlant et assez précis. Malheureusement, la terminologie la plus utilisée par d''''exécution dans le désordre'''. Et nous utiliserons ce terme dans la suite du cours, histoire de ne pas trop dévier de la nomenclature habituelle. * Nous utiliserons parfois l'abréviation OOO pour parler d'exécution dans le désordre. L'abréviation est celle de ''Out Of Order Excution''. * Nous utiliserons aussi l'abréviation ''µop'' pour parler de micro-opération, ''µops'' au pluriel pour parler de plusieurs micro-opérations, ou des micro-opérations en général. L'exécution dans le désordre ne gère en effet que des µops, elle se situe après l'étape de décodage. Pour décrire comment est implémentée l'émission dans le désordre, il faut commencer par parler des processeurs sans. Les processeurs sans exécution dans le désordre ont une unité d'émission qui bloque tout le pipeline dès qu'une µop ne peut pas être émise. Pour limiter l'impact de ce blocage, quelques rares processeurs incorporent une '''file de micro-opération''', une mémoire FIFO qui met en attente les µops. Vu que c'est une mémoire FIFO, les µops sont émises dans l'ordre, à savoir l'ordre d'ajout, dans l'ordre de décodage. Le schéma ci-dessous illustre une telle file d'attente couplée à un ''scoreboard''. L'exécution dans le désordre améliore la file de µops sur un point : ce n'est plus une mémoire FIFO. Les µops sont insérées dans l'ordre, mais peuvent sortir dans le désordre (être émises dans le désordre). La file de µops devient alors un '''''scheduler''''', terme anglais que je ne compte pas traduire. Un terme équivalent est '''''scheduler''''', terme traduit directement de l'anglais ''instruction Window''. Terme assez trompeur, car elles mettent en attente des µops, pas des instructions. [[File:Différence file µops et fenêtres instruction.png|centre|vignette|upright=2|Différence file µops et ''schedulers'' ]] Le ''scheduler'' émet une µop dès que ses opérandes sont disponibles. Par disponible, on veut dire présent soit dans le réseau de contournement, soit dans les registres. Le ''scheduler'' détecte automatiquement quand les opérandes d'une µop sont disponibles, grâce à une unité d'émission intégrée. L'unité d'émission et le ''scheduler'' sont fusionnés ensemble, dans un seul circuit, mais nous allons dire qu'ils sont conceptuellement séparés pour le moment. A chaque cycle, l'unité d'émission consulte les µops en attente pour détecter lesquelles peuvent s'exécuter. Le ''scheduler'' est spécialement être conçue pour, c'est une sorte de mémoire associative très complexe, comme on le verra dans ce qui suit. [[File:OOO Issue.png|centre|vignette|upright=2.5|Exécution dans le désordre avec un ''scheduler'']] Une fois qu'une µop sort du décodeur d'instructions, elle est ajoutée en parallèle dans la ''scheduler'' et le ROB. La raison est que les µops quittent la ''scheduler'' dans le désordre, et qu'elles doivent être remises en ordre par la suite. Le ROB s'occupe de cette remise en ordre, mais il a besoin de savoir dans quel ordre les µops sont censées être, et cet ordre est celui du décodage. Aussi, pour remplir le ROB, la seule opportunité est en sortie de l'unité de décodage. Dans le cas où une instruction est décodée en plusieurs micro-opérations, elles sont toutes insérées en même temps dans la ''scheduler'' et le ROB, en tenant compte de leur ordre. L'implémentation la plus simple de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Les µops décodées sont accumulées dans le ''scheduler'', où elles attendent leur tour. La ''scheduler'' sert donc de file d'attente. Avant de poursuivre, précisons que les micro-opérations mémoire sont à part des autres, pour diverses raisons. Une de ces raisons est que les dépendances de données sont classées en deux types : les dépendances de registre et les dépendances d'adresse. Et les deux sont fondamentalement différentes. Autant on peut détecter les dépendances de registre lors de l'émission, autant c'est plus compliqué avec les dépendances d'adresse. De plus, rappelons que si les lectures peuvent s'exécuter dans le désordre, les écritures doivent s'exécuter dans l'ordre, ou du moins en donner l'illusion. Pour cela, le processeur remet les écritures dans l'ordre avec une sorte de mini-ROB intégré à l'unité mémoire, appelée la file d'écriture. Elle complémente le ROB, qui lui ne gère que les écritures dans les registres, mais les deux collaborent. La file d'écriture envoie une écriture à la mémoire RAM quand le ROB lui dit que c'est bon, les instructions précédentes sont terminées ''dans l'ordre du programme''. Les processeurs modernes ajoutent des techniques d'exécution dans le désordre des accès mémoire, mais nous les verrons dans un chapitre dédié. Elles permettent d'utiliser un ''scheduler'' unique, qui mémorise aussi les µops mémoire. Si elles sont mises en place, l'unité mémoire n'a pas besoin de file de µops séparée. L'idée est que les dépendances de registre sont traitées par la ''scheduler'', mais que l'unité mémoire gére les dépendances d'adresse. Les dépendances d'adresse sont gérées par des techniques de ''désambiguation mémoire'', qui auront droit à un chapitre dédié. [[File:Processeur avec exécution dans le désodre des accès mémoire.png|centre|vignette|upright=2|Processeur avec exécution dans le désodre des accès mémoire]] Les processeurs assez anciens n'autorisaient pas d'exécution dans le désordre des accès mémoire. Concrétement, les accs mémoire devaient se faire dans l'ordre, mais les autres µops pouvaient être exécutées dans le désordre. Il s'agit donc d'un ordre entre µops mémoire, pas entre µops mémoire et autres µops. Les µops entières et flottantes pouvaient être exécutées avant une µops mémoire qui est avant elle dans l'ordre du programme, ce n'est pas un problème. Pour garantir l'ordre des µops mémoire, l'unité mémoire est précédée par une file de micro-opérations séparée, pour forcer l'exécution dans l'ordre des accès mémoire. De plus, les µops mémoire ne peuvent pas utiliser la ''scheduler''. Dit autrement, la ''scheduler'' ne mémorise pas de µops mémoire. Après le décodage, les µops sont réparties soit dans la file de µops mémoire, soit dans la ''scheduler''. Le décodeur classe les µops suivant que ce sont des µops mémoire ou non, et les envoient à la bonne destination. Dans ce chapitre, on supposera que c'est cette solution qui est utilisée. [[File:Processeur avec émission dans l'ordre des accès mémoire.png|centre|vignette|upright=2|Processeur avec émission dans l'ordre des accès mémoire]] ==L'implémentation d'un ''scheduler'' : généralités== Un ''scheduler'' est une mémoire qui mémorise des micro-opérations. Elle est cependant plus complexe qu'une mémoire RAM ou qu'une FIFO et ressemble un petit peu à une mémoire cache. Elle dispose d'un port d'écriture et d'un port de lecture, au minimum. Le port d'écriture permet à l'unité de décodage d'insérer une micro-opération dedans, d'ajouter la micro-opération qui vient d'être décodée. Si une instruction machine est décodée en plusieurs micro-opération, deux possibilités. La première est de les insérer un par un, ce qui fait qu'on peut se contenter d'un seul port d'écriture. L'autre possibilité est de les ajouter en même temps, ce qui demande plusieurs ports d'écriture. Le port de lecture sert à émettre une instruction. On part du principe que la ''scheduler'' ne peut émettre qu'une seule instruction à la fois, car les processeurs que nous avons vu précédemment sont de ce type. Mais nous verrons dans quelques chapitres qu'il existe des processeurs dits superscalaires, qui sont capables d'émettre plusieurs instructions par cycle. Dans ce cas, la ''scheduler'' a un seul port de lecture. Un processeur superscalaire, quant à lui, doit avoir un port de lecture par unité de calcul, ce qui fait beaucoup plus. Les ''schedulers'' sont composées d''''entrées''', des mots mémoire qui stockent une instruction. Une instruction réserve une entrée après son décodage et la libère dès qu'elle est envoyée aux unités de calcul. Une entrée contient l'opcode (les signaux de commande à envoyer à l'ALU), le registre de destination du résultat, les registres de chaque opérande, et éventuellement des signaux de commande en plus. De plus, chaque opérande est couplée à un bit de disponibilité, qui indique si elle est disponible. Quand un opérande est écrit dans les registres, le bit de présence correspondant est mis à jour. Enfin, chaque entrée possède un bit ''empty'' qui indique si elle est vide, cette information étant utile pour réserver des entrées. [[File:Entrée d'une station de réservation - sans les tags.png|centre|vignette|upright=3|Entrée d'un ''scheduler'']] ===Les stations de réservation=== Les '''stations de réservation''' sont des ''scheduler'' particulières, qui sont capables de mémoriser les opérandes des instructions. Les entrées des stations de réservation sont identiques à celle des autres ''scheduler'', si ce n'est que les opérandes de l'instruction sont enregistrés directement dans des champs séparés. Il y a deux champs, un par opérande, pour stocker l'opérande elle-même, lue depuis les registres ou obtenue via le réseau de contournement. Notons que les champs pour les opérandes viennent en plus des champs pour les noms de registres, encore que les deux peuvent être fusionnés si on veut optimiser le tout. [[File:Entrée d'une station de réservation.png|centre|vignette|upright=3|Entrée d'une station de réservation.]] Précisons que la terminologie n'est pas très fiable. Les termes "''scheduler''" et "station de réservation" ne regroupent pas du tout la même chose d'un papier de recherche à l'autre, d'un bouquin à l'autre, d'un chercheur à l'autre, d'un ingénieur à l'autre, d'un professeur à l'autre. Le terme initial vient pourtant de l'article original sur l'algorithme de Tomasulo, où il désignait un ''scheduler'' associée à une unité de calcul précise. Mais le terme a ensuite été réutilisé, ce qui fait que certains processeurs avec plusieurs unités de calcul sont décrits comme ayant une unique station de réservation. En bref : c'est le bazar ! Mais nous en reparlerons dans le chapitre sur le renommage de registres, car c'est la place idéale pour les aborder. Toujours est-il que j'ai fait le choix de confondre les concepts de ''scheduler'' et de station de réservation avec les concepts de '''lecture avant émission''' et de '''lecture après émission'''. La différence entre les deux est que les registres sont lus après émission avec un ''scheduler'', avant avec des stations de réservation. Dans le cas "avant émission", les opérandes sont mémorisés dans la station de réservation. Et cette différence a une influence sur le pipeline du processeur, le banc de registres et tout ce qui s'en suit. Un désavantage de la lecture avant émission est qu'il faut stocker les opérandes après lecture, ici dans les stations de réservation. Mais un avantage est que le banc de registre a besoin de moins de ports de lecture, car une bonne partie des opérandes sont fournies par le système de contournement. Nous verrons cela dans le détail dans le chapitre sur les processeurs superscalaires. [[File:Processeur avec plusieurs ''scheduler''.png|centre|vignette|upright=2.5|Lecture après émission.]] [[File:Read Before Issue.png|centre|vignette|upright=2.5|Lecture avant émission.]] ===La logique d'éveil et de sélection=== Dans le cas qui va suivre, on suppose que le processeur ne peut émettre qu'une instruction à la fois. Chaque cycle, une instruction est sélectionnée et est envoyée dans le chemin de données, soit à une ALU, soit à une unité d'accès mémoire. La sélection d'une instruction est effectuée par l'unité d'émission, qui est aussi appelée le '''''scheduler'''''. Elle gère la disponibilité des opérandes et la disponibilité des unités de calcul adéquate. Le choix de l'instruction émise doit être le plus pertinent possible, pour des raisons de performances. Pour le premier point, l'unité d'émission détermine quelles instructions sont candidates pour l'émission. Les ''instructions candidates'' sont celles dont tous les opérandes sont prêts. Le processeur contient un circuit qui détecte les instructions candidates : la '''logique d’éveil''' (''wake-up logic''). Une fois que la logique d'éveil a fait son travail, une instruction est choisie pour s’exécuter en fonction de la disponibilité des unités de calcul adéquates. Ce rôle est dévolu à un circuit qu'on appelle la '''logique de sélection''', ou ''select logic''. [[File:Fonctionnement complet de la logique d’émission.jpg|centre|vignette|upright=1.5|Fonctionnement complet de la logique d’émission.]] La logique de sélection doit gérer le fait que les unités de calcul du processeur ne sont pas toutes identiques. Déjà, un processeur a généralement des unités séparées pour les instructions entières et flottantes, des unités spécialisées dans les accès mémoire, parfois des unités spécialisées pour les branchements. Une instruction doit être attribuée à la bonne unité de calcul, on ne doit pas envoyer une instruction entière dans une unité de calcul flottante. De plus, parmi les unités de calcul entières, toutes ne sont pas identiques. Par exemple, il est fréquent d'avoir plusieurs unités de calcul spécialisées dans les opérations simples (additions, soustractions, opérations logiques) avec une unité pour les multiplications/divisions séparées, parfois une unité spécialisée pour les décalages/rotations, etc. Là encore, allouer la bonne instruction à la bonne ALU est complexe. Plus les unités de calcul sont hétérogènes, plus la logique de sélection est compliquée. Les logiques d'éveil comme de sélection sont assez complexes. Comme on le verra plus bas, la logique de sélection la plus simple, qui gère une seule unité de calcul, est basée sur un encodeur à priorité couplé à d'autres circuits. Et pour gérer plusieurs ALUs, il faut mettre des encodeurs en cascade. Le résultat est que même en prenant une logique de sélection simple, elle sera assez lente et gourmande en circuits. Aussi, la logique de sélection met souvent un cycle d'horloge entier pour faire son travail, elle a son propre étage de pipeline attribué. La logique d'éveil est dans le même cas, ce qui fait qu'émettre une micro-opération demande deux cycles d'horloge. Le défaut est que cela rajoute des cycles d'horloges entre la ''scheduler'' et l'ALU, ce qui complique la gestion du pipeline. Ces cycles de retard sont à prendre en compte au moment d'émettre les instructions, les ''scheduler'' doit en tenir compte pour des performances optimales. Sans tenir compte de ces cycles de retard, les instructions arrivent en retard de quelques cycles à l'ALU, cycles de retard durant lesquels l'ALU n'a pas fait de calcul et a été sous-utilisée, sans compter que le système de contournement n'est pas utilisé au mieux. Et le problème est encore plus important sur les processeurs avec des stations de réservation, qui utilisent la "lecture après émission" : cela rajoute un cycle d'horloge en plus, un temps de retard en plus. ===La logique d'éveil : l'émission anticipée=== La logique d'éveil doit tenir compte du fait qu'il y a plusieurs étages entre l'émission et l'exécution sur une unité de calcul. Par exemple, un processeur a souvent entre un et à cinq étages entre la file d'attente et les unités de calcul. Il faut lire les registres, gérer le contournement, et cela peut prendre quelques cycles d'horloge. Sur le Pentium 4, on trouve 6 étages entre le ''scheduler'' et l'entrée de l'ALU. Si les micro-opérations sont émises quand les opérandes sont disponibles, il y aura un délai de quelques cycles avant qu'elles atteignent l'ALU. Alors qu'idéalement, on souhaiterait que la micro-opération atteigne l'ALU dès que ses opérandes sont disponibles, pour profiter des techniques de contournement. Pour cela, la logique d'éveil émet les instructions quelques cycles en avance pour qu'elles arrivent au bon moment. Il s'agit d'une technique d''''émission anticipée''', dont nous avions parlé dans le chapitre sur le contournement. : Il faut noter que le problème se pose plus avec des ''scheduler'' qu'avec des stations de réservation. Les premières ont un étage en plus entre émission et ALU, vu qu'il faut lire des registres après l'émission. L'émission anticipée demande d'émettre un signal d'éveil en avance de quelques cycles, pile au bon moment. Par exemples, si on a deux étages entre l'ALU et l'unité d'émission, le signal de réveil sera généré deux cycles avant que le résultat soit effectivement calculé. L'implémentation varie, mais deux solutions sont possibles. La première est de générer le signal d'éveil dans l'ALU, ce qui n'a de sens que pour les opérations comme les multiplications ou les divisions, qui prennent plusieurs cycles. Une autre technique génère le signal de réveil dans une structure centralisée, spécialisée dans la génération des signaux d'éveil. L'unité de composée d'un registre à décalage par registre. Imaginons qu'une instruction est émise, que cette instruction mette N cycles à s'exécuter, et qu'elle écrive dans un registre de destination. L'unité sélectionne alors le registre à décalage associé au registre de destination, et met le bit numéro N à 1. Le registre décalé d'un cran à chaque cycle. Quand le bit sortant est un 1, alors le signal de validité pour l'opérande est généré. L'émission anticipée marche bien si l'instruction a une durée fixe, connue à l'avance. Et autant c'est le cas pour les instructions arithmétiques et logiques, autant ce n'est pas le cas pour les accès mémoire. Les accès mémoire ont une latence variable : quelques cycles pour un succès de cache, plusieurs dizaines de cycles pour un défaut de cache L1, pas loin de la centaine pour un défaut de cache L2, etc. Et cela pose des problèmes pour l'émission anticipée. L'émission en avance pour les accès mémoire est purement spéculative : le processeur émet des instructions en supposant que la lecture entrainera un succès de cache, quitte à annuler l'instruction en cas de défaut de cache. Mais faire ainsi demande non seulement d'annuler les instructions émises en avance, mais aussi de ne pas retirer les instructions émises en avance de la ''scheduler''. Elles sont émises, mais une copie de sauvegarde est conservée dans la ''scheduler''. Si le processeur détecte un défaut de cache, il peut alors ré-exécuter l'instruction. S'il détecte un succès de cache, les instructions lecture-dépendante sont retirées de la ''scheduler'', la copie de sauvegarde est devenue inutile et est donc jetée. ===La logique de sélection : âge ou position ?=== La logique de sélection est primordiale pour de bonnes performances. Il existe deux méthodes principales pour sélectionner l'instruction à exécuter. La première est la plus simple : elle se base sur lé numéro de l'entrée. En effet, un ''scheduler'' est avant tout une sorte de mémoire, un mix entre mémoire associative, mémoire RAM, et FIFO. Et chaque entrée a un numéro, une adresse mémoire. Nous parlerons de numéro dans ce qui suit, car ce sera plus simple, le terme d'adresse mémoire étant peut-être un peu exagéré dans le contexte des ''scheduler''. Toujours est-il que la ''scheduler'' est adressable dans le sens où on peut lui envoyer le numéro de l'entrée voulue, et le ''scheduler'' renvoie le contenu de l'entrée sur son port de lecture. Et c'est ce que fait la logique de sélection : elle génère le numéro de l'entrée à lire. Le numéro est alors envoyé sur l'entrée d'adresse du ''scheduler'', et elle fournit la micro-opération associée sur son port de lecture, son '''port d'émission'''. La première méthode de sélection, donc. Elle est basée sur le numéro de l'entrée. Si plusieurs entrées sont éveillées, la logique de sélection prend celle avec le plus petit numéro. Elle porte le nom de '''sélection par position''', sous-entendu position dans la ''scheduler''. Vous l'avez peut-être deviné, mais la logique de sélection est alors un encodeur à priorité. Le circuit de sélection ne se résume donc pas seulement à un encodeur à priorité, mais c'est le circuit central. L'avantage d'une telle méthode de sélection est qu'elle est simple à implémenter : un encodeur à priorité est un circuit connu, facile à implémenter. Mais on remarque un défaut : un encodeur est un circuit assez rapide, mais qui utilise beaucoup de transistors, beaucoup de portes logiques, surtout si on veut qu'il soit rapide. Ce qui explique que la logique de sélection ait son propre étage de pipeline rien que pour elle. La seconde méthode s'appelle la '''sélection par âge''', au nom assez transparent. L'idée est de privilégier l'émission de l'instruction la plus ancienne. Elle demande que la ''scheduler'' trie les micro-opérations par ordre d'insertion dans la ''scheduler'', ce qui en fait une pseudo-FIFO. Le tri est partiel, car les instructions peuvent sortir de la fenêtre d’instruction à tout moment. Compacter la ''scheduler'', à savoir regrouper toutes les entrées valides est une idée, mais elle est compliquée à implémenter. Aussi, elles préfèrent encoder des informations sur l'ordre d'émission dans chaque entrée. L'encodeur à priorité doit alors travailler non pas sur des nombres entiers liés à l'ordre d'insertion dans la pseudo-FIFO. Elle est encore plus gourmande en circuits que la méthode précédente. Les processeurs haute performance utilisent souvent des méthodes hybrides. Par exemple, les processeurs AMD de microarchitecture Bulldozer utilisaient une méthode intermédiaire. Ils utilisaient un ''scheduler'' couplée à un encodeur à priorité pour la sélection par position, mais complémentaient le tout avec une unité qui mémorisait l'instruction la plus ancienne dans la fenêtre d’instruction. Le mécanisme de sélection par âge était utilisé en priorité. Mais si l'instruction la plus ancienne n'était pas prête, le processeur basculait sur le mécanisme de sélection par position. ===La compaction des ''scheduler''=== À chaque cycle, les instructions décodées sont ajoutées dans la ''scheduler'', dans des entrées vides. Vu que les instructions quittent celle-ci dans le désordre, ces vides sont dispersés dans la ''scheduler'', ce qui pose problème pour déterminer où placer les nouvelles instructions. La solution la plus triviale consiste à conserver une liste des vides, mise à jour à chaque insertion ou émission d'instruction. Une autre solution consiste à éliminer les vides en compactant la ''scheduler'' à chaque cycle d'horloge. Des circuits se chargent de détecter les vides et de regrouper les instructions en un unique bloc. Il faut signaler que certains processeurs arrivent à se passer de cette étape de compactage, mais au prix de ''scheduler'' nettement plus complexes. Autre problème : quand il faut choisir quelle instruction émettre, il y a toujours plusieurs candidats. Si on choisit mal, des instructions restent en attente trop longtemps parce que d'autres instructions plus jeunes leur passent devant. Pour éviter cela, les instructions les plus vielles, les plus anciennes, sont prioritaires. Pour cela, on peut utiliser une FIFO un peu spéciale pour la ''scheduler''. Si les ajouts d'instruction se font dans l'ordre, les instructions ne quittent pas forcément la ''scheduler'' dans l'ordre imposé par une FIFO : les instructions restent triées dans leur ordre d'ajout, même s'il y a des vides entre elles. Dans ces conditions, il est préférable que le compactage conserve l'ordre FIFO des instructions. Dans ces conditions, l'instruction la plus ancienne est celle qui est située à l'adresse la plus faible : le circuit de sélection peut donc être fabriqué avec des encodeurs, et est relativement simple. ==Les ''schedulers'' basées sur une matrice de dépendances== L'implémentation la plus simple étend le fonctionnement d'un pipeline dynamique usuel. Rappelez-vous le chapitre sur les pipelines dynamiques. Nous avions vu que de tels pipelines émettaient une instruction par cycle, quitte à émettre des bulles de pipeline en cas de dépendance bloquante. Et il est possible d'améliorer leur unité d'émission pour qu'elle soit compatible avec l'exécution dans le désordre. ===Rappels sur le registre de réservation/disponibilité=== L'émission d'une instruction est gouvernée par un ''registre de réservation'' qui indique quels registres sont réservés par une instruction, et ceux qui sont libres. Un registre réservé est un registre qui sera écrit par une instruction en cours d'exécution, mais qui n'a pas encore écrit son résultat. Les instructions candidates doivent avoir leurs opérandes dans des registres libres. Sinon, c'est signe que leurs opérandes sont réservés en écriture, donc pas encore écrites, donc pas disponibles. Si une instruction candidate veut lire ce registre, c'est signe qu'il y a une dépendance RAW : elle veut lire un registre réservé, qui est destiné à être écrit par une instruction en vol. Si elle veut écrire, c'est signe qu'elle veut écrire dans un registre où une autre instruction veut écrire : c'est une dépendance WAW. Dans les deux cas, l'instruction n'est pas émise. Le registre de réservation encode les registres réservés comme suit : chaque bit est associé à un registre. Le bit numéro 0 est associé au registre numéro 0, le bit numéro 1 au registre numéro 1, etc. Là, En clair, les numéros de registres réservés sont encodés en représentation non pas binaire, mais en représentation ''one-hot'' (vue au premier chapitre). {|class="wikitable" |+ Registre de réservation |- ! Registre 7 !! Registre 6 !! Registre 5 !! Registre 4 !! Registre 3 !! Registre 2 !! Registre 1 !! Registre 0 |- | 0 || 0 || 1 || 0 || 0 || 1 || 0 || 0 |} Avant d'émettre une instruction, l'unité d'émission extrait les registres opérande/destination et les convertis dans la même représentation que le registre de réservation, à savoir en représentation ''one-hot''. Le circuit de traduction binaire vers ''one-hot'' est, pour rappel, un simple décodeur. Puis, on fait un OU logique entre les sorties des décodeurs. Le résultat est un masque qui indique quels registres sont lus par l'instruction, encodé en représentation ''one-hot''. Appelons-le le '''masque d'opérandes'''. Le masque est alors comparé au registre de réservation pour vérifier si l'instruction peut être émise. [[File:Unité d'émission simple, dans l'ordre.png|centre|vignette|upright=2|Unité d'émission simple, dans l'ordre]] Si l'émission est autorisée, le registre de réservation est là aussi mis à jour. Le registre de réservation est aussi mis à jour dès qu'une instruction enregistre son résultat dans les registres, ou alors dès qu'il est disponible pour le contournement. Le bit associé au registre repasse alors à 0 (ou à 1). Sans contournement, la mise à jour se fait alors à la toute fin de l'instruction, quand elle se termine, lors de la dernière étape d'enregistrement, à la fin de son pipeline. Avec, elle se fait quand l'instruction quitte l'unité de calcul. ===L'extension à l'exécution dans le désordre : l'éveil par matrice de bits=== La différence entre un pipeline dynamique et l'exécution dans le désordre est que l'on passe d'une instruction à émettre à plusieurs. Plusieurs instructions sont mises en attente dans un ''scheduler'', et y attendent leur tour. L'idée est alors d'envoyer le registre de disponibilité à toutes les entrées, à toutes les instructions en attente. Ainsi, on sait quelles sont les instructions qui peuvent s'exécuter et celles qui ne le peuvent pas. L'implémentation est assez simple, elle ressemble beaucoup à l'implémentation d'un pipeline dynamique simple, si ce n'est que des circuits sont dupliqués. L'implémentation utilise des ''scheduler'' légèrement différentes de celles introduites plus haut. Elles n'utilisent notamment pas de bits de disponibilité, mais autre chose. Lorsqu'une instruction est ajoutée à la ''scheduler'', le masque de disponibilité des opérandes est stocké dans la ''scheduler''. A chaque cycle, le registre de disponibilité est envoyé à toutes les entrées, et est comparé avec tous les masques de disponibilité des opérandes. Si une comparaison renvoie un 1, alors l'instruction de l'entrée est une instruction candidate à l'émission. [[File:Unité d'émission dans le désordre basée sur un registre de disponibilité.png|centre|vignette|upright=2.5|Unité d'émission dans le désordre basée sur un registre de disponibilité]] L'ensemble est implémenté avec l'aide d'une '''matrice de bits''', où chaque ligne correspond à une entrée et chaque colonne à un registre. À chaque croisement entre une ligne et une colonne, on trouve un bit. Si le bit de la ligne n et de la colonne m est à 1, cela veut dire : l'instruction dans l'entrée n a besoin de lire le registre m. S’il est à 0, alors cela veut dire que l'instruction stockée dans la ligne n'a pas besoin de la donnée dans le registre m. [[File:Planificateur à matrice de bits.jpg|centre|vignette|upright=2|Planificateur à matrice de bits.]] Lorsqu'une instruction réserve une entrée, elle initialise la ligne en fonction des registres qu'elle souhaite lire. Pour vérifier si une instruction a ses opérandes prêts, le processeur compare le registre de disponibilité à la ligne associée à l'instruction/entrée. A chaque intersection ligne-colonne, se trouve un comparateur de 1 bit, qui détecte si le registre est demandé et disponible. Les résultats de cette porte sont ensuite envoyés à une porte ET, qui fait le gros du travail. [[File:Logique de détection de la disponibilité d'une instruction.jpg|centre|vignette|upright=2|Logique de détection de la disponibilité d'une instruction.]] ==Les ''scheduler'' basées sur une mémoire associative== Les processeurs modernes utilisent une mémoire associative pour la ''scheduler''. Les mémoires associatives ont été abordées il y a quelques chapitres, mais faisons quelques rappels. Les mémoires associatives servent à accélérer la recherche de données dans un ensemble. Or, un ''scheduler'' vérifie régulièrement si chaque entrée est prête. Il s'agit d'un processus de recherche d'une instruction qui respecte une condition bien précise dans la mémoire, ce qui fait que les mémoires associatives sont donc tout indiquées. Comme vous le savez, les signaux de commande d'une instruction sont propagés avec celle-ci dans le pipeline, le nom du registre de destination ne faisant pas exception. Le nom de registre est envoyé à la ''scheduler'' lors de l'écriture du résultat dans les registres. S'il y a correspondance, l'opérande est disponible et son bit de disponibilité est mis à 1. On peut adapter cette méthode pour tenir compte du contournement assez simplement. [[File:Détection des dépendances par propagation du registre de destination.png|centre|vignette|upright=2|Détection des dépendances par propagation du registre de destination.]] En conséquence, le circuit de détection des dépendances est constitué d'un grand nombre de comparateurs : un par champ « nom de registre » dans chaque entrée. La logique d'éveil/''wake up'' regroupe tous les comparateurs, la logique de sélection est un circuit situé en-dehors de la mémoire associative. Les entrées sont dans la mémoire associative elle-même. [[File:Gestion des bits de validité.png|centre|vignette|upright=2|Gestion des bits de validité.]] L'implémentation la plus simple est celle du schéma précédent, où on utilise une mémoire associative unique. Une version plus élaborée sépare la ''scheduler'' en deux parties : une mémoire qui mémorise les registres des opérandes, une autre mémoire pour le reste. La mémoire pour les registres opérandes est la mémoire associative proprement dite, c'est elle qui est associée aux comparateurs, à la logique de ''wake-up''/réveil, etc. Par contre, l'autre mémoire est une mémoire RAM simplifiée, qui mémorise les informations qui n'ont pas besoin des comparateurs. L'opcode de l'instruction est là-dedans, par exemple. La ''scheduler'' est donc une sorte de mémoire associative améliorée. Il se trouve que c'est aussi le cas du ROB. Et il est possible de fusionner le tampon de ré-ordonnancement avec la ''scheduler'' dans une structure unique. La différence avec un ''scheduler'' normal est que les entrées sont libérées non pas quand l'instruction est exécutée/émise, mais quand elle termine son exécution et quitte le ROB. La ''scheduler'' incorpore des bits dans chaque entrée, pour savoir si la µops associée a été émise et est en cours de traitement dans les ALUs. La méthode a notamment été utilisée sur les processeurs d'architecture K6 d'AMD. Le tout donnait une structure appelée le '''DRIS''' (''deferred scheduling register renaming instruction shelf''). Les processeurs PA 8000 de HP étaient aussi vraisemblabment dans ce cas, aussi. ===Les optimisations de la consommation d'énergie : la désactivation des portions inutilisées=== Le problème avec des ''scheduler'' de ce type est leur forte consommation énergétique, ainsi que le grand nombre de portes logiques utilisées, qui deviennent prohibitifs pour des ''scheduler'' un peu grosses. Pour résoudre ce problème, certains ont optimisé les comparateurs. D'autres ont tenté de profiter du fait que la majorité des bits dans les entrées sont composés de zéros. Bref, les optimisations purement matérielles sont légion. Une première solution est de désactiver les entrées qui sont inutilisées, vides, sans instruction. Pour cela, on fait précéder les comparateurs par un circuit qui les connecte ou déconnecte des lignes de bit. Le circuit est commandé par le bit ''empty'' qui indique si une entrée est vide ou non. L'avantage est que la consommation d'énergie de la ''scheduler'' devient alors proportionnelle au nombre d'entrées non-vides, et non au nombre d'entrées total. Du moins, en apparence, les entrées non-utilisées doivent quand même être alimentées pour fonctionner, mais l'activité de comparaison disparait dans les entrées vides. Il est possible d'étendre cette technique aux entrées dont les opérandes sont prêts. Les gains sont généralement assez bons, avec une réduction de consommation variant entre 30 et 50%, avec une implémentation très simple et très économe en circuits. Une autre solution, assez simple à mettre en place, consiste à désactiver une partie de la ''scheduler'' sin elle est inutilisée. Pour cela, il faut segmenter la ''scheduler'' avec la technique du ''wire partitionning''. Pour rappel, un ''scheduler'' est une mémoire associative. Et comme toute mémoire associative, elle contient des fils, les lignes de bit, qui relient les entrées/sorties à toutes les cellules mémoire. Plus une ligne de bit est longue, plus elle consomme d'énergie et plus le temps de lecture/écriture est long. L'idée est de segmenter les lignes de bits en plaçant des répéteurs qui recopient la tension d'un segment au suivant. Les répéteurs sont des tampons trois-états, ce qui permet de déconnecter les portions inutilisées de la ligne de bit. Ce faisant, la ''scheduler'' est découpée en segments, qui peuvent être désactivés si besoin. S'il y a peu d'instructions chargées dans la ''scheduler'', les portions inutilisées sont désactivées. La technique marche d'autan mieux si les instructions sont compactées au début de la ''scheduler''. [[File:Wire partitionning.png|centre|vignette|upright=2|Wire partitionning]] Tout le problème est de savoir quelles portions désactiver. La technique est assez simple si la ''scheduler'' est compactée, à savoir si toutes les instructions sont régulièrement regroupées au début de la mémoire CAM. Mais même avec cette optimisation, la décision de désactiver une portion de la ''scheduler'' n'est pas à prendre à la légère. Il ne faut pas désactiver une portion contenant des instructions pouvant être émise sous peu. La décision dépend de paramètres variés : proportion d'entrée vides, quantité d'entrées récemment activées/désactivées récemment, présences d'entrées avec un ''match'' d'opérandes récent, etc. Il est important de préciser que les techniques en question fonctionnent aussi sur les autres types de ''scheduler'', qui ne sont pas basées sur des mémoires associatives. Nous allons voir celles-ci dans la suite du chapitre, mais gardez à l'esprit que ces optimisations, à savoir désactiver les entrées vides/prêts et partitionner la ''scheduler'', sont des optimisations générales qui marchent avec presque tout. ===L'ajout d'une FIFO pour les instructions déjà prêtes à l'émission=== D'autres techniques permettent de réduire aussi bien le cout en circuits que la consommation d'énergie de la ''scheduler''. L'idée est d'utiliser une mémoire associative quand elle est réellement nécessaire, mais d'utiliser un ''scheduler'' "normale" dès que possible. La méthode la plus simple tient compte du fait que certaines µopsont déjà toutes leurs opérandes de disponibles à l'émission, mais doivent quand même être mises en attente, parce que l'ALU adéquate est occupée, parce que des dépendances WAW/WAR sont encore là, ou pour tout autre raison. Dans ce cas, elles sont mises en attente non pas dans la ''scheduler'', mais dans une mémoire FIFO toute simple. L'idée est qu'au lieu d'avoir une énorme mémoire associative pour la ''scheduler'', on déplace quelques entrées dans une petite FIFO annexe. Le résultat est un gain d'énergie et de circuits, au prix d'une perte de performance mineure. La perte de performance en question se manifeste si aucune instruction n'a ses opérandes de prêtes à l'émission : le programme n'utilise pas la FIFO et voit alors un ''scheduler'' plus petite. Une amélioration de cette technique tient compte du fait que certaines instructions sont dans un cas intermédiaire. Elles ont déjà un opérande de prête lors de l'émission, mais pas l'autre. Le nombre d'opérandes varie suivant l’instruction : certaines n'ont besoin que d'un seul opérande. De plus, il arrive qu'une opération tout juste décodée ait déjà un ou plusieurs de ses opérandes de prêts. Cette constatation permet d'éviter d'utiliser des comparateurs pour les opérandes déjà prêts. Par exemple, on peut parfaitement utiliser trois ''scheduler'' : * une pour les instructions dont tous les opérandes sont prêts, mais qui sont quand même mises en attente, sans comparateur ; * une pour les instructions dont un seul opérande manque, qui n'utilise qu'un comparateur par entrée ; * une pour les instructions dont deux opérandes manquent à l'appel, qui utilise deux comparateurs par entrée. C'est beaucoup plus économique que d'utiliser une seule grosse ''scheduler'' qui contiendrait autant d'entrées que les trois précédentes réunies, avec deux comparateurs par entrée. Certains sont même allés plus loin, et ont proposé de supprimer la ''scheduler'' avec deux opérandes par entrée. Les instructions dont deux opérandes sont inconnus au décodage sont stockées dans la ''scheduler'' pour instructions avec un comparateur par entrée. Un circuit de prédiction se charge alors de prédire l'opérande manquant, cette prédiction étant vérifiée plus loin dans le pipeline. Il serait cependant étonnant qu'une telle proposition ait donné lieu à la moindre implémentation réelle. ===Les optimisations de la consommation d'énergie avancées=== D'autres chercheurs ont conservé un ''scheduler'' unique, avec autant de comparateurs par entrée qu'il y a d'opérandes possibles par instruction. Simplement, le processus de détection des opérandes prêts est légèrement ralenti : on ne vérifie qu'un opérande par cycle. Pour vérifier les deux opérandes d'une entrée, on doit attendre deux cycles. Enfin, certains chercheurs ont proposé des ''scheduler'' segmentées. Les instructions circulent à chaque cycle d'un segment vers le suivant : en conséquence, certains segments conservent les instructions les plus anciennes, un autre les instructions les plus jeunes, etc. Seul le denier segment, celui qui contient les instructions les plus vielles, peut émettre une instruction : la détection des opérandes se fait seulement dans le dernier segment, qui contient les instructions les plus anciennes. On économise ainsi beaucoup de comparateurs. Certains chercheurs ont tenté de pipeliner l'étape de sélection des opérandes, ainsi que l'étage d'arbitrage. Mais en faisant cela, il faut plusieurs cycles pour détecter qu'une instruction a ses opérandes prêts, ce qui pose problème face à de nombreuses dépendances RAW. Pour éviter de trop perdre en performances, certains chercheurs ont décidé d'utiliser des techniques pour prédire quelles seront les instructions dont les opérandes seront bientôt prêts. Si détecter qu'une instruction est prête prend n cycles, le processeur devra tenter de prédire la future disponibilité des opérandes n cycles en avance pour obtenir des performances optimales. ===Remplacer la mémoire associative par une RAM=== Une autre optimisation possible est de remplacer la ''scheduler'' par une mémoire RAM, dont chaque mot mémoire correspondrait à une entrée. Une telle optimisation permet en théorie de se passer des comparateurs associés à chaque entrée, mais au prix de l'ajout de circuits annexes potentiellement couteux. La première de ces techniques, la '''recherche directe par étiquette''' (direct tag search) fut créée par Weiss et son collègue Smith. Ils cherchaient à améliorer l'algorithme de Tomasulo, un algorithme qu'on expliquera dans quelques chapitres. Rappelons que chaque instruction produit un résultat, qui devra être rapatrié dans une ou plusieurs entrées de la ''scheduler''. L'optimisation de la recherche directe par étiquette fonctionne dans le cas où le résultat de l'instruction n'est utilisé que par une seule entrée, et pas plusieurs. Le principe est simple : chaque champ « opérande » d'une entrée est adressable via le nom de registre de cet opérande. Pour faire le lien entre entrée et nom de registre, la recherche directe par étiquette ajoute une table de correspondances matérielle, une mémoire RAM qui mémorise les adresses des champs « opérande » des entrées. Les adresses envoyées dans cette mémoire sont les noms de registres des résultats. Lors de l'émission, la table de correspondances est mise à jour. Les numéros des champs « opérande » réservés lors de l'émission sont mémorisés dans les mots mémoire qui correspondent aux deux registres sources. Toutefois, une petite vérification est faite lors de l'émission : s'il y a déjà une correspondance dans la table pour un registre source, alors une autre instruction compte lire ce registre. Pour éviter d'écraser les données de l'instruction précédente dans la table de correspondances, l'émission de l'instruction est bloquée. [[File:Recherche directe par étiquette.png|centre|vignette|upright=2|Recherche directe par étiquette.]] ==Les ''schedulers'' avec préplanification== Avec la '''préplanification''' (''prescheduling''), le ''scheduler'' est composée de mémoires FIFO dans lesquelles les instructions sont triées dans l'ordre d'émission. Il n'y a pas de logique d’émission proprement dite, celle-ci se bornant à vérifier si l'instruction située au début de la FIFO peut s’exécuter. Par contre, le préplanificateur détecte les dépendances et en déduit où insérer les instructions dans le tampon d'émission, à l'endroit le plus adéquat. [[File:Préplanification.jpg|centre|vignette|upright=2|Préplanification.]] ===L'usage de FIFO multiples=== La technique de préplanification la plus simple utilise plusieurs FIFO. Quand une instruction a une dépendance avec une autre instruction, les deux sont placées dans la même FIFO. Pour cela, le préplanificateur détecte les chaines d'instructions dépendantes, et place les instructions dans la FIFO adéquate. A chaque cycle, l'unité d'émission lit une micro-opération dans chaque FIFO et vérifie si elle peut l'émettre. Si la micro-opération n'a pas ses opérandes disponibles, ou qu'une dépendance structurelle survient, alors la FIFO est bloquée. La micro-opération attend que la dépendance soit résolue, bloquant toutes les instructions précédentes. Mais les autres FIFO ne sont pas bloquées, laissant de la marge de manœuvre. [[File:Préplanification par FIFO multiples.png|centre|vignette|upright=1.5|Préplanification par FIFO multiples.]] ===La technique du tampon trié=== La technique du '''tampon trié''' trie les instructions selon le temps d'attente avant leur exécution. Les instructions qui sont censées s’exécuter bientôt sont insérées au tout début de la FIFO, tandis que les instructions qui s’exécuteront dans un long moment sont insérées vers la fin. Là encore, l'unité d'émission lit une micro-opération dans la FIFO, et détermine si elle peut être émise. Si une dépendance survient, l'émission est retardée, et la FIFO est bloquée. [[File:Préplanification par tampon trié.png|centre|vignette|upright=1.5|Préplanification par tampon trié.]] La technique a cependant quelques problèmes assez importants. Le premier problème est que la FIFO est bloquée lorsqu'une micro-opération ne peut être émise. Le second problème est que le temps avant exécution n'est pas toujours connu, notamment pour les instructions d'accès mémoire. Et cela se répercute sur les instructions dépendantes de celles-ci. Pour résoudre ce genre de problèmes, l'usage d'un pipeline à ''replay'' est possible, et est même l'une des meilleures solutions possible, malgré ses défauts. L'idée est que les lectures sont pré-planifiées en supposant qu'elles font un succès de cache L1. Si la prédiction est fausse, la lecture est ré-exécutée plusieurs cycles plus tard, en supposant qu'elle fait un succès dans le cache L2, et ainsi de suite. Elle est alors ré-insérée dans la FIFO, elle est pré-planifiée une seconde fois. Il en est de même si une micro-opération ne peut pas être émise : il suffit de la réinsérer dans la FIFO au bon endroit, en attendant que ses dépendances soient résolues. Ainsi, l'instruction fautive ne bloque pas la fenêtre d’instruction, et retente sa chance autant de fois qu'il le faut. [[File:Préplanification par fenêtre d’instruction scorebarodée.png|centre|vignette|upright=1.5|Préplanification par fenêtre d’instruction scorebarodée.]] Une autre solution utilise deux ''schedulers'' : une FIFO gérée par la préplanification, et une vraie ''scheduler'' pour les instructions dont le temps d'attente ne peut pas être déterminé. Il est possible de mettre cette dernière avant la préplanification, afin de gérer les temps d'attente des instructions d'accès mémoire. Quand le temps d'attente d'une lecture devient connu, ses instructions dépendantes sont gérées avec préplanification. [[File:Préplanification avec fenêtre d’instruction.png|centre|vignette|upright=2.5|Préplanification avec fenêtre d’instruction.]] ===Les ''scheduler'' avec allocation temporelle statique=== L''''allocation temporelle statique''' correspond à une technique utilisée sur les processeurs Cuzco de l'entreprise Condor. La technique en question a été présenté en 2025, mais des idées similaires ont été présentées dans la littérature académique. Elle ressemble beaucoup aux techniques de pré-planification, avec cependant quelques différences. L'idée est simple : le processeur dispose de plusieurs ''scheduler'', qui mettent en attente les micro-opérations. Lors de l'étape de renommage de registres, le processeur détermine dans combien de cycles d'horloge la micro-opération sera prête pour exécution. La micro-opération est alors mise en attente durant ce nombre de cycles, dans les ''scheduler'', puis est émise une fois ce nombre de cycles écoulés. Ce faisant, les ''scheduler'' n'ont pas besoin de détecter la disponibilité des opérandes à chaque cycle, pour chaque micro-opération en attente. Le ''timing'' de l'émission des micro-opérations est décidé à l'avance. L'implémentation exacte n'est pas connue, mais plusieurs solutions sont imaginables. Par exemple, la ''scheduler'' peut simplement être composée de plusieurs mémoires de petite taille, chacune contenant les micro-opérations destinées à être exécutées dans N cycles, N étant différent pour chaque mémoire. Une autre solution, plus réaliste, utilise un ''scheduler'' dans laquelle la micro-opération est couplée à des champs pour les opérandes, et un champ compteur. Le champ compteur est initialisé avec le nombre de cycles à attendre, et est décrémenté à chaque cycle d'horloge. Quand il atteint zéro, la micro-opération est émise. Vous remarquerez que la méthode ne marche que si toutes les micro-opérations prennent un nombre fixe de cycles d'horloge. Et autant c'est le cas pour les micro-opérations arithmétiques ou logiques, autant les accès mémoire ne rentrent pas dans ce cadre. En théorie, on ne sait pas combien de temps prendra un accès mémoire. Et cette incertitude se répercute sur les instructions dépendantes d'un accès mémoire. Pour éviter cela, le processeur réutilise un pipeline à ''replay'' tel que vu dans le chapitre précédent. L'unité de renommage de registre suppose que tout accès mémoire fait un succès de cache L1, et décide des ''timings'' d'émission sous cette hypothèse. Si une lecture subit un défaut de cache, elle est ré-exécutée, de même que toutes les instructions dépendantes. Pour cela, le registre de destination de la lecture est marqué comme invalide, grâce à un bit spécifique attaché au registre. Toute instruction qui lit un opérande invalide est elle aussi ré-executée de zéro. Pour simplifier, l'unité d'émission ressemble à une unité d'émission dans l'ordre, avec un registre de disponibilité, qu'on aurait amélioré pour aller au-delà de la simple détection des dépendances d'instruction. Pour déterminer les ''timings'' d'émission, à savoir quand émettre une micro-opération, le processeur utilise une unité d'émission à deux étages. Le premier étage est appelé le ''register scoreboard'', le second étage est appelé la ''Time Ressource Matrix''. Les deux étages communiquent entre eux, comme on va le voir, et leurs noms donnent une idée de ce qu'ils font. Le premier étage gère les dépendances de registres, le second gère les dépendances structurelles. Le premier étage est un registre de disponibilité amélioré, qui gère les dépendances de registre. Cet étage sait quand tel registre sera écrit, et donc que l'opérande écrit dedans sera disponible à partir de tel cycle d'horloge. Il le sait car l'étage suivant l'aura prévenu, mais laissons cela de côté pour le moment. Quand une micro-opération rentre dans cet étage, il vérifie les dépendances avec les registres et les micro-opérations antérieures. Vu qu'il sait quand les registres seront disponibles, il peut déterminer quand l'instruction pourra s'exécuter. Par exemple, si une micro-opération lit les deux registres R7 et R15, qui sont disponibles respectivement dans 5 et 7 cycles, le premier étage sait que la micro-opération devra attendre 7 cycles. Mais tout cela ne suffit pas à déterminer quand émettre une micro-opération. En effet, il fait aussi gérer les dépendances structurelles, ce qui est le boulot du second étage. Le second étage utilise pour cela une ''Time Ressource Matrix'', qui mémorise l'occupation de diverses "ressources", pour les 256 cycles d'horloge à venir. Les ressources en question sont les ports de lecture/écriture du banc de registre, les ALUs utilisées, si la micro-opération utilise l'unité mémoire, etc. Le second étage prend en entrée une micro-opération, détermine quelles "ressources" elle utilise, puis regarde leur disponibilité. Elle détecte alors les dépendances structurelles et détermine alors quand peut s'exécuter la micro-opération. Elle peut retarder l'émission de quelques cycles, si une dépendance structurelle est détectée. Une fois sortie du second étage, on sait quand la micro-opération va être émise, à quel cycle précisément. Et vu que la durée de l'instruction est fixe, on sait quand cette micro-opération va se terminer, quand son résultat sera disponible. Cela permet de mettre à jour la ''Time Ressource Matrix'', pour préciser que le port d'écriture sera occupé à tel moment. De plus, cette information est transmise au premier étage, qui sait alors quand est enregistré le résultat dans le registre de destination. C'est comme cela que le premier étage sait quand un registre est disponible : le second étage le prévient, quand il émet une instruction ! La ''Time Ressource Matrix''mémorise l'occupation des "ressources" pour les 256 cycles d'horloge à venir. Cependant, elle ne vérifie pas les dépendances pour les 256 cycles suivants. Quand elle reçoit une micro-opération, elle teste les dépendances structurelles pour seulement les 8 prochains cycles maximum. Si la micro-opération ne peut pas être émise pendant ces 8 cycles, le pipeline est bloqué, un ''pipeline stall'' est émis. Pour être plus précis, vu que le processeur peut décoder 8 micro-opérations en même temps, cela permet de ne consulter que 64 cycles d'horloge sur les 256. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les premiers processeurs Intel | prevText=Les premiers processeurs Intel | next=Le renommage de registres | nextText=Le renommage de registres }} </noinclude> 1pzsyw5hp8u5mlblbeeyj8zexv79oew 773626 773625 2026-09-29T21:03:45Z Mewtow 31375 /* La logique de sélection : âge ou position ? */ 773626 wikitext text/x-wiki Dans les chapitres précédents, nous avons parlé des techniques dites d''''émission dans l'ordre'''. L'idée est d’exécuter une nouvelle micro-opération à chaque cycle, dans des unités de calcul séparées. Les instructions sont émises consécutivement, mais les instructions s’exécutent en parallèle dans des unités de calcul séparées. Par contre, quand l'unité d'émission ne peut pas émettre une instruction, elle bloque tout le pipeline. Les instructions qui suivent sont elles aussi bloquées, elles doivent attendre leur tour, même si elles sont en capacité de s'exécuter. Les techniques d'exécution dans le désordre que nous allons voir dans ce chapitre corrigent ce point précis. Elles sont dites à '''émission dans le désordre'''. Elles se distinguent des précédentes sur un point précis : quand l'unité d'émission bloque l'émission d'une instruction, les instructions suivantes peuvent poursuivre. L'émission des instructions peut donc se faire dans le désordre, dans le sens où une instruction peut être émise alors qu'une instruction précédente ne l'est pas encore. Mais avant de poursuivre, quelques point niveaux terminologie : * L'émission dans le désordre est un terme parlant et assez précis. Malheureusement, la terminologie la plus utilisée par d''''exécution dans le désordre'''. Et nous utiliserons ce terme dans la suite du cours, histoire de ne pas trop dévier de la nomenclature habituelle. * Nous utiliserons parfois l'abréviation OOO pour parler d'exécution dans le désordre. L'abréviation est celle de ''Out Of Order Excution''. * Nous utiliserons aussi l'abréviation ''µop'' pour parler de micro-opération, ''µops'' au pluriel pour parler de plusieurs micro-opérations, ou des micro-opérations en général. L'exécution dans le désordre ne gère en effet que des µops, elle se situe après l'étape de décodage. Pour décrire comment est implémentée l'émission dans le désordre, il faut commencer par parler des processeurs sans. Les processeurs sans exécution dans le désordre ont une unité d'émission qui bloque tout le pipeline dès qu'une µop ne peut pas être émise. Pour limiter l'impact de ce blocage, quelques rares processeurs incorporent une '''file de micro-opération''', une mémoire FIFO qui met en attente les µops. Vu que c'est une mémoire FIFO, les µops sont émises dans l'ordre, à savoir l'ordre d'ajout, dans l'ordre de décodage. Le schéma ci-dessous illustre une telle file d'attente couplée à un ''scoreboard''. L'exécution dans le désordre améliore la file de µops sur un point : ce n'est plus une mémoire FIFO. Les µops sont insérées dans l'ordre, mais peuvent sortir dans le désordre (être émises dans le désordre). La file de µops devient alors un '''''scheduler''''', terme anglais que je ne compte pas traduire. Un terme équivalent est '''''scheduler''''', terme traduit directement de l'anglais ''instruction Window''. Terme assez trompeur, car elles mettent en attente des µops, pas des instructions. [[File:Différence file µops et fenêtres instruction.png|centre|vignette|upright=2|Différence file µops et ''schedulers'' ]] Le ''scheduler'' émet une µop dès que ses opérandes sont disponibles. Par disponible, on veut dire présent soit dans le réseau de contournement, soit dans les registres. Le ''scheduler'' détecte automatiquement quand les opérandes d'une µop sont disponibles, grâce à une unité d'émission intégrée. L'unité d'émission et le ''scheduler'' sont fusionnés ensemble, dans un seul circuit, mais nous allons dire qu'ils sont conceptuellement séparés pour le moment. A chaque cycle, l'unité d'émission consulte les µops en attente pour détecter lesquelles peuvent s'exécuter. Le ''scheduler'' est spécialement être conçue pour, c'est une sorte de mémoire associative très complexe, comme on le verra dans ce qui suit. [[File:OOO Issue.png|centre|vignette|upright=2.5|Exécution dans le désordre avec un ''scheduler'']] Une fois qu'une µop sort du décodeur d'instructions, elle est ajoutée en parallèle dans la ''scheduler'' et le ROB. La raison est que les µops quittent la ''scheduler'' dans le désordre, et qu'elles doivent être remises en ordre par la suite. Le ROB s'occupe de cette remise en ordre, mais il a besoin de savoir dans quel ordre les µops sont censées être, et cet ordre est celui du décodage. Aussi, pour remplir le ROB, la seule opportunité est en sortie de l'unité de décodage. Dans le cas où une instruction est décodée en plusieurs micro-opérations, elles sont toutes insérées en même temps dans la ''scheduler'' et le ROB, en tenant compte de leur ordre. L'implémentation la plus simple de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Les µops décodées sont accumulées dans le ''scheduler'', où elles attendent leur tour. La ''scheduler'' sert donc de file d'attente. Avant de poursuivre, précisons que les micro-opérations mémoire sont à part des autres, pour diverses raisons. Une de ces raisons est que les dépendances de données sont classées en deux types : les dépendances de registre et les dépendances d'adresse. Et les deux sont fondamentalement différentes. Autant on peut détecter les dépendances de registre lors de l'émission, autant c'est plus compliqué avec les dépendances d'adresse. De plus, rappelons que si les lectures peuvent s'exécuter dans le désordre, les écritures doivent s'exécuter dans l'ordre, ou du moins en donner l'illusion. Pour cela, le processeur remet les écritures dans l'ordre avec une sorte de mini-ROB intégré à l'unité mémoire, appelée la file d'écriture. Elle complémente le ROB, qui lui ne gère que les écritures dans les registres, mais les deux collaborent. La file d'écriture envoie une écriture à la mémoire RAM quand le ROB lui dit que c'est bon, les instructions précédentes sont terminées ''dans l'ordre du programme''. Les processeurs modernes ajoutent des techniques d'exécution dans le désordre des accès mémoire, mais nous les verrons dans un chapitre dédié. Elles permettent d'utiliser un ''scheduler'' unique, qui mémorise aussi les µops mémoire. Si elles sont mises en place, l'unité mémoire n'a pas besoin de file de µops séparée. L'idée est que les dépendances de registre sont traitées par la ''scheduler'', mais que l'unité mémoire gére les dépendances d'adresse. Les dépendances d'adresse sont gérées par des techniques de ''désambiguation mémoire'', qui auront droit à un chapitre dédié. [[File:Processeur avec exécution dans le désodre des accès mémoire.png|centre|vignette|upright=2|Processeur avec exécution dans le désodre des accès mémoire]] Les processeurs assez anciens n'autorisaient pas d'exécution dans le désordre des accès mémoire. Concrétement, les accs mémoire devaient se faire dans l'ordre, mais les autres µops pouvaient être exécutées dans le désordre. Il s'agit donc d'un ordre entre µops mémoire, pas entre µops mémoire et autres µops. Les µops entières et flottantes pouvaient être exécutées avant une µops mémoire qui est avant elle dans l'ordre du programme, ce n'est pas un problème. Pour garantir l'ordre des µops mémoire, l'unité mémoire est précédée par une file de micro-opérations séparée, pour forcer l'exécution dans l'ordre des accès mémoire. De plus, les µops mémoire ne peuvent pas utiliser la ''scheduler''. Dit autrement, la ''scheduler'' ne mémorise pas de µops mémoire. Après le décodage, les µops sont réparties soit dans la file de µops mémoire, soit dans la ''scheduler''. Le décodeur classe les µops suivant que ce sont des µops mémoire ou non, et les envoient à la bonne destination. Dans ce chapitre, on supposera que c'est cette solution qui est utilisée. [[File:Processeur avec émission dans l'ordre des accès mémoire.png|centre|vignette|upright=2|Processeur avec émission dans l'ordre des accès mémoire]] ==L'implémentation d'un ''scheduler'' : généralités== Un ''scheduler'' est une mémoire qui mémorise des micro-opérations. Elle est cependant plus complexe qu'une mémoire RAM ou qu'une FIFO et ressemble un petit peu à une mémoire cache. Elle dispose d'un port d'écriture et d'un port de lecture, au minimum. Le port d'écriture permet à l'unité de décodage d'insérer une micro-opération dedans, d'ajouter la micro-opération qui vient d'être décodée. Si une instruction machine est décodée en plusieurs micro-opération, deux possibilités. La première est de les insérer un par un, ce qui fait qu'on peut se contenter d'un seul port d'écriture. L'autre possibilité est de les ajouter en même temps, ce qui demande plusieurs ports d'écriture. Le port de lecture sert à émettre une instruction. On part du principe que la ''scheduler'' ne peut émettre qu'une seule instruction à la fois, car les processeurs que nous avons vu précédemment sont de ce type. Mais nous verrons dans quelques chapitres qu'il existe des processeurs dits superscalaires, qui sont capables d'émettre plusieurs instructions par cycle. Dans ce cas, la ''scheduler'' a un seul port de lecture. Un processeur superscalaire, quant à lui, doit avoir un port de lecture par unité de calcul, ce qui fait beaucoup plus. Les ''schedulers'' sont composées d''''entrées''', des mots mémoire qui stockent une instruction. Une instruction réserve une entrée après son décodage et la libère dès qu'elle est envoyée aux unités de calcul. Une entrée contient l'opcode (les signaux de commande à envoyer à l'ALU), le registre de destination du résultat, les registres de chaque opérande, et éventuellement des signaux de commande en plus. De plus, chaque opérande est couplée à un bit de disponibilité, qui indique si elle est disponible. Quand un opérande est écrit dans les registres, le bit de présence correspondant est mis à jour. Enfin, chaque entrée possède un bit ''empty'' qui indique si elle est vide, cette information étant utile pour réserver des entrées. [[File:Entrée d'une station de réservation - sans les tags.png|centre|vignette|upright=3|Entrée d'un ''scheduler'']] ===Les stations de réservation=== Les '''stations de réservation''' sont des ''scheduler'' particulières, qui sont capables de mémoriser les opérandes des instructions. Les entrées des stations de réservation sont identiques à celle des autres ''scheduler'', si ce n'est que les opérandes de l'instruction sont enregistrés directement dans des champs séparés. Il y a deux champs, un par opérande, pour stocker l'opérande elle-même, lue depuis les registres ou obtenue via le réseau de contournement. Notons que les champs pour les opérandes viennent en plus des champs pour les noms de registres, encore que les deux peuvent être fusionnés si on veut optimiser le tout. [[File:Entrée d'une station de réservation.png|centre|vignette|upright=3|Entrée d'une station de réservation.]] Précisons que la terminologie n'est pas très fiable. Les termes "''scheduler''" et "station de réservation" ne regroupent pas du tout la même chose d'un papier de recherche à l'autre, d'un bouquin à l'autre, d'un chercheur à l'autre, d'un ingénieur à l'autre, d'un professeur à l'autre. Le terme initial vient pourtant de l'article original sur l'algorithme de Tomasulo, où il désignait un ''scheduler'' associée à une unité de calcul précise. Mais le terme a ensuite été réutilisé, ce qui fait que certains processeurs avec plusieurs unités de calcul sont décrits comme ayant une unique station de réservation. En bref : c'est le bazar ! Mais nous en reparlerons dans le chapitre sur le renommage de registres, car c'est la place idéale pour les aborder. Toujours est-il que j'ai fait le choix de confondre les concepts de ''scheduler'' et de station de réservation avec les concepts de '''lecture avant émission''' et de '''lecture après émission'''. La différence entre les deux est que les registres sont lus après émission avec un ''scheduler'', avant avec des stations de réservation. Dans le cas "avant émission", les opérandes sont mémorisés dans la station de réservation. Et cette différence a une influence sur le pipeline du processeur, le banc de registres et tout ce qui s'en suit. Un désavantage de la lecture avant émission est qu'il faut stocker les opérandes après lecture, ici dans les stations de réservation. Mais un avantage est que le banc de registre a besoin de moins de ports de lecture, car une bonne partie des opérandes sont fournies par le système de contournement. Nous verrons cela dans le détail dans le chapitre sur les processeurs superscalaires. [[File:Processeur avec plusieurs ''scheduler''.png|centre|vignette|upright=2.5|Lecture après émission.]] [[File:Read Before Issue.png|centre|vignette|upright=2.5|Lecture avant émission.]] ===La logique d'éveil et de sélection=== Dans le cas qui va suivre, on suppose que le processeur ne peut émettre qu'une instruction à la fois. Chaque cycle, une instruction est sélectionnée et est envoyée dans le chemin de données, soit à une ALU, soit à une unité d'accès mémoire. La sélection d'une instruction est effectuée par l'unité d'émission, qui est aussi appelée le '''''scheduler'''''. Elle gère la disponibilité des opérandes et la disponibilité des unités de calcul adéquate. Le choix de l'instruction émise doit être le plus pertinent possible, pour des raisons de performances. Pour le premier point, l'unité d'émission détermine quelles instructions sont candidates pour l'émission. Les ''instructions candidates'' sont celles dont tous les opérandes sont prêts. Le processeur contient un circuit qui détecte les instructions candidates : la '''logique d’éveil''' (''wake-up logic''). Une fois que la logique d'éveil a fait son travail, une instruction est choisie pour s’exécuter en fonction de la disponibilité des unités de calcul adéquates. Ce rôle est dévolu à un circuit qu'on appelle la '''logique de sélection''', ou ''select logic''. [[File:Fonctionnement complet de la logique d’émission.jpg|centre|vignette|upright=1.5|Fonctionnement complet de la logique d’émission.]] La logique de sélection doit gérer le fait que les unités de calcul du processeur ne sont pas toutes identiques. Déjà, un processeur a généralement des unités séparées pour les instructions entières et flottantes, des unités spécialisées dans les accès mémoire, parfois des unités spécialisées pour les branchements. Une instruction doit être attribuée à la bonne unité de calcul, on ne doit pas envoyer une instruction entière dans une unité de calcul flottante. De plus, parmi les unités de calcul entières, toutes ne sont pas identiques. Par exemple, il est fréquent d'avoir plusieurs unités de calcul spécialisées dans les opérations simples (additions, soustractions, opérations logiques) avec une unité pour les multiplications/divisions séparées, parfois une unité spécialisée pour les décalages/rotations, etc. Là encore, allouer la bonne instruction à la bonne ALU est complexe. Plus les unités de calcul sont hétérogènes, plus la logique de sélection est compliquée. Les logiques d'éveil comme de sélection sont assez complexes. Comme on le verra plus bas, la logique de sélection la plus simple, qui gère une seule unité de calcul, est basée sur un encodeur à priorité couplé à d'autres circuits. Et pour gérer plusieurs ALUs, il faut mettre des encodeurs en cascade. Le résultat est que même en prenant une logique de sélection simple, elle sera assez lente et gourmande en circuits. Aussi, la logique de sélection met souvent un cycle d'horloge entier pour faire son travail, elle a son propre étage de pipeline attribué. La logique d'éveil est dans le même cas, ce qui fait qu'émettre une micro-opération demande deux cycles d'horloge. Le défaut est que cela rajoute des cycles d'horloges entre la ''scheduler'' et l'ALU, ce qui complique la gestion du pipeline. Ces cycles de retard sont à prendre en compte au moment d'émettre les instructions, les ''scheduler'' doit en tenir compte pour des performances optimales. Sans tenir compte de ces cycles de retard, les instructions arrivent en retard de quelques cycles à l'ALU, cycles de retard durant lesquels l'ALU n'a pas fait de calcul et a été sous-utilisée, sans compter que le système de contournement n'est pas utilisé au mieux. Et le problème est encore plus important sur les processeurs avec des stations de réservation, qui utilisent la "lecture après émission" : cela rajoute un cycle d'horloge en plus, un temps de retard en plus. ===La logique d'éveil : l'émission anticipée=== La logique d'éveil doit tenir compte du fait qu'il y a plusieurs étages entre l'émission et l'exécution sur une unité de calcul. Par exemple, un processeur a souvent entre un et à cinq étages entre la file d'attente et les unités de calcul. Il faut lire les registres, gérer le contournement, et cela peut prendre quelques cycles d'horloge. Sur le Pentium 4, on trouve 6 étages entre le ''scheduler'' et l'entrée de l'ALU. Si les micro-opérations sont émises quand les opérandes sont disponibles, il y aura un délai de quelques cycles avant qu'elles atteignent l'ALU. Alors qu'idéalement, on souhaiterait que la micro-opération atteigne l'ALU dès que ses opérandes sont disponibles, pour profiter des techniques de contournement. Pour cela, la logique d'éveil émet les instructions quelques cycles en avance pour qu'elles arrivent au bon moment. Il s'agit d'une technique d''''émission anticipée''', dont nous avions parlé dans le chapitre sur le contournement. : Il faut noter que le problème se pose plus avec des ''scheduler'' qu'avec des stations de réservation. Les premières ont un étage en plus entre émission et ALU, vu qu'il faut lire des registres après l'émission. L'émission anticipée demande d'émettre un signal d'éveil en avance de quelques cycles, pile au bon moment. Par exemples, si on a deux étages entre l'ALU et l'unité d'émission, le signal de réveil sera généré deux cycles avant que le résultat soit effectivement calculé. L'implémentation varie, mais deux solutions sont possibles. La première est de générer le signal d'éveil dans l'ALU, ce qui n'a de sens que pour les opérations comme les multiplications ou les divisions, qui prennent plusieurs cycles. Une autre technique génère le signal de réveil dans une structure centralisée, spécialisée dans la génération des signaux d'éveil. L'unité de composée d'un registre à décalage par registre. Imaginons qu'une instruction est émise, que cette instruction mette N cycles à s'exécuter, et qu'elle écrive dans un registre de destination. L'unité sélectionne alors le registre à décalage associé au registre de destination, et met le bit numéro N à 1. Le registre décalé d'un cran à chaque cycle. Quand le bit sortant est un 1, alors le signal de validité pour l'opérande est généré. L'émission anticipée marche bien si l'instruction a une durée fixe, connue à l'avance. Et autant c'est le cas pour les instructions arithmétiques et logiques, autant ce n'est pas le cas pour les accès mémoire. Les accès mémoire ont une latence variable : quelques cycles pour un succès de cache, plusieurs dizaines de cycles pour un défaut de cache L1, pas loin de la centaine pour un défaut de cache L2, etc. Et cela pose des problèmes pour l'émission anticipée. L'émission en avance pour les accès mémoire est purement spéculative : le processeur émet des instructions en supposant que la lecture entrainera un succès de cache, quitte à annuler l'instruction en cas de défaut de cache. Mais faire ainsi demande non seulement d'annuler les instructions émises en avance, mais aussi de ne pas retirer les instructions émises en avance de la ''scheduler''. Elles sont émises, mais une copie de sauvegarde est conservée dans la ''scheduler''. Si le processeur détecte un défaut de cache, il peut alors ré-exécuter l'instruction. S'il détecte un succès de cache, les instructions lecture-dépendante sont retirées de la ''scheduler'', la copie de sauvegarde est devenue inutile et est donc jetée. ===La logique de sélection : âge ou position ?=== La logique de sélection est primordiale pour de bonnes performances. Il existe deux méthodes principales pour sélectionner l'instruction à exécuter. La première est la plus simple : elle se base sur lé numéro de l'entrée. En effet, un ''scheduler'' est avant tout une sorte de mémoire, un mix entre mémoire associative, mémoire RAM, et FIFO. Et chaque entrée a un numéro, une adresse mémoire. Nous parlerons de numéro dans ce qui suit, car ce sera plus simple, le terme d'adresse mémoire étant peut-être un peu exagéré dans le contexte des ''scheduler''. Toujours est-il que la ''scheduler'' est adressable dans le sens où on peut lui envoyer le numéro de l'entrée voulue, et le ''scheduler'' renvoie le contenu de l'entrée sur son port de lecture. Et c'est ce que fait la logique de sélection : elle génère le numéro de l'entrée à lire. Le numéro est alors envoyé sur l'entrée d'adresse du ''scheduler'', et elle fournit la micro-opération associée sur son port de lecture, son '''port d'émission'''. La première méthode de sélection, donc. Elle est basée sur le numéro de l'entrée. Si plusieurs entrées sont éveillées, la logique de sélection prend celle avec le plus petit numéro. Elle porte le nom de '''sélection par position''', sous-entendu position dans la ''scheduler''. Vous l'avez peut-être deviné, mais la logique de sélection est alors un encodeur à priorité. Le circuit de sélection ne se résume donc pas seulement à un encodeur à priorité, mais c'est le circuit central. L'avantage d'une telle méthode de sélection est qu'elle est simple à implémenter : un encodeur à priorité est un circuit connu, facile à implémenter. Mais on remarque un défaut : un encodeur est un circuit assez rapide, mais qui utilise beaucoup de transistors, beaucoup de portes logiques, surtout si on veut qu'il soit rapide. Ce qui explique que la logique de sélection ait son propre étage de pipeline rien que pour elle. La seconde méthode s'appelle la '''sélection par âge''', au nom assez transparent. L'idée est de privilégier l'émission de l'instruction la plus ancienne. Elle demande que la ''scheduler'' trie les micro-opérations par ordre d'insertion dans la ''scheduler'', ce qui en fait une pseudo-FIFO. Le tri est partiel, car les instructions peuvent sortir du ''scheduler'' à tout moment. Compacter le ''scheduler'', à savoir regrouper toutes les entrées valides est une idée, mais elle est compliquée à implémenter. Aussi, elles préfèrent encoder des informations sur l'ordre d'émission dans chaque entrée. L'encodeur à priorité doit alors travailler non pas sur des nombres entiers liés à l'ordre d'insertion dans la pseudo-FIFO. Elle est encore plus gourmande en circuits que la méthode précédente. Les processeurs haute performance utilisent souvent des méthodes hybrides. Par exemple, les processeurs AMD de microarchitecture Bulldozer utilisaient une méthode intermédiaire. Ils utilisaient un ''scheduler'' couplée à un encodeur à priorité pour la sélection par position, mais complémentaient le tout avec une unité qui mémorisait l'instruction la plus ancienne dans la fenêtre d’instruction. Le mécanisme de sélection par âge était utilisé en priorité. Mais si l'instruction la plus ancienne n'était pas prête, le processeur basculait sur le mécanisme de sélection par position. ===La compaction des ''scheduler''=== À chaque cycle, les instructions décodées sont ajoutées dans la ''scheduler'', dans des entrées vides. Vu que les instructions quittent celle-ci dans le désordre, ces vides sont dispersés dans la ''scheduler'', ce qui pose problème pour déterminer où placer les nouvelles instructions. La solution la plus triviale consiste à conserver une liste des vides, mise à jour à chaque insertion ou émission d'instruction. Une autre solution consiste à éliminer les vides en compactant la ''scheduler'' à chaque cycle d'horloge. Des circuits se chargent de détecter les vides et de regrouper les instructions en un unique bloc. Il faut signaler que certains processeurs arrivent à se passer de cette étape de compactage, mais au prix de ''scheduler'' nettement plus complexes. Autre problème : quand il faut choisir quelle instruction émettre, il y a toujours plusieurs candidats. Si on choisit mal, des instructions restent en attente trop longtemps parce que d'autres instructions plus jeunes leur passent devant. Pour éviter cela, les instructions les plus vielles, les plus anciennes, sont prioritaires. Pour cela, on peut utiliser une FIFO un peu spéciale pour la ''scheduler''. Si les ajouts d'instruction se font dans l'ordre, les instructions ne quittent pas forcément la ''scheduler'' dans l'ordre imposé par une FIFO : les instructions restent triées dans leur ordre d'ajout, même s'il y a des vides entre elles. Dans ces conditions, il est préférable que le compactage conserve l'ordre FIFO des instructions. Dans ces conditions, l'instruction la plus ancienne est celle qui est située à l'adresse la plus faible : le circuit de sélection peut donc être fabriqué avec des encodeurs, et est relativement simple. ==Les ''schedulers'' basées sur une matrice de dépendances== L'implémentation la plus simple étend le fonctionnement d'un pipeline dynamique usuel. Rappelez-vous le chapitre sur les pipelines dynamiques. Nous avions vu que de tels pipelines émettaient une instruction par cycle, quitte à émettre des bulles de pipeline en cas de dépendance bloquante. Et il est possible d'améliorer leur unité d'émission pour qu'elle soit compatible avec l'exécution dans le désordre. ===Rappels sur le registre de réservation/disponibilité=== L'émission d'une instruction est gouvernée par un ''registre de réservation'' qui indique quels registres sont réservés par une instruction, et ceux qui sont libres. Un registre réservé est un registre qui sera écrit par une instruction en cours d'exécution, mais qui n'a pas encore écrit son résultat. Les instructions candidates doivent avoir leurs opérandes dans des registres libres. Sinon, c'est signe que leurs opérandes sont réservés en écriture, donc pas encore écrites, donc pas disponibles. Si une instruction candidate veut lire ce registre, c'est signe qu'il y a une dépendance RAW : elle veut lire un registre réservé, qui est destiné à être écrit par une instruction en vol. Si elle veut écrire, c'est signe qu'elle veut écrire dans un registre où une autre instruction veut écrire : c'est une dépendance WAW. Dans les deux cas, l'instruction n'est pas émise. Le registre de réservation encode les registres réservés comme suit : chaque bit est associé à un registre. Le bit numéro 0 est associé au registre numéro 0, le bit numéro 1 au registre numéro 1, etc. Là, En clair, les numéros de registres réservés sont encodés en représentation non pas binaire, mais en représentation ''one-hot'' (vue au premier chapitre). {|class="wikitable" |+ Registre de réservation |- ! Registre 7 !! Registre 6 !! Registre 5 !! Registre 4 !! Registre 3 !! Registre 2 !! Registre 1 !! Registre 0 |- | 0 || 0 || 1 || 0 || 0 || 1 || 0 || 0 |} Avant d'émettre une instruction, l'unité d'émission extrait les registres opérande/destination et les convertis dans la même représentation que le registre de réservation, à savoir en représentation ''one-hot''. Le circuit de traduction binaire vers ''one-hot'' est, pour rappel, un simple décodeur. Puis, on fait un OU logique entre les sorties des décodeurs. Le résultat est un masque qui indique quels registres sont lus par l'instruction, encodé en représentation ''one-hot''. Appelons-le le '''masque d'opérandes'''. Le masque est alors comparé au registre de réservation pour vérifier si l'instruction peut être émise. [[File:Unité d'émission simple, dans l'ordre.png|centre|vignette|upright=2|Unité d'émission simple, dans l'ordre]] Si l'émission est autorisée, le registre de réservation est là aussi mis à jour. Le registre de réservation est aussi mis à jour dès qu'une instruction enregistre son résultat dans les registres, ou alors dès qu'il est disponible pour le contournement. Le bit associé au registre repasse alors à 0 (ou à 1). Sans contournement, la mise à jour se fait alors à la toute fin de l'instruction, quand elle se termine, lors de la dernière étape d'enregistrement, à la fin de son pipeline. Avec, elle se fait quand l'instruction quitte l'unité de calcul. ===L'extension à l'exécution dans le désordre : l'éveil par matrice de bits=== La différence entre un pipeline dynamique et l'exécution dans le désordre est que l'on passe d'une instruction à émettre à plusieurs. Plusieurs instructions sont mises en attente dans un ''scheduler'', et y attendent leur tour. L'idée est alors d'envoyer le registre de disponibilité à toutes les entrées, à toutes les instructions en attente. Ainsi, on sait quelles sont les instructions qui peuvent s'exécuter et celles qui ne le peuvent pas. L'implémentation est assez simple, elle ressemble beaucoup à l'implémentation d'un pipeline dynamique simple, si ce n'est que des circuits sont dupliqués. L'implémentation utilise des ''scheduler'' légèrement différentes de celles introduites plus haut. Elles n'utilisent notamment pas de bits de disponibilité, mais autre chose. Lorsqu'une instruction est ajoutée à la ''scheduler'', le masque de disponibilité des opérandes est stocké dans la ''scheduler''. A chaque cycle, le registre de disponibilité est envoyé à toutes les entrées, et est comparé avec tous les masques de disponibilité des opérandes. Si une comparaison renvoie un 1, alors l'instruction de l'entrée est une instruction candidate à l'émission. [[File:Unité d'émission dans le désordre basée sur un registre de disponibilité.png|centre|vignette|upright=2.5|Unité d'émission dans le désordre basée sur un registre de disponibilité]] L'ensemble est implémenté avec l'aide d'une '''matrice de bits''', où chaque ligne correspond à une entrée et chaque colonne à un registre. À chaque croisement entre une ligne et une colonne, on trouve un bit. Si le bit de la ligne n et de la colonne m est à 1, cela veut dire : l'instruction dans l'entrée n a besoin de lire le registre m. S’il est à 0, alors cela veut dire que l'instruction stockée dans la ligne n'a pas besoin de la donnée dans le registre m. [[File:Planificateur à matrice de bits.jpg|centre|vignette|upright=2|Planificateur à matrice de bits.]] Lorsqu'une instruction réserve une entrée, elle initialise la ligne en fonction des registres qu'elle souhaite lire. Pour vérifier si une instruction a ses opérandes prêts, le processeur compare le registre de disponibilité à la ligne associée à l'instruction/entrée. A chaque intersection ligne-colonne, se trouve un comparateur de 1 bit, qui détecte si le registre est demandé et disponible. Les résultats de cette porte sont ensuite envoyés à une porte ET, qui fait le gros du travail. [[File:Logique de détection de la disponibilité d'une instruction.jpg|centre|vignette|upright=2|Logique de détection de la disponibilité d'une instruction.]] ==Les ''scheduler'' basées sur une mémoire associative== Les processeurs modernes utilisent une mémoire associative pour la ''scheduler''. Les mémoires associatives ont été abordées il y a quelques chapitres, mais faisons quelques rappels. Les mémoires associatives servent à accélérer la recherche de données dans un ensemble. Or, un ''scheduler'' vérifie régulièrement si chaque entrée est prête. Il s'agit d'un processus de recherche d'une instruction qui respecte une condition bien précise dans la mémoire, ce qui fait que les mémoires associatives sont donc tout indiquées. Comme vous le savez, les signaux de commande d'une instruction sont propagés avec celle-ci dans le pipeline, le nom du registre de destination ne faisant pas exception. Le nom de registre est envoyé à la ''scheduler'' lors de l'écriture du résultat dans les registres. S'il y a correspondance, l'opérande est disponible et son bit de disponibilité est mis à 1. On peut adapter cette méthode pour tenir compte du contournement assez simplement. [[File:Détection des dépendances par propagation du registre de destination.png|centre|vignette|upright=2|Détection des dépendances par propagation du registre de destination.]] En conséquence, le circuit de détection des dépendances est constitué d'un grand nombre de comparateurs : un par champ « nom de registre » dans chaque entrée. La logique d'éveil/''wake up'' regroupe tous les comparateurs, la logique de sélection est un circuit situé en-dehors de la mémoire associative. Les entrées sont dans la mémoire associative elle-même. [[File:Gestion des bits de validité.png|centre|vignette|upright=2|Gestion des bits de validité.]] L'implémentation la plus simple est celle du schéma précédent, où on utilise une mémoire associative unique. Une version plus élaborée sépare la ''scheduler'' en deux parties : une mémoire qui mémorise les registres des opérandes, une autre mémoire pour le reste. La mémoire pour les registres opérandes est la mémoire associative proprement dite, c'est elle qui est associée aux comparateurs, à la logique de ''wake-up''/réveil, etc. Par contre, l'autre mémoire est une mémoire RAM simplifiée, qui mémorise les informations qui n'ont pas besoin des comparateurs. L'opcode de l'instruction est là-dedans, par exemple. La ''scheduler'' est donc une sorte de mémoire associative améliorée. Il se trouve que c'est aussi le cas du ROB. Et il est possible de fusionner le tampon de ré-ordonnancement avec la ''scheduler'' dans une structure unique. La différence avec un ''scheduler'' normal est que les entrées sont libérées non pas quand l'instruction est exécutée/émise, mais quand elle termine son exécution et quitte le ROB. La ''scheduler'' incorpore des bits dans chaque entrée, pour savoir si la µops associée a été émise et est en cours de traitement dans les ALUs. La méthode a notamment été utilisée sur les processeurs d'architecture K6 d'AMD. Le tout donnait une structure appelée le '''DRIS''' (''deferred scheduling register renaming instruction shelf''). Les processeurs PA 8000 de HP étaient aussi vraisemblabment dans ce cas, aussi. ===Les optimisations de la consommation d'énergie : la désactivation des portions inutilisées=== Le problème avec des ''scheduler'' de ce type est leur forte consommation énergétique, ainsi que le grand nombre de portes logiques utilisées, qui deviennent prohibitifs pour des ''scheduler'' un peu grosses. Pour résoudre ce problème, certains ont optimisé les comparateurs. D'autres ont tenté de profiter du fait que la majorité des bits dans les entrées sont composés de zéros. Bref, les optimisations purement matérielles sont légion. Une première solution est de désactiver les entrées qui sont inutilisées, vides, sans instruction. Pour cela, on fait précéder les comparateurs par un circuit qui les connecte ou déconnecte des lignes de bit. Le circuit est commandé par le bit ''empty'' qui indique si une entrée est vide ou non. L'avantage est que la consommation d'énergie de la ''scheduler'' devient alors proportionnelle au nombre d'entrées non-vides, et non au nombre d'entrées total. Du moins, en apparence, les entrées non-utilisées doivent quand même être alimentées pour fonctionner, mais l'activité de comparaison disparait dans les entrées vides. Il est possible d'étendre cette technique aux entrées dont les opérandes sont prêts. Les gains sont généralement assez bons, avec une réduction de consommation variant entre 30 et 50%, avec une implémentation très simple et très économe en circuits. Une autre solution, assez simple à mettre en place, consiste à désactiver une partie de la ''scheduler'' sin elle est inutilisée. Pour cela, il faut segmenter la ''scheduler'' avec la technique du ''wire partitionning''. Pour rappel, un ''scheduler'' est une mémoire associative. Et comme toute mémoire associative, elle contient des fils, les lignes de bit, qui relient les entrées/sorties à toutes les cellules mémoire. Plus une ligne de bit est longue, plus elle consomme d'énergie et plus le temps de lecture/écriture est long. L'idée est de segmenter les lignes de bits en plaçant des répéteurs qui recopient la tension d'un segment au suivant. Les répéteurs sont des tampons trois-états, ce qui permet de déconnecter les portions inutilisées de la ligne de bit. Ce faisant, la ''scheduler'' est découpée en segments, qui peuvent être désactivés si besoin. S'il y a peu d'instructions chargées dans la ''scheduler'', les portions inutilisées sont désactivées. La technique marche d'autan mieux si les instructions sont compactées au début de la ''scheduler''. [[File:Wire partitionning.png|centre|vignette|upright=2|Wire partitionning]] Tout le problème est de savoir quelles portions désactiver. La technique est assez simple si la ''scheduler'' est compactée, à savoir si toutes les instructions sont régulièrement regroupées au début de la mémoire CAM. Mais même avec cette optimisation, la décision de désactiver une portion de la ''scheduler'' n'est pas à prendre à la légère. Il ne faut pas désactiver une portion contenant des instructions pouvant être émise sous peu. La décision dépend de paramètres variés : proportion d'entrée vides, quantité d'entrées récemment activées/désactivées récemment, présences d'entrées avec un ''match'' d'opérandes récent, etc. Il est important de préciser que les techniques en question fonctionnent aussi sur les autres types de ''scheduler'', qui ne sont pas basées sur des mémoires associatives. Nous allons voir celles-ci dans la suite du chapitre, mais gardez à l'esprit que ces optimisations, à savoir désactiver les entrées vides/prêts et partitionner la ''scheduler'', sont des optimisations générales qui marchent avec presque tout. ===L'ajout d'une FIFO pour les instructions déjà prêtes à l'émission=== D'autres techniques permettent de réduire aussi bien le cout en circuits que la consommation d'énergie de la ''scheduler''. L'idée est d'utiliser une mémoire associative quand elle est réellement nécessaire, mais d'utiliser un ''scheduler'' "normale" dès que possible. La méthode la plus simple tient compte du fait que certaines µopsont déjà toutes leurs opérandes de disponibles à l'émission, mais doivent quand même être mises en attente, parce que l'ALU adéquate est occupée, parce que des dépendances WAW/WAR sont encore là, ou pour tout autre raison. Dans ce cas, elles sont mises en attente non pas dans la ''scheduler'', mais dans une mémoire FIFO toute simple. L'idée est qu'au lieu d'avoir une énorme mémoire associative pour la ''scheduler'', on déplace quelques entrées dans une petite FIFO annexe. Le résultat est un gain d'énergie et de circuits, au prix d'une perte de performance mineure. La perte de performance en question se manifeste si aucune instruction n'a ses opérandes de prêtes à l'émission : le programme n'utilise pas la FIFO et voit alors un ''scheduler'' plus petite. Une amélioration de cette technique tient compte du fait que certaines instructions sont dans un cas intermédiaire. Elles ont déjà un opérande de prête lors de l'émission, mais pas l'autre. Le nombre d'opérandes varie suivant l’instruction : certaines n'ont besoin que d'un seul opérande. De plus, il arrive qu'une opération tout juste décodée ait déjà un ou plusieurs de ses opérandes de prêts. Cette constatation permet d'éviter d'utiliser des comparateurs pour les opérandes déjà prêts. Par exemple, on peut parfaitement utiliser trois ''scheduler'' : * une pour les instructions dont tous les opérandes sont prêts, mais qui sont quand même mises en attente, sans comparateur ; * une pour les instructions dont un seul opérande manque, qui n'utilise qu'un comparateur par entrée ; * une pour les instructions dont deux opérandes manquent à l'appel, qui utilise deux comparateurs par entrée. C'est beaucoup plus économique que d'utiliser une seule grosse ''scheduler'' qui contiendrait autant d'entrées que les trois précédentes réunies, avec deux comparateurs par entrée. Certains sont même allés plus loin, et ont proposé de supprimer la ''scheduler'' avec deux opérandes par entrée. Les instructions dont deux opérandes sont inconnus au décodage sont stockées dans la ''scheduler'' pour instructions avec un comparateur par entrée. Un circuit de prédiction se charge alors de prédire l'opérande manquant, cette prédiction étant vérifiée plus loin dans le pipeline. Il serait cependant étonnant qu'une telle proposition ait donné lieu à la moindre implémentation réelle. ===Les optimisations de la consommation d'énergie avancées=== D'autres chercheurs ont conservé un ''scheduler'' unique, avec autant de comparateurs par entrée qu'il y a d'opérandes possibles par instruction. Simplement, le processus de détection des opérandes prêts est légèrement ralenti : on ne vérifie qu'un opérande par cycle. Pour vérifier les deux opérandes d'une entrée, on doit attendre deux cycles. Enfin, certains chercheurs ont proposé des ''scheduler'' segmentées. Les instructions circulent à chaque cycle d'un segment vers le suivant : en conséquence, certains segments conservent les instructions les plus anciennes, un autre les instructions les plus jeunes, etc. Seul le denier segment, celui qui contient les instructions les plus vielles, peut émettre une instruction : la détection des opérandes se fait seulement dans le dernier segment, qui contient les instructions les plus anciennes. On économise ainsi beaucoup de comparateurs. Certains chercheurs ont tenté de pipeliner l'étape de sélection des opérandes, ainsi que l'étage d'arbitrage. Mais en faisant cela, il faut plusieurs cycles pour détecter qu'une instruction a ses opérandes prêts, ce qui pose problème face à de nombreuses dépendances RAW. Pour éviter de trop perdre en performances, certains chercheurs ont décidé d'utiliser des techniques pour prédire quelles seront les instructions dont les opérandes seront bientôt prêts. Si détecter qu'une instruction est prête prend n cycles, le processeur devra tenter de prédire la future disponibilité des opérandes n cycles en avance pour obtenir des performances optimales. ===Remplacer la mémoire associative par une RAM=== Une autre optimisation possible est de remplacer la ''scheduler'' par une mémoire RAM, dont chaque mot mémoire correspondrait à une entrée. Une telle optimisation permet en théorie de se passer des comparateurs associés à chaque entrée, mais au prix de l'ajout de circuits annexes potentiellement couteux. La première de ces techniques, la '''recherche directe par étiquette''' (direct tag search) fut créée par Weiss et son collègue Smith. Ils cherchaient à améliorer l'algorithme de Tomasulo, un algorithme qu'on expliquera dans quelques chapitres. Rappelons que chaque instruction produit un résultat, qui devra être rapatrié dans une ou plusieurs entrées de la ''scheduler''. L'optimisation de la recherche directe par étiquette fonctionne dans le cas où le résultat de l'instruction n'est utilisé que par une seule entrée, et pas plusieurs. Le principe est simple : chaque champ « opérande » d'une entrée est adressable via le nom de registre de cet opérande. Pour faire le lien entre entrée et nom de registre, la recherche directe par étiquette ajoute une table de correspondances matérielle, une mémoire RAM qui mémorise les adresses des champs « opérande » des entrées. Les adresses envoyées dans cette mémoire sont les noms de registres des résultats. Lors de l'émission, la table de correspondances est mise à jour. Les numéros des champs « opérande » réservés lors de l'émission sont mémorisés dans les mots mémoire qui correspondent aux deux registres sources. Toutefois, une petite vérification est faite lors de l'émission : s'il y a déjà une correspondance dans la table pour un registre source, alors une autre instruction compte lire ce registre. Pour éviter d'écraser les données de l'instruction précédente dans la table de correspondances, l'émission de l'instruction est bloquée. [[File:Recherche directe par étiquette.png|centre|vignette|upright=2|Recherche directe par étiquette.]] ==Les ''schedulers'' avec préplanification== Avec la '''préplanification''' (''prescheduling''), le ''scheduler'' est composée de mémoires FIFO dans lesquelles les instructions sont triées dans l'ordre d'émission. Il n'y a pas de logique d’émission proprement dite, celle-ci se bornant à vérifier si l'instruction située au début de la FIFO peut s’exécuter. Par contre, le préplanificateur détecte les dépendances et en déduit où insérer les instructions dans le tampon d'émission, à l'endroit le plus adéquat. [[File:Préplanification.jpg|centre|vignette|upright=2|Préplanification.]] ===L'usage de FIFO multiples=== La technique de préplanification la plus simple utilise plusieurs FIFO. Quand une instruction a une dépendance avec une autre instruction, les deux sont placées dans la même FIFO. Pour cela, le préplanificateur détecte les chaines d'instructions dépendantes, et place les instructions dans la FIFO adéquate. A chaque cycle, l'unité d'émission lit une micro-opération dans chaque FIFO et vérifie si elle peut l'émettre. Si la micro-opération n'a pas ses opérandes disponibles, ou qu'une dépendance structurelle survient, alors la FIFO est bloquée. La micro-opération attend que la dépendance soit résolue, bloquant toutes les instructions précédentes. Mais les autres FIFO ne sont pas bloquées, laissant de la marge de manœuvre. [[File:Préplanification par FIFO multiples.png|centre|vignette|upright=1.5|Préplanification par FIFO multiples.]] ===La technique du tampon trié=== La technique du '''tampon trié''' trie les instructions selon le temps d'attente avant leur exécution. Les instructions qui sont censées s’exécuter bientôt sont insérées au tout début de la FIFO, tandis que les instructions qui s’exécuteront dans un long moment sont insérées vers la fin. Là encore, l'unité d'émission lit une micro-opération dans la FIFO, et détermine si elle peut être émise. Si une dépendance survient, l'émission est retardée, et la FIFO est bloquée. [[File:Préplanification par tampon trié.png|centre|vignette|upright=1.5|Préplanification par tampon trié.]] La technique a cependant quelques problèmes assez importants. Le premier problème est que la FIFO est bloquée lorsqu'une micro-opération ne peut être émise. Le second problème est que le temps avant exécution n'est pas toujours connu, notamment pour les instructions d'accès mémoire. Et cela se répercute sur les instructions dépendantes de celles-ci. Pour résoudre ce genre de problèmes, l'usage d'un pipeline à ''replay'' est possible, et est même l'une des meilleures solutions possible, malgré ses défauts. L'idée est que les lectures sont pré-planifiées en supposant qu'elles font un succès de cache L1. Si la prédiction est fausse, la lecture est ré-exécutée plusieurs cycles plus tard, en supposant qu'elle fait un succès dans le cache L2, et ainsi de suite. Elle est alors ré-insérée dans la FIFO, elle est pré-planifiée une seconde fois. Il en est de même si une micro-opération ne peut pas être émise : il suffit de la réinsérer dans la FIFO au bon endroit, en attendant que ses dépendances soient résolues. Ainsi, l'instruction fautive ne bloque pas la fenêtre d’instruction, et retente sa chance autant de fois qu'il le faut. [[File:Préplanification par fenêtre d’instruction scorebarodée.png|centre|vignette|upright=1.5|Préplanification par fenêtre d’instruction scorebarodée.]] Une autre solution utilise deux ''schedulers'' : une FIFO gérée par la préplanification, et une vraie ''scheduler'' pour les instructions dont le temps d'attente ne peut pas être déterminé. Il est possible de mettre cette dernière avant la préplanification, afin de gérer les temps d'attente des instructions d'accès mémoire. Quand le temps d'attente d'une lecture devient connu, ses instructions dépendantes sont gérées avec préplanification. [[File:Préplanification avec fenêtre d’instruction.png|centre|vignette|upright=2.5|Préplanification avec fenêtre d’instruction.]] ===Les ''scheduler'' avec allocation temporelle statique=== L''''allocation temporelle statique''' correspond à une technique utilisée sur les processeurs Cuzco de l'entreprise Condor. La technique en question a été présenté en 2025, mais des idées similaires ont été présentées dans la littérature académique. Elle ressemble beaucoup aux techniques de pré-planification, avec cependant quelques différences. L'idée est simple : le processeur dispose de plusieurs ''scheduler'', qui mettent en attente les micro-opérations. Lors de l'étape de renommage de registres, le processeur détermine dans combien de cycles d'horloge la micro-opération sera prête pour exécution. La micro-opération est alors mise en attente durant ce nombre de cycles, dans les ''scheduler'', puis est émise une fois ce nombre de cycles écoulés. Ce faisant, les ''scheduler'' n'ont pas besoin de détecter la disponibilité des opérandes à chaque cycle, pour chaque micro-opération en attente. Le ''timing'' de l'émission des micro-opérations est décidé à l'avance. L'implémentation exacte n'est pas connue, mais plusieurs solutions sont imaginables. Par exemple, la ''scheduler'' peut simplement être composée de plusieurs mémoires de petite taille, chacune contenant les micro-opérations destinées à être exécutées dans N cycles, N étant différent pour chaque mémoire. Une autre solution, plus réaliste, utilise un ''scheduler'' dans laquelle la micro-opération est couplée à des champs pour les opérandes, et un champ compteur. Le champ compteur est initialisé avec le nombre de cycles à attendre, et est décrémenté à chaque cycle d'horloge. Quand il atteint zéro, la micro-opération est émise. Vous remarquerez que la méthode ne marche que si toutes les micro-opérations prennent un nombre fixe de cycles d'horloge. Et autant c'est le cas pour les micro-opérations arithmétiques ou logiques, autant les accès mémoire ne rentrent pas dans ce cadre. En théorie, on ne sait pas combien de temps prendra un accès mémoire. Et cette incertitude se répercute sur les instructions dépendantes d'un accès mémoire. Pour éviter cela, le processeur réutilise un pipeline à ''replay'' tel que vu dans le chapitre précédent. L'unité de renommage de registre suppose que tout accès mémoire fait un succès de cache L1, et décide des ''timings'' d'émission sous cette hypothèse. Si une lecture subit un défaut de cache, elle est ré-exécutée, de même que toutes les instructions dépendantes. Pour cela, le registre de destination de la lecture est marqué comme invalide, grâce à un bit spécifique attaché au registre. Toute instruction qui lit un opérande invalide est elle aussi ré-executée de zéro. Pour simplifier, l'unité d'émission ressemble à une unité d'émission dans l'ordre, avec un registre de disponibilité, qu'on aurait amélioré pour aller au-delà de la simple détection des dépendances d'instruction. Pour déterminer les ''timings'' d'émission, à savoir quand émettre une micro-opération, le processeur utilise une unité d'émission à deux étages. Le premier étage est appelé le ''register scoreboard'', le second étage est appelé la ''Time Ressource Matrix''. Les deux étages communiquent entre eux, comme on va le voir, et leurs noms donnent une idée de ce qu'ils font. Le premier étage gère les dépendances de registres, le second gère les dépendances structurelles. Le premier étage est un registre de disponibilité amélioré, qui gère les dépendances de registre. Cet étage sait quand tel registre sera écrit, et donc que l'opérande écrit dedans sera disponible à partir de tel cycle d'horloge. Il le sait car l'étage suivant l'aura prévenu, mais laissons cela de côté pour le moment. Quand une micro-opération rentre dans cet étage, il vérifie les dépendances avec les registres et les micro-opérations antérieures. Vu qu'il sait quand les registres seront disponibles, il peut déterminer quand l'instruction pourra s'exécuter. Par exemple, si une micro-opération lit les deux registres R7 et R15, qui sont disponibles respectivement dans 5 et 7 cycles, le premier étage sait que la micro-opération devra attendre 7 cycles. Mais tout cela ne suffit pas à déterminer quand émettre une micro-opération. En effet, il fait aussi gérer les dépendances structurelles, ce qui est le boulot du second étage. Le second étage utilise pour cela une ''Time Ressource Matrix'', qui mémorise l'occupation de diverses "ressources", pour les 256 cycles d'horloge à venir. Les ressources en question sont les ports de lecture/écriture du banc de registre, les ALUs utilisées, si la micro-opération utilise l'unité mémoire, etc. Le second étage prend en entrée une micro-opération, détermine quelles "ressources" elle utilise, puis regarde leur disponibilité. Elle détecte alors les dépendances structurelles et détermine alors quand peut s'exécuter la micro-opération. Elle peut retarder l'émission de quelques cycles, si une dépendance structurelle est détectée. Une fois sortie du second étage, on sait quand la micro-opération va être émise, à quel cycle précisément. Et vu que la durée de l'instruction est fixe, on sait quand cette micro-opération va se terminer, quand son résultat sera disponible. Cela permet de mettre à jour la ''Time Ressource Matrix'', pour préciser que le port d'écriture sera occupé à tel moment. De plus, cette information est transmise au premier étage, qui sait alors quand est enregistré le résultat dans le registre de destination. C'est comme cela que le premier étage sait quand un registre est disponible : le second étage le prévient, quand il émet une instruction ! La ''Time Ressource Matrix''mémorise l'occupation des "ressources" pour les 256 cycles d'horloge à venir. Cependant, elle ne vérifie pas les dépendances pour les 256 cycles suivants. Quand elle reçoit une micro-opération, elle teste les dépendances structurelles pour seulement les 8 prochains cycles maximum. Si la micro-opération ne peut pas être émise pendant ces 8 cycles, le pipeline est bloqué, un ''pipeline stall'' est émis. Pour être plus précis, vu que le processeur peut décoder 8 micro-opérations en même temps, cela permet de ne consulter que 64 cycles d'horloge sur les 256. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les premiers processeurs Intel | prevText=Les premiers processeurs Intel | next=Le renommage de registres | nextText=Le renommage de registres }} </noinclude> 8w8krbxosyf3qe8k3lgbo1xum7xo6fk 773627 773626 2026-09-29T21:04:30Z Mewtow 31375 /* Les schedulers avec préplanification */ 773627 wikitext text/x-wiki Dans les chapitres précédents, nous avons parlé des techniques dites d''''émission dans l'ordre'''. L'idée est d’exécuter une nouvelle micro-opération à chaque cycle, dans des unités de calcul séparées. Les instructions sont émises consécutivement, mais les instructions s’exécutent en parallèle dans des unités de calcul séparées. Par contre, quand l'unité d'émission ne peut pas émettre une instruction, elle bloque tout le pipeline. Les instructions qui suivent sont elles aussi bloquées, elles doivent attendre leur tour, même si elles sont en capacité de s'exécuter. Les techniques d'exécution dans le désordre que nous allons voir dans ce chapitre corrigent ce point précis. Elles sont dites à '''émission dans le désordre'''. Elles se distinguent des précédentes sur un point précis : quand l'unité d'émission bloque l'émission d'une instruction, les instructions suivantes peuvent poursuivre. L'émission des instructions peut donc se faire dans le désordre, dans le sens où une instruction peut être émise alors qu'une instruction précédente ne l'est pas encore. Mais avant de poursuivre, quelques point niveaux terminologie : * L'émission dans le désordre est un terme parlant et assez précis. Malheureusement, la terminologie la plus utilisée par d''''exécution dans le désordre'''. Et nous utiliserons ce terme dans la suite du cours, histoire de ne pas trop dévier de la nomenclature habituelle. * Nous utiliserons parfois l'abréviation OOO pour parler d'exécution dans le désordre. L'abréviation est celle de ''Out Of Order Excution''. * Nous utiliserons aussi l'abréviation ''µop'' pour parler de micro-opération, ''µops'' au pluriel pour parler de plusieurs micro-opérations, ou des micro-opérations en général. L'exécution dans le désordre ne gère en effet que des µops, elle se situe après l'étape de décodage. Pour décrire comment est implémentée l'émission dans le désordre, il faut commencer par parler des processeurs sans. Les processeurs sans exécution dans le désordre ont une unité d'émission qui bloque tout le pipeline dès qu'une µop ne peut pas être émise. Pour limiter l'impact de ce blocage, quelques rares processeurs incorporent une '''file de micro-opération''', une mémoire FIFO qui met en attente les µops. Vu que c'est une mémoire FIFO, les µops sont émises dans l'ordre, à savoir l'ordre d'ajout, dans l'ordre de décodage. Le schéma ci-dessous illustre une telle file d'attente couplée à un ''scoreboard''. L'exécution dans le désordre améliore la file de µops sur un point : ce n'est plus une mémoire FIFO. Les µops sont insérées dans l'ordre, mais peuvent sortir dans le désordre (être émises dans le désordre). La file de µops devient alors un '''''scheduler''''', terme anglais que je ne compte pas traduire. Un terme équivalent est '''''scheduler''''', terme traduit directement de l'anglais ''instruction Window''. Terme assez trompeur, car elles mettent en attente des µops, pas des instructions. [[File:Différence file µops et fenêtres instruction.png|centre|vignette|upright=2|Différence file µops et ''schedulers'' ]] Le ''scheduler'' émet une µop dès que ses opérandes sont disponibles. Par disponible, on veut dire présent soit dans le réseau de contournement, soit dans les registres. Le ''scheduler'' détecte automatiquement quand les opérandes d'une µop sont disponibles, grâce à une unité d'émission intégrée. L'unité d'émission et le ''scheduler'' sont fusionnés ensemble, dans un seul circuit, mais nous allons dire qu'ils sont conceptuellement séparés pour le moment. A chaque cycle, l'unité d'émission consulte les µops en attente pour détecter lesquelles peuvent s'exécuter. Le ''scheduler'' est spécialement être conçue pour, c'est une sorte de mémoire associative très complexe, comme on le verra dans ce qui suit. [[File:OOO Issue.png|centre|vignette|upright=2.5|Exécution dans le désordre avec un ''scheduler'']] Une fois qu'une µop sort du décodeur d'instructions, elle est ajoutée en parallèle dans la ''scheduler'' et le ROB. La raison est que les µops quittent la ''scheduler'' dans le désordre, et qu'elles doivent être remises en ordre par la suite. Le ROB s'occupe de cette remise en ordre, mais il a besoin de savoir dans quel ordre les µops sont censées être, et cet ordre est celui du décodage. Aussi, pour remplir le ROB, la seule opportunité est en sortie de l'unité de décodage. Dans le cas où une instruction est décodée en plusieurs micro-opérations, elles sont toutes insérées en même temps dans la ''scheduler'' et le ROB, en tenant compte de leur ordre. L'implémentation la plus simple de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Les µops décodées sont accumulées dans le ''scheduler'', où elles attendent leur tour. La ''scheduler'' sert donc de file d'attente. Avant de poursuivre, précisons que les micro-opérations mémoire sont à part des autres, pour diverses raisons. Une de ces raisons est que les dépendances de données sont classées en deux types : les dépendances de registre et les dépendances d'adresse. Et les deux sont fondamentalement différentes. Autant on peut détecter les dépendances de registre lors de l'émission, autant c'est plus compliqué avec les dépendances d'adresse. De plus, rappelons que si les lectures peuvent s'exécuter dans le désordre, les écritures doivent s'exécuter dans l'ordre, ou du moins en donner l'illusion. Pour cela, le processeur remet les écritures dans l'ordre avec une sorte de mini-ROB intégré à l'unité mémoire, appelée la file d'écriture. Elle complémente le ROB, qui lui ne gère que les écritures dans les registres, mais les deux collaborent. La file d'écriture envoie une écriture à la mémoire RAM quand le ROB lui dit que c'est bon, les instructions précédentes sont terminées ''dans l'ordre du programme''. Les processeurs modernes ajoutent des techniques d'exécution dans le désordre des accès mémoire, mais nous les verrons dans un chapitre dédié. Elles permettent d'utiliser un ''scheduler'' unique, qui mémorise aussi les µops mémoire. Si elles sont mises en place, l'unité mémoire n'a pas besoin de file de µops séparée. L'idée est que les dépendances de registre sont traitées par la ''scheduler'', mais que l'unité mémoire gére les dépendances d'adresse. Les dépendances d'adresse sont gérées par des techniques de ''désambiguation mémoire'', qui auront droit à un chapitre dédié. [[File:Processeur avec exécution dans le désodre des accès mémoire.png|centre|vignette|upright=2|Processeur avec exécution dans le désodre des accès mémoire]] Les processeurs assez anciens n'autorisaient pas d'exécution dans le désordre des accès mémoire. Concrétement, les accs mémoire devaient se faire dans l'ordre, mais les autres µops pouvaient être exécutées dans le désordre. Il s'agit donc d'un ordre entre µops mémoire, pas entre µops mémoire et autres µops. Les µops entières et flottantes pouvaient être exécutées avant une µops mémoire qui est avant elle dans l'ordre du programme, ce n'est pas un problème. Pour garantir l'ordre des µops mémoire, l'unité mémoire est précédée par une file de micro-opérations séparée, pour forcer l'exécution dans l'ordre des accès mémoire. De plus, les µops mémoire ne peuvent pas utiliser la ''scheduler''. Dit autrement, la ''scheduler'' ne mémorise pas de µops mémoire. Après le décodage, les µops sont réparties soit dans la file de µops mémoire, soit dans la ''scheduler''. Le décodeur classe les µops suivant que ce sont des µops mémoire ou non, et les envoient à la bonne destination. Dans ce chapitre, on supposera que c'est cette solution qui est utilisée. [[File:Processeur avec émission dans l'ordre des accès mémoire.png|centre|vignette|upright=2|Processeur avec émission dans l'ordre des accès mémoire]] ==L'implémentation d'un ''scheduler'' : généralités== Un ''scheduler'' est une mémoire qui mémorise des micro-opérations. Elle est cependant plus complexe qu'une mémoire RAM ou qu'une FIFO et ressemble un petit peu à une mémoire cache. Elle dispose d'un port d'écriture et d'un port de lecture, au minimum. Le port d'écriture permet à l'unité de décodage d'insérer une micro-opération dedans, d'ajouter la micro-opération qui vient d'être décodée. Si une instruction machine est décodée en plusieurs micro-opération, deux possibilités. La première est de les insérer un par un, ce qui fait qu'on peut se contenter d'un seul port d'écriture. L'autre possibilité est de les ajouter en même temps, ce qui demande plusieurs ports d'écriture. Le port de lecture sert à émettre une instruction. On part du principe que la ''scheduler'' ne peut émettre qu'une seule instruction à la fois, car les processeurs que nous avons vu précédemment sont de ce type. Mais nous verrons dans quelques chapitres qu'il existe des processeurs dits superscalaires, qui sont capables d'émettre plusieurs instructions par cycle. Dans ce cas, la ''scheduler'' a un seul port de lecture. Un processeur superscalaire, quant à lui, doit avoir un port de lecture par unité de calcul, ce qui fait beaucoup plus. Les ''schedulers'' sont composées d''''entrées''', des mots mémoire qui stockent une instruction. Une instruction réserve une entrée après son décodage et la libère dès qu'elle est envoyée aux unités de calcul. Une entrée contient l'opcode (les signaux de commande à envoyer à l'ALU), le registre de destination du résultat, les registres de chaque opérande, et éventuellement des signaux de commande en plus. De plus, chaque opérande est couplée à un bit de disponibilité, qui indique si elle est disponible. Quand un opérande est écrit dans les registres, le bit de présence correspondant est mis à jour. Enfin, chaque entrée possède un bit ''empty'' qui indique si elle est vide, cette information étant utile pour réserver des entrées. [[File:Entrée d'une station de réservation - sans les tags.png|centre|vignette|upright=3|Entrée d'un ''scheduler'']] ===Les stations de réservation=== Les '''stations de réservation''' sont des ''scheduler'' particulières, qui sont capables de mémoriser les opérandes des instructions. Les entrées des stations de réservation sont identiques à celle des autres ''scheduler'', si ce n'est que les opérandes de l'instruction sont enregistrés directement dans des champs séparés. Il y a deux champs, un par opérande, pour stocker l'opérande elle-même, lue depuis les registres ou obtenue via le réseau de contournement. Notons que les champs pour les opérandes viennent en plus des champs pour les noms de registres, encore que les deux peuvent être fusionnés si on veut optimiser le tout. [[File:Entrée d'une station de réservation.png|centre|vignette|upright=3|Entrée d'une station de réservation.]] Précisons que la terminologie n'est pas très fiable. Les termes "''scheduler''" et "station de réservation" ne regroupent pas du tout la même chose d'un papier de recherche à l'autre, d'un bouquin à l'autre, d'un chercheur à l'autre, d'un ingénieur à l'autre, d'un professeur à l'autre. Le terme initial vient pourtant de l'article original sur l'algorithme de Tomasulo, où il désignait un ''scheduler'' associée à une unité de calcul précise. Mais le terme a ensuite été réutilisé, ce qui fait que certains processeurs avec plusieurs unités de calcul sont décrits comme ayant une unique station de réservation. En bref : c'est le bazar ! Mais nous en reparlerons dans le chapitre sur le renommage de registres, car c'est la place idéale pour les aborder. Toujours est-il que j'ai fait le choix de confondre les concepts de ''scheduler'' et de station de réservation avec les concepts de '''lecture avant émission''' et de '''lecture après émission'''. La différence entre les deux est que les registres sont lus après émission avec un ''scheduler'', avant avec des stations de réservation. Dans le cas "avant émission", les opérandes sont mémorisés dans la station de réservation. Et cette différence a une influence sur le pipeline du processeur, le banc de registres et tout ce qui s'en suit. Un désavantage de la lecture avant émission est qu'il faut stocker les opérandes après lecture, ici dans les stations de réservation. Mais un avantage est que le banc de registre a besoin de moins de ports de lecture, car une bonne partie des opérandes sont fournies par le système de contournement. Nous verrons cela dans le détail dans le chapitre sur les processeurs superscalaires. [[File:Processeur avec plusieurs ''scheduler''.png|centre|vignette|upright=2.5|Lecture après émission.]] [[File:Read Before Issue.png|centre|vignette|upright=2.5|Lecture avant émission.]] ===La logique d'éveil et de sélection=== Dans le cas qui va suivre, on suppose que le processeur ne peut émettre qu'une instruction à la fois. Chaque cycle, une instruction est sélectionnée et est envoyée dans le chemin de données, soit à une ALU, soit à une unité d'accès mémoire. La sélection d'une instruction est effectuée par l'unité d'émission, qui est aussi appelée le '''''scheduler'''''. Elle gère la disponibilité des opérandes et la disponibilité des unités de calcul adéquate. Le choix de l'instruction émise doit être le plus pertinent possible, pour des raisons de performances. Pour le premier point, l'unité d'émission détermine quelles instructions sont candidates pour l'émission. Les ''instructions candidates'' sont celles dont tous les opérandes sont prêts. Le processeur contient un circuit qui détecte les instructions candidates : la '''logique d’éveil''' (''wake-up logic''). Une fois que la logique d'éveil a fait son travail, une instruction est choisie pour s’exécuter en fonction de la disponibilité des unités de calcul adéquates. Ce rôle est dévolu à un circuit qu'on appelle la '''logique de sélection''', ou ''select logic''. [[File:Fonctionnement complet de la logique d’émission.jpg|centre|vignette|upright=1.5|Fonctionnement complet de la logique d’émission.]] La logique de sélection doit gérer le fait que les unités de calcul du processeur ne sont pas toutes identiques. Déjà, un processeur a généralement des unités séparées pour les instructions entières et flottantes, des unités spécialisées dans les accès mémoire, parfois des unités spécialisées pour les branchements. Une instruction doit être attribuée à la bonne unité de calcul, on ne doit pas envoyer une instruction entière dans une unité de calcul flottante. De plus, parmi les unités de calcul entières, toutes ne sont pas identiques. Par exemple, il est fréquent d'avoir plusieurs unités de calcul spécialisées dans les opérations simples (additions, soustractions, opérations logiques) avec une unité pour les multiplications/divisions séparées, parfois une unité spécialisée pour les décalages/rotations, etc. Là encore, allouer la bonne instruction à la bonne ALU est complexe. Plus les unités de calcul sont hétérogènes, plus la logique de sélection est compliquée. Les logiques d'éveil comme de sélection sont assez complexes. Comme on le verra plus bas, la logique de sélection la plus simple, qui gère une seule unité de calcul, est basée sur un encodeur à priorité couplé à d'autres circuits. Et pour gérer plusieurs ALUs, il faut mettre des encodeurs en cascade. Le résultat est que même en prenant une logique de sélection simple, elle sera assez lente et gourmande en circuits. Aussi, la logique de sélection met souvent un cycle d'horloge entier pour faire son travail, elle a son propre étage de pipeline attribué. La logique d'éveil est dans le même cas, ce qui fait qu'émettre une micro-opération demande deux cycles d'horloge. Le défaut est que cela rajoute des cycles d'horloges entre la ''scheduler'' et l'ALU, ce qui complique la gestion du pipeline. Ces cycles de retard sont à prendre en compte au moment d'émettre les instructions, les ''scheduler'' doit en tenir compte pour des performances optimales. Sans tenir compte de ces cycles de retard, les instructions arrivent en retard de quelques cycles à l'ALU, cycles de retard durant lesquels l'ALU n'a pas fait de calcul et a été sous-utilisée, sans compter que le système de contournement n'est pas utilisé au mieux. Et le problème est encore plus important sur les processeurs avec des stations de réservation, qui utilisent la "lecture après émission" : cela rajoute un cycle d'horloge en plus, un temps de retard en plus. ===La logique d'éveil : l'émission anticipée=== La logique d'éveil doit tenir compte du fait qu'il y a plusieurs étages entre l'émission et l'exécution sur une unité de calcul. Par exemple, un processeur a souvent entre un et à cinq étages entre la file d'attente et les unités de calcul. Il faut lire les registres, gérer le contournement, et cela peut prendre quelques cycles d'horloge. Sur le Pentium 4, on trouve 6 étages entre le ''scheduler'' et l'entrée de l'ALU. Si les micro-opérations sont émises quand les opérandes sont disponibles, il y aura un délai de quelques cycles avant qu'elles atteignent l'ALU. Alors qu'idéalement, on souhaiterait que la micro-opération atteigne l'ALU dès que ses opérandes sont disponibles, pour profiter des techniques de contournement. Pour cela, la logique d'éveil émet les instructions quelques cycles en avance pour qu'elles arrivent au bon moment. Il s'agit d'une technique d''''émission anticipée''', dont nous avions parlé dans le chapitre sur le contournement. : Il faut noter que le problème se pose plus avec des ''scheduler'' qu'avec des stations de réservation. Les premières ont un étage en plus entre émission et ALU, vu qu'il faut lire des registres après l'émission. L'émission anticipée demande d'émettre un signal d'éveil en avance de quelques cycles, pile au bon moment. Par exemples, si on a deux étages entre l'ALU et l'unité d'émission, le signal de réveil sera généré deux cycles avant que le résultat soit effectivement calculé. L'implémentation varie, mais deux solutions sont possibles. La première est de générer le signal d'éveil dans l'ALU, ce qui n'a de sens que pour les opérations comme les multiplications ou les divisions, qui prennent plusieurs cycles. Une autre technique génère le signal de réveil dans une structure centralisée, spécialisée dans la génération des signaux d'éveil. L'unité de composée d'un registre à décalage par registre. Imaginons qu'une instruction est émise, que cette instruction mette N cycles à s'exécuter, et qu'elle écrive dans un registre de destination. L'unité sélectionne alors le registre à décalage associé au registre de destination, et met le bit numéro N à 1. Le registre décalé d'un cran à chaque cycle. Quand le bit sortant est un 1, alors le signal de validité pour l'opérande est généré. L'émission anticipée marche bien si l'instruction a une durée fixe, connue à l'avance. Et autant c'est le cas pour les instructions arithmétiques et logiques, autant ce n'est pas le cas pour les accès mémoire. Les accès mémoire ont une latence variable : quelques cycles pour un succès de cache, plusieurs dizaines de cycles pour un défaut de cache L1, pas loin de la centaine pour un défaut de cache L2, etc. Et cela pose des problèmes pour l'émission anticipée. L'émission en avance pour les accès mémoire est purement spéculative : le processeur émet des instructions en supposant que la lecture entrainera un succès de cache, quitte à annuler l'instruction en cas de défaut de cache. Mais faire ainsi demande non seulement d'annuler les instructions émises en avance, mais aussi de ne pas retirer les instructions émises en avance de la ''scheduler''. Elles sont émises, mais une copie de sauvegarde est conservée dans la ''scheduler''. Si le processeur détecte un défaut de cache, il peut alors ré-exécuter l'instruction. S'il détecte un succès de cache, les instructions lecture-dépendante sont retirées de la ''scheduler'', la copie de sauvegarde est devenue inutile et est donc jetée. ===La logique de sélection : âge ou position ?=== La logique de sélection est primordiale pour de bonnes performances. Il existe deux méthodes principales pour sélectionner l'instruction à exécuter. La première est la plus simple : elle se base sur lé numéro de l'entrée. En effet, un ''scheduler'' est avant tout une sorte de mémoire, un mix entre mémoire associative, mémoire RAM, et FIFO. Et chaque entrée a un numéro, une adresse mémoire. Nous parlerons de numéro dans ce qui suit, car ce sera plus simple, le terme d'adresse mémoire étant peut-être un peu exagéré dans le contexte des ''scheduler''. Toujours est-il que la ''scheduler'' est adressable dans le sens où on peut lui envoyer le numéro de l'entrée voulue, et le ''scheduler'' renvoie le contenu de l'entrée sur son port de lecture. Et c'est ce que fait la logique de sélection : elle génère le numéro de l'entrée à lire. Le numéro est alors envoyé sur l'entrée d'adresse du ''scheduler'', et elle fournit la micro-opération associée sur son port de lecture, son '''port d'émission'''. La première méthode de sélection, donc. Elle est basée sur le numéro de l'entrée. Si plusieurs entrées sont éveillées, la logique de sélection prend celle avec le plus petit numéro. Elle porte le nom de '''sélection par position''', sous-entendu position dans la ''scheduler''. Vous l'avez peut-être deviné, mais la logique de sélection est alors un encodeur à priorité. Le circuit de sélection ne se résume donc pas seulement à un encodeur à priorité, mais c'est le circuit central. L'avantage d'une telle méthode de sélection est qu'elle est simple à implémenter : un encodeur à priorité est un circuit connu, facile à implémenter. Mais on remarque un défaut : un encodeur est un circuit assez rapide, mais qui utilise beaucoup de transistors, beaucoup de portes logiques, surtout si on veut qu'il soit rapide. Ce qui explique que la logique de sélection ait son propre étage de pipeline rien que pour elle. La seconde méthode s'appelle la '''sélection par âge''', au nom assez transparent. L'idée est de privilégier l'émission de l'instruction la plus ancienne. Elle demande que la ''scheduler'' trie les micro-opérations par ordre d'insertion dans la ''scheduler'', ce qui en fait une pseudo-FIFO. Le tri est partiel, car les instructions peuvent sortir du ''scheduler'' à tout moment. Compacter le ''scheduler'', à savoir regrouper toutes les entrées valides est une idée, mais elle est compliquée à implémenter. Aussi, elles préfèrent encoder des informations sur l'ordre d'émission dans chaque entrée. L'encodeur à priorité doit alors travailler non pas sur des nombres entiers liés à l'ordre d'insertion dans la pseudo-FIFO. Elle est encore plus gourmande en circuits que la méthode précédente. Les processeurs haute performance utilisent souvent des méthodes hybrides. Par exemple, les processeurs AMD de microarchitecture Bulldozer utilisaient une méthode intermédiaire. Ils utilisaient un ''scheduler'' couplée à un encodeur à priorité pour la sélection par position, mais complémentaient le tout avec une unité qui mémorisait l'instruction la plus ancienne dans la fenêtre d’instruction. Le mécanisme de sélection par âge était utilisé en priorité. Mais si l'instruction la plus ancienne n'était pas prête, le processeur basculait sur le mécanisme de sélection par position. ===La compaction des ''scheduler''=== À chaque cycle, les instructions décodées sont ajoutées dans la ''scheduler'', dans des entrées vides. Vu que les instructions quittent celle-ci dans le désordre, ces vides sont dispersés dans la ''scheduler'', ce qui pose problème pour déterminer où placer les nouvelles instructions. La solution la plus triviale consiste à conserver une liste des vides, mise à jour à chaque insertion ou émission d'instruction. Une autre solution consiste à éliminer les vides en compactant la ''scheduler'' à chaque cycle d'horloge. Des circuits se chargent de détecter les vides et de regrouper les instructions en un unique bloc. Il faut signaler que certains processeurs arrivent à se passer de cette étape de compactage, mais au prix de ''scheduler'' nettement plus complexes. Autre problème : quand il faut choisir quelle instruction émettre, il y a toujours plusieurs candidats. Si on choisit mal, des instructions restent en attente trop longtemps parce que d'autres instructions plus jeunes leur passent devant. Pour éviter cela, les instructions les plus vielles, les plus anciennes, sont prioritaires. Pour cela, on peut utiliser une FIFO un peu spéciale pour la ''scheduler''. Si les ajouts d'instruction se font dans l'ordre, les instructions ne quittent pas forcément la ''scheduler'' dans l'ordre imposé par une FIFO : les instructions restent triées dans leur ordre d'ajout, même s'il y a des vides entre elles. Dans ces conditions, il est préférable que le compactage conserve l'ordre FIFO des instructions. Dans ces conditions, l'instruction la plus ancienne est celle qui est située à l'adresse la plus faible : le circuit de sélection peut donc être fabriqué avec des encodeurs, et est relativement simple. ==Les ''schedulers'' basées sur une matrice de dépendances== L'implémentation la plus simple étend le fonctionnement d'un pipeline dynamique usuel. Rappelez-vous le chapitre sur les pipelines dynamiques. Nous avions vu que de tels pipelines émettaient une instruction par cycle, quitte à émettre des bulles de pipeline en cas de dépendance bloquante. Et il est possible d'améliorer leur unité d'émission pour qu'elle soit compatible avec l'exécution dans le désordre. ===Rappels sur le registre de réservation/disponibilité=== L'émission d'une instruction est gouvernée par un ''registre de réservation'' qui indique quels registres sont réservés par une instruction, et ceux qui sont libres. Un registre réservé est un registre qui sera écrit par une instruction en cours d'exécution, mais qui n'a pas encore écrit son résultat. Les instructions candidates doivent avoir leurs opérandes dans des registres libres. Sinon, c'est signe que leurs opérandes sont réservés en écriture, donc pas encore écrites, donc pas disponibles. Si une instruction candidate veut lire ce registre, c'est signe qu'il y a une dépendance RAW : elle veut lire un registre réservé, qui est destiné à être écrit par une instruction en vol. Si elle veut écrire, c'est signe qu'elle veut écrire dans un registre où une autre instruction veut écrire : c'est une dépendance WAW. Dans les deux cas, l'instruction n'est pas émise. Le registre de réservation encode les registres réservés comme suit : chaque bit est associé à un registre. Le bit numéro 0 est associé au registre numéro 0, le bit numéro 1 au registre numéro 1, etc. Là, En clair, les numéros de registres réservés sont encodés en représentation non pas binaire, mais en représentation ''one-hot'' (vue au premier chapitre). {|class="wikitable" |+ Registre de réservation |- ! Registre 7 !! Registre 6 !! Registre 5 !! Registre 4 !! Registre 3 !! Registre 2 !! Registre 1 !! Registre 0 |- | 0 || 0 || 1 || 0 || 0 || 1 || 0 || 0 |} Avant d'émettre une instruction, l'unité d'émission extrait les registres opérande/destination et les convertis dans la même représentation que le registre de réservation, à savoir en représentation ''one-hot''. Le circuit de traduction binaire vers ''one-hot'' est, pour rappel, un simple décodeur. Puis, on fait un OU logique entre les sorties des décodeurs. Le résultat est un masque qui indique quels registres sont lus par l'instruction, encodé en représentation ''one-hot''. Appelons-le le '''masque d'opérandes'''. Le masque est alors comparé au registre de réservation pour vérifier si l'instruction peut être émise. [[File:Unité d'émission simple, dans l'ordre.png|centre|vignette|upright=2|Unité d'émission simple, dans l'ordre]] Si l'émission est autorisée, le registre de réservation est là aussi mis à jour. Le registre de réservation est aussi mis à jour dès qu'une instruction enregistre son résultat dans les registres, ou alors dès qu'il est disponible pour le contournement. Le bit associé au registre repasse alors à 0 (ou à 1). Sans contournement, la mise à jour se fait alors à la toute fin de l'instruction, quand elle se termine, lors de la dernière étape d'enregistrement, à la fin de son pipeline. Avec, elle se fait quand l'instruction quitte l'unité de calcul. ===L'extension à l'exécution dans le désordre : l'éveil par matrice de bits=== La différence entre un pipeline dynamique et l'exécution dans le désordre est que l'on passe d'une instruction à émettre à plusieurs. Plusieurs instructions sont mises en attente dans un ''scheduler'', et y attendent leur tour. L'idée est alors d'envoyer le registre de disponibilité à toutes les entrées, à toutes les instructions en attente. Ainsi, on sait quelles sont les instructions qui peuvent s'exécuter et celles qui ne le peuvent pas. L'implémentation est assez simple, elle ressemble beaucoup à l'implémentation d'un pipeline dynamique simple, si ce n'est que des circuits sont dupliqués. L'implémentation utilise des ''scheduler'' légèrement différentes de celles introduites plus haut. Elles n'utilisent notamment pas de bits de disponibilité, mais autre chose. Lorsqu'une instruction est ajoutée à la ''scheduler'', le masque de disponibilité des opérandes est stocké dans la ''scheduler''. A chaque cycle, le registre de disponibilité est envoyé à toutes les entrées, et est comparé avec tous les masques de disponibilité des opérandes. Si une comparaison renvoie un 1, alors l'instruction de l'entrée est une instruction candidate à l'émission. [[File:Unité d'émission dans le désordre basée sur un registre de disponibilité.png|centre|vignette|upright=2.5|Unité d'émission dans le désordre basée sur un registre de disponibilité]] L'ensemble est implémenté avec l'aide d'une '''matrice de bits''', où chaque ligne correspond à une entrée et chaque colonne à un registre. À chaque croisement entre une ligne et une colonne, on trouve un bit. Si le bit de la ligne n et de la colonne m est à 1, cela veut dire : l'instruction dans l'entrée n a besoin de lire le registre m. S’il est à 0, alors cela veut dire que l'instruction stockée dans la ligne n'a pas besoin de la donnée dans le registre m. [[File:Planificateur à matrice de bits.jpg|centre|vignette|upright=2|Planificateur à matrice de bits.]] Lorsqu'une instruction réserve une entrée, elle initialise la ligne en fonction des registres qu'elle souhaite lire. Pour vérifier si une instruction a ses opérandes prêts, le processeur compare le registre de disponibilité à la ligne associée à l'instruction/entrée. A chaque intersection ligne-colonne, se trouve un comparateur de 1 bit, qui détecte si le registre est demandé et disponible. Les résultats de cette porte sont ensuite envoyés à une porte ET, qui fait le gros du travail. [[File:Logique de détection de la disponibilité d'une instruction.jpg|centre|vignette|upright=2|Logique de détection de la disponibilité d'une instruction.]] ==Les ''scheduler'' basées sur une mémoire associative== Les processeurs modernes utilisent une mémoire associative pour la ''scheduler''. Les mémoires associatives ont été abordées il y a quelques chapitres, mais faisons quelques rappels. Les mémoires associatives servent à accélérer la recherche de données dans un ensemble. Or, un ''scheduler'' vérifie régulièrement si chaque entrée est prête. Il s'agit d'un processus de recherche d'une instruction qui respecte une condition bien précise dans la mémoire, ce qui fait que les mémoires associatives sont donc tout indiquées. Comme vous le savez, les signaux de commande d'une instruction sont propagés avec celle-ci dans le pipeline, le nom du registre de destination ne faisant pas exception. Le nom de registre est envoyé à la ''scheduler'' lors de l'écriture du résultat dans les registres. S'il y a correspondance, l'opérande est disponible et son bit de disponibilité est mis à 1. On peut adapter cette méthode pour tenir compte du contournement assez simplement. [[File:Détection des dépendances par propagation du registre de destination.png|centre|vignette|upright=2|Détection des dépendances par propagation du registre de destination.]] En conséquence, le circuit de détection des dépendances est constitué d'un grand nombre de comparateurs : un par champ « nom de registre » dans chaque entrée. La logique d'éveil/''wake up'' regroupe tous les comparateurs, la logique de sélection est un circuit situé en-dehors de la mémoire associative. Les entrées sont dans la mémoire associative elle-même. [[File:Gestion des bits de validité.png|centre|vignette|upright=2|Gestion des bits de validité.]] L'implémentation la plus simple est celle du schéma précédent, où on utilise une mémoire associative unique. Une version plus élaborée sépare la ''scheduler'' en deux parties : une mémoire qui mémorise les registres des opérandes, une autre mémoire pour le reste. La mémoire pour les registres opérandes est la mémoire associative proprement dite, c'est elle qui est associée aux comparateurs, à la logique de ''wake-up''/réveil, etc. Par contre, l'autre mémoire est une mémoire RAM simplifiée, qui mémorise les informations qui n'ont pas besoin des comparateurs. L'opcode de l'instruction est là-dedans, par exemple. La ''scheduler'' est donc une sorte de mémoire associative améliorée. Il se trouve que c'est aussi le cas du ROB. Et il est possible de fusionner le tampon de ré-ordonnancement avec la ''scheduler'' dans une structure unique. La différence avec un ''scheduler'' normal est que les entrées sont libérées non pas quand l'instruction est exécutée/émise, mais quand elle termine son exécution et quitte le ROB. La ''scheduler'' incorpore des bits dans chaque entrée, pour savoir si la µops associée a été émise et est en cours de traitement dans les ALUs. La méthode a notamment été utilisée sur les processeurs d'architecture K6 d'AMD. Le tout donnait une structure appelée le '''DRIS''' (''deferred scheduling register renaming instruction shelf''). Les processeurs PA 8000 de HP étaient aussi vraisemblabment dans ce cas, aussi. ===Les optimisations de la consommation d'énergie : la désactivation des portions inutilisées=== Le problème avec des ''scheduler'' de ce type est leur forte consommation énergétique, ainsi que le grand nombre de portes logiques utilisées, qui deviennent prohibitifs pour des ''scheduler'' un peu grosses. Pour résoudre ce problème, certains ont optimisé les comparateurs. D'autres ont tenté de profiter du fait que la majorité des bits dans les entrées sont composés de zéros. Bref, les optimisations purement matérielles sont légion. Une première solution est de désactiver les entrées qui sont inutilisées, vides, sans instruction. Pour cela, on fait précéder les comparateurs par un circuit qui les connecte ou déconnecte des lignes de bit. Le circuit est commandé par le bit ''empty'' qui indique si une entrée est vide ou non. L'avantage est que la consommation d'énergie de la ''scheduler'' devient alors proportionnelle au nombre d'entrées non-vides, et non au nombre d'entrées total. Du moins, en apparence, les entrées non-utilisées doivent quand même être alimentées pour fonctionner, mais l'activité de comparaison disparait dans les entrées vides. Il est possible d'étendre cette technique aux entrées dont les opérandes sont prêts. Les gains sont généralement assez bons, avec une réduction de consommation variant entre 30 et 50%, avec une implémentation très simple et très économe en circuits. Une autre solution, assez simple à mettre en place, consiste à désactiver une partie de la ''scheduler'' sin elle est inutilisée. Pour cela, il faut segmenter la ''scheduler'' avec la technique du ''wire partitionning''. Pour rappel, un ''scheduler'' est une mémoire associative. Et comme toute mémoire associative, elle contient des fils, les lignes de bit, qui relient les entrées/sorties à toutes les cellules mémoire. Plus une ligne de bit est longue, plus elle consomme d'énergie et plus le temps de lecture/écriture est long. L'idée est de segmenter les lignes de bits en plaçant des répéteurs qui recopient la tension d'un segment au suivant. Les répéteurs sont des tampons trois-états, ce qui permet de déconnecter les portions inutilisées de la ligne de bit. Ce faisant, la ''scheduler'' est découpée en segments, qui peuvent être désactivés si besoin. S'il y a peu d'instructions chargées dans la ''scheduler'', les portions inutilisées sont désactivées. La technique marche d'autan mieux si les instructions sont compactées au début de la ''scheduler''. [[File:Wire partitionning.png|centre|vignette|upright=2|Wire partitionning]] Tout le problème est de savoir quelles portions désactiver. La technique est assez simple si la ''scheduler'' est compactée, à savoir si toutes les instructions sont régulièrement regroupées au début de la mémoire CAM. Mais même avec cette optimisation, la décision de désactiver une portion de la ''scheduler'' n'est pas à prendre à la légère. Il ne faut pas désactiver une portion contenant des instructions pouvant être émise sous peu. La décision dépend de paramètres variés : proportion d'entrée vides, quantité d'entrées récemment activées/désactivées récemment, présences d'entrées avec un ''match'' d'opérandes récent, etc. Il est important de préciser que les techniques en question fonctionnent aussi sur les autres types de ''scheduler'', qui ne sont pas basées sur des mémoires associatives. Nous allons voir celles-ci dans la suite du chapitre, mais gardez à l'esprit que ces optimisations, à savoir désactiver les entrées vides/prêts et partitionner la ''scheduler'', sont des optimisations générales qui marchent avec presque tout. ===L'ajout d'une FIFO pour les instructions déjà prêtes à l'émission=== D'autres techniques permettent de réduire aussi bien le cout en circuits que la consommation d'énergie de la ''scheduler''. L'idée est d'utiliser une mémoire associative quand elle est réellement nécessaire, mais d'utiliser un ''scheduler'' "normale" dès que possible. La méthode la plus simple tient compte du fait que certaines µopsont déjà toutes leurs opérandes de disponibles à l'émission, mais doivent quand même être mises en attente, parce que l'ALU adéquate est occupée, parce que des dépendances WAW/WAR sont encore là, ou pour tout autre raison. Dans ce cas, elles sont mises en attente non pas dans la ''scheduler'', mais dans une mémoire FIFO toute simple. L'idée est qu'au lieu d'avoir une énorme mémoire associative pour la ''scheduler'', on déplace quelques entrées dans une petite FIFO annexe. Le résultat est un gain d'énergie et de circuits, au prix d'une perte de performance mineure. La perte de performance en question se manifeste si aucune instruction n'a ses opérandes de prêtes à l'émission : le programme n'utilise pas la FIFO et voit alors un ''scheduler'' plus petite. Une amélioration de cette technique tient compte du fait que certaines instructions sont dans un cas intermédiaire. Elles ont déjà un opérande de prête lors de l'émission, mais pas l'autre. Le nombre d'opérandes varie suivant l’instruction : certaines n'ont besoin que d'un seul opérande. De plus, il arrive qu'une opération tout juste décodée ait déjà un ou plusieurs de ses opérandes de prêts. Cette constatation permet d'éviter d'utiliser des comparateurs pour les opérandes déjà prêts. Par exemple, on peut parfaitement utiliser trois ''scheduler'' : * une pour les instructions dont tous les opérandes sont prêts, mais qui sont quand même mises en attente, sans comparateur ; * une pour les instructions dont un seul opérande manque, qui n'utilise qu'un comparateur par entrée ; * une pour les instructions dont deux opérandes manquent à l'appel, qui utilise deux comparateurs par entrée. C'est beaucoup plus économique que d'utiliser une seule grosse ''scheduler'' qui contiendrait autant d'entrées que les trois précédentes réunies, avec deux comparateurs par entrée. Certains sont même allés plus loin, et ont proposé de supprimer la ''scheduler'' avec deux opérandes par entrée. Les instructions dont deux opérandes sont inconnus au décodage sont stockées dans la ''scheduler'' pour instructions avec un comparateur par entrée. Un circuit de prédiction se charge alors de prédire l'opérande manquant, cette prédiction étant vérifiée plus loin dans le pipeline. Il serait cependant étonnant qu'une telle proposition ait donné lieu à la moindre implémentation réelle. ===Les optimisations de la consommation d'énergie avancées=== D'autres chercheurs ont conservé un ''scheduler'' unique, avec autant de comparateurs par entrée qu'il y a d'opérandes possibles par instruction. Simplement, le processus de détection des opérandes prêts est légèrement ralenti : on ne vérifie qu'un opérande par cycle. Pour vérifier les deux opérandes d'une entrée, on doit attendre deux cycles. Enfin, certains chercheurs ont proposé des ''scheduler'' segmentées. Les instructions circulent à chaque cycle d'un segment vers le suivant : en conséquence, certains segments conservent les instructions les plus anciennes, un autre les instructions les plus jeunes, etc. Seul le denier segment, celui qui contient les instructions les plus vielles, peut émettre une instruction : la détection des opérandes se fait seulement dans le dernier segment, qui contient les instructions les plus anciennes. On économise ainsi beaucoup de comparateurs. Certains chercheurs ont tenté de pipeliner l'étape de sélection des opérandes, ainsi que l'étage d'arbitrage. Mais en faisant cela, il faut plusieurs cycles pour détecter qu'une instruction a ses opérandes prêts, ce qui pose problème face à de nombreuses dépendances RAW. Pour éviter de trop perdre en performances, certains chercheurs ont décidé d'utiliser des techniques pour prédire quelles seront les instructions dont les opérandes seront bientôt prêts. Si détecter qu'une instruction est prête prend n cycles, le processeur devra tenter de prédire la future disponibilité des opérandes n cycles en avance pour obtenir des performances optimales. ===Remplacer la mémoire associative par une RAM=== Une autre optimisation possible est de remplacer la ''scheduler'' par une mémoire RAM, dont chaque mot mémoire correspondrait à une entrée. Une telle optimisation permet en théorie de se passer des comparateurs associés à chaque entrée, mais au prix de l'ajout de circuits annexes potentiellement couteux. La première de ces techniques, la '''recherche directe par étiquette''' (direct tag search) fut créée par Weiss et son collègue Smith. Ils cherchaient à améliorer l'algorithme de Tomasulo, un algorithme qu'on expliquera dans quelques chapitres. Rappelons que chaque instruction produit un résultat, qui devra être rapatrié dans une ou plusieurs entrées de la ''scheduler''. L'optimisation de la recherche directe par étiquette fonctionne dans le cas où le résultat de l'instruction n'est utilisé que par une seule entrée, et pas plusieurs. Le principe est simple : chaque champ « opérande » d'une entrée est adressable via le nom de registre de cet opérande. Pour faire le lien entre entrée et nom de registre, la recherche directe par étiquette ajoute une table de correspondances matérielle, une mémoire RAM qui mémorise les adresses des champs « opérande » des entrées. Les adresses envoyées dans cette mémoire sont les noms de registres des résultats. Lors de l'émission, la table de correspondances est mise à jour. Les numéros des champs « opérande » réservés lors de l'émission sont mémorisés dans les mots mémoire qui correspondent aux deux registres sources. Toutefois, une petite vérification est faite lors de l'émission : s'il y a déjà une correspondance dans la table pour un registre source, alors une autre instruction compte lire ce registre. Pour éviter d'écraser les données de l'instruction précédente dans la table de correspondances, l'émission de l'instruction est bloquée. [[File:Recherche directe par étiquette.png|centre|vignette|upright=2|Recherche directe par étiquette.]] ==Les ''schedulers'' avec préplanification== Avec la '''préplanification''' (''prescheduling''), le ''scheduler'' est composée de mémoires FIFO dans lesquelles les instructions sont triées dans l'ordre d'émission. Il n'y a pas de logique d’émission proprement dite, celle-ci se bornant à vérifier si l'instruction située au début de la FIFO peut s’exécuter. Par contre, le préplanificateur détecte les dépendances et en déduit où insérer les instructions dans le tampon d'émission, à l'endroit le plus adéquat. [[File:Préplanification.jpg|centre|vignette|upright=2|Préplanification.]] ===L'usage de FIFO multiples=== La technique de préplanification la plus simple utilise plusieurs FIFO. Quand une instruction a une dépendance avec une autre instruction, les deux sont placées dans la même FIFO. Pour cela, le préplanificateur détecte les chaines d'instructions dépendantes, et place les instructions dans la FIFO adéquate. A chaque cycle, l'unité d'émission lit une micro-opération dans chaque FIFO et vérifie si elle peut l'émettre. Si la micro-opération n'a pas ses opérandes disponibles, ou qu'une dépendance structurelle survient, alors la FIFO est bloquée. La micro-opération attend que la dépendance soit résolue, bloquant toutes les instructions précédentes. Mais les autres FIFO ne sont pas bloquées, laissant de la marge de manœuvre. [[File:Préplanification par FIFO multiples.png|centre|vignette|upright=1.5|Préplanification par FIFO multiples.]] ===La technique du tampon trié=== La technique du '''tampon trié''' trie les instructions selon le temps d'attente avant leur exécution. Les instructions qui sont censées s’exécuter bientôt sont insérées au tout début de la FIFO, tandis que les instructions qui s’exécuteront dans un long moment sont insérées vers la fin. Là encore, l'unité d'émission lit une micro-opération dans la FIFO, et détermine si elle peut être émise. Si une dépendance survient, l'émission est retardée, et la FIFO est bloquée. [[File:Préplanification par tampon trié.png|centre|vignette|upright=1.5|Préplanification par tampon trié.]] La technique a cependant quelques problèmes assez importants. Le premier problème est que la FIFO est bloquée lorsqu'une micro-opération ne peut être émise. Le second problème est que le temps avant exécution n'est pas toujours connu, notamment pour les instructions d'accès mémoire. Et cela se répercute sur les instructions dépendantes de celles-ci. Pour résoudre ce genre de problèmes, l'usage d'un pipeline à ''replay'' est possible, et est même l'une des meilleures solutions possible, malgré ses défauts. L'idée est que les lectures sont pré-planifiées en supposant qu'elles font un succès de cache L1. Si la prédiction est fausse, la lecture est ré-exécutée plusieurs cycles plus tard, en supposant qu'elle fait un succès dans le cache L2, et ainsi de suite. Elle est alors ré-insérée dans la FIFO, elle est pré-planifiée une seconde fois. Il en est de même si une micro-opération ne peut pas être émise : il suffit de la réinsérer dans la FIFO au bon endroit, en attendant que ses dépendances soient résolues. Ainsi, l'instruction fautive ne bloque pas le ''scheduler'', et retente sa chance autant de fois qu'il le faut. [[File:Préplanification par fenêtre d’instruction scorebarodée.png|centre|vignette|upright=1.5|Préplanification par ''scheduler'' scorebarodé.]] Une autre solution utilise deux ''schedulers'' : une FIFO gérée par la préplanification, et une vraie ''scheduler'' pour les instructions dont le temps d'attente ne peut pas être déterminé. Il est possible de mettre cette dernière avant la préplanification, afin de gérer les temps d'attente des instructions d'accès mémoire. Quand le temps d'attente d'une lecture devient connu, ses instructions dépendantes sont gérées avec préplanification. [[File:Préplanification avec fenêtre d’instruction.png|centre|vignette|upright=2.5|Préplanification avec ''scheduler''.]] ===Les ''scheduler'' avec allocation temporelle statique=== L''''allocation temporelle statique''' correspond à une technique utilisée sur les processeurs Cuzco de l'entreprise Condor. La technique en question a été présenté en 2025, mais des idées similaires ont été présentées dans la littérature académique. Elle ressemble beaucoup aux techniques de pré-planification, avec cependant quelques différences. L'idée est simple : le processeur dispose de plusieurs ''scheduler'', qui mettent en attente les micro-opérations. Lors de l'étape de renommage de registres, le processeur détermine dans combien de cycles d'horloge la micro-opération sera prête pour exécution. La micro-opération est alors mise en attente durant ce nombre de cycles, dans les ''scheduler'', puis est émise une fois ce nombre de cycles écoulés. Ce faisant, les ''scheduler'' n'ont pas besoin de détecter la disponibilité des opérandes à chaque cycle, pour chaque micro-opération en attente. Le ''timing'' de l'émission des micro-opérations est décidé à l'avance. L'implémentation exacte n'est pas connue, mais plusieurs solutions sont imaginables. Par exemple, la ''scheduler'' peut simplement être composée de plusieurs mémoires de petite taille, chacune contenant les micro-opérations destinées à être exécutées dans N cycles, N étant différent pour chaque mémoire. Une autre solution, plus réaliste, utilise un ''scheduler'' dans laquelle la micro-opération est couplée à des champs pour les opérandes, et un champ compteur. Le champ compteur est initialisé avec le nombre de cycles à attendre, et est décrémenté à chaque cycle d'horloge. Quand il atteint zéro, la micro-opération est émise. Vous remarquerez que la méthode ne marche que si toutes les micro-opérations prennent un nombre fixe de cycles d'horloge. Et autant c'est le cas pour les micro-opérations arithmétiques ou logiques, autant les accès mémoire ne rentrent pas dans ce cadre. En théorie, on ne sait pas combien de temps prendra un accès mémoire. Et cette incertitude se répercute sur les instructions dépendantes d'un accès mémoire. Pour éviter cela, le processeur réutilise un pipeline à ''replay'' tel que vu dans le chapitre précédent. L'unité de renommage de registre suppose que tout accès mémoire fait un succès de cache L1, et décide des ''timings'' d'émission sous cette hypothèse. Si une lecture subit un défaut de cache, elle est ré-exécutée, de même que toutes les instructions dépendantes. Pour cela, le registre de destination de la lecture est marqué comme invalide, grâce à un bit spécifique attaché au registre. Toute instruction qui lit un opérande invalide est elle aussi ré-executée de zéro. Pour simplifier, l'unité d'émission ressemble à une unité d'émission dans l'ordre, avec un registre de disponibilité, qu'on aurait amélioré pour aller au-delà de la simple détection des dépendances d'instruction. Pour déterminer les ''timings'' d'émission, à savoir quand émettre une micro-opération, le processeur utilise une unité d'émission à deux étages. Le premier étage est appelé le ''register scoreboard'', le second étage est appelé la ''Time Ressource Matrix''. Les deux étages communiquent entre eux, comme on va le voir, et leurs noms donnent une idée de ce qu'ils font. Le premier étage gère les dépendances de registres, le second gère les dépendances structurelles. Le premier étage est un registre de disponibilité amélioré, qui gère les dépendances de registre. Cet étage sait quand tel registre sera écrit, et donc que l'opérande écrit dedans sera disponible à partir de tel cycle d'horloge. Il le sait car l'étage suivant l'aura prévenu, mais laissons cela de côté pour le moment. Quand une micro-opération rentre dans cet étage, il vérifie les dépendances avec les registres et les micro-opérations antérieures. Vu qu'il sait quand les registres seront disponibles, il peut déterminer quand l'instruction pourra s'exécuter. Par exemple, si une micro-opération lit les deux registres R7 et R15, qui sont disponibles respectivement dans 5 et 7 cycles, le premier étage sait que la micro-opération devra attendre 7 cycles. Mais tout cela ne suffit pas à déterminer quand émettre une micro-opération. En effet, il fait aussi gérer les dépendances structurelles, ce qui est le boulot du second étage. Le second étage utilise pour cela une ''Time Ressource Matrix'', qui mémorise l'occupation de diverses "ressources", pour les 256 cycles d'horloge à venir. Les ressources en question sont les ports de lecture/écriture du banc de registre, les ALUs utilisées, si la micro-opération utilise l'unité mémoire, etc. Le second étage prend en entrée une micro-opération, détermine quelles "ressources" elle utilise, puis regarde leur disponibilité. Elle détecte alors les dépendances structurelles et détermine alors quand peut s'exécuter la micro-opération. Elle peut retarder l'émission de quelques cycles, si une dépendance structurelle est détectée. Une fois sortie du second étage, on sait quand la micro-opération va être émise, à quel cycle précisément. Et vu que la durée de l'instruction est fixe, on sait quand cette micro-opération va se terminer, quand son résultat sera disponible. Cela permet de mettre à jour la ''Time Ressource Matrix'', pour préciser que le port d'écriture sera occupé à tel moment. De plus, cette information est transmise au premier étage, qui sait alors quand est enregistré le résultat dans le registre de destination. C'est comme cela que le premier étage sait quand un registre est disponible : le second étage le prévient, quand il émet une instruction ! La ''Time Ressource Matrix''mémorise l'occupation des "ressources" pour les 256 cycles d'horloge à venir. Cependant, elle ne vérifie pas les dépendances pour les 256 cycles suivants. Quand elle reçoit une micro-opération, elle teste les dépendances structurelles pour seulement les 8 prochains cycles maximum. Si la micro-opération ne peut pas être émise pendant ces 8 cycles, le pipeline est bloqué, un ''pipeline stall'' est émis. Pour être plus précis, vu que le processeur peut décoder 8 micro-opérations en même temps, cela permet de ne consulter que 64 cycles d'horloge sur les 256. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les premiers processeurs Intel | prevText=Les premiers processeurs Intel | next=Le renommage de registres | nextText=Le renommage de registres }} </noinclude> owwsyu7nx2vn4omnagdquiqy1m9kau3 773628 773627 2026-09-29T21:04:55Z Mewtow 31375 /* La logique de sélection : âge ou position ? */ 773628 wikitext text/x-wiki Dans les chapitres précédents, nous avons parlé des techniques dites d''''émission dans l'ordre'''. L'idée est d’exécuter une nouvelle micro-opération à chaque cycle, dans des unités de calcul séparées. Les instructions sont émises consécutivement, mais les instructions s’exécutent en parallèle dans des unités de calcul séparées. Par contre, quand l'unité d'émission ne peut pas émettre une instruction, elle bloque tout le pipeline. Les instructions qui suivent sont elles aussi bloquées, elles doivent attendre leur tour, même si elles sont en capacité de s'exécuter. Les techniques d'exécution dans le désordre que nous allons voir dans ce chapitre corrigent ce point précis. Elles sont dites à '''émission dans le désordre'''. Elles se distinguent des précédentes sur un point précis : quand l'unité d'émission bloque l'émission d'une instruction, les instructions suivantes peuvent poursuivre. L'émission des instructions peut donc se faire dans le désordre, dans le sens où une instruction peut être émise alors qu'une instruction précédente ne l'est pas encore. Mais avant de poursuivre, quelques point niveaux terminologie : * L'émission dans le désordre est un terme parlant et assez précis. Malheureusement, la terminologie la plus utilisée par d''''exécution dans le désordre'''. Et nous utiliserons ce terme dans la suite du cours, histoire de ne pas trop dévier de la nomenclature habituelle. * Nous utiliserons parfois l'abréviation OOO pour parler d'exécution dans le désordre. L'abréviation est celle de ''Out Of Order Excution''. * Nous utiliserons aussi l'abréviation ''µop'' pour parler de micro-opération, ''µops'' au pluriel pour parler de plusieurs micro-opérations, ou des micro-opérations en général. L'exécution dans le désordre ne gère en effet que des µops, elle se situe après l'étape de décodage. Pour décrire comment est implémentée l'émission dans le désordre, il faut commencer par parler des processeurs sans. Les processeurs sans exécution dans le désordre ont une unité d'émission qui bloque tout le pipeline dès qu'une µop ne peut pas être émise. Pour limiter l'impact de ce blocage, quelques rares processeurs incorporent une '''file de micro-opération''', une mémoire FIFO qui met en attente les µops. Vu que c'est une mémoire FIFO, les µops sont émises dans l'ordre, à savoir l'ordre d'ajout, dans l'ordre de décodage. Le schéma ci-dessous illustre une telle file d'attente couplée à un ''scoreboard''. L'exécution dans le désordre améliore la file de µops sur un point : ce n'est plus une mémoire FIFO. Les µops sont insérées dans l'ordre, mais peuvent sortir dans le désordre (être émises dans le désordre). La file de µops devient alors un '''''scheduler''''', terme anglais que je ne compte pas traduire. Un terme équivalent est '''''scheduler''''', terme traduit directement de l'anglais ''instruction Window''. Terme assez trompeur, car elles mettent en attente des µops, pas des instructions. [[File:Différence file µops et fenêtres instruction.png|centre|vignette|upright=2|Différence file µops et ''schedulers'' ]] Le ''scheduler'' émet une µop dès que ses opérandes sont disponibles. Par disponible, on veut dire présent soit dans le réseau de contournement, soit dans les registres. Le ''scheduler'' détecte automatiquement quand les opérandes d'une µop sont disponibles, grâce à une unité d'émission intégrée. L'unité d'émission et le ''scheduler'' sont fusionnés ensemble, dans un seul circuit, mais nous allons dire qu'ils sont conceptuellement séparés pour le moment. A chaque cycle, l'unité d'émission consulte les µops en attente pour détecter lesquelles peuvent s'exécuter. Le ''scheduler'' est spécialement être conçue pour, c'est une sorte de mémoire associative très complexe, comme on le verra dans ce qui suit. [[File:OOO Issue.png|centre|vignette|upright=2.5|Exécution dans le désordre avec un ''scheduler'']] Une fois qu'une µop sort du décodeur d'instructions, elle est ajoutée en parallèle dans la ''scheduler'' et le ROB. La raison est que les µops quittent la ''scheduler'' dans le désordre, et qu'elles doivent être remises en ordre par la suite. Le ROB s'occupe de cette remise en ordre, mais il a besoin de savoir dans quel ordre les µops sont censées être, et cet ordre est celui du décodage. Aussi, pour remplir le ROB, la seule opportunité est en sortie de l'unité de décodage. Dans le cas où une instruction est décodée en plusieurs micro-opérations, elles sont toutes insérées en même temps dans la ''scheduler'' et le ROB, en tenant compte de leur ordre. L'implémentation la plus simple de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Les µops décodées sont accumulées dans le ''scheduler'', où elles attendent leur tour. La ''scheduler'' sert donc de file d'attente. Avant de poursuivre, précisons que les micro-opérations mémoire sont à part des autres, pour diverses raisons. Une de ces raisons est que les dépendances de données sont classées en deux types : les dépendances de registre et les dépendances d'adresse. Et les deux sont fondamentalement différentes. Autant on peut détecter les dépendances de registre lors de l'émission, autant c'est plus compliqué avec les dépendances d'adresse. De plus, rappelons que si les lectures peuvent s'exécuter dans le désordre, les écritures doivent s'exécuter dans l'ordre, ou du moins en donner l'illusion. Pour cela, le processeur remet les écritures dans l'ordre avec une sorte de mini-ROB intégré à l'unité mémoire, appelée la file d'écriture. Elle complémente le ROB, qui lui ne gère que les écritures dans les registres, mais les deux collaborent. La file d'écriture envoie une écriture à la mémoire RAM quand le ROB lui dit que c'est bon, les instructions précédentes sont terminées ''dans l'ordre du programme''. Les processeurs modernes ajoutent des techniques d'exécution dans le désordre des accès mémoire, mais nous les verrons dans un chapitre dédié. Elles permettent d'utiliser un ''scheduler'' unique, qui mémorise aussi les µops mémoire. Si elles sont mises en place, l'unité mémoire n'a pas besoin de file de µops séparée. L'idée est que les dépendances de registre sont traitées par la ''scheduler'', mais que l'unité mémoire gére les dépendances d'adresse. Les dépendances d'adresse sont gérées par des techniques de ''désambiguation mémoire'', qui auront droit à un chapitre dédié. [[File:Processeur avec exécution dans le désodre des accès mémoire.png|centre|vignette|upright=2|Processeur avec exécution dans le désodre des accès mémoire]] Les processeurs assez anciens n'autorisaient pas d'exécution dans le désordre des accès mémoire. Concrétement, les accs mémoire devaient se faire dans l'ordre, mais les autres µops pouvaient être exécutées dans le désordre. Il s'agit donc d'un ordre entre µops mémoire, pas entre µops mémoire et autres µops. Les µops entières et flottantes pouvaient être exécutées avant une µops mémoire qui est avant elle dans l'ordre du programme, ce n'est pas un problème. Pour garantir l'ordre des µops mémoire, l'unité mémoire est précédée par une file de micro-opérations séparée, pour forcer l'exécution dans l'ordre des accès mémoire. De plus, les µops mémoire ne peuvent pas utiliser la ''scheduler''. Dit autrement, la ''scheduler'' ne mémorise pas de µops mémoire. Après le décodage, les µops sont réparties soit dans la file de µops mémoire, soit dans la ''scheduler''. Le décodeur classe les µops suivant que ce sont des µops mémoire ou non, et les envoient à la bonne destination. Dans ce chapitre, on supposera que c'est cette solution qui est utilisée. [[File:Processeur avec émission dans l'ordre des accès mémoire.png|centre|vignette|upright=2|Processeur avec émission dans l'ordre des accès mémoire]] ==L'implémentation d'un ''scheduler'' : généralités== Un ''scheduler'' est une mémoire qui mémorise des micro-opérations. Elle est cependant plus complexe qu'une mémoire RAM ou qu'une FIFO et ressemble un petit peu à une mémoire cache. Elle dispose d'un port d'écriture et d'un port de lecture, au minimum. Le port d'écriture permet à l'unité de décodage d'insérer une micro-opération dedans, d'ajouter la micro-opération qui vient d'être décodée. Si une instruction machine est décodée en plusieurs micro-opération, deux possibilités. La première est de les insérer un par un, ce qui fait qu'on peut se contenter d'un seul port d'écriture. L'autre possibilité est de les ajouter en même temps, ce qui demande plusieurs ports d'écriture. Le port de lecture sert à émettre une instruction. On part du principe que la ''scheduler'' ne peut émettre qu'une seule instruction à la fois, car les processeurs que nous avons vu précédemment sont de ce type. Mais nous verrons dans quelques chapitres qu'il existe des processeurs dits superscalaires, qui sont capables d'émettre plusieurs instructions par cycle. Dans ce cas, la ''scheduler'' a un seul port de lecture. Un processeur superscalaire, quant à lui, doit avoir un port de lecture par unité de calcul, ce qui fait beaucoup plus. Les ''schedulers'' sont composées d''''entrées''', des mots mémoire qui stockent une instruction. Une instruction réserve une entrée après son décodage et la libère dès qu'elle est envoyée aux unités de calcul. Une entrée contient l'opcode (les signaux de commande à envoyer à l'ALU), le registre de destination du résultat, les registres de chaque opérande, et éventuellement des signaux de commande en plus. De plus, chaque opérande est couplée à un bit de disponibilité, qui indique si elle est disponible. Quand un opérande est écrit dans les registres, le bit de présence correspondant est mis à jour. Enfin, chaque entrée possède un bit ''empty'' qui indique si elle est vide, cette information étant utile pour réserver des entrées. [[File:Entrée d'une station de réservation - sans les tags.png|centre|vignette|upright=3|Entrée d'un ''scheduler'']] ===Les stations de réservation=== Les '''stations de réservation''' sont des ''scheduler'' particulières, qui sont capables de mémoriser les opérandes des instructions. Les entrées des stations de réservation sont identiques à celle des autres ''scheduler'', si ce n'est que les opérandes de l'instruction sont enregistrés directement dans des champs séparés. Il y a deux champs, un par opérande, pour stocker l'opérande elle-même, lue depuis les registres ou obtenue via le réseau de contournement. Notons que les champs pour les opérandes viennent en plus des champs pour les noms de registres, encore que les deux peuvent être fusionnés si on veut optimiser le tout. [[File:Entrée d'une station de réservation.png|centre|vignette|upright=3|Entrée d'une station de réservation.]] Précisons que la terminologie n'est pas très fiable. Les termes "''scheduler''" et "station de réservation" ne regroupent pas du tout la même chose d'un papier de recherche à l'autre, d'un bouquin à l'autre, d'un chercheur à l'autre, d'un ingénieur à l'autre, d'un professeur à l'autre. Le terme initial vient pourtant de l'article original sur l'algorithme de Tomasulo, où il désignait un ''scheduler'' associée à une unité de calcul précise. Mais le terme a ensuite été réutilisé, ce qui fait que certains processeurs avec plusieurs unités de calcul sont décrits comme ayant une unique station de réservation. En bref : c'est le bazar ! Mais nous en reparlerons dans le chapitre sur le renommage de registres, car c'est la place idéale pour les aborder. Toujours est-il que j'ai fait le choix de confondre les concepts de ''scheduler'' et de station de réservation avec les concepts de '''lecture avant émission''' et de '''lecture après émission'''. La différence entre les deux est que les registres sont lus après émission avec un ''scheduler'', avant avec des stations de réservation. Dans le cas "avant émission", les opérandes sont mémorisés dans la station de réservation. Et cette différence a une influence sur le pipeline du processeur, le banc de registres et tout ce qui s'en suit. Un désavantage de la lecture avant émission est qu'il faut stocker les opérandes après lecture, ici dans les stations de réservation. Mais un avantage est que le banc de registre a besoin de moins de ports de lecture, car une bonne partie des opérandes sont fournies par le système de contournement. Nous verrons cela dans le détail dans le chapitre sur les processeurs superscalaires. [[File:Processeur avec plusieurs ''scheduler''.png|centre|vignette|upright=2.5|Lecture après émission.]] [[File:Read Before Issue.png|centre|vignette|upright=2.5|Lecture avant émission.]] ===La logique d'éveil et de sélection=== Dans le cas qui va suivre, on suppose que le processeur ne peut émettre qu'une instruction à la fois. Chaque cycle, une instruction est sélectionnée et est envoyée dans le chemin de données, soit à une ALU, soit à une unité d'accès mémoire. La sélection d'une instruction est effectuée par l'unité d'émission, qui est aussi appelée le '''''scheduler'''''. Elle gère la disponibilité des opérandes et la disponibilité des unités de calcul adéquate. Le choix de l'instruction émise doit être le plus pertinent possible, pour des raisons de performances. Pour le premier point, l'unité d'émission détermine quelles instructions sont candidates pour l'émission. Les ''instructions candidates'' sont celles dont tous les opérandes sont prêts. Le processeur contient un circuit qui détecte les instructions candidates : la '''logique d’éveil''' (''wake-up logic''). Une fois que la logique d'éveil a fait son travail, une instruction est choisie pour s’exécuter en fonction de la disponibilité des unités de calcul adéquates. Ce rôle est dévolu à un circuit qu'on appelle la '''logique de sélection''', ou ''select logic''. [[File:Fonctionnement complet de la logique d’émission.jpg|centre|vignette|upright=1.5|Fonctionnement complet de la logique d’émission.]] La logique de sélection doit gérer le fait que les unités de calcul du processeur ne sont pas toutes identiques. Déjà, un processeur a généralement des unités séparées pour les instructions entières et flottantes, des unités spécialisées dans les accès mémoire, parfois des unités spécialisées pour les branchements. Une instruction doit être attribuée à la bonne unité de calcul, on ne doit pas envoyer une instruction entière dans une unité de calcul flottante. De plus, parmi les unités de calcul entières, toutes ne sont pas identiques. Par exemple, il est fréquent d'avoir plusieurs unités de calcul spécialisées dans les opérations simples (additions, soustractions, opérations logiques) avec une unité pour les multiplications/divisions séparées, parfois une unité spécialisée pour les décalages/rotations, etc. Là encore, allouer la bonne instruction à la bonne ALU est complexe. Plus les unités de calcul sont hétérogènes, plus la logique de sélection est compliquée. Les logiques d'éveil comme de sélection sont assez complexes. Comme on le verra plus bas, la logique de sélection la plus simple, qui gère une seule unité de calcul, est basée sur un encodeur à priorité couplé à d'autres circuits. Et pour gérer plusieurs ALUs, il faut mettre des encodeurs en cascade. Le résultat est que même en prenant une logique de sélection simple, elle sera assez lente et gourmande en circuits. Aussi, la logique de sélection met souvent un cycle d'horloge entier pour faire son travail, elle a son propre étage de pipeline attribué. La logique d'éveil est dans le même cas, ce qui fait qu'émettre une micro-opération demande deux cycles d'horloge. Le défaut est que cela rajoute des cycles d'horloges entre la ''scheduler'' et l'ALU, ce qui complique la gestion du pipeline. Ces cycles de retard sont à prendre en compte au moment d'émettre les instructions, les ''scheduler'' doit en tenir compte pour des performances optimales. Sans tenir compte de ces cycles de retard, les instructions arrivent en retard de quelques cycles à l'ALU, cycles de retard durant lesquels l'ALU n'a pas fait de calcul et a été sous-utilisée, sans compter que le système de contournement n'est pas utilisé au mieux. Et le problème est encore plus important sur les processeurs avec des stations de réservation, qui utilisent la "lecture après émission" : cela rajoute un cycle d'horloge en plus, un temps de retard en plus. ===La logique d'éveil : l'émission anticipée=== La logique d'éveil doit tenir compte du fait qu'il y a plusieurs étages entre l'émission et l'exécution sur une unité de calcul. Par exemple, un processeur a souvent entre un et à cinq étages entre la file d'attente et les unités de calcul. Il faut lire les registres, gérer le contournement, et cela peut prendre quelques cycles d'horloge. Sur le Pentium 4, on trouve 6 étages entre le ''scheduler'' et l'entrée de l'ALU. Si les micro-opérations sont émises quand les opérandes sont disponibles, il y aura un délai de quelques cycles avant qu'elles atteignent l'ALU. Alors qu'idéalement, on souhaiterait que la micro-opération atteigne l'ALU dès que ses opérandes sont disponibles, pour profiter des techniques de contournement. Pour cela, la logique d'éveil émet les instructions quelques cycles en avance pour qu'elles arrivent au bon moment. Il s'agit d'une technique d''''émission anticipée''', dont nous avions parlé dans le chapitre sur le contournement. : Il faut noter que le problème se pose plus avec des ''scheduler'' qu'avec des stations de réservation. Les premières ont un étage en plus entre émission et ALU, vu qu'il faut lire des registres après l'émission. L'émission anticipée demande d'émettre un signal d'éveil en avance de quelques cycles, pile au bon moment. Par exemples, si on a deux étages entre l'ALU et l'unité d'émission, le signal de réveil sera généré deux cycles avant que le résultat soit effectivement calculé. L'implémentation varie, mais deux solutions sont possibles. La première est de générer le signal d'éveil dans l'ALU, ce qui n'a de sens que pour les opérations comme les multiplications ou les divisions, qui prennent plusieurs cycles. Une autre technique génère le signal de réveil dans une structure centralisée, spécialisée dans la génération des signaux d'éveil. L'unité de composée d'un registre à décalage par registre. Imaginons qu'une instruction est émise, que cette instruction mette N cycles à s'exécuter, et qu'elle écrive dans un registre de destination. L'unité sélectionne alors le registre à décalage associé au registre de destination, et met le bit numéro N à 1. Le registre décalé d'un cran à chaque cycle. Quand le bit sortant est un 1, alors le signal de validité pour l'opérande est généré. L'émission anticipée marche bien si l'instruction a une durée fixe, connue à l'avance. Et autant c'est le cas pour les instructions arithmétiques et logiques, autant ce n'est pas le cas pour les accès mémoire. Les accès mémoire ont une latence variable : quelques cycles pour un succès de cache, plusieurs dizaines de cycles pour un défaut de cache L1, pas loin de la centaine pour un défaut de cache L2, etc. Et cela pose des problèmes pour l'émission anticipée. L'émission en avance pour les accès mémoire est purement spéculative : le processeur émet des instructions en supposant que la lecture entrainera un succès de cache, quitte à annuler l'instruction en cas de défaut de cache. Mais faire ainsi demande non seulement d'annuler les instructions émises en avance, mais aussi de ne pas retirer les instructions émises en avance de la ''scheduler''. Elles sont émises, mais une copie de sauvegarde est conservée dans la ''scheduler''. Si le processeur détecte un défaut de cache, il peut alors ré-exécuter l'instruction. S'il détecte un succès de cache, les instructions lecture-dépendante sont retirées de la ''scheduler'', la copie de sauvegarde est devenue inutile et est donc jetée. ===La logique de sélection : âge ou position ?=== La logique de sélection est primordiale pour de bonnes performances. Il existe deux méthodes principales pour sélectionner l'instruction à exécuter. La première est la plus simple : elle se base sur lé numéro de l'entrée. En effet, un ''scheduler'' est avant tout une sorte de mémoire, un mix entre mémoire associative, mémoire RAM, et FIFO. Et chaque entrée a un numéro, une adresse mémoire. Nous parlerons de numéro dans ce qui suit, car ce sera plus simple, le terme d'adresse mémoire étant peut-être un peu exagéré dans le contexte des ''scheduler''. Toujours est-il que la ''scheduler'' est adressable dans le sens où on peut lui envoyer le numéro de l'entrée voulue, et le ''scheduler'' renvoie le contenu de l'entrée sur son port de lecture. Et c'est ce que fait la logique de sélection : elle génère le numéro de l'entrée à lire. Le numéro est alors envoyé sur l'entrée d'adresse du ''scheduler'', et elle fournit la micro-opération associée sur son port de lecture, son '''port d'émission'''. La première méthode de sélection, donc. Elle est basée sur le numéro de l'entrée. Si plusieurs entrées sont éveillées, la logique de sélection prend celle avec le plus petit numéro. Elle porte le nom de '''sélection par position''', sous-entendu position dans la ''scheduler''. Vous l'avez peut-être deviné, mais la logique de sélection est alors un encodeur à priorité. Le circuit de sélection ne se résume donc pas seulement à un encodeur à priorité, mais c'est le circuit central. L'avantage d'une telle méthode de sélection est qu'elle est simple à implémenter : un encodeur à priorité est un circuit connu, facile à implémenter. Mais on remarque un défaut : un encodeur est un circuit assez rapide, mais qui utilise beaucoup de transistors, beaucoup de portes logiques, surtout si on veut qu'il soit rapide. Ce qui explique que la logique de sélection ait son propre étage de pipeline rien que pour elle. La seconde méthode s'appelle la '''sélection par âge''', au nom assez transparent. L'idée est de privilégier l'émission de l'instruction la plus ancienne. Elle demande que la ''scheduler'' trie les micro-opérations par ordre d'insertion dans la ''scheduler'', ce qui en fait une pseudo-FIFO. Le tri est partiel, car les instructions peuvent sortir du ''scheduler'' à tout moment. Compacter le ''scheduler'', à savoir regrouper toutes les entrées valides est une idée, mais elle est compliquée à implémenter. Aussi, elles préfèrent encoder des informations sur l'ordre d'émission dans chaque entrée. L'encodeur à priorité doit alors travailler non pas sur des nombres entiers liés à l'ordre d'insertion dans la pseudo-FIFO. Elle est encore plus gourmande en circuits que la méthode précédente. Les processeurs haute performance utilisent souvent des méthodes hybrides. Par exemple, les processeurs AMD de microarchitecture Bulldozer utilisaient une méthode intermédiaire. Ils utilisaient un ''scheduler'' couplée à un encodeur à priorité pour la sélection par position, mais complémentaient le tout avec une unité qui mémorisait l'instruction la plus ancienne dans le ''scheduler''. Le mécanisme de sélection par âge était utilisé en priorité. Mais si l'instruction la plus ancienne n'était pas prête, le processeur basculait sur le mécanisme de sélection par position. ===La compaction des ''scheduler''=== À chaque cycle, les instructions décodées sont ajoutées dans la ''scheduler'', dans des entrées vides. Vu que les instructions quittent celle-ci dans le désordre, ces vides sont dispersés dans la ''scheduler'', ce qui pose problème pour déterminer où placer les nouvelles instructions. La solution la plus triviale consiste à conserver une liste des vides, mise à jour à chaque insertion ou émission d'instruction. Une autre solution consiste à éliminer les vides en compactant la ''scheduler'' à chaque cycle d'horloge. Des circuits se chargent de détecter les vides et de regrouper les instructions en un unique bloc. Il faut signaler que certains processeurs arrivent à se passer de cette étape de compactage, mais au prix de ''scheduler'' nettement plus complexes. Autre problème : quand il faut choisir quelle instruction émettre, il y a toujours plusieurs candidats. Si on choisit mal, des instructions restent en attente trop longtemps parce que d'autres instructions plus jeunes leur passent devant. Pour éviter cela, les instructions les plus vielles, les plus anciennes, sont prioritaires. Pour cela, on peut utiliser une FIFO un peu spéciale pour la ''scheduler''. Si les ajouts d'instruction se font dans l'ordre, les instructions ne quittent pas forcément la ''scheduler'' dans l'ordre imposé par une FIFO : les instructions restent triées dans leur ordre d'ajout, même s'il y a des vides entre elles. Dans ces conditions, il est préférable que le compactage conserve l'ordre FIFO des instructions. Dans ces conditions, l'instruction la plus ancienne est celle qui est située à l'adresse la plus faible : le circuit de sélection peut donc être fabriqué avec des encodeurs, et est relativement simple. ==Les ''schedulers'' basées sur une matrice de dépendances== L'implémentation la plus simple étend le fonctionnement d'un pipeline dynamique usuel. Rappelez-vous le chapitre sur les pipelines dynamiques. Nous avions vu que de tels pipelines émettaient une instruction par cycle, quitte à émettre des bulles de pipeline en cas de dépendance bloquante. Et il est possible d'améliorer leur unité d'émission pour qu'elle soit compatible avec l'exécution dans le désordre. ===Rappels sur le registre de réservation/disponibilité=== L'émission d'une instruction est gouvernée par un ''registre de réservation'' qui indique quels registres sont réservés par une instruction, et ceux qui sont libres. Un registre réservé est un registre qui sera écrit par une instruction en cours d'exécution, mais qui n'a pas encore écrit son résultat. Les instructions candidates doivent avoir leurs opérandes dans des registres libres. Sinon, c'est signe que leurs opérandes sont réservés en écriture, donc pas encore écrites, donc pas disponibles. Si une instruction candidate veut lire ce registre, c'est signe qu'il y a une dépendance RAW : elle veut lire un registre réservé, qui est destiné à être écrit par une instruction en vol. Si elle veut écrire, c'est signe qu'elle veut écrire dans un registre où une autre instruction veut écrire : c'est une dépendance WAW. Dans les deux cas, l'instruction n'est pas émise. Le registre de réservation encode les registres réservés comme suit : chaque bit est associé à un registre. Le bit numéro 0 est associé au registre numéro 0, le bit numéro 1 au registre numéro 1, etc. Là, En clair, les numéros de registres réservés sont encodés en représentation non pas binaire, mais en représentation ''one-hot'' (vue au premier chapitre). {|class="wikitable" |+ Registre de réservation |- ! Registre 7 !! Registre 6 !! Registre 5 !! Registre 4 !! Registre 3 !! Registre 2 !! Registre 1 !! Registre 0 |- | 0 || 0 || 1 || 0 || 0 || 1 || 0 || 0 |} Avant d'émettre une instruction, l'unité d'émission extrait les registres opérande/destination et les convertis dans la même représentation que le registre de réservation, à savoir en représentation ''one-hot''. Le circuit de traduction binaire vers ''one-hot'' est, pour rappel, un simple décodeur. Puis, on fait un OU logique entre les sorties des décodeurs. Le résultat est un masque qui indique quels registres sont lus par l'instruction, encodé en représentation ''one-hot''. Appelons-le le '''masque d'opérandes'''. Le masque est alors comparé au registre de réservation pour vérifier si l'instruction peut être émise. [[File:Unité d'émission simple, dans l'ordre.png|centre|vignette|upright=2|Unité d'émission simple, dans l'ordre]] Si l'émission est autorisée, le registre de réservation est là aussi mis à jour. Le registre de réservation est aussi mis à jour dès qu'une instruction enregistre son résultat dans les registres, ou alors dès qu'il est disponible pour le contournement. Le bit associé au registre repasse alors à 0 (ou à 1). Sans contournement, la mise à jour se fait alors à la toute fin de l'instruction, quand elle se termine, lors de la dernière étape d'enregistrement, à la fin de son pipeline. Avec, elle se fait quand l'instruction quitte l'unité de calcul. ===L'extension à l'exécution dans le désordre : l'éveil par matrice de bits=== La différence entre un pipeline dynamique et l'exécution dans le désordre est que l'on passe d'une instruction à émettre à plusieurs. Plusieurs instructions sont mises en attente dans un ''scheduler'', et y attendent leur tour. L'idée est alors d'envoyer le registre de disponibilité à toutes les entrées, à toutes les instructions en attente. Ainsi, on sait quelles sont les instructions qui peuvent s'exécuter et celles qui ne le peuvent pas. L'implémentation est assez simple, elle ressemble beaucoup à l'implémentation d'un pipeline dynamique simple, si ce n'est que des circuits sont dupliqués. L'implémentation utilise des ''scheduler'' légèrement différentes de celles introduites plus haut. Elles n'utilisent notamment pas de bits de disponibilité, mais autre chose. Lorsqu'une instruction est ajoutée à la ''scheduler'', le masque de disponibilité des opérandes est stocké dans la ''scheduler''. A chaque cycle, le registre de disponibilité est envoyé à toutes les entrées, et est comparé avec tous les masques de disponibilité des opérandes. Si une comparaison renvoie un 1, alors l'instruction de l'entrée est une instruction candidate à l'émission. [[File:Unité d'émission dans le désordre basée sur un registre de disponibilité.png|centre|vignette|upright=2.5|Unité d'émission dans le désordre basée sur un registre de disponibilité]] L'ensemble est implémenté avec l'aide d'une '''matrice de bits''', où chaque ligne correspond à une entrée et chaque colonne à un registre. À chaque croisement entre une ligne et une colonne, on trouve un bit. Si le bit de la ligne n et de la colonne m est à 1, cela veut dire : l'instruction dans l'entrée n a besoin de lire le registre m. S’il est à 0, alors cela veut dire que l'instruction stockée dans la ligne n'a pas besoin de la donnée dans le registre m. [[File:Planificateur à matrice de bits.jpg|centre|vignette|upright=2|Planificateur à matrice de bits.]] Lorsqu'une instruction réserve une entrée, elle initialise la ligne en fonction des registres qu'elle souhaite lire. Pour vérifier si une instruction a ses opérandes prêts, le processeur compare le registre de disponibilité à la ligne associée à l'instruction/entrée. A chaque intersection ligne-colonne, se trouve un comparateur de 1 bit, qui détecte si le registre est demandé et disponible. Les résultats de cette porte sont ensuite envoyés à une porte ET, qui fait le gros du travail. [[File:Logique de détection de la disponibilité d'une instruction.jpg|centre|vignette|upright=2|Logique de détection de la disponibilité d'une instruction.]] ==Les ''scheduler'' basées sur une mémoire associative== Les processeurs modernes utilisent une mémoire associative pour la ''scheduler''. Les mémoires associatives ont été abordées il y a quelques chapitres, mais faisons quelques rappels. Les mémoires associatives servent à accélérer la recherche de données dans un ensemble. Or, un ''scheduler'' vérifie régulièrement si chaque entrée est prête. Il s'agit d'un processus de recherche d'une instruction qui respecte une condition bien précise dans la mémoire, ce qui fait que les mémoires associatives sont donc tout indiquées. Comme vous le savez, les signaux de commande d'une instruction sont propagés avec celle-ci dans le pipeline, le nom du registre de destination ne faisant pas exception. Le nom de registre est envoyé à la ''scheduler'' lors de l'écriture du résultat dans les registres. S'il y a correspondance, l'opérande est disponible et son bit de disponibilité est mis à 1. On peut adapter cette méthode pour tenir compte du contournement assez simplement. [[File:Détection des dépendances par propagation du registre de destination.png|centre|vignette|upright=2|Détection des dépendances par propagation du registre de destination.]] En conséquence, le circuit de détection des dépendances est constitué d'un grand nombre de comparateurs : un par champ « nom de registre » dans chaque entrée. La logique d'éveil/''wake up'' regroupe tous les comparateurs, la logique de sélection est un circuit situé en-dehors de la mémoire associative. Les entrées sont dans la mémoire associative elle-même. [[File:Gestion des bits de validité.png|centre|vignette|upright=2|Gestion des bits de validité.]] L'implémentation la plus simple est celle du schéma précédent, où on utilise une mémoire associative unique. Une version plus élaborée sépare la ''scheduler'' en deux parties : une mémoire qui mémorise les registres des opérandes, une autre mémoire pour le reste. La mémoire pour les registres opérandes est la mémoire associative proprement dite, c'est elle qui est associée aux comparateurs, à la logique de ''wake-up''/réveil, etc. Par contre, l'autre mémoire est une mémoire RAM simplifiée, qui mémorise les informations qui n'ont pas besoin des comparateurs. L'opcode de l'instruction est là-dedans, par exemple. La ''scheduler'' est donc une sorte de mémoire associative améliorée. Il se trouve que c'est aussi le cas du ROB. Et il est possible de fusionner le tampon de ré-ordonnancement avec la ''scheduler'' dans une structure unique. La différence avec un ''scheduler'' normal est que les entrées sont libérées non pas quand l'instruction est exécutée/émise, mais quand elle termine son exécution et quitte le ROB. La ''scheduler'' incorpore des bits dans chaque entrée, pour savoir si la µops associée a été émise et est en cours de traitement dans les ALUs. La méthode a notamment été utilisée sur les processeurs d'architecture K6 d'AMD. Le tout donnait une structure appelée le '''DRIS''' (''deferred scheduling register renaming instruction shelf''). Les processeurs PA 8000 de HP étaient aussi vraisemblabment dans ce cas, aussi. ===Les optimisations de la consommation d'énergie : la désactivation des portions inutilisées=== Le problème avec des ''scheduler'' de ce type est leur forte consommation énergétique, ainsi que le grand nombre de portes logiques utilisées, qui deviennent prohibitifs pour des ''scheduler'' un peu grosses. Pour résoudre ce problème, certains ont optimisé les comparateurs. D'autres ont tenté de profiter du fait que la majorité des bits dans les entrées sont composés de zéros. Bref, les optimisations purement matérielles sont légion. Une première solution est de désactiver les entrées qui sont inutilisées, vides, sans instruction. Pour cela, on fait précéder les comparateurs par un circuit qui les connecte ou déconnecte des lignes de bit. Le circuit est commandé par le bit ''empty'' qui indique si une entrée est vide ou non. L'avantage est que la consommation d'énergie de la ''scheduler'' devient alors proportionnelle au nombre d'entrées non-vides, et non au nombre d'entrées total. Du moins, en apparence, les entrées non-utilisées doivent quand même être alimentées pour fonctionner, mais l'activité de comparaison disparait dans les entrées vides. Il est possible d'étendre cette technique aux entrées dont les opérandes sont prêts. Les gains sont généralement assez bons, avec une réduction de consommation variant entre 30 et 50%, avec une implémentation très simple et très économe en circuits. Une autre solution, assez simple à mettre en place, consiste à désactiver une partie de la ''scheduler'' sin elle est inutilisée. Pour cela, il faut segmenter la ''scheduler'' avec la technique du ''wire partitionning''. Pour rappel, un ''scheduler'' est une mémoire associative. Et comme toute mémoire associative, elle contient des fils, les lignes de bit, qui relient les entrées/sorties à toutes les cellules mémoire. Plus une ligne de bit est longue, plus elle consomme d'énergie et plus le temps de lecture/écriture est long. L'idée est de segmenter les lignes de bits en plaçant des répéteurs qui recopient la tension d'un segment au suivant. Les répéteurs sont des tampons trois-états, ce qui permet de déconnecter les portions inutilisées de la ligne de bit. Ce faisant, la ''scheduler'' est découpée en segments, qui peuvent être désactivés si besoin. S'il y a peu d'instructions chargées dans la ''scheduler'', les portions inutilisées sont désactivées. La technique marche d'autan mieux si les instructions sont compactées au début de la ''scheduler''. [[File:Wire partitionning.png|centre|vignette|upright=2|Wire partitionning]] Tout le problème est de savoir quelles portions désactiver. La technique est assez simple si la ''scheduler'' est compactée, à savoir si toutes les instructions sont régulièrement regroupées au début de la mémoire CAM. Mais même avec cette optimisation, la décision de désactiver une portion de la ''scheduler'' n'est pas à prendre à la légère. Il ne faut pas désactiver une portion contenant des instructions pouvant être émise sous peu. La décision dépend de paramètres variés : proportion d'entrée vides, quantité d'entrées récemment activées/désactivées récemment, présences d'entrées avec un ''match'' d'opérandes récent, etc. Il est important de préciser que les techniques en question fonctionnent aussi sur les autres types de ''scheduler'', qui ne sont pas basées sur des mémoires associatives. Nous allons voir celles-ci dans la suite du chapitre, mais gardez à l'esprit que ces optimisations, à savoir désactiver les entrées vides/prêts et partitionner la ''scheduler'', sont des optimisations générales qui marchent avec presque tout. ===L'ajout d'une FIFO pour les instructions déjà prêtes à l'émission=== D'autres techniques permettent de réduire aussi bien le cout en circuits que la consommation d'énergie de la ''scheduler''. L'idée est d'utiliser une mémoire associative quand elle est réellement nécessaire, mais d'utiliser un ''scheduler'' "normale" dès que possible. La méthode la plus simple tient compte du fait que certaines µopsont déjà toutes leurs opérandes de disponibles à l'émission, mais doivent quand même être mises en attente, parce que l'ALU adéquate est occupée, parce que des dépendances WAW/WAR sont encore là, ou pour tout autre raison. Dans ce cas, elles sont mises en attente non pas dans la ''scheduler'', mais dans une mémoire FIFO toute simple. L'idée est qu'au lieu d'avoir une énorme mémoire associative pour la ''scheduler'', on déplace quelques entrées dans une petite FIFO annexe. Le résultat est un gain d'énergie et de circuits, au prix d'une perte de performance mineure. La perte de performance en question se manifeste si aucune instruction n'a ses opérandes de prêtes à l'émission : le programme n'utilise pas la FIFO et voit alors un ''scheduler'' plus petite. Une amélioration de cette technique tient compte du fait que certaines instructions sont dans un cas intermédiaire. Elles ont déjà un opérande de prête lors de l'émission, mais pas l'autre. Le nombre d'opérandes varie suivant l’instruction : certaines n'ont besoin que d'un seul opérande. De plus, il arrive qu'une opération tout juste décodée ait déjà un ou plusieurs de ses opérandes de prêts. Cette constatation permet d'éviter d'utiliser des comparateurs pour les opérandes déjà prêts. Par exemple, on peut parfaitement utiliser trois ''scheduler'' : * une pour les instructions dont tous les opérandes sont prêts, mais qui sont quand même mises en attente, sans comparateur ; * une pour les instructions dont un seul opérande manque, qui n'utilise qu'un comparateur par entrée ; * une pour les instructions dont deux opérandes manquent à l'appel, qui utilise deux comparateurs par entrée. C'est beaucoup plus économique que d'utiliser une seule grosse ''scheduler'' qui contiendrait autant d'entrées que les trois précédentes réunies, avec deux comparateurs par entrée. Certains sont même allés plus loin, et ont proposé de supprimer la ''scheduler'' avec deux opérandes par entrée. Les instructions dont deux opérandes sont inconnus au décodage sont stockées dans la ''scheduler'' pour instructions avec un comparateur par entrée. Un circuit de prédiction se charge alors de prédire l'opérande manquant, cette prédiction étant vérifiée plus loin dans le pipeline. Il serait cependant étonnant qu'une telle proposition ait donné lieu à la moindre implémentation réelle. ===Les optimisations de la consommation d'énergie avancées=== D'autres chercheurs ont conservé un ''scheduler'' unique, avec autant de comparateurs par entrée qu'il y a d'opérandes possibles par instruction. Simplement, le processus de détection des opérandes prêts est légèrement ralenti : on ne vérifie qu'un opérande par cycle. Pour vérifier les deux opérandes d'une entrée, on doit attendre deux cycles. Enfin, certains chercheurs ont proposé des ''scheduler'' segmentées. Les instructions circulent à chaque cycle d'un segment vers le suivant : en conséquence, certains segments conservent les instructions les plus anciennes, un autre les instructions les plus jeunes, etc. Seul le denier segment, celui qui contient les instructions les plus vielles, peut émettre une instruction : la détection des opérandes se fait seulement dans le dernier segment, qui contient les instructions les plus anciennes. On économise ainsi beaucoup de comparateurs. Certains chercheurs ont tenté de pipeliner l'étape de sélection des opérandes, ainsi que l'étage d'arbitrage. Mais en faisant cela, il faut plusieurs cycles pour détecter qu'une instruction a ses opérandes prêts, ce qui pose problème face à de nombreuses dépendances RAW. Pour éviter de trop perdre en performances, certains chercheurs ont décidé d'utiliser des techniques pour prédire quelles seront les instructions dont les opérandes seront bientôt prêts. Si détecter qu'une instruction est prête prend n cycles, le processeur devra tenter de prédire la future disponibilité des opérandes n cycles en avance pour obtenir des performances optimales. ===Remplacer la mémoire associative par une RAM=== Une autre optimisation possible est de remplacer la ''scheduler'' par une mémoire RAM, dont chaque mot mémoire correspondrait à une entrée. Une telle optimisation permet en théorie de se passer des comparateurs associés à chaque entrée, mais au prix de l'ajout de circuits annexes potentiellement couteux. La première de ces techniques, la '''recherche directe par étiquette''' (direct tag search) fut créée par Weiss et son collègue Smith. Ils cherchaient à améliorer l'algorithme de Tomasulo, un algorithme qu'on expliquera dans quelques chapitres. Rappelons que chaque instruction produit un résultat, qui devra être rapatrié dans une ou plusieurs entrées de la ''scheduler''. L'optimisation de la recherche directe par étiquette fonctionne dans le cas où le résultat de l'instruction n'est utilisé que par une seule entrée, et pas plusieurs. Le principe est simple : chaque champ « opérande » d'une entrée est adressable via le nom de registre de cet opérande. Pour faire le lien entre entrée et nom de registre, la recherche directe par étiquette ajoute une table de correspondances matérielle, une mémoire RAM qui mémorise les adresses des champs « opérande » des entrées. Les adresses envoyées dans cette mémoire sont les noms de registres des résultats. Lors de l'émission, la table de correspondances est mise à jour. Les numéros des champs « opérande » réservés lors de l'émission sont mémorisés dans les mots mémoire qui correspondent aux deux registres sources. Toutefois, une petite vérification est faite lors de l'émission : s'il y a déjà une correspondance dans la table pour un registre source, alors une autre instruction compte lire ce registre. Pour éviter d'écraser les données de l'instruction précédente dans la table de correspondances, l'émission de l'instruction est bloquée. [[File:Recherche directe par étiquette.png|centre|vignette|upright=2|Recherche directe par étiquette.]] ==Les ''schedulers'' avec préplanification== Avec la '''préplanification''' (''prescheduling''), le ''scheduler'' est composée de mémoires FIFO dans lesquelles les instructions sont triées dans l'ordre d'émission. Il n'y a pas de logique d’émission proprement dite, celle-ci se bornant à vérifier si l'instruction située au début de la FIFO peut s’exécuter. Par contre, le préplanificateur détecte les dépendances et en déduit où insérer les instructions dans le tampon d'émission, à l'endroit le plus adéquat. [[File:Préplanification.jpg|centre|vignette|upright=2|Préplanification.]] ===L'usage de FIFO multiples=== La technique de préplanification la plus simple utilise plusieurs FIFO. Quand une instruction a une dépendance avec une autre instruction, les deux sont placées dans la même FIFO. Pour cela, le préplanificateur détecte les chaines d'instructions dépendantes, et place les instructions dans la FIFO adéquate. A chaque cycle, l'unité d'émission lit une micro-opération dans chaque FIFO et vérifie si elle peut l'émettre. Si la micro-opération n'a pas ses opérandes disponibles, ou qu'une dépendance structurelle survient, alors la FIFO est bloquée. La micro-opération attend que la dépendance soit résolue, bloquant toutes les instructions précédentes. Mais les autres FIFO ne sont pas bloquées, laissant de la marge de manœuvre. [[File:Préplanification par FIFO multiples.png|centre|vignette|upright=1.5|Préplanification par FIFO multiples.]] ===La technique du tampon trié=== La technique du '''tampon trié''' trie les instructions selon le temps d'attente avant leur exécution. Les instructions qui sont censées s’exécuter bientôt sont insérées au tout début de la FIFO, tandis que les instructions qui s’exécuteront dans un long moment sont insérées vers la fin. Là encore, l'unité d'émission lit une micro-opération dans la FIFO, et détermine si elle peut être émise. Si une dépendance survient, l'émission est retardée, et la FIFO est bloquée. [[File:Préplanification par tampon trié.png|centre|vignette|upright=1.5|Préplanification par tampon trié.]] La technique a cependant quelques problèmes assez importants. Le premier problème est que la FIFO est bloquée lorsqu'une micro-opération ne peut être émise. Le second problème est que le temps avant exécution n'est pas toujours connu, notamment pour les instructions d'accès mémoire. Et cela se répercute sur les instructions dépendantes de celles-ci. Pour résoudre ce genre de problèmes, l'usage d'un pipeline à ''replay'' est possible, et est même l'une des meilleures solutions possible, malgré ses défauts. L'idée est que les lectures sont pré-planifiées en supposant qu'elles font un succès de cache L1. Si la prédiction est fausse, la lecture est ré-exécutée plusieurs cycles plus tard, en supposant qu'elle fait un succès dans le cache L2, et ainsi de suite. Elle est alors ré-insérée dans la FIFO, elle est pré-planifiée une seconde fois. Il en est de même si une micro-opération ne peut pas être émise : il suffit de la réinsérer dans la FIFO au bon endroit, en attendant que ses dépendances soient résolues. Ainsi, l'instruction fautive ne bloque pas le ''scheduler'', et retente sa chance autant de fois qu'il le faut. [[File:Préplanification par fenêtre d’instruction scorebarodée.png|centre|vignette|upright=1.5|Préplanification par ''scheduler'' scorebarodé.]] Une autre solution utilise deux ''schedulers'' : une FIFO gérée par la préplanification, et une vraie ''scheduler'' pour les instructions dont le temps d'attente ne peut pas être déterminé. Il est possible de mettre cette dernière avant la préplanification, afin de gérer les temps d'attente des instructions d'accès mémoire. Quand le temps d'attente d'une lecture devient connu, ses instructions dépendantes sont gérées avec préplanification. [[File:Préplanification avec fenêtre d’instruction.png|centre|vignette|upright=2.5|Préplanification avec ''scheduler''.]] ===Les ''scheduler'' avec allocation temporelle statique=== L''''allocation temporelle statique''' correspond à une technique utilisée sur les processeurs Cuzco de l'entreprise Condor. La technique en question a été présenté en 2025, mais des idées similaires ont été présentées dans la littérature académique. Elle ressemble beaucoup aux techniques de pré-planification, avec cependant quelques différences. L'idée est simple : le processeur dispose de plusieurs ''scheduler'', qui mettent en attente les micro-opérations. Lors de l'étape de renommage de registres, le processeur détermine dans combien de cycles d'horloge la micro-opération sera prête pour exécution. La micro-opération est alors mise en attente durant ce nombre de cycles, dans les ''scheduler'', puis est émise une fois ce nombre de cycles écoulés. Ce faisant, les ''scheduler'' n'ont pas besoin de détecter la disponibilité des opérandes à chaque cycle, pour chaque micro-opération en attente. Le ''timing'' de l'émission des micro-opérations est décidé à l'avance. L'implémentation exacte n'est pas connue, mais plusieurs solutions sont imaginables. Par exemple, la ''scheduler'' peut simplement être composée de plusieurs mémoires de petite taille, chacune contenant les micro-opérations destinées à être exécutées dans N cycles, N étant différent pour chaque mémoire. Une autre solution, plus réaliste, utilise un ''scheduler'' dans laquelle la micro-opération est couplée à des champs pour les opérandes, et un champ compteur. Le champ compteur est initialisé avec le nombre de cycles à attendre, et est décrémenté à chaque cycle d'horloge. Quand il atteint zéro, la micro-opération est émise. Vous remarquerez que la méthode ne marche que si toutes les micro-opérations prennent un nombre fixe de cycles d'horloge. Et autant c'est le cas pour les micro-opérations arithmétiques ou logiques, autant les accès mémoire ne rentrent pas dans ce cadre. En théorie, on ne sait pas combien de temps prendra un accès mémoire. Et cette incertitude se répercute sur les instructions dépendantes d'un accès mémoire. Pour éviter cela, le processeur réutilise un pipeline à ''replay'' tel que vu dans le chapitre précédent. L'unité de renommage de registre suppose que tout accès mémoire fait un succès de cache L1, et décide des ''timings'' d'émission sous cette hypothèse. Si une lecture subit un défaut de cache, elle est ré-exécutée, de même que toutes les instructions dépendantes. Pour cela, le registre de destination de la lecture est marqué comme invalide, grâce à un bit spécifique attaché au registre. Toute instruction qui lit un opérande invalide est elle aussi ré-executée de zéro. Pour simplifier, l'unité d'émission ressemble à une unité d'émission dans l'ordre, avec un registre de disponibilité, qu'on aurait amélioré pour aller au-delà de la simple détection des dépendances d'instruction. Pour déterminer les ''timings'' d'émission, à savoir quand émettre une micro-opération, le processeur utilise une unité d'émission à deux étages. Le premier étage est appelé le ''register scoreboard'', le second étage est appelé la ''Time Ressource Matrix''. Les deux étages communiquent entre eux, comme on va le voir, et leurs noms donnent une idée de ce qu'ils font. Le premier étage gère les dépendances de registres, le second gère les dépendances structurelles. Le premier étage est un registre de disponibilité amélioré, qui gère les dépendances de registre. Cet étage sait quand tel registre sera écrit, et donc que l'opérande écrit dedans sera disponible à partir de tel cycle d'horloge. Il le sait car l'étage suivant l'aura prévenu, mais laissons cela de côté pour le moment. Quand une micro-opération rentre dans cet étage, il vérifie les dépendances avec les registres et les micro-opérations antérieures. Vu qu'il sait quand les registres seront disponibles, il peut déterminer quand l'instruction pourra s'exécuter. Par exemple, si une micro-opération lit les deux registres R7 et R15, qui sont disponibles respectivement dans 5 et 7 cycles, le premier étage sait que la micro-opération devra attendre 7 cycles. Mais tout cela ne suffit pas à déterminer quand émettre une micro-opération. En effet, il fait aussi gérer les dépendances structurelles, ce qui est le boulot du second étage. Le second étage utilise pour cela une ''Time Ressource Matrix'', qui mémorise l'occupation de diverses "ressources", pour les 256 cycles d'horloge à venir. Les ressources en question sont les ports de lecture/écriture du banc de registre, les ALUs utilisées, si la micro-opération utilise l'unité mémoire, etc. Le second étage prend en entrée une micro-opération, détermine quelles "ressources" elle utilise, puis regarde leur disponibilité. Elle détecte alors les dépendances structurelles et détermine alors quand peut s'exécuter la micro-opération. Elle peut retarder l'émission de quelques cycles, si une dépendance structurelle est détectée. Une fois sortie du second étage, on sait quand la micro-opération va être émise, à quel cycle précisément. Et vu que la durée de l'instruction est fixe, on sait quand cette micro-opération va se terminer, quand son résultat sera disponible. Cela permet de mettre à jour la ''Time Ressource Matrix'', pour préciser que le port d'écriture sera occupé à tel moment. De plus, cette information est transmise au premier étage, qui sait alors quand est enregistré le résultat dans le registre de destination. C'est comme cela que le premier étage sait quand un registre est disponible : le second étage le prévient, quand il émet une instruction ! La ''Time Ressource Matrix''mémorise l'occupation des "ressources" pour les 256 cycles d'horloge à venir. Cependant, elle ne vérifie pas les dépendances pour les 256 cycles suivants. Quand elle reçoit une micro-opération, elle teste les dépendances structurelles pour seulement les 8 prochains cycles maximum. Si la micro-opération ne peut pas être émise pendant ces 8 cycles, le pipeline est bloqué, un ''pipeline stall'' est émis. Pour être plus précis, vu que le processeur peut décoder 8 micro-opérations en même temps, cela permet de ne consulter que 64 cycles d'horloge sur les 256. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les premiers processeurs Intel | prevText=Les premiers processeurs Intel | next=Le renommage de registres | nextText=Le renommage de registres }} </noinclude> qk512czcvzgpna2o51gp4tbfdiq0zl3 773629 773628 2026-09-29T21:07:20Z Mewtow 31375 773629 wikitext text/x-wiki Dans les chapitres précédents, nous avons parlé des techniques dites d''''émission dans l'ordre'''. L'idée est d’exécuter une nouvelle micro-opération à chaque cycle, dans des unités de calcul séparées. Les instructions sont émises consécutivement, mais les instructions s’exécutent en parallèle dans des unités de calcul séparées. Par contre, quand l'unité d'émission ne peut pas émettre une instruction, elle bloque tout le pipeline. Les instructions qui suivent sont elles aussi bloquées, elles doivent attendre leur tour, même si elles sont en capacité de s'exécuter. Les techniques d'exécution dans le désordre que nous allons voir dans ce chapitre corrigent ce point précis. Elles sont dites à '''émission dans le désordre'''. Elles se distinguent des précédentes sur un point précis : quand l'unité d'émission bloque l'émission d'une instruction, les instructions suivantes peuvent poursuivre. L'émission des instructions peut donc se faire dans le désordre, dans le sens où une instruction peut être émise alors qu'une instruction précédente ne l'est pas encore. Mais avant de poursuivre, quelques point niveaux terminologie : * L'émission dans le désordre est un terme parlant et assez précis. Malheureusement, la terminologie la plus utilisée par d''''exécution dans le désordre'''. Et nous utiliserons ce terme dans la suite du cours, histoire de ne pas trop dévier de la nomenclature habituelle. * Nous utiliserons parfois l'abréviation OOO pour parler d'exécution dans le désordre. L'abréviation est celle de ''Out Of Order Execution''. * Nous utiliserons aussi l'abréviation ''µop'' pour parler de micro-opération, ''µops'' au pluriel pour parler de plusieurs micro-opérations, ou des micro-opérations en général. L'exécution dans le désordre ne gère en effet que des µops, elle se situe après l'étape de décodage. Pour décrire comment est implémentée l'émission dans le désordre, il faut commencer par parler des processeurs sans. Les processeurs sans exécution dans le désordre ont une unité d'émission qui bloque tout le pipeline dès qu'une µop ne peut pas être émise. Pour limiter l'impact de ce blocage, quelques rares processeurs incorporent une '''file de micro-opération''', une mémoire FIFO qui met en attente les µops. Vu que c'est une mémoire FIFO, les µops sont émises dans l'ordre, à savoir l'ordre d'ajout, dans l'ordre de décodage. Le schéma ci-dessous illustre une telle file d'attente couplée à un ''scoreboard''. L'exécution dans le désordre améliore la file de µops sur un point : ce n'est plus une mémoire FIFO. Les µops sont insérées dans l'ordre, mais peuvent sortir dans le désordre (être émises dans le désordre). La file de µops devient alors un '''''scheduler''''', terme anglais que je ne compte pas traduire. Un terme équivalent est '''''scheduler''''', terme traduit directement de l'anglais ''instruction Window''. Terme assez trompeur, car elles mettent en attente des µops, pas des instructions. [[File:Différence file µops et fenêtres instruction.png|centre|vignette|upright=2|Différence file µops et ''schedulers'' ]] Le ''scheduler'' émet une µop dès que ses opérandes sont disponibles. Par disponible, on veut dire présent soit dans le réseau de contournement, soit dans les registres. Le ''scheduler'' détecte automatiquement quand les opérandes d'une µop sont disponibles, grâce à une unité d'émission intégrée. L'unité d'émission et le ''scheduler'' sont fusionnés ensemble, dans un seul circuit, mais nous allons dire qu'ils sont conceptuellement séparés pour le moment. À chaque cycle, l'unité d'émission consulte les µops en attente pour détecter lesquelles peuvent s'exécuter. Le ''scheduler'' est spécialement être conçue pour, c'est une sorte de mémoire associative très complexe, comme on le verra dans ce qui suit. [[File:OOO Issue.png|centre|vignette|upright=2.5|Exécution dans le désordre avec un ''scheduler'']] Une fois qu'une µop sort du décodeur d'instructions, elle est ajoutée en parallèle dans le ''scheduler'' et le ROB. La raison est que les µops quittent le ''scheduler'' dans le désordre, et qu'elles doivent être remises en ordre par la suite. Le ROB s'occupe de cette remise en ordre, mais il a besoin de savoir dans quel ordre les µops sont censées être, et cet ordre est celui du décodage. Aussi, pour remplir le ROB, la seule opportunité est en sortie de l'unité de décodage. Dans le cas où une instruction est décodée en plusieurs micro-opérations, elles sont toutes insérées en même temps dans le ''scheduler'' et le ROB, en tenant compte de leur ordre. L'implémentation la plus simple de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Les µops décodées sont accumulées dans le ''scheduler'', où elles attendent leur tour. le ''scheduler'' sert donc de file d'attente. Avant de poursuivre, précisons que les micro-opérations mémoire sont à part des autres, pour diverses raisons. Une de ces raisons est que les dépendances de données sont classées en deux types : les dépendances de registre et les dépendances d'adresse. Et les deux sont fondamentalement différentes. Autant on peut détecter les dépendances de registre lors de l'émission, autant c'est plus compliqué avec les dépendances d'adresse. De plus, rappelons que si les lectures peuvent s'exécuter dans le désordre, les écritures doivent s'exécuter dans l'ordre, ou du moins en donner l'illusion. Pour cela, le processeur remet les écritures dans l'ordre avec une sorte de mini-ROB intégré à l'unité mémoire, appelée la file d'écriture. Elle complémente le ROB, qui lui ne gère que les écritures dans les registres, mais les deux collaborent. La file d'écriture envoie une écriture à la mémoire RAM quand le ROB lui dit que c'est bon, les instructions précédentes sont terminées ''dans l'ordre du programme''. Les processeurs modernes ajoutent des techniques d'exécution dans le désordre des accès mémoire, mais nous les verrons dans un chapitre dédié. Elles permettent d'utiliser un ''scheduler'' unique, qui mémorise aussi les µops mémoire. Si elles sont mises en place, l'unité mémoire n'a pas besoin de file de µops séparée. L'idée est que les dépendances de registre sont traitées par le ''scheduler'', mais que l'unité mémoire gére les dépendances d'adresse. Les dépendances d'adresse sont gérées par des techniques de ''désambiguation mémoire'', qui auront droit à un chapitre dédié. [[File:Processeur avec exécution dans le désodre des accès mémoire.png|centre|vignette|upright=2|Processeur avec exécution dans le désodre des accès mémoire]] Les processeurs assez anciens n'autorisaient pas d'exécution dans le désordre des accès mémoire. Concrètement, les accès mémoire devaient se faire dans l'ordre, mais les autres µops pouvaient être exécutées dans le désordre. Il s'agit donc d'un ordre entre µops mémoire, pas entre µops mémoire et autres µops. Les µops entières et flottantes pouvaient être exécutées avant une µops mémoire qui est avant elle dans l'ordre du programme, ce n'est pas un problème. Pour garantir l'ordre des µops mémoire, l'unité mémoire est précédée par une file de micro-opérations séparée, pour forcer l'exécution dans l'ordre des accès mémoire. De plus, les µops mémoire ne peuvent pas utiliser le ''scheduler''. Dit autrement, le ''scheduler'' ne mémorise pas de µops mémoire. Après le décodage, les µops sont réparties soit dans la file de µops mémoire, soit dans le ''scheduler''. Le décodeur classe les µops suivant que ce sont des µops mémoire ou non, et les envoient à la bonne destination. Dans ce chapitre, on supposera que c'est cette solution qui est utilisée. [[File:Processeur avec émission dans l'ordre des accès mémoire.png|centre|vignette|upright=2|Processeur avec émission dans l'ordre des accès mémoire]] ==L'implémentation d'un ''scheduler'' : généralités== Un ''scheduler'' est une mémoire qui mémorise des micro-opérations. Elle est cependant plus complexe qu'une mémoire RAM ou qu'une FIFO et ressemble un petit peu à une mémoire cache. Elle dispose d'un port d'écriture et d'un port de lecture, au minimum. Le port d'écriture permet à l'unité de décodage d'insérer une micro-opération dedans, d'ajouter la micro-opération qui vient d'être décodée. Si une instruction machine est décodée en plusieurs micro-opération, deux possibilités. La première est de les insérer un par un, ce qui fait qu'on peut se contenter d'un seul port d'écriture. L'autre possibilité est de les ajouter en même temps, ce qui demande plusieurs ports d'écriture. Le port de lecture sert à émettre une instruction. On part du principe que le ''scheduler'' ne peut émettre qu'une seule instruction à la fois, car les processeurs que nous avons vu précédemment sont de ce type. Mais nous verrons dans quelques chapitres qu'il existe des processeurs dits superscalaires, qui sont capables d'émettre plusieurs instructions par cycle. Dans ce cas, le ''scheduler'' a un seul port de lecture. Un processeur superscalaire, quant à lui, doit avoir un port de lecture par unité de calcul, ce qui fait beaucoup plus. Les ''schedulers'' sont composées d''''entrées''', des mots mémoire qui stockent une instruction. Une instruction réserve une entrée après son décodage et la libère dès qu'elle est envoyée aux unités de calcul. Une entrée contient l'opcode (les signaux de commande à envoyer à l'ALU), le registre de destination du résultat, les registres de chaque opérande, et éventuellement des signaux de commande en plus. De plus, chaque opérande est couplée à un bit de disponibilité, qui indique si elle est disponible. Quand un opérande est écrit dans les registres, le bit de présence correspondant est mis à jour. Enfin, chaque entrée possède un bit ''empty'' qui indique si elle est vide, cette information étant utile pour réserver des entrées. [[File:Entrée d'une station de réservation - sans les tags.png|centre|vignette|upright=3|Entrée d'un ''scheduler'']] ===Les stations de réservation=== Les '''stations de réservation''' sont des ''scheduler'' particulières, qui sont capables de mémoriser les opérandes des instructions. Les entrées des stations de réservation sont identiques à celle des autres ''scheduler'', si ce n'est que les opérandes de l'instruction sont enregistrés directement dans des champs séparés. Il y a deux champs, un par opérande, pour stocker l'opérande elle-même, lue depuis les registres ou obtenue via le réseau de contournement. Notons que les champs pour les opérandes viennent en plus des champs pour les noms de registres, encore que les deux peuvent être fusionnés si on veut optimiser le tout. [[File:Entrée d'une station de réservation.png|centre|vignette|upright=3|Entrée d'une station de réservation.]] Précisons que la terminologie n'est pas très fiable. Les termes "''scheduler''" et "station de réservation" ne regroupent pas du tout la même chose d'un papier de recherche à l'autre, d'un bouquin à l'autre, d'un chercheur à l'autre, d'un ingénieur à l'autre, d'un professeur à l'autre. Le terme initial vient pourtant de l'article original sur l'algorithme de Tomasulo, où il désignait un ''scheduler'' associée à une unité de calcul précise. Mais le terme a ensuite été réutilisé, ce qui fait que certains processeurs avec plusieurs unités de calcul sont décrits comme ayant une unique station de réservation. En bref : c'est le bazar ! Mais nous en reparlerons dans le chapitre sur le renommage de registres, car c'est la place idéale pour les aborder. Toujours est-il que j'ai fait le choix de confondre les concepts de ''scheduler'' et de station de réservation avec les concepts de '''lecture avant émission''' et de '''lecture après émission'''. La différence entre les deux est que les registres sont lus après émission avec un ''scheduler'', avant avec des stations de réservation. Dans le cas "avant émission", les opérandes sont mémorisés dans la station de réservation. Et cette différence a une influence sur le pipeline du processeur, le banc de registres et tout ce qui s'ensuit. Un désavantage de la lecture avant émission est qu'il faut stocker les opérandes après lecture, ici dans les stations de réservation. Mais un avantage est que le banc de registre a besoin de moins de ports de lecture, car une bonne partie des opérandes sont fournies par le système de contournement. Nous verrons cela dans le détail dans le chapitre sur les processeurs superscalaires. [[File:Processeur avec plusieurs ''scheduler''.png|centre|vignette|upright=2.5|Lecture après émission.]] [[File:Read Before Issue.png|centre|vignette|upright=2.5|Lecture avant émission.]] ===La logique d'éveil et de sélection=== Dans le cas qui va suivre, on suppose que le processeur ne peut émettre qu'une instruction à la fois. Chaque cycle, une instruction est sélectionnée et est envoyée dans le chemin de données, soit à une ALU, soit à une unité d'accès mémoire. La sélection d'une instruction est effectuée par l'unité d'émission, qui est aussi appelée le '''''scheduler'''''. Elle gère la disponibilité des opérandes et la disponibilité des unités de calcul adéquate. Le choix de l'instruction émise doit être le plus pertinent possible, pour des raisons de performances. Pour le premier point, l'unité d'émission détermine quelles instructions sont candidates pour l'émission. Les ''instructions candidates'' sont celles dont tous les opérandes sont prêts. Le processeur contient un circuit qui détecte les instructions candidates : la '''logique d’éveil''' (''wake-up logic''). Une fois que la logique d'éveil a fait son travail, une instruction est choisie pour s’exécuter en fonction de la disponibilité des unités de calcul adéquates. Ce rôle est dévolu à un circuit qu'on appelle la '''logique de sélection''', ou ''select logic''. [[File:Fonctionnement complet de la logique d’émission.jpg|centre|vignette|upright=1.5|Fonctionnement complet de la logique d’émission.]] La logique de sélection doit gérer le fait que les unités de calcul du processeur ne sont pas toutes identiques. Déjà, un processeur a généralement des unités séparées pour les instructions entières et flottantes, des unités spécialisées dans les accès mémoire, parfois des unités spécialisées pour les branchements. Une instruction doit être attribuée à la bonne unité de calcul, on ne doit pas envoyer une instruction entière dans une unité de calcul flottante. De plus, parmi les unités de calcul entières, toutes ne sont pas identiques. Par exemple, il est fréquent d'avoir plusieurs unités de calcul spécialisées dans les opérations simples (additions, soustractions, opérations logiques) avec une unité pour les multiplications/divisions séparées, parfois une unité spécialisée pour les décalages/rotations, etc. Là encore, allouer la bonne instruction à la bonne ALU est complexe. Plus les unités de calcul sont hétérogènes, plus la logique de sélection est compliquée. Les logiques d'éveil comme de sélection sont assez complexes. Comme on le verra plus bas, la logique de sélection la plus simple, qui gère une seule unité de calcul, est basée sur un encodeur à priorité, couplé à d'autres circuits. Et pour gérer plusieurs ALUs, il faut mettre des encodeurs en cascade. Le résultat est que même en prenant une logique de sélection simple, elle sera assez lente et gourmande en circuits. Aussi, la logique de sélection met souvent un cycle d'horloge entier pour faire son travail, elle a son propre étage de pipeline attribué. La logique d'éveil est dans le même cas, ce qui fait qu'émettre une micro-opération demande deux cycles d'horloge. Le défaut est que cela rajoute des cycles d'horloges entre le ''scheduler'' et l'ALU, ce qui complique la gestion du pipeline. Ces cycles de retard sont à prendre en compte au moment d'émettre les instructions, les ''scheduler'' doit en tenir compte pour des performances optimales. Sans tenir compte de ces cycles de retard, les instructions arrivent en retard de quelques cycles à l'ALU, cycles de retard durant lesquels l'ALU n'a pas fait de calcul et a été sous-utilisée, sans compter que le système de contournement n'est pas utilisé au mieux. Et le problème est encore plus important sur les processeurs avec des stations de réservation, qui utilisent la "lecture après émission" : cela rajoute un cycle d'horloge en plus, un temps de retard en plus. ===La logique d'éveil : l'émission anticipée=== La logique d'éveil doit tenir compte du fait qu'il y a plusieurs étages entre l'émission et l'exécution sur une unité de calcul. Par exemple, un processeur a souvent entre un et à cinq étages entre la file d'attente et les unités de calcul. Il faut lire les registres, gérer le contournement, et cela peut prendre quelques cycles d'horloge. Sur le Pentium 4, on trouve 6 étages entre le ''scheduler'' et l'entrée de l'ALU. Si les micro-opérations sont émises quand les opérandes sont disponibles, il y aura un délai de quelques cycles avant qu'elles atteignent l'ALU. Alors qu'idéalement, on souhaiterait que la micro-opération atteigne l'ALU dès que ses opérandes sont disponibles, pour profiter des techniques de contournement. Pour cela, la logique d'éveil émet les instructions quelques cycles en avance pour qu'elles arrivent au bon moment. Il s'agit d'une technique d''''émission anticipée''', dont nous avions parlé dans le chapitre sur le contournement. : Il faut noter que le problème se pose plus avec des ''schedulers'' qu'avec des stations de réservation. Les premières ont un étage en plus entre émission et ALU, vu qu'il faut lire des registres après l'émission. L'émission anticipée demande d'émettre un signal d'éveil en avance de quelques cycles, pile au bon moment. Par exemples, si on a deux étages entre l'ALU et l'unité d'émission, le signal de réveil sera généré deux cycles avant que le résultat soit effectivement calculé. L'implémentation varie, mais deux solutions sont possibles. La première est de générer le signal d'éveil dans l'ALU, ce qui n'a de sens que pour les opérations comme les multiplications ou les divisions, qui prennent plusieurs cycles. Une autre technique génère le signal de réveil dans une structure centralisée, spécialisée dans la génération des signaux d'éveil. L'unité de composée d'un registre à décalage par registre. Imaginons qu'une instruction est émise, que cette instruction mette N cycles à s'exécuter, et qu'elle écrive dans un registre de destination. L'unité sélectionne alors le registre à décalage associé au registre de destination, et met le bit numéro N à 1. Le registre décalé d'un cran à chaque cycle. Quand le bit sortant est un 1, alors le signal de validité pour l'opérande est généré. L'émission anticipée marche bien si l'instruction a une durée fixe, connue à l'avance. Et autant c'est le cas pour les instructions arithmétiques et logiques, autant ce n'est pas le cas pour les accès mémoire. Les accès mémoire ont une latence variable : quelques cycles pour un succès de cache, plusieurs dizaines de cycles pour un défaut de cache L1, pas loin de la centaine pour un défaut de cache L2, etc. Et cela pose des problèmes pour l'émission anticipée. L'émission en avance pour les accès mémoire est purement spéculative : le processeur émet des instructions en supposant que la lecture entrainera un succès de cache, quitte à annuler l'instruction en cas de défaut de cache. Mais faire ainsi demande non seulement d'annuler les instructions émises en avance, mais aussi de ne pas retirer les instructions émises en avance de le ''scheduler''. Elles sont émises, mais une copie de sauvegarde est conservée dans le ''scheduler''. Si le processeur détecte un défaut de cache, il peut alors ré-exécuter l'instruction. S'il détecte un succès de cache, les instructions lecture-dépendante sont retirées de le ''scheduler'', la copie de sauvegarde est devenue inutile et est donc jetée. ===La logique de sélection : âge ou position ?=== La logique de sélection est primordiale pour de bonnes performances. Il existe deux méthodes principales pour sélectionner l'instruction à exécuter. La première est la plus simple : elle se base sur lé numéro de l'entrée. En effet, un ''scheduler'' est avant tout une sorte de mémoire, un mix entre mémoire associative, mémoire RAM, et FIFO. Et chaque entrée a un numéro, une adresse mémoire. Nous parlerons de numéro dans ce qui suit, car ce sera plus simple, le terme d'adresse mémoire étant peut-être un peu exagéré dans le contexte des ''scheduler''. Toujours est-il que le ''scheduler'' est adressable dans le sens où on peut lui envoyer le numéro de l'entrée voulue, et le ''scheduler'' renvoie le contenu de l'entrée sur son port de lecture. Et c'est ce que fait la logique de sélection : elle génère le numéro de l'entrée à lire. Le numéro est alors envoyé sur l'entrée d'adresse du ''scheduler'', et elle fournit la micro-opération associée sur son port de lecture, son '''port d'émission'''. La première méthode de sélection, donc. Elle est basée sur le numéro de l'entrée. Si plusieurs entrées sont éveillées, la logique de sélection prend celle avec le plus petit numéro. Elle porte le nom de '''sélection par position''', sous-entendu position dans le ''scheduler''. Vous l'avez peut-être deviné, mais la logique de sélection est alors un encodeur à priorité. Le circuit de sélection ne se résume donc pas seulement à un encodeur à priorité, mais c'est le circuit central. L'avantage d'une telle méthode de sélection est qu'elle est simple à implémenter : un encodeur à priorité est un circuit connu, facile à implémenter. Mais on remarque un défaut : un encodeur est un circuit assez rapide, mais qui utilise beaucoup de transistors, beaucoup de portes logiques, surtout si on veut qu'il soit rapide. Ce qui explique que la logique de sélection ait son propre étage de pipeline rien que pour elle. La seconde méthode s'appelle la '''sélection par âge''', au nom assez transparent. L'idée est de privilégier l'émission de l'instruction la plus ancienne. Elle demande que le ''scheduler'' trie les micro-opérations par ordre d'insertion dans le ''scheduler'', ce qui en fait une pseudo-FIFO. Le tri est partiel, car les instructions peuvent sortir du ''scheduler'' à tout moment. Compacter le ''scheduler'', à savoir regrouper toutes les entrées valides est une idée, mais elle est compliquée à implémenter. Aussi, elles préfèrent encoder des informations sur l'ordre d'émission dans chaque entrée. L'encodeur à priorité doit alors travailler non pas sur des nombres entiers liés à l'ordre d'insertion dans la pseudo-FIFO. Elle est encore plus gourmande en circuits que la méthode précédente. Les processeurs haute performance utilisent souvent des méthodes hybrides. Par exemple, les processeurs AMD de microarchitecture Bulldozer utilisaient une méthode intermédiaire. Ils utilisaient un ''scheduler'' couplée à un encodeur à priorité pour la sélection par position, mais complémentaient le tout avec une unité qui mémorisait l'instruction la plus ancienne dans le ''scheduler''. Le mécanisme de sélection par âge était utilisé en priorité. Mais si l'instruction la plus ancienne n'était pas prête, le processeur basculait sur le mécanisme de sélection par position. ===La compaction des ''scheduler''=== À chaque cycle, les instructions décodées sont ajoutées dans le ''scheduler'', dans des entrées vides. Vu que les instructions quittent celle-ci dans le désordre, ces vides sont dispersés dans le ''scheduler'', ce qui pose problème pour déterminer où placer les nouvelles instructions. La solution la plus triviale consiste à conserver une liste des vides, mise à jour à chaque insertion ou émission d'instruction. Une autre solution consiste à éliminer les vides en compactant le ''scheduler'' à chaque cycle d'horloge. Des circuits se chargent de détecter les vides et de regrouper les instructions en un unique bloc. Il faut signaler que certains processeurs arrivent à se passer de cette étape de compactage, mais au prix de ''scheduler'' nettement plus complexes. Autre problème : quand il faut choisir quelle instruction émettre, il y a toujours plusieurs candidats. Si on choisit mal, des instructions restent en attente trop longtemps parce que d'autres instructions plus jeunes leur passent devant. Pour éviter cela, les instructions les plus vielles, les plus anciennes, sont prioritaires. Pour cela, on peut utiliser une FIFO un peu spéciale pour le ''scheduler''. Si les ajouts d'instruction se font dans l'ordre, les instructions ne quittent pas forcément le ''scheduler'' dans l'ordre imposé par une FIFO : les instructions restent triées dans leur ordre d'ajout, même s'il y a des vides entre elles. Dans ces conditions, il est préférable que le compactage conserve l'ordre FIFO des instructions. Dans ces conditions, l'instruction la plus ancienne est celle qui est située à l'adresse la plus faible : le circuit de sélection peut donc être fabriqué avec des encodeurs, et est relativement simple. ==Les ''schedulers'' basées sur une matrice de dépendances== L'implémentation la plus simple étend le fonctionnement d'un pipeline dynamique usuel. Rappelez-vous le chapitre sur les pipelines dynamiques. Nous avions vu que de tels pipelines émettaient une instruction par cycle, quitte à émettre des bulles de pipeline en cas de dépendance bloquante. Et il est possible d'améliorer leur unité d'émission pour qu'elle soit compatible avec l'exécution dans le désordre. ===Rappels sur le registre de réservation/disponibilité=== L'émission d'une instruction est gouvernée par un ''registre de réservation'' qui indique quels registres sont réservés par une instruction, et ceux qui sont libres. Un registre réservé est un registre qui sera écrit par une instruction en cours d'exécution, mais qui n'a pas encore écrit son résultat. Les instructions candidates doivent avoir leurs opérandes dans des registres libres. Sinon, c'est signe que leurs opérandes sont réservés en écriture, donc pas encore écrites, donc pas disponibles. Si une instruction candidate veut lire ce registre, c'est signe qu'il y a une dépendance RAW : elle veut lire un registre réservé, qui est destiné à être écrit par une instruction en vol. Si elle veut écrire, c'est signe qu'elle veut écrire dans un registre où une autre instruction veut écrire : c'est une dépendance WAW. Dans les deux cas, l'instruction n'est pas émise. Le registre de réservation encode les registres réservés comme suit : chaque bit est associé à un registre. Le bit numéro 0 est associé au registre numéro 0, le bit numéro 1 au registre numéro 1, etc. Là, En clair, les numéros de registres réservés sont encodés en représentation non pas binaire, mais en représentation ''one-hot'' (vue au premier chapitre). {|class="wikitable" |+ Registre de réservation |- ! Registre 7 !! Registre 6 !! Registre 5 !! Registre 4 !! Registre 3 !! Registre 2 !! Registre 1 !! Registre 0 |- | 0 || 0 || 1 || 0 || 0 || 1 || 0 || 0 |} Avant d'émettre une instruction, l'unité d'émission extrait les registres opérande/destination et les convertis dans la même représentation que le registre de réservation, à savoir en représentation ''one-hot''. Le circuit de traduction binaire vers ''one-hot'' est, pour rappel, un simple décodeur. Puis, on fait un OU logique entre les sorties des décodeurs. Le résultat est un masque qui indique quels registres sont lus par l'instruction, encodé en représentation ''one-hot''. Appelons-le le '''masque d'opérandes'''. Le masque est alors comparé au registre de réservation pour vérifier si l'instruction peut être émise. [[File:Unité d'émission simple, dans l'ordre.png|centre|vignette|upright=2|Unité d'émission simple, dans l'ordre]] Si l'émission est autorisée, le registre de réservation est là aussi mis à jour. Le registre de réservation est aussi mis à jour dès qu'une instruction enregistre son résultat dans les registres, ou alors dès qu'il est disponible pour le contournement. Le bit associé au registre repasse alors à 0 (ou à 1). Sans contournement, la mise à jour se fait alors à la toute fin de l'instruction, quand elle se termine, lors de la dernière étape d'enregistrement, à la fin de son pipeline. Avec, elle se fait quand l'instruction quitte l'unité de calcul. ===L'extension à l'exécution dans le désordre : l'éveil par matrice de bits=== La différence entre un pipeline dynamique et l'exécution dans le désordre est que l'on passe d'une instruction à émettre à plusieurs. Plusieurs instructions sont mises en attente dans un ''scheduler'', et y attendent leur tour. L'idée est alors d'envoyer le registre de disponibilité à toutes les entrées, à toutes les instructions en attente. Ainsi, on sait quelles sont les instructions qui peuvent s'exécuter et celles qui ne le peuvent pas. L'implémentation est assez simple, elle ressemble beaucoup à l'implémentation d'un pipeline dynamique simple, si ce n'est que des circuits sont dupliqués. L'implémentation utilise des ''scheduler'' légèrement différentes de celles introduites plus haut. Elles n'utilisent notamment pas de bits de disponibilité, mais autre chose. Lorsqu'une instruction est ajoutée à le ''scheduler'', le masque de disponibilité des opérandes est stocké dans le ''scheduler''. A chaque cycle, le registre de disponibilité est envoyé à toutes les entrées, et est comparé avec tous les masques de disponibilité des opérandes. Si une comparaison renvoie un 1, alors l'instruction de l'entrée est une instruction candidate à l'émission. [[File:Unité d'émission dans le désordre basée sur un registre de disponibilité.png|centre|vignette|upright=2.5|Unité d'émission dans le désordre basée sur un registre de disponibilité]] L'ensemble est implémenté avec l'aide d'une '''matrice de bits''', où chaque ligne correspond à une entrée et chaque colonne à un registre. À chaque croisement entre une ligne et une colonne, on trouve un bit. Si le bit de la ligne n et de la colonne m est à 1, cela veut dire : l'instruction dans l'entrée n a besoin de lire le registre m. S’il est à 0, alors cela veut dire que l'instruction stockée dans la ligne n'a pas besoin de la donnée dans le registre m. [[File:Planificateur à matrice de bits.jpg|centre|vignette|upright=2|Planificateur à matrice de bits.]] Lorsqu'une instruction réserve une entrée, elle initialise la ligne en fonction des registres qu'elle souhaite lire. Pour vérifier si une instruction a ses opérandes prêts, le processeur compare le registre de disponibilité à la ligne associée à l'instruction/entrée. A chaque intersection ligne-colonne, se trouve un comparateur de 1 bit, qui détecte si le registre est demandé et disponible. Les résultats de cette porte sont ensuite envoyés à une porte ET, qui fait le gros du travail. [[File:Logique de détection de la disponibilité d'une instruction.jpg|centre|vignette|upright=2|Logique de détection de la disponibilité d'une instruction.]] ==Les ''scheduler'' basées sur une mémoire associative== Les processeurs modernes utilisent une mémoire associative pour le ''scheduler''. Les mémoires associatives ont été abordées il y a quelques chapitres, mais faisons quelques rappels. Les mémoires associatives servent à accélérer la recherche de données dans un ensemble. Or, un ''scheduler'' vérifie régulièrement si chaque entrée est prête. Il s'agit d'un processus de recherche d'une instruction qui respecte une condition bien précise dans la mémoire, ce qui fait que les mémoires associatives sont donc tout indiquées. Comme vous le savez, les signaux de commande d'une instruction sont propagés avec celle-ci dans le pipeline, le nom du registre de destination ne faisant pas exception. Le nom de registre est envoyé à le ''scheduler'' lors de l'écriture du résultat dans les registres. S'il y a correspondance, l'opérande est disponible et son bit de disponibilité est mis à 1. On peut adapter cette méthode pour tenir compte du contournement assez simplement. [[File:Détection des dépendances par propagation du registre de destination.png|centre|vignette|upright=2|Détection des dépendances par propagation du registre de destination.]] En conséquence, le circuit de détection des dépendances est constitué d'un grand nombre de comparateurs : un par champ « nom de registre » dans chaque entrée. La logique d'éveil/''wake up'' regroupe tous les comparateurs, la logique de sélection est un circuit situé en-dehors de la mémoire associative. Les entrées sont dans la mémoire associative elle-même. [[File:Gestion des bits de validité.png|centre|vignette|upright=2|Gestion des bits de validité.]] L'implémentation la plus simple est celle du schéma précédent, où on utilise une mémoire associative unique. Une version plus élaborée sépare le ''scheduler'' en deux parties : une mémoire qui mémorise les registres des opérandes, une autre mémoire pour le reste. La mémoire pour les registres opérandes est la mémoire associative proprement dite, c'est elle qui est associée aux comparateurs, à la logique de ''wake-up''/réveil, etc. Par contre, l'autre mémoire est une mémoire RAM simplifiée, qui mémorise les informations qui n'ont pas besoin des comparateurs. L'opcode de l'instruction est là-dedans, par exemple. le ''scheduler'' est donc une sorte de mémoire associative améliorée. Il se trouve que c'est aussi le cas du ROB. Et il est possible de fusionner le tampon de ré-ordonnancement avec le ''scheduler'' dans une structure unique. La différence avec un ''scheduler'' normal est que les entrées sont libérées non pas quand l'instruction est exécutée/émise, mais quand elle termine son exécution et quitte le ROB. le ''scheduler'' incorpore des bits dans chaque entrée, pour savoir si la µops associée a été émise et est en cours de traitement dans les ALUs. La méthode a notamment été utilisée sur les processeurs d'architecture K6 d'AMD. Le tout donnait une structure appelée le '''DRIS''' (''deferred scheduling register renaming instruction shelf''). Les processeurs PA 8000 de HP étaient aussi vraisemblabment dans ce cas, aussi. ===Les optimisations de la consommation d'énergie : la désactivation des portions inutilisées=== Le problème avec des ''scheduler'' de ce type est leur forte consommation énergétique, ainsi que le grand nombre de portes logiques utilisées, qui deviennent prohibitifs pour des ''scheduler'' un peu grosses. Pour résoudre ce problème, certains ont optimisé les comparateurs. D'autres ont tenté de profiter du fait que la majorité des bits dans les entrées sont composés de zéros. Bref, les optimisations purement matérielles sont légion. Une première solution est de désactiver les entrées qui sont inutilisées, vides, sans instruction. Pour cela, on fait précéder les comparateurs par un circuit qui les connecte ou déconnecte des lignes de bit. Le circuit est commandé par le bit ''empty'' qui indique si une entrée est vide ou non. L'avantage est que la consommation d'énergie de le ''scheduler'' devient alors proportionnelle au nombre d'entrées non-vides, et non au nombre d'entrées total. Du moins, en apparence, les entrées non-utilisées doivent quand même être alimentées pour fonctionner, mais l'activité de comparaison disparait dans les entrées vides. Il est possible d'étendre cette technique aux entrées dont les opérandes sont prêts. Les gains sont généralement assez bons, avec une réduction de consommation variant entre 30 et 50%, avec une implémentation très simple et très économe en circuits. Une autre solution, assez simple à mettre en place, consiste à désactiver une partie de le ''scheduler'' sin elle est inutilisée. Pour cela, il faut segmenter le ''scheduler'' avec la technique du ''wire partitionning''. Pour rappel, un ''scheduler'' est une mémoire associative. Et comme toute mémoire associative, elle contient des fils, les lignes de bit, qui relient les entrées/sorties à toutes les cellules mémoire. Plus une ligne de bit est longue, plus elle consomme d'énergie et plus le temps de lecture/écriture est long. L'idée est de segmenter les lignes de bits en plaçant des répéteurs qui recopient la tension d'un segment au suivant. Les répéteurs sont des tampons trois-états, ce qui permet de déconnecter les portions inutilisées de la ligne de bit. Ce faisant, le ''scheduler'' est découpée en segments, qui peuvent être désactivés si besoin. S'il y a peu d'instructions chargées dans le ''scheduler'', les portions inutilisées sont désactivées. La technique marche d'autan mieux si les instructions sont compactées au début de le ''scheduler''. [[File:Wire partitionning.png|centre|vignette|upright=2|Wire partitionning]] Tout le problème est de savoir quelles portions désactiver. La technique est assez simple si le ''scheduler'' est compactée, à savoir si toutes les instructions sont régulièrement regroupées au début de la mémoire CAM. Mais même avec cette optimisation, la décision de désactiver une portion de le ''scheduler'' n'est pas à prendre à la légère. Il ne faut pas désactiver une portion contenant des instructions pouvant être émise sous peu. La décision dépend de paramètres variés : proportion d'entrée vides, quantité d'entrées récemment activées/désactivées récemment, présences d'entrées avec un ''match'' d'opérandes récent, etc. Il est important de préciser que les techniques en question fonctionnent aussi sur les autres types de ''scheduler'', qui ne sont pas basées sur des mémoires associatives. Nous allons voir celles-ci dans la suite du chapitre, mais gardez à l'esprit que ces optimisations, à savoir désactiver les entrées vides/prêts et partitionner le ''scheduler'', sont des optimisations générales qui marchent avec presque tout. ===L'ajout d'une FIFO pour les instructions déjà prêtes à l'émission=== D'autres techniques permettent de réduire aussi bien le cout en circuits que la consommation d'énergie de le ''scheduler''. L'idée est d'utiliser une mémoire associative quand elle est réellement nécessaire, mais d'utiliser un ''scheduler'' "normale" dès que possible. La méthode la plus simple tient compte du fait que certaines µopsont déjà toutes leurs opérandes de disponibles à l'émission, mais doivent quand même être mises en attente, parce que l'ALU adéquate est occupée, parce que des dépendances WAW/WAR sont encore là, ou pour tout autre raison. Dans ce cas, elles sont mises en attente non pas dans le ''scheduler'', mais dans une mémoire FIFO toute simple. L'idée est qu'au lieu d'avoir une énorme mémoire associative pour le ''scheduler'', on déplace quelques entrées dans une petite FIFO annexe. Le résultat est un gain d'énergie et de circuits, au prix d'une perte de performance mineure. La perte de performance en question se manifeste si aucune instruction n'a ses opérandes de prêtes à l'émission : le programme n'utilise pas la FIFO et voit alors un ''scheduler'' plus petite. Une amélioration de cette technique tient compte du fait que certaines instructions sont dans un cas intermédiaire. Elles ont déjà un opérande de prête lors de l'émission, mais pas l'autre. Le nombre d'opérandes varie suivant l’instruction : certaines n'ont besoin que d'un seul opérande. De plus, il arrive qu'une opération tout juste décodée ait déjà un ou plusieurs de ses opérandes de prêts. Cette constatation permet d'éviter d'utiliser des comparateurs pour les opérandes déjà prêts. Par exemple, on peut parfaitement utiliser trois ''scheduler'' : * une pour les instructions dont tous les opérandes sont prêts, mais qui sont quand même mises en attente, sans comparateur ; * une pour les instructions dont un seul opérande manque, qui n'utilise qu'un comparateur par entrée ; * une pour les instructions dont deux opérandes manquent à l'appel, qui utilise deux comparateurs par entrée. C'est beaucoup plus économique que d'utiliser une seule grosse ''scheduler'' qui contiendrait autant d'entrées que les trois précédentes réunies, avec deux comparateurs par entrée. Certains sont même allés plus loin, et ont proposé de supprimer le ''scheduler'' avec deux opérandes par entrée. Les instructions dont deux opérandes sont inconnus au décodage sont stockées dans le ''scheduler'' pour instructions avec un comparateur par entrée. Un circuit de prédiction se charge alors de prédire l'opérande manquant, cette prédiction étant vérifiée plus loin dans le pipeline. Il serait cependant étonnant qu'une telle proposition ait donné lieu à la moindre implémentation réelle. ===Les optimisations de la consommation d'énergie avancées=== D'autres chercheurs ont conservé un ''scheduler'' unique, avec autant de comparateurs par entrée qu'il y a d'opérandes possibles par instruction. Simplement, le processus de détection des opérandes prêts est légèrement ralenti : on ne vérifie qu'un opérande par cycle. Pour vérifier les deux opérandes d'une entrée, on doit attendre deux cycles. Enfin, certains chercheurs ont proposé des ''scheduler'' segmentées. Les instructions circulent à chaque cycle d'un segment vers le suivant : en conséquence, certains segments conservent les instructions les plus anciennes, un autre les instructions les plus jeunes, etc. Seul le denier segment, celui qui contient les instructions les plus vielles, peut émettre une instruction : la détection des opérandes se fait seulement dans le dernier segment, qui contient les instructions les plus anciennes. On économise ainsi beaucoup de comparateurs. Certains chercheurs ont tenté de pipeliner l'étape de sélection des opérandes, ainsi que l'étage d'arbitrage. Mais en faisant cela, il faut plusieurs cycles pour détecter qu'une instruction a ses opérandes prêts, ce qui pose problème face à de nombreuses dépendances RAW. Pour éviter de trop perdre en performances, certains chercheurs ont décidé d'utiliser des techniques pour prédire quelles seront les instructions dont les opérandes seront bientôt prêts. Si détecter qu'une instruction est prête prend n cycles, le processeur devra tenter de prédire la future disponibilité des opérandes n cycles en avance pour obtenir des performances optimales. ===Remplacer la mémoire associative par une RAM=== Une autre optimisation possible est de remplacer le ''scheduler'' par une mémoire RAM, dont chaque mot mémoire correspondrait à une entrée. Une telle optimisation permet en théorie de se passer des comparateurs associés à chaque entrée, mais au prix de l'ajout de circuits annexes potentiellement couteux. La première de ces techniques, la '''recherche directe par étiquette''' (direct tag search) fut créée par Weiss et son collègue Smith. Ils cherchaient à améliorer l'algorithme de Tomasulo, un algorithme qu'on expliquera dans quelques chapitres. Rappelons que chaque instruction produit un résultat, qui devra être rapatrié dans une ou plusieurs entrées de le ''scheduler''. L'optimisation de la recherche directe par étiquette fonctionne dans le cas où le résultat de l'instruction n'est utilisé que par une seule entrée, et pas plusieurs. Le principe est simple : chaque champ « opérande » d'une entrée est adressable via le nom de registre de cet opérande. Pour faire le lien entre entrée et nom de registre, la recherche directe par étiquette ajoute une table de correspondances matérielle, une mémoire RAM qui mémorise les adresses des champs « opérande » des entrées. Les adresses envoyées dans cette mémoire sont les noms de registres des résultats. Lors de l'émission, la table de correspondances est mise à jour. Les numéros des champs « opérande » réservés lors de l'émission sont mémorisés dans les mots mémoire qui correspondent aux deux registres sources. Toutefois, une petite vérification est faite lors de l'émission : s'il y a déjà une correspondance dans la table pour un registre source, alors une autre instruction compte lire ce registre. Pour éviter d'écraser les données de l'instruction précédente dans la table de correspondances, l'émission de l'instruction est bloquée. [[File:Recherche directe par étiquette.png|centre|vignette|upright=2|Recherche directe par étiquette.]] ==Les ''schedulers'' avec préplanification== Avec la '''préplanification''' (''prescheduling''), le ''scheduler'' est composée de mémoires FIFO dans lesquelles les instructions sont triées dans l'ordre d'émission. Il n'y a pas de logique d’émission proprement dite, celle-ci se bornant à vérifier si l'instruction située au début de la FIFO peut s’exécuter. Par contre, le préplanificateur détecte les dépendances et en déduit où insérer les instructions dans le tampon d'émission, à l'endroit le plus adéquat. [[File:Préplanification.jpg|centre|vignette|upright=2|Préplanification.]] ===L'usage de FIFO multiples=== La technique de préplanification la plus simple utilise plusieurs FIFO. Quand une instruction a une dépendance avec une autre instruction, les deux sont placées dans la même FIFO. Pour cela, le préplanificateur détecte les chaines d'instructions dépendantes, et place les instructions dans la FIFO adéquate. A chaque cycle, l'unité d'émission lit une micro-opération dans chaque FIFO et vérifie si elle peut l'émettre. Si la micro-opération n'a pas ses opérandes disponibles, ou qu'une dépendance structurelle survient, alors la FIFO est bloquée. La micro-opération attend que la dépendance soit résolue, bloquant toutes les instructions précédentes. Mais les autres FIFO ne sont pas bloquées, laissant de la marge de manœuvre. [[File:Préplanification par FIFO multiples.png|centre|vignette|upright=1.5|Préplanification par FIFO multiples.]] ===La technique du tampon trié=== La technique du '''tampon trié''' trie les instructions selon le temps d'attente avant leur exécution. Les instructions qui sont censées s’exécuter bientôt sont insérées au tout début de la FIFO, tandis que les instructions qui s’exécuteront dans un long moment sont insérées vers la fin. Là encore, l'unité d'émission lit une micro-opération dans la FIFO, et détermine si elle peut être émise. Si une dépendance survient, l'émission est retardée, et la FIFO est bloquée. [[File:Préplanification par tampon trié.png|centre|vignette|upright=1.5|Préplanification par tampon trié.]] La technique a cependant quelques problèmes assez importants. Le premier problème est que la FIFO est bloquée lorsqu'une micro-opération ne peut être émise. Le second problème est que le temps avant exécution n'est pas toujours connu, notamment pour les instructions d'accès mémoire. Et cela se répercute sur les instructions dépendantes de celles-ci. Pour résoudre ce genre de problèmes, l'usage d'un pipeline à ''replay'' est possible, et est même l'une des meilleures solutions possible, malgré ses défauts. L'idée est que les lectures sont pré-planifiées en supposant qu'elles font un succès de cache L1. Si la prédiction est fausse, la lecture est ré-exécutée plusieurs cycles plus tard, en supposant qu'elle fait un succès dans le cache L2, et ainsi de suite. Elle est alors ré-insérée dans la FIFO, elle est pré-planifiée une seconde fois. Il en est de même si une micro-opération ne peut pas être émise : il suffit de la réinsérer dans la FIFO au bon endroit, en attendant que ses dépendances soient résolues. Ainsi, l'instruction fautive ne bloque pas le ''scheduler'', et retente sa chance autant de fois qu'il le faut. [[File:Préplanification par fenêtre d’instruction scorebarodée.png|centre|vignette|upright=1.5|Préplanification par ''scheduler'' scorebarodé.]] Une autre solution utilise deux ''schedulers'' : une FIFO gérée par la préplanification, et une vraie ''scheduler'' pour les instructions dont le temps d'attente ne peut pas être déterminé. Il est possible de mettre cette dernière avant la préplanification, afin de gérer les temps d'attente des instructions d'accès mémoire. Quand le temps d'attente d'une lecture devient connu, ses instructions dépendantes sont gérées avec préplanification. [[File:Préplanification avec fenêtre d’instruction.png|centre|vignette|upright=2.5|Préplanification avec ''scheduler''.]] ===Les ''scheduler'' avec allocation temporelle statique=== L''''allocation temporelle statique''' correspond à une technique utilisée sur les processeurs Cuzco de l'entreprise Condor. La technique en question a été présenté en 2025, mais des idées similaires ont été présentées dans la littérature académique. Elle ressemble beaucoup aux techniques de pré-planification, avec cependant quelques différences. L'idée est simple : le processeur dispose de plusieurs ''scheduler'', qui mettent en attente les micro-opérations. Lors de l'étape de renommage de registres, le processeur détermine dans combien de cycles d'horloge la micro-opération sera prête pour exécution. La micro-opération est alors mise en attente durant ce nombre de cycles, dans les ''scheduler'', puis est émise une fois ce nombre de cycles écoulés. Ce faisant, les ''scheduler'' n'ont pas besoin de détecter la disponibilité des opérandes à chaque cycle, pour chaque micro-opération en attente. Le ''timing'' de l'émission des micro-opérations est décidé à l'avance. L'implémentation exacte n'est pas connue, mais plusieurs solutions sont imaginables. Par exemple, le ''scheduler'' peut simplement être composée de plusieurs mémoires de petite taille, chacune contenant les micro-opérations destinées à être exécutées dans N cycles, N étant différent pour chaque mémoire. Une autre solution, plus réaliste, utilise un ''scheduler'' dans laquelle la micro-opération est couplée à des champs pour les opérandes, et un champ compteur. Le champ compteur est initialisé avec le nombre de cycles à attendre, et est décrémenté à chaque cycle d'horloge. Quand il atteint zéro, la micro-opération est émise. Vous remarquerez que la méthode ne marche que si toutes les micro-opérations prennent un nombre fixe de cycles d'horloge. Et autant c'est le cas pour les micro-opérations arithmétiques ou logiques, autant les accès mémoire ne rentrent pas dans ce cadre. En théorie, on ne sait pas combien de temps prendra un accès mémoire. Et cette incertitude se répercute sur les instructions dépendantes d'un accès mémoire. Pour éviter cela, le processeur réutilise un pipeline à ''replay'' tel que vu dans le chapitre précédent. L'unité de renommage de registre suppose que tout accès mémoire fait un succès de cache L1, et décide des ''timings'' d'émission sous cette hypothèse. Si une lecture subit un défaut de cache, elle est ré-exécutée, de même que toutes les instructions dépendantes. Pour cela, le registre de destination de la lecture est marqué comme invalide, grâce à un bit spécifique attaché au registre. Toute instruction qui lit un opérande invalide est elle aussi ré-executée de zéro. Pour simplifier, l'unité d'émission ressemble à une unité d'émission dans l'ordre, avec un registre de disponibilité, qu'on aurait amélioré pour aller au-delà de la simple détection des dépendances d'instruction. Pour déterminer les ''timings'' d'émission, à savoir quand émettre une micro-opération, le processeur utilise une unité d'émission à deux étages. Le premier étage est appelé le ''register scoreboard'', le second étage est appelé la ''Time Ressource Matrix''. Les deux étages communiquent entre eux, comme on va le voir, et leurs noms donnent une idée de ce qu'ils font. Le premier étage gère les dépendances de registres, le second gère les dépendances structurelles. Le premier étage est un registre de disponibilité amélioré, qui gère les dépendances de registre. Cet étage sait quand tel registre sera écrit, et donc que l'opérande écrit dedans sera disponible à partir de tel cycle d'horloge. Il le sait car l'étage suivant l'aura prévenu, mais laissons cela de côté pour le moment. Quand une micro-opération rentre dans cet étage, il vérifie les dépendances avec les registres et les micro-opérations antérieures. Vu qu'il sait quand les registres seront disponibles, il peut déterminer quand l'instruction pourra s'exécuter. Par exemple, si une micro-opération lit les deux registres R7 et R15, qui sont disponibles respectivement dans 5 et 7 cycles, le premier étage sait que la micro-opération devra attendre 7 cycles. Mais tout cela ne suffit pas à déterminer quand émettre une micro-opération. En effet, il fait aussi gérer les dépendances structurelles, ce qui est le boulot du second étage. Le second étage utilise pour cela une ''Time Ressource Matrix'', qui mémorise l'occupation de diverses "ressources", pour les 256 cycles d'horloge à venir. Les ressources en question sont les ports de lecture/écriture du banc de registre, les ALUs utilisées, si la micro-opération utilise l'unité mémoire, etc. Le second étage prend en entrée une micro-opération, détermine quelles "ressources" elle utilise, puis regarde leur disponibilité. Elle détecte alors les dépendances structurelles et détermine alors quand peut s'exécuter la micro-opération. Elle peut retarder l'émission de quelques cycles, si une dépendance structurelle est détectée. Une fois sortie du second étage, on sait quand la micro-opération va être émise, à quel cycle précisément. Et vu que la durée de l'instruction est fixe, on sait quand cette micro-opération va se terminer, quand son résultat sera disponible. Cela permet de mettre à jour la ''Time Ressource Matrix'', pour préciser que le port d'écriture sera occupé à tel moment. De plus, cette information est transmise au premier étage, qui sait alors quand est enregistré le résultat dans le registre de destination. C'est comme cela que le premier étage sait quand un registre est disponible : le second étage le prévient, quand il émet une instruction ! La ''Time Ressource Matrix''mémorise l'occupation des "ressources" pour les 256 cycles d'horloge à venir. Cependant, elle ne vérifie pas les dépendances pour les 256 cycles suivants. Quand elle reçoit une micro-opération, elle teste les dépendances structurelles pour seulement les 8 prochains cycles maximum. Si la micro-opération ne peut pas être émise pendant ces 8 cycles, le pipeline est bloqué, un ''pipeline stall'' est émis. Pour être plus précis, vu que le processeur peut décoder 8 micro-opérations en même temps, cela permet de ne consulter que 64 cycles d'horloge sur les 256. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les premiers processeurs Intel | prevText=Les premiers processeurs Intel | next=Le renommage de registres | nextText=Le renommage de registres }} </noinclude> topdsafzqi31yuu6htdr5szlhd314g1 773634 773629 2026-09-29T21:11:24Z Mewtow 31375 /* Les scheduler basées sur une mémoire associative */ 773634 wikitext text/x-wiki Dans les chapitres précédents, nous avons parlé des techniques dites d''''émission dans l'ordre'''. L'idée est d’exécuter une nouvelle micro-opération à chaque cycle, dans des unités de calcul séparées. Les instructions sont émises consécutivement, mais les instructions s’exécutent en parallèle dans des unités de calcul séparées. Par contre, quand l'unité d'émission ne peut pas émettre une instruction, elle bloque tout le pipeline. Les instructions qui suivent sont elles aussi bloquées, elles doivent attendre leur tour, même si elles sont en capacité de s'exécuter. Les techniques d'exécution dans le désordre que nous allons voir dans ce chapitre corrigent ce point précis. Elles sont dites à '''émission dans le désordre'''. Elles se distinguent des précédentes sur un point précis : quand l'unité d'émission bloque l'émission d'une instruction, les instructions suivantes peuvent poursuivre. L'émission des instructions peut donc se faire dans le désordre, dans le sens où une instruction peut être émise alors qu'une instruction précédente ne l'est pas encore. Mais avant de poursuivre, quelques point niveaux terminologie : * L'émission dans le désordre est un terme parlant et assez précis. Malheureusement, la terminologie la plus utilisée par d''''exécution dans le désordre'''. Et nous utiliserons ce terme dans la suite du cours, histoire de ne pas trop dévier de la nomenclature habituelle. * Nous utiliserons parfois l'abréviation OOO pour parler d'exécution dans le désordre. L'abréviation est celle de ''Out Of Order Execution''. * Nous utiliserons aussi l'abréviation ''µop'' pour parler de micro-opération, ''µops'' au pluriel pour parler de plusieurs micro-opérations, ou des micro-opérations en général. L'exécution dans le désordre ne gère en effet que des µops, elle se situe après l'étape de décodage. Pour décrire comment est implémentée l'émission dans le désordre, il faut commencer par parler des processeurs sans. Les processeurs sans exécution dans le désordre ont une unité d'émission qui bloque tout le pipeline dès qu'une µop ne peut pas être émise. Pour limiter l'impact de ce blocage, quelques rares processeurs incorporent une '''file de micro-opération''', une mémoire FIFO qui met en attente les µops. Vu que c'est une mémoire FIFO, les µops sont émises dans l'ordre, à savoir l'ordre d'ajout, dans l'ordre de décodage. Le schéma ci-dessous illustre une telle file d'attente couplée à un ''scoreboard''. L'exécution dans le désordre améliore la file de µops sur un point : ce n'est plus une mémoire FIFO. Les µops sont insérées dans l'ordre, mais peuvent sortir dans le désordre (être émises dans le désordre). La file de µops devient alors un '''''scheduler''''', terme anglais que je ne compte pas traduire. Un terme équivalent est '''''scheduler''''', terme traduit directement de l'anglais ''instruction Window''. Terme assez trompeur, car elles mettent en attente des µops, pas des instructions. [[File:Différence file µops et fenêtres instruction.png|centre|vignette|upright=2|Différence file µops et ''schedulers'' ]] Le ''scheduler'' émet une µop dès que ses opérandes sont disponibles. Par disponible, on veut dire présent soit dans le réseau de contournement, soit dans les registres. Le ''scheduler'' détecte automatiquement quand les opérandes d'une µop sont disponibles, grâce à une unité d'émission intégrée. L'unité d'émission et le ''scheduler'' sont fusionnés ensemble, dans un seul circuit, mais nous allons dire qu'ils sont conceptuellement séparés pour le moment. À chaque cycle, l'unité d'émission consulte les µops en attente pour détecter lesquelles peuvent s'exécuter. Le ''scheduler'' est spécialement être conçue pour, c'est une sorte de mémoire associative très complexe, comme on le verra dans ce qui suit. [[File:OOO Issue.png|centre|vignette|upright=2.5|Exécution dans le désordre avec un ''scheduler'']] Une fois qu'une µop sort du décodeur d'instructions, elle est ajoutée en parallèle dans le ''scheduler'' et le ROB. La raison est que les µops quittent le ''scheduler'' dans le désordre, et qu'elles doivent être remises en ordre par la suite. Le ROB s'occupe de cette remise en ordre, mais il a besoin de savoir dans quel ordre les µops sont censées être, et cet ordre est celui du décodage. Aussi, pour remplir le ROB, la seule opportunité est en sortie de l'unité de décodage. Dans le cas où une instruction est décodée en plusieurs micro-opérations, elles sont toutes insérées en même temps dans le ''scheduler'' et le ROB, en tenant compte de leur ordre. L'implémentation la plus simple de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Les µops décodées sont accumulées dans le ''scheduler'', où elles attendent leur tour. le ''scheduler'' sert donc de file d'attente. Avant de poursuivre, précisons que les micro-opérations mémoire sont à part des autres, pour diverses raisons. Une de ces raisons est que les dépendances de données sont classées en deux types : les dépendances de registre et les dépendances d'adresse. Et les deux sont fondamentalement différentes. Autant on peut détecter les dépendances de registre lors de l'émission, autant c'est plus compliqué avec les dépendances d'adresse. De plus, rappelons que si les lectures peuvent s'exécuter dans le désordre, les écritures doivent s'exécuter dans l'ordre, ou du moins en donner l'illusion. Pour cela, le processeur remet les écritures dans l'ordre avec une sorte de mini-ROB intégré à l'unité mémoire, appelée la file d'écriture. Elle complémente le ROB, qui lui ne gère que les écritures dans les registres, mais les deux collaborent. La file d'écriture envoie une écriture à la mémoire RAM quand le ROB lui dit que c'est bon, les instructions précédentes sont terminées ''dans l'ordre du programme''. Les processeurs modernes ajoutent des techniques d'exécution dans le désordre des accès mémoire, mais nous les verrons dans un chapitre dédié. Elles permettent d'utiliser un ''scheduler'' unique, qui mémorise aussi les µops mémoire. Si elles sont mises en place, l'unité mémoire n'a pas besoin de file de µops séparée. L'idée est que les dépendances de registre sont traitées par le ''scheduler'', mais que l'unité mémoire gére les dépendances d'adresse. Les dépendances d'adresse sont gérées par des techniques de ''désambiguation mémoire'', qui auront droit à un chapitre dédié. [[File:Processeur avec exécution dans le désodre des accès mémoire.png|centre|vignette|upright=2|Processeur avec exécution dans le désodre des accès mémoire]] Les processeurs assez anciens n'autorisaient pas d'exécution dans le désordre des accès mémoire. Concrètement, les accès mémoire devaient se faire dans l'ordre, mais les autres µops pouvaient être exécutées dans le désordre. Il s'agit donc d'un ordre entre µops mémoire, pas entre µops mémoire et autres µops. Les µops entières et flottantes pouvaient être exécutées avant une µops mémoire qui est avant elle dans l'ordre du programme, ce n'est pas un problème. Pour garantir l'ordre des µops mémoire, l'unité mémoire est précédée par une file de micro-opérations séparée, pour forcer l'exécution dans l'ordre des accès mémoire. De plus, les µops mémoire ne peuvent pas utiliser le ''scheduler''. Dit autrement, le ''scheduler'' ne mémorise pas de µops mémoire. Après le décodage, les µops sont réparties soit dans la file de µops mémoire, soit dans le ''scheduler''. Le décodeur classe les µops suivant que ce sont des µops mémoire ou non, et les envoient à la bonne destination. Dans ce chapitre, on supposera que c'est cette solution qui est utilisée. [[File:Processeur avec émission dans l'ordre des accès mémoire.png|centre|vignette|upright=2|Processeur avec émission dans l'ordre des accès mémoire]] ==L'implémentation d'un ''scheduler'' : généralités== Un ''scheduler'' est une mémoire qui mémorise des micro-opérations. Elle est cependant plus complexe qu'une mémoire RAM ou qu'une FIFO et ressemble un petit peu à une mémoire cache. Elle dispose d'un port d'écriture et d'un port de lecture, au minimum. Le port d'écriture permet à l'unité de décodage d'insérer une micro-opération dedans, d'ajouter la micro-opération qui vient d'être décodée. Si une instruction machine est décodée en plusieurs micro-opération, deux possibilités. La première est de les insérer un par un, ce qui fait qu'on peut se contenter d'un seul port d'écriture. L'autre possibilité est de les ajouter en même temps, ce qui demande plusieurs ports d'écriture. Le port de lecture sert à émettre une instruction. On part du principe que le ''scheduler'' ne peut émettre qu'une seule instruction à la fois, car les processeurs que nous avons vu précédemment sont de ce type. Mais nous verrons dans quelques chapitres qu'il existe des processeurs dits superscalaires, qui sont capables d'émettre plusieurs instructions par cycle. Dans ce cas, le ''scheduler'' a un seul port de lecture. Un processeur superscalaire, quant à lui, doit avoir un port de lecture par unité de calcul, ce qui fait beaucoup plus. Les ''schedulers'' sont composées d''''entrées''', des mots mémoire qui stockent une instruction. Une instruction réserve une entrée après son décodage et la libère dès qu'elle est envoyée aux unités de calcul. Une entrée contient l'opcode (les signaux de commande à envoyer à l'ALU), le registre de destination du résultat, les registres de chaque opérande, et éventuellement des signaux de commande en plus. De plus, chaque opérande est couplée à un bit de disponibilité, qui indique si elle est disponible. Quand un opérande est écrit dans les registres, le bit de présence correspondant est mis à jour. Enfin, chaque entrée possède un bit ''empty'' qui indique si elle est vide, cette information étant utile pour réserver des entrées. [[File:Entrée d'une station de réservation - sans les tags.png|centre|vignette|upright=3|Entrée d'un ''scheduler'']] ===Les stations de réservation=== Les '''stations de réservation''' sont des ''scheduler'' particulières, qui sont capables de mémoriser les opérandes des instructions. Les entrées des stations de réservation sont identiques à celle des autres ''scheduler'', si ce n'est que les opérandes de l'instruction sont enregistrés directement dans des champs séparés. Il y a deux champs, un par opérande, pour stocker l'opérande elle-même, lue depuis les registres ou obtenue via le réseau de contournement. Notons que les champs pour les opérandes viennent en plus des champs pour les noms de registres, encore que les deux peuvent être fusionnés si on veut optimiser le tout. [[File:Entrée d'une station de réservation.png|centre|vignette|upright=3|Entrée d'une station de réservation.]] Précisons que la terminologie n'est pas très fiable. Les termes "''scheduler''" et "station de réservation" ne regroupent pas du tout la même chose d'un papier de recherche à l'autre, d'un bouquin à l'autre, d'un chercheur à l'autre, d'un ingénieur à l'autre, d'un professeur à l'autre. Le terme initial vient pourtant de l'article original sur l'algorithme de Tomasulo, où il désignait un ''scheduler'' associée à une unité de calcul précise. Mais le terme a ensuite été réutilisé, ce qui fait que certains processeurs avec plusieurs unités de calcul sont décrits comme ayant une unique station de réservation. En bref : c'est le bazar ! Mais nous en reparlerons dans le chapitre sur le renommage de registres, car c'est la place idéale pour les aborder. Toujours est-il que j'ai fait le choix de confondre les concepts de ''scheduler'' et de station de réservation avec les concepts de '''lecture avant émission''' et de '''lecture après émission'''. La différence entre les deux est que les registres sont lus après émission avec un ''scheduler'', avant avec des stations de réservation. Dans le cas "avant émission", les opérandes sont mémorisés dans la station de réservation. Et cette différence a une influence sur le pipeline du processeur, le banc de registres et tout ce qui s'ensuit. Un désavantage de la lecture avant émission est qu'il faut stocker les opérandes après lecture, ici dans les stations de réservation. Mais un avantage est que le banc de registre a besoin de moins de ports de lecture, car une bonne partie des opérandes sont fournies par le système de contournement. Nous verrons cela dans le détail dans le chapitre sur les processeurs superscalaires. [[File:Processeur avec plusieurs ''scheduler''.png|centre|vignette|upright=2.5|Lecture après émission.]] [[File:Read Before Issue.png|centre|vignette|upright=2.5|Lecture avant émission.]] ===La logique d'éveil et de sélection=== Dans le cas qui va suivre, on suppose que le processeur ne peut émettre qu'une instruction à la fois. Chaque cycle, une instruction est sélectionnée et est envoyée dans le chemin de données, soit à une ALU, soit à une unité d'accès mémoire. La sélection d'une instruction est effectuée par l'unité d'émission, qui est aussi appelée le '''''scheduler'''''. Elle gère la disponibilité des opérandes et la disponibilité des unités de calcul adéquate. Le choix de l'instruction émise doit être le plus pertinent possible, pour des raisons de performances. Pour le premier point, l'unité d'émission détermine quelles instructions sont candidates pour l'émission. Les ''instructions candidates'' sont celles dont tous les opérandes sont prêts. Le processeur contient un circuit qui détecte les instructions candidates : la '''logique d’éveil''' (''wake-up logic''). Une fois que la logique d'éveil a fait son travail, une instruction est choisie pour s’exécuter en fonction de la disponibilité des unités de calcul adéquates. Ce rôle est dévolu à un circuit qu'on appelle la '''logique de sélection''', ou ''select logic''. [[File:Fonctionnement complet de la logique d’émission.jpg|centre|vignette|upright=1.5|Fonctionnement complet de la logique d’émission.]] La logique de sélection doit gérer le fait que les unités de calcul du processeur ne sont pas toutes identiques. Déjà, un processeur a généralement des unités séparées pour les instructions entières et flottantes, des unités spécialisées dans les accès mémoire, parfois des unités spécialisées pour les branchements. Une instruction doit être attribuée à la bonne unité de calcul, on ne doit pas envoyer une instruction entière dans une unité de calcul flottante. De plus, parmi les unités de calcul entières, toutes ne sont pas identiques. Par exemple, il est fréquent d'avoir plusieurs unités de calcul spécialisées dans les opérations simples (additions, soustractions, opérations logiques) avec une unité pour les multiplications/divisions séparées, parfois une unité spécialisée pour les décalages/rotations, etc. Là encore, allouer la bonne instruction à la bonne ALU est complexe. Plus les unités de calcul sont hétérogènes, plus la logique de sélection est compliquée. Les logiques d'éveil comme de sélection sont assez complexes. Comme on le verra plus bas, la logique de sélection la plus simple, qui gère une seule unité de calcul, est basée sur un encodeur à priorité, couplé à d'autres circuits. Et pour gérer plusieurs ALUs, il faut mettre des encodeurs en cascade. Le résultat est que même en prenant une logique de sélection simple, elle sera assez lente et gourmande en circuits. Aussi, la logique de sélection met souvent un cycle d'horloge entier pour faire son travail, elle a son propre étage de pipeline attribué. La logique d'éveil est dans le même cas, ce qui fait qu'émettre une micro-opération demande deux cycles d'horloge. Le défaut est que cela rajoute des cycles d'horloges entre le ''scheduler'' et l'ALU, ce qui complique la gestion du pipeline. Ces cycles de retard sont à prendre en compte au moment d'émettre les instructions, les ''scheduler'' doit en tenir compte pour des performances optimales. Sans tenir compte de ces cycles de retard, les instructions arrivent en retard de quelques cycles à l'ALU, cycles de retard durant lesquels l'ALU n'a pas fait de calcul et a été sous-utilisée, sans compter que le système de contournement n'est pas utilisé au mieux. Et le problème est encore plus important sur les processeurs avec des stations de réservation, qui utilisent la "lecture après émission" : cela rajoute un cycle d'horloge en plus, un temps de retard en plus. ===La logique d'éveil : l'émission anticipée=== La logique d'éveil doit tenir compte du fait qu'il y a plusieurs étages entre l'émission et l'exécution sur une unité de calcul. Par exemple, un processeur a souvent entre un et à cinq étages entre la file d'attente et les unités de calcul. Il faut lire les registres, gérer le contournement, et cela peut prendre quelques cycles d'horloge. Sur le Pentium 4, on trouve 6 étages entre le ''scheduler'' et l'entrée de l'ALU. Si les micro-opérations sont émises quand les opérandes sont disponibles, il y aura un délai de quelques cycles avant qu'elles atteignent l'ALU. Alors qu'idéalement, on souhaiterait que la micro-opération atteigne l'ALU dès que ses opérandes sont disponibles, pour profiter des techniques de contournement. Pour cela, la logique d'éveil émet les instructions quelques cycles en avance pour qu'elles arrivent au bon moment. Il s'agit d'une technique d''''émission anticipée''', dont nous avions parlé dans le chapitre sur le contournement. : Il faut noter que le problème se pose plus avec des ''schedulers'' qu'avec des stations de réservation. Les premières ont un étage en plus entre émission et ALU, vu qu'il faut lire des registres après l'émission. L'émission anticipée demande d'émettre un signal d'éveil en avance de quelques cycles, pile au bon moment. Par exemples, si on a deux étages entre l'ALU et l'unité d'émission, le signal de réveil sera généré deux cycles avant que le résultat soit effectivement calculé. L'implémentation varie, mais deux solutions sont possibles. La première est de générer le signal d'éveil dans l'ALU, ce qui n'a de sens que pour les opérations comme les multiplications ou les divisions, qui prennent plusieurs cycles. Une autre technique génère le signal de réveil dans une structure centralisée, spécialisée dans la génération des signaux d'éveil. L'unité de composée d'un registre à décalage par registre. Imaginons qu'une instruction est émise, que cette instruction mette N cycles à s'exécuter, et qu'elle écrive dans un registre de destination. L'unité sélectionne alors le registre à décalage associé au registre de destination, et met le bit numéro N à 1. Le registre décalé d'un cran à chaque cycle. Quand le bit sortant est un 1, alors le signal de validité pour l'opérande est généré. L'émission anticipée marche bien si l'instruction a une durée fixe, connue à l'avance. Et autant c'est le cas pour les instructions arithmétiques et logiques, autant ce n'est pas le cas pour les accès mémoire. Les accès mémoire ont une latence variable : quelques cycles pour un succès de cache, plusieurs dizaines de cycles pour un défaut de cache L1, pas loin de la centaine pour un défaut de cache L2, etc. Et cela pose des problèmes pour l'émission anticipée. L'émission en avance pour les accès mémoire est purement spéculative : le processeur émet des instructions en supposant que la lecture entrainera un succès de cache, quitte à annuler l'instruction en cas de défaut de cache. Mais faire ainsi demande non seulement d'annuler les instructions émises en avance, mais aussi de ne pas retirer les instructions émises en avance de le ''scheduler''. Elles sont émises, mais une copie de sauvegarde est conservée dans le ''scheduler''. Si le processeur détecte un défaut de cache, il peut alors ré-exécuter l'instruction. S'il détecte un succès de cache, les instructions lecture-dépendante sont retirées de le ''scheduler'', la copie de sauvegarde est devenue inutile et est donc jetée. ===La logique de sélection : âge ou position ?=== La logique de sélection est primordiale pour de bonnes performances. Il existe deux méthodes principales pour sélectionner l'instruction à exécuter. La première est la plus simple : elle se base sur lé numéro de l'entrée. En effet, un ''scheduler'' est avant tout une sorte de mémoire, un mix entre mémoire associative, mémoire RAM, et FIFO. Et chaque entrée a un numéro, une adresse mémoire. Nous parlerons de numéro dans ce qui suit, car ce sera plus simple, le terme d'adresse mémoire étant peut-être un peu exagéré dans le contexte des ''scheduler''. Toujours est-il que le ''scheduler'' est adressable dans le sens où on peut lui envoyer le numéro de l'entrée voulue, et le ''scheduler'' renvoie le contenu de l'entrée sur son port de lecture. Et c'est ce que fait la logique de sélection : elle génère le numéro de l'entrée à lire. Le numéro est alors envoyé sur l'entrée d'adresse du ''scheduler'', et elle fournit la micro-opération associée sur son port de lecture, son '''port d'émission'''. La première méthode de sélection, donc. Elle est basée sur le numéro de l'entrée. Si plusieurs entrées sont éveillées, la logique de sélection prend celle avec le plus petit numéro. Elle porte le nom de '''sélection par position''', sous-entendu position dans le ''scheduler''. Vous l'avez peut-être deviné, mais la logique de sélection est alors un encodeur à priorité. Le circuit de sélection ne se résume donc pas seulement à un encodeur à priorité, mais c'est le circuit central. L'avantage d'une telle méthode de sélection est qu'elle est simple à implémenter : un encodeur à priorité est un circuit connu, facile à implémenter. Mais on remarque un défaut : un encodeur est un circuit assez rapide, mais qui utilise beaucoup de transistors, beaucoup de portes logiques, surtout si on veut qu'il soit rapide. Ce qui explique que la logique de sélection ait son propre étage de pipeline rien que pour elle. La seconde méthode s'appelle la '''sélection par âge''', au nom assez transparent. L'idée est de privilégier l'émission de l'instruction la plus ancienne. Elle demande que le ''scheduler'' trie les micro-opérations par ordre d'insertion dans le ''scheduler'', ce qui en fait une pseudo-FIFO. Le tri est partiel, car les instructions peuvent sortir du ''scheduler'' à tout moment. Compacter le ''scheduler'', à savoir regrouper toutes les entrées valides est une idée, mais elle est compliquée à implémenter. Aussi, elles préfèrent encoder des informations sur l'ordre d'émission dans chaque entrée. L'encodeur à priorité doit alors travailler non pas sur des nombres entiers liés à l'ordre d'insertion dans la pseudo-FIFO. Elle est encore plus gourmande en circuits que la méthode précédente. Les processeurs haute performance utilisent souvent des méthodes hybrides. Par exemple, les processeurs AMD de microarchitecture Bulldozer utilisaient une méthode intermédiaire. Ils utilisaient un ''scheduler'' couplée à un encodeur à priorité pour la sélection par position, mais complémentaient le tout avec une unité qui mémorisait l'instruction la plus ancienne dans le ''scheduler''. Le mécanisme de sélection par âge était utilisé en priorité. Mais si l'instruction la plus ancienne n'était pas prête, le processeur basculait sur le mécanisme de sélection par position. ===La compaction des ''scheduler''=== À chaque cycle, les instructions décodées sont ajoutées dans le ''scheduler'', dans des entrées vides. Vu que les instructions quittent celle-ci dans le désordre, ces vides sont dispersés dans le ''scheduler'', ce qui pose problème pour déterminer où placer les nouvelles instructions. La solution la plus triviale consiste à conserver une liste des vides, mise à jour à chaque insertion ou émission d'instruction. Une autre solution consiste à éliminer les vides en compactant le ''scheduler'' à chaque cycle d'horloge. Des circuits se chargent de détecter les vides et de regrouper les instructions en un unique bloc. Il faut signaler que certains processeurs arrivent à se passer de cette étape de compactage, mais au prix de ''scheduler'' nettement plus complexes. Autre problème : quand il faut choisir quelle instruction émettre, il y a toujours plusieurs candidats. Si on choisit mal, des instructions restent en attente trop longtemps parce que d'autres instructions plus jeunes leur passent devant. Pour éviter cela, les instructions les plus vielles, les plus anciennes, sont prioritaires. Pour cela, on peut utiliser une FIFO un peu spéciale pour le ''scheduler''. Si les ajouts d'instruction se font dans l'ordre, les instructions ne quittent pas forcément le ''scheduler'' dans l'ordre imposé par une FIFO : les instructions restent triées dans leur ordre d'ajout, même s'il y a des vides entre elles. Dans ces conditions, il est préférable que le compactage conserve l'ordre FIFO des instructions. Dans ces conditions, l'instruction la plus ancienne est celle qui est située à l'adresse la plus faible : le circuit de sélection peut donc être fabriqué avec des encodeurs, et est relativement simple. ==Les ''schedulers'' basées sur une matrice de dépendances== L'implémentation la plus simple étend le fonctionnement d'un pipeline dynamique usuel. Rappelez-vous le chapitre sur les pipelines dynamiques. Nous avions vu que de tels pipelines émettaient une instruction par cycle, quitte à émettre des bulles de pipeline en cas de dépendance bloquante. Et il est possible d'améliorer leur unité d'émission pour qu'elle soit compatible avec l'exécution dans le désordre. ===Rappels sur le registre de réservation/disponibilité=== L'émission d'une instruction est gouvernée par un ''registre de réservation'' qui indique quels registres sont réservés par une instruction, et ceux qui sont libres. Un registre réservé est un registre qui sera écrit par une instruction en cours d'exécution, mais qui n'a pas encore écrit son résultat. Les instructions candidates doivent avoir leurs opérandes dans des registres libres. Sinon, c'est signe que leurs opérandes sont réservés en écriture, donc pas encore écrites, donc pas disponibles. Si une instruction candidate veut lire ce registre, c'est signe qu'il y a une dépendance RAW : elle veut lire un registre réservé, qui est destiné à être écrit par une instruction en vol. Si elle veut écrire, c'est signe qu'elle veut écrire dans un registre où une autre instruction veut écrire : c'est une dépendance WAW. Dans les deux cas, l'instruction n'est pas émise. Le registre de réservation encode les registres réservés comme suit : chaque bit est associé à un registre. Le bit numéro 0 est associé au registre numéro 0, le bit numéro 1 au registre numéro 1, etc. Là, En clair, les numéros de registres réservés sont encodés en représentation non pas binaire, mais en représentation ''one-hot'' (vue au premier chapitre). {|class="wikitable" |+ Registre de réservation |- ! Registre 7 !! Registre 6 !! Registre 5 !! Registre 4 !! Registre 3 !! Registre 2 !! Registre 1 !! Registre 0 |- | 0 || 0 || 1 || 0 || 0 || 1 || 0 || 0 |} Avant d'émettre une instruction, l'unité d'émission extrait les registres opérande/destination et les convertis dans la même représentation que le registre de réservation, à savoir en représentation ''one-hot''. Le circuit de traduction binaire vers ''one-hot'' est, pour rappel, un simple décodeur. Puis, on fait un OU logique entre les sorties des décodeurs. Le résultat est un masque qui indique quels registres sont lus par l'instruction, encodé en représentation ''one-hot''. Appelons-le le '''masque d'opérandes'''. Le masque est alors comparé au registre de réservation pour vérifier si l'instruction peut être émise. [[File:Unité d'émission simple, dans l'ordre.png|centre|vignette|upright=2|Unité d'émission simple, dans l'ordre]] Si l'émission est autorisée, le registre de réservation est là aussi mis à jour. Le registre de réservation est aussi mis à jour dès qu'une instruction enregistre son résultat dans les registres, ou alors dès qu'il est disponible pour le contournement. Le bit associé au registre repasse alors à 0 (ou à 1). Sans contournement, la mise à jour se fait alors à la toute fin de l'instruction, quand elle se termine, lors de la dernière étape d'enregistrement, à la fin de son pipeline. Avec, elle se fait quand l'instruction quitte l'unité de calcul. ===L'extension à l'exécution dans le désordre : l'éveil par matrice de bits=== La différence entre un pipeline dynamique et l'exécution dans le désordre est que l'on passe d'une instruction à émettre à plusieurs. Plusieurs instructions sont mises en attente dans un ''scheduler'', et y attendent leur tour. L'idée est alors d'envoyer le registre de disponibilité à toutes les entrées, à toutes les instructions en attente. Ainsi, on sait quelles sont les instructions qui peuvent s'exécuter et celles qui ne le peuvent pas. L'implémentation est assez simple, elle ressemble beaucoup à l'implémentation d'un pipeline dynamique simple, si ce n'est que des circuits sont dupliqués. L'implémentation utilise des ''scheduler'' légèrement différentes de celles introduites plus haut. Elles n'utilisent notamment pas de bits de disponibilité, mais autre chose. Lorsqu'une instruction est ajoutée à le ''scheduler'', le masque de disponibilité des opérandes est stocké dans le ''scheduler''. A chaque cycle, le registre de disponibilité est envoyé à toutes les entrées, et est comparé avec tous les masques de disponibilité des opérandes. Si une comparaison renvoie un 1, alors l'instruction de l'entrée est une instruction candidate à l'émission. [[File:Unité d'émission dans le désordre basée sur un registre de disponibilité.png|centre|vignette|upright=2.5|Unité d'émission dans le désordre basée sur un registre de disponibilité]] L'ensemble est implémenté avec l'aide d'une '''matrice de bits''', où chaque ligne correspond à une entrée et chaque colonne à un registre. À chaque croisement entre une ligne et une colonne, on trouve un bit. Si le bit de la ligne n et de la colonne m est à 1, cela veut dire : l'instruction dans l'entrée n a besoin de lire le registre m. S’il est à 0, alors cela veut dire que l'instruction stockée dans la ligne n'a pas besoin de la donnée dans le registre m. [[File:Planificateur à matrice de bits.jpg|centre|vignette|upright=2|Planificateur à matrice de bits.]] Lorsqu'une instruction réserve une entrée, elle initialise la ligne en fonction des registres qu'elle souhaite lire. Pour vérifier si une instruction a ses opérandes prêts, le processeur compare le registre de disponibilité à la ligne associée à l'instruction/entrée. A chaque intersection ligne-colonne, se trouve un comparateur de 1 bit, qui détecte si le registre est demandé et disponible. Les résultats de cette porte sont ensuite envoyés à une porte ET, qui fait le gros du travail. [[File:Logique de détection de la disponibilité d'une instruction.jpg|centre|vignette|upright=2|Logique de détection de la disponibilité d'une instruction.]] ==Les ''schedulers'' basées sur une mémoire associative== Les processeurs modernes utilisent une mémoire associative pour le ''scheduler''. Les mémoires associatives ont été abordées il y a quelques chapitres, mais faisons quelques rappels. Les mémoires associatives servent à accélérer la recherche de données dans un ensemble. Or, un ''scheduler'' vérifie régulièrement si chaque entrée est prête. Il s'agit d'un processus de recherche d'une instruction qui respecte une condition bien précise dans la mémoire, ce qui fait que les mémoires associatives sont donc tout indiquées. Comme vous le savez, les signaux de commande d'une instruction sont propagés avec celle-ci dans le pipeline, le nom du registre de destination ne faisant pas exception. Le nom de registre est envoyé à le ''scheduler'' lors de l'écriture du résultat dans les registres. S'il y a correspondance, l'opérande est disponible et son bit de disponibilité est mis à 1. On peut adapter cette méthode pour tenir compte du contournement assez simplement. [[File:Détection des dépendances par propagation du registre de destination.png|centre|vignette|upright=2|Détection des dépendances par propagation du registre de destination.]] En conséquence, le circuit de détection des dépendances est constitué d'un grand nombre de comparateurs : un par champ « nom de registre » dans chaque entrée. La logique d'éveil/''wake up'' regroupe tous les comparateurs, la logique de sélection est un circuit situé en-dehors de la mémoire associative. Les entrées sont dans la mémoire associative elle-même. [[File:Gestion des bits de validité.png|centre|vignette|upright=2|Gestion des bits de validité.]] L'implémentation la plus simple est celle du schéma précédent, où on utilise une mémoire associative unique. Une version plus élaborée sépare le ''scheduler'' en deux parties : une mémoire qui mémorise les registres des opérandes, une autre mémoire pour le reste. La mémoire pour les registres opérandes est la mémoire associative proprement dite, c'est elle qui est associée aux comparateurs, à la logique de ''wake-up''/réveil, etc. Par contre, l'autre mémoire est une mémoire RAM simplifiée, qui mémorise les informations qui n'ont pas besoin des comparateurs. L'opcode de l'instruction est là-dedans, par exemple. le ''scheduler'' est donc une sorte de mémoire associative améliorée. Il se trouve que c'est aussi le cas du ROB. Et il est possible de fusionner le tampon de ré-ordonnancement avec le ''scheduler'' dans une structure unique. La différence avec un ''scheduler'' normal est que les entrées sont libérées non pas quand l'instruction est exécutée/émise, mais quand elle termine son exécution et quitte le ROB. le ''scheduler'' incorpore des bits dans chaque entrée, pour savoir si la µops associée a été émise et est en cours de traitement dans les ALUs. La méthode a notamment été utilisée sur les processeurs d'architecture K6 d'AMD. Le tout donnait une structure appelée le '''DRIS''' (''deferred scheduling register renaming instruction shelf''). Les processeurs PA 8000 de HP étaient aussi vraisemblabment dans ce cas, aussi. ===Les optimisations de la consommation d'énergie : la désactivation des portions inutilisées=== Le problème avec des ''scheduler'' de ce type est leur forte consommation énergétique, ainsi que le grand nombre de portes logiques utilisées, qui deviennent prohibitifs pour des ''scheduler'' un peu grosses. Pour résoudre ce problème, certains ont optimisé les comparateurs. D'autres ont tenté de profiter du fait que la majorité des bits dans les entrées sont composés de zéros. Bref, les optimisations purement matérielles sont légion. Une première solution est de désactiver les entrées qui sont inutilisées, vides, sans instruction. Pour cela, on fait précéder les comparateurs par un circuit qui les connecte ou déconnecte des lignes de bit. Le circuit est commandé par le bit ''empty'' qui indique si une entrée est vide ou non. L'avantage est que la consommation d'énergie de le ''scheduler'' devient alors proportionnelle au nombre d'entrées non-vides, et non au nombre d'entrées total. Du moins, en apparence, les entrées non-utilisées doivent quand même être alimentées pour fonctionner, mais l'activité de comparaison disparait dans les entrées vides. Il est possible d'étendre cette technique aux entrées dont les opérandes sont prêts. Les gains sont généralement assez bons, avec une réduction de consommation variant entre 30 et 50%, avec une implémentation très simple et très économe en circuits. Une autre solution, assez simple à mettre en place, consiste à désactiver une partie de le ''scheduler'' sin elle est inutilisée. Pour cela, il faut segmenter le ''scheduler'' avec la technique du ''wire partitionning''. Pour rappel, un ''scheduler'' est une mémoire associative. Et comme toute mémoire associative, elle contient des fils, les lignes de bit, qui relient les entrées/sorties à toutes les cellules mémoire. Plus une ligne de bit est longue, plus elle consomme d'énergie et plus le temps de lecture/écriture est long. L'idée est de segmenter les lignes de bits en plaçant des répéteurs qui recopient la tension d'un segment au suivant. Les répéteurs sont des tampons trois-états, ce qui permet de déconnecter les portions inutilisées de la ligne de bit. Ce faisant, le ''scheduler'' est découpée en segments, qui peuvent être désactivés si besoin. S'il y a peu d'instructions chargées dans le ''scheduler'', les portions inutilisées sont désactivées. La technique marche d'autan mieux si les instructions sont compactées au début de le ''scheduler''. [[File:Wire partitionning.png|centre|vignette|upright=2|Wire partitionning]] Tout le problème est de savoir quelles portions désactiver. La technique est assez simple si le ''scheduler'' est compactée, à savoir si toutes les instructions sont régulièrement regroupées au début de la mémoire CAM. Mais même avec cette optimisation, la décision de désactiver une portion de le ''scheduler'' n'est pas à prendre à la légère. Il ne faut pas désactiver une portion contenant des instructions pouvant être émise sous peu. La décision dépend de paramètres variés : proportion d'entrée vides, quantité d'entrées récemment activées/désactivées récemment, présences d'entrées avec un ''match'' d'opérandes récent, etc. Il est important de préciser que les techniques en question fonctionnent aussi sur les autres types de ''scheduler'', qui ne sont pas basées sur des mémoires associatives. Nous allons voir celles-ci dans la suite du chapitre, mais gardez à l'esprit que ces optimisations, à savoir désactiver les entrées vides/prêts et partitionner le ''scheduler'', sont des optimisations générales qui marchent avec presque tout. ===L'ajout d'une FIFO pour les instructions déjà prêtes à l'émission=== D'autres techniques permettent de réduire aussi bien le cout en circuits que la consommation d'énergie de le ''scheduler''. L'idée est d'utiliser une mémoire associative quand elle est réellement nécessaire, mais d'utiliser un ''scheduler'' "normale" dès que possible. La méthode la plus simple tient compte du fait que certaines µopsont déjà toutes leurs opérandes de disponibles à l'émission, mais doivent quand même être mises en attente, parce que l'ALU adéquate est occupée, parce que des dépendances WAW/WAR sont encore là, ou pour tout autre raison. Dans ce cas, elles sont mises en attente non pas dans le ''scheduler'', mais dans une mémoire FIFO toute simple. L'idée est qu'au lieu d'avoir une énorme mémoire associative pour le ''scheduler'', on déplace quelques entrées dans une petite FIFO annexe. Le résultat est un gain d'énergie et de circuits, au prix d'une perte de performance mineure. La perte de performance en question se manifeste si aucune instruction n'a ses opérandes de prêtes à l'émission : le programme n'utilise pas la FIFO et voit alors un ''scheduler'' plus petite. Une amélioration de cette technique tient compte du fait que certaines instructions sont dans un cas intermédiaire. Elles ont déjà un opérande de prête lors de l'émission, mais pas l'autre. Le nombre d'opérandes varie suivant l’instruction : certaines n'ont besoin que d'un seul opérande. De plus, il arrive qu'une opération tout juste décodée ait déjà un ou plusieurs de ses opérandes de prêts. Cette constatation permet d'éviter d'utiliser des comparateurs pour les opérandes déjà prêts. Par exemple, on peut parfaitement utiliser trois ''scheduler'' : * une pour les instructions dont tous les opérandes sont prêts, mais qui sont quand même mises en attente, sans comparateur ; * une pour les instructions dont un seul opérande manque, qui n'utilise qu'un comparateur par entrée ; * une pour les instructions dont deux opérandes manquent à l'appel, qui utilise deux comparateurs par entrée. C'est beaucoup plus économique que d'utiliser une seule grosse ''scheduler'' qui contiendrait autant d'entrées que les trois précédentes réunies, avec deux comparateurs par entrée. Certains sont même allés plus loin, et ont proposé de supprimer le ''scheduler'' avec deux opérandes par entrée. Les instructions dont deux opérandes sont inconnus au décodage sont stockées dans le ''scheduler'' pour instructions avec un comparateur par entrée. Un circuit de prédiction se charge alors de prédire l'opérande manquant, cette prédiction étant vérifiée plus loin dans le pipeline. Il serait cependant étonnant qu'une telle proposition ait donné lieu à la moindre implémentation réelle. ===Les optimisations de la consommation d'énergie avancées=== D'autres chercheurs ont conservé un ''scheduler'' unique, avec autant de comparateurs par entrée qu'il y a d'opérandes possibles par instruction. Simplement, le processus de détection des opérandes prêts est légèrement ralenti : on ne vérifie qu'un opérande par cycle. Pour vérifier les deux opérandes d'une entrée, on doit attendre deux cycles. Enfin, certains chercheurs ont proposé des ''scheduler'' segmentées. Les instructions circulent à chaque cycle d'un segment vers le suivant : en conséquence, certains segments conservent les instructions les plus anciennes, un autre les instructions les plus jeunes, etc. Seul le denier segment, celui qui contient les instructions les plus vielles, peut émettre une instruction : la détection des opérandes se fait seulement dans le dernier segment, qui contient les instructions les plus anciennes. On économise ainsi beaucoup de comparateurs. Certains chercheurs ont tenté de pipeliner l'étape de sélection des opérandes, ainsi que l'étage d'arbitrage. Mais en faisant cela, il faut plusieurs cycles pour détecter qu'une instruction a ses opérandes prêts, ce qui pose problème face à de nombreuses dépendances RAW. Pour éviter de trop perdre en performances, certains chercheurs ont décidé d'utiliser des techniques pour prédire quelles seront les instructions dont les opérandes seront bientôt prêts. Si détecter qu'une instruction est prête prend n cycles, le processeur devra tenter de prédire la future disponibilité des opérandes n cycles en avance pour obtenir des performances optimales. ===Remplacer la mémoire associative par une RAM=== Une autre optimisation possible est de remplacer le ''scheduler'' par une mémoire RAM, dont chaque mot mémoire correspondrait à une entrée. Une telle optimisation permet en théorie de se passer des comparateurs associés à chaque entrée, mais au prix de l'ajout de circuits annexes potentiellement couteux. La première de ces techniques, la '''recherche directe par étiquette''' (direct tag search) fut créée par Weiss et son collègue Smith. Ils cherchaient à améliorer l'algorithme de Tomasulo, un algorithme qu'on expliquera dans quelques chapitres. Rappelons que chaque instruction produit un résultat, qui devra être rapatrié dans une ou plusieurs entrées de le ''scheduler''. L'optimisation de la recherche directe par étiquette fonctionne dans le cas où le résultat de l'instruction n'est utilisé que par une seule entrée, et pas plusieurs. Le principe est simple : chaque champ « opérande » d'une entrée est adressable via le nom de registre de cet opérande. Pour faire le lien entre entrée et nom de registre, la recherche directe par étiquette ajoute une table de correspondances matérielle, une mémoire RAM qui mémorise les adresses des champs « opérande » des entrées. Les adresses envoyées dans cette mémoire sont les noms de registres des résultats. Lors de l'émission, la table de correspondances est mise à jour. Les numéros des champs « opérande » réservés lors de l'émission sont mémorisés dans les mots mémoire qui correspondent aux deux registres sources. Toutefois, une petite vérification est faite lors de l'émission : s'il y a déjà une correspondance dans la table pour un registre source, alors une autre instruction compte lire ce registre. Pour éviter d'écraser les données de l'instruction précédente dans la table de correspondances, l'émission de l'instruction est bloquée. [[File:Recherche directe par étiquette.png|centre|vignette|upright=2|Recherche directe par étiquette.]] ==Les ''schedulers'' avec préplanification== Avec la '''préplanification''' (''prescheduling''), le ''scheduler'' est composée de mémoires FIFO dans lesquelles les instructions sont triées dans l'ordre d'émission. Il n'y a pas de logique d’émission proprement dite, celle-ci se bornant à vérifier si l'instruction située au début de la FIFO peut s’exécuter. Par contre, le préplanificateur détecte les dépendances et en déduit où insérer les instructions dans le tampon d'émission, à l'endroit le plus adéquat. [[File:Préplanification.jpg|centre|vignette|upright=2|Préplanification.]] ===L'usage de FIFO multiples=== La technique de préplanification la plus simple utilise plusieurs FIFO. Quand une instruction a une dépendance avec une autre instruction, les deux sont placées dans la même FIFO. Pour cela, le préplanificateur détecte les chaines d'instructions dépendantes, et place les instructions dans la FIFO adéquate. A chaque cycle, l'unité d'émission lit une micro-opération dans chaque FIFO et vérifie si elle peut l'émettre. Si la micro-opération n'a pas ses opérandes disponibles, ou qu'une dépendance structurelle survient, alors la FIFO est bloquée. La micro-opération attend que la dépendance soit résolue, bloquant toutes les instructions précédentes. Mais les autres FIFO ne sont pas bloquées, laissant de la marge de manœuvre. [[File:Préplanification par FIFO multiples.png|centre|vignette|upright=1.5|Préplanification par FIFO multiples.]] ===La technique du tampon trié=== La technique du '''tampon trié''' trie les instructions selon le temps d'attente avant leur exécution. Les instructions qui sont censées s’exécuter bientôt sont insérées au tout début de la FIFO, tandis que les instructions qui s’exécuteront dans un long moment sont insérées vers la fin. Là encore, l'unité d'émission lit une micro-opération dans la FIFO, et détermine si elle peut être émise. Si une dépendance survient, l'émission est retardée, et la FIFO est bloquée. [[File:Préplanification par tampon trié.png|centre|vignette|upright=1.5|Préplanification par tampon trié.]] La technique a cependant quelques problèmes assez importants. Le premier problème est que la FIFO est bloquée lorsqu'une micro-opération ne peut être émise. Le second problème est que le temps avant exécution n'est pas toujours connu, notamment pour les instructions d'accès mémoire. Et cela se répercute sur les instructions dépendantes de celles-ci. Pour résoudre ce genre de problèmes, l'usage d'un pipeline à ''replay'' est possible, et est même l'une des meilleures solutions possible, malgré ses défauts. L'idée est que les lectures sont pré-planifiées en supposant qu'elles font un succès de cache L1. Si la prédiction est fausse, la lecture est ré-exécutée plusieurs cycles plus tard, en supposant qu'elle fait un succès dans le cache L2, et ainsi de suite. Elle est alors ré-insérée dans la FIFO, elle est pré-planifiée une seconde fois. Il en est de même si une micro-opération ne peut pas être émise : il suffit de la réinsérer dans la FIFO au bon endroit, en attendant que ses dépendances soient résolues. Ainsi, l'instruction fautive ne bloque pas le ''scheduler'', et retente sa chance autant de fois qu'il le faut. [[File:Préplanification par fenêtre d’instruction scorebarodée.png|centre|vignette|upright=1.5|Préplanification par ''scheduler'' scorebarodé.]] Une autre solution utilise deux ''schedulers'' : une FIFO gérée par la préplanification, et une vraie ''scheduler'' pour les instructions dont le temps d'attente ne peut pas être déterminé. Il est possible de mettre cette dernière avant la préplanification, afin de gérer les temps d'attente des instructions d'accès mémoire. Quand le temps d'attente d'une lecture devient connu, ses instructions dépendantes sont gérées avec préplanification. [[File:Préplanification avec fenêtre d’instruction.png|centre|vignette|upright=2.5|Préplanification avec ''scheduler''.]] ===Les ''scheduler'' avec allocation temporelle statique=== L''''allocation temporelle statique''' correspond à une technique utilisée sur les processeurs Cuzco de l'entreprise Condor. La technique en question a été présenté en 2025, mais des idées similaires ont été présentées dans la littérature académique. Elle ressemble beaucoup aux techniques de pré-planification, avec cependant quelques différences. L'idée est simple : le processeur dispose de plusieurs ''scheduler'', qui mettent en attente les micro-opérations. Lors de l'étape de renommage de registres, le processeur détermine dans combien de cycles d'horloge la micro-opération sera prête pour exécution. La micro-opération est alors mise en attente durant ce nombre de cycles, dans les ''scheduler'', puis est émise une fois ce nombre de cycles écoulés. Ce faisant, les ''scheduler'' n'ont pas besoin de détecter la disponibilité des opérandes à chaque cycle, pour chaque micro-opération en attente. Le ''timing'' de l'émission des micro-opérations est décidé à l'avance. L'implémentation exacte n'est pas connue, mais plusieurs solutions sont imaginables. Par exemple, le ''scheduler'' peut simplement être composée de plusieurs mémoires de petite taille, chacune contenant les micro-opérations destinées à être exécutées dans N cycles, N étant différent pour chaque mémoire. Une autre solution, plus réaliste, utilise un ''scheduler'' dans laquelle la micro-opération est couplée à des champs pour les opérandes, et un champ compteur. Le champ compteur est initialisé avec le nombre de cycles à attendre, et est décrémenté à chaque cycle d'horloge. Quand il atteint zéro, la micro-opération est émise. Vous remarquerez que la méthode ne marche que si toutes les micro-opérations prennent un nombre fixe de cycles d'horloge. Et autant c'est le cas pour les micro-opérations arithmétiques ou logiques, autant les accès mémoire ne rentrent pas dans ce cadre. En théorie, on ne sait pas combien de temps prendra un accès mémoire. Et cette incertitude se répercute sur les instructions dépendantes d'un accès mémoire. Pour éviter cela, le processeur réutilise un pipeline à ''replay'' tel que vu dans le chapitre précédent. L'unité de renommage de registre suppose que tout accès mémoire fait un succès de cache L1, et décide des ''timings'' d'émission sous cette hypothèse. Si une lecture subit un défaut de cache, elle est ré-exécutée, de même que toutes les instructions dépendantes. Pour cela, le registre de destination de la lecture est marqué comme invalide, grâce à un bit spécifique attaché au registre. Toute instruction qui lit un opérande invalide est elle aussi ré-executée de zéro. Pour simplifier, l'unité d'émission ressemble à une unité d'émission dans l'ordre, avec un registre de disponibilité, qu'on aurait amélioré pour aller au-delà de la simple détection des dépendances d'instruction. Pour déterminer les ''timings'' d'émission, à savoir quand émettre une micro-opération, le processeur utilise une unité d'émission à deux étages. Le premier étage est appelé le ''register scoreboard'', le second étage est appelé la ''Time Ressource Matrix''. Les deux étages communiquent entre eux, comme on va le voir, et leurs noms donnent une idée de ce qu'ils font. Le premier étage gère les dépendances de registres, le second gère les dépendances structurelles. Le premier étage est un registre de disponibilité amélioré, qui gère les dépendances de registre. Cet étage sait quand tel registre sera écrit, et donc que l'opérande écrit dedans sera disponible à partir de tel cycle d'horloge. Il le sait car l'étage suivant l'aura prévenu, mais laissons cela de côté pour le moment. Quand une micro-opération rentre dans cet étage, il vérifie les dépendances avec les registres et les micro-opérations antérieures. Vu qu'il sait quand les registres seront disponibles, il peut déterminer quand l'instruction pourra s'exécuter. Par exemple, si une micro-opération lit les deux registres R7 et R15, qui sont disponibles respectivement dans 5 et 7 cycles, le premier étage sait que la micro-opération devra attendre 7 cycles. Mais tout cela ne suffit pas à déterminer quand émettre une micro-opération. En effet, il fait aussi gérer les dépendances structurelles, ce qui est le boulot du second étage. Le second étage utilise pour cela une ''Time Ressource Matrix'', qui mémorise l'occupation de diverses "ressources", pour les 256 cycles d'horloge à venir. Les ressources en question sont les ports de lecture/écriture du banc de registre, les ALUs utilisées, si la micro-opération utilise l'unité mémoire, etc. Le second étage prend en entrée une micro-opération, détermine quelles "ressources" elle utilise, puis regarde leur disponibilité. Elle détecte alors les dépendances structurelles et détermine alors quand peut s'exécuter la micro-opération. Elle peut retarder l'émission de quelques cycles, si une dépendance structurelle est détectée. Une fois sortie du second étage, on sait quand la micro-opération va être émise, à quel cycle précisément. Et vu que la durée de l'instruction est fixe, on sait quand cette micro-opération va se terminer, quand son résultat sera disponible. Cela permet de mettre à jour la ''Time Ressource Matrix'', pour préciser que le port d'écriture sera occupé à tel moment. De plus, cette information est transmise au premier étage, qui sait alors quand est enregistré le résultat dans le registre de destination. C'est comme cela que le premier étage sait quand un registre est disponible : le second étage le prévient, quand il émet une instruction ! La ''Time Ressource Matrix''mémorise l'occupation des "ressources" pour les 256 cycles d'horloge à venir. Cependant, elle ne vérifie pas les dépendances pour les 256 cycles suivants. Quand elle reçoit une micro-opération, elle teste les dépendances structurelles pour seulement les 8 prochains cycles maximum. Si la micro-opération ne peut pas être émise pendant ces 8 cycles, le pipeline est bloqué, un ''pipeline stall'' est émis. Pour être plus précis, vu que le processeur peut décoder 8 micro-opérations en même temps, cela permet de ne consulter que 64 cycles d'horloge sur les 256. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les premiers processeurs Intel | prevText=Les premiers processeurs Intel | next=Le renommage de registres | nextText=Le renommage de registres }} </noinclude> kir85w7nsvn8zackvymco4k3rzfacx3 773675 773634 2026-09-29T22:44:56Z Mewtow 31375 /* Les stations de réservation */ 773675 wikitext text/x-wiki Dans les chapitres précédents, nous avons parlé des techniques dites d''''émission dans l'ordre'''. L'idée est d’exécuter une nouvelle micro-opération à chaque cycle, dans des unités de calcul séparées. Les instructions sont émises consécutivement, mais les instructions s’exécutent en parallèle dans des unités de calcul séparées. Par contre, quand l'unité d'émission ne peut pas émettre une instruction, elle bloque tout le pipeline. Les instructions qui suivent sont elles aussi bloquées, elles doivent attendre leur tour, même si elles sont en capacité de s'exécuter. Les techniques d'exécution dans le désordre que nous allons voir dans ce chapitre corrigent ce point précis. Elles sont dites à '''émission dans le désordre'''. Elles se distinguent des précédentes sur un point précis : quand l'unité d'émission bloque l'émission d'une instruction, les instructions suivantes peuvent poursuivre. L'émission des instructions peut donc se faire dans le désordre, dans le sens où une instruction peut être émise alors qu'une instruction précédente ne l'est pas encore. Mais avant de poursuivre, quelques point niveaux terminologie : * L'émission dans le désordre est un terme parlant et assez précis. Malheureusement, la terminologie la plus utilisée par d''''exécution dans le désordre'''. Et nous utiliserons ce terme dans la suite du cours, histoire de ne pas trop dévier de la nomenclature habituelle. * Nous utiliserons parfois l'abréviation OOO pour parler d'exécution dans le désordre. L'abréviation est celle de ''Out Of Order Execution''. * Nous utiliserons aussi l'abréviation ''µop'' pour parler de micro-opération, ''µops'' au pluriel pour parler de plusieurs micro-opérations, ou des micro-opérations en général. L'exécution dans le désordre ne gère en effet que des µops, elle se situe après l'étape de décodage. Pour décrire comment est implémentée l'émission dans le désordre, il faut commencer par parler des processeurs sans. Les processeurs sans exécution dans le désordre ont une unité d'émission qui bloque tout le pipeline dès qu'une µop ne peut pas être émise. Pour limiter l'impact de ce blocage, quelques rares processeurs incorporent une '''file de micro-opération''', une mémoire FIFO qui met en attente les µops. Vu que c'est une mémoire FIFO, les µops sont émises dans l'ordre, à savoir l'ordre d'ajout, dans l'ordre de décodage. Le schéma ci-dessous illustre une telle file d'attente couplée à un ''scoreboard''. L'exécution dans le désordre améliore la file de µops sur un point : ce n'est plus une mémoire FIFO. Les µops sont insérées dans l'ordre, mais peuvent sortir dans le désordre (être émises dans le désordre). La file de µops devient alors un '''''scheduler''''', terme anglais que je ne compte pas traduire. Un terme équivalent est '''''scheduler''''', terme traduit directement de l'anglais ''instruction Window''. Terme assez trompeur, car elles mettent en attente des µops, pas des instructions. [[File:Différence file µops et fenêtres instruction.png|centre|vignette|upright=2|Différence file µops et ''schedulers'' ]] Le ''scheduler'' émet une µop dès que ses opérandes sont disponibles. Par disponible, on veut dire présent soit dans le réseau de contournement, soit dans les registres. Le ''scheduler'' détecte automatiquement quand les opérandes d'une µop sont disponibles, grâce à une unité d'émission intégrée. L'unité d'émission et le ''scheduler'' sont fusionnés ensemble, dans un seul circuit, mais nous allons dire qu'ils sont conceptuellement séparés pour le moment. À chaque cycle, l'unité d'émission consulte les µops en attente pour détecter lesquelles peuvent s'exécuter. Le ''scheduler'' est spécialement être conçue pour, c'est une sorte de mémoire associative très complexe, comme on le verra dans ce qui suit. [[File:OOO Issue.png|centre|vignette|upright=2.5|Exécution dans le désordre avec un ''scheduler'']] Une fois qu'une µop sort du décodeur d'instructions, elle est ajoutée en parallèle dans le ''scheduler'' et le ROB. La raison est que les µops quittent le ''scheduler'' dans le désordre, et qu'elles doivent être remises en ordre par la suite. Le ROB s'occupe de cette remise en ordre, mais il a besoin de savoir dans quel ordre les µops sont censées être, et cet ordre est celui du décodage. Aussi, pour remplir le ROB, la seule opportunité est en sortie de l'unité de décodage. Dans le cas où une instruction est décodée en plusieurs micro-opérations, elles sont toutes insérées en même temps dans le ''scheduler'' et le ROB, en tenant compte de leur ordre. L'implémentation la plus simple de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Les µops décodées sont accumulées dans le ''scheduler'', où elles attendent leur tour. le ''scheduler'' sert donc de file d'attente. Avant de poursuivre, précisons que les micro-opérations mémoire sont à part des autres, pour diverses raisons. Une de ces raisons est que les dépendances de données sont classées en deux types : les dépendances de registre et les dépendances d'adresse. Et les deux sont fondamentalement différentes. Autant on peut détecter les dépendances de registre lors de l'émission, autant c'est plus compliqué avec les dépendances d'adresse. De plus, rappelons que si les lectures peuvent s'exécuter dans le désordre, les écritures doivent s'exécuter dans l'ordre, ou du moins en donner l'illusion. Pour cela, le processeur remet les écritures dans l'ordre avec une sorte de mini-ROB intégré à l'unité mémoire, appelée la file d'écriture. Elle complémente le ROB, qui lui ne gère que les écritures dans les registres, mais les deux collaborent. La file d'écriture envoie une écriture à la mémoire RAM quand le ROB lui dit que c'est bon, les instructions précédentes sont terminées ''dans l'ordre du programme''. Les processeurs modernes ajoutent des techniques d'exécution dans le désordre des accès mémoire, mais nous les verrons dans un chapitre dédié. Elles permettent d'utiliser un ''scheduler'' unique, qui mémorise aussi les µops mémoire. Si elles sont mises en place, l'unité mémoire n'a pas besoin de file de µops séparée. L'idée est que les dépendances de registre sont traitées par le ''scheduler'', mais que l'unité mémoire gére les dépendances d'adresse. Les dépendances d'adresse sont gérées par des techniques de ''désambiguation mémoire'', qui auront droit à un chapitre dédié. [[File:Processeur avec exécution dans le désodre des accès mémoire.png|centre|vignette|upright=2|Processeur avec exécution dans le désodre des accès mémoire]] Les processeurs assez anciens n'autorisaient pas d'exécution dans le désordre des accès mémoire. Concrètement, les accès mémoire devaient se faire dans l'ordre, mais les autres µops pouvaient être exécutées dans le désordre. Il s'agit donc d'un ordre entre µops mémoire, pas entre µops mémoire et autres µops. Les µops entières et flottantes pouvaient être exécutées avant une µops mémoire qui est avant elle dans l'ordre du programme, ce n'est pas un problème. Pour garantir l'ordre des µops mémoire, l'unité mémoire est précédée par une file de micro-opérations séparée, pour forcer l'exécution dans l'ordre des accès mémoire. De plus, les µops mémoire ne peuvent pas utiliser le ''scheduler''. Dit autrement, le ''scheduler'' ne mémorise pas de µops mémoire. Après le décodage, les µops sont réparties soit dans la file de µops mémoire, soit dans le ''scheduler''. Le décodeur classe les µops suivant que ce sont des µops mémoire ou non, et les envoient à la bonne destination. Dans ce chapitre, on supposera que c'est cette solution qui est utilisée. [[File:Processeur avec émission dans l'ordre des accès mémoire.png|centre|vignette|upright=2|Processeur avec émission dans l'ordre des accès mémoire]] ==L'implémentation d'un ''scheduler'' : généralités== Un ''scheduler'' est une mémoire qui mémorise des micro-opérations. Elle est cependant plus complexe qu'une mémoire RAM ou qu'une FIFO et ressemble un petit peu à une mémoire cache. Elle dispose d'un port d'écriture et d'un port de lecture, au minimum. Le port d'écriture permet à l'unité de décodage d'insérer une micro-opération dedans, d'ajouter la micro-opération qui vient d'être décodée. Si une instruction machine est décodée en plusieurs micro-opération, deux possibilités. La première est de les insérer un par un, ce qui fait qu'on peut se contenter d'un seul port d'écriture. L'autre possibilité est de les ajouter en même temps, ce qui demande plusieurs ports d'écriture. Le port de lecture sert à émettre une instruction. On part du principe que le ''scheduler'' ne peut émettre qu'une seule instruction à la fois, car les processeurs que nous avons vu précédemment sont de ce type. Mais nous verrons dans quelques chapitres qu'il existe des processeurs dits superscalaires, qui sont capables d'émettre plusieurs instructions par cycle. Dans ce cas, le ''scheduler'' a un seul port de lecture. Un processeur superscalaire, quant à lui, doit avoir un port de lecture par unité de calcul, ce qui fait beaucoup plus. Les ''schedulers'' sont composées d''''entrées''', des mots mémoire qui stockent une instruction. Une instruction réserve une entrée après son décodage et la libère dès qu'elle est envoyée aux unités de calcul. Une entrée contient l'opcode (les signaux de commande à envoyer à l'ALU), le registre de destination du résultat, les registres de chaque opérande, et éventuellement des signaux de commande en plus. De plus, chaque opérande est couplée à un bit de disponibilité, qui indique si elle est disponible. Quand un opérande est écrit dans les registres, le bit de présence correspondant est mis à jour. Enfin, chaque entrée possède un bit ''empty'' qui indique si elle est vide, cette information étant utile pour réserver des entrées. [[File:Entrée d'une station de réservation - sans les tags.png|centre|vignette|upright=3|Entrée d'un ''scheduler'']] ===Les stations de réservation=== Les '''stations de réservation''' sont des ''scheduler'' particulières, qui sont capables de mémoriser les opérandes des instructions. Les entrées des stations de réservation sont identiques à celle des autres ''scheduler'', si ce n'est que les opérandes de l'instruction sont enregistrés directement dans des champs séparés. Il y a deux champs, un par opérande, pour stocker l'opérande elle-même, lue depuis les registres ou obtenue via le réseau de contournement. Notons que les champs pour les opérandes viennent en plus des champs pour les noms de registres, encore que les deux peuvent être fusionnés si on veut optimiser le tout. [[File:Entrée d'une station de réservation.png|centre|vignette|upright=3|Entrée d'une station de réservation.]] Précisons que la terminologie n'est pas très fiable. Les termes "''scheduler''" et "station de réservation" ne regroupent pas du tout la même chose d'un papier de recherche à l'autre, d'un bouquin à l'autre, d'un chercheur à l'autre, d'un ingénieur à l'autre, d'un professeur à l'autre. Le terme initial vient pourtant de l'article original sur l'algorithme de Tomasulo, où il désignait un ''scheduler'' associée à une unité de calcul précise. Mais le terme a ensuite été réutilisé, ce qui fait que certains processeurs avec plusieurs unités de calcul sont décrits comme ayant une unique station de réservation. En bref : c'est le bazar ! Mais nous en reparlerons dans le chapitre sur le renommage de registres, car c'est la place idéale pour les aborder. Toujours est-il que j'ai fait le choix de confondre les concepts de ''scheduler'' et de station de réservation avec les concepts de '''lecture avant émission''' et de '''lecture après émission'''. La différence entre les deux est que les registres sont lus après émission avec un ''scheduler'', avant avec des stations de réservation. Dans le cas "avant émission", les opérandes sont mémorisés dans la station de réservation. Et cette différence a une influence sur le pipeline du processeur, le banc de registres et tout ce qui s'ensuit. Un désavantage de la lecture avant émission est qu'il faut stocker les opérandes après lecture, ici dans les stations de réservation. Mais un avantage est que le banc de registre a besoin de moins de ports de lecture, car une bonne partie des opérandes sont fournies par le système de contournement. Nous verrons cela dans le détail dans le chapitre sur les processeurs superscalaires. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Lecture après émission.]] [[File:Read Before Issue.png|centre|vignette|upright=2.5|Lecture avant émission.]] ===La logique d'éveil et de sélection=== Dans le cas qui va suivre, on suppose que le processeur ne peut émettre qu'une instruction à la fois. Chaque cycle, une instruction est sélectionnée et est envoyée dans le chemin de données, soit à une ALU, soit à une unité d'accès mémoire. La sélection d'une instruction est effectuée par l'unité d'émission, qui est aussi appelée le '''''scheduler'''''. Elle gère la disponibilité des opérandes et la disponibilité des unités de calcul adéquate. Le choix de l'instruction émise doit être le plus pertinent possible, pour des raisons de performances. Pour le premier point, l'unité d'émission détermine quelles instructions sont candidates pour l'émission. Les ''instructions candidates'' sont celles dont tous les opérandes sont prêts. Le processeur contient un circuit qui détecte les instructions candidates : la '''logique d’éveil''' (''wake-up logic''). Une fois que la logique d'éveil a fait son travail, une instruction est choisie pour s’exécuter en fonction de la disponibilité des unités de calcul adéquates. Ce rôle est dévolu à un circuit qu'on appelle la '''logique de sélection''', ou ''select logic''. [[File:Fonctionnement complet de la logique d’émission.jpg|centre|vignette|upright=1.5|Fonctionnement complet de la logique d’émission.]] La logique de sélection doit gérer le fait que les unités de calcul du processeur ne sont pas toutes identiques. Déjà, un processeur a généralement des unités séparées pour les instructions entières et flottantes, des unités spécialisées dans les accès mémoire, parfois des unités spécialisées pour les branchements. Une instruction doit être attribuée à la bonne unité de calcul, on ne doit pas envoyer une instruction entière dans une unité de calcul flottante. De plus, parmi les unités de calcul entières, toutes ne sont pas identiques. Par exemple, il est fréquent d'avoir plusieurs unités de calcul spécialisées dans les opérations simples (additions, soustractions, opérations logiques) avec une unité pour les multiplications/divisions séparées, parfois une unité spécialisée pour les décalages/rotations, etc. Là encore, allouer la bonne instruction à la bonne ALU est complexe. Plus les unités de calcul sont hétérogènes, plus la logique de sélection est compliquée. Les logiques d'éveil comme de sélection sont assez complexes. Comme on le verra plus bas, la logique de sélection la plus simple, qui gère une seule unité de calcul, est basée sur un encodeur à priorité, couplé à d'autres circuits. Et pour gérer plusieurs ALUs, il faut mettre des encodeurs en cascade. Le résultat est que même en prenant une logique de sélection simple, elle sera assez lente et gourmande en circuits. Aussi, la logique de sélection met souvent un cycle d'horloge entier pour faire son travail, elle a son propre étage de pipeline attribué. La logique d'éveil est dans le même cas, ce qui fait qu'émettre une micro-opération demande deux cycles d'horloge. Le défaut est que cela rajoute des cycles d'horloges entre le ''scheduler'' et l'ALU, ce qui complique la gestion du pipeline. Ces cycles de retard sont à prendre en compte au moment d'émettre les instructions, les ''scheduler'' doit en tenir compte pour des performances optimales. Sans tenir compte de ces cycles de retard, les instructions arrivent en retard de quelques cycles à l'ALU, cycles de retard durant lesquels l'ALU n'a pas fait de calcul et a été sous-utilisée, sans compter que le système de contournement n'est pas utilisé au mieux. Et le problème est encore plus important sur les processeurs avec des stations de réservation, qui utilisent la "lecture après émission" : cela rajoute un cycle d'horloge en plus, un temps de retard en plus. ===La logique d'éveil : l'émission anticipée=== La logique d'éveil doit tenir compte du fait qu'il y a plusieurs étages entre l'émission et l'exécution sur une unité de calcul. Par exemple, un processeur a souvent entre un et à cinq étages entre la file d'attente et les unités de calcul. Il faut lire les registres, gérer le contournement, et cela peut prendre quelques cycles d'horloge. Sur le Pentium 4, on trouve 6 étages entre le ''scheduler'' et l'entrée de l'ALU. Si les micro-opérations sont émises quand les opérandes sont disponibles, il y aura un délai de quelques cycles avant qu'elles atteignent l'ALU. Alors qu'idéalement, on souhaiterait que la micro-opération atteigne l'ALU dès que ses opérandes sont disponibles, pour profiter des techniques de contournement. Pour cela, la logique d'éveil émet les instructions quelques cycles en avance pour qu'elles arrivent au bon moment. Il s'agit d'une technique d''''émission anticipée''', dont nous avions parlé dans le chapitre sur le contournement. : Il faut noter que le problème se pose plus avec des ''schedulers'' qu'avec des stations de réservation. Les premières ont un étage en plus entre émission et ALU, vu qu'il faut lire des registres après l'émission. L'émission anticipée demande d'émettre un signal d'éveil en avance de quelques cycles, pile au bon moment. Par exemples, si on a deux étages entre l'ALU et l'unité d'émission, le signal de réveil sera généré deux cycles avant que le résultat soit effectivement calculé. L'implémentation varie, mais deux solutions sont possibles. La première est de générer le signal d'éveil dans l'ALU, ce qui n'a de sens que pour les opérations comme les multiplications ou les divisions, qui prennent plusieurs cycles. Une autre technique génère le signal de réveil dans une structure centralisée, spécialisée dans la génération des signaux d'éveil. L'unité de composée d'un registre à décalage par registre. Imaginons qu'une instruction est émise, que cette instruction mette N cycles à s'exécuter, et qu'elle écrive dans un registre de destination. L'unité sélectionne alors le registre à décalage associé au registre de destination, et met le bit numéro N à 1. Le registre décalé d'un cran à chaque cycle. Quand le bit sortant est un 1, alors le signal de validité pour l'opérande est généré. L'émission anticipée marche bien si l'instruction a une durée fixe, connue à l'avance. Et autant c'est le cas pour les instructions arithmétiques et logiques, autant ce n'est pas le cas pour les accès mémoire. Les accès mémoire ont une latence variable : quelques cycles pour un succès de cache, plusieurs dizaines de cycles pour un défaut de cache L1, pas loin de la centaine pour un défaut de cache L2, etc. Et cela pose des problèmes pour l'émission anticipée. L'émission en avance pour les accès mémoire est purement spéculative : le processeur émet des instructions en supposant que la lecture entrainera un succès de cache, quitte à annuler l'instruction en cas de défaut de cache. Mais faire ainsi demande non seulement d'annuler les instructions émises en avance, mais aussi de ne pas retirer les instructions émises en avance de le ''scheduler''. Elles sont émises, mais une copie de sauvegarde est conservée dans le ''scheduler''. Si le processeur détecte un défaut de cache, il peut alors ré-exécuter l'instruction. S'il détecte un succès de cache, les instructions lecture-dépendante sont retirées de le ''scheduler'', la copie de sauvegarde est devenue inutile et est donc jetée. ===La logique de sélection : âge ou position ?=== La logique de sélection est primordiale pour de bonnes performances. Il existe deux méthodes principales pour sélectionner l'instruction à exécuter. La première est la plus simple : elle se base sur lé numéro de l'entrée. En effet, un ''scheduler'' est avant tout une sorte de mémoire, un mix entre mémoire associative, mémoire RAM, et FIFO. Et chaque entrée a un numéro, une adresse mémoire. Nous parlerons de numéro dans ce qui suit, car ce sera plus simple, le terme d'adresse mémoire étant peut-être un peu exagéré dans le contexte des ''scheduler''. Toujours est-il que le ''scheduler'' est adressable dans le sens où on peut lui envoyer le numéro de l'entrée voulue, et le ''scheduler'' renvoie le contenu de l'entrée sur son port de lecture. Et c'est ce que fait la logique de sélection : elle génère le numéro de l'entrée à lire. Le numéro est alors envoyé sur l'entrée d'adresse du ''scheduler'', et elle fournit la micro-opération associée sur son port de lecture, son '''port d'émission'''. La première méthode de sélection, donc. Elle est basée sur le numéro de l'entrée. Si plusieurs entrées sont éveillées, la logique de sélection prend celle avec le plus petit numéro. Elle porte le nom de '''sélection par position''', sous-entendu position dans le ''scheduler''. Vous l'avez peut-être deviné, mais la logique de sélection est alors un encodeur à priorité. Le circuit de sélection ne se résume donc pas seulement à un encodeur à priorité, mais c'est le circuit central. L'avantage d'une telle méthode de sélection est qu'elle est simple à implémenter : un encodeur à priorité est un circuit connu, facile à implémenter. Mais on remarque un défaut : un encodeur est un circuit assez rapide, mais qui utilise beaucoup de transistors, beaucoup de portes logiques, surtout si on veut qu'il soit rapide. Ce qui explique que la logique de sélection ait son propre étage de pipeline rien que pour elle. La seconde méthode s'appelle la '''sélection par âge''', au nom assez transparent. L'idée est de privilégier l'émission de l'instruction la plus ancienne. Elle demande que le ''scheduler'' trie les micro-opérations par ordre d'insertion dans le ''scheduler'', ce qui en fait une pseudo-FIFO. Le tri est partiel, car les instructions peuvent sortir du ''scheduler'' à tout moment. Compacter le ''scheduler'', à savoir regrouper toutes les entrées valides est une idée, mais elle est compliquée à implémenter. Aussi, elles préfèrent encoder des informations sur l'ordre d'émission dans chaque entrée. L'encodeur à priorité doit alors travailler non pas sur des nombres entiers liés à l'ordre d'insertion dans la pseudo-FIFO. Elle est encore plus gourmande en circuits que la méthode précédente. Les processeurs haute performance utilisent souvent des méthodes hybrides. Par exemple, les processeurs AMD de microarchitecture Bulldozer utilisaient une méthode intermédiaire. Ils utilisaient un ''scheduler'' couplée à un encodeur à priorité pour la sélection par position, mais complémentaient le tout avec une unité qui mémorisait l'instruction la plus ancienne dans le ''scheduler''. Le mécanisme de sélection par âge était utilisé en priorité. Mais si l'instruction la plus ancienne n'était pas prête, le processeur basculait sur le mécanisme de sélection par position. ===La compaction des ''scheduler''=== À chaque cycle, les instructions décodées sont ajoutées dans le ''scheduler'', dans des entrées vides. Vu que les instructions quittent celle-ci dans le désordre, ces vides sont dispersés dans le ''scheduler'', ce qui pose problème pour déterminer où placer les nouvelles instructions. La solution la plus triviale consiste à conserver une liste des vides, mise à jour à chaque insertion ou émission d'instruction. Une autre solution consiste à éliminer les vides en compactant le ''scheduler'' à chaque cycle d'horloge. Des circuits se chargent de détecter les vides et de regrouper les instructions en un unique bloc. Il faut signaler que certains processeurs arrivent à se passer de cette étape de compactage, mais au prix de ''scheduler'' nettement plus complexes. Autre problème : quand il faut choisir quelle instruction émettre, il y a toujours plusieurs candidats. Si on choisit mal, des instructions restent en attente trop longtemps parce que d'autres instructions plus jeunes leur passent devant. Pour éviter cela, les instructions les plus vielles, les plus anciennes, sont prioritaires. Pour cela, on peut utiliser une FIFO un peu spéciale pour le ''scheduler''. Si les ajouts d'instruction se font dans l'ordre, les instructions ne quittent pas forcément le ''scheduler'' dans l'ordre imposé par une FIFO : les instructions restent triées dans leur ordre d'ajout, même s'il y a des vides entre elles. Dans ces conditions, il est préférable que le compactage conserve l'ordre FIFO des instructions. Dans ces conditions, l'instruction la plus ancienne est celle qui est située à l'adresse la plus faible : le circuit de sélection peut donc être fabriqué avec des encodeurs, et est relativement simple. ==Les ''schedulers'' basées sur une matrice de dépendances== L'implémentation la plus simple étend le fonctionnement d'un pipeline dynamique usuel. Rappelez-vous le chapitre sur les pipelines dynamiques. Nous avions vu que de tels pipelines émettaient une instruction par cycle, quitte à émettre des bulles de pipeline en cas de dépendance bloquante. Et il est possible d'améliorer leur unité d'émission pour qu'elle soit compatible avec l'exécution dans le désordre. ===Rappels sur le registre de réservation/disponibilité=== L'émission d'une instruction est gouvernée par un ''registre de réservation'' qui indique quels registres sont réservés par une instruction, et ceux qui sont libres. Un registre réservé est un registre qui sera écrit par une instruction en cours d'exécution, mais qui n'a pas encore écrit son résultat. Les instructions candidates doivent avoir leurs opérandes dans des registres libres. Sinon, c'est signe que leurs opérandes sont réservés en écriture, donc pas encore écrites, donc pas disponibles. Si une instruction candidate veut lire ce registre, c'est signe qu'il y a une dépendance RAW : elle veut lire un registre réservé, qui est destiné à être écrit par une instruction en vol. Si elle veut écrire, c'est signe qu'elle veut écrire dans un registre où une autre instruction veut écrire : c'est une dépendance WAW. Dans les deux cas, l'instruction n'est pas émise. Le registre de réservation encode les registres réservés comme suit : chaque bit est associé à un registre. Le bit numéro 0 est associé au registre numéro 0, le bit numéro 1 au registre numéro 1, etc. Là, En clair, les numéros de registres réservés sont encodés en représentation non pas binaire, mais en représentation ''one-hot'' (vue au premier chapitre). {|class="wikitable" |+ Registre de réservation |- ! Registre 7 !! Registre 6 !! Registre 5 !! Registre 4 !! Registre 3 !! Registre 2 !! Registre 1 !! Registre 0 |- | 0 || 0 || 1 || 0 || 0 || 1 || 0 || 0 |} Avant d'émettre une instruction, l'unité d'émission extrait les registres opérande/destination et les convertis dans la même représentation que le registre de réservation, à savoir en représentation ''one-hot''. Le circuit de traduction binaire vers ''one-hot'' est, pour rappel, un simple décodeur. Puis, on fait un OU logique entre les sorties des décodeurs. Le résultat est un masque qui indique quels registres sont lus par l'instruction, encodé en représentation ''one-hot''. Appelons-le le '''masque d'opérandes'''. Le masque est alors comparé au registre de réservation pour vérifier si l'instruction peut être émise. [[File:Unité d'émission simple, dans l'ordre.png|centre|vignette|upright=2|Unité d'émission simple, dans l'ordre]] Si l'émission est autorisée, le registre de réservation est là aussi mis à jour. Le registre de réservation est aussi mis à jour dès qu'une instruction enregistre son résultat dans les registres, ou alors dès qu'il est disponible pour le contournement. Le bit associé au registre repasse alors à 0 (ou à 1). Sans contournement, la mise à jour se fait alors à la toute fin de l'instruction, quand elle se termine, lors de la dernière étape d'enregistrement, à la fin de son pipeline. Avec, elle se fait quand l'instruction quitte l'unité de calcul. ===L'extension à l'exécution dans le désordre : l'éveil par matrice de bits=== La différence entre un pipeline dynamique et l'exécution dans le désordre est que l'on passe d'une instruction à émettre à plusieurs. Plusieurs instructions sont mises en attente dans un ''scheduler'', et y attendent leur tour. L'idée est alors d'envoyer le registre de disponibilité à toutes les entrées, à toutes les instructions en attente. Ainsi, on sait quelles sont les instructions qui peuvent s'exécuter et celles qui ne le peuvent pas. L'implémentation est assez simple, elle ressemble beaucoup à l'implémentation d'un pipeline dynamique simple, si ce n'est que des circuits sont dupliqués. L'implémentation utilise des ''scheduler'' légèrement différentes de celles introduites plus haut. Elles n'utilisent notamment pas de bits de disponibilité, mais autre chose. Lorsqu'une instruction est ajoutée à le ''scheduler'', le masque de disponibilité des opérandes est stocké dans le ''scheduler''. A chaque cycle, le registre de disponibilité est envoyé à toutes les entrées, et est comparé avec tous les masques de disponibilité des opérandes. Si une comparaison renvoie un 1, alors l'instruction de l'entrée est une instruction candidate à l'émission. [[File:Unité d'émission dans le désordre basée sur un registre de disponibilité.png|centre|vignette|upright=2.5|Unité d'émission dans le désordre basée sur un registre de disponibilité]] L'ensemble est implémenté avec l'aide d'une '''matrice de bits''', où chaque ligne correspond à une entrée et chaque colonne à un registre. À chaque croisement entre une ligne et une colonne, on trouve un bit. Si le bit de la ligne n et de la colonne m est à 1, cela veut dire : l'instruction dans l'entrée n a besoin de lire le registre m. S’il est à 0, alors cela veut dire que l'instruction stockée dans la ligne n'a pas besoin de la donnée dans le registre m. [[File:Planificateur à matrice de bits.jpg|centre|vignette|upright=2|Planificateur à matrice de bits.]] Lorsqu'une instruction réserve une entrée, elle initialise la ligne en fonction des registres qu'elle souhaite lire. Pour vérifier si une instruction a ses opérandes prêts, le processeur compare le registre de disponibilité à la ligne associée à l'instruction/entrée. A chaque intersection ligne-colonne, se trouve un comparateur de 1 bit, qui détecte si le registre est demandé et disponible. Les résultats de cette porte sont ensuite envoyés à une porte ET, qui fait le gros du travail. [[File:Logique de détection de la disponibilité d'une instruction.jpg|centre|vignette|upright=2|Logique de détection de la disponibilité d'une instruction.]] ==Les ''schedulers'' basées sur une mémoire associative== Les processeurs modernes utilisent une mémoire associative pour le ''scheduler''. Les mémoires associatives ont été abordées il y a quelques chapitres, mais faisons quelques rappels. Les mémoires associatives servent à accélérer la recherche de données dans un ensemble. Or, un ''scheduler'' vérifie régulièrement si chaque entrée est prête. Il s'agit d'un processus de recherche d'une instruction qui respecte une condition bien précise dans la mémoire, ce qui fait que les mémoires associatives sont donc tout indiquées. Comme vous le savez, les signaux de commande d'une instruction sont propagés avec celle-ci dans le pipeline, le nom du registre de destination ne faisant pas exception. Le nom de registre est envoyé à le ''scheduler'' lors de l'écriture du résultat dans les registres. S'il y a correspondance, l'opérande est disponible et son bit de disponibilité est mis à 1. On peut adapter cette méthode pour tenir compte du contournement assez simplement. [[File:Détection des dépendances par propagation du registre de destination.png|centre|vignette|upright=2|Détection des dépendances par propagation du registre de destination.]] En conséquence, le circuit de détection des dépendances est constitué d'un grand nombre de comparateurs : un par champ « nom de registre » dans chaque entrée. La logique d'éveil/''wake up'' regroupe tous les comparateurs, la logique de sélection est un circuit situé en-dehors de la mémoire associative. Les entrées sont dans la mémoire associative elle-même. [[File:Gestion des bits de validité.png|centre|vignette|upright=2|Gestion des bits de validité.]] L'implémentation la plus simple est celle du schéma précédent, où on utilise une mémoire associative unique. Une version plus élaborée sépare le ''scheduler'' en deux parties : une mémoire qui mémorise les registres des opérandes, une autre mémoire pour le reste. La mémoire pour les registres opérandes est la mémoire associative proprement dite, c'est elle qui est associée aux comparateurs, à la logique de ''wake-up''/réveil, etc. Par contre, l'autre mémoire est une mémoire RAM simplifiée, qui mémorise les informations qui n'ont pas besoin des comparateurs. L'opcode de l'instruction est là-dedans, par exemple. le ''scheduler'' est donc une sorte de mémoire associative améliorée. Il se trouve que c'est aussi le cas du ROB. Et il est possible de fusionner le tampon de ré-ordonnancement avec le ''scheduler'' dans une structure unique. La différence avec un ''scheduler'' normal est que les entrées sont libérées non pas quand l'instruction est exécutée/émise, mais quand elle termine son exécution et quitte le ROB. le ''scheduler'' incorpore des bits dans chaque entrée, pour savoir si la µops associée a été émise et est en cours de traitement dans les ALUs. La méthode a notamment été utilisée sur les processeurs d'architecture K6 d'AMD. Le tout donnait une structure appelée le '''DRIS''' (''deferred scheduling register renaming instruction shelf''). Les processeurs PA 8000 de HP étaient aussi vraisemblabment dans ce cas, aussi. ===Les optimisations de la consommation d'énergie : la désactivation des portions inutilisées=== Le problème avec des ''scheduler'' de ce type est leur forte consommation énergétique, ainsi que le grand nombre de portes logiques utilisées, qui deviennent prohibitifs pour des ''scheduler'' un peu grosses. Pour résoudre ce problème, certains ont optimisé les comparateurs. D'autres ont tenté de profiter du fait que la majorité des bits dans les entrées sont composés de zéros. Bref, les optimisations purement matérielles sont légion. Une première solution est de désactiver les entrées qui sont inutilisées, vides, sans instruction. Pour cela, on fait précéder les comparateurs par un circuit qui les connecte ou déconnecte des lignes de bit. Le circuit est commandé par le bit ''empty'' qui indique si une entrée est vide ou non. L'avantage est que la consommation d'énergie de le ''scheduler'' devient alors proportionnelle au nombre d'entrées non-vides, et non au nombre d'entrées total. Du moins, en apparence, les entrées non-utilisées doivent quand même être alimentées pour fonctionner, mais l'activité de comparaison disparait dans les entrées vides. Il est possible d'étendre cette technique aux entrées dont les opérandes sont prêts. Les gains sont généralement assez bons, avec une réduction de consommation variant entre 30 et 50%, avec une implémentation très simple et très économe en circuits. Une autre solution, assez simple à mettre en place, consiste à désactiver une partie de le ''scheduler'' sin elle est inutilisée. Pour cela, il faut segmenter le ''scheduler'' avec la technique du ''wire partitionning''. Pour rappel, un ''scheduler'' est une mémoire associative. Et comme toute mémoire associative, elle contient des fils, les lignes de bit, qui relient les entrées/sorties à toutes les cellules mémoire. Plus une ligne de bit est longue, plus elle consomme d'énergie et plus le temps de lecture/écriture est long. L'idée est de segmenter les lignes de bits en plaçant des répéteurs qui recopient la tension d'un segment au suivant. Les répéteurs sont des tampons trois-états, ce qui permet de déconnecter les portions inutilisées de la ligne de bit. Ce faisant, le ''scheduler'' est découpée en segments, qui peuvent être désactivés si besoin. S'il y a peu d'instructions chargées dans le ''scheduler'', les portions inutilisées sont désactivées. La technique marche d'autan mieux si les instructions sont compactées au début de le ''scheduler''. [[File:Wire partitionning.png|centre|vignette|upright=2|Wire partitionning]] Tout le problème est de savoir quelles portions désactiver. La technique est assez simple si le ''scheduler'' est compactée, à savoir si toutes les instructions sont régulièrement regroupées au début de la mémoire CAM. Mais même avec cette optimisation, la décision de désactiver une portion de le ''scheduler'' n'est pas à prendre à la légère. Il ne faut pas désactiver une portion contenant des instructions pouvant être émise sous peu. La décision dépend de paramètres variés : proportion d'entrée vides, quantité d'entrées récemment activées/désactivées récemment, présences d'entrées avec un ''match'' d'opérandes récent, etc. Il est important de préciser que les techniques en question fonctionnent aussi sur les autres types de ''scheduler'', qui ne sont pas basées sur des mémoires associatives. Nous allons voir celles-ci dans la suite du chapitre, mais gardez à l'esprit que ces optimisations, à savoir désactiver les entrées vides/prêts et partitionner le ''scheduler'', sont des optimisations générales qui marchent avec presque tout. ===L'ajout d'une FIFO pour les instructions déjà prêtes à l'émission=== D'autres techniques permettent de réduire aussi bien le cout en circuits que la consommation d'énergie de le ''scheduler''. L'idée est d'utiliser une mémoire associative quand elle est réellement nécessaire, mais d'utiliser un ''scheduler'' "normale" dès que possible. La méthode la plus simple tient compte du fait que certaines µopsont déjà toutes leurs opérandes de disponibles à l'émission, mais doivent quand même être mises en attente, parce que l'ALU adéquate est occupée, parce que des dépendances WAW/WAR sont encore là, ou pour tout autre raison. Dans ce cas, elles sont mises en attente non pas dans le ''scheduler'', mais dans une mémoire FIFO toute simple. L'idée est qu'au lieu d'avoir une énorme mémoire associative pour le ''scheduler'', on déplace quelques entrées dans une petite FIFO annexe. Le résultat est un gain d'énergie et de circuits, au prix d'une perte de performance mineure. La perte de performance en question se manifeste si aucune instruction n'a ses opérandes de prêtes à l'émission : le programme n'utilise pas la FIFO et voit alors un ''scheduler'' plus petite. Une amélioration de cette technique tient compte du fait que certaines instructions sont dans un cas intermédiaire. Elles ont déjà un opérande de prête lors de l'émission, mais pas l'autre. Le nombre d'opérandes varie suivant l’instruction : certaines n'ont besoin que d'un seul opérande. De plus, il arrive qu'une opération tout juste décodée ait déjà un ou plusieurs de ses opérandes de prêts. Cette constatation permet d'éviter d'utiliser des comparateurs pour les opérandes déjà prêts. Par exemple, on peut parfaitement utiliser trois ''scheduler'' : * une pour les instructions dont tous les opérandes sont prêts, mais qui sont quand même mises en attente, sans comparateur ; * une pour les instructions dont un seul opérande manque, qui n'utilise qu'un comparateur par entrée ; * une pour les instructions dont deux opérandes manquent à l'appel, qui utilise deux comparateurs par entrée. C'est beaucoup plus économique que d'utiliser une seule grosse ''scheduler'' qui contiendrait autant d'entrées que les trois précédentes réunies, avec deux comparateurs par entrée. Certains sont même allés plus loin, et ont proposé de supprimer le ''scheduler'' avec deux opérandes par entrée. Les instructions dont deux opérandes sont inconnus au décodage sont stockées dans le ''scheduler'' pour instructions avec un comparateur par entrée. Un circuit de prédiction se charge alors de prédire l'opérande manquant, cette prédiction étant vérifiée plus loin dans le pipeline. Il serait cependant étonnant qu'une telle proposition ait donné lieu à la moindre implémentation réelle. ===Les optimisations de la consommation d'énergie avancées=== D'autres chercheurs ont conservé un ''scheduler'' unique, avec autant de comparateurs par entrée qu'il y a d'opérandes possibles par instruction. Simplement, le processus de détection des opérandes prêts est légèrement ralenti : on ne vérifie qu'un opérande par cycle. Pour vérifier les deux opérandes d'une entrée, on doit attendre deux cycles. Enfin, certains chercheurs ont proposé des ''scheduler'' segmentées. Les instructions circulent à chaque cycle d'un segment vers le suivant : en conséquence, certains segments conservent les instructions les plus anciennes, un autre les instructions les plus jeunes, etc. Seul le denier segment, celui qui contient les instructions les plus vielles, peut émettre une instruction : la détection des opérandes se fait seulement dans le dernier segment, qui contient les instructions les plus anciennes. On économise ainsi beaucoup de comparateurs. Certains chercheurs ont tenté de pipeliner l'étape de sélection des opérandes, ainsi que l'étage d'arbitrage. Mais en faisant cela, il faut plusieurs cycles pour détecter qu'une instruction a ses opérandes prêts, ce qui pose problème face à de nombreuses dépendances RAW. Pour éviter de trop perdre en performances, certains chercheurs ont décidé d'utiliser des techniques pour prédire quelles seront les instructions dont les opérandes seront bientôt prêts. Si détecter qu'une instruction est prête prend n cycles, le processeur devra tenter de prédire la future disponibilité des opérandes n cycles en avance pour obtenir des performances optimales. ===Remplacer la mémoire associative par une RAM=== Une autre optimisation possible est de remplacer le ''scheduler'' par une mémoire RAM, dont chaque mot mémoire correspondrait à une entrée. Une telle optimisation permet en théorie de se passer des comparateurs associés à chaque entrée, mais au prix de l'ajout de circuits annexes potentiellement couteux. La première de ces techniques, la '''recherche directe par étiquette''' (direct tag search) fut créée par Weiss et son collègue Smith. Ils cherchaient à améliorer l'algorithme de Tomasulo, un algorithme qu'on expliquera dans quelques chapitres. Rappelons que chaque instruction produit un résultat, qui devra être rapatrié dans une ou plusieurs entrées de le ''scheduler''. L'optimisation de la recherche directe par étiquette fonctionne dans le cas où le résultat de l'instruction n'est utilisé que par une seule entrée, et pas plusieurs. Le principe est simple : chaque champ « opérande » d'une entrée est adressable via le nom de registre de cet opérande. Pour faire le lien entre entrée et nom de registre, la recherche directe par étiquette ajoute une table de correspondances matérielle, une mémoire RAM qui mémorise les adresses des champs « opérande » des entrées. Les adresses envoyées dans cette mémoire sont les noms de registres des résultats. Lors de l'émission, la table de correspondances est mise à jour. Les numéros des champs « opérande » réservés lors de l'émission sont mémorisés dans les mots mémoire qui correspondent aux deux registres sources. Toutefois, une petite vérification est faite lors de l'émission : s'il y a déjà une correspondance dans la table pour un registre source, alors une autre instruction compte lire ce registre. Pour éviter d'écraser les données de l'instruction précédente dans la table de correspondances, l'émission de l'instruction est bloquée. [[File:Recherche directe par étiquette.png|centre|vignette|upright=2|Recherche directe par étiquette.]] ==Les ''schedulers'' avec préplanification== Avec la '''préplanification''' (''prescheduling''), le ''scheduler'' est composée de mémoires FIFO dans lesquelles les instructions sont triées dans l'ordre d'émission. Il n'y a pas de logique d’émission proprement dite, celle-ci se bornant à vérifier si l'instruction située au début de la FIFO peut s’exécuter. Par contre, le préplanificateur détecte les dépendances et en déduit où insérer les instructions dans le tampon d'émission, à l'endroit le plus adéquat. [[File:Préplanification.jpg|centre|vignette|upright=2|Préplanification.]] ===L'usage de FIFO multiples=== La technique de préplanification la plus simple utilise plusieurs FIFO. Quand une instruction a une dépendance avec une autre instruction, les deux sont placées dans la même FIFO. Pour cela, le préplanificateur détecte les chaines d'instructions dépendantes, et place les instructions dans la FIFO adéquate. A chaque cycle, l'unité d'émission lit une micro-opération dans chaque FIFO et vérifie si elle peut l'émettre. Si la micro-opération n'a pas ses opérandes disponibles, ou qu'une dépendance structurelle survient, alors la FIFO est bloquée. La micro-opération attend que la dépendance soit résolue, bloquant toutes les instructions précédentes. Mais les autres FIFO ne sont pas bloquées, laissant de la marge de manœuvre. [[File:Préplanification par FIFO multiples.png|centre|vignette|upright=1.5|Préplanification par FIFO multiples.]] ===La technique du tampon trié=== La technique du '''tampon trié''' trie les instructions selon le temps d'attente avant leur exécution. Les instructions qui sont censées s’exécuter bientôt sont insérées au tout début de la FIFO, tandis que les instructions qui s’exécuteront dans un long moment sont insérées vers la fin. Là encore, l'unité d'émission lit une micro-opération dans la FIFO, et détermine si elle peut être émise. Si une dépendance survient, l'émission est retardée, et la FIFO est bloquée. [[File:Préplanification par tampon trié.png|centre|vignette|upright=1.5|Préplanification par tampon trié.]] La technique a cependant quelques problèmes assez importants. Le premier problème est que la FIFO est bloquée lorsqu'une micro-opération ne peut être émise. Le second problème est que le temps avant exécution n'est pas toujours connu, notamment pour les instructions d'accès mémoire. Et cela se répercute sur les instructions dépendantes de celles-ci. Pour résoudre ce genre de problèmes, l'usage d'un pipeline à ''replay'' est possible, et est même l'une des meilleures solutions possible, malgré ses défauts. L'idée est que les lectures sont pré-planifiées en supposant qu'elles font un succès de cache L1. Si la prédiction est fausse, la lecture est ré-exécutée plusieurs cycles plus tard, en supposant qu'elle fait un succès dans le cache L2, et ainsi de suite. Elle est alors ré-insérée dans la FIFO, elle est pré-planifiée une seconde fois. Il en est de même si une micro-opération ne peut pas être émise : il suffit de la réinsérer dans la FIFO au bon endroit, en attendant que ses dépendances soient résolues. Ainsi, l'instruction fautive ne bloque pas le ''scheduler'', et retente sa chance autant de fois qu'il le faut. [[File:Préplanification par fenêtre d’instruction scorebarodée.png|centre|vignette|upright=1.5|Préplanification par ''scheduler'' scorebarodé.]] Une autre solution utilise deux ''schedulers'' : une FIFO gérée par la préplanification, et une vraie ''scheduler'' pour les instructions dont le temps d'attente ne peut pas être déterminé. Il est possible de mettre cette dernière avant la préplanification, afin de gérer les temps d'attente des instructions d'accès mémoire. Quand le temps d'attente d'une lecture devient connu, ses instructions dépendantes sont gérées avec préplanification. [[File:Préplanification avec fenêtre d’instruction.png|centre|vignette|upright=2.5|Préplanification avec ''scheduler''.]] ===Les ''scheduler'' avec allocation temporelle statique=== L''''allocation temporelle statique''' correspond à une technique utilisée sur les processeurs Cuzco de l'entreprise Condor. La technique en question a été présenté en 2025, mais des idées similaires ont été présentées dans la littérature académique. Elle ressemble beaucoup aux techniques de pré-planification, avec cependant quelques différences. L'idée est simple : le processeur dispose de plusieurs ''scheduler'', qui mettent en attente les micro-opérations. Lors de l'étape de renommage de registres, le processeur détermine dans combien de cycles d'horloge la micro-opération sera prête pour exécution. La micro-opération est alors mise en attente durant ce nombre de cycles, dans les ''scheduler'', puis est émise une fois ce nombre de cycles écoulés. Ce faisant, les ''scheduler'' n'ont pas besoin de détecter la disponibilité des opérandes à chaque cycle, pour chaque micro-opération en attente. Le ''timing'' de l'émission des micro-opérations est décidé à l'avance. L'implémentation exacte n'est pas connue, mais plusieurs solutions sont imaginables. Par exemple, le ''scheduler'' peut simplement être composée de plusieurs mémoires de petite taille, chacune contenant les micro-opérations destinées à être exécutées dans N cycles, N étant différent pour chaque mémoire. Une autre solution, plus réaliste, utilise un ''scheduler'' dans laquelle la micro-opération est couplée à des champs pour les opérandes, et un champ compteur. Le champ compteur est initialisé avec le nombre de cycles à attendre, et est décrémenté à chaque cycle d'horloge. Quand il atteint zéro, la micro-opération est émise. Vous remarquerez que la méthode ne marche que si toutes les micro-opérations prennent un nombre fixe de cycles d'horloge. Et autant c'est le cas pour les micro-opérations arithmétiques ou logiques, autant les accès mémoire ne rentrent pas dans ce cadre. En théorie, on ne sait pas combien de temps prendra un accès mémoire. Et cette incertitude se répercute sur les instructions dépendantes d'un accès mémoire. Pour éviter cela, le processeur réutilise un pipeline à ''replay'' tel que vu dans le chapitre précédent. L'unité de renommage de registre suppose que tout accès mémoire fait un succès de cache L1, et décide des ''timings'' d'émission sous cette hypothèse. Si une lecture subit un défaut de cache, elle est ré-exécutée, de même que toutes les instructions dépendantes. Pour cela, le registre de destination de la lecture est marqué comme invalide, grâce à un bit spécifique attaché au registre. Toute instruction qui lit un opérande invalide est elle aussi ré-executée de zéro. Pour simplifier, l'unité d'émission ressemble à une unité d'émission dans l'ordre, avec un registre de disponibilité, qu'on aurait amélioré pour aller au-delà de la simple détection des dépendances d'instruction. Pour déterminer les ''timings'' d'émission, à savoir quand émettre une micro-opération, le processeur utilise une unité d'émission à deux étages. Le premier étage est appelé le ''register scoreboard'', le second étage est appelé la ''Time Ressource Matrix''. Les deux étages communiquent entre eux, comme on va le voir, et leurs noms donnent une idée de ce qu'ils font. Le premier étage gère les dépendances de registres, le second gère les dépendances structurelles. Le premier étage est un registre de disponibilité amélioré, qui gère les dépendances de registre. Cet étage sait quand tel registre sera écrit, et donc que l'opérande écrit dedans sera disponible à partir de tel cycle d'horloge. Il le sait car l'étage suivant l'aura prévenu, mais laissons cela de côté pour le moment. Quand une micro-opération rentre dans cet étage, il vérifie les dépendances avec les registres et les micro-opérations antérieures. Vu qu'il sait quand les registres seront disponibles, il peut déterminer quand l'instruction pourra s'exécuter. Par exemple, si une micro-opération lit les deux registres R7 et R15, qui sont disponibles respectivement dans 5 et 7 cycles, le premier étage sait que la micro-opération devra attendre 7 cycles. Mais tout cela ne suffit pas à déterminer quand émettre une micro-opération. En effet, il fait aussi gérer les dépendances structurelles, ce qui est le boulot du second étage. Le second étage utilise pour cela une ''Time Ressource Matrix'', qui mémorise l'occupation de diverses "ressources", pour les 256 cycles d'horloge à venir. Les ressources en question sont les ports de lecture/écriture du banc de registre, les ALUs utilisées, si la micro-opération utilise l'unité mémoire, etc. Le second étage prend en entrée une micro-opération, détermine quelles "ressources" elle utilise, puis regarde leur disponibilité. Elle détecte alors les dépendances structurelles et détermine alors quand peut s'exécuter la micro-opération. Elle peut retarder l'émission de quelques cycles, si une dépendance structurelle est détectée. Une fois sortie du second étage, on sait quand la micro-opération va être émise, à quel cycle précisément. Et vu que la durée de l'instruction est fixe, on sait quand cette micro-opération va se terminer, quand son résultat sera disponible. Cela permet de mettre à jour la ''Time Ressource Matrix'', pour préciser que le port d'écriture sera occupé à tel moment. De plus, cette information est transmise au premier étage, qui sait alors quand est enregistré le résultat dans le registre de destination. C'est comme cela que le premier étage sait quand un registre est disponible : le second étage le prévient, quand il émet une instruction ! La ''Time Ressource Matrix''mémorise l'occupation des "ressources" pour les 256 cycles d'horloge à venir. Cependant, elle ne vérifie pas les dépendances pour les 256 cycles suivants. Quand elle reçoit une micro-opération, elle teste les dépendances structurelles pour seulement les 8 prochains cycles maximum. Si la micro-opération ne peut pas être émise pendant ces 8 cycles, le pipeline est bloqué, un ''pipeline stall'' est émis. Pour être plus précis, vu que le processeur peut décoder 8 micro-opérations en même temps, cela permet de ne consulter que 64 cycles d'horloge sur les 256. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les premiers processeurs Intel | prevText=Les premiers processeurs Intel | next=Le renommage de registres | nextText=Le renommage de registres }} </noinclude> nkavxhu9cv9cnqyomdw2pgbzgif2pdd 773676 773675 2026-09-29T23:01:08Z Mewtow 31375 773676 wikitext text/x-wiki Dans les chapitres précédents, nous avons parlé des techniques dites d''''émission dans l'ordre'''. L'idée est d’exécuter une nouvelle micro-opération à chaque cycle, dans des unités de calcul séparées. Les instructions sont émises consécutivement, mais les instructions s’exécutent en parallèle dans des unités de calcul séparées. Par contre, quand l'unité d'émission ne peut pas émettre une instruction, elle bloque tout le pipeline. Les instructions qui suivent sont elles aussi bloquées, elles doivent attendre leur tour, même si elles sont en capacité de s'exécuter. Les techniques d'exécution dans le désordre que nous allons voir dans ce chapitre corrigent ce point précis. Elles sont dites à '''émission dans le désordre'''. Elles se distinguent des précédentes sur un point précis : quand l'unité d'émission bloque l'émission d'une instruction, les instructions suivantes peuvent poursuivre. L'émission des instructions peut donc se faire dans le désordre, dans le sens où une instruction peut être émise alors qu'une instruction précédente ne l'est pas encore. Mais avant de poursuivre, quelques point niveaux terminologie : * L'émission dans le désordre est un terme parlant et assez précis. Malheureusement, la terminologie la plus utilisée par d''''exécution dans le désordre'''. Et nous utiliserons ce terme dans la suite du cours, histoire de ne pas trop dévier de la nomenclature habituelle. * Nous utiliserons parfois l'abréviation OOO pour parler d'exécution dans le désordre. L'abréviation est celle de ''Out Of Order Execution''. * Nous utiliserons aussi l'abréviation ''µop'' pour parler de micro-opération, ''µops'' au pluriel pour parler de plusieurs micro-opérations, ou des micro-opérations en général. L'exécution dans le désordre ne gère en effet que des µops, elle se situe après l'étape de décodage. Pour décrire comment est implémentée l'émission dans le désordre, il faut commencer par parler des processeurs sans. Les processeurs sans exécution dans le désordre ont une unité d'émission qui bloque tout le pipeline dès qu'une µop ne peut pas être émise. Pour limiter l'impact de ce blocage, quelques rares processeurs incorporent une '''file de micro-opération''', une mémoire FIFO qui met en attente les µops. Vu que c'est une mémoire FIFO, les µops sont émises dans l'ordre, à savoir l'ordre d'ajout, dans l'ordre de décodage. Le schéma ci-dessous illustre une telle file d'attente couplée à un ''scoreboard''. L'exécution dans le désordre améliore la file de µops sur un point : ce n'est plus une mémoire FIFO. Les µops sont insérées dans l'ordre, mais peuvent sortir dans le désordre (être émises dans le désordre). La file de µops devient alors un '''''scheduler''''', terme anglais que je ne compte pas traduire. Un terme équivalent est '''''scheduler''''', terme traduit directement de l'anglais ''instruction Window''. Terme assez trompeur, car elles mettent en attente des µops, pas des instructions. [[File:Différence file µops et fenêtres instruction.png|centre|vignette|upright=2|Différence file µops et ''schedulers'' ]] Le ''scheduler'' émet une µop dès que ses opérandes sont disponibles. Par disponible, on veut dire présent soit dans le réseau de contournement, soit dans les registres. Le ''scheduler'' détecte automatiquement quand les opérandes d'une µop sont disponibles, grâce à une unité d'émission intégrée. L'unité d'émission et le ''scheduler'' sont fusionnés ensemble, dans un seul circuit, mais nous allons dire qu'ils sont conceptuellement séparés pour le moment. À chaque cycle, l'unité d'émission consulte les µops en attente pour détecter lesquelles peuvent s'exécuter. Le ''scheduler'' est spécialement être conçue pour, c'est une sorte de mémoire associative très complexe, comme on le verra dans ce qui suit. [[File:OOO Issue.png|centre|vignette|upright=2.5|Exécution dans le désordre avec un ''scheduler'']] Une fois qu'une µop sort du décodeur d'instructions, elle est ajoutée en parallèle dans le ''scheduler'' et le ROB. La raison est que les µops quittent le ''scheduler'' dans le désordre, et qu'elles doivent être remises en ordre par la suite. Le ROB s'occupe de cette remise en ordre, mais il a besoin de savoir dans quel ordre les µops sont censées être, et cet ordre est celui du décodage. Aussi, pour remplir le ROB, la seule opportunité est en sortie de l'unité de décodage. Dans le cas où une instruction est décodée en plusieurs micro-opérations, elles sont toutes insérées en même temps dans le ''scheduler'' et le ROB, en tenant compte de leur ordre. L'implémentation la plus "simple" de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Les µops décodées sont accumulées dans le ''scheduler'', où elles attendent leur tour. le ''scheduler'' sert donc de file d'attente. Bien que simple en apparence, cette implémentation cache une complexité très importante, liée aux accès mémoire. Les micro-opérations mémoire sont à part des autres, pour ce qui est de leurs dépendances de données. Non seulement elles ont des dépendances de registre, mais elles sont aussi des dépendances d'adresse. Par exemple, deux écritures peuvent utiliser deux registres d'adresse différents, mais ceux-ci peuvent contenir la même adresse. Et autant on peut détecter les dépendances de registre lors de l'émission, autant c'est plus compliqué avec les dépendances d'adresse. De plus, rappelons que si les lectures peuvent s'exécuter dans le désordre, les écritures doivent s'exécuter dans l'ordre, ou du moins en donner l'illusion. Pour cela, le processeur remet les écritures dans l'ordre avec une sorte de mini-ROB intégré à l'unité mémoire, appelée la file d'écriture. Elle complémente le ROB, qui lui ne gère que les écritures dans les registres, mais les deux collaborent. La file d'écriture envoie une écriture à la mémoire RAM quand le ROB lui dit que c'est bon, les instructions précédentes sont terminées ''dans l'ordre du programme''. Les processeurs modernes ajoutent des techniques d'exécution dans le désordre des accès mémoire, mais nous les verrons dans un chapitre dédié. Elles permettent d'utiliser un ''scheduler'' unique, qui mémorise aussi les µops mémoire. Si elles sont mises en place, l'unité mémoire n'a pas besoin de file de µops séparée. L'idée est que les dépendances de registre sont traitées par le ''scheduler'', mais que l'unité mémoire gére les dépendances d'adresse. Les dépendances d'adresse sont gérées par des techniques de ''désambiguation mémoire'', qui auront droit à un chapitre dédié. [[File:Processeur avec exécution dans le désodre des accès mémoire.png|centre|vignette|upright=2|Processeur avec exécution dans le désodre des accès mémoire]] Les processeurs assez anciens n'autorisaient pas d'exécution dans le désordre des accès mémoire. Concrètement, les accès mémoire devaient se faire dans l'ordre, mais les autres µops pouvaient être exécutées dans le désordre. Il s'agit donc d'un ordre entre µops mémoire, pas entre µops mémoire et autres µops. Les µops entières et flottantes pouvaient être exécutées avant une µops mémoire qui est avant elle dans l'ordre du programme, ce n'est pas un problème. Pour garantir l'ordre des µops mémoire, l'unité mémoire est précédée par une file de micro-opérations séparée, pour forcer l'exécution dans l'ordre des accès mémoire. De plus, les µops mémoire ne peuvent pas utiliser le ''scheduler''. Dit autrement, le ''scheduler'' ne mémorise pas de µops mémoire. Après le décodage, les µops sont réparties soit dans la file de µops mémoire, soit dans le ''scheduler''. Le décodeur classe les µops suivant que ce sont des µops mémoire ou non, et les envoient à la bonne destination. Dans ce chapitre, on supposera que c'est cette solution qui est utilisée. [[File:Processeur avec émission dans l'ordre des accès mémoire.png|centre|vignette|upright=2|Processeur avec émission dans l'ordre des accès mémoire]] ==L'implémentation d'un ''scheduler'' : généralités== Un ''scheduler'' est une mémoire qui mémorise des micro-opérations. Elle est cependant plus complexe qu'une mémoire RAM ou qu'une FIFO et ressemble un petit peu à une mémoire cache. Elle dispose d'un port d'écriture et d'un port de lecture, au minimum. Le port d'écriture permet à l'unité de décodage d'insérer une micro-opération dedans, d'ajouter la micro-opération qui vient d'être décodée. Si une instruction machine est décodée en plusieurs micro-opération, deux possibilités. La première est de les insérer un par un, ce qui fait qu'on peut se contenter d'un seul port d'écriture. L'autre possibilité est de les ajouter en même temps, ce qui demande plusieurs ports d'écriture. Le port de lecture sert à émettre une instruction. On part du principe que le ''scheduler'' ne peut émettre qu'une seule instruction à la fois, car les processeurs que nous avons vu précédemment sont de ce type. Mais nous verrons dans quelques chapitres qu'il existe des processeurs dits superscalaires, qui sont capables d'émettre plusieurs instructions par cycle. Dans ce cas, le ''scheduler'' a un seul port de lecture. Un processeur superscalaire, quant à lui, doit avoir un port de lecture par unité de calcul, ce qui fait beaucoup plus. Les ''schedulers'' sont composées d''''entrées''', des mots mémoire qui stockent une instruction. Une instruction réserve une entrée après son décodage et la libère dès qu'elle est envoyée aux unités de calcul. Une entrée contient l'opcode (les signaux de commande à envoyer à l'ALU), le registre de destination du résultat, les registres de chaque opérande, et éventuellement des signaux de commande en plus. De plus, chaque opérande est couplée à un bit de disponibilité, qui indique si elle est disponible. Quand un opérande est écrit dans les registres, le bit de présence correspondant est mis à jour. Enfin, chaque entrée possède un bit ''empty'' qui indique si elle est vide, cette information étant utile pour réserver des entrées. [[File:Entrée d'une station de réservation - sans les tags.png|centre|vignette|upright=3|Entrée d'un ''scheduler'']] ===Les stations de réservation=== Les '''stations de réservation''' sont des ''scheduler'' particulières, qui sont capables de mémoriser les opérandes des instructions. Les entrées des stations de réservation sont identiques à celle des autres ''scheduler'', si ce n'est que les opérandes de l'instruction sont enregistrés directement dans des champs séparés. Il y a deux champs, un par opérande, pour stocker l'opérande elle-même, lue depuis les registres ou obtenue via le réseau de contournement. Notons que les champs pour les opérandes viennent en plus des champs pour les noms de registres, encore que les deux peuvent être fusionnés si on veut optimiser le tout. [[File:Entrée d'une station de réservation.png|centre|vignette|upright=3|Entrée d'une station de réservation.]] Précisons que la terminologie n'est pas très fiable. Les termes "''scheduler''" et "station de réservation" ne regroupent pas du tout la même chose d'un papier de recherche à l'autre, d'un bouquin à l'autre, d'un chercheur à l'autre, d'un ingénieur à l'autre, d'un professeur à l'autre. Le terme initial vient pourtant de l'article original sur l'algorithme de Tomasulo, où il désignait un ''scheduler'' associée à une unité de calcul précise. Mais le terme a ensuite été réutilisé, ce qui fait que certains processeurs avec plusieurs unités de calcul sont décrits comme ayant une unique station de réservation. En bref : c'est le bazar ! Mais nous en reparlerons dans le chapitre sur le renommage de registres, car c'est la place idéale pour les aborder. Toujours est-il que j'ai fait le choix de confondre les concepts de ''scheduler'' et de station de réservation avec les concepts de '''lecture avant émission''' et de '''lecture après émission'''. La différence entre les deux est que les registres sont lus après émission avec un ''scheduler'', avant avec des stations de réservation. Dans le cas "avant émission", les opérandes sont mémorisés dans la station de réservation. Et cette différence a une influence sur le pipeline du processeur, le banc de registres et tout ce qui s'ensuit. Un désavantage de la lecture avant émission est qu'il faut stocker les opérandes après lecture, ici dans les stations de réservation. Mais un avantage est que le banc de registre a besoin de moins de ports de lecture, car une bonne partie des opérandes sont fournies par le système de contournement. Nous verrons cela dans le détail dans le chapitre sur les processeurs superscalaires. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Lecture après émission.]] [[File:Read Before Issue.png|centre|vignette|upright=2.5|Lecture avant émission.]] ===La logique d'éveil et de sélection=== Dans le cas qui va suivre, on suppose que le processeur ne peut émettre qu'une instruction à la fois. Chaque cycle, une instruction est sélectionnée et est envoyée dans le chemin de données, soit à une ALU, soit à une unité d'accès mémoire. La sélection d'une instruction est effectuée par l'unité d'émission, qui est aussi appelée le '''''scheduler'''''. Elle gère la disponibilité des opérandes et la disponibilité des unités de calcul adéquate. Le choix de l'instruction émise doit être le plus pertinent possible, pour des raisons de performances. Pour le premier point, l'unité d'émission détermine quelles instructions sont candidates pour l'émission. Les ''instructions candidates'' sont celles dont tous les opérandes sont prêts. Le processeur contient un circuit qui détecte les instructions candidates : la '''logique d’éveil''' (''wake-up logic''). Une fois que la logique d'éveil a fait son travail, une instruction est choisie pour s’exécuter en fonction de la disponibilité des unités de calcul adéquates. Ce rôle est dévolu à un circuit qu'on appelle la '''logique de sélection''', ou ''select logic''. [[File:Fonctionnement complet de la logique d’émission.jpg|centre|vignette|upright=1.5|Fonctionnement complet de la logique d’émission.]] La logique de sélection doit gérer le fait que les unités de calcul du processeur ne sont pas toutes identiques. Déjà, un processeur a généralement des unités séparées pour les instructions entières et flottantes, des unités spécialisées dans les accès mémoire, parfois des unités spécialisées pour les branchements. Une instruction doit être attribuée à la bonne unité de calcul, on ne doit pas envoyer une instruction entière dans une unité de calcul flottante. De plus, parmi les unités de calcul entières, toutes ne sont pas identiques. Par exemple, il est fréquent d'avoir plusieurs unités de calcul spécialisées dans les opérations simples (additions, soustractions, opérations logiques) avec une unité pour les multiplications/divisions séparées, parfois une unité spécialisée pour les décalages/rotations, etc. Là encore, allouer la bonne instruction à la bonne ALU est complexe. Plus les unités de calcul sont hétérogènes, plus la logique de sélection est compliquée. Les logiques d'éveil comme de sélection sont assez complexes. Comme on le verra plus bas, la logique de sélection la plus simple, qui gère une seule unité de calcul, est basée sur un encodeur à priorité, couplé à d'autres circuits. Et pour gérer plusieurs ALUs, il faut mettre des encodeurs en cascade. Le résultat est que même en prenant une logique de sélection simple, elle sera assez lente et gourmande en circuits. Aussi, la logique de sélection met souvent un cycle d'horloge entier pour faire son travail, elle a son propre étage de pipeline attribué. La logique d'éveil est dans le même cas, ce qui fait qu'émettre une micro-opération demande deux cycles d'horloge. Le défaut est que cela rajoute des cycles d'horloges entre le ''scheduler'' et l'ALU, ce qui complique la gestion du pipeline. Ces cycles de retard sont à prendre en compte au moment d'émettre les instructions, les ''scheduler'' doit en tenir compte pour des performances optimales. Sans tenir compte de ces cycles de retard, les instructions arrivent en retard de quelques cycles à l'ALU, cycles de retard durant lesquels l'ALU n'a pas fait de calcul et a été sous-utilisée, sans compter que le système de contournement n'est pas utilisé au mieux. Et le problème est encore plus important sur les processeurs avec des stations de réservation, qui utilisent la "lecture après émission" : cela rajoute un cycle d'horloge en plus, un temps de retard en plus. ===La logique d'éveil : l'émission anticipée=== La logique d'éveil doit tenir compte du fait qu'il y a plusieurs étages entre l'émission et l'exécution sur une unité de calcul. Par exemple, un processeur a souvent entre un et à cinq étages entre la file d'attente et les unités de calcul. Il faut lire les registres, gérer le contournement, et cela peut prendre quelques cycles d'horloge. Sur le Pentium 4, on trouve 6 étages entre le ''scheduler'' et l'entrée de l'ALU. Si les micro-opérations sont émises quand les opérandes sont disponibles, il y aura un délai de quelques cycles avant qu'elles atteignent l'ALU. Alors qu'idéalement, on souhaiterait que la micro-opération atteigne l'ALU dès que ses opérandes sont disponibles, pour profiter des techniques de contournement. Pour cela, la logique d'éveil émet les instructions quelques cycles en avance pour qu'elles arrivent au bon moment. Il s'agit d'une technique d''''émission anticipée''', dont nous avions parlé dans le chapitre sur le contournement. : Il faut noter que le problème se pose plus avec des ''schedulers'' qu'avec des stations de réservation. Les premières ont un étage en plus entre émission et ALU, vu qu'il faut lire des registres après l'émission. L'émission anticipée demande d'émettre un signal d'éveil en avance de quelques cycles, pile au bon moment. Par exemples, si on a deux étages entre l'ALU et l'unité d'émission, le signal de réveil sera généré deux cycles avant que le résultat soit effectivement calculé. L'implémentation varie, mais deux solutions sont possibles. La première est de générer le signal d'éveil dans l'ALU, ce qui n'a de sens que pour les opérations comme les multiplications ou les divisions, qui prennent plusieurs cycles. Une autre technique génère le signal de réveil dans une structure centralisée, spécialisée dans la génération des signaux d'éveil. L'unité de composée d'un registre à décalage par registre. Imaginons qu'une instruction est émise, que cette instruction mette N cycles à s'exécuter, et qu'elle écrive dans un registre de destination. L'unité sélectionne alors le registre à décalage associé au registre de destination, et met le bit numéro N à 1. Le registre décalé d'un cran à chaque cycle. Quand le bit sortant est un 1, alors le signal de validité pour l'opérande est généré. L'émission anticipée marche bien si l'instruction a une durée fixe, connue à l'avance. Et autant c'est le cas pour les instructions arithmétiques et logiques, autant ce n'est pas le cas pour les accès mémoire. Les accès mémoire ont une latence variable : quelques cycles pour un succès de cache, plusieurs dizaines de cycles pour un défaut de cache L1, pas loin de la centaine pour un défaut de cache L2, etc. Et cela pose des problèmes pour l'émission anticipée. L'émission en avance pour les accès mémoire est purement spéculative : le processeur émet des instructions en supposant que la lecture entrainera un succès de cache, quitte à annuler l'instruction en cas de défaut de cache. Mais faire ainsi demande non seulement d'annuler les instructions émises en avance, mais aussi de ne pas retirer les instructions émises en avance de le ''scheduler''. Elles sont émises, mais une copie de sauvegarde est conservée dans le ''scheduler''. Si le processeur détecte un défaut de cache, il peut alors ré-exécuter l'instruction. S'il détecte un succès de cache, les instructions lecture-dépendante sont retirées de le ''scheduler'', la copie de sauvegarde est devenue inutile et est donc jetée. ===La logique de sélection : âge ou position ?=== La logique de sélection est primordiale pour de bonnes performances. Il existe deux méthodes principales pour sélectionner l'instruction à exécuter. La première est la plus simple : elle se base sur lé numéro de l'entrée. En effet, un ''scheduler'' est avant tout une sorte de mémoire, un mix entre mémoire associative, mémoire RAM, et FIFO. Et chaque entrée a un numéro, une adresse mémoire. Nous parlerons de numéro dans ce qui suit, car ce sera plus simple, le terme d'adresse mémoire étant peut-être un peu exagéré dans le contexte des ''scheduler''. Toujours est-il que le ''scheduler'' est adressable dans le sens où on peut lui envoyer le numéro de l'entrée voulue, et le ''scheduler'' renvoie le contenu de l'entrée sur son port de lecture. Et c'est ce que fait la logique de sélection : elle génère le numéro de l'entrée à lire. Le numéro est alors envoyé sur l'entrée d'adresse du ''scheduler'', et elle fournit la micro-opération associée sur son port de lecture, son '''port d'émission'''. La première méthode de sélection, donc. Elle est basée sur le numéro de l'entrée. Si plusieurs entrées sont éveillées, la logique de sélection prend celle avec le plus petit numéro. Elle porte le nom de '''sélection par position''', sous-entendu position dans le ''scheduler''. Vous l'avez peut-être deviné, mais la logique de sélection est alors un encodeur à priorité. Le circuit de sélection ne se résume donc pas seulement à un encodeur à priorité, mais c'est le circuit central. L'avantage d'une telle méthode de sélection est qu'elle est simple à implémenter : un encodeur à priorité est un circuit connu, facile à implémenter. Mais on remarque un défaut : un encodeur est un circuit assez rapide, mais qui utilise beaucoup de transistors, beaucoup de portes logiques, surtout si on veut qu'il soit rapide. Ce qui explique que la logique de sélection ait son propre étage de pipeline rien que pour elle. La seconde méthode s'appelle la '''sélection par âge''', au nom assez transparent. L'idée est de privilégier l'émission de l'instruction la plus ancienne. Elle demande que le ''scheduler'' trie les micro-opérations par ordre d'insertion dans le ''scheduler'', ce qui en fait une pseudo-FIFO. Le tri est partiel, car les instructions peuvent sortir du ''scheduler'' à tout moment. Compacter le ''scheduler'', à savoir regrouper toutes les entrées valides est une idée, mais elle est compliquée à implémenter. Aussi, elles préfèrent encoder des informations sur l'ordre d'émission dans chaque entrée. L'encodeur à priorité doit alors travailler non pas sur des nombres entiers liés à l'ordre d'insertion dans la pseudo-FIFO. Elle est encore plus gourmande en circuits que la méthode précédente. Les processeurs haute performance utilisent souvent des méthodes hybrides. Par exemple, les processeurs AMD de microarchitecture Bulldozer utilisaient une méthode intermédiaire. Ils utilisaient un ''scheduler'' couplée à un encodeur à priorité pour la sélection par position, mais complémentaient le tout avec une unité qui mémorisait l'instruction la plus ancienne dans le ''scheduler''. Le mécanisme de sélection par âge était utilisé en priorité. Mais si l'instruction la plus ancienne n'était pas prête, le processeur basculait sur le mécanisme de sélection par position. ===La compaction des ''scheduler''=== À chaque cycle, les instructions décodées sont ajoutées dans le ''scheduler'', dans des entrées vides. Vu que les instructions quittent celle-ci dans le désordre, ces vides sont dispersés dans le ''scheduler'', ce qui pose problème pour déterminer où placer les nouvelles instructions. La solution la plus triviale consiste à conserver une liste des vides, mise à jour à chaque insertion ou émission d'instruction. Une autre solution consiste à éliminer les vides en compactant le ''scheduler'' à chaque cycle d'horloge. Des circuits se chargent de détecter les vides et de regrouper les instructions en un unique bloc. Il faut signaler que certains processeurs arrivent à se passer de cette étape de compactage, mais au prix de ''scheduler'' nettement plus complexes. Autre problème : quand il faut choisir quelle instruction émettre, il y a toujours plusieurs candidats. Si on choisit mal, des instructions restent en attente trop longtemps parce que d'autres instructions plus jeunes leur passent devant. Pour éviter cela, les instructions les plus vielles, les plus anciennes, sont prioritaires. Pour cela, on peut utiliser une FIFO un peu spéciale pour le ''scheduler''. Si les ajouts d'instruction se font dans l'ordre, les instructions ne quittent pas forcément le ''scheduler'' dans l'ordre imposé par une FIFO : les instructions restent triées dans leur ordre d'ajout, même s'il y a des vides entre elles. Dans ces conditions, il est préférable que le compactage conserve l'ordre FIFO des instructions. Dans ces conditions, l'instruction la plus ancienne est celle qui est située à l'adresse la plus faible : le circuit de sélection peut donc être fabriqué avec des encodeurs, et est relativement simple. ==Les ''schedulers'' basées sur une matrice de dépendances== L'implémentation la plus simple étend le fonctionnement d'un pipeline dynamique usuel. Rappelez-vous le chapitre sur les pipelines dynamiques. Nous avions vu que de tels pipelines émettaient une instruction par cycle, quitte à émettre des bulles de pipeline en cas de dépendance bloquante. Et il est possible d'améliorer leur unité d'émission pour qu'elle soit compatible avec l'exécution dans le désordre. ===Rappels sur le registre de réservation/disponibilité=== L'émission d'une instruction est gouvernée par un ''registre de réservation'' qui indique quels registres sont réservés par une instruction, et ceux qui sont libres. Un registre réservé est un registre qui sera écrit par une instruction en cours d'exécution, mais qui n'a pas encore écrit son résultat. Les instructions candidates doivent avoir leurs opérandes dans des registres libres. Sinon, c'est signe que leurs opérandes sont réservés en écriture, donc pas encore écrites, donc pas disponibles. Si une instruction candidate veut lire ce registre, c'est signe qu'il y a une dépendance RAW : elle veut lire un registre réservé, qui est destiné à être écrit par une instruction en vol. Si elle veut écrire, c'est signe qu'elle veut écrire dans un registre où une autre instruction veut écrire : c'est une dépendance WAW. Dans les deux cas, l'instruction n'est pas émise. Le registre de réservation encode les registres réservés comme suit : chaque bit est associé à un registre. Le bit numéro 0 est associé au registre numéro 0, le bit numéro 1 au registre numéro 1, etc. Là, En clair, les numéros de registres réservés sont encodés en représentation non pas binaire, mais en représentation ''one-hot'' (vue au premier chapitre). {|class="wikitable" |+ Registre de réservation |- ! Registre 7 !! Registre 6 !! Registre 5 !! Registre 4 !! Registre 3 !! Registre 2 !! Registre 1 !! Registre 0 |- | 0 || 0 || 1 || 0 || 0 || 1 || 0 || 0 |} Avant d'émettre une instruction, l'unité d'émission extrait les registres opérande/destination et les convertis dans la même représentation que le registre de réservation, à savoir en représentation ''one-hot''. Le circuit de traduction binaire vers ''one-hot'' est, pour rappel, un simple décodeur. Puis, on fait un OU logique entre les sorties des décodeurs. Le résultat est un masque qui indique quels registres sont lus par l'instruction, encodé en représentation ''one-hot''. Appelons-le le '''masque d'opérandes'''. Le masque est alors comparé au registre de réservation pour vérifier si l'instruction peut être émise. [[File:Unité d'émission simple, dans l'ordre.png|centre|vignette|upright=2|Unité d'émission simple, dans l'ordre]] Si l'émission est autorisée, le registre de réservation est là aussi mis à jour. Le registre de réservation est aussi mis à jour dès qu'une instruction enregistre son résultat dans les registres, ou alors dès qu'il est disponible pour le contournement. Le bit associé au registre repasse alors à 0 (ou à 1). Sans contournement, la mise à jour se fait alors à la toute fin de l'instruction, quand elle se termine, lors de la dernière étape d'enregistrement, à la fin de son pipeline. Avec, elle se fait quand l'instruction quitte l'unité de calcul. ===L'extension à l'exécution dans le désordre : l'éveil par matrice de bits=== La différence entre un pipeline dynamique et l'exécution dans le désordre est que l'on passe d'une instruction à émettre à plusieurs. Plusieurs instructions sont mises en attente dans un ''scheduler'', et y attendent leur tour. L'idée est alors d'envoyer le registre de disponibilité à toutes les entrées, à toutes les instructions en attente. Ainsi, on sait quelles sont les instructions qui peuvent s'exécuter et celles qui ne le peuvent pas. L'implémentation est assez simple, elle ressemble beaucoup à l'implémentation d'un pipeline dynamique simple, si ce n'est que des circuits sont dupliqués. L'implémentation utilise des ''scheduler'' légèrement différentes de celles introduites plus haut. Elles n'utilisent notamment pas de bits de disponibilité, mais autre chose. Lorsqu'une instruction est ajoutée à le ''scheduler'', le masque de disponibilité des opérandes est stocké dans le ''scheduler''. A chaque cycle, le registre de disponibilité est envoyé à toutes les entrées, et est comparé avec tous les masques de disponibilité des opérandes. Si une comparaison renvoie un 1, alors l'instruction de l'entrée est une instruction candidate à l'émission. [[File:Unité d'émission dans le désordre basée sur un registre de disponibilité.png|centre|vignette|upright=2.5|Unité d'émission dans le désordre basée sur un registre de disponibilité]] L'ensemble est implémenté avec l'aide d'une '''matrice de bits''', où chaque ligne correspond à une entrée et chaque colonne à un registre. À chaque croisement entre une ligne et une colonne, on trouve un bit. Si le bit de la ligne n et de la colonne m est à 1, cela veut dire : l'instruction dans l'entrée n a besoin de lire le registre m. S’il est à 0, alors cela veut dire que l'instruction stockée dans la ligne n'a pas besoin de la donnée dans le registre m. [[File:Planificateur à matrice de bits.jpg|centre|vignette|upright=2|Planificateur à matrice de bits.]] Lorsqu'une instruction réserve une entrée, elle initialise la ligne en fonction des registres qu'elle souhaite lire. Pour vérifier si une instruction a ses opérandes prêts, le processeur compare le registre de disponibilité à la ligne associée à l'instruction/entrée. A chaque intersection ligne-colonne, se trouve un comparateur de 1 bit, qui détecte si le registre est demandé et disponible. Les résultats de cette porte sont ensuite envoyés à une porte ET, qui fait le gros du travail. [[File:Logique de détection de la disponibilité d'une instruction.jpg|centre|vignette|upright=2|Logique de détection de la disponibilité d'une instruction.]] ==Les ''schedulers'' basées sur une mémoire associative== Les processeurs modernes utilisent une mémoire associative pour le ''scheduler''. Les mémoires associatives ont été abordées il y a quelques chapitres, mais faisons quelques rappels. Les mémoires associatives servent à accélérer la recherche de données dans un ensemble. Or, un ''scheduler'' vérifie régulièrement si chaque entrée est prête. Il s'agit d'un processus de recherche d'une instruction qui respecte une condition bien précise dans la mémoire, ce qui fait que les mémoires associatives sont donc tout indiquées. Comme vous le savez, les signaux de commande d'une instruction sont propagés avec celle-ci dans le pipeline, le nom du registre de destination ne faisant pas exception. Le nom de registre est envoyé à le ''scheduler'' lors de l'écriture du résultat dans les registres. S'il y a correspondance, l'opérande est disponible et son bit de disponibilité est mis à 1. On peut adapter cette méthode pour tenir compte du contournement assez simplement. [[File:Détection des dépendances par propagation du registre de destination.png|centre|vignette|upright=2|Détection des dépendances par propagation du registre de destination.]] En conséquence, le circuit de détection des dépendances est constitué d'un grand nombre de comparateurs : un par champ « nom de registre » dans chaque entrée. La logique d'éveil/''wake up'' regroupe tous les comparateurs, la logique de sélection est un circuit situé en-dehors de la mémoire associative. Les entrées sont dans la mémoire associative elle-même. [[File:Gestion des bits de validité.png|centre|vignette|upright=2|Gestion des bits de validité.]] L'implémentation la plus simple est celle du schéma précédent, où on utilise une mémoire associative unique. Une version plus élaborée sépare le ''scheduler'' en deux parties : une mémoire qui mémorise les registres des opérandes, une autre mémoire pour le reste. La mémoire pour les registres opérandes est la mémoire associative proprement dite, c'est elle qui est associée aux comparateurs, à la logique de ''wake-up''/réveil, etc. Par contre, l'autre mémoire est une mémoire RAM simplifiée, qui mémorise les informations qui n'ont pas besoin des comparateurs. L'opcode de l'instruction est là-dedans, par exemple. le ''scheduler'' est donc une sorte de mémoire associative améliorée. Il se trouve que c'est aussi le cas du ROB. Et il est possible de fusionner le tampon de ré-ordonnancement avec le ''scheduler'' dans une structure unique. La différence avec un ''scheduler'' normal est que les entrées sont libérées non pas quand l'instruction est exécutée/émise, mais quand elle termine son exécution et quitte le ROB. le ''scheduler'' incorpore des bits dans chaque entrée, pour savoir si la µops associée a été émise et est en cours de traitement dans les ALUs. La méthode a notamment été utilisée sur les processeurs d'architecture K6 d'AMD. Le tout donnait une structure appelée le '''DRIS''' (''deferred scheduling register renaming instruction shelf''). Les processeurs PA 8000 de HP étaient aussi vraisemblabment dans ce cas, aussi. ===Les optimisations de la consommation d'énergie : la désactivation des portions inutilisées=== Le problème avec des ''scheduler'' de ce type est leur forte consommation énergétique, ainsi que le grand nombre de portes logiques utilisées, qui deviennent prohibitifs pour des ''scheduler'' un peu grosses. Pour résoudre ce problème, certains ont optimisé les comparateurs. D'autres ont tenté de profiter du fait que la majorité des bits dans les entrées sont composés de zéros. Bref, les optimisations purement matérielles sont légion. Une première solution est de désactiver les entrées qui sont inutilisées, vides, sans instruction. Pour cela, on fait précéder les comparateurs par un circuit qui les connecte ou déconnecte des lignes de bit. Le circuit est commandé par le bit ''empty'' qui indique si une entrée est vide ou non. L'avantage est que la consommation d'énergie de le ''scheduler'' devient alors proportionnelle au nombre d'entrées non-vides, et non au nombre d'entrées total. Du moins, en apparence, les entrées non-utilisées doivent quand même être alimentées pour fonctionner, mais l'activité de comparaison disparait dans les entrées vides. Il est possible d'étendre cette technique aux entrées dont les opérandes sont prêts. Les gains sont généralement assez bons, avec une réduction de consommation variant entre 30 et 50%, avec une implémentation très simple et très économe en circuits. Une autre solution, assez simple à mettre en place, consiste à désactiver une partie de le ''scheduler'' sin elle est inutilisée. Pour cela, il faut segmenter le ''scheduler'' avec la technique du ''wire partitionning''. Pour rappel, un ''scheduler'' est une mémoire associative. Et comme toute mémoire associative, elle contient des fils, les lignes de bit, qui relient les entrées/sorties à toutes les cellules mémoire. Plus une ligne de bit est longue, plus elle consomme d'énergie et plus le temps de lecture/écriture est long. L'idée est de segmenter les lignes de bits en plaçant des répéteurs qui recopient la tension d'un segment au suivant. Les répéteurs sont des tampons trois-états, ce qui permet de déconnecter les portions inutilisées de la ligne de bit. Ce faisant, le ''scheduler'' est découpée en segments, qui peuvent être désactivés si besoin. S'il y a peu d'instructions chargées dans le ''scheduler'', les portions inutilisées sont désactivées. La technique marche d'autan mieux si les instructions sont compactées au début de le ''scheduler''. [[File:Wire partitionning.png|centre|vignette|upright=2|Wire partitionning]] Tout le problème est de savoir quelles portions désactiver. La technique est assez simple si le ''scheduler'' est compactée, à savoir si toutes les instructions sont régulièrement regroupées au début de la mémoire CAM. Mais même avec cette optimisation, la décision de désactiver une portion de le ''scheduler'' n'est pas à prendre à la légère. Il ne faut pas désactiver une portion contenant des instructions pouvant être émise sous peu. La décision dépend de paramètres variés : proportion d'entrée vides, quantité d'entrées récemment activées/désactivées récemment, présences d'entrées avec un ''match'' d'opérandes récent, etc. Il est important de préciser que les techniques en question fonctionnent aussi sur les autres types de ''scheduler'', qui ne sont pas basées sur des mémoires associatives. Nous allons voir celles-ci dans la suite du chapitre, mais gardez à l'esprit que ces optimisations, à savoir désactiver les entrées vides/prêts et partitionner le ''scheduler'', sont des optimisations générales qui marchent avec presque tout. ===L'ajout d'une FIFO pour les instructions déjà prêtes à l'émission=== D'autres techniques permettent de réduire aussi bien le cout en circuits que la consommation d'énergie de le ''scheduler''. L'idée est d'utiliser une mémoire associative quand elle est réellement nécessaire, mais d'utiliser un ''scheduler'' "normale" dès que possible. La méthode la plus simple tient compte du fait que certaines µopsont déjà toutes leurs opérandes de disponibles à l'émission, mais doivent quand même être mises en attente, parce que l'ALU adéquate est occupée, parce que des dépendances WAW/WAR sont encore là, ou pour tout autre raison. Dans ce cas, elles sont mises en attente non pas dans le ''scheduler'', mais dans une mémoire FIFO toute simple. L'idée est qu'au lieu d'avoir une énorme mémoire associative pour le ''scheduler'', on déplace quelques entrées dans une petite FIFO annexe. Le résultat est un gain d'énergie et de circuits, au prix d'une perte de performance mineure. La perte de performance en question se manifeste si aucune instruction n'a ses opérandes de prêtes à l'émission : le programme n'utilise pas la FIFO et voit alors un ''scheduler'' plus petite. Une amélioration de cette technique tient compte du fait que certaines instructions sont dans un cas intermédiaire. Elles ont déjà un opérande de prête lors de l'émission, mais pas l'autre. Le nombre d'opérandes varie suivant l’instruction : certaines n'ont besoin que d'un seul opérande. De plus, il arrive qu'une opération tout juste décodée ait déjà un ou plusieurs de ses opérandes de prêts. Cette constatation permet d'éviter d'utiliser des comparateurs pour les opérandes déjà prêts. Par exemple, on peut parfaitement utiliser trois ''scheduler'' : * une pour les instructions dont tous les opérandes sont prêts, mais qui sont quand même mises en attente, sans comparateur ; * une pour les instructions dont un seul opérande manque, qui n'utilise qu'un comparateur par entrée ; * une pour les instructions dont deux opérandes manquent à l'appel, qui utilise deux comparateurs par entrée. C'est beaucoup plus économique que d'utiliser une seule grosse ''scheduler'' qui contiendrait autant d'entrées que les trois précédentes réunies, avec deux comparateurs par entrée. Certains sont même allés plus loin, et ont proposé de supprimer le ''scheduler'' avec deux opérandes par entrée. Les instructions dont deux opérandes sont inconnus au décodage sont stockées dans le ''scheduler'' pour instructions avec un comparateur par entrée. Un circuit de prédiction se charge alors de prédire l'opérande manquant, cette prédiction étant vérifiée plus loin dans le pipeline. Il serait cependant étonnant qu'une telle proposition ait donné lieu à la moindre implémentation réelle. ===Les optimisations de la consommation d'énergie avancées=== D'autres chercheurs ont conservé un ''scheduler'' unique, avec autant de comparateurs par entrée qu'il y a d'opérandes possibles par instruction. Simplement, le processus de détection des opérandes prêts est légèrement ralenti : on ne vérifie qu'un opérande par cycle. Pour vérifier les deux opérandes d'une entrée, on doit attendre deux cycles. Enfin, certains chercheurs ont proposé des ''scheduler'' segmentées. Les instructions circulent à chaque cycle d'un segment vers le suivant : en conséquence, certains segments conservent les instructions les plus anciennes, un autre les instructions les plus jeunes, etc. Seul le denier segment, celui qui contient les instructions les plus vielles, peut émettre une instruction : la détection des opérandes se fait seulement dans le dernier segment, qui contient les instructions les plus anciennes. On économise ainsi beaucoup de comparateurs. Certains chercheurs ont tenté de pipeliner l'étape de sélection des opérandes, ainsi que l'étage d'arbitrage. Mais en faisant cela, il faut plusieurs cycles pour détecter qu'une instruction a ses opérandes prêts, ce qui pose problème face à de nombreuses dépendances RAW. Pour éviter de trop perdre en performances, certains chercheurs ont décidé d'utiliser des techniques pour prédire quelles seront les instructions dont les opérandes seront bientôt prêts. Si détecter qu'une instruction est prête prend n cycles, le processeur devra tenter de prédire la future disponibilité des opérandes n cycles en avance pour obtenir des performances optimales. ===Remplacer la mémoire associative par une RAM=== Une autre optimisation possible est de remplacer le ''scheduler'' par une mémoire RAM, dont chaque mot mémoire correspondrait à une entrée. Une telle optimisation permet en théorie de se passer des comparateurs associés à chaque entrée, mais au prix de l'ajout de circuits annexes potentiellement couteux. La première de ces techniques, la '''recherche directe par étiquette''' (direct tag search) fut créée par Weiss et son collègue Smith. Ils cherchaient à améliorer l'algorithme de Tomasulo, un algorithme qu'on expliquera dans quelques chapitres. Rappelons que chaque instruction produit un résultat, qui devra être rapatrié dans une ou plusieurs entrées de le ''scheduler''. L'optimisation de la recherche directe par étiquette fonctionne dans le cas où le résultat de l'instruction n'est utilisé que par une seule entrée, et pas plusieurs. Le principe est simple : chaque champ « opérande » d'une entrée est adressable via le nom de registre de cet opérande. Pour faire le lien entre entrée et nom de registre, la recherche directe par étiquette ajoute une table de correspondances matérielle, une mémoire RAM qui mémorise les adresses des champs « opérande » des entrées. Les adresses envoyées dans cette mémoire sont les noms de registres des résultats. Lors de l'émission, la table de correspondances est mise à jour. Les numéros des champs « opérande » réservés lors de l'émission sont mémorisés dans les mots mémoire qui correspondent aux deux registres sources. Toutefois, une petite vérification est faite lors de l'émission : s'il y a déjà une correspondance dans la table pour un registre source, alors une autre instruction compte lire ce registre. Pour éviter d'écraser les données de l'instruction précédente dans la table de correspondances, l'émission de l'instruction est bloquée. [[File:Recherche directe par étiquette.png|centre|vignette|upright=2|Recherche directe par étiquette.]] ==Les ''schedulers'' avec préplanification== Avec la '''préplanification''' (''prescheduling''), le ''scheduler'' est composée de mémoires FIFO dans lesquelles les instructions sont triées dans l'ordre d'émission. Il n'y a pas de logique d’émission proprement dite, celle-ci se bornant à vérifier si l'instruction située au début de la FIFO peut s’exécuter. Par contre, le préplanificateur détecte les dépendances et en déduit où insérer les instructions dans le tampon d'émission, à l'endroit le plus adéquat. [[File:Préplanification.jpg|centre|vignette|upright=2|Préplanification.]] ===L'usage de FIFO multiples=== La technique de préplanification la plus simple utilise plusieurs FIFO. Quand une instruction a une dépendance avec une autre instruction, les deux sont placées dans la même FIFO. Pour cela, le préplanificateur détecte les chaines d'instructions dépendantes, et place les instructions dans la FIFO adéquate. A chaque cycle, l'unité d'émission lit une micro-opération dans chaque FIFO et vérifie si elle peut l'émettre. Si la micro-opération n'a pas ses opérandes disponibles, ou qu'une dépendance structurelle survient, alors la FIFO est bloquée. La micro-opération attend que la dépendance soit résolue, bloquant toutes les instructions précédentes. Mais les autres FIFO ne sont pas bloquées, laissant de la marge de manœuvre. [[File:Préplanification par FIFO multiples.png|centre|vignette|upright=1.5|Préplanification par FIFO multiples.]] ===La technique du tampon trié=== La technique du '''tampon trié''' trie les instructions selon le temps d'attente avant leur exécution. Les instructions qui sont censées s’exécuter bientôt sont insérées au tout début de la FIFO, tandis que les instructions qui s’exécuteront dans un long moment sont insérées vers la fin. Là encore, l'unité d'émission lit une micro-opération dans la FIFO, et détermine si elle peut être émise. Si une dépendance survient, l'émission est retardée, et la FIFO est bloquée. [[File:Préplanification par tampon trié.png|centre|vignette|upright=1.5|Préplanification par tampon trié.]] La technique a cependant quelques problèmes assez importants. Le premier problème est que la FIFO est bloquée lorsqu'une micro-opération ne peut être émise. Le second problème est que le temps avant exécution n'est pas toujours connu, notamment pour les instructions d'accès mémoire. Et cela se répercute sur les instructions dépendantes de celles-ci. Pour résoudre ce genre de problèmes, l'usage d'un pipeline à ''replay'' est possible, et est même l'une des meilleures solutions possible, malgré ses défauts. L'idée est que les lectures sont pré-planifiées en supposant qu'elles font un succès de cache L1. Si la prédiction est fausse, la lecture est ré-exécutée plusieurs cycles plus tard, en supposant qu'elle fait un succès dans le cache L2, et ainsi de suite. Elle est alors ré-insérée dans la FIFO, elle est pré-planifiée une seconde fois. Il en est de même si une micro-opération ne peut pas être émise : il suffit de la réinsérer dans la FIFO au bon endroit, en attendant que ses dépendances soient résolues. Ainsi, l'instruction fautive ne bloque pas le ''scheduler'', et retente sa chance autant de fois qu'il le faut. [[File:Préplanification par fenêtre d’instruction scorebarodée.png|centre|vignette|upright=1.5|Préplanification par ''scheduler'' scorebarodé.]] Une autre solution utilise deux ''schedulers'' : une FIFO gérée par la préplanification, et une vraie ''scheduler'' pour les instructions dont le temps d'attente ne peut pas être déterminé. Il est possible de mettre cette dernière avant la préplanification, afin de gérer les temps d'attente des instructions d'accès mémoire. Quand le temps d'attente d'une lecture devient connu, ses instructions dépendantes sont gérées avec préplanification. [[File:Préplanification avec fenêtre d’instruction.png|centre|vignette|upright=2.5|Préplanification avec ''scheduler''.]] ===Les ''scheduler'' avec allocation temporelle statique=== L''''allocation temporelle statique''' correspond à une technique utilisée sur les processeurs Cuzco de l'entreprise Condor. La technique en question a été présenté en 2025, mais des idées similaires ont été présentées dans la littérature académique. Elle ressemble beaucoup aux techniques de pré-planification, avec cependant quelques différences. L'idée est simple : le processeur dispose de plusieurs ''scheduler'', qui mettent en attente les micro-opérations. Lors de l'étape de renommage de registres, le processeur détermine dans combien de cycles d'horloge la micro-opération sera prête pour exécution. La micro-opération est alors mise en attente durant ce nombre de cycles, dans les ''scheduler'', puis est émise une fois ce nombre de cycles écoulés. Ce faisant, les ''scheduler'' n'ont pas besoin de détecter la disponibilité des opérandes à chaque cycle, pour chaque micro-opération en attente. Le ''timing'' de l'émission des micro-opérations est décidé à l'avance. L'implémentation exacte n'est pas connue, mais plusieurs solutions sont imaginables. Par exemple, le ''scheduler'' peut simplement être composée de plusieurs mémoires de petite taille, chacune contenant les micro-opérations destinées à être exécutées dans N cycles, N étant différent pour chaque mémoire. Une autre solution, plus réaliste, utilise un ''scheduler'' dans laquelle la micro-opération est couplée à des champs pour les opérandes, et un champ compteur. Le champ compteur est initialisé avec le nombre de cycles à attendre, et est décrémenté à chaque cycle d'horloge. Quand il atteint zéro, la micro-opération est émise. Vous remarquerez que la méthode ne marche que si toutes les micro-opérations prennent un nombre fixe de cycles d'horloge. Et autant c'est le cas pour les micro-opérations arithmétiques ou logiques, autant les accès mémoire ne rentrent pas dans ce cadre. En théorie, on ne sait pas combien de temps prendra un accès mémoire. Et cette incertitude se répercute sur les instructions dépendantes d'un accès mémoire. Pour éviter cela, le processeur réutilise un pipeline à ''replay'' tel que vu dans le chapitre précédent. L'unité de renommage de registre suppose que tout accès mémoire fait un succès de cache L1, et décide des ''timings'' d'émission sous cette hypothèse. Si une lecture subit un défaut de cache, elle est ré-exécutée, de même que toutes les instructions dépendantes. Pour cela, le registre de destination de la lecture est marqué comme invalide, grâce à un bit spécifique attaché au registre. Toute instruction qui lit un opérande invalide est elle aussi ré-executée de zéro. Pour simplifier, l'unité d'émission ressemble à une unité d'émission dans l'ordre, avec un registre de disponibilité, qu'on aurait amélioré pour aller au-delà de la simple détection des dépendances d'instruction. Pour déterminer les ''timings'' d'émission, à savoir quand émettre une micro-opération, le processeur utilise une unité d'émission à deux étages. Le premier étage est appelé le ''register scoreboard'', le second étage est appelé la ''Time Ressource Matrix''. Les deux étages communiquent entre eux, comme on va le voir, et leurs noms donnent une idée de ce qu'ils font. Le premier étage gère les dépendances de registres, le second gère les dépendances structurelles. Le premier étage est un registre de disponibilité amélioré, qui gère les dépendances de registre. Cet étage sait quand tel registre sera écrit, et donc que l'opérande écrit dedans sera disponible à partir de tel cycle d'horloge. Il le sait car l'étage suivant l'aura prévenu, mais laissons cela de côté pour le moment. Quand une micro-opération rentre dans cet étage, il vérifie les dépendances avec les registres et les micro-opérations antérieures. Vu qu'il sait quand les registres seront disponibles, il peut déterminer quand l'instruction pourra s'exécuter. Par exemple, si une micro-opération lit les deux registres R7 et R15, qui sont disponibles respectivement dans 5 et 7 cycles, le premier étage sait que la micro-opération devra attendre 7 cycles. Mais tout cela ne suffit pas à déterminer quand émettre une micro-opération. En effet, il fait aussi gérer les dépendances structurelles, ce qui est le boulot du second étage. Le second étage utilise pour cela une ''Time Ressource Matrix'', qui mémorise l'occupation de diverses "ressources", pour les 256 cycles d'horloge à venir. Les ressources en question sont les ports de lecture/écriture du banc de registre, les ALUs utilisées, si la micro-opération utilise l'unité mémoire, etc. Le second étage prend en entrée une micro-opération, détermine quelles "ressources" elle utilise, puis regarde leur disponibilité. Elle détecte alors les dépendances structurelles et détermine alors quand peut s'exécuter la micro-opération. Elle peut retarder l'émission de quelques cycles, si une dépendance structurelle est détectée. Une fois sortie du second étage, on sait quand la micro-opération va être émise, à quel cycle précisément. Et vu que la durée de l'instruction est fixe, on sait quand cette micro-opération va se terminer, quand son résultat sera disponible. Cela permet de mettre à jour la ''Time Ressource Matrix'', pour préciser que le port d'écriture sera occupé à tel moment. De plus, cette information est transmise au premier étage, qui sait alors quand est enregistré le résultat dans le registre de destination. C'est comme cela que le premier étage sait quand un registre est disponible : le second étage le prévient, quand il émet une instruction ! La ''Time Ressource Matrix''mémorise l'occupation des "ressources" pour les 256 cycles d'horloge à venir. Cependant, elle ne vérifie pas les dépendances pour les 256 cycles suivants. Quand elle reçoit une micro-opération, elle teste les dépendances structurelles pour seulement les 8 prochains cycles maximum. Si la micro-opération ne peut pas être émise pendant ces 8 cycles, le pipeline est bloqué, un ''pipeline stall'' est émis. Pour être plus précis, vu que le processeur peut décoder 8 micro-opérations en même temps, cela permet de ne consulter que 64 cycles d'horloge sur les 256. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les premiers processeurs Intel | prevText=Les premiers processeurs Intel | next=Le renommage de registres | nextText=Le renommage de registres }} </noinclude> cp8d5abje6mqbfi7m2uuyectu957lk4 773677 773676 2026-09-29T23:01:50Z Mewtow 31375 773677 wikitext text/x-wiki Dans les chapitres précédents, nous avons parlé des techniques dites d''''émission dans l'ordre'''. L'idée est d’exécuter une nouvelle micro-opération à chaque cycle, dans des unités de calcul séparées. Les instructions sont émises consécutivement, mais les instructions s’exécutent en parallèle dans des unités de calcul séparées. Par contre, quand l'unité d'émission ne peut pas émettre une instruction, elle bloque tout le pipeline. Les instructions qui suivent sont elles aussi bloquées, elles doivent attendre leur tour, même si elles sont en capacité de s'exécuter. Les techniques d'exécution dans le désordre que nous allons voir dans ce chapitre corrigent ce point précis. Elles sont dites à '''émission dans le désordre'''. Elles se distinguent des précédentes sur un point précis : quand l'unité d'émission bloque l'émission d'une instruction, les instructions suivantes peuvent poursuivre. L'émission des instructions peut donc se faire dans le désordre, dans le sens où une instruction peut être émise alors qu'une instruction précédente ne l'est pas encore. Mais avant de poursuivre, quelques point niveaux terminologie : * L'émission dans le désordre est un terme parlant et assez précis. Malheureusement, la terminologie la plus utilisée par d''''exécution dans le désordre'''. Et nous utiliserons ce terme dans la suite du cours, histoire de ne pas trop dévier de la nomenclature habituelle. * Nous utiliserons parfois l'abréviation OOO pour parler d'exécution dans le désordre. L'abréviation est celle de ''Out Of Order Execution''. * Nous utiliserons aussi l'abréviation ''µop'' pour parler de micro-opération, ''µops'' au pluriel pour parler de plusieurs micro-opérations, ou des micro-opérations en général. L'exécution dans le désordre ne gère en effet que des µops, elle se situe après l'étape de décodage. Pour décrire comment est implémentée l'émission dans le désordre, il faut commencer par parler des processeurs sans. Les processeurs sans exécution dans le désordre ont une unité d'émission qui bloque tout le pipeline dès qu'une µop ne peut pas être émise. Pour limiter l'impact de ce blocage, quelques rares processeurs incorporent une '''file de micro-opération''', une mémoire FIFO qui met en attente les µops. Vu que c'est une mémoire FIFO, les µops sont émises dans l'ordre, à savoir l'ordre d'ajout, dans l'ordre de décodage. Le schéma ci-dessous illustre une telle file d'attente couplée à un ''scoreboard''. L'exécution dans le désordre améliore la file de µops sur un point : ce n'est plus une mémoire FIFO. Les µops sont insérées dans l'ordre, mais peuvent sortir dans le désordre (être émises dans le désordre). La file de µops devient alors un '''''scheduler''''', terme anglais que je ne compte pas traduire. Un terme équivalent est '''''scheduler''''', terme traduit directement de l'anglais ''instruction Window''. Terme assez trompeur, car elles mettent en attente des µops, pas des instructions. [[File:Différence file µops et fenêtres instruction.png|centre|vignette|upright=2|Différence file µops et ''schedulers'' ]] Le ''scheduler'' émet une µop dès que ses opérandes sont disponibles. Par disponible, on veut dire présent soit dans le réseau de contournement, soit dans les registres. Le ''scheduler'' détecte automatiquement quand les opérandes d'une µop sont disponibles, grâce à une unité d'émission intégrée. L'unité d'émission et la file d'attente de µops sont fusionnés ensemble, dans un seul circuit, mais nous allons dire qu'ils sont conceptuellement séparés pour le moment. À chaque cycle, l'unité d'émission consulte les µops en attente pour détecter lesquelles peuvent s'exécuter. Le ''scheduler'' est spécialement être conçue pour, c'est une sorte de mémoire associative très complexe, comme on le verra dans ce qui suit. [[File:OOO Issue.png|centre|vignette|upright=2.5|Exécution dans le désordre avec un ''scheduler'']] Une fois qu'une µop sort du décodeur d'instructions, elle est ajoutée en parallèle dans le ''scheduler'' et le ROB. La raison est que les µops quittent le ''scheduler'' dans le désordre, et qu'elles doivent être remises en ordre par la suite. Le ROB s'occupe de cette remise en ordre, mais il a besoin de savoir dans quel ordre les µops sont censées être, et cet ordre est celui du décodage. Aussi, pour remplir le ROB, la seule opportunité est en sortie de l'unité de décodage. Dans le cas où une instruction est décodée en plusieurs micro-opérations, elles sont toutes insérées en même temps dans le ''scheduler'' et le ROB, en tenant compte de leur ordre. L'implémentation la plus "simple" de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Les µops décodées sont accumulées dans le ''scheduler'', où elles attendent leur tour. Bien que simple en apparence, cette implémentation cache une complexité très importante, liée aux accès mémoire. Les micro-opérations mémoire sont à part des autres, pour ce qui est de leurs dépendances de données. Non seulement elles ont des dépendances de registre, mais elles sont aussi des dépendances d'adresse. Par exemple, deux écritures peuvent utiliser deux registres d'adresse différents, mais ceux-ci peuvent contenir la même adresse. Et autant on peut détecter les dépendances de registre lors de l'émission, autant c'est plus compliqué avec les dépendances d'adresse. De plus, rappelons que si les lectures peuvent s'exécuter dans le désordre, les écritures doivent s'exécuter dans l'ordre, ou du moins en donner l'illusion. Pour cela, le processeur remet les écritures dans l'ordre avec une sorte de mini-ROB intégré à l'unité mémoire, appelée la file d'écriture. Elle complémente le ROB, qui lui ne gère que les écritures dans les registres, mais les deux collaborent. La file d'écriture envoie une écriture à la mémoire RAM quand le ROB lui dit que c'est bon, les instructions précédentes sont terminées ''dans l'ordre du programme''. Les processeurs modernes ajoutent des techniques d'exécution dans le désordre des accès mémoire, mais nous les verrons dans un chapitre dédié. Elles permettent d'utiliser un ''scheduler'' unique, qui mémorise aussi les µops mémoire. Si elles sont mises en place, l'unité mémoire n'a pas besoin de file de µops séparée. L'idée est que les dépendances de registre sont traitées par le ''scheduler'', mais que l'unité mémoire gére les dépendances d'adresse. Les dépendances d'adresse sont gérées par des techniques de ''désambiguation mémoire'', qui auront droit à un chapitre dédié. [[File:Processeur avec exécution dans le désodre des accès mémoire.png|centre|vignette|upright=2|Processeur avec exécution dans le désodre des accès mémoire]] Les processeurs assez anciens n'autorisaient pas d'exécution dans le désordre des accès mémoire. Concrètement, les accès mémoire devaient se faire dans l'ordre, mais les autres µops pouvaient être exécutées dans le désordre. Il s'agit donc d'un ordre entre µops mémoire, pas entre µops mémoire et autres µops. Les µops entières et flottantes pouvaient être exécutées avant une µops mémoire qui est avant elle dans l'ordre du programme, ce n'est pas un problème. Pour garantir l'ordre des µops mémoire, l'unité mémoire est précédée par une file de micro-opérations séparée, pour forcer l'exécution dans l'ordre des accès mémoire. De plus, les µops mémoire ne peuvent pas utiliser le ''scheduler''. Dit autrement, le ''scheduler'' ne mémorise pas de µops mémoire. Après le décodage, les µops sont réparties soit dans la file de µops mémoire, soit dans le ''scheduler''. Le décodeur classe les µops suivant que ce sont des µops mémoire ou non, et les envoient à la bonne destination. Dans ce chapitre, on supposera que c'est cette solution qui est utilisée. [[File:Processeur avec émission dans l'ordre des accès mémoire.png|centre|vignette|upright=2|Processeur avec émission dans l'ordre des accès mémoire]] ==L'implémentation d'un ''scheduler'' : généralités== Un ''scheduler'' est une mémoire qui mémorise des micro-opérations. Elle est cependant plus complexe qu'une mémoire RAM ou qu'une FIFO et ressemble un petit peu à une mémoire cache. Elle dispose d'un port d'écriture et d'un port de lecture, au minimum. Le port d'écriture permet à l'unité de décodage d'insérer une micro-opération dedans, d'ajouter la micro-opération qui vient d'être décodée. Si une instruction machine est décodée en plusieurs micro-opération, deux possibilités. La première est de les insérer un par un, ce qui fait qu'on peut se contenter d'un seul port d'écriture. L'autre possibilité est de les ajouter en même temps, ce qui demande plusieurs ports d'écriture. Le port de lecture sert à émettre une instruction. On part du principe que le ''scheduler'' ne peut émettre qu'une seule instruction à la fois, car les processeurs que nous avons vu précédemment sont de ce type. Mais nous verrons dans quelques chapitres qu'il existe des processeurs dits superscalaires, qui sont capables d'émettre plusieurs instructions par cycle. Dans ce cas, le ''scheduler'' a un seul port de lecture. Un processeur superscalaire, quant à lui, doit avoir un port de lecture par unité de calcul, ce qui fait beaucoup plus. Les ''schedulers'' sont composées d''''entrées''', des mots mémoire qui stockent une instruction. Une instruction réserve une entrée après son décodage et la libère dès qu'elle est envoyée aux unités de calcul. Une entrée contient l'opcode (les signaux de commande à envoyer à l'ALU), le registre de destination du résultat, les registres de chaque opérande, et éventuellement des signaux de commande en plus. De plus, chaque opérande est couplée à un bit de disponibilité, qui indique si elle est disponible. Quand un opérande est écrit dans les registres, le bit de présence correspondant est mis à jour. Enfin, chaque entrée possède un bit ''empty'' qui indique si elle est vide, cette information étant utile pour réserver des entrées. [[File:Entrée d'une station de réservation - sans les tags.png|centre|vignette|upright=3|Entrée d'un ''scheduler'']] ===Les stations de réservation=== Les '''stations de réservation''' sont des ''scheduler'' particulières, qui sont capables de mémoriser les opérandes des instructions. Les entrées des stations de réservation sont identiques à celle des autres ''scheduler'', si ce n'est que les opérandes de l'instruction sont enregistrés directement dans des champs séparés. Il y a deux champs, un par opérande, pour stocker l'opérande elle-même, lue depuis les registres ou obtenue via le réseau de contournement. Notons que les champs pour les opérandes viennent en plus des champs pour les noms de registres, encore que les deux peuvent être fusionnés si on veut optimiser le tout. [[File:Entrée d'une station de réservation.png|centre|vignette|upright=3|Entrée d'une station de réservation.]] Précisons que la terminologie n'est pas très fiable. Les termes "''scheduler''" et "station de réservation" ne regroupent pas du tout la même chose d'un papier de recherche à l'autre, d'un bouquin à l'autre, d'un chercheur à l'autre, d'un ingénieur à l'autre, d'un professeur à l'autre. Le terme initial vient pourtant de l'article original sur l'algorithme de Tomasulo, où il désignait un ''scheduler'' associée à une unité de calcul précise. Mais le terme a ensuite été réutilisé, ce qui fait que certains processeurs avec plusieurs unités de calcul sont décrits comme ayant une unique station de réservation. En bref : c'est le bazar ! Mais nous en reparlerons dans le chapitre sur le renommage de registres, car c'est la place idéale pour les aborder. Toujours est-il que j'ai fait le choix de confondre les concepts de ''scheduler'' et de station de réservation avec les concepts de '''lecture avant émission''' et de '''lecture après émission'''. La différence entre les deux est que les registres sont lus après émission avec un ''scheduler'', avant avec des stations de réservation. Dans le cas "avant émission", les opérandes sont mémorisés dans la station de réservation. Et cette différence a une influence sur le pipeline du processeur, le banc de registres et tout ce qui s'ensuit. Un désavantage de la lecture avant émission est qu'il faut stocker les opérandes après lecture, ici dans les stations de réservation. Mais un avantage est que le banc de registre a besoin de moins de ports de lecture, car une bonne partie des opérandes sont fournies par le système de contournement. Nous verrons cela dans le détail dans le chapitre sur les processeurs superscalaires. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Lecture après émission.]] [[File:Read Before Issue.png|centre|vignette|upright=2.5|Lecture avant émission.]] ===La logique d'éveil et de sélection=== Dans le cas qui va suivre, on suppose que le processeur ne peut émettre qu'une instruction à la fois. Chaque cycle, une instruction est sélectionnée et est envoyée dans le chemin de données, soit à une ALU, soit à une unité d'accès mémoire. La sélection d'une instruction est effectuée par l'unité d'émission, qui est aussi appelée le '''''scheduler'''''. Elle gère la disponibilité des opérandes et la disponibilité des unités de calcul adéquate. Le choix de l'instruction émise doit être le plus pertinent possible, pour des raisons de performances. Pour le premier point, l'unité d'émission détermine quelles instructions sont candidates pour l'émission. Les ''instructions candidates'' sont celles dont tous les opérandes sont prêts. Le processeur contient un circuit qui détecte les instructions candidates : la '''logique d’éveil''' (''wake-up logic''). Une fois que la logique d'éveil a fait son travail, une instruction est choisie pour s’exécuter en fonction de la disponibilité des unités de calcul adéquates. Ce rôle est dévolu à un circuit qu'on appelle la '''logique de sélection''', ou ''select logic''. [[File:Fonctionnement complet de la logique d’émission.jpg|centre|vignette|upright=1.5|Fonctionnement complet de la logique d’émission.]] La logique de sélection doit gérer le fait que les unités de calcul du processeur ne sont pas toutes identiques. Déjà, un processeur a généralement des unités séparées pour les instructions entières et flottantes, des unités spécialisées dans les accès mémoire, parfois des unités spécialisées pour les branchements. Une instruction doit être attribuée à la bonne unité de calcul, on ne doit pas envoyer une instruction entière dans une unité de calcul flottante. De plus, parmi les unités de calcul entières, toutes ne sont pas identiques. Par exemple, il est fréquent d'avoir plusieurs unités de calcul spécialisées dans les opérations simples (additions, soustractions, opérations logiques) avec une unité pour les multiplications/divisions séparées, parfois une unité spécialisée pour les décalages/rotations, etc. Là encore, allouer la bonne instruction à la bonne ALU est complexe. Plus les unités de calcul sont hétérogènes, plus la logique de sélection est compliquée. Les logiques d'éveil comme de sélection sont assez complexes. Comme on le verra plus bas, la logique de sélection la plus simple, qui gère une seule unité de calcul, est basée sur un encodeur à priorité, couplé à d'autres circuits. Et pour gérer plusieurs ALUs, il faut mettre des encodeurs en cascade. Le résultat est que même en prenant une logique de sélection simple, elle sera assez lente et gourmande en circuits. Aussi, la logique de sélection met souvent un cycle d'horloge entier pour faire son travail, elle a son propre étage de pipeline attribué. La logique d'éveil est dans le même cas, ce qui fait qu'émettre une micro-opération demande deux cycles d'horloge. Le défaut est que cela rajoute des cycles d'horloges entre le ''scheduler'' et l'ALU, ce qui complique la gestion du pipeline. Ces cycles de retard sont à prendre en compte au moment d'émettre les instructions, les ''scheduler'' doit en tenir compte pour des performances optimales. Sans tenir compte de ces cycles de retard, les instructions arrivent en retard de quelques cycles à l'ALU, cycles de retard durant lesquels l'ALU n'a pas fait de calcul et a été sous-utilisée, sans compter que le système de contournement n'est pas utilisé au mieux. Et le problème est encore plus important sur les processeurs avec des stations de réservation, qui utilisent la "lecture après émission" : cela rajoute un cycle d'horloge en plus, un temps de retard en plus. ===La logique d'éveil : l'émission anticipée=== La logique d'éveil doit tenir compte du fait qu'il y a plusieurs étages entre l'émission et l'exécution sur une unité de calcul. Par exemple, un processeur a souvent entre un et à cinq étages entre la file d'attente et les unités de calcul. Il faut lire les registres, gérer le contournement, et cela peut prendre quelques cycles d'horloge. Sur le Pentium 4, on trouve 6 étages entre le ''scheduler'' et l'entrée de l'ALU. Si les micro-opérations sont émises quand les opérandes sont disponibles, il y aura un délai de quelques cycles avant qu'elles atteignent l'ALU. Alors qu'idéalement, on souhaiterait que la micro-opération atteigne l'ALU dès que ses opérandes sont disponibles, pour profiter des techniques de contournement. Pour cela, la logique d'éveil émet les instructions quelques cycles en avance pour qu'elles arrivent au bon moment. Il s'agit d'une technique d''''émission anticipée''', dont nous avions parlé dans le chapitre sur le contournement. : Il faut noter que le problème se pose plus avec des ''schedulers'' qu'avec des stations de réservation. Les premières ont un étage en plus entre émission et ALU, vu qu'il faut lire des registres après l'émission. L'émission anticipée demande d'émettre un signal d'éveil en avance de quelques cycles, pile au bon moment. Par exemples, si on a deux étages entre l'ALU et l'unité d'émission, le signal de réveil sera généré deux cycles avant que le résultat soit effectivement calculé. L'implémentation varie, mais deux solutions sont possibles. La première est de générer le signal d'éveil dans l'ALU, ce qui n'a de sens que pour les opérations comme les multiplications ou les divisions, qui prennent plusieurs cycles. Une autre technique génère le signal de réveil dans une structure centralisée, spécialisée dans la génération des signaux d'éveil. L'unité de composée d'un registre à décalage par registre. Imaginons qu'une instruction est émise, que cette instruction mette N cycles à s'exécuter, et qu'elle écrive dans un registre de destination. L'unité sélectionne alors le registre à décalage associé au registre de destination, et met le bit numéro N à 1. Le registre décalé d'un cran à chaque cycle. Quand le bit sortant est un 1, alors le signal de validité pour l'opérande est généré. L'émission anticipée marche bien si l'instruction a une durée fixe, connue à l'avance. Et autant c'est le cas pour les instructions arithmétiques et logiques, autant ce n'est pas le cas pour les accès mémoire. Les accès mémoire ont une latence variable : quelques cycles pour un succès de cache, plusieurs dizaines de cycles pour un défaut de cache L1, pas loin de la centaine pour un défaut de cache L2, etc. Et cela pose des problèmes pour l'émission anticipée. L'émission en avance pour les accès mémoire est purement spéculative : le processeur émet des instructions en supposant que la lecture entrainera un succès de cache, quitte à annuler l'instruction en cas de défaut de cache. Mais faire ainsi demande non seulement d'annuler les instructions émises en avance, mais aussi de ne pas retirer les instructions émises en avance de le ''scheduler''. Elles sont émises, mais une copie de sauvegarde est conservée dans le ''scheduler''. Si le processeur détecte un défaut de cache, il peut alors ré-exécuter l'instruction. S'il détecte un succès de cache, les instructions lecture-dépendante sont retirées de le ''scheduler'', la copie de sauvegarde est devenue inutile et est donc jetée. ===La logique de sélection : âge ou position ?=== La logique de sélection est primordiale pour de bonnes performances. Il existe deux méthodes principales pour sélectionner l'instruction à exécuter. La première est la plus simple : elle se base sur lé numéro de l'entrée. En effet, un ''scheduler'' est avant tout une sorte de mémoire, un mix entre mémoire associative, mémoire RAM, et FIFO. Et chaque entrée a un numéro, une adresse mémoire. Nous parlerons de numéro dans ce qui suit, car ce sera plus simple, le terme d'adresse mémoire étant peut-être un peu exagéré dans le contexte des ''scheduler''. Toujours est-il que le ''scheduler'' est adressable dans le sens où on peut lui envoyer le numéro de l'entrée voulue, et le ''scheduler'' renvoie le contenu de l'entrée sur son port de lecture. Et c'est ce que fait la logique de sélection : elle génère le numéro de l'entrée à lire. Le numéro est alors envoyé sur l'entrée d'adresse du ''scheduler'', et elle fournit la micro-opération associée sur son port de lecture, son '''port d'émission'''. La première méthode de sélection, donc. Elle est basée sur le numéro de l'entrée. Si plusieurs entrées sont éveillées, la logique de sélection prend celle avec le plus petit numéro. Elle porte le nom de '''sélection par position''', sous-entendu position dans le ''scheduler''. Vous l'avez peut-être deviné, mais la logique de sélection est alors un encodeur à priorité. Le circuit de sélection ne se résume donc pas seulement à un encodeur à priorité, mais c'est le circuit central. L'avantage d'une telle méthode de sélection est qu'elle est simple à implémenter : un encodeur à priorité est un circuit connu, facile à implémenter. Mais on remarque un défaut : un encodeur est un circuit assez rapide, mais qui utilise beaucoup de transistors, beaucoup de portes logiques, surtout si on veut qu'il soit rapide. Ce qui explique que la logique de sélection ait son propre étage de pipeline rien que pour elle. La seconde méthode s'appelle la '''sélection par âge''', au nom assez transparent. L'idée est de privilégier l'émission de l'instruction la plus ancienne. Elle demande que le ''scheduler'' trie les micro-opérations par ordre d'insertion dans le ''scheduler'', ce qui en fait une pseudo-FIFO. Le tri est partiel, car les instructions peuvent sortir du ''scheduler'' à tout moment. Compacter le ''scheduler'', à savoir regrouper toutes les entrées valides est une idée, mais elle est compliquée à implémenter. Aussi, elles préfèrent encoder des informations sur l'ordre d'émission dans chaque entrée. L'encodeur à priorité doit alors travailler non pas sur des nombres entiers liés à l'ordre d'insertion dans la pseudo-FIFO. Elle est encore plus gourmande en circuits que la méthode précédente. Les processeurs haute performance utilisent souvent des méthodes hybrides. Par exemple, les processeurs AMD de microarchitecture Bulldozer utilisaient une méthode intermédiaire. Ils utilisaient un ''scheduler'' couplée à un encodeur à priorité pour la sélection par position, mais complémentaient le tout avec une unité qui mémorisait l'instruction la plus ancienne dans le ''scheduler''. Le mécanisme de sélection par âge était utilisé en priorité. Mais si l'instruction la plus ancienne n'était pas prête, le processeur basculait sur le mécanisme de sélection par position. ===La compaction des ''scheduler''=== À chaque cycle, les instructions décodées sont ajoutées dans le ''scheduler'', dans des entrées vides. Vu que les instructions quittent celle-ci dans le désordre, ces vides sont dispersés dans le ''scheduler'', ce qui pose problème pour déterminer où placer les nouvelles instructions. La solution la plus triviale consiste à conserver une liste des vides, mise à jour à chaque insertion ou émission d'instruction. Une autre solution consiste à éliminer les vides en compactant le ''scheduler'' à chaque cycle d'horloge. Des circuits se chargent de détecter les vides et de regrouper les instructions en un unique bloc. Il faut signaler que certains processeurs arrivent à se passer de cette étape de compactage, mais au prix de ''scheduler'' nettement plus complexes. Autre problème : quand il faut choisir quelle instruction émettre, il y a toujours plusieurs candidats. Si on choisit mal, des instructions restent en attente trop longtemps parce que d'autres instructions plus jeunes leur passent devant. Pour éviter cela, les instructions les plus vielles, les plus anciennes, sont prioritaires. Pour cela, on peut utiliser une FIFO un peu spéciale pour le ''scheduler''. Si les ajouts d'instruction se font dans l'ordre, les instructions ne quittent pas forcément le ''scheduler'' dans l'ordre imposé par une FIFO : les instructions restent triées dans leur ordre d'ajout, même s'il y a des vides entre elles. Dans ces conditions, il est préférable que le compactage conserve l'ordre FIFO des instructions. Dans ces conditions, l'instruction la plus ancienne est celle qui est située à l'adresse la plus faible : le circuit de sélection peut donc être fabriqué avec des encodeurs, et est relativement simple. ==Les ''schedulers'' basées sur une matrice de dépendances== L'implémentation la plus simple étend le fonctionnement d'un pipeline dynamique usuel. Rappelez-vous le chapitre sur les pipelines dynamiques. Nous avions vu que de tels pipelines émettaient une instruction par cycle, quitte à émettre des bulles de pipeline en cas de dépendance bloquante. Et il est possible d'améliorer leur unité d'émission pour qu'elle soit compatible avec l'exécution dans le désordre. ===Rappels sur le registre de réservation/disponibilité=== L'émission d'une instruction est gouvernée par un ''registre de réservation'' qui indique quels registres sont réservés par une instruction, et ceux qui sont libres. Un registre réservé est un registre qui sera écrit par une instruction en cours d'exécution, mais qui n'a pas encore écrit son résultat. Les instructions candidates doivent avoir leurs opérandes dans des registres libres. Sinon, c'est signe que leurs opérandes sont réservés en écriture, donc pas encore écrites, donc pas disponibles. Si une instruction candidate veut lire ce registre, c'est signe qu'il y a une dépendance RAW : elle veut lire un registre réservé, qui est destiné à être écrit par une instruction en vol. Si elle veut écrire, c'est signe qu'elle veut écrire dans un registre où une autre instruction veut écrire : c'est une dépendance WAW. Dans les deux cas, l'instruction n'est pas émise. Le registre de réservation encode les registres réservés comme suit : chaque bit est associé à un registre. Le bit numéro 0 est associé au registre numéro 0, le bit numéro 1 au registre numéro 1, etc. Là, En clair, les numéros de registres réservés sont encodés en représentation non pas binaire, mais en représentation ''one-hot'' (vue au premier chapitre). {|class="wikitable" |+ Registre de réservation |- ! Registre 7 !! Registre 6 !! Registre 5 !! Registre 4 !! Registre 3 !! Registre 2 !! Registre 1 !! Registre 0 |- | 0 || 0 || 1 || 0 || 0 || 1 || 0 || 0 |} Avant d'émettre une instruction, l'unité d'émission extrait les registres opérande/destination et les convertis dans la même représentation que le registre de réservation, à savoir en représentation ''one-hot''. Le circuit de traduction binaire vers ''one-hot'' est, pour rappel, un simple décodeur. Puis, on fait un OU logique entre les sorties des décodeurs. Le résultat est un masque qui indique quels registres sont lus par l'instruction, encodé en représentation ''one-hot''. Appelons-le le '''masque d'opérandes'''. Le masque est alors comparé au registre de réservation pour vérifier si l'instruction peut être émise. [[File:Unité d'émission simple, dans l'ordre.png|centre|vignette|upright=2|Unité d'émission simple, dans l'ordre]] Si l'émission est autorisée, le registre de réservation est là aussi mis à jour. Le registre de réservation est aussi mis à jour dès qu'une instruction enregistre son résultat dans les registres, ou alors dès qu'il est disponible pour le contournement. Le bit associé au registre repasse alors à 0 (ou à 1). Sans contournement, la mise à jour se fait alors à la toute fin de l'instruction, quand elle se termine, lors de la dernière étape d'enregistrement, à la fin de son pipeline. Avec, elle se fait quand l'instruction quitte l'unité de calcul. ===L'extension à l'exécution dans le désordre : l'éveil par matrice de bits=== La différence entre un pipeline dynamique et l'exécution dans le désordre est que l'on passe d'une instruction à émettre à plusieurs. Plusieurs instructions sont mises en attente dans un ''scheduler'', et y attendent leur tour. L'idée est alors d'envoyer le registre de disponibilité à toutes les entrées, à toutes les instructions en attente. Ainsi, on sait quelles sont les instructions qui peuvent s'exécuter et celles qui ne le peuvent pas. L'implémentation est assez simple, elle ressemble beaucoup à l'implémentation d'un pipeline dynamique simple, si ce n'est que des circuits sont dupliqués. L'implémentation utilise des ''scheduler'' légèrement différentes de celles introduites plus haut. Elles n'utilisent notamment pas de bits de disponibilité, mais autre chose. Lorsqu'une instruction est ajoutée à le ''scheduler'', le masque de disponibilité des opérandes est stocké dans le ''scheduler''. A chaque cycle, le registre de disponibilité est envoyé à toutes les entrées, et est comparé avec tous les masques de disponibilité des opérandes. Si une comparaison renvoie un 1, alors l'instruction de l'entrée est une instruction candidate à l'émission. [[File:Unité d'émission dans le désordre basée sur un registre de disponibilité.png|centre|vignette|upright=2.5|Unité d'émission dans le désordre basée sur un registre de disponibilité]] L'ensemble est implémenté avec l'aide d'une '''matrice de bits''', où chaque ligne correspond à une entrée et chaque colonne à un registre. À chaque croisement entre une ligne et une colonne, on trouve un bit. Si le bit de la ligne n et de la colonne m est à 1, cela veut dire : l'instruction dans l'entrée n a besoin de lire le registre m. S’il est à 0, alors cela veut dire que l'instruction stockée dans la ligne n'a pas besoin de la donnée dans le registre m. [[File:Planificateur à matrice de bits.jpg|centre|vignette|upright=2|Planificateur à matrice de bits.]] Lorsqu'une instruction réserve une entrée, elle initialise la ligne en fonction des registres qu'elle souhaite lire. Pour vérifier si une instruction a ses opérandes prêts, le processeur compare le registre de disponibilité à la ligne associée à l'instruction/entrée. A chaque intersection ligne-colonne, se trouve un comparateur de 1 bit, qui détecte si le registre est demandé et disponible. Les résultats de cette porte sont ensuite envoyés à une porte ET, qui fait le gros du travail. [[File:Logique de détection de la disponibilité d'une instruction.jpg|centre|vignette|upright=2|Logique de détection de la disponibilité d'une instruction.]] ==Les ''schedulers'' basées sur une mémoire associative== Les processeurs modernes utilisent une mémoire associative pour le ''scheduler''. Les mémoires associatives ont été abordées il y a quelques chapitres, mais faisons quelques rappels. Les mémoires associatives servent à accélérer la recherche de données dans un ensemble. Or, un ''scheduler'' vérifie régulièrement si chaque entrée est prête. Il s'agit d'un processus de recherche d'une instruction qui respecte une condition bien précise dans la mémoire, ce qui fait que les mémoires associatives sont donc tout indiquées. Comme vous le savez, les signaux de commande d'une instruction sont propagés avec celle-ci dans le pipeline, le nom du registre de destination ne faisant pas exception. Le nom de registre est envoyé à le ''scheduler'' lors de l'écriture du résultat dans les registres. S'il y a correspondance, l'opérande est disponible et son bit de disponibilité est mis à 1. On peut adapter cette méthode pour tenir compte du contournement assez simplement. [[File:Détection des dépendances par propagation du registre de destination.png|centre|vignette|upright=2|Détection des dépendances par propagation du registre de destination.]] En conséquence, le circuit de détection des dépendances est constitué d'un grand nombre de comparateurs : un par champ « nom de registre » dans chaque entrée. La logique d'éveil/''wake up'' regroupe tous les comparateurs, la logique de sélection est un circuit situé en-dehors de la mémoire associative. Les entrées sont dans la mémoire associative elle-même. [[File:Gestion des bits de validité.png|centre|vignette|upright=2|Gestion des bits de validité.]] L'implémentation la plus simple est celle du schéma précédent, où on utilise une mémoire associative unique. Une version plus élaborée sépare le ''scheduler'' en deux parties : une mémoire qui mémorise les registres des opérandes, une autre mémoire pour le reste. La mémoire pour les registres opérandes est la mémoire associative proprement dite, c'est elle qui est associée aux comparateurs, à la logique de ''wake-up''/réveil, etc. Par contre, l'autre mémoire est une mémoire RAM simplifiée, qui mémorise les informations qui n'ont pas besoin des comparateurs. L'opcode de l'instruction est là-dedans, par exemple. le ''scheduler'' est donc une sorte de mémoire associative améliorée. Il se trouve que c'est aussi le cas du ROB. Et il est possible de fusionner le tampon de ré-ordonnancement avec le ''scheduler'' dans une structure unique. La différence avec un ''scheduler'' normal est que les entrées sont libérées non pas quand l'instruction est exécutée/émise, mais quand elle termine son exécution et quitte le ROB. le ''scheduler'' incorpore des bits dans chaque entrée, pour savoir si la µops associée a été émise et est en cours de traitement dans les ALUs. La méthode a notamment été utilisée sur les processeurs d'architecture K6 d'AMD. Le tout donnait une structure appelée le '''DRIS''' (''deferred scheduling register renaming instruction shelf''). Les processeurs PA 8000 de HP étaient aussi vraisemblabment dans ce cas, aussi. ===Les optimisations de la consommation d'énergie : la désactivation des portions inutilisées=== Le problème avec des ''scheduler'' de ce type est leur forte consommation énergétique, ainsi que le grand nombre de portes logiques utilisées, qui deviennent prohibitifs pour des ''scheduler'' un peu grosses. Pour résoudre ce problème, certains ont optimisé les comparateurs. D'autres ont tenté de profiter du fait que la majorité des bits dans les entrées sont composés de zéros. Bref, les optimisations purement matérielles sont légion. Une première solution est de désactiver les entrées qui sont inutilisées, vides, sans instruction. Pour cela, on fait précéder les comparateurs par un circuit qui les connecte ou déconnecte des lignes de bit. Le circuit est commandé par le bit ''empty'' qui indique si une entrée est vide ou non. L'avantage est que la consommation d'énergie de le ''scheduler'' devient alors proportionnelle au nombre d'entrées non-vides, et non au nombre d'entrées total. Du moins, en apparence, les entrées non-utilisées doivent quand même être alimentées pour fonctionner, mais l'activité de comparaison disparait dans les entrées vides. Il est possible d'étendre cette technique aux entrées dont les opérandes sont prêts. Les gains sont généralement assez bons, avec une réduction de consommation variant entre 30 et 50%, avec une implémentation très simple et très économe en circuits. Une autre solution, assez simple à mettre en place, consiste à désactiver une partie de le ''scheduler'' sin elle est inutilisée. Pour cela, il faut segmenter le ''scheduler'' avec la technique du ''wire partitionning''. Pour rappel, un ''scheduler'' est une mémoire associative. Et comme toute mémoire associative, elle contient des fils, les lignes de bit, qui relient les entrées/sorties à toutes les cellules mémoire. Plus une ligne de bit est longue, plus elle consomme d'énergie et plus le temps de lecture/écriture est long. L'idée est de segmenter les lignes de bits en plaçant des répéteurs qui recopient la tension d'un segment au suivant. Les répéteurs sont des tampons trois-états, ce qui permet de déconnecter les portions inutilisées de la ligne de bit. Ce faisant, le ''scheduler'' est découpée en segments, qui peuvent être désactivés si besoin. S'il y a peu d'instructions chargées dans le ''scheduler'', les portions inutilisées sont désactivées. La technique marche d'autan mieux si les instructions sont compactées au début de le ''scheduler''. [[File:Wire partitionning.png|centre|vignette|upright=2|Wire partitionning]] Tout le problème est de savoir quelles portions désactiver. La technique est assez simple si le ''scheduler'' est compactée, à savoir si toutes les instructions sont régulièrement regroupées au début de la mémoire CAM. Mais même avec cette optimisation, la décision de désactiver une portion de le ''scheduler'' n'est pas à prendre à la légère. Il ne faut pas désactiver une portion contenant des instructions pouvant être émise sous peu. La décision dépend de paramètres variés : proportion d'entrée vides, quantité d'entrées récemment activées/désactivées récemment, présences d'entrées avec un ''match'' d'opérandes récent, etc. Il est important de préciser que les techniques en question fonctionnent aussi sur les autres types de ''scheduler'', qui ne sont pas basées sur des mémoires associatives. Nous allons voir celles-ci dans la suite du chapitre, mais gardez à l'esprit que ces optimisations, à savoir désactiver les entrées vides/prêts et partitionner le ''scheduler'', sont des optimisations générales qui marchent avec presque tout. ===L'ajout d'une FIFO pour les instructions déjà prêtes à l'émission=== D'autres techniques permettent de réduire aussi bien le cout en circuits que la consommation d'énergie de le ''scheduler''. L'idée est d'utiliser une mémoire associative quand elle est réellement nécessaire, mais d'utiliser un ''scheduler'' "normale" dès que possible. La méthode la plus simple tient compte du fait que certaines µopsont déjà toutes leurs opérandes de disponibles à l'émission, mais doivent quand même être mises en attente, parce que l'ALU adéquate est occupée, parce que des dépendances WAW/WAR sont encore là, ou pour tout autre raison. Dans ce cas, elles sont mises en attente non pas dans le ''scheduler'', mais dans une mémoire FIFO toute simple. L'idée est qu'au lieu d'avoir une énorme mémoire associative pour le ''scheduler'', on déplace quelques entrées dans une petite FIFO annexe. Le résultat est un gain d'énergie et de circuits, au prix d'une perte de performance mineure. La perte de performance en question se manifeste si aucune instruction n'a ses opérandes de prêtes à l'émission : le programme n'utilise pas la FIFO et voit alors un ''scheduler'' plus petite. Une amélioration de cette technique tient compte du fait que certaines instructions sont dans un cas intermédiaire. Elles ont déjà un opérande de prête lors de l'émission, mais pas l'autre. Le nombre d'opérandes varie suivant l’instruction : certaines n'ont besoin que d'un seul opérande. De plus, il arrive qu'une opération tout juste décodée ait déjà un ou plusieurs de ses opérandes de prêts. Cette constatation permet d'éviter d'utiliser des comparateurs pour les opérandes déjà prêts. Par exemple, on peut parfaitement utiliser trois ''scheduler'' : * une pour les instructions dont tous les opérandes sont prêts, mais qui sont quand même mises en attente, sans comparateur ; * une pour les instructions dont un seul opérande manque, qui n'utilise qu'un comparateur par entrée ; * une pour les instructions dont deux opérandes manquent à l'appel, qui utilise deux comparateurs par entrée. C'est beaucoup plus économique que d'utiliser une seule grosse ''scheduler'' qui contiendrait autant d'entrées que les trois précédentes réunies, avec deux comparateurs par entrée. Certains sont même allés plus loin, et ont proposé de supprimer le ''scheduler'' avec deux opérandes par entrée. Les instructions dont deux opérandes sont inconnus au décodage sont stockées dans le ''scheduler'' pour instructions avec un comparateur par entrée. Un circuit de prédiction se charge alors de prédire l'opérande manquant, cette prédiction étant vérifiée plus loin dans le pipeline. Il serait cependant étonnant qu'une telle proposition ait donné lieu à la moindre implémentation réelle. ===Les optimisations de la consommation d'énergie avancées=== D'autres chercheurs ont conservé un ''scheduler'' unique, avec autant de comparateurs par entrée qu'il y a d'opérandes possibles par instruction. Simplement, le processus de détection des opérandes prêts est légèrement ralenti : on ne vérifie qu'un opérande par cycle. Pour vérifier les deux opérandes d'une entrée, on doit attendre deux cycles. Enfin, certains chercheurs ont proposé des ''scheduler'' segmentées. Les instructions circulent à chaque cycle d'un segment vers le suivant : en conséquence, certains segments conservent les instructions les plus anciennes, un autre les instructions les plus jeunes, etc. Seul le denier segment, celui qui contient les instructions les plus vielles, peut émettre une instruction : la détection des opérandes se fait seulement dans le dernier segment, qui contient les instructions les plus anciennes. On économise ainsi beaucoup de comparateurs. Certains chercheurs ont tenté de pipeliner l'étape de sélection des opérandes, ainsi que l'étage d'arbitrage. Mais en faisant cela, il faut plusieurs cycles pour détecter qu'une instruction a ses opérandes prêts, ce qui pose problème face à de nombreuses dépendances RAW. Pour éviter de trop perdre en performances, certains chercheurs ont décidé d'utiliser des techniques pour prédire quelles seront les instructions dont les opérandes seront bientôt prêts. Si détecter qu'une instruction est prête prend n cycles, le processeur devra tenter de prédire la future disponibilité des opérandes n cycles en avance pour obtenir des performances optimales. ===Remplacer la mémoire associative par une RAM=== Une autre optimisation possible est de remplacer le ''scheduler'' par une mémoire RAM, dont chaque mot mémoire correspondrait à une entrée. Une telle optimisation permet en théorie de se passer des comparateurs associés à chaque entrée, mais au prix de l'ajout de circuits annexes potentiellement couteux. La première de ces techniques, la '''recherche directe par étiquette''' (direct tag search) fut créée par Weiss et son collègue Smith. Ils cherchaient à améliorer l'algorithme de Tomasulo, un algorithme qu'on expliquera dans quelques chapitres. Rappelons que chaque instruction produit un résultat, qui devra être rapatrié dans une ou plusieurs entrées de le ''scheduler''. L'optimisation de la recherche directe par étiquette fonctionne dans le cas où le résultat de l'instruction n'est utilisé que par une seule entrée, et pas plusieurs. Le principe est simple : chaque champ « opérande » d'une entrée est adressable via le nom de registre de cet opérande. Pour faire le lien entre entrée et nom de registre, la recherche directe par étiquette ajoute une table de correspondances matérielle, une mémoire RAM qui mémorise les adresses des champs « opérande » des entrées. Les adresses envoyées dans cette mémoire sont les noms de registres des résultats. Lors de l'émission, la table de correspondances est mise à jour. Les numéros des champs « opérande » réservés lors de l'émission sont mémorisés dans les mots mémoire qui correspondent aux deux registres sources. Toutefois, une petite vérification est faite lors de l'émission : s'il y a déjà une correspondance dans la table pour un registre source, alors une autre instruction compte lire ce registre. Pour éviter d'écraser les données de l'instruction précédente dans la table de correspondances, l'émission de l'instruction est bloquée. [[File:Recherche directe par étiquette.png|centre|vignette|upright=2|Recherche directe par étiquette.]] ==Les ''schedulers'' avec préplanification== Avec la '''préplanification''' (''prescheduling''), le ''scheduler'' est composée de mémoires FIFO dans lesquelles les instructions sont triées dans l'ordre d'émission. Il n'y a pas de logique d’émission proprement dite, celle-ci se bornant à vérifier si l'instruction située au début de la FIFO peut s’exécuter. Par contre, le préplanificateur détecte les dépendances et en déduit où insérer les instructions dans le tampon d'émission, à l'endroit le plus adéquat. [[File:Préplanification.jpg|centre|vignette|upright=2|Préplanification.]] ===L'usage de FIFO multiples=== La technique de préplanification la plus simple utilise plusieurs FIFO. Quand une instruction a une dépendance avec une autre instruction, les deux sont placées dans la même FIFO. Pour cela, le préplanificateur détecte les chaines d'instructions dépendantes, et place les instructions dans la FIFO adéquate. A chaque cycle, l'unité d'émission lit une micro-opération dans chaque FIFO et vérifie si elle peut l'émettre. Si la micro-opération n'a pas ses opérandes disponibles, ou qu'une dépendance structurelle survient, alors la FIFO est bloquée. La micro-opération attend que la dépendance soit résolue, bloquant toutes les instructions précédentes. Mais les autres FIFO ne sont pas bloquées, laissant de la marge de manœuvre. [[File:Préplanification par FIFO multiples.png|centre|vignette|upright=1.5|Préplanification par FIFO multiples.]] ===La technique du tampon trié=== La technique du '''tampon trié''' trie les instructions selon le temps d'attente avant leur exécution. Les instructions qui sont censées s’exécuter bientôt sont insérées au tout début de la FIFO, tandis que les instructions qui s’exécuteront dans un long moment sont insérées vers la fin. Là encore, l'unité d'émission lit une micro-opération dans la FIFO, et détermine si elle peut être émise. Si une dépendance survient, l'émission est retardée, et la FIFO est bloquée. [[File:Préplanification par tampon trié.png|centre|vignette|upright=1.5|Préplanification par tampon trié.]] La technique a cependant quelques problèmes assez importants. Le premier problème est que la FIFO est bloquée lorsqu'une micro-opération ne peut être émise. Le second problème est que le temps avant exécution n'est pas toujours connu, notamment pour les instructions d'accès mémoire. Et cela se répercute sur les instructions dépendantes de celles-ci. Pour résoudre ce genre de problèmes, l'usage d'un pipeline à ''replay'' est possible, et est même l'une des meilleures solutions possible, malgré ses défauts. L'idée est que les lectures sont pré-planifiées en supposant qu'elles font un succès de cache L1. Si la prédiction est fausse, la lecture est ré-exécutée plusieurs cycles plus tard, en supposant qu'elle fait un succès dans le cache L2, et ainsi de suite. Elle est alors ré-insérée dans la FIFO, elle est pré-planifiée une seconde fois. Il en est de même si une micro-opération ne peut pas être émise : il suffit de la réinsérer dans la FIFO au bon endroit, en attendant que ses dépendances soient résolues. Ainsi, l'instruction fautive ne bloque pas le ''scheduler'', et retente sa chance autant de fois qu'il le faut. [[File:Préplanification par fenêtre d’instruction scorebarodée.png|centre|vignette|upright=1.5|Préplanification par ''scheduler'' scorebarodé.]] Une autre solution utilise deux ''schedulers'' : une FIFO gérée par la préplanification, et une vraie ''scheduler'' pour les instructions dont le temps d'attente ne peut pas être déterminé. Il est possible de mettre cette dernière avant la préplanification, afin de gérer les temps d'attente des instructions d'accès mémoire. Quand le temps d'attente d'une lecture devient connu, ses instructions dépendantes sont gérées avec préplanification. [[File:Préplanification avec fenêtre d’instruction.png|centre|vignette|upright=2.5|Préplanification avec ''scheduler''.]] ===Les ''scheduler'' avec allocation temporelle statique=== L''''allocation temporelle statique''' correspond à une technique utilisée sur les processeurs Cuzco de l'entreprise Condor. La technique en question a été présenté en 2025, mais des idées similaires ont été présentées dans la littérature académique. Elle ressemble beaucoup aux techniques de pré-planification, avec cependant quelques différences. L'idée est simple : le processeur dispose de plusieurs ''scheduler'', qui mettent en attente les micro-opérations. Lors de l'étape de renommage de registres, le processeur détermine dans combien de cycles d'horloge la micro-opération sera prête pour exécution. La micro-opération est alors mise en attente durant ce nombre de cycles, dans les ''scheduler'', puis est émise une fois ce nombre de cycles écoulés. Ce faisant, les ''scheduler'' n'ont pas besoin de détecter la disponibilité des opérandes à chaque cycle, pour chaque micro-opération en attente. Le ''timing'' de l'émission des micro-opérations est décidé à l'avance. L'implémentation exacte n'est pas connue, mais plusieurs solutions sont imaginables. Par exemple, le ''scheduler'' peut simplement être composée de plusieurs mémoires de petite taille, chacune contenant les micro-opérations destinées à être exécutées dans N cycles, N étant différent pour chaque mémoire. Une autre solution, plus réaliste, utilise un ''scheduler'' dans laquelle la micro-opération est couplée à des champs pour les opérandes, et un champ compteur. Le champ compteur est initialisé avec le nombre de cycles à attendre, et est décrémenté à chaque cycle d'horloge. Quand il atteint zéro, la micro-opération est émise. Vous remarquerez que la méthode ne marche que si toutes les micro-opérations prennent un nombre fixe de cycles d'horloge. Et autant c'est le cas pour les micro-opérations arithmétiques ou logiques, autant les accès mémoire ne rentrent pas dans ce cadre. En théorie, on ne sait pas combien de temps prendra un accès mémoire. Et cette incertitude se répercute sur les instructions dépendantes d'un accès mémoire. Pour éviter cela, le processeur réutilise un pipeline à ''replay'' tel que vu dans le chapitre précédent. L'unité de renommage de registre suppose que tout accès mémoire fait un succès de cache L1, et décide des ''timings'' d'émission sous cette hypothèse. Si une lecture subit un défaut de cache, elle est ré-exécutée, de même que toutes les instructions dépendantes. Pour cela, le registre de destination de la lecture est marqué comme invalide, grâce à un bit spécifique attaché au registre. Toute instruction qui lit un opérande invalide est elle aussi ré-executée de zéro. Pour simplifier, l'unité d'émission ressemble à une unité d'émission dans l'ordre, avec un registre de disponibilité, qu'on aurait amélioré pour aller au-delà de la simple détection des dépendances d'instruction. Pour déterminer les ''timings'' d'émission, à savoir quand émettre une micro-opération, le processeur utilise une unité d'émission à deux étages. Le premier étage est appelé le ''register scoreboard'', le second étage est appelé la ''Time Ressource Matrix''. Les deux étages communiquent entre eux, comme on va le voir, et leurs noms donnent une idée de ce qu'ils font. Le premier étage gère les dépendances de registres, le second gère les dépendances structurelles. Le premier étage est un registre de disponibilité amélioré, qui gère les dépendances de registre. Cet étage sait quand tel registre sera écrit, et donc que l'opérande écrit dedans sera disponible à partir de tel cycle d'horloge. Il le sait car l'étage suivant l'aura prévenu, mais laissons cela de côté pour le moment. Quand une micro-opération rentre dans cet étage, il vérifie les dépendances avec les registres et les micro-opérations antérieures. Vu qu'il sait quand les registres seront disponibles, il peut déterminer quand l'instruction pourra s'exécuter. Par exemple, si une micro-opération lit les deux registres R7 et R15, qui sont disponibles respectivement dans 5 et 7 cycles, le premier étage sait que la micro-opération devra attendre 7 cycles. Mais tout cela ne suffit pas à déterminer quand émettre une micro-opération. En effet, il fait aussi gérer les dépendances structurelles, ce qui est le boulot du second étage. Le second étage utilise pour cela une ''Time Ressource Matrix'', qui mémorise l'occupation de diverses "ressources", pour les 256 cycles d'horloge à venir. Les ressources en question sont les ports de lecture/écriture du banc de registre, les ALUs utilisées, si la micro-opération utilise l'unité mémoire, etc. Le second étage prend en entrée une micro-opération, détermine quelles "ressources" elle utilise, puis regarde leur disponibilité. Elle détecte alors les dépendances structurelles et détermine alors quand peut s'exécuter la micro-opération. Elle peut retarder l'émission de quelques cycles, si une dépendance structurelle est détectée. Une fois sortie du second étage, on sait quand la micro-opération va être émise, à quel cycle précisément. Et vu que la durée de l'instruction est fixe, on sait quand cette micro-opération va se terminer, quand son résultat sera disponible. Cela permet de mettre à jour la ''Time Ressource Matrix'', pour préciser que le port d'écriture sera occupé à tel moment. De plus, cette information est transmise au premier étage, qui sait alors quand est enregistré le résultat dans le registre de destination. C'est comme cela que le premier étage sait quand un registre est disponible : le second étage le prévient, quand il émet une instruction ! La ''Time Ressource Matrix''mémorise l'occupation des "ressources" pour les 256 cycles d'horloge à venir. Cependant, elle ne vérifie pas les dépendances pour les 256 cycles suivants. Quand elle reçoit une micro-opération, elle teste les dépendances structurelles pour seulement les 8 prochains cycles maximum. Si la micro-opération ne peut pas être émise pendant ces 8 cycles, le pipeline est bloqué, un ''pipeline stall'' est émis. Pour être plus précis, vu que le processeur peut décoder 8 micro-opérations en même temps, cela permet de ne consulter que 64 cycles d'horloge sur les 256. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les premiers processeurs Intel | prevText=Les premiers processeurs Intel | next=Le renommage de registres | nextText=Le renommage de registres }} </noinclude> m6xoaeyjte0ijtj77jb7pgyeto4dkbl 773683 773677 2026-09-29T23:16:48Z Mewtow 31375 773683 wikitext text/x-wiki Dans les chapitres précédents, nous avons parlé des techniques dites d''''émission dans l'ordre'''. L'idée est d’exécuter une nouvelle micro-opération à chaque cycle, dans des unités de calcul séparées. Les instructions sont émises consécutivement, mais les instructions s’exécutent en parallèle dans des unités de calcul séparées. Par contre, quand l'unité d'émission ne peut pas émettre une instruction, elle bloque tout le pipeline. Les instructions qui suivent sont elles aussi bloquées, elles doivent attendre leur tour, même si elles sont en capacité de s'exécuter. Les techniques d'exécution dans le désordre que nous allons voir dans ce chapitre corrigent ce point précis. Elles sont dites à '''émission dans le désordre'''. Elles se distinguent des précédentes sur un point précis : quand l'unité d'émission bloque l'émission d'une instruction, les instructions suivantes peuvent poursuivre. L'émission des instructions peut donc se faire dans le désordre, dans le sens où une instruction peut être émise alors qu'une instruction précédente ne l'est pas encore. Mais avant de poursuivre, quelques point niveaux terminologie : * L'émission dans le désordre est un terme parlant et assez précis. Malheureusement, la terminologie la plus utilisée par d''''exécution dans le désordre'''. Et nous utiliserons ce terme dans la suite du cours, histoire de ne pas trop dévier de la nomenclature habituelle. * Nous utiliserons parfois l'abréviation OOO pour parler d'exécution dans le désordre. L'abréviation est celle de ''Out Of Order Execution''. * Nous utiliserons aussi l'abréviation ''µop'' pour parler de micro-opération, ''µops'' au pluriel pour parler de plusieurs micro-opérations, ou des micro-opérations en général. L'exécution dans le désordre ne gère en effet que des µops, elle se situe après l'étape de décodage. Pour décrire comment est implémentée l'émission dans le désordre, il faut commencer par parler des processeurs sans. Les processeurs sans exécution dans le désordre ont une unité d'émission qui bloque tout le pipeline dès qu'une µop ne peut pas être émise. Pour limiter l'impact de ce blocage, quelques rares processeurs incorporent une '''file de micro-opération''', une mémoire FIFO qui met en attente les µops. Vu que c'est une mémoire FIFO, les µops sont émises dans l'ordre, à savoir l'ordre d'ajout, dans l'ordre de décodage. Le schéma ci-dessous illustre une telle file d'attente couplée à un ''scoreboard''. L'exécution dans le désordre améliore la file de µops sur un point : ce n'est plus une mémoire FIFO. Les µops sont insérées dans l'ordre, mais peuvent sortir dans le désordre (être émises dans le désordre). La file de µops devient alors un '''''scheduler''''', terme anglais que je ne compte pas traduire. Un terme équivalent est '''''scheduler''''', terme traduit directement de l'anglais ''instruction Window''. Terme assez trompeur, car elles mettent en attente des µops, pas des instructions. [[File:Différence file µops et fenêtres instruction.png|centre|vignette|upright=2|Différence file µops et ''schedulers'' ]] Le ''scheduler'' émet une µop dès que ses opérandes sont disponibles. Par disponible, on veut dire présent soit dans le réseau de contournement, soit dans les registres. Le ''scheduler'' détecte automatiquement quand les opérandes d'une µop sont disponibles, grâce à une unité d'émission intégrée. L'unité d'émission et la file d'attente de µops sont fusionnés ensemble, dans un seul circuit, mais nous allons dire qu'ils sont conceptuellement séparés pour le moment. À chaque cycle, l'unité d'émission consulte les µops en attente pour détecter lesquelles peuvent s'exécuter. Le ''scheduler'' est spécialement être conçue pour, c'est une sorte de mémoire associative très complexe, comme on le verra dans ce qui suit. [[File:OOO Issue.png|centre|vignette|upright=2.5|Exécution dans le désordre avec un ''scheduler'']] Une fois qu'une µop sort du décodeur d'instructions, elle est ajoutée en parallèle dans le ''scheduler'' et le ROB. La raison est que les µops quittent le ''scheduler'' dans le désordre, et qu'elles doivent être remises en ordre par la suite. Le ROB s'occupe de cette remise en ordre, mais il a besoin de savoir dans quel ordre les µops sont censées être, et cet ordre est celui du décodage. Aussi, pour remplir le ROB, la seule opportunité est en sortie de l'unité de décodage. Dans le cas où une instruction est décodée en plusieurs micro-opérations, elles sont toutes insérées en même temps dans le ''scheduler'' et le ROB, en tenant compte de leur ordre. L'implémentation la plus "simple" de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Les µops décodées sont accumulées dans le ''scheduler'', où elles attendent leur tour. Bien que simple en apparence, cette implémentation cache une complexité très importante, liée aux accès mémoire. Les micro-opérations mémoire sont à part des autres, pour ce qui est de leurs dépendances de données. Non seulement elles ont des dépendances de registre, mais elles sont aussi des dépendances d'adresse. Par exemple, deux écritures peuvent utiliser deux registres d'adresse différents, mais ceux-ci peuvent contenir la même adresse. Et autant on peut détecter les dépendances de registre lors de l'émission, autant c'est plus compliqué avec les dépendances d'adresse. De plus, rappelons que si les lectures peuvent s'exécuter dans le désordre, les écritures doivent s'exécuter dans l'ordre, ou du moins en donner l'illusion. Pour cela, le processeur remet les écritures dans l'ordre avec une sorte de mini-ROB intégré à l'unité mémoire, appelée la file d'écriture. Elle complémente le ROB, qui lui ne gère que les écritures dans les registres, mais les deux collaborent. La file d'écriture envoie une écriture à la mémoire RAM quand le ROB lui dit que c'est bon, les instructions précédentes sont terminées ''dans l'ordre du programme''. Les processeurs modernes ajoutent des techniques d'exécution dans le désordre des accès mémoire, mais nous les verrons dans un chapitre dédié. Elles permettent d'utiliser un ''scheduler'' unique, qui mémorise aussi les µops mémoire. Si elles sont mises en place, l'unité mémoire n'a pas besoin de file de µops séparée. Les dépendances de registre sont traitées par le ''scheduler'', alors que les dépendances d'adresse sont gérées par l'unité mémoire gére les dépendances d'adresse. Elle utilise pour cela des techniques de '''''désambiguïsation mémoire''''', qui auront droit à un chapitre dédié. [[File:Processeur avec exécution dans le désodre des accès mémoire.png|centre|vignette|upright=2|Processeur avec exécution dans le désodre des accès mémoire]] Les processeurs assez anciens n'autorisaient pas d'exécution dans le désordre des accès mémoire. Concrètement, les accès mémoire devaient se faire dans l'ordre, mais les autres µops pouvaient être exécutées dans le désordre. Pour garantir l'ordre des µops mémoire, l'unité mémoire est précédée par une file de micro-opérations séparée, pour forcer l'exécution dans l'ordre des accès mémoire. De plus, les µops mémoire ne peuvent pas utiliser le ''scheduler''. Dit autrement, le ''scheduler'' ne mémorise pas de µops mémoire. Après le décodage, les µops sont réparties soit dans la file de µops mémoire, soit dans le ''scheduler''. Le décodeur classe les µops suivant que ce sont des µops mémoire ou non, et les envoient à la bonne destination. Dans ce chapitre, on supposera que c'est cette solution qui est utilisée. [[File:Processeur avec émission dans l'ordre des accès mémoire.png|centre|vignette|upright=2|Processeur avec émission dans l'ordre des accès mémoire]] ==L'implémentation d'un ''scheduler'' : généralités== Un ''scheduler'' est une mémoire qui mémorise des micro-opérations. Elle est cependant plus complexe qu'une mémoire RAM ou qu'une FIFO et ressemble un petit peu à une mémoire cache. Elle dispose d'un port d'écriture et d'un port de lecture, au minimum. Le port d'écriture permet à l'unité de décodage d'insérer une micro-opération dedans, d'ajouter la micro-opération qui vient d'être décodée. Si une instruction machine est décodée en plusieurs micro-opération, deux possibilités. La première est de les insérer un par un, ce qui fait qu'on peut se contenter d'un seul port d'écriture. L'autre possibilité est de les ajouter en même temps, ce qui demande plusieurs ports d'écriture. Le port de lecture sert à émettre une instruction. On part du principe que le ''scheduler'' ne peut émettre qu'une seule instruction à la fois, car les processeurs que nous avons vu précédemment sont de ce type. Mais nous verrons dans quelques chapitres qu'il existe des processeurs dits superscalaires, qui sont capables d'émettre plusieurs instructions par cycle. Dans ce cas, le ''scheduler'' a un seul port de lecture. Un processeur superscalaire, quant à lui, doit avoir un port de lecture par unité de calcul, ce qui fait beaucoup plus. Les ''schedulers'' sont composées d''''entrées''', des mots mémoire qui stockent une instruction. Une instruction réserve une entrée après son décodage et la libère dès qu'elle est envoyée aux unités de calcul. Une entrée contient l'opcode (les signaux de commande à envoyer à l'ALU), le registre de destination du résultat, les registres de chaque opérande, et éventuellement des signaux de commande en plus. De plus, chaque opérande est couplée à un bit de disponibilité, qui indique si elle est disponible. Quand un opérande est écrit dans les registres, le bit de présence correspondant est mis à jour. Enfin, chaque entrée possède un bit ''empty'' qui indique si elle est vide, cette information étant utile pour réserver des entrées. [[File:Entrée d'une station de réservation - sans les tags.png|centre|vignette|upright=3|Entrée d'un ''scheduler'']] ===Les stations de réservation=== Les '''stations de réservation''' sont des ''scheduler'' particulières, qui sont capables de mémoriser les opérandes des instructions. Les entrées des stations de réservation sont identiques à celle des autres ''scheduler'', si ce n'est que les opérandes de l'instruction sont enregistrés directement dans des champs séparés. Il y a deux champs, un par opérande, pour stocker l'opérande elle-même, lue depuis les registres ou obtenue via le réseau de contournement. Notons que les champs pour les opérandes viennent en plus des champs pour les noms de registres, encore que les deux peuvent être fusionnés si on veut optimiser le tout. [[File:Entrée d'une station de réservation.png|centre|vignette|upright=3|Entrée d'une station de réservation.]] Précisons que la terminologie n'est pas très fiable. Les termes "''scheduler''" et "station de réservation" ne regroupent pas du tout la même chose d'un papier de recherche à l'autre, d'un bouquin à l'autre, d'un chercheur à l'autre, d'un ingénieur à l'autre, d'un professeur à l'autre. Le terme initial vient pourtant de l'article original sur l'algorithme de Tomasulo, où il désignait un ''scheduler'' associée à une unité de calcul précise. Mais le terme a ensuite été réutilisé, ce qui fait que certains processeurs avec plusieurs unités de calcul sont décrits comme ayant une unique station de réservation. En bref : c'est le bazar ! Mais nous en reparlerons dans le chapitre sur le renommage de registres, car c'est la place idéale pour les aborder. Toujours est-il que j'ai fait le choix de confondre les concepts de ''scheduler'' et de station de réservation avec les concepts de '''lecture avant émission''' et de '''lecture après émission'''. La différence entre les deux est que les registres sont lus après émission avec un ''scheduler'', avant avec des stations de réservation. Dans le cas "avant émission", les opérandes sont mémorisés dans la station de réservation. Et cette différence a une influence sur le pipeline du processeur, le banc de registres et tout ce qui s'ensuit. Un désavantage de la lecture avant émission est qu'il faut stocker les opérandes après lecture, ici dans les stations de réservation. Mais un avantage est que le banc de registre a besoin de moins de ports de lecture, car une bonne partie des opérandes sont fournies par le système de contournement. Nous verrons cela dans le détail dans le chapitre sur les processeurs superscalaires. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Lecture après émission.]] [[File:Read Before Issue.png|centre|vignette|upright=2.5|Lecture avant émission.]] ===La logique d'éveil et de sélection=== Dans le cas qui va suivre, on suppose que le processeur ne peut émettre qu'une instruction à la fois. Chaque cycle, une instruction est sélectionnée et est envoyée dans le chemin de données, soit à une ALU, soit à une unité d'accès mémoire. La sélection d'une instruction est effectuée par l'unité d'émission, qui est aussi appelée le '''''scheduler'''''. Elle gère la disponibilité des opérandes et la disponibilité des unités de calcul adéquate. Le choix de l'instruction émise doit être le plus pertinent possible, pour des raisons de performances. Pour le premier point, l'unité d'émission détermine quelles instructions sont candidates pour l'émission. Les ''instructions candidates'' sont celles dont tous les opérandes sont prêts. Le processeur contient un circuit qui détecte les instructions candidates : la '''logique d’éveil''' (''wake-up logic''). Une fois que la logique d'éveil a fait son travail, une instruction est choisie pour s’exécuter en fonction de la disponibilité des unités de calcul adéquates. Ce rôle est dévolu à un circuit qu'on appelle la '''logique de sélection''', ou ''select logic''. [[File:Fonctionnement complet de la logique d’émission.jpg|centre|vignette|upright=1.5|Fonctionnement complet de la logique d’émission.]] La logique de sélection doit gérer le fait que les unités de calcul du processeur ne sont pas toutes identiques. Déjà, un processeur a généralement des unités séparées pour les instructions entières et flottantes, des unités spécialisées dans les accès mémoire, parfois des unités spécialisées pour les branchements. Une instruction doit être attribuée à la bonne unité de calcul, on ne doit pas envoyer une instruction entière dans une unité de calcul flottante. De plus, parmi les unités de calcul entières, toutes ne sont pas identiques. Par exemple, il est fréquent d'avoir plusieurs unités de calcul spécialisées dans les opérations simples (additions, soustractions, opérations logiques) avec une unité pour les multiplications/divisions séparées, parfois une unité spécialisée pour les décalages/rotations, etc. Là encore, allouer la bonne instruction à la bonne ALU est complexe. Plus les unités de calcul sont hétérogènes, plus la logique de sélection est compliquée. Les logiques d'éveil comme de sélection sont assez complexes. Comme on le verra plus bas, la logique de sélection la plus simple, qui gère une seule unité de calcul, est basée sur un encodeur à priorité, couplé à d'autres circuits. Et pour gérer plusieurs ALUs, il faut mettre des encodeurs en cascade. Le résultat est que même en prenant une logique de sélection simple, elle sera assez lente et gourmande en circuits. Aussi, la logique de sélection met souvent un cycle d'horloge entier pour faire son travail, elle a son propre étage de pipeline attribué. La logique d'éveil est dans le même cas, ce qui fait qu'émettre une micro-opération demande deux cycles d'horloge. Le défaut est que cela rajoute des cycles d'horloges entre le ''scheduler'' et l'ALU, ce qui complique la gestion du pipeline. Ces cycles de retard sont à prendre en compte au moment d'émettre les instructions, les ''scheduler'' doit en tenir compte pour des performances optimales. Sans tenir compte de ces cycles de retard, les instructions arrivent en retard de quelques cycles à l'ALU, cycles de retard durant lesquels l'ALU n'a pas fait de calcul et a été sous-utilisée, sans compter que le système de contournement n'est pas utilisé au mieux. Et le problème est encore plus important sur les processeurs avec des stations de réservation, qui utilisent la "lecture après émission" : cela rajoute un cycle d'horloge en plus, un temps de retard en plus. ===La logique d'éveil : l'émission anticipée=== La logique d'éveil doit tenir compte du fait qu'il y a plusieurs étages entre l'émission et l'exécution sur une unité de calcul. Par exemple, un processeur a souvent entre un et à cinq étages entre la file d'attente et les unités de calcul. Il faut lire les registres, gérer le contournement, et cela peut prendre quelques cycles d'horloge. Sur le Pentium 4, on trouve 6 étages entre le ''scheduler'' et l'entrée de l'ALU. Si les micro-opérations sont émises quand les opérandes sont disponibles, il y aura un délai de quelques cycles avant qu'elles atteignent l'ALU. Alors qu'idéalement, on souhaiterait que la micro-opération atteigne l'ALU dès que ses opérandes sont disponibles, pour profiter des techniques de contournement. Pour cela, la logique d'éveil émet les instructions quelques cycles en avance pour qu'elles arrivent au bon moment. Il s'agit d'une technique d''''émission anticipée''', dont nous avions parlé dans le chapitre sur le contournement. : Il faut noter que le problème se pose plus avec des ''schedulers'' qu'avec des stations de réservation. Les premières ont un étage en plus entre émission et ALU, vu qu'il faut lire des registres après l'émission. L'émission anticipée demande d'émettre un signal d'éveil en avance de quelques cycles, pile au bon moment. Par exemples, si on a deux étages entre l'ALU et l'unité d'émission, le signal de réveil sera généré deux cycles avant que le résultat soit effectivement calculé. L'implémentation varie, mais deux solutions sont possibles. La première est de générer le signal d'éveil dans l'ALU, ce qui n'a de sens que pour les opérations comme les multiplications ou les divisions, qui prennent plusieurs cycles. Une autre technique génère le signal de réveil dans une structure centralisée, spécialisée dans la génération des signaux d'éveil. L'unité de composée d'un registre à décalage par registre. Imaginons qu'une instruction est émise, que cette instruction mette N cycles à s'exécuter, et qu'elle écrive dans un registre de destination. L'unité sélectionne alors le registre à décalage associé au registre de destination, et met le bit numéro N à 1. Le registre décalé d'un cran à chaque cycle. Quand le bit sortant est un 1, alors le signal de validité pour l'opérande est généré. L'émission anticipée marche bien si l'instruction a une durée fixe, connue à l'avance. Et autant c'est le cas pour les instructions arithmétiques et logiques, autant ce n'est pas le cas pour les accès mémoire. Les accès mémoire ont une latence variable : quelques cycles pour un succès de cache, plusieurs dizaines de cycles pour un défaut de cache L1, pas loin de la centaine pour un défaut de cache L2, etc. Et cela pose des problèmes pour l'émission anticipée. L'émission en avance pour les accès mémoire est purement spéculative : le processeur émet des instructions en supposant que la lecture entrainera un succès de cache, quitte à annuler l'instruction en cas de défaut de cache. Mais faire ainsi demande non seulement d'annuler les instructions émises en avance, mais aussi de ne pas retirer les instructions émises en avance de le ''scheduler''. Elles sont émises, mais une copie de sauvegarde est conservée dans le ''scheduler''. Si le processeur détecte un défaut de cache, il peut alors ré-exécuter l'instruction. S'il détecte un succès de cache, les instructions lecture-dépendante sont retirées de le ''scheduler'', la copie de sauvegarde est devenue inutile et est donc jetée. ===La logique de sélection : âge ou position ?=== La logique de sélection est primordiale pour de bonnes performances. Il existe deux méthodes principales pour sélectionner l'instruction à exécuter. La première est la plus simple : elle se base sur lé numéro de l'entrée. En effet, un ''scheduler'' est avant tout une sorte de mémoire, un mix entre mémoire associative, mémoire RAM, et FIFO. Et chaque entrée a un numéro, une adresse mémoire. Nous parlerons de numéro dans ce qui suit, car ce sera plus simple, le terme d'adresse mémoire étant peut-être un peu exagéré dans le contexte des ''scheduler''. Toujours est-il que le ''scheduler'' est adressable dans le sens où on peut lui envoyer le numéro de l'entrée voulue, et le ''scheduler'' renvoie le contenu de l'entrée sur son port de lecture. Et c'est ce que fait la logique de sélection : elle génère le numéro de l'entrée à lire. Le numéro est alors envoyé sur l'entrée d'adresse du ''scheduler'', et elle fournit la micro-opération associée sur son port de lecture, son '''port d'émission'''. La première méthode de sélection, donc. Elle est basée sur le numéro de l'entrée. Si plusieurs entrées sont éveillées, la logique de sélection prend celle avec le plus petit numéro. Elle porte le nom de '''sélection par position''', sous-entendu position dans le ''scheduler''. Vous l'avez peut-être deviné, mais la logique de sélection est alors un encodeur à priorité. Le circuit de sélection ne se résume donc pas seulement à un encodeur à priorité, mais c'est le circuit central. L'avantage d'une telle méthode de sélection est qu'elle est simple à implémenter : un encodeur à priorité est un circuit connu, facile à implémenter. Mais on remarque un défaut : un encodeur est un circuit assez rapide, mais qui utilise beaucoup de transistors, beaucoup de portes logiques, surtout si on veut qu'il soit rapide. Ce qui explique que la logique de sélection ait son propre étage de pipeline rien que pour elle. La seconde méthode s'appelle la '''sélection par âge''', au nom assez transparent. L'idée est de privilégier l'émission de l'instruction la plus ancienne. Elle demande que le ''scheduler'' trie les micro-opérations par ordre d'insertion dans le ''scheduler'', ce qui en fait une pseudo-FIFO. Le tri est partiel, car les instructions peuvent sortir du ''scheduler'' à tout moment. Compacter le ''scheduler'', à savoir regrouper toutes les entrées valides est une idée, mais elle est compliquée à implémenter. Aussi, elles préfèrent encoder des informations sur l'ordre d'émission dans chaque entrée. L'encodeur à priorité doit alors travailler non pas sur des nombres entiers liés à l'ordre d'insertion dans la pseudo-FIFO. Elle est encore plus gourmande en circuits que la méthode précédente. Les processeurs haute performance utilisent souvent des méthodes hybrides. Par exemple, les processeurs AMD de microarchitecture Bulldozer utilisaient une méthode intermédiaire. Ils utilisaient un ''scheduler'' couplée à un encodeur à priorité pour la sélection par position, mais complémentaient le tout avec une unité qui mémorisait l'instruction la plus ancienne dans le ''scheduler''. Le mécanisme de sélection par âge était utilisé en priorité. Mais si l'instruction la plus ancienne n'était pas prête, le processeur basculait sur le mécanisme de sélection par position. ===La compaction des ''scheduler''=== À chaque cycle, les instructions décodées sont ajoutées dans le ''scheduler'', dans des entrées vides. Vu que les instructions quittent celle-ci dans le désordre, ces vides sont dispersés dans le ''scheduler'', ce qui pose problème pour déterminer où placer les nouvelles instructions. La solution la plus triviale consiste à conserver une liste des vides, mise à jour à chaque insertion ou émission d'instruction. Une autre solution consiste à éliminer les vides en compactant le ''scheduler'' à chaque cycle d'horloge. Des circuits se chargent de détecter les vides et de regrouper les instructions en un unique bloc. Il faut signaler que certains processeurs arrivent à se passer de cette étape de compactage, mais au prix de ''scheduler'' nettement plus complexes. Autre problème : quand il faut choisir quelle instruction émettre, il y a toujours plusieurs candidats. Si on choisit mal, des instructions restent en attente trop longtemps parce que d'autres instructions plus jeunes leur passent devant. Pour éviter cela, les instructions les plus vielles, les plus anciennes, sont prioritaires. Pour cela, on peut utiliser une FIFO un peu spéciale pour le ''scheduler''. Si les ajouts d'instruction se font dans l'ordre, les instructions ne quittent pas forcément le ''scheduler'' dans l'ordre imposé par une FIFO : les instructions restent triées dans leur ordre d'ajout, même s'il y a des vides entre elles. Dans ces conditions, il est préférable que le compactage conserve l'ordre FIFO des instructions. Dans ces conditions, l'instruction la plus ancienne est celle qui est située à l'adresse la plus faible : le circuit de sélection peut donc être fabriqué avec des encodeurs, et est relativement simple. ==Les ''schedulers'' basées sur une matrice de dépendances== L'implémentation la plus simple étend le fonctionnement d'un pipeline dynamique usuel. Rappelez-vous le chapitre sur les pipelines dynamiques. Nous avions vu que de tels pipelines émettaient une instruction par cycle, quitte à émettre des bulles de pipeline en cas de dépendance bloquante. Et il est possible d'améliorer leur unité d'émission pour qu'elle soit compatible avec l'exécution dans le désordre. ===Rappels sur le registre de réservation/disponibilité=== L'émission d'une instruction est gouvernée par un ''registre de réservation'' qui indique quels registres sont réservés par une instruction, et ceux qui sont libres. Un registre réservé est un registre qui sera écrit par une instruction en cours d'exécution, mais qui n'a pas encore écrit son résultat. Les instructions candidates doivent avoir leurs opérandes dans des registres libres. Sinon, c'est signe que leurs opérandes sont réservés en écriture, donc pas encore écrites, donc pas disponibles. Si une instruction candidate veut lire ce registre, c'est signe qu'il y a une dépendance RAW : elle veut lire un registre réservé, qui est destiné à être écrit par une instruction en vol. Si elle veut écrire, c'est signe qu'elle veut écrire dans un registre où une autre instruction veut écrire : c'est une dépendance WAW. Dans les deux cas, l'instruction n'est pas émise. Le registre de réservation encode les registres réservés comme suit : chaque bit est associé à un registre. Le bit numéro 0 est associé au registre numéro 0, le bit numéro 1 au registre numéro 1, etc. Là, En clair, les numéros de registres réservés sont encodés en représentation non pas binaire, mais en représentation ''one-hot'' (vue au premier chapitre). {|class="wikitable" |+ Registre de réservation |- ! Registre 7 !! Registre 6 !! Registre 5 !! Registre 4 !! Registre 3 !! Registre 2 !! Registre 1 !! Registre 0 |- | 0 || 0 || 1 || 0 || 0 || 1 || 0 || 0 |} Avant d'émettre une instruction, l'unité d'émission extrait les registres opérande/destination et les convertis dans la même représentation que le registre de réservation, à savoir en représentation ''one-hot''. Le circuit de traduction binaire vers ''one-hot'' est, pour rappel, un simple décodeur. Puis, on fait un OU logique entre les sorties des décodeurs. Le résultat est un masque qui indique quels registres sont lus par l'instruction, encodé en représentation ''one-hot''. Appelons-le le '''masque d'opérandes'''. Le masque est alors comparé au registre de réservation pour vérifier si l'instruction peut être émise. [[File:Unité d'émission simple, dans l'ordre.png|centre|vignette|upright=2|Unité d'émission simple, dans l'ordre]] Si l'émission est autorisée, le registre de réservation est là aussi mis à jour. Le registre de réservation est aussi mis à jour dès qu'une instruction enregistre son résultat dans les registres, ou alors dès qu'il est disponible pour le contournement. Le bit associé au registre repasse alors à 0 (ou à 1). Sans contournement, la mise à jour se fait alors à la toute fin de l'instruction, quand elle se termine, lors de la dernière étape d'enregistrement, à la fin de son pipeline. Avec, elle se fait quand l'instruction quitte l'unité de calcul. ===L'extension à l'exécution dans le désordre : l'éveil par matrice de bits=== La différence entre un pipeline dynamique et l'exécution dans le désordre est que l'on passe d'une instruction à émettre à plusieurs. Plusieurs instructions sont mises en attente dans un ''scheduler'', et y attendent leur tour. L'idée est alors d'envoyer le registre de disponibilité à toutes les entrées, à toutes les instructions en attente. Ainsi, on sait quelles sont les instructions qui peuvent s'exécuter et celles qui ne le peuvent pas. L'implémentation est assez simple, elle ressemble beaucoup à l'implémentation d'un pipeline dynamique simple, si ce n'est que des circuits sont dupliqués. L'implémentation utilise des ''scheduler'' légèrement différentes de celles introduites plus haut. Elles n'utilisent notamment pas de bits de disponibilité, mais autre chose. Lorsqu'une instruction est ajoutée à le ''scheduler'', le masque de disponibilité des opérandes est stocké dans le ''scheduler''. A chaque cycle, le registre de disponibilité est envoyé à toutes les entrées, et est comparé avec tous les masques de disponibilité des opérandes. Si une comparaison renvoie un 1, alors l'instruction de l'entrée est une instruction candidate à l'émission. [[File:Unité d'émission dans le désordre basée sur un registre de disponibilité.png|centre|vignette|upright=2.5|Unité d'émission dans le désordre basée sur un registre de disponibilité]] L'ensemble est implémenté avec l'aide d'une '''matrice de bits''', où chaque ligne correspond à une entrée et chaque colonne à un registre. À chaque croisement entre une ligne et une colonne, on trouve un bit. Si le bit de la ligne n et de la colonne m est à 1, cela veut dire : l'instruction dans l'entrée n a besoin de lire le registre m. S’il est à 0, alors cela veut dire que l'instruction stockée dans la ligne n'a pas besoin de la donnée dans le registre m. [[File:Planificateur à matrice de bits.jpg|centre|vignette|upright=2|Planificateur à matrice de bits.]] Lorsqu'une instruction réserve une entrée, elle initialise la ligne en fonction des registres qu'elle souhaite lire. Pour vérifier si une instruction a ses opérandes prêts, le processeur compare le registre de disponibilité à la ligne associée à l'instruction/entrée. A chaque intersection ligne-colonne, se trouve un comparateur de 1 bit, qui détecte si le registre est demandé et disponible. Les résultats de cette porte sont ensuite envoyés à une porte ET, qui fait le gros du travail. [[File:Logique de détection de la disponibilité d'une instruction.jpg|centre|vignette|upright=2|Logique de détection de la disponibilité d'une instruction.]] ==Les ''schedulers'' basées sur une mémoire associative== Les processeurs modernes utilisent une mémoire associative pour le ''scheduler''. Les mémoires associatives ont été abordées il y a quelques chapitres, mais faisons quelques rappels. Les mémoires associatives servent à accélérer la recherche de données dans un ensemble. Or, un ''scheduler'' vérifie régulièrement si chaque entrée est prête. Il s'agit d'un processus de recherche d'une instruction qui respecte une condition bien précise dans la mémoire, ce qui fait que les mémoires associatives sont donc tout indiquées. Comme vous le savez, les signaux de commande d'une instruction sont propagés avec celle-ci dans le pipeline, le nom du registre de destination ne faisant pas exception. Le nom de registre est envoyé à le ''scheduler'' lors de l'écriture du résultat dans les registres. S'il y a correspondance, l'opérande est disponible et son bit de disponibilité est mis à 1. On peut adapter cette méthode pour tenir compte du contournement assez simplement. [[File:Détection des dépendances par propagation du registre de destination.png|centre|vignette|upright=2|Détection des dépendances par propagation du registre de destination.]] En conséquence, le circuit de détection des dépendances est constitué d'un grand nombre de comparateurs : un par champ « nom de registre » dans chaque entrée. La logique d'éveil/''wake up'' regroupe tous les comparateurs, la logique de sélection est un circuit situé en-dehors de la mémoire associative. Les entrées sont dans la mémoire associative elle-même. [[File:Gestion des bits de validité.png|centre|vignette|upright=2|Gestion des bits de validité.]] L'implémentation la plus simple est celle du schéma précédent, où on utilise une mémoire associative unique. Une version plus élaborée sépare le ''scheduler'' en deux parties : une mémoire qui mémorise les registres des opérandes, une autre mémoire pour le reste. La mémoire pour les registres opérandes est la mémoire associative proprement dite, c'est elle qui est associée aux comparateurs, à la logique de ''wake-up''/réveil, etc. Par contre, l'autre mémoire est une mémoire RAM simplifiée, qui mémorise les informations qui n'ont pas besoin des comparateurs. L'opcode de l'instruction est là-dedans, par exemple. le ''scheduler'' est donc une sorte de mémoire associative améliorée. Il se trouve que c'est aussi le cas du ROB. Et il est possible de fusionner le tampon de ré-ordonnancement avec le ''scheduler'' dans une structure unique. La différence avec un ''scheduler'' normal est que les entrées sont libérées non pas quand l'instruction est exécutée/émise, mais quand elle termine son exécution et quitte le ROB. le ''scheduler'' incorpore des bits dans chaque entrée, pour savoir si la µops associée a été émise et est en cours de traitement dans les ALUs. La méthode a notamment été utilisée sur les processeurs d'architecture K6 d'AMD. Le tout donnait une structure appelée le '''DRIS''' (''deferred scheduling register renaming instruction shelf''). Les processeurs PA 8000 de HP étaient aussi vraisemblabment dans ce cas, aussi. ===Les optimisations de la consommation d'énergie : la désactivation des portions inutilisées=== Le problème avec des ''scheduler'' de ce type est leur forte consommation énergétique, ainsi que le grand nombre de portes logiques utilisées, qui deviennent prohibitifs pour des ''scheduler'' un peu grosses. Pour résoudre ce problème, certains ont optimisé les comparateurs. D'autres ont tenté de profiter du fait que la majorité des bits dans les entrées sont composés de zéros. Bref, les optimisations purement matérielles sont légion. Une première solution est de désactiver les entrées qui sont inutilisées, vides, sans instruction. Pour cela, on fait précéder les comparateurs par un circuit qui les connecte ou déconnecte des lignes de bit. Le circuit est commandé par le bit ''empty'' qui indique si une entrée est vide ou non. L'avantage est que la consommation d'énergie de le ''scheduler'' devient alors proportionnelle au nombre d'entrées non-vides, et non au nombre d'entrées total. Du moins, en apparence, les entrées non-utilisées doivent quand même être alimentées pour fonctionner, mais l'activité de comparaison disparait dans les entrées vides. Il est possible d'étendre cette technique aux entrées dont les opérandes sont prêts. Les gains sont généralement assez bons, avec une réduction de consommation variant entre 30 et 50%, avec une implémentation très simple et très économe en circuits. Une autre solution, assez simple à mettre en place, consiste à désactiver une partie de le ''scheduler'' sin elle est inutilisée. Pour cela, il faut segmenter le ''scheduler'' avec la technique du ''wire partitionning''. Pour rappel, un ''scheduler'' est une mémoire associative. Et comme toute mémoire associative, elle contient des fils, les lignes de bit, qui relient les entrées/sorties à toutes les cellules mémoire. Plus une ligne de bit est longue, plus elle consomme d'énergie et plus le temps de lecture/écriture est long. L'idée est de segmenter les lignes de bits en plaçant des répéteurs qui recopient la tension d'un segment au suivant. Les répéteurs sont des tampons trois-états, ce qui permet de déconnecter les portions inutilisées de la ligne de bit. Ce faisant, le ''scheduler'' est découpée en segments, qui peuvent être désactivés si besoin. S'il y a peu d'instructions chargées dans le ''scheduler'', les portions inutilisées sont désactivées. La technique marche d'autan mieux si les instructions sont compactées au début de le ''scheduler''. [[File:Wire partitionning.png|centre|vignette|upright=2|Wire partitionning]] Tout le problème est de savoir quelles portions désactiver. La technique est assez simple si le ''scheduler'' est compactée, à savoir si toutes les instructions sont régulièrement regroupées au début de la mémoire CAM. Mais même avec cette optimisation, la décision de désactiver une portion de le ''scheduler'' n'est pas à prendre à la légère. Il ne faut pas désactiver une portion contenant des instructions pouvant être émise sous peu. La décision dépend de paramètres variés : proportion d'entrée vides, quantité d'entrées récemment activées/désactivées récemment, présences d'entrées avec un ''match'' d'opérandes récent, etc. Il est important de préciser que les techniques en question fonctionnent aussi sur les autres types de ''scheduler'', qui ne sont pas basées sur des mémoires associatives. Nous allons voir celles-ci dans la suite du chapitre, mais gardez à l'esprit que ces optimisations, à savoir désactiver les entrées vides/prêts et partitionner le ''scheduler'', sont des optimisations générales qui marchent avec presque tout. ===L'ajout d'une FIFO pour les instructions déjà prêtes à l'émission=== D'autres techniques permettent de réduire aussi bien le cout en circuits que la consommation d'énergie de le ''scheduler''. L'idée est d'utiliser une mémoire associative quand elle est réellement nécessaire, mais d'utiliser un ''scheduler'' "normale" dès que possible. La méthode la plus simple tient compte du fait que certaines µopsont déjà toutes leurs opérandes de disponibles à l'émission, mais doivent quand même être mises en attente, parce que l'ALU adéquate est occupée, parce que des dépendances WAW/WAR sont encore là, ou pour tout autre raison. Dans ce cas, elles sont mises en attente non pas dans le ''scheduler'', mais dans une mémoire FIFO toute simple. L'idée est qu'au lieu d'avoir une énorme mémoire associative pour le ''scheduler'', on déplace quelques entrées dans une petite FIFO annexe. Le résultat est un gain d'énergie et de circuits, au prix d'une perte de performance mineure. La perte de performance en question se manifeste si aucune instruction n'a ses opérandes de prêtes à l'émission : le programme n'utilise pas la FIFO et voit alors un ''scheduler'' plus petite. Une amélioration de cette technique tient compte du fait que certaines instructions sont dans un cas intermédiaire. Elles ont déjà un opérande de prête lors de l'émission, mais pas l'autre. Le nombre d'opérandes varie suivant l’instruction : certaines n'ont besoin que d'un seul opérande. De plus, il arrive qu'une opération tout juste décodée ait déjà un ou plusieurs de ses opérandes de prêts. Cette constatation permet d'éviter d'utiliser des comparateurs pour les opérandes déjà prêts. Par exemple, on peut parfaitement utiliser trois ''scheduler'' : * une pour les instructions dont tous les opérandes sont prêts, mais qui sont quand même mises en attente, sans comparateur ; * une pour les instructions dont un seul opérande manque, qui n'utilise qu'un comparateur par entrée ; * une pour les instructions dont deux opérandes manquent à l'appel, qui utilise deux comparateurs par entrée. C'est beaucoup plus économique que d'utiliser une seule grosse ''scheduler'' qui contiendrait autant d'entrées que les trois précédentes réunies, avec deux comparateurs par entrée. Certains sont même allés plus loin, et ont proposé de supprimer le ''scheduler'' avec deux opérandes par entrée. Les instructions dont deux opérandes sont inconnus au décodage sont stockées dans le ''scheduler'' pour instructions avec un comparateur par entrée. Un circuit de prédiction se charge alors de prédire l'opérande manquant, cette prédiction étant vérifiée plus loin dans le pipeline. Il serait cependant étonnant qu'une telle proposition ait donné lieu à la moindre implémentation réelle. ===Les optimisations de la consommation d'énergie avancées=== D'autres chercheurs ont conservé un ''scheduler'' unique, avec autant de comparateurs par entrée qu'il y a d'opérandes possibles par instruction. Simplement, le processus de détection des opérandes prêts est légèrement ralenti : on ne vérifie qu'un opérande par cycle. Pour vérifier les deux opérandes d'une entrée, on doit attendre deux cycles. Enfin, certains chercheurs ont proposé des ''scheduler'' segmentées. Les instructions circulent à chaque cycle d'un segment vers le suivant : en conséquence, certains segments conservent les instructions les plus anciennes, un autre les instructions les plus jeunes, etc. Seul le denier segment, celui qui contient les instructions les plus vielles, peut émettre une instruction : la détection des opérandes se fait seulement dans le dernier segment, qui contient les instructions les plus anciennes. On économise ainsi beaucoup de comparateurs. Certains chercheurs ont tenté de pipeliner l'étape de sélection des opérandes, ainsi que l'étage d'arbitrage. Mais en faisant cela, il faut plusieurs cycles pour détecter qu'une instruction a ses opérandes prêts, ce qui pose problème face à de nombreuses dépendances RAW. Pour éviter de trop perdre en performances, certains chercheurs ont décidé d'utiliser des techniques pour prédire quelles seront les instructions dont les opérandes seront bientôt prêts. Si détecter qu'une instruction est prête prend n cycles, le processeur devra tenter de prédire la future disponibilité des opérandes n cycles en avance pour obtenir des performances optimales. ===Remplacer la mémoire associative par une RAM=== Une autre optimisation possible est de remplacer le ''scheduler'' par une mémoire RAM, dont chaque mot mémoire correspondrait à une entrée. Une telle optimisation permet en théorie de se passer des comparateurs associés à chaque entrée, mais au prix de l'ajout de circuits annexes potentiellement couteux. La première de ces techniques, la '''recherche directe par étiquette''' (direct tag search) fut créée par Weiss et son collègue Smith. Ils cherchaient à améliorer l'algorithme de Tomasulo, un algorithme qu'on expliquera dans quelques chapitres. Rappelons que chaque instruction produit un résultat, qui devra être rapatrié dans une ou plusieurs entrées de le ''scheduler''. L'optimisation de la recherche directe par étiquette fonctionne dans le cas où le résultat de l'instruction n'est utilisé que par une seule entrée, et pas plusieurs. Le principe est simple : chaque champ « opérande » d'une entrée est adressable via le nom de registre de cet opérande. Pour faire le lien entre entrée et nom de registre, la recherche directe par étiquette ajoute une table de correspondances matérielle, une mémoire RAM qui mémorise les adresses des champs « opérande » des entrées. Les adresses envoyées dans cette mémoire sont les noms de registres des résultats. Lors de l'émission, la table de correspondances est mise à jour. Les numéros des champs « opérande » réservés lors de l'émission sont mémorisés dans les mots mémoire qui correspondent aux deux registres sources. Toutefois, une petite vérification est faite lors de l'émission : s'il y a déjà une correspondance dans la table pour un registre source, alors une autre instruction compte lire ce registre. Pour éviter d'écraser les données de l'instruction précédente dans la table de correspondances, l'émission de l'instruction est bloquée. [[File:Recherche directe par étiquette.png|centre|vignette|upright=2|Recherche directe par étiquette.]] ==Les ''schedulers'' avec préplanification== Avec la '''préplanification''' (''prescheduling''), le ''scheduler'' est composée de mémoires FIFO dans lesquelles les instructions sont triées dans l'ordre d'émission. Il n'y a pas de logique d’émission proprement dite, celle-ci se bornant à vérifier si l'instruction située au début de la FIFO peut s’exécuter. Par contre, le préplanificateur détecte les dépendances et en déduit où insérer les instructions dans le tampon d'émission, à l'endroit le plus adéquat. [[File:Préplanification.jpg|centre|vignette|upright=2|Préplanification.]] ===L'usage de FIFO multiples=== La technique de préplanification la plus simple utilise plusieurs FIFO. Quand une instruction a une dépendance avec une autre instruction, les deux sont placées dans la même FIFO. Pour cela, le préplanificateur détecte les chaines d'instructions dépendantes, et place les instructions dans la FIFO adéquate. A chaque cycle, l'unité d'émission lit une micro-opération dans chaque FIFO et vérifie si elle peut l'émettre. Si la micro-opération n'a pas ses opérandes disponibles, ou qu'une dépendance structurelle survient, alors la FIFO est bloquée. La micro-opération attend que la dépendance soit résolue, bloquant toutes les instructions précédentes. Mais les autres FIFO ne sont pas bloquées, laissant de la marge de manœuvre. [[File:Préplanification par FIFO multiples.png|centre|vignette|upright=1.5|Préplanification par FIFO multiples.]] ===La technique du tampon trié=== La technique du '''tampon trié''' trie les instructions selon le temps d'attente avant leur exécution. Les instructions qui sont censées s’exécuter bientôt sont insérées au tout début de la FIFO, tandis que les instructions qui s’exécuteront dans un long moment sont insérées vers la fin. Là encore, l'unité d'émission lit une micro-opération dans la FIFO, et détermine si elle peut être émise. Si une dépendance survient, l'émission est retardée, et la FIFO est bloquée. [[File:Préplanification par tampon trié.png|centre|vignette|upright=1.5|Préplanification par tampon trié.]] La technique a cependant quelques problèmes assez importants. Le premier problème est que la FIFO est bloquée lorsqu'une micro-opération ne peut être émise. Le second problème est que le temps avant exécution n'est pas toujours connu, notamment pour les instructions d'accès mémoire. Et cela se répercute sur les instructions dépendantes de celles-ci. Pour résoudre ce genre de problèmes, l'usage d'un pipeline à ''replay'' est possible, et est même l'une des meilleures solutions possible, malgré ses défauts. L'idée est que les lectures sont pré-planifiées en supposant qu'elles font un succès de cache L1. Si la prédiction est fausse, la lecture est ré-exécutée plusieurs cycles plus tard, en supposant qu'elle fait un succès dans le cache L2, et ainsi de suite. Elle est alors ré-insérée dans la FIFO, elle est pré-planifiée une seconde fois. Il en est de même si une micro-opération ne peut pas être émise : il suffit de la réinsérer dans la FIFO au bon endroit, en attendant que ses dépendances soient résolues. Ainsi, l'instruction fautive ne bloque pas le ''scheduler'', et retente sa chance autant de fois qu'il le faut. [[File:Préplanification par fenêtre d’instruction scorebarodée.png|centre|vignette|upright=1.5|Préplanification par ''scheduler'' scorebarodé.]] Une autre solution utilise deux ''schedulers'' : une FIFO gérée par la préplanification, et une vraie ''scheduler'' pour les instructions dont le temps d'attente ne peut pas être déterminé. Il est possible de mettre cette dernière avant la préplanification, afin de gérer les temps d'attente des instructions d'accès mémoire. Quand le temps d'attente d'une lecture devient connu, ses instructions dépendantes sont gérées avec préplanification. [[File:Préplanification avec fenêtre d’instruction.png|centre|vignette|upright=2.5|Préplanification avec ''scheduler''.]] ===Les ''scheduler'' avec allocation temporelle statique=== L''''allocation temporelle statique''' correspond à une technique utilisée sur les processeurs Cuzco de l'entreprise Condor. La technique en question a été présenté en 2025, mais des idées similaires ont été présentées dans la littérature académique. Elle ressemble beaucoup aux techniques de pré-planification, avec cependant quelques différences. L'idée est simple : le processeur dispose de plusieurs ''scheduler'', qui mettent en attente les micro-opérations. Lors de l'étape de renommage de registres, le processeur détermine dans combien de cycles d'horloge la micro-opération sera prête pour exécution. La micro-opération est alors mise en attente durant ce nombre de cycles, dans les ''scheduler'', puis est émise une fois ce nombre de cycles écoulés. Ce faisant, les ''scheduler'' n'ont pas besoin de détecter la disponibilité des opérandes à chaque cycle, pour chaque micro-opération en attente. Le ''timing'' de l'émission des micro-opérations est décidé à l'avance. L'implémentation exacte n'est pas connue, mais plusieurs solutions sont imaginables. Par exemple, le ''scheduler'' peut simplement être composée de plusieurs mémoires de petite taille, chacune contenant les micro-opérations destinées à être exécutées dans N cycles, N étant différent pour chaque mémoire. Une autre solution, plus réaliste, utilise un ''scheduler'' dans laquelle la micro-opération est couplée à des champs pour les opérandes, et un champ compteur. Le champ compteur est initialisé avec le nombre de cycles à attendre, et est décrémenté à chaque cycle d'horloge. Quand il atteint zéro, la micro-opération est émise. Vous remarquerez que la méthode ne marche que si toutes les micro-opérations prennent un nombre fixe de cycles d'horloge. Et autant c'est le cas pour les micro-opérations arithmétiques ou logiques, autant les accès mémoire ne rentrent pas dans ce cadre. En théorie, on ne sait pas combien de temps prendra un accès mémoire. Et cette incertitude se répercute sur les instructions dépendantes d'un accès mémoire. Pour éviter cela, le processeur réutilise un pipeline à ''replay'' tel que vu dans le chapitre précédent. L'unité de renommage de registre suppose que tout accès mémoire fait un succès de cache L1, et décide des ''timings'' d'émission sous cette hypothèse. Si une lecture subit un défaut de cache, elle est ré-exécutée, de même que toutes les instructions dépendantes. Pour cela, le registre de destination de la lecture est marqué comme invalide, grâce à un bit spécifique attaché au registre. Toute instruction qui lit un opérande invalide est elle aussi ré-executée de zéro. Pour simplifier, l'unité d'émission ressemble à une unité d'émission dans l'ordre, avec un registre de disponibilité, qu'on aurait amélioré pour aller au-delà de la simple détection des dépendances d'instruction. Pour déterminer les ''timings'' d'émission, à savoir quand émettre une micro-opération, le processeur utilise une unité d'émission à deux étages. Le premier étage est appelé le ''register scoreboard'', le second étage est appelé la ''Time Ressource Matrix''. Les deux étages communiquent entre eux, comme on va le voir, et leurs noms donnent une idée de ce qu'ils font. Le premier étage gère les dépendances de registres, le second gère les dépendances structurelles. Le premier étage est un registre de disponibilité amélioré, qui gère les dépendances de registre. Cet étage sait quand tel registre sera écrit, et donc que l'opérande écrit dedans sera disponible à partir de tel cycle d'horloge. Il le sait car l'étage suivant l'aura prévenu, mais laissons cela de côté pour le moment. Quand une micro-opération rentre dans cet étage, il vérifie les dépendances avec les registres et les micro-opérations antérieures. Vu qu'il sait quand les registres seront disponibles, il peut déterminer quand l'instruction pourra s'exécuter. Par exemple, si une micro-opération lit les deux registres R7 et R15, qui sont disponibles respectivement dans 5 et 7 cycles, le premier étage sait que la micro-opération devra attendre 7 cycles. Mais tout cela ne suffit pas à déterminer quand émettre une micro-opération. En effet, il fait aussi gérer les dépendances structurelles, ce qui est le boulot du second étage. Le second étage utilise pour cela une ''Time Ressource Matrix'', qui mémorise l'occupation de diverses "ressources", pour les 256 cycles d'horloge à venir. Les ressources en question sont les ports de lecture/écriture du banc de registre, les ALUs utilisées, si la micro-opération utilise l'unité mémoire, etc. Le second étage prend en entrée une micro-opération, détermine quelles "ressources" elle utilise, puis regarde leur disponibilité. Elle détecte alors les dépendances structurelles et détermine alors quand peut s'exécuter la micro-opération. Elle peut retarder l'émission de quelques cycles, si une dépendance structurelle est détectée. Une fois sortie du second étage, on sait quand la micro-opération va être émise, à quel cycle précisément. Et vu que la durée de l'instruction est fixe, on sait quand cette micro-opération va se terminer, quand son résultat sera disponible. Cela permet de mettre à jour la ''Time Ressource Matrix'', pour préciser que le port d'écriture sera occupé à tel moment. De plus, cette information est transmise au premier étage, qui sait alors quand est enregistré le résultat dans le registre de destination. C'est comme cela que le premier étage sait quand un registre est disponible : le second étage le prévient, quand il émet une instruction ! La ''Time Ressource Matrix''mémorise l'occupation des "ressources" pour les 256 cycles d'horloge à venir. Cependant, elle ne vérifie pas les dépendances pour les 256 cycles suivants. Quand elle reçoit une micro-opération, elle teste les dépendances structurelles pour seulement les 8 prochains cycles maximum. Si la micro-opération ne peut pas être émise pendant ces 8 cycles, le pipeline est bloqué, un ''pipeline stall'' est émis. Pour être plus précis, vu que le processeur peut décoder 8 micro-opérations en même temps, cela permet de ne consulter que 64 cycles d'horloge sur les 256. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les premiers processeurs Intel | prevText=Les premiers processeurs Intel | next=Le renommage de registres | nextText=Le renommage de registres }} </noinclude> d9etxzw1egkd98mesri9e3bv8pc1fep 773684 773683 2026-09-29T23:18:01Z Mewtow 31375 773684 wikitext text/x-wiki Dans les chapitres précédents, nous avons parlé des techniques dites d''''émission dans l'ordre'''. L'idée est d’exécuter une nouvelle micro-opération à chaque cycle, dans des unités de calcul séparées. Les instructions sont émises consécutivement, mais les instructions s’exécutent en parallèle dans des unités de calcul séparées. Par contre, quand l'unité d'émission ne peut pas émettre une instruction, elle bloque tout le pipeline. Les instructions qui suivent sont elles aussi bloquées, elles doivent attendre leur tour, même si elles sont en capacité de s'exécuter. Les techniques d'exécution dans le désordre que nous allons voir dans ce chapitre corrigent ce point précis. Elles sont dites à '''émission dans le désordre'''. Elles se distinguent des précédentes sur un point précis : quand l'unité d'émission bloque l'émission d'une instruction, les instructions suivantes peuvent poursuivre. L'émission des instructions peut donc se faire dans le désordre, dans le sens où une instruction peut être émise alors qu'une instruction précédente ne l'est pas encore. Mais avant de poursuivre, quelques point niveaux terminologie : * L'émission dans le désordre est un terme parlant et assez précis. Malheureusement, la terminologie la plus utilisée par d''''exécution dans le désordre'''. Et nous utiliserons ce terme dans la suite du cours, histoire de ne pas trop dévier de la nomenclature habituelle. * Nous utiliserons parfois l'abréviation OOO pour parler d'exécution dans le désordre. L'abréviation est celle de ''Out Of Order Execution''. * Nous utiliserons aussi l'abréviation ''µop'' pour parler de micro-opération, ''µops'' au pluriel pour parler de plusieurs micro-opérations, ou des micro-opérations en général. L'exécution dans le désordre ne gère en effet que des µops, elle se situe après l'étape de décodage. Pour décrire comment est implémentée l'émission dans le désordre, il faut commencer par parler des processeurs sans. Les processeurs sans exécution dans le désordre ont une unité d'émission qui bloque tout le pipeline dès qu'une µop ne peut pas être émise. Pour limiter l'impact de ce blocage, quelques rares processeurs incorporent une '''file de micro-opération''', une mémoire FIFO qui met en attente les µops. Vu que c'est une mémoire FIFO, les µops sont émises dans l'ordre, à savoir l'ordre d'ajout, dans l'ordre de décodage. Le schéma ci-dessous illustre une telle file d'attente couplée à un ''scoreboard''. L'exécution dans le désordre améliore la file de µops sur un point : ce n'est plus une mémoire FIFO. Les µops sont insérées dans l'ordre, mais peuvent sortir dans le désordre (être émises dans le désordre). La file de µops devient alors un '''''scheduler''''', terme anglais que je ne compte pas traduire. Un terme équivalent est '''''scheduler''''', terme traduit directement de l'anglais ''instruction Window''. Terme assez trompeur, car elles mettent en attente des µops, pas des instructions. [[File:Différence file µops et fenêtres instruction.png|centre|vignette|upright=2|Différence file µops et ''schedulers'' ]] Le ''scheduler'' émet une µop dès que ses opérandes sont disponibles. Par disponible, on veut dire présent soit dans le réseau de contournement, soit dans les registres. Le ''scheduler'' détecte automatiquement quand les opérandes d'une µop sont disponibles, grâce à une unité d'émission intégrée. L'unité d'émission et la file d'attente de µops sont fusionnés ensemble, dans un seul circuit, mais nous allons dire qu'ils sont conceptuellement séparés pour le moment. À chaque cycle, l'unité d'émission consulte les µops en attente pour détecter lesquelles peuvent s'exécuter. Le ''scheduler'' est spécialement être conçue pour, c'est une sorte de mémoire associative très complexe, comme on le verra dans ce qui suit. [[File:OOO Issue.png|centre|vignette|upright=2.5|Exécution dans le désordre avec un ''scheduler'']] Une fois qu'une µop sort du décodeur d'instructions, elle est ajoutée en parallèle dans le ''scheduler'' et le ROB. La raison est que les µops quittent le ''scheduler'' dans le désordre, et qu'elles doivent être remises en ordre par la suite. Le ROB s'occupe de cette remise en ordre, mais il a besoin de savoir dans quel ordre les µops sont censées être, et cet ordre est celui du décodage. Aussi, pour remplir le ROB, la seule opportunité est en sortie de l'unité de décodage. Dans le cas où une instruction est décodée en plusieurs micro-opérations, elles sont toutes insérées en même temps dans le ''scheduler'' et le ROB, en tenant compte de leur ordre. L'implémentation la plus "simple" de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Les µops décodées sont accumulées dans le ''scheduler'', où elles attendent leur tour. Bien que simple en apparence, cette implémentation cache une complexité très importante, liée aux accès mémoire. Les micro-opérations mémoire sont à part des autres, pour ce qui est de leurs dépendances de données. Non seulement elles ont des dépendances de registre, mais elles sont aussi des dépendances d'adresse. Par exemple, deux écritures peuvent utiliser deux registres d'adresse différents, mais ceux-ci peuvent contenir la même adresse. Et autant on peut détecter les dépendances de registre lors de l'émission, autant c'est plus compliqué avec les dépendances d'adresse. De plus, rappelons que si les lectures peuvent s'exécuter dans le désordre, les écritures doivent s'exécuter dans l'ordre, ou du moins en donner l'illusion. Pour cela, le processeur remet les écritures dans l'ordre avec une sorte de mini-ROB intégré à l'unité mémoire, appelée la file d'écriture. Elle complémente le ROB, qui lui ne gère que les écritures dans les registres, mais les deux collaborent. La file d'écriture envoie une écriture à la mémoire RAM quand le ROB lui dit que c'est bon, les instructions précédentes sont terminées ''dans l'ordre du programme''. Les processeurs modernes ajoutent des techniques d'exécution dans le désordre des accès mémoire, mais nous les verrons dans un chapitre dédié. Elles permettent d'utiliser un ''scheduler'' unique, qui mémorise aussi les µops mémoire. Si elles sont mises en place, l'unité mémoire n'a pas besoin de file de µops séparée. Les dépendances de registre sont traitées par le ''scheduler'', alors que les dépendances d'adresse sont gérées par l'unité mémoire gére les dépendances d'adresse. Elle utilise pour cela des techniques de '''''désambiguïsation mémoire''''', qui auront droit à un chapitre dédié. [[File:Processeur avec exécution dans le désodre des accès mémoire.png|centre|vignette|upright=2|Processeur avec exécution dans le désodre des accès mémoire]] Les processeurs assez anciens n'autorisaient pas d'exécution dans le désordre des accès mémoire. Concrètement, les accès mémoire devaient se faire dans l'ordre, mais les autres µops pouvaient être exécutées dans le désordre. Pour garantir l'ordre des µops mémoire, les µops mémoire ne passent pas par le ''scheduler'', mais sont accumulées dans une file de micro-opérations séparée. Après le décodage, les µops sont réparties soit dans la file de µops mémoire, soit dans le ''scheduler''. Le décodeur classe les µops suivant que ce sont des µops mémoire ou non, et les envoient à la bonne destination. Dans ce chapitre, on supposera que c'est cette solution qui est utilisée. [[File:Processeur avec émission dans l'ordre des accès mémoire.png|centre|vignette|upright=2|Processeur avec émission dans l'ordre des accès mémoire]] ==L'implémentation d'un ''scheduler'' : généralités== Un ''scheduler'' est une mémoire qui mémorise des micro-opérations. Elle est cependant plus complexe qu'une mémoire RAM ou qu'une FIFO et ressemble un petit peu à une mémoire cache. Elle dispose d'un port d'écriture et d'un port de lecture, au minimum. Le port d'écriture permet à l'unité de décodage d'insérer une micro-opération dedans, d'ajouter la micro-opération qui vient d'être décodée. Si une instruction machine est décodée en plusieurs micro-opération, deux possibilités. La première est de les insérer un par un, ce qui fait qu'on peut se contenter d'un seul port d'écriture. L'autre possibilité est de les ajouter en même temps, ce qui demande plusieurs ports d'écriture. Le port de lecture sert à émettre une instruction. On part du principe que le ''scheduler'' ne peut émettre qu'une seule instruction à la fois, car les processeurs que nous avons vu précédemment sont de ce type. Mais nous verrons dans quelques chapitres qu'il existe des processeurs dits superscalaires, qui sont capables d'émettre plusieurs instructions par cycle. Dans ce cas, le ''scheduler'' a un seul port de lecture. Un processeur superscalaire, quant à lui, doit avoir un port de lecture par unité de calcul, ce qui fait beaucoup plus. Les ''schedulers'' sont composées d''''entrées''', des mots mémoire qui stockent une instruction. Une instruction réserve une entrée après son décodage et la libère dès qu'elle est envoyée aux unités de calcul. Une entrée contient l'opcode (les signaux de commande à envoyer à l'ALU), le registre de destination du résultat, les registres de chaque opérande, et éventuellement des signaux de commande en plus. De plus, chaque opérande est couplée à un bit de disponibilité, qui indique si elle est disponible. Quand un opérande est écrit dans les registres, le bit de présence correspondant est mis à jour. Enfin, chaque entrée possède un bit ''empty'' qui indique si elle est vide, cette information étant utile pour réserver des entrées. [[File:Entrée d'une station de réservation - sans les tags.png|centre|vignette|upright=3|Entrée d'un ''scheduler'']] ===Les stations de réservation=== Les '''stations de réservation''' sont des ''scheduler'' particulières, qui sont capables de mémoriser les opérandes des instructions. Les entrées des stations de réservation sont identiques à celle des autres ''scheduler'', si ce n'est que les opérandes de l'instruction sont enregistrés directement dans des champs séparés. Il y a deux champs, un par opérande, pour stocker l'opérande elle-même, lue depuis les registres ou obtenue via le réseau de contournement. Notons que les champs pour les opérandes viennent en plus des champs pour les noms de registres, encore que les deux peuvent être fusionnés si on veut optimiser le tout. [[File:Entrée d'une station de réservation.png|centre|vignette|upright=3|Entrée d'une station de réservation.]] Précisons que la terminologie n'est pas très fiable. Les termes "''scheduler''" et "station de réservation" ne regroupent pas du tout la même chose d'un papier de recherche à l'autre, d'un bouquin à l'autre, d'un chercheur à l'autre, d'un ingénieur à l'autre, d'un professeur à l'autre. Le terme initial vient pourtant de l'article original sur l'algorithme de Tomasulo, où il désignait un ''scheduler'' associée à une unité de calcul précise. Mais le terme a ensuite été réutilisé, ce qui fait que certains processeurs avec plusieurs unités de calcul sont décrits comme ayant une unique station de réservation. En bref : c'est le bazar ! Mais nous en reparlerons dans le chapitre sur le renommage de registres, car c'est la place idéale pour les aborder. Toujours est-il que j'ai fait le choix de confondre les concepts de ''scheduler'' et de station de réservation avec les concepts de '''lecture avant émission''' et de '''lecture après émission'''. La différence entre les deux est que les registres sont lus après émission avec un ''scheduler'', avant avec des stations de réservation. Dans le cas "avant émission", les opérandes sont mémorisés dans la station de réservation. Et cette différence a une influence sur le pipeline du processeur, le banc de registres et tout ce qui s'ensuit. Un désavantage de la lecture avant émission est qu'il faut stocker les opérandes après lecture, ici dans les stations de réservation. Mais un avantage est que le banc de registre a besoin de moins de ports de lecture, car une bonne partie des opérandes sont fournies par le système de contournement. Nous verrons cela dans le détail dans le chapitre sur les processeurs superscalaires. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Lecture après émission.]] [[File:Read Before Issue.png|centre|vignette|upright=2.5|Lecture avant émission.]] ===La logique d'éveil et de sélection=== Dans le cas qui va suivre, on suppose que le processeur ne peut émettre qu'une instruction à la fois. Chaque cycle, une instruction est sélectionnée et est envoyée dans le chemin de données, soit à une ALU, soit à une unité d'accès mémoire. La sélection d'une instruction est effectuée par l'unité d'émission, qui est aussi appelée le '''''scheduler'''''. Elle gère la disponibilité des opérandes et la disponibilité des unités de calcul adéquate. Le choix de l'instruction émise doit être le plus pertinent possible, pour des raisons de performances. Pour le premier point, l'unité d'émission détermine quelles instructions sont candidates pour l'émission. Les ''instructions candidates'' sont celles dont tous les opérandes sont prêts. Le processeur contient un circuit qui détecte les instructions candidates : la '''logique d’éveil''' (''wake-up logic''). Une fois que la logique d'éveil a fait son travail, une instruction est choisie pour s’exécuter en fonction de la disponibilité des unités de calcul adéquates. Ce rôle est dévolu à un circuit qu'on appelle la '''logique de sélection''', ou ''select logic''. [[File:Fonctionnement complet de la logique d’émission.jpg|centre|vignette|upright=1.5|Fonctionnement complet de la logique d’émission.]] La logique de sélection doit gérer le fait que les unités de calcul du processeur ne sont pas toutes identiques. Déjà, un processeur a généralement des unités séparées pour les instructions entières et flottantes, des unités spécialisées dans les accès mémoire, parfois des unités spécialisées pour les branchements. Une instruction doit être attribuée à la bonne unité de calcul, on ne doit pas envoyer une instruction entière dans une unité de calcul flottante. De plus, parmi les unités de calcul entières, toutes ne sont pas identiques. Par exemple, il est fréquent d'avoir plusieurs unités de calcul spécialisées dans les opérations simples (additions, soustractions, opérations logiques) avec une unité pour les multiplications/divisions séparées, parfois une unité spécialisée pour les décalages/rotations, etc. Là encore, allouer la bonne instruction à la bonne ALU est complexe. Plus les unités de calcul sont hétérogènes, plus la logique de sélection est compliquée. Les logiques d'éveil comme de sélection sont assez complexes. Comme on le verra plus bas, la logique de sélection la plus simple, qui gère une seule unité de calcul, est basée sur un encodeur à priorité, couplé à d'autres circuits. Et pour gérer plusieurs ALUs, il faut mettre des encodeurs en cascade. Le résultat est que même en prenant une logique de sélection simple, elle sera assez lente et gourmande en circuits. Aussi, la logique de sélection met souvent un cycle d'horloge entier pour faire son travail, elle a son propre étage de pipeline attribué. La logique d'éveil est dans le même cas, ce qui fait qu'émettre une micro-opération demande deux cycles d'horloge. Le défaut est que cela rajoute des cycles d'horloges entre le ''scheduler'' et l'ALU, ce qui complique la gestion du pipeline. Ces cycles de retard sont à prendre en compte au moment d'émettre les instructions, les ''scheduler'' doit en tenir compte pour des performances optimales. Sans tenir compte de ces cycles de retard, les instructions arrivent en retard de quelques cycles à l'ALU, cycles de retard durant lesquels l'ALU n'a pas fait de calcul et a été sous-utilisée, sans compter que le système de contournement n'est pas utilisé au mieux. Et le problème est encore plus important sur les processeurs avec des stations de réservation, qui utilisent la "lecture après émission" : cela rajoute un cycle d'horloge en plus, un temps de retard en plus. ===La logique d'éveil : l'émission anticipée=== La logique d'éveil doit tenir compte du fait qu'il y a plusieurs étages entre l'émission et l'exécution sur une unité de calcul. Par exemple, un processeur a souvent entre un et à cinq étages entre la file d'attente et les unités de calcul. Il faut lire les registres, gérer le contournement, et cela peut prendre quelques cycles d'horloge. Sur le Pentium 4, on trouve 6 étages entre le ''scheduler'' et l'entrée de l'ALU. Si les micro-opérations sont émises quand les opérandes sont disponibles, il y aura un délai de quelques cycles avant qu'elles atteignent l'ALU. Alors qu'idéalement, on souhaiterait que la micro-opération atteigne l'ALU dès que ses opérandes sont disponibles, pour profiter des techniques de contournement. Pour cela, la logique d'éveil émet les instructions quelques cycles en avance pour qu'elles arrivent au bon moment. Il s'agit d'une technique d''''émission anticipée''', dont nous avions parlé dans le chapitre sur le contournement. : Il faut noter que le problème se pose plus avec des ''schedulers'' qu'avec des stations de réservation. Les premières ont un étage en plus entre émission et ALU, vu qu'il faut lire des registres après l'émission. L'émission anticipée demande d'émettre un signal d'éveil en avance de quelques cycles, pile au bon moment. Par exemples, si on a deux étages entre l'ALU et l'unité d'émission, le signal de réveil sera généré deux cycles avant que le résultat soit effectivement calculé. L'implémentation varie, mais deux solutions sont possibles. La première est de générer le signal d'éveil dans l'ALU, ce qui n'a de sens que pour les opérations comme les multiplications ou les divisions, qui prennent plusieurs cycles. Une autre technique génère le signal de réveil dans une structure centralisée, spécialisée dans la génération des signaux d'éveil. L'unité de composée d'un registre à décalage par registre. Imaginons qu'une instruction est émise, que cette instruction mette N cycles à s'exécuter, et qu'elle écrive dans un registre de destination. L'unité sélectionne alors le registre à décalage associé au registre de destination, et met le bit numéro N à 1. Le registre décalé d'un cran à chaque cycle. Quand le bit sortant est un 1, alors le signal de validité pour l'opérande est généré. L'émission anticipée marche bien si l'instruction a une durée fixe, connue à l'avance. Et autant c'est le cas pour les instructions arithmétiques et logiques, autant ce n'est pas le cas pour les accès mémoire. Les accès mémoire ont une latence variable : quelques cycles pour un succès de cache, plusieurs dizaines de cycles pour un défaut de cache L1, pas loin de la centaine pour un défaut de cache L2, etc. Et cela pose des problèmes pour l'émission anticipée. L'émission en avance pour les accès mémoire est purement spéculative : le processeur émet des instructions en supposant que la lecture entrainera un succès de cache, quitte à annuler l'instruction en cas de défaut de cache. Mais faire ainsi demande non seulement d'annuler les instructions émises en avance, mais aussi de ne pas retirer les instructions émises en avance de le ''scheduler''. Elles sont émises, mais une copie de sauvegarde est conservée dans le ''scheduler''. Si le processeur détecte un défaut de cache, il peut alors ré-exécuter l'instruction. S'il détecte un succès de cache, les instructions lecture-dépendante sont retirées de le ''scheduler'', la copie de sauvegarde est devenue inutile et est donc jetée. ===La logique de sélection : âge ou position ?=== La logique de sélection est primordiale pour de bonnes performances. Il existe deux méthodes principales pour sélectionner l'instruction à exécuter. La première est la plus simple : elle se base sur lé numéro de l'entrée. En effet, un ''scheduler'' est avant tout une sorte de mémoire, un mix entre mémoire associative, mémoire RAM, et FIFO. Et chaque entrée a un numéro, une adresse mémoire. Nous parlerons de numéro dans ce qui suit, car ce sera plus simple, le terme d'adresse mémoire étant peut-être un peu exagéré dans le contexte des ''scheduler''. Toujours est-il que le ''scheduler'' est adressable dans le sens où on peut lui envoyer le numéro de l'entrée voulue, et le ''scheduler'' renvoie le contenu de l'entrée sur son port de lecture. Et c'est ce que fait la logique de sélection : elle génère le numéro de l'entrée à lire. Le numéro est alors envoyé sur l'entrée d'adresse du ''scheduler'', et elle fournit la micro-opération associée sur son port de lecture, son '''port d'émission'''. La première méthode de sélection, donc. Elle est basée sur le numéro de l'entrée. Si plusieurs entrées sont éveillées, la logique de sélection prend celle avec le plus petit numéro. Elle porte le nom de '''sélection par position''', sous-entendu position dans le ''scheduler''. Vous l'avez peut-être deviné, mais la logique de sélection est alors un encodeur à priorité. Le circuit de sélection ne se résume donc pas seulement à un encodeur à priorité, mais c'est le circuit central. L'avantage d'une telle méthode de sélection est qu'elle est simple à implémenter : un encodeur à priorité est un circuit connu, facile à implémenter. Mais on remarque un défaut : un encodeur est un circuit assez rapide, mais qui utilise beaucoup de transistors, beaucoup de portes logiques, surtout si on veut qu'il soit rapide. Ce qui explique que la logique de sélection ait son propre étage de pipeline rien que pour elle. La seconde méthode s'appelle la '''sélection par âge''', au nom assez transparent. L'idée est de privilégier l'émission de l'instruction la plus ancienne. Elle demande que le ''scheduler'' trie les micro-opérations par ordre d'insertion dans le ''scheduler'', ce qui en fait une pseudo-FIFO. Le tri est partiel, car les instructions peuvent sortir du ''scheduler'' à tout moment. Compacter le ''scheduler'', à savoir regrouper toutes les entrées valides est une idée, mais elle est compliquée à implémenter. Aussi, elles préfèrent encoder des informations sur l'ordre d'émission dans chaque entrée. L'encodeur à priorité doit alors travailler non pas sur des nombres entiers liés à l'ordre d'insertion dans la pseudo-FIFO. Elle est encore plus gourmande en circuits que la méthode précédente. Les processeurs haute performance utilisent souvent des méthodes hybrides. Par exemple, les processeurs AMD de microarchitecture Bulldozer utilisaient une méthode intermédiaire. Ils utilisaient un ''scheduler'' couplée à un encodeur à priorité pour la sélection par position, mais complémentaient le tout avec une unité qui mémorisait l'instruction la plus ancienne dans le ''scheduler''. Le mécanisme de sélection par âge était utilisé en priorité. Mais si l'instruction la plus ancienne n'était pas prête, le processeur basculait sur le mécanisme de sélection par position. ===La compaction des ''scheduler''=== À chaque cycle, les instructions décodées sont ajoutées dans le ''scheduler'', dans des entrées vides. Vu que les instructions quittent celle-ci dans le désordre, ces vides sont dispersés dans le ''scheduler'', ce qui pose problème pour déterminer où placer les nouvelles instructions. La solution la plus triviale consiste à conserver une liste des vides, mise à jour à chaque insertion ou émission d'instruction. Une autre solution consiste à éliminer les vides en compactant le ''scheduler'' à chaque cycle d'horloge. Des circuits se chargent de détecter les vides et de regrouper les instructions en un unique bloc. Il faut signaler que certains processeurs arrivent à se passer de cette étape de compactage, mais au prix de ''scheduler'' nettement plus complexes. Autre problème : quand il faut choisir quelle instruction émettre, il y a toujours plusieurs candidats. Si on choisit mal, des instructions restent en attente trop longtemps parce que d'autres instructions plus jeunes leur passent devant. Pour éviter cela, les instructions les plus vielles, les plus anciennes, sont prioritaires. Pour cela, on peut utiliser une FIFO un peu spéciale pour le ''scheduler''. Si les ajouts d'instruction se font dans l'ordre, les instructions ne quittent pas forcément le ''scheduler'' dans l'ordre imposé par une FIFO : les instructions restent triées dans leur ordre d'ajout, même s'il y a des vides entre elles. Dans ces conditions, il est préférable que le compactage conserve l'ordre FIFO des instructions. Dans ces conditions, l'instruction la plus ancienne est celle qui est située à l'adresse la plus faible : le circuit de sélection peut donc être fabriqué avec des encodeurs, et est relativement simple. ==Les ''schedulers'' basées sur une matrice de dépendances== L'implémentation la plus simple étend le fonctionnement d'un pipeline dynamique usuel. Rappelez-vous le chapitre sur les pipelines dynamiques. Nous avions vu que de tels pipelines émettaient une instruction par cycle, quitte à émettre des bulles de pipeline en cas de dépendance bloquante. Et il est possible d'améliorer leur unité d'émission pour qu'elle soit compatible avec l'exécution dans le désordre. ===Rappels sur le registre de réservation/disponibilité=== L'émission d'une instruction est gouvernée par un ''registre de réservation'' qui indique quels registres sont réservés par une instruction, et ceux qui sont libres. Un registre réservé est un registre qui sera écrit par une instruction en cours d'exécution, mais qui n'a pas encore écrit son résultat. Les instructions candidates doivent avoir leurs opérandes dans des registres libres. Sinon, c'est signe que leurs opérandes sont réservés en écriture, donc pas encore écrites, donc pas disponibles. Si une instruction candidate veut lire ce registre, c'est signe qu'il y a une dépendance RAW : elle veut lire un registre réservé, qui est destiné à être écrit par une instruction en vol. Si elle veut écrire, c'est signe qu'elle veut écrire dans un registre où une autre instruction veut écrire : c'est une dépendance WAW. Dans les deux cas, l'instruction n'est pas émise. Le registre de réservation encode les registres réservés comme suit : chaque bit est associé à un registre. Le bit numéro 0 est associé au registre numéro 0, le bit numéro 1 au registre numéro 1, etc. Là, En clair, les numéros de registres réservés sont encodés en représentation non pas binaire, mais en représentation ''one-hot'' (vue au premier chapitre). {|class="wikitable" |+ Registre de réservation |- ! Registre 7 !! Registre 6 !! Registre 5 !! Registre 4 !! Registre 3 !! Registre 2 !! Registre 1 !! Registre 0 |- | 0 || 0 || 1 || 0 || 0 || 1 || 0 || 0 |} Avant d'émettre une instruction, l'unité d'émission extrait les registres opérande/destination et les convertis dans la même représentation que le registre de réservation, à savoir en représentation ''one-hot''. Le circuit de traduction binaire vers ''one-hot'' est, pour rappel, un simple décodeur. Puis, on fait un OU logique entre les sorties des décodeurs. Le résultat est un masque qui indique quels registres sont lus par l'instruction, encodé en représentation ''one-hot''. Appelons-le le '''masque d'opérandes'''. Le masque est alors comparé au registre de réservation pour vérifier si l'instruction peut être émise. [[File:Unité d'émission simple, dans l'ordre.png|centre|vignette|upright=2|Unité d'émission simple, dans l'ordre]] Si l'émission est autorisée, le registre de réservation est là aussi mis à jour. Le registre de réservation est aussi mis à jour dès qu'une instruction enregistre son résultat dans les registres, ou alors dès qu'il est disponible pour le contournement. Le bit associé au registre repasse alors à 0 (ou à 1). Sans contournement, la mise à jour se fait alors à la toute fin de l'instruction, quand elle se termine, lors de la dernière étape d'enregistrement, à la fin de son pipeline. Avec, elle se fait quand l'instruction quitte l'unité de calcul. ===L'extension à l'exécution dans le désordre : l'éveil par matrice de bits=== La différence entre un pipeline dynamique et l'exécution dans le désordre est que l'on passe d'une instruction à émettre à plusieurs. Plusieurs instructions sont mises en attente dans un ''scheduler'', et y attendent leur tour. L'idée est alors d'envoyer le registre de disponibilité à toutes les entrées, à toutes les instructions en attente. Ainsi, on sait quelles sont les instructions qui peuvent s'exécuter et celles qui ne le peuvent pas. L'implémentation est assez simple, elle ressemble beaucoup à l'implémentation d'un pipeline dynamique simple, si ce n'est que des circuits sont dupliqués. L'implémentation utilise des ''scheduler'' légèrement différentes de celles introduites plus haut. Elles n'utilisent notamment pas de bits de disponibilité, mais autre chose. Lorsqu'une instruction est ajoutée à le ''scheduler'', le masque de disponibilité des opérandes est stocké dans le ''scheduler''. A chaque cycle, le registre de disponibilité est envoyé à toutes les entrées, et est comparé avec tous les masques de disponibilité des opérandes. Si une comparaison renvoie un 1, alors l'instruction de l'entrée est une instruction candidate à l'émission. [[File:Unité d'émission dans le désordre basée sur un registre de disponibilité.png|centre|vignette|upright=2.5|Unité d'émission dans le désordre basée sur un registre de disponibilité]] L'ensemble est implémenté avec l'aide d'une '''matrice de bits''', où chaque ligne correspond à une entrée et chaque colonne à un registre. À chaque croisement entre une ligne et une colonne, on trouve un bit. Si le bit de la ligne n et de la colonne m est à 1, cela veut dire : l'instruction dans l'entrée n a besoin de lire le registre m. S’il est à 0, alors cela veut dire que l'instruction stockée dans la ligne n'a pas besoin de la donnée dans le registre m. [[File:Planificateur à matrice de bits.jpg|centre|vignette|upright=2|Planificateur à matrice de bits.]] Lorsqu'une instruction réserve une entrée, elle initialise la ligne en fonction des registres qu'elle souhaite lire. Pour vérifier si une instruction a ses opérandes prêts, le processeur compare le registre de disponibilité à la ligne associée à l'instruction/entrée. A chaque intersection ligne-colonne, se trouve un comparateur de 1 bit, qui détecte si le registre est demandé et disponible. Les résultats de cette porte sont ensuite envoyés à une porte ET, qui fait le gros du travail. [[File:Logique de détection de la disponibilité d'une instruction.jpg|centre|vignette|upright=2|Logique de détection de la disponibilité d'une instruction.]] ==Les ''schedulers'' basées sur une mémoire associative== Les processeurs modernes utilisent une mémoire associative pour le ''scheduler''. Les mémoires associatives ont été abordées il y a quelques chapitres, mais faisons quelques rappels. Les mémoires associatives servent à accélérer la recherche de données dans un ensemble. Or, un ''scheduler'' vérifie régulièrement si chaque entrée est prête. Il s'agit d'un processus de recherche d'une instruction qui respecte une condition bien précise dans la mémoire, ce qui fait que les mémoires associatives sont donc tout indiquées. Comme vous le savez, les signaux de commande d'une instruction sont propagés avec celle-ci dans le pipeline, le nom du registre de destination ne faisant pas exception. Le nom de registre est envoyé à le ''scheduler'' lors de l'écriture du résultat dans les registres. S'il y a correspondance, l'opérande est disponible et son bit de disponibilité est mis à 1. On peut adapter cette méthode pour tenir compte du contournement assez simplement. [[File:Détection des dépendances par propagation du registre de destination.png|centre|vignette|upright=2|Détection des dépendances par propagation du registre de destination.]] En conséquence, le circuit de détection des dépendances est constitué d'un grand nombre de comparateurs : un par champ « nom de registre » dans chaque entrée. La logique d'éveil/''wake up'' regroupe tous les comparateurs, la logique de sélection est un circuit situé en-dehors de la mémoire associative. Les entrées sont dans la mémoire associative elle-même. [[File:Gestion des bits de validité.png|centre|vignette|upright=2|Gestion des bits de validité.]] L'implémentation la plus simple est celle du schéma précédent, où on utilise une mémoire associative unique. Une version plus élaborée sépare le ''scheduler'' en deux parties : une mémoire qui mémorise les registres des opérandes, une autre mémoire pour le reste. La mémoire pour les registres opérandes est la mémoire associative proprement dite, c'est elle qui est associée aux comparateurs, à la logique de ''wake-up''/réveil, etc. Par contre, l'autre mémoire est une mémoire RAM simplifiée, qui mémorise les informations qui n'ont pas besoin des comparateurs. L'opcode de l'instruction est là-dedans, par exemple. le ''scheduler'' est donc une sorte de mémoire associative améliorée. Il se trouve que c'est aussi le cas du ROB. Et il est possible de fusionner le tampon de ré-ordonnancement avec le ''scheduler'' dans une structure unique. La différence avec un ''scheduler'' normal est que les entrées sont libérées non pas quand l'instruction est exécutée/émise, mais quand elle termine son exécution et quitte le ROB. le ''scheduler'' incorpore des bits dans chaque entrée, pour savoir si la µops associée a été émise et est en cours de traitement dans les ALUs. La méthode a notamment été utilisée sur les processeurs d'architecture K6 d'AMD. Le tout donnait une structure appelée le '''DRIS''' (''deferred scheduling register renaming instruction shelf''). Les processeurs PA 8000 de HP étaient aussi vraisemblabment dans ce cas, aussi. ===Les optimisations de la consommation d'énergie : la désactivation des portions inutilisées=== Le problème avec des ''scheduler'' de ce type est leur forte consommation énergétique, ainsi que le grand nombre de portes logiques utilisées, qui deviennent prohibitifs pour des ''scheduler'' un peu grosses. Pour résoudre ce problème, certains ont optimisé les comparateurs. D'autres ont tenté de profiter du fait que la majorité des bits dans les entrées sont composés de zéros. Bref, les optimisations purement matérielles sont légion. Une première solution est de désactiver les entrées qui sont inutilisées, vides, sans instruction. Pour cela, on fait précéder les comparateurs par un circuit qui les connecte ou déconnecte des lignes de bit. Le circuit est commandé par le bit ''empty'' qui indique si une entrée est vide ou non. L'avantage est que la consommation d'énergie de le ''scheduler'' devient alors proportionnelle au nombre d'entrées non-vides, et non au nombre d'entrées total. Du moins, en apparence, les entrées non-utilisées doivent quand même être alimentées pour fonctionner, mais l'activité de comparaison disparait dans les entrées vides. Il est possible d'étendre cette technique aux entrées dont les opérandes sont prêts. Les gains sont généralement assez bons, avec une réduction de consommation variant entre 30 et 50%, avec une implémentation très simple et très économe en circuits. Une autre solution, assez simple à mettre en place, consiste à désactiver une partie de le ''scheduler'' sin elle est inutilisée. Pour cela, il faut segmenter le ''scheduler'' avec la technique du ''wire partitionning''. Pour rappel, un ''scheduler'' est une mémoire associative. Et comme toute mémoire associative, elle contient des fils, les lignes de bit, qui relient les entrées/sorties à toutes les cellules mémoire. Plus une ligne de bit est longue, plus elle consomme d'énergie et plus le temps de lecture/écriture est long. L'idée est de segmenter les lignes de bits en plaçant des répéteurs qui recopient la tension d'un segment au suivant. Les répéteurs sont des tampons trois-états, ce qui permet de déconnecter les portions inutilisées de la ligne de bit. Ce faisant, le ''scheduler'' est découpée en segments, qui peuvent être désactivés si besoin. S'il y a peu d'instructions chargées dans le ''scheduler'', les portions inutilisées sont désactivées. La technique marche d'autan mieux si les instructions sont compactées au début de le ''scheduler''. [[File:Wire partitionning.png|centre|vignette|upright=2|Wire partitionning]] Tout le problème est de savoir quelles portions désactiver. La technique est assez simple si le ''scheduler'' est compactée, à savoir si toutes les instructions sont régulièrement regroupées au début de la mémoire CAM. Mais même avec cette optimisation, la décision de désactiver une portion de le ''scheduler'' n'est pas à prendre à la légère. Il ne faut pas désactiver une portion contenant des instructions pouvant être émise sous peu. La décision dépend de paramètres variés : proportion d'entrée vides, quantité d'entrées récemment activées/désactivées récemment, présences d'entrées avec un ''match'' d'opérandes récent, etc. Il est important de préciser que les techniques en question fonctionnent aussi sur les autres types de ''scheduler'', qui ne sont pas basées sur des mémoires associatives. Nous allons voir celles-ci dans la suite du chapitre, mais gardez à l'esprit que ces optimisations, à savoir désactiver les entrées vides/prêts et partitionner le ''scheduler'', sont des optimisations générales qui marchent avec presque tout. ===L'ajout d'une FIFO pour les instructions déjà prêtes à l'émission=== D'autres techniques permettent de réduire aussi bien le cout en circuits que la consommation d'énergie de le ''scheduler''. L'idée est d'utiliser une mémoire associative quand elle est réellement nécessaire, mais d'utiliser un ''scheduler'' "normale" dès que possible. La méthode la plus simple tient compte du fait que certaines µopsont déjà toutes leurs opérandes de disponibles à l'émission, mais doivent quand même être mises en attente, parce que l'ALU adéquate est occupée, parce que des dépendances WAW/WAR sont encore là, ou pour tout autre raison. Dans ce cas, elles sont mises en attente non pas dans le ''scheduler'', mais dans une mémoire FIFO toute simple. L'idée est qu'au lieu d'avoir une énorme mémoire associative pour le ''scheduler'', on déplace quelques entrées dans une petite FIFO annexe. Le résultat est un gain d'énergie et de circuits, au prix d'une perte de performance mineure. La perte de performance en question se manifeste si aucune instruction n'a ses opérandes de prêtes à l'émission : le programme n'utilise pas la FIFO et voit alors un ''scheduler'' plus petite. Une amélioration de cette technique tient compte du fait que certaines instructions sont dans un cas intermédiaire. Elles ont déjà un opérande de prête lors de l'émission, mais pas l'autre. Le nombre d'opérandes varie suivant l’instruction : certaines n'ont besoin que d'un seul opérande. De plus, il arrive qu'une opération tout juste décodée ait déjà un ou plusieurs de ses opérandes de prêts. Cette constatation permet d'éviter d'utiliser des comparateurs pour les opérandes déjà prêts. Par exemple, on peut parfaitement utiliser trois ''scheduler'' : * une pour les instructions dont tous les opérandes sont prêts, mais qui sont quand même mises en attente, sans comparateur ; * une pour les instructions dont un seul opérande manque, qui n'utilise qu'un comparateur par entrée ; * une pour les instructions dont deux opérandes manquent à l'appel, qui utilise deux comparateurs par entrée. C'est beaucoup plus économique que d'utiliser une seule grosse ''scheduler'' qui contiendrait autant d'entrées que les trois précédentes réunies, avec deux comparateurs par entrée. Certains sont même allés plus loin, et ont proposé de supprimer le ''scheduler'' avec deux opérandes par entrée. Les instructions dont deux opérandes sont inconnus au décodage sont stockées dans le ''scheduler'' pour instructions avec un comparateur par entrée. Un circuit de prédiction se charge alors de prédire l'opérande manquant, cette prédiction étant vérifiée plus loin dans le pipeline. Il serait cependant étonnant qu'une telle proposition ait donné lieu à la moindre implémentation réelle. ===Les optimisations de la consommation d'énergie avancées=== D'autres chercheurs ont conservé un ''scheduler'' unique, avec autant de comparateurs par entrée qu'il y a d'opérandes possibles par instruction. Simplement, le processus de détection des opérandes prêts est légèrement ralenti : on ne vérifie qu'un opérande par cycle. Pour vérifier les deux opérandes d'une entrée, on doit attendre deux cycles. Enfin, certains chercheurs ont proposé des ''scheduler'' segmentées. Les instructions circulent à chaque cycle d'un segment vers le suivant : en conséquence, certains segments conservent les instructions les plus anciennes, un autre les instructions les plus jeunes, etc. Seul le denier segment, celui qui contient les instructions les plus vielles, peut émettre une instruction : la détection des opérandes se fait seulement dans le dernier segment, qui contient les instructions les plus anciennes. On économise ainsi beaucoup de comparateurs. Certains chercheurs ont tenté de pipeliner l'étape de sélection des opérandes, ainsi que l'étage d'arbitrage. Mais en faisant cela, il faut plusieurs cycles pour détecter qu'une instruction a ses opérandes prêts, ce qui pose problème face à de nombreuses dépendances RAW. Pour éviter de trop perdre en performances, certains chercheurs ont décidé d'utiliser des techniques pour prédire quelles seront les instructions dont les opérandes seront bientôt prêts. Si détecter qu'une instruction est prête prend n cycles, le processeur devra tenter de prédire la future disponibilité des opérandes n cycles en avance pour obtenir des performances optimales. ===Remplacer la mémoire associative par une RAM=== Une autre optimisation possible est de remplacer le ''scheduler'' par une mémoire RAM, dont chaque mot mémoire correspondrait à une entrée. Une telle optimisation permet en théorie de se passer des comparateurs associés à chaque entrée, mais au prix de l'ajout de circuits annexes potentiellement couteux. La première de ces techniques, la '''recherche directe par étiquette''' (direct tag search) fut créée par Weiss et son collègue Smith. Ils cherchaient à améliorer l'algorithme de Tomasulo, un algorithme qu'on expliquera dans quelques chapitres. Rappelons que chaque instruction produit un résultat, qui devra être rapatrié dans une ou plusieurs entrées de le ''scheduler''. L'optimisation de la recherche directe par étiquette fonctionne dans le cas où le résultat de l'instruction n'est utilisé que par une seule entrée, et pas plusieurs. Le principe est simple : chaque champ « opérande » d'une entrée est adressable via le nom de registre de cet opérande. Pour faire le lien entre entrée et nom de registre, la recherche directe par étiquette ajoute une table de correspondances matérielle, une mémoire RAM qui mémorise les adresses des champs « opérande » des entrées. Les adresses envoyées dans cette mémoire sont les noms de registres des résultats. Lors de l'émission, la table de correspondances est mise à jour. Les numéros des champs « opérande » réservés lors de l'émission sont mémorisés dans les mots mémoire qui correspondent aux deux registres sources. Toutefois, une petite vérification est faite lors de l'émission : s'il y a déjà une correspondance dans la table pour un registre source, alors une autre instruction compte lire ce registre. Pour éviter d'écraser les données de l'instruction précédente dans la table de correspondances, l'émission de l'instruction est bloquée. [[File:Recherche directe par étiquette.png|centre|vignette|upright=2|Recherche directe par étiquette.]] ==Les ''schedulers'' avec préplanification== Avec la '''préplanification''' (''prescheduling''), le ''scheduler'' est composée de mémoires FIFO dans lesquelles les instructions sont triées dans l'ordre d'émission. Il n'y a pas de logique d’émission proprement dite, celle-ci se bornant à vérifier si l'instruction située au début de la FIFO peut s’exécuter. Par contre, le préplanificateur détecte les dépendances et en déduit où insérer les instructions dans le tampon d'émission, à l'endroit le plus adéquat. [[File:Préplanification.jpg|centre|vignette|upright=2|Préplanification.]] ===L'usage de FIFO multiples=== La technique de préplanification la plus simple utilise plusieurs FIFO. Quand une instruction a une dépendance avec une autre instruction, les deux sont placées dans la même FIFO. Pour cela, le préplanificateur détecte les chaines d'instructions dépendantes, et place les instructions dans la FIFO adéquate. A chaque cycle, l'unité d'émission lit une micro-opération dans chaque FIFO et vérifie si elle peut l'émettre. Si la micro-opération n'a pas ses opérandes disponibles, ou qu'une dépendance structurelle survient, alors la FIFO est bloquée. La micro-opération attend que la dépendance soit résolue, bloquant toutes les instructions précédentes. Mais les autres FIFO ne sont pas bloquées, laissant de la marge de manœuvre. [[File:Préplanification par FIFO multiples.png|centre|vignette|upright=1.5|Préplanification par FIFO multiples.]] ===La technique du tampon trié=== La technique du '''tampon trié''' trie les instructions selon le temps d'attente avant leur exécution. Les instructions qui sont censées s’exécuter bientôt sont insérées au tout début de la FIFO, tandis que les instructions qui s’exécuteront dans un long moment sont insérées vers la fin. Là encore, l'unité d'émission lit une micro-opération dans la FIFO, et détermine si elle peut être émise. Si une dépendance survient, l'émission est retardée, et la FIFO est bloquée. [[File:Préplanification par tampon trié.png|centre|vignette|upright=1.5|Préplanification par tampon trié.]] La technique a cependant quelques problèmes assez importants. Le premier problème est que la FIFO est bloquée lorsqu'une micro-opération ne peut être émise. Le second problème est que le temps avant exécution n'est pas toujours connu, notamment pour les instructions d'accès mémoire. Et cela se répercute sur les instructions dépendantes de celles-ci. Pour résoudre ce genre de problèmes, l'usage d'un pipeline à ''replay'' est possible, et est même l'une des meilleures solutions possible, malgré ses défauts. L'idée est que les lectures sont pré-planifiées en supposant qu'elles font un succès de cache L1. Si la prédiction est fausse, la lecture est ré-exécutée plusieurs cycles plus tard, en supposant qu'elle fait un succès dans le cache L2, et ainsi de suite. Elle est alors ré-insérée dans la FIFO, elle est pré-planifiée une seconde fois. Il en est de même si une micro-opération ne peut pas être émise : il suffit de la réinsérer dans la FIFO au bon endroit, en attendant que ses dépendances soient résolues. Ainsi, l'instruction fautive ne bloque pas le ''scheduler'', et retente sa chance autant de fois qu'il le faut. [[File:Préplanification par fenêtre d’instruction scorebarodée.png|centre|vignette|upright=1.5|Préplanification par ''scheduler'' scorebarodé.]] Une autre solution utilise deux ''schedulers'' : une FIFO gérée par la préplanification, et une vraie ''scheduler'' pour les instructions dont le temps d'attente ne peut pas être déterminé. Il est possible de mettre cette dernière avant la préplanification, afin de gérer les temps d'attente des instructions d'accès mémoire. Quand le temps d'attente d'une lecture devient connu, ses instructions dépendantes sont gérées avec préplanification. [[File:Préplanification avec fenêtre d’instruction.png|centre|vignette|upright=2.5|Préplanification avec ''scheduler''.]] ===Les ''scheduler'' avec allocation temporelle statique=== L''''allocation temporelle statique''' correspond à une technique utilisée sur les processeurs Cuzco de l'entreprise Condor. La technique en question a été présenté en 2025, mais des idées similaires ont été présentées dans la littérature académique. Elle ressemble beaucoup aux techniques de pré-planification, avec cependant quelques différences. L'idée est simple : le processeur dispose de plusieurs ''scheduler'', qui mettent en attente les micro-opérations. Lors de l'étape de renommage de registres, le processeur détermine dans combien de cycles d'horloge la micro-opération sera prête pour exécution. La micro-opération est alors mise en attente durant ce nombre de cycles, dans les ''scheduler'', puis est émise une fois ce nombre de cycles écoulés. Ce faisant, les ''scheduler'' n'ont pas besoin de détecter la disponibilité des opérandes à chaque cycle, pour chaque micro-opération en attente. Le ''timing'' de l'émission des micro-opérations est décidé à l'avance. L'implémentation exacte n'est pas connue, mais plusieurs solutions sont imaginables. Par exemple, le ''scheduler'' peut simplement être composée de plusieurs mémoires de petite taille, chacune contenant les micro-opérations destinées à être exécutées dans N cycles, N étant différent pour chaque mémoire. Une autre solution, plus réaliste, utilise un ''scheduler'' dans laquelle la micro-opération est couplée à des champs pour les opérandes, et un champ compteur. Le champ compteur est initialisé avec le nombre de cycles à attendre, et est décrémenté à chaque cycle d'horloge. Quand il atteint zéro, la micro-opération est émise. Vous remarquerez que la méthode ne marche que si toutes les micro-opérations prennent un nombre fixe de cycles d'horloge. Et autant c'est le cas pour les micro-opérations arithmétiques ou logiques, autant les accès mémoire ne rentrent pas dans ce cadre. En théorie, on ne sait pas combien de temps prendra un accès mémoire. Et cette incertitude se répercute sur les instructions dépendantes d'un accès mémoire. Pour éviter cela, le processeur réutilise un pipeline à ''replay'' tel que vu dans le chapitre précédent. L'unité de renommage de registre suppose que tout accès mémoire fait un succès de cache L1, et décide des ''timings'' d'émission sous cette hypothèse. Si une lecture subit un défaut de cache, elle est ré-exécutée, de même que toutes les instructions dépendantes. Pour cela, le registre de destination de la lecture est marqué comme invalide, grâce à un bit spécifique attaché au registre. Toute instruction qui lit un opérande invalide est elle aussi ré-executée de zéro. Pour simplifier, l'unité d'émission ressemble à une unité d'émission dans l'ordre, avec un registre de disponibilité, qu'on aurait amélioré pour aller au-delà de la simple détection des dépendances d'instruction. Pour déterminer les ''timings'' d'émission, à savoir quand émettre une micro-opération, le processeur utilise une unité d'émission à deux étages. Le premier étage est appelé le ''register scoreboard'', le second étage est appelé la ''Time Ressource Matrix''. Les deux étages communiquent entre eux, comme on va le voir, et leurs noms donnent une idée de ce qu'ils font. Le premier étage gère les dépendances de registres, le second gère les dépendances structurelles. Le premier étage est un registre de disponibilité amélioré, qui gère les dépendances de registre. Cet étage sait quand tel registre sera écrit, et donc que l'opérande écrit dedans sera disponible à partir de tel cycle d'horloge. Il le sait car l'étage suivant l'aura prévenu, mais laissons cela de côté pour le moment. Quand une micro-opération rentre dans cet étage, il vérifie les dépendances avec les registres et les micro-opérations antérieures. Vu qu'il sait quand les registres seront disponibles, il peut déterminer quand l'instruction pourra s'exécuter. Par exemple, si une micro-opération lit les deux registres R7 et R15, qui sont disponibles respectivement dans 5 et 7 cycles, le premier étage sait que la micro-opération devra attendre 7 cycles. Mais tout cela ne suffit pas à déterminer quand émettre une micro-opération. En effet, il fait aussi gérer les dépendances structurelles, ce qui est le boulot du second étage. Le second étage utilise pour cela une ''Time Ressource Matrix'', qui mémorise l'occupation de diverses "ressources", pour les 256 cycles d'horloge à venir. Les ressources en question sont les ports de lecture/écriture du banc de registre, les ALUs utilisées, si la micro-opération utilise l'unité mémoire, etc. Le second étage prend en entrée une micro-opération, détermine quelles "ressources" elle utilise, puis regarde leur disponibilité. Elle détecte alors les dépendances structurelles et détermine alors quand peut s'exécuter la micro-opération. Elle peut retarder l'émission de quelques cycles, si une dépendance structurelle est détectée. Une fois sortie du second étage, on sait quand la micro-opération va être émise, à quel cycle précisément. Et vu que la durée de l'instruction est fixe, on sait quand cette micro-opération va se terminer, quand son résultat sera disponible. Cela permet de mettre à jour la ''Time Ressource Matrix'', pour préciser que le port d'écriture sera occupé à tel moment. De plus, cette information est transmise au premier étage, qui sait alors quand est enregistré le résultat dans le registre de destination. C'est comme cela que le premier étage sait quand un registre est disponible : le second étage le prévient, quand il émet une instruction ! La ''Time Ressource Matrix''mémorise l'occupation des "ressources" pour les 256 cycles d'horloge à venir. Cependant, elle ne vérifie pas les dépendances pour les 256 cycles suivants. Quand elle reçoit une micro-opération, elle teste les dépendances structurelles pour seulement les 8 prochains cycles maximum. Si la micro-opération ne peut pas être émise pendant ces 8 cycles, le pipeline est bloqué, un ''pipeline stall'' est émis. Pour être plus précis, vu que le processeur peut décoder 8 micro-opérations en même temps, cela permet de ne consulter que 64 cycles d'horloge sur les 256. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les premiers processeurs Intel | prevText=Les premiers processeurs Intel | next=Le renommage de registres | nextText=Le renommage de registres }} </noinclude> 3q51d9mkjciuribzero9m2o5jmg8m8l 773685 773684 2026-09-29T23:21:38Z Mewtow 31375 /* L'implémentation d'un scheduler : généralités */ 773685 wikitext text/x-wiki Dans les chapitres précédents, nous avons parlé des techniques dites d''''émission dans l'ordre'''. L'idée est d’exécuter une nouvelle micro-opération à chaque cycle, dans des unités de calcul séparées. Les instructions sont émises consécutivement, mais les instructions s’exécutent en parallèle dans des unités de calcul séparées. Par contre, quand l'unité d'émission ne peut pas émettre une instruction, elle bloque tout le pipeline. Les instructions qui suivent sont elles aussi bloquées, elles doivent attendre leur tour, même si elles sont en capacité de s'exécuter. Les techniques d'exécution dans le désordre que nous allons voir dans ce chapitre corrigent ce point précis. Elles sont dites à '''émission dans le désordre'''. Elles se distinguent des précédentes sur un point précis : quand l'unité d'émission bloque l'émission d'une instruction, les instructions suivantes peuvent poursuivre. L'émission des instructions peut donc se faire dans le désordre, dans le sens où une instruction peut être émise alors qu'une instruction précédente ne l'est pas encore. Mais avant de poursuivre, quelques point niveaux terminologie : * L'émission dans le désordre est un terme parlant et assez précis. Malheureusement, la terminologie la plus utilisée par d''''exécution dans le désordre'''. Et nous utiliserons ce terme dans la suite du cours, histoire de ne pas trop dévier de la nomenclature habituelle. * Nous utiliserons parfois l'abréviation OOO pour parler d'exécution dans le désordre. L'abréviation est celle de ''Out Of Order Execution''. * Nous utiliserons aussi l'abréviation ''µop'' pour parler de micro-opération, ''µops'' au pluriel pour parler de plusieurs micro-opérations, ou des micro-opérations en général. L'exécution dans le désordre ne gère en effet que des µops, elle se situe après l'étape de décodage. Pour décrire comment est implémentée l'émission dans le désordre, il faut commencer par parler des processeurs sans. Les processeurs sans exécution dans le désordre ont une unité d'émission qui bloque tout le pipeline dès qu'une µop ne peut pas être émise. Pour limiter l'impact de ce blocage, quelques rares processeurs incorporent une '''file de micro-opération''', une mémoire FIFO qui met en attente les µops. Vu que c'est une mémoire FIFO, les µops sont émises dans l'ordre, à savoir l'ordre d'ajout, dans l'ordre de décodage. Le schéma ci-dessous illustre une telle file d'attente couplée à un ''scoreboard''. L'exécution dans le désordre améliore la file de µops sur un point : ce n'est plus une mémoire FIFO. Les µops sont insérées dans l'ordre, mais peuvent sortir dans le désordre (être émises dans le désordre). La file de µops devient alors un '''''scheduler''''', terme anglais que je ne compte pas traduire. Un terme équivalent est '''''scheduler''''', terme traduit directement de l'anglais ''instruction Window''. Terme assez trompeur, car elles mettent en attente des µops, pas des instructions. [[File:Différence file µops et fenêtres instruction.png|centre|vignette|upright=2|Différence file µops et ''schedulers'' ]] Le ''scheduler'' émet une µop dès que ses opérandes sont disponibles. Par disponible, on veut dire présent soit dans le réseau de contournement, soit dans les registres. Le ''scheduler'' détecte automatiquement quand les opérandes d'une µop sont disponibles, grâce à une unité d'émission intégrée. L'unité d'émission et la file d'attente de µops sont fusionnés ensemble, dans un seul circuit, mais nous allons dire qu'ils sont conceptuellement séparés pour le moment. À chaque cycle, l'unité d'émission consulte les µops en attente pour détecter lesquelles peuvent s'exécuter. Le ''scheduler'' est spécialement être conçue pour, c'est une sorte de mémoire associative très complexe, comme on le verra dans ce qui suit. [[File:OOO Issue.png|centre|vignette|upright=2.5|Exécution dans le désordre avec un ''scheduler'']] Une fois qu'une µop sort du décodeur d'instructions, elle est ajoutée en parallèle dans le ''scheduler'' et le ROB. La raison est que les µops quittent le ''scheduler'' dans le désordre, et qu'elles doivent être remises en ordre par la suite. Le ROB s'occupe de cette remise en ordre, mais il a besoin de savoir dans quel ordre les µops sont censées être, et cet ordre est celui du décodage. Aussi, pour remplir le ROB, la seule opportunité est en sortie de l'unité de décodage. Dans le cas où une instruction est décodée en plusieurs micro-opérations, elles sont toutes insérées en même temps dans le ''scheduler'' et le ROB, en tenant compte de leur ordre. L'implémentation la plus "simple" de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Les µops décodées sont accumulées dans le ''scheduler'', où elles attendent leur tour. Bien que simple en apparence, cette implémentation cache une complexité très importante, liée aux accès mémoire. Les micro-opérations mémoire sont à part des autres, pour ce qui est de leurs dépendances de données. Non seulement elles ont des dépendances de registre, mais elles sont aussi des dépendances d'adresse. Par exemple, deux écritures peuvent utiliser deux registres d'adresse différents, mais ceux-ci peuvent contenir la même adresse. Et autant on peut détecter les dépendances de registre lors de l'émission, autant c'est plus compliqué avec les dépendances d'adresse. De plus, rappelons que si les lectures peuvent s'exécuter dans le désordre, les écritures doivent s'exécuter dans l'ordre, ou du moins en donner l'illusion. Pour cela, le processeur remet les écritures dans l'ordre avec une sorte de mini-ROB intégré à l'unité mémoire, appelée la file d'écriture. Elle complémente le ROB, qui lui ne gère que les écritures dans les registres, mais les deux collaborent. La file d'écriture envoie une écriture à la mémoire RAM quand le ROB lui dit que c'est bon, les instructions précédentes sont terminées ''dans l'ordre du programme''. Les processeurs modernes ajoutent des techniques d'exécution dans le désordre des accès mémoire, mais nous les verrons dans un chapitre dédié. Elles permettent d'utiliser un ''scheduler'' unique, qui mémorise aussi les µops mémoire. Si elles sont mises en place, l'unité mémoire n'a pas besoin de file de µops séparée. Les dépendances de registre sont traitées par le ''scheduler'', alors que les dépendances d'adresse sont gérées par l'unité mémoire gére les dépendances d'adresse. Elle utilise pour cela des techniques de '''''désambiguïsation mémoire''''', qui auront droit à un chapitre dédié. [[File:Processeur avec exécution dans le désodre des accès mémoire.png|centre|vignette|upright=2|Processeur avec exécution dans le désodre des accès mémoire]] Les processeurs assez anciens n'autorisaient pas d'exécution dans le désordre des accès mémoire. Concrètement, les accès mémoire devaient se faire dans l'ordre, mais les autres µops pouvaient être exécutées dans le désordre. Pour garantir l'ordre des µops mémoire, les µops mémoire ne passent pas par le ''scheduler'', mais sont accumulées dans une file de micro-opérations séparée. Après le décodage, les µops sont réparties soit dans la file de µops mémoire, soit dans le ''scheduler''. Le décodeur classe les µops suivant que ce sont des µops mémoire ou non, et les envoient à la bonne destination. Dans ce chapitre, on supposera que c'est cette solution qui est utilisée. [[File:Processeur avec émission dans l'ordre des accès mémoire.png|centre|vignette|upright=2|Processeur avec émission dans l'ordre des accès mémoire]] ==L'implémentation d'un ''scheduler'' : généralités== Un ''scheduler'' est une mémoire qui mémorise des micro-opérations. Elle est cependant plus complexe qu'une mémoire RAM ou qu'une FIFO et ressemble un petit peu à une mémoire cache. Elle dispose d'un port d'écriture et d'un port de lecture, au minimum. Le port d'écriture permet à l'unité de décodage d'insérer une micro-opération dedans, d'ajouter la micro-opération qui vient d'être décodée. Aussi, il est appelé le '''port de décodage'''. Si une instruction machine est décodée en plusieurs micro-opérations, deux possibilités. La première est de les insérer un par un, ce qui fait qu'on peut se contenter d'un seul port d'écriture. L'autre possibilité est de les ajouter en même temps, ce qui demande plusieurs ports d'écriture. Le port de lecture sert à émettre une micro-opération, ce qui fait qu'il est appelée le '''port d'émission'''. Dans ce chapitre, on part du principe que le ''scheduler'' ne peut émettre qu'une seule micro-opération à la fois. Dans ce cas, le ''scheduler'' a un seul port de lecture. Mais nous verrons dans quelques chapitres qu'il existe des processeurs dits superscalaires, qui sont capables d'émettre plusieurs micro-opérations par cycle. Un processeur superscalaire a avoir un port d'émission par unité de calcul, ce qui fait beaucoup plus. Les ''schedulers'' sont composées d''''entrées''', des mots mémoire qui stockent une micro-opération. Une micro-opération tout juste décodée réserve une entrée et la libère dès qu'elle est envoyée aux unités de calcul. Une entrée contient l'opcode (les signaux de commande à envoyer à l'ALU), le registre de destination du résultat, les registres de chaque opérande, et éventuellement des signaux de commande en plus. De plus, chaque opérande est couplée à un bit de disponibilité, qui indique si elle est disponible. Quand un opérande est écrit dans les registres, le bit de présence correspondant est mis à jour. Enfin, chaque entrée possède un bit ''empty'' qui indique si elle est vide, cette information étant utile pour réserver des entrées. [[File:Entrée d'une station de réservation - sans les tags.png|centre|vignette|upright=3|Entrée d'un ''scheduler'']] ===Les stations de réservation=== Les '''stations de réservation''' sont des ''scheduler'' particulières, qui sont capables de mémoriser les opérandes des micro-opérations. Les entrées des stations de réservation sont identiques à celle des autres ''scheduler'', si ce n'est que les opérandes de la micro-opération sont enregistrés directement dans des champs séparés. Il y a deux champs, un par opérande, pour stocker l'opérande elle-même, lue depuis les registres ou obtenue via le réseau de contournement. Notons que les champs pour les opérandes viennent en plus des champs pour les noms de registres, encore que les deux peuvent être fusionnés si on veut optimiser le tout. [[File:Entrée d'une station de réservation.png|centre|vignette|upright=3|Entrée d'une station de réservation.]] Précisons que la terminologie n'est pas très fiable. Les termes "''scheduler''" et "station de réservation" ne regroupent pas du tout la même chose d'un papier de recherche à l'autre, d'un bouquin à l'autre, d'un chercheur à l'autre, d'un ingénieur à l'autre, d'un professeur à l'autre. Le terme initial vient pourtant de l'article original sur l'algorithme de Tomasulo, où il désignait un ''scheduler'' associée à une unité de calcul précise. Mais le terme a ensuite été réutilisé, ce qui fait que certains processeurs avec plusieurs unités de calcul sont décrits comme ayant une unique station de réservation. En bref : c'est le bazar ! Mais nous en reparlerons dans le chapitre sur le renommage de registres, car c'est la place idéale pour les aborder. Toujours est-il que j'ai fait le choix de confondre les concepts de ''scheduler'' et de station de réservation avec les concepts de '''lecture avant émission''' et de '''lecture après émission'''. La différence entre les deux est que les registres sont lus après émission avec un ''scheduler'', avant avec des stations de réservation. Dans le cas "avant émission", les opérandes sont mémorisés dans la station de réservation. Et cette différence a une influence sur le pipeline du processeur, le banc de registres et tout ce qui s'ensuit. Un désavantage de la lecture avant émission est qu'il faut stocker les opérandes après lecture, ici dans les stations de réservation. Mais un avantage est que le banc de registre a besoin de moins de ports de lecture, car une bonne partie des opérandes sont fournies par le système de contournement. Nous verrons cela dans le détail dans le chapitre sur les processeurs superscalaires. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Lecture après émission.]] [[File:Read Before Issue.png|centre|vignette|upright=2.5|Lecture avant émission.]] ===La logique d'éveil et de sélection=== Dans le cas qui va suivre, on suppose que le processeur ne peut émettre qu'une micro-opération à la fois. Chaque cycle, une micro-opération est sélectionnée et est envoyée dans le chemin de données, soit à une ALU, soit à une unité d'accès mémoire. La sélection d'une micro-opération est effectuée par l'unité d'émission intégré au '''''scheduler'''''. Elle gère la disponibilité des opérandes et la disponibilité des unités de calcul adéquate. Le choix de la micro-opération émise doit être le plus pertinent possible, pour des raisons de performances. Pour le premier point, l'unité d'émission détermine quelles micro-opérations sont candidates pour l'émission. Les ''instructions candidates'' sont celles dont tous les opérandes sont prêts. Le processeur contient un circuit qui détecte les instructions candidates : la '''logique d’éveil''' (''wake-up logic''). Une fois que la logique d'éveil a fait son travail, une instruction est choisie pour s’exécuter en fonction de la disponibilité des unités de calcul adéquates. Ce rôle est dévolu à un circuit qu'on appelle la '''logique de sélection''', ou ''select logic''. [[File:Fonctionnement complet de la logique d’émission.jpg|centre|vignette|upright=1.5|Fonctionnement complet de la logique d’émission.]] La logique de sélection doit gérer le fait que les unités de calcul du processeur ne sont pas toutes identiques. Déjà, un processeur a généralement des unités séparées pour les instructions entières et flottantes, des unités spécialisées dans les accès mémoire, parfois des unités spécialisées pour les branchements. Une instruction doit être attribuée à la bonne unité de calcul, on ne doit pas envoyer une instruction entière dans une unité de calcul flottante. De plus, parmi les unités de calcul entières, toutes ne sont pas identiques. Par exemple, il est fréquent d'avoir plusieurs unités de calcul spécialisées dans les opérations simples (additions, soustractions, opérations logiques) avec une unité pour les multiplications/divisions séparées, parfois une unité spécialisée pour les décalages/rotations, etc. Là encore, allouer la bonne instruction à la bonne ALU est complexe. Plus les unités de calcul sont hétérogènes, plus la logique de sélection est compliquée. Les logiques d'éveil comme de sélection sont assez complexes. Comme on le verra plus bas, la logique de sélection la plus simple, qui gère une seule unité de calcul, est basée sur un encodeur à priorité, couplé à d'autres circuits. Et pour gérer plusieurs ALUs, il faut mettre des encodeurs en cascade. Le résultat est que même en prenant une logique de sélection simple, elle sera assez lente et gourmande en circuits. Aussi, la logique de sélection met souvent un cycle d'horloge entier pour faire son travail, elle a son propre étage de pipeline attribué. La logique d'éveil est dans le même cas, ce qui fait qu'émettre une micro-opération demande deux cycles d'horloge. Le défaut est que cela rajoute des cycles d'horloges entre le ''scheduler'' et l'ALU, ce qui complique la gestion du pipeline. Ces cycles de retard sont à prendre en compte au moment d'émettre les instructions, les ''scheduler'' doit en tenir compte pour des performances optimales. Sans tenir compte de ces cycles de retard, les instructions arrivent en retard de quelques cycles à l'ALU, cycles de retard durant lesquels l'ALU n'a pas fait de calcul et a été sous-utilisée, sans compter que le système de contournement n'est pas utilisé au mieux. Et le problème est encore plus important sur les processeurs avec des stations de réservation, qui utilisent la "lecture après émission" : cela rajoute un cycle d'horloge en plus, un temps de retard en plus. ===La logique d'éveil : l'émission anticipée=== La logique d'éveil doit tenir compte du fait qu'il y a plusieurs étages entre l'émission et l'exécution sur une unité de calcul. Par exemple, un processeur a souvent entre un et à cinq étages entre la file d'attente et les unités de calcul. Il faut lire les registres, gérer le contournement, et cela peut prendre quelques cycles d'horloge. Sur le Pentium 4, on trouve 6 étages entre le ''scheduler'' et l'entrée de l'ALU. Si les micro-opérations sont émises quand les opérandes sont disponibles, il y aura un délai de quelques cycles avant qu'elles atteignent l'ALU. Alors qu'idéalement, on souhaiterait que la micro-opération atteigne l'ALU dès que ses opérandes sont disponibles, pour profiter des techniques de contournement. Pour cela, la logique d'éveil émet les instructions quelques cycles en avance pour qu'elles arrivent au bon moment. Il s'agit d'une technique d''''émission anticipée''', dont nous avions parlé dans le chapitre sur le contournement. : Il faut noter que le problème se pose plus avec des ''schedulers'' qu'avec des stations de réservation. Les premières ont un étage en plus entre émission et ALU, vu qu'il faut lire des registres après l'émission. L'émission anticipée demande d'émettre un signal d'éveil en avance de quelques cycles, pile au bon moment. Par exemples, si on a deux étages entre l'ALU et l'unité d'émission, le signal de réveil sera généré deux cycles avant que le résultat soit effectivement calculé. L'implémentation varie, mais deux solutions sont possibles. La première est de générer le signal d'éveil dans l'ALU, ce qui n'a de sens que pour les opérations comme les multiplications ou les divisions, qui prennent plusieurs cycles. Une autre technique génère le signal de réveil dans une structure centralisée, spécialisée dans la génération des signaux d'éveil. L'unité de composée d'un registre à décalage par registre. Imaginons qu'une instruction est émise, que cette instruction mette N cycles à s'exécuter, et qu'elle écrive dans un registre de destination. L'unité sélectionne alors le registre à décalage associé au registre de destination, et met le bit numéro N à 1. Le registre décalé d'un cran à chaque cycle. Quand le bit sortant est un 1, alors le signal de validité pour l'opérande est généré. L'émission anticipée marche bien si l'instruction a une durée fixe, connue à l'avance. Et autant c'est le cas pour les instructions arithmétiques et logiques, autant ce n'est pas le cas pour les accès mémoire. Les accès mémoire ont une latence variable : quelques cycles pour un succès de cache, plusieurs dizaines de cycles pour un défaut de cache L1, pas loin de la centaine pour un défaut de cache L2, etc. Et cela pose des problèmes pour l'émission anticipée. L'émission en avance pour les accès mémoire est purement spéculative : le processeur émet des instructions en supposant que la lecture entrainera un succès de cache, quitte à annuler l'instruction en cas de défaut de cache. Mais faire ainsi demande non seulement d'annuler les instructions émises en avance, mais aussi de ne pas retirer les instructions émises en avance de le ''scheduler''. Elles sont émises, mais une copie de sauvegarde est conservée dans le ''scheduler''. Si le processeur détecte un défaut de cache, il peut alors ré-exécuter l'instruction. S'il détecte un succès de cache, les instructions lecture-dépendante sont retirées de le ''scheduler'', la copie de sauvegarde est devenue inutile et est donc jetée. ===La logique de sélection : âge ou position ?=== La logique de sélection est primordiale pour de bonnes performances. Il existe deux méthodes principales pour sélectionner l'instruction à exécuter. La première est la plus simple : elle se base sur lé numéro de l'entrée. En effet, un ''scheduler'' est avant tout une sorte de mémoire, un mix entre mémoire associative, mémoire RAM, et FIFO. Et chaque entrée a un numéro, une adresse mémoire. Nous parlerons de numéro dans ce qui suit, car ce sera plus simple, le terme d'adresse mémoire étant peut-être un peu exagéré dans le contexte des ''scheduler''. Toujours est-il que le ''scheduler'' est adressable dans le sens où on peut lui envoyer le numéro de l'entrée voulue, et le ''scheduler'' renvoie le contenu de l'entrée sur son port de lecture. Et c'est ce que fait la logique de sélection : elle génère le numéro de l'entrée à lire. Le numéro est alors envoyé sur l'entrée d'adresse du ''scheduler'', et elle fournit la micro-opération associée sur son port de lecture, son '''port d'émission'''. La première méthode de sélection, donc. Elle est basée sur le numéro de l'entrée. Si plusieurs entrées sont éveillées, la logique de sélection prend celle avec le plus petit numéro. Elle porte le nom de '''sélection par position''', sous-entendu position dans le ''scheduler''. Vous l'avez peut-être deviné, mais la logique de sélection est alors un encodeur à priorité. Le circuit de sélection ne se résume donc pas seulement à un encodeur à priorité, mais c'est le circuit central. L'avantage d'une telle méthode de sélection est qu'elle est simple à implémenter : un encodeur à priorité est un circuit connu, facile à implémenter. Mais on remarque un défaut : un encodeur est un circuit assez rapide, mais qui utilise beaucoup de transistors, beaucoup de portes logiques, surtout si on veut qu'il soit rapide. Ce qui explique que la logique de sélection ait son propre étage de pipeline rien que pour elle. La seconde méthode s'appelle la '''sélection par âge''', au nom assez transparent. L'idée est de privilégier l'émission de l'instruction la plus ancienne. Elle demande que le ''scheduler'' trie les micro-opérations par ordre d'insertion dans le ''scheduler'', ce qui en fait une pseudo-FIFO. Le tri est partiel, car les instructions peuvent sortir du ''scheduler'' à tout moment. Compacter le ''scheduler'', à savoir regrouper toutes les entrées valides est une idée, mais elle est compliquée à implémenter. Aussi, elles préfèrent encoder des informations sur l'ordre d'émission dans chaque entrée. L'encodeur à priorité doit alors travailler non pas sur des nombres entiers liés à l'ordre d'insertion dans la pseudo-FIFO. Elle est encore plus gourmande en circuits que la méthode précédente. Les processeurs haute performance utilisent souvent des méthodes hybrides. Par exemple, les processeurs AMD de microarchitecture Bulldozer utilisaient une méthode intermédiaire. Ils utilisaient un ''scheduler'' couplée à un encodeur à priorité pour la sélection par position, mais complémentaient le tout avec une unité qui mémorisait l'instruction la plus ancienne dans le ''scheduler''. Le mécanisme de sélection par âge était utilisé en priorité. Mais si l'instruction la plus ancienne n'était pas prête, le processeur basculait sur le mécanisme de sélection par position. ===La compaction des ''scheduler''=== À chaque cycle, les instructions décodées sont ajoutées dans le ''scheduler'', dans des entrées vides. Vu que les instructions quittent celle-ci dans le désordre, ces vides sont dispersés dans le ''scheduler'', ce qui pose problème pour déterminer où placer les nouvelles instructions. La solution la plus triviale consiste à conserver une liste des vides, mise à jour à chaque insertion ou émission d'instruction. Une autre solution consiste à éliminer les vides en compactant le ''scheduler'' à chaque cycle d'horloge. Des circuits se chargent de détecter les vides et de regrouper les instructions en un unique bloc. Il faut signaler que certains processeurs arrivent à se passer de cette étape de compactage, mais au prix de ''scheduler'' nettement plus complexes. Autre problème : quand il faut choisir quelle instruction émettre, il y a toujours plusieurs candidats. Si on choisit mal, des instructions restent en attente trop longtemps parce que d'autres instructions plus jeunes leur passent devant. Pour éviter cela, les instructions les plus vielles, les plus anciennes, sont prioritaires. Pour cela, on peut utiliser une FIFO un peu spéciale pour le ''scheduler''. Si les ajouts d'instruction se font dans l'ordre, les instructions ne quittent pas forcément le ''scheduler'' dans l'ordre imposé par une FIFO : les instructions restent triées dans leur ordre d'ajout, même s'il y a des vides entre elles. Dans ces conditions, il est préférable que le compactage conserve l'ordre FIFO des instructions. Dans ces conditions, l'instruction la plus ancienne est celle qui est située à l'adresse la plus faible : le circuit de sélection peut donc être fabriqué avec des encodeurs, et est relativement simple. ==Les ''schedulers'' basées sur une matrice de dépendances== L'implémentation la plus simple étend le fonctionnement d'un pipeline dynamique usuel. Rappelez-vous le chapitre sur les pipelines dynamiques. Nous avions vu que de tels pipelines émettaient une instruction par cycle, quitte à émettre des bulles de pipeline en cas de dépendance bloquante. Et il est possible d'améliorer leur unité d'émission pour qu'elle soit compatible avec l'exécution dans le désordre. ===Rappels sur le registre de réservation/disponibilité=== L'émission d'une instruction est gouvernée par un ''registre de réservation'' qui indique quels registres sont réservés par une instruction, et ceux qui sont libres. Un registre réservé est un registre qui sera écrit par une instruction en cours d'exécution, mais qui n'a pas encore écrit son résultat. Les instructions candidates doivent avoir leurs opérandes dans des registres libres. Sinon, c'est signe que leurs opérandes sont réservés en écriture, donc pas encore écrites, donc pas disponibles. Si une instruction candidate veut lire ce registre, c'est signe qu'il y a une dépendance RAW : elle veut lire un registre réservé, qui est destiné à être écrit par une instruction en vol. Si elle veut écrire, c'est signe qu'elle veut écrire dans un registre où une autre instruction veut écrire : c'est une dépendance WAW. Dans les deux cas, l'instruction n'est pas émise. Le registre de réservation encode les registres réservés comme suit : chaque bit est associé à un registre. Le bit numéro 0 est associé au registre numéro 0, le bit numéro 1 au registre numéro 1, etc. Là, En clair, les numéros de registres réservés sont encodés en représentation non pas binaire, mais en représentation ''one-hot'' (vue au premier chapitre). {|class="wikitable" |+ Registre de réservation |- ! Registre 7 !! Registre 6 !! Registre 5 !! Registre 4 !! Registre 3 !! Registre 2 !! Registre 1 !! Registre 0 |- | 0 || 0 || 1 || 0 || 0 || 1 || 0 || 0 |} Avant d'émettre une instruction, l'unité d'émission extrait les registres opérande/destination et les convertis dans la même représentation que le registre de réservation, à savoir en représentation ''one-hot''. Le circuit de traduction binaire vers ''one-hot'' est, pour rappel, un simple décodeur. Puis, on fait un OU logique entre les sorties des décodeurs. Le résultat est un masque qui indique quels registres sont lus par l'instruction, encodé en représentation ''one-hot''. Appelons-le le '''masque d'opérandes'''. Le masque est alors comparé au registre de réservation pour vérifier si l'instruction peut être émise. [[File:Unité d'émission simple, dans l'ordre.png|centre|vignette|upright=2|Unité d'émission simple, dans l'ordre]] Si l'émission est autorisée, le registre de réservation est là aussi mis à jour. Le registre de réservation est aussi mis à jour dès qu'une instruction enregistre son résultat dans les registres, ou alors dès qu'il est disponible pour le contournement. Le bit associé au registre repasse alors à 0 (ou à 1). Sans contournement, la mise à jour se fait alors à la toute fin de l'instruction, quand elle se termine, lors de la dernière étape d'enregistrement, à la fin de son pipeline. Avec, elle se fait quand l'instruction quitte l'unité de calcul. ===L'extension à l'exécution dans le désordre : l'éveil par matrice de bits=== La différence entre un pipeline dynamique et l'exécution dans le désordre est que l'on passe d'une instruction à émettre à plusieurs. Plusieurs instructions sont mises en attente dans un ''scheduler'', et y attendent leur tour. L'idée est alors d'envoyer le registre de disponibilité à toutes les entrées, à toutes les instructions en attente. Ainsi, on sait quelles sont les instructions qui peuvent s'exécuter et celles qui ne le peuvent pas. L'implémentation est assez simple, elle ressemble beaucoup à l'implémentation d'un pipeline dynamique simple, si ce n'est que des circuits sont dupliqués. L'implémentation utilise des ''scheduler'' légèrement différentes de celles introduites plus haut. Elles n'utilisent notamment pas de bits de disponibilité, mais autre chose. Lorsqu'une instruction est ajoutée à le ''scheduler'', le masque de disponibilité des opérandes est stocké dans le ''scheduler''. A chaque cycle, le registre de disponibilité est envoyé à toutes les entrées, et est comparé avec tous les masques de disponibilité des opérandes. Si une comparaison renvoie un 1, alors l'instruction de l'entrée est une instruction candidate à l'émission. [[File:Unité d'émission dans le désordre basée sur un registre de disponibilité.png|centre|vignette|upright=2.5|Unité d'émission dans le désordre basée sur un registre de disponibilité]] L'ensemble est implémenté avec l'aide d'une '''matrice de bits''', où chaque ligne correspond à une entrée et chaque colonne à un registre. À chaque croisement entre une ligne et une colonne, on trouve un bit. Si le bit de la ligne n et de la colonne m est à 1, cela veut dire : l'instruction dans l'entrée n a besoin de lire le registre m. S’il est à 0, alors cela veut dire que l'instruction stockée dans la ligne n'a pas besoin de la donnée dans le registre m. [[File:Planificateur à matrice de bits.jpg|centre|vignette|upright=2|Planificateur à matrice de bits.]] Lorsqu'une instruction réserve une entrée, elle initialise la ligne en fonction des registres qu'elle souhaite lire. Pour vérifier si une instruction a ses opérandes prêts, le processeur compare le registre de disponibilité à la ligne associée à l'instruction/entrée. A chaque intersection ligne-colonne, se trouve un comparateur de 1 bit, qui détecte si le registre est demandé et disponible. Les résultats de cette porte sont ensuite envoyés à une porte ET, qui fait le gros du travail. [[File:Logique de détection de la disponibilité d'une instruction.jpg|centre|vignette|upright=2|Logique de détection de la disponibilité d'une instruction.]] ==Les ''schedulers'' basées sur une mémoire associative== Les processeurs modernes utilisent une mémoire associative pour le ''scheduler''. Les mémoires associatives ont été abordées il y a quelques chapitres, mais faisons quelques rappels. Les mémoires associatives servent à accélérer la recherche de données dans un ensemble. Or, un ''scheduler'' vérifie régulièrement si chaque entrée est prête. Il s'agit d'un processus de recherche d'une instruction qui respecte une condition bien précise dans la mémoire, ce qui fait que les mémoires associatives sont donc tout indiquées. Comme vous le savez, les signaux de commande d'une instruction sont propagés avec celle-ci dans le pipeline, le nom du registre de destination ne faisant pas exception. Le nom de registre est envoyé à le ''scheduler'' lors de l'écriture du résultat dans les registres. S'il y a correspondance, l'opérande est disponible et son bit de disponibilité est mis à 1. On peut adapter cette méthode pour tenir compte du contournement assez simplement. [[File:Détection des dépendances par propagation du registre de destination.png|centre|vignette|upright=2|Détection des dépendances par propagation du registre de destination.]] En conséquence, le circuit de détection des dépendances est constitué d'un grand nombre de comparateurs : un par champ « nom de registre » dans chaque entrée. La logique d'éveil/''wake up'' regroupe tous les comparateurs, la logique de sélection est un circuit situé en-dehors de la mémoire associative. Les entrées sont dans la mémoire associative elle-même. [[File:Gestion des bits de validité.png|centre|vignette|upright=2|Gestion des bits de validité.]] L'implémentation la plus simple est celle du schéma précédent, où on utilise une mémoire associative unique. Une version plus élaborée sépare le ''scheduler'' en deux parties : une mémoire qui mémorise les registres des opérandes, une autre mémoire pour le reste. La mémoire pour les registres opérandes est la mémoire associative proprement dite, c'est elle qui est associée aux comparateurs, à la logique de ''wake-up''/réveil, etc. Par contre, l'autre mémoire est une mémoire RAM simplifiée, qui mémorise les informations qui n'ont pas besoin des comparateurs. L'opcode de l'instruction est là-dedans, par exemple. le ''scheduler'' est donc une sorte de mémoire associative améliorée. Il se trouve que c'est aussi le cas du ROB. Et il est possible de fusionner le tampon de ré-ordonnancement avec le ''scheduler'' dans une structure unique. La différence avec un ''scheduler'' normal est que les entrées sont libérées non pas quand l'instruction est exécutée/émise, mais quand elle termine son exécution et quitte le ROB. le ''scheduler'' incorpore des bits dans chaque entrée, pour savoir si la µops associée a été émise et est en cours de traitement dans les ALUs. La méthode a notamment été utilisée sur les processeurs d'architecture K6 d'AMD. Le tout donnait une structure appelée le '''DRIS''' (''deferred scheduling register renaming instruction shelf''). Les processeurs PA 8000 de HP étaient aussi vraisemblabment dans ce cas, aussi. ===Les optimisations de la consommation d'énergie : la désactivation des portions inutilisées=== Le problème avec des ''scheduler'' de ce type est leur forte consommation énergétique, ainsi que le grand nombre de portes logiques utilisées, qui deviennent prohibitifs pour des ''scheduler'' un peu grosses. Pour résoudre ce problème, certains ont optimisé les comparateurs. D'autres ont tenté de profiter du fait que la majorité des bits dans les entrées sont composés de zéros. Bref, les optimisations purement matérielles sont légion. Une première solution est de désactiver les entrées qui sont inutilisées, vides, sans instruction. Pour cela, on fait précéder les comparateurs par un circuit qui les connecte ou déconnecte des lignes de bit. Le circuit est commandé par le bit ''empty'' qui indique si une entrée est vide ou non. L'avantage est que la consommation d'énergie de le ''scheduler'' devient alors proportionnelle au nombre d'entrées non-vides, et non au nombre d'entrées total. Du moins, en apparence, les entrées non-utilisées doivent quand même être alimentées pour fonctionner, mais l'activité de comparaison disparait dans les entrées vides. Il est possible d'étendre cette technique aux entrées dont les opérandes sont prêts. Les gains sont généralement assez bons, avec une réduction de consommation variant entre 30 et 50%, avec une implémentation très simple et très économe en circuits. Une autre solution, assez simple à mettre en place, consiste à désactiver une partie de le ''scheduler'' sin elle est inutilisée. Pour cela, il faut segmenter le ''scheduler'' avec la technique du ''wire partitionning''. Pour rappel, un ''scheduler'' est une mémoire associative. Et comme toute mémoire associative, elle contient des fils, les lignes de bit, qui relient les entrées/sorties à toutes les cellules mémoire. Plus une ligne de bit est longue, plus elle consomme d'énergie et plus le temps de lecture/écriture est long. L'idée est de segmenter les lignes de bits en plaçant des répéteurs qui recopient la tension d'un segment au suivant. Les répéteurs sont des tampons trois-états, ce qui permet de déconnecter les portions inutilisées de la ligne de bit. Ce faisant, le ''scheduler'' est découpée en segments, qui peuvent être désactivés si besoin. S'il y a peu d'instructions chargées dans le ''scheduler'', les portions inutilisées sont désactivées. La technique marche d'autan mieux si les instructions sont compactées au début de le ''scheduler''. [[File:Wire partitionning.png|centre|vignette|upright=2|Wire partitionning]] Tout le problème est de savoir quelles portions désactiver. La technique est assez simple si le ''scheduler'' est compactée, à savoir si toutes les instructions sont régulièrement regroupées au début de la mémoire CAM. Mais même avec cette optimisation, la décision de désactiver une portion de le ''scheduler'' n'est pas à prendre à la légère. Il ne faut pas désactiver une portion contenant des instructions pouvant être émise sous peu. La décision dépend de paramètres variés : proportion d'entrée vides, quantité d'entrées récemment activées/désactivées récemment, présences d'entrées avec un ''match'' d'opérandes récent, etc. Il est important de préciser que les techniques en question fonctionnent aussi sur les autres types de ''scheduler'', qui ne sont pas basées sur des mémoires associatives. Nous allons voir celles-ci dans la suite du chapitre, mais gardez à l'esprit que ces optimisations, à savoir désactiver les entrées vides/prêts et partitionner le ''scheduler'', sont des optimisations générales qui marchent avec presque tout. ===L'ajout d'une FIFO pour les instructions déjà prêtes à l'émission=== D'autres techniques permettent de réduire aussi bien le cout en circuits que la consommation d'énergie de le ''scheduler''. L'idée est d'utiliser une mémoire associative quand elle est réellement nécessaire, mais d'utiliser un ''scheduler'' "normale" dès que possible. La méthode la plus simple tient compte du fait que certaines µopsont déjà toutes leurs opérandes de disponibles à l'émission, mais doivent quand même être mises en attente, parce que l'ALU adéquate est occupée, parce que des dépendances WAW/WAR sont encore là, ou pour tout autre raison. Dans ce cas, elles sont mises en attente non pas dans le ''scheduler'', mais dans une mémoire FIFO toute simple. L'idée est qu'au lieu d'avoir une énorme mémoire associative pour le ''scheduler'', on déplace quelques entrées dans une petite FIFO annexe. Le résultat est un gain d'énergie et de circuits, au prix d'une perte de performance mineure. La perte de performance en question se manifeste si aucune instruction n'a ses opérandes de prêtes à l'émission : le programme n'utilise pas la FIFO et voit alors un ''scheduler'' plus petite. Une amélioration de cette technique tient compte du fait que certaines instructions sont dans un cas intermédiaire. Elles ont déjà un opérande de prête lors de l'émission, mais pas l'autre. Le nombre d'opérandes varie suivant l’instruction : certaines n'ont besoin que d'un seul opérande. De plus, il arrive qu'une opération tout juste décodée ait déjà un ou plusieurs de ses opérandes de prêts. Cette constatation permet d'éviter d'utiliser des comparateurs pour les opérandes déjà prêts. Par exemple, on peut parfaitement utiliser trois ''scheduler'' : * une pour les instructions dont tous les opérandes sont prêts, mais qui sont quand même mises en attente, sans comparateur ; * une pour les instructions dont un seul opérande manque, qui n'utilise qu'un comparateur par entrée ; * une pour les instructions dont deux opérandes manquent à l'appel, qui utilise deux comparateurs par entrée. C'est beaucoup plus économique que d'utiliser une seule grosse ''scheduler'' qui contiendrait autant d'entrées que les trois précédentes réunies, avec deux comparateurs par entrée. Certains sont même allés plus loin, et ont proposé de supprimer le ''scheduler'' avec deux opérandes par entrée. Les instructions dont deux opérandes sont inconnus au décodage sont stockées dans le ''scheduler'' pour instructions avec un comparateur par entrée. Un circuit de prédiction se charge alors de prédire l'opérande manquant, cette prédiction étant vérifiée plus loin dans le pipeline. Il serait cependant étonnant qu'une telle proposition ait donné lieu à la moindre implémentation réelle. ===Les optimisations de la consommation d'énergie avancées=== D'autres chercheurs ont conservé un ''scheduler'' unique, avec autant de comparateurs par entrée qu'il y a d'opérandes possibles par instruction. Simplement, le processus de détection des opérandes prêts est légèrement ralenti : on ne vérifie qu'un opérande par cycle. Pour vérifier les deux opérandes d'une entrée, on doit attendre deux cycles. Enfin, certains chercheurs ont proposé des ''scheduler'' segmentées. Les instructions circulent à chaque cycle d'un segment vers le suivant : en conséquence, certains segments conservent les instructions les plus anciennes, un autre les instructions les plus jeunes, etc. Seul le denier segment, celui qui contient les instructions les plus vielles, peut émettre une instruction : la détection des opérandes se fait seulement dans le dernier segment, qui contient les instructions les plus anciennes. On économise ainsi beaucoup de comparateurs. Certains chercheurs ont tenté de pipeliner l'étape de sélection des opérandes, ainsi que l'étage d'arbitrage. Mais en faisant cela, il faut plusieurs cycles pour détecter qu'une instruction a ses opérandes prêts, ce qui pose problème face à de nombreuses dépendances RAW. Pour éviter de trop perdre en performances, certains chercheurs ont décidé d'utiliser des techniques pour prédire quelles seront les instructions dont les opérandes seront bientôt prêts. Si détecter qu'une instruction est prête prend n cycles, le processeur devra tenter de prédire la future disponibilité des opérandes n cycles en avance pour obtenir des performances optimales. ===Remplacer la mémoire associative par une RAM=== Une autre optimisation possible est de remplacer le ''scheduler'' par une mémoire RAM, dont chaque mot mémoire correspondrait à une entrée. Une telle optimisation permet en théorie de se passer des comparateurs associés à chaque entrée, mais au prix de l'ajout de circuits annexes potentiellement couteux. La première de ces techniques, la '''recherche directe par étiquette''' (direct tag search) fut créée par Weiss et son collègue Smith. Ils cherchaient à améliorer l'algorithme de Tomasulo, un algorithme qu'on expliquera dans quelques chapitres. Rappelons que chaque instruction produit un résultat, qui devra être rapatrié dans une ou plusieurs entrées de le ''scheduler''. L'optimisation de la recherche directe par étiquette fonctionne dans le cas où le résultat de l'instruction n'est utilisé que par une seule entrée, et pas plusieurs. Le principe est simple : chaque champ « opérande » d'une entrée est adressable via le nom de registre de cet opérande. Pour faire le lien entre entrée et nom de registre, la recherche directe par étiquette ajoute une table de correspondances matérielle, une mémoire RAM qui mémorise les adresses des champs « opérande » des entrées. Les adresses envoyées dans cette mémoire sont les noms de registres des résultats. Lors de l'émission, la table de correspondances est mise à jour. Les numéros des champs « opérande » réservés lors de l'émission sont mémorisés dans les mots mémoire qui correspondent aux deux registres sources. Toutefois, une petite vérification est faite lors de l'émission : s'il y a déjà une correspondance dans la table pour un registre source, alors une autre instruction compte lire ce registre. Pour éviter d'écraser les données de l'instruction précédente dans la table de correspondances, l'émission de l'instruction est bloquée. [[File:Recherche directe par étiquette.png|centre|vignette|upright=2|Recherche directe par étiquette.]] ==Les ''schedulers'' avec préplanification== Avec la '''préplanification''' (''prescheduling''), le ''scheduler'' est composée de mémoires FIFO dans lesquelles les instructions sont triées dans l'ordre d'émission. Il n'y a pas de logique d’émission proprement dite, celle-ci se bornant à vérifier si l'instruction située au début de la FIFO peut s’exécuter. Par contre, le préplanificateur détecte les dépendances et en déduit où insérer les instructions dans le tampon d'émission, à l'endroit le plus adéquat. [[File:Préplanification.jpg|centre|vignette|upright=2|Préplanification.]] ===L'usage de FIFO multiples=== La technique de préplanification la plus simple utilise plusieurs FIFO. Quand une instruction a une dépendance avec une autre instruction, les deux sont placées dans la même FIFO. Pour cela, le préplanificateur détecte les chaines d'instructions dépendantes, et place les instructions dans la FIFO adéquate. A chaque cycle, l'unité d'émission lit une micro-opération dans chaque FIFO et vérifie si elle peut l'émettre. Si la micro-opération n'a pas ses opérandes disponibles, ou qu'une dépendance structurelle survient, alors la FIFO est bloquée. La micro-opération attend que la dépendance soit résolue, bloquant toutes les instructions précédentes. Mais les autres FIFO ne sont pas bloquées, laissant de la marge de manœuvre. [[File:Préplanification par FIFO multiples.png|centre|vignette|upright=1.5|Préplanification par FIFO multiples.]] ===La technique du tampon trié=== La technique du '''tampon trié''' trie les instructions selon le temps d'attente avant leur exécution. Les instructions qui sont censées s’exécuter bientôt sont insérées au tout début de la FIFO, tandis que les instructions qui s’exécuteront dans un long moment sont insérées vers la fin. Là encore, l'unité d'émission lit une micro-opération dans la FIFO, et détermine si elle peut être émise. Si une dépendance survient, l'émission est retardée, et la FIFO est bloquée. [[File:Préplanification par tampon trié.png|centre|vignette|upright=1.5|Préplanification par tampon trié.]] La technique a cependant quelques problèmes assez importants. Le premier problème est que la FIFO est bloquée lorsqu'une micro-opération ne peut être émise. Le second problème est que le temps avant exécution n'est pas toujours connu, notamment pour les instructions d'accès mémoire. Et cela se répercute sur les instructions dépendantes de celles-ci. Pour résoudre ce genre de problèmes, l'usage d'un pipeline à ''replay'' est possible, et est même l'une des meilleures solutions possible, malgré ses défauts. L'idée est que les lectures sont pré-planifiées en supposant qu'elles font un succès de cache L1. Si la prédiction est fausse, la lecture est ré-exécutée plusieurs cycles plus tard, en supposant qu'elle fait un succès dans le cache L2, et ainsi de suite. Elle est alors ré-insérée dans la FIFO, elle est pré-planifiée une seconde fois. Il en est de même si une micro-opération ne peut pas être émise : il suffit de la réinsérer dans la FIFO au bon endroit, en attendant que ses dépendances soient résolues. Ainsi, l'instruction fautive ne bloque pas le ''scheduler'', et retente sa chance autant de fois qu'il le faut. [[File:Préplanification par fenêtre d’instruction scorebarodée.png|centre|vignette|upright=1.5|Préplanification par ''scheduler'' scorebarodé.]] Une autre solution utilise deux ''schedulers'' : une FIFO gérée par la préplanification, et une vraie ''scheduler'' pour les instructions dont le temps d'attente ne peut pas être déterminé. Il est possible de mettre cette dernière avant la préplanification, afin de gérer les temps d'attente des instructions d'accès mémoire. Quand le temps d'attente d'une lecture devient connu, ses instructions dépendantes sont gérées avec préplanification. [[File:Préplanification avec fenêtre d’instruction.png|centre|vignette|upright=2.5|Préplanification avec ''scheduler''.]] ===Les ''scheduler'' avec allocation temporelle statique=== L''''allocation temporelle statique''' correspond à une technique utilisée sur les processeurs Cuzco de l'entreprise Condor. La technique en question a été présenté en 2025, mais des idées similaires ont été présentées dans la littérature académique. Elle ressemble beaucoup aux techniques de pré-planification, avec cependant quelques différences. L'idée est simple : le processeur dispose de plusieurs ''scheduler'', qui mettent en attente les micro-opérations. Lors de l'étape de renommage de registres, le processeur détermine dans combien de cycles d'horloge la micro-opération sera prête pour exécution. La micro-opération est alors mise en attente durant ce nombre de cycles, dans les ''scheduler'', puis est émise une fois ce nombre de cycles écoulés. Ce faisant, les ''scheduler'' n'ont pas besoin de détecter la disponibilité des opérandes à chaque cycle, pour chaque micro-opération en attente. Le ''timing'' de l'émission des micro-opérations est décidé à l'avance. L'implémentation exacte n'est pas connue, mais plusieurs solutions sont imaginables. Par exemple, le ''scheduler'' peut simplement être composée de plusieurs mémoires de petite taille, chacune contenant les micro-opérations destinées à être exécutées dans N cycles, N étant différent pour chaque mémoire. Une autre solution, plus réaliste, utilise un ''scheduler'' dans laquelle la micro-opération est couplée à des champs pour les opérandes, et un champ compteur. Le champ compteur est initialisé avec le nombre de cycles à attendre, et est décrémenté à chaque cycle d'horloge. Quand il atteint zéro, la micro-opération est émise. Vous remarquerez que la méthode ne marche que si toutes les micro-opérations prennent un nombre fixe de cycles d'horloge. Et autant c'est le cas pour les micro-opérations arithmétiques ou logiques, autant les accès mémoire ne rentrent pas dans ce cadre. En théorie, on ne sait pas combien de temps prendra un accès mémoire. Et cette incertitude se répercute sur les instructions dépendantes d'un accès mémoire. Pour éviter cela, le processeur réutilise un pipeline à ''replay'' tel que vu dans le chapitre précédent. L'unité de renommage de registre suppose que tout accès mémoire fait un succès de cache L1, et décide des ''timings'' d'émission sous cette hypothèse. Si une lecture subit un défaut de cache, elle est ré-exécutée, de même que toutes les instructions dépendantes. Pour cela, le registre de destination de la lecture est marqué comme invalide, grâce à un bit spécifique attaché au registre. Toute instruction qui lit un opérande invalide est elle aussi ré-executée de zéro. Pour simplifier, l'unité d'émission ressemble à une unité d'émission dans l'ordre, avec un registre de disponibilité, qu'on aurait amélioré pour aller au-delà de la simple détection des dépendances d'instruction. Pour déterminer les ''timings'' d'émission, à savoir quand émettre une micro-opération, le processeur utilise une unité d'émission à deux étages. Le premier étage est appelé le ''register scoreboard'', le second étage est appelé la ''Time Ressource Matrix''. Les deux étages communiquent entre eux, comme on va le voir, et leurs noms donnent une idée de ce qu'ils font. Le premier étage gère les dépendances de registres, le second gère les dépendances structurelles. Le premier étage est un registre de disponibilité amélioré, qui gère les dépendances de registre. Cet étage sait quand tel registre sera écrit, et donc que l'opérande écrit dedans sera disponible à partir de tel cycle d'horloge. Il le sait car l'étage suivant l'aura prévenu, mais laissons cela de côté pour le moment. Quand une micro-opération rentre dans cet étage, il vérifie les dépendances avec les registres et les micro-opérations antérieures. Vu qu'il sait quand les registres seront disponibles, il peut déterminer quand l'instruction pourra s'exécuter. Par exemple, si une micro-opération lit les deux registres R7 et R15, qui sont disponibles respectivement dans 5 et 7 cycles, le premier étage sait que la micro-opération devra attendre 7 cycles. Mais tout cela ne suffit pas à déterminer quand émettre une micro-opération. En effet, il fait aussi gérer les dépendances structurelles, ce qui est le boulot du second étage. Le second étage utilise pour cela une ''Time Ressource Matrix'', qui mémorise l'occupation de diverses "ressources", pour les 256 cycles d'horloge à venir. Les ressources en question sont les ports de lecture/écriture du banc de registre, les ALUs utilisées, si la micro-opération utilise l'unité mémoire, etc. Le second étage prend en entrée une micro-opération, détermine quelles "ressources" elle utilise, puis regarde leur disponibilité. Elle détecte alors les dépendances structurelles et détermine alors quand peut s'exécuter la micro-opération. Elle peut retarder l'émission de quelques cycles, si une dépendance structurelle est détectée. Une fois sortie du second étage, on sait quand la micro-opération va être émise, à quel cycle précisément. Et vu que la durée de l'instruction est fixe, on sait quand cette micro-opération va se terminer, quand son résultat sera disponible. Cela permet de mettre à jour la ''Time Ressource Matrix'', pour préciser que le port d'écriture sera occupé à tel moment. De plus, cette information est transmise au premier étage, qui sait alors quand est enregistré le résultat dans le registre de destination. C'est comme cela que le premier étage sait quand un registre est disponible : le second étage le prévient, quand il émet une instruction ! La ''Time Ressource Matrix''mémorise l'occupation des "ressources" pour les 256 cycles d'horloge à venir. Cependant, elle ne vérifie pas les dépendances pour les 256 cycles suivants. Quand elle reçoit une micro-opération, elle teste les dépendances structurelles pour seulement les 8 prochains cycles maximum. Si la micro-opération ne peut pas être émise pendant ces 8 cycles, le pipeline est bloqué, un ''pipeline stall'' est émis. Pour être plus précis, vu que le processeur peut décoder 8 micro-opérations en même temps, cela permet de ne consulter que 64 cycles d'horloge sur les 256. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les premiers processeurs Intel | prevText=Les premiers processeurs Intel | next=Le renommage de registres | nextText=Le renommage de registres }} </noinclude> 0pefxbliketmrgqkognmrhyjl8jwwf4 773686 773685 2026-09-29T23:27:35Z Mewtow 31375 773686 wikitext text/x-wiki Dans les chapitres précédents, nous avons parlé des techniques dites d''''émission dans l'ordre'''. L'idée est d’exécuter une nouvelle micro-opération à chaque cycle, dans des unités de calcul séparées. Les instructions sont émises consécutivement, mais les instructions s’exécutent en parallèle dans des unités de calcul séparées. Par contre, quand l'unité d'émission ne peut pas émettre une instruction, elle bloque tout le pipeline. Les instructions qui suivent sont elles aussi bloquées, elles doivent attendre leur tour, même si elles sont en capacité de s'exécuter. Les techniques d'exécution dans le désordre que nous allons voir dans ce chapitre corrigent ce point précis. Elles sont dites à '''émission dans le désordre'''. Elles se distinguent des précédentes sur un point précis : quand l'unité d'émission bloque l'émission d'une instruction, les instructions suivantes peuvent poursuivre. L'émission des instructions peut donc se faire dans le désordre, dans le sens où une instruction peut être émise alors qu'une instruction précédente ne l'est pas encore. Mais avant de poursuivre, quelques point niveaux terminologie : * L'émission dans le désordre est un terme parlant et assez précis. Malheureusement, la terminologie la plus utilisée par d''''exécution dans le désordre'''. Et nous utiliserons ce terme dans la suite du cours, histoire de ne pas trop dévier de la nomenclature habituelle. * Nous utiliserons parfois l'abréviation OOO pour parler d'exécution dans le désordre. L'abréviation est celle de ''Out Of Order Execution''. * Nous utiliserons aussi l'abréviation ''µop'' pour parler de micro-opération, ''µops'' au pluriel pour parler de plusieurs micro-opérations, ou des micro-opérations en général. L'exécution dans le désordre ne gère en effet que des µops, elle se situe après l'étape de décodage. Pour décrire comment est implémentée l'émission dans le désordre, il faut commencer par parler des processeurs sans. Les processeurs sans exécution dans le désordre ont une unité d'émission qui bloque tout le pipeline dès qu'une µop ne peut pas être émise. Pour limiter l'impact de ce blocage, quelques rares processeurs incorporent une '''file de micro-opération''', une mémoire FIFO qui met en attente les µops. Vu que c'est une mémoire FIFO, les µops sont émises dans l'ordre, à savoir l'ordre d'ajout, dans l'ordre de décodage. Le schéma ci-dessous illustre une telle file d'attente couplée à un ''scoreboard''. L'exécution dans le désordre améliore la file de µops sur un point : ce n'est plus une mémoire FIFO. Les µops sont insérées dans l'ordre, mais peuvent sortir dans le désordre (être émises dans le désordre). La file de µops devient alors un '''''scheduler''''', terme anglais que je ne compte pas traduire. Un terme équivalent est '''''scheduler''''', terme traduit directement de l'anglais ''instruction Window''. Terme assez trompeur, car elles mettent en attente des µops, pas des instructions. [[File:Différence file µops et fenêtres instruction.png|centre|vignette|upright=2|Différence file µops et ''schedulers'' ]] Le ''scheduler'' émet une µop dès que ses opérandes sont disponibles. Par disponible, on veut dire présent soit dans le réseau de contournement, soit dans les registres. Le ''scheduler'' détecte automatiquement quand les opérandes d'une µop sont disponibles, grâce à une unité d'émission intégrée. L'unité d'émission et la file d'attente de µops sont fusionnés ensemble, dans un seul circuit, mais nous allons dire qu'ils sont conceptuellement séparés pour le moment. À chaque cycle, l'unité d'émission consulte les µops en attente pour détecter lesquelles peuvent s'exécuter. Le ''scheduler'' est spécialement être conçue pour, c'est une sorte de mémoire associative très complexe, comme on le verra dans ce qui suit. [[File:OOO Issue.png|centre|vignette|upright=2.5|Exécution dans le désordre avec un ''scheduler'']] Une fois qu'une µop sort du décodeur d'instructions, elle est ajoutée en parallèle dans le ''scheduler'' et le ROB. La raison est que les µops quittent le ''scheduler'' dans le désordre, et qu'elles doivent être remises en ordre par la suite. Le ROB s'occupe de cette remise en ordre, mais il a besoin de savoir dans quel ordre les µops sont censées être, et cet ordre est celui du décodage. Aussi, pour remplir le ROB, la seule opportunité est en sortie de l'unité de décodage. Dans le cas où une instruction est décodée en plusieurs micro-opérations, elles sont toutes insérées en même temps dans le ''scheduler'' et le ROB, en tenant compte de leur ordre. L'implémentation la plus "simple" de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Les µops décodées sont accumulées dans le ''scheduler'', où elles attendent leur tour. Bien que simple en apparence, cette implémentation cache une complexité très importante, liée aux accès mémoire. Les micro-opérations mémoire sont à part des autres, pour ce qui est de leurs dépendances de données. Non seulement elles ont des dépendances de registre, mais elles sont aussi des dépendances d'adresse. Par exemple, deux écritures peuvent utiliser deux registres d'adresse différents, mais ceux-ci peuvent contenir la même adresse. Et autant on peut détecter les dépendances de registre lors de l'émission, autant c'est plus compliqué avec les dépendances d'adresse. De plus, rappelons que si les lectures peuvent s'exécuter dans le désordre, les écritures doivent s'exécuter dans l'ordre, ou du moins en donner l'illusion. Pour cela, le processeur remet les écritures dans l'ordre avec une sorte de mini-ROB intégré à l'unité mémoire, appelée la file d'écriture. Elle complémente le ROB, qui lui ne gère que les écritures dans les registres, mais les deux collaborent. La file d'écriture envoie une écriture à la mémoire RAM quand le ROB lui dit que c'est bon, les instructions précédentes sont terminées ''dans l'ordre du programme''. Les processeurs modernes ajoutent des techniques d'exécution dans le désordre des accès mémoire, mais nous les verrons dans un chapitre dédié. Elles permettent d'utiliser un ''scheduler'' unique, qui mémorise aussi les µops mémoire. Si elles sont mises en place, l'unité mémoire n'a pas besoin de file de µops séparée. Les dépendances de registre sont traitées par le ''scheduler'', alors que les dépendances d'adresse sont gérées par l'unité mémoire gére les dépendances d'adresse. Elle utilise pour cela des techniques de '''''désambiguïsation mémoire''''', qui auront droit à un chapitre dédié. [[File:Processeur avec exécution dans le désodre des accès mémoire.png|centre|vignette|upright=2|Processeur avec exécution dans le désodre des accès mémoire]] Les processeurs assez anciens n'autorisaient pas d'exécution dans le désordre des accès mémoire. Concrètement, les accès mémoire devaient se faire dans l'ordre, mais les autres µops pouvaient être exécutées dans le désordre. Pour garantir l'ordre des µops mémoire, les µops mémoire ne passent pas par le ''scheduler'', mais sont accumulées dans une file de micro-opérations séparée. Après le décodage, les µops sont réparties soit dans la file de µops mémoire, soit dans le ''scheduler''. Le décodeur classe les µops suivant que ce sont des µops mémoire ou non, et les envoient à la bonne destination. Dans ce chapitre, on supposera que c'est cette solution qui est utilisée. [[File:Processeur avec émission dans l'ordre des accès mémoire.png|centre|vignette|upright=2|Processeur avec émission dans l'ordre des accès mémoire]] ==L'implémentation d'un ''scheduler'' : généralités== Un ''scheduler'' est une mémoire qui mémorise des micro-opérations. Elle est cependant plus complexe qu'une mémoire RAM ou qu'une FIFO et ressemble un petit peu à une mémoire cache. Elle dispose d'un port d'écriture et d'un port de lecture, au minimum. Le port d'écriture permet à l'unité de décodage d'insérer une micro-opération dedans, d'ajouter la micro-opération qui vient d'être décodée. Aussi, il est appelé le '''port de décodage'''. Si une instruction machine est décodée en plusieurs micro-opérations, deux possibilités. La première est de les insérer un par un, ce qui fait qu'on peut se contenter d'un seul port d'écriture. L'autre possibilité est de les ajouter en même temps, ce qui demande plusieurs ports d'écriture. Le port de lecture sert à émettre une micro-opération, ce qui fait qu'il est appelée le '''port d'émission'''. Dans ce chapitre, on part du principe que le ''scheduler'' ne peut émettre qu'une seule micro-opération à la fois. Dans ce cas, le ''scheduler'' a un seul port de lecture. Mais nous verrons dans quelques chapitres qu'il existe des processeurs dits superscalaires, qui sont capables d'émettre plusieurs micro-opérations par cycle. Un processeur superscalaire a avoir un port d'émission par unité de calcul, ce qui fait beaucoup plus. Les ''schedulers'' sont composées d''''entrées''', des mots mémoire qui stockent une micro-opération. Une micro-opération tout juste décodée réserve une entrée et la libère dès qu'elle est envoyée aux unités de calcul. Une entrée contient l'opcode (les signaux de commande à envoyer à l'ALU), le registre de destination du résultat, les registres de chaque opérande, et éventuellement des signaux de commande en plus. De plus, chaque opérande est couplée à un bit de disponibilité, qui indique si elle est disponible. Quand un opérande est écrit dans les registres, le bit de présence correspondant est mis à jour. Enfin, chaque entrée possède un bit ''empty'' qui indique si elle est vide, cette information étant utile pour réserver des entrées. [[File:Entrée d'une station de réservation - sans les tags.png|centre|vignette|upright=3|Entrée d'un ''scheduler'']] ===Les stations de réservation=== Les '''stations de réservation''' sont des ''scheduler'' particulières, qui sont capables de mémoriser les opérandes des micro-opérations. Les entrées des stations de réservation sont identiques à celle des autres ''scheduler'', si ce n'est que les opérandes de la micro-opération sont enregistrés directement dans des champs séparés. Il y a deux champs, un par opérande, pour stocker l'opérande elle-même, lue depuis les registres ou obtenue via le réseau de contournement. Notons que les champs pour les opérandes viennent en plus des champs pour les noms de registres, encore que les deux peuvent être fusionnés si on veut optimiser le tout. [[File:Entrée d'une station de réservation.png|centre|vignette|upright=3|Entrée d'une station de réservation.]] Précisons que la terminologie n'est pas très fiable. Les termes "''scheduler''" et "station de réservation" ne regroupent pas du tout la même chose d'un papier de recherche à l'autre, d'un bouquin à l'autre, d'un chercheur à l'autre, d'un ingénieur à l'autre, d'un professeur à l'autre. Le terme initial vient pourtant de l'article original sur l'algorithme de Tomasulo, où il désignait un ''scheduler'' associée à une unité de calcul précise. Mais le terme a ensuite été réutilisé, ce qui fait que certains processeurs avec plusieurs unités de calcul sont décrits comme ayant une unique station de réservation. En bref : c'est le bazar ! Mais nous en reparlerons dans le chapitre sur le renommage de registres, car c'est la place idéale pour les aborder. Toujours est-il que j'ai fait le choix de confondre les concepts de ''scheduler'' et de station de réservation avec les concepts de '''lecture avant émission''' et de '''lecture après émission'''. La différence entre les deux est que les registres sont lus après émission avec un ''scheduler'', avant avec des stations de réservation. Dans le cas "avant émission", les opérandes sont mémorisés dans la station de réservation. Et cette différence a une influence sur le pipeline du processeur, le banc de registres et tout ce qui s'ensuit. Un désavantage de la lecture avant émission est qu'il faut stocker les opérandes après lecture, ici dans les stations de réservation. Mais un avantage est que le banc de registre a besoin de moins de ports de lecture, car une bonne partie des opérandes sont fournies par le système de contournement. Nous verrons cela dans le détail dans le chapitre sur les processeurs superscalaires. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Lecture après émission.]] [[File:Read Before Issue.png|centre|vignette|upright=2.5|Lecture avant émission.]] ===La logique d'éveil et de sélection=== Dans le cas qui va suivre, on suppose que le processeur ne peut émettre qu'une micro-opération à la fois. Chaque cycle, une micro-opération est sélectionnée et est envoyée dans le chemin de données, soit à une ALU, soit à une unité d'accès mémoire. La sélection d'une micro-opération est effectuée par l'unité d'émission intégré au '''''scheduler'''''. Elle gère la disponibilité des opérandes et la disponibilité des unités de calcul adéquate. Le choix de la micro-opération émise doit être le plus pertinent possible, pour des raisons de performances. Pour le premier point, l'unité d'émission détermine quelles micro-opérations sont candidates pour l'émission. Les '''micro-opération candidates''' sont celles dont tous les opérandes sont prêts. Le processeur contient un circuit qui détecte les micro-opérations candidates : la '''logique d’éveil''' (''wake-up logic''). Une fois que la logique d'éveil a fait son travail, une micro-opération est choisie pour s’exécuter en fonction de la disponibilité des unités de calcul adéquates. Ce rôle est dévolu à un circuit qu'on appelle la '''logique de sélection''', ou ''select logic''. [[File:Fonctionnement complet de la logique d’émission.jpg|centre|vignette|upright=1.5|Fonctionnement complet de la logique d’émission.]] La logique de sélection doit gérer le fait que les unités de calcul du processeur ne sont pas toutes identiques. Déjà, un processeur a généralement des unités séparées pour les µops entières et flottantes, des unités spécialisées dans les accès mémoire, parfois des unités spécialisées pour les branchements. Une micro-opération doit être attribuée à la bonne unité de calcul, on ne doit pas envoyer une µop entière dans une unité de calcul flottante. De plus, parmi les unités de calcul entières, toutes ne sont pas identiques. Par exemple, il est fréquent d'avoir plusieurs unités de calcul spécialisées dans les opérations simples (additions, soustractions, opérations logiques), mais une seule unité pour les multiplications/divisions, une seule unité spécialisée pour les décalages/rotations, etc. Là encore, allouer la bonne micro-opération à la bonne ALU est complexe. Plus les unités de calcul sont hétérogènes, plus la logique de sélection est compliquée. Les logiques d'éveil comme de sélection sont assez complexes. Comme on le verra plus bas, la logique de sélection la plus simple, qui gère une seule unité de calcul, est basée sur un encodeur à priorité, couplé à d'autres circuits. Et pour gérer plusieurs ALUs, il faut mettre des encodeurs en cascade. Le résultat est que même en prenant une logique de sélection simple, elle sera assez lente et gourmande en circuits. Aussi, la logique de sélection met souvent un cycle d'horloge entier pour faire son travail, elle a son propre étage de pipeline attribué. La logique d'éveil est dans le même cas, ce qui fait qu'émettre une micro-opération demande deux cycles d'horloge. Le défaut est que cela rajoute des cycles d'horloges entre le ''scheduler'' et l'ALU, ce qui complique la gestion du pipeline. Ces cycles de retard sont à prendre en compte au moment d'émettre les micro-opérations, le ''scheduler'' doit en tenir compte pour des performances optimales. Sans tenir compte de ces cycles de retard, les micro-opérations arrivent en retard de quelques cycles à l'ALU, cycles de retard durant lesquels l'ALU n'a pas fait de calcul et a été sous-utilisée, sans compter que le système de contournement n'est pas utilisé au mieux. Et le problème est encore plus important sur les processeurs avec des stations de réservation, qui utilisent la "lecture après émission" : cela rajoute un cycle d'horloge en plus, un temps de retard en plus. ===La logique d'éveil : l'émission anticipée=== La logique d'éveil doit tenir compte du fait qu'il y a plusieurs étages entre l'émission et l'exécution sur une unité de calcul. Par exemple, un processeur a souvent entre un et à cinq étages entre la file d'attente et les unités de calcul. Il faut lire les registres, gérer le contournement, et cela peut prendre quelques cycles d'horloge. Sur le Pentium 4, on trouve 6 étages entre le ''scheduler'' et l'entrée de l'ALU. Si les micro-opérations sont émises quand les opérandes sont disponibles, il y aura un délai de quelques cycles avant qu'elles atteignent l'ALU. Alors qu'idéalement, on souhaiterait que la micro-opération atteigne l'ALU dès que ses opérandes sont disponibles, pour profiter des techniques de contournement. Pour cela, la logique d'éveil émet les micro-opérations quelques cycles en avance pour qu'elles arrivent au bon moment. Il s'agit d'une technique d''''émission anticipée''', dont nous avions parlé dans le chapitre sur le contournement. : Il faut noter que le problème se pose plus avec des ''schedulers'' qu'avec des stations de réservation. Les premières ont un étage en plus entre émission et ALU, vu qu'il faut lire des registres après l'émission. L'émission anticipée demande d'émettre un signal d'éveil en avance de quelques cycles, pile au bon moment. Par exemples, si on a deux étages entre l'ALU et l'unité d'émission, le signal de réveil sera généré deux cycles avant que le résultat soit effectivement calculé. L'implémentation varie, mais deux solutions sont possibles. La première est de générer le signal d'éveil dans l'ALU, ce qui n'a de sens que pour les opérations comme les multiplications ou les divisions, qui prennent plusieurs cycles. Une autre technique génère le signal de réveil dans une structure centralisée, spécialisée dans la génération des signaux d'éveil. L'unité de composée d'un registre à décalage par registre. Imaginons qu'une micro-opération est émise, que cette micro-opération mette N cycles à s'exécuter, et qu'elle écrive dans un registre de destination. L'unité sélectionne alors le registre à décalage associé au registre de destination, et met le bit numéro N à 1. Le registre décalé d'un cran à chaque cycle. Quand le bit sortant est un 1, alors le signal de validité pour l'opérande est généré. L'émission anticipée marche bien si la micro-opération a une durée fixe, connue à l'avance. Et autant c'est le cas pour les micro-opérations arithmétiques et logiques, autant ce n'est pas le cas pour les accès mémoire. Les accès mémoire ont une latence variable : quelques cycles pour un succès de cache, plusieurs dizaines de cycles pour un défaut de cache L1, pas loin de la centaine pour un défaut de cache L2, etc. Et cela pose des problèmes pour l'émission anticipée. L'émission en avance pour les accès mémoire est purement spéculative : le processeur émet des micro-opérations en supposant que la lecture entrainera un succès de cache, quitte à annuler la micro-opération en cas de défaut de cache. Mais faire ainsi demande non seulement d'annuler les micro-opérations émises en avance, mais aussi de ne pas retirer les micro-opérations émises en avance de le ''scheduler''. Elles sont émises, mais une copie de sauvegarde est conservée dans le ''scheduler''. Si le processeur détecte un défaut de cache, il peut alors ré-exécuter la micro-opération. S'il détecte un succès de cache, les micro-opérations lecture-dépendante sont retirées de le ''scheduler'', la copie de sauvegarde est devenue inutile et est donc jetée. ===La logique de sélection : âge ou position ?=== La logique de sélection est primordiale pour de bonnes performances. Il existe deux méthodes principales pour sélectionner la micro-opération à exécuter. La première est la plus simple : elle se base sur lé numéro de l'entrée. En effet, un ''scheduler'' est avant tout une sorte de mémoire, un mix entre mémoire associative, mémoire RAM, et FIFO. Et chaque entrée a un numéro, une adresse mémoire. Nous parlerons de numéro dans ce qui suit, car ce sera plus simple, le terme d'adresse mémoire étant peut-être un peu exagéré dans le contexte des ''scheduler''. Toujours est-il que le ''scheduler'' est adressable dans le sens où on peut lui envoyer le numéro de l'entrée voulue, et le ''scheduler'' renvoie le contenu de l'entrée sur son port de lecture. Et c'est ce que fait la logique de sélection : elle génère le numéro de l'entrée à lire. Le numéro est alors envoyé sur l'entrée d'adresse du ''scheduler'', et elle fournit la micro-opération associée sur son port de lecture, son '''port d'émission'''. La première méthode de sélection, donc. Elle est basée sur le numéro de l'entrée. Si plusieurs entrées sont éveillées, la logique de sélection prend celle avec le plus petit numéro. Elle porte le nom de '''sélection par position''', sous-entendu position dans le ''scheduler''. Vous l'avez peut-être deviné, mais la logique de sélection est alors un encodeur à priorité. Le circuit de sélection ne se résume donc pas seulement à un encodeur à priorité, mais c'est le circuit central. L'avantage d'une telle méthode de sélection est qu'elle est simple à implémenter : un encodeur à priorité est un circuit connu, facile à implémenter. Mais on remarque un défaut : un encodeur est un circuit assez rapide, mais qui utilise beaucoup de transistors, beaucoup de portes logiques, surtout si on veut qu'il soit rapide. Ce qui explique que la logique de sélection ait son propre étage de pipeline rien que pour elle. La seconde méthode s'appelle la '''sélection par âge''', au nom assez transparent. L'idée est de privilégier l'émission de la micro-opération la plus ancienne. Elle demande que le ''scheduler'' trie les micro-opérations par ordre d'insertion dans le ''scheduler'', ce qui en fait une pseudo-FIFO. Le tri est partiel, car les instructions peuvent sortir du ''scheduler'' à tout moment. Compacter le ''scheduler'', à savoir regrouper toutes les entrées valides est une idée, mais elle est compliquée à implémenter. Aussi, elles préfèrent encoder des informations sur l'ordre d'émission dans chaque entrée. L'encodeur à priorité doit alors travailler non pas sur des nombres entiers liés à l'ordre d'insertion dans la pseudo-FIFO. Elle est encore plus gourmande en circuits que la méthode précédente. Les processeurs haute performance utilisent souvent des méthodes hybrides. Par exemple, les processeurs AMD de microarchitecture Bulldozer utilisaient une méthode intermédiaire. Ils utilisaient un ''scheduler'' couplée à un encodeur à priorité pour la sélection par position, mais complémentaient le tout avec une unité qui mémorisait la micro-opération la plus ancienne dans le ''scheduler''. Le mécanisme de sélection par âge était utilisé en priorité. Mais si la micro-opération la plus ancienne n'était pas prête, le processeur basculait sur le mécanisme de sélection par position. ===La compaction des ''scheduler''=== À chaque cycle, les micro-opérations décodées sont ajoutées dans le ''scheduler'', dans des entrées vides. Vu que les micro-opérations quittent celle-ci dans le désordre, ces vides sont dispersés dans le ''scheduler'', ce qui pose problème pour déterminer où placer les nouvelles micro-opérations. La solution la plus triviale consiste à conserver une liste des vides, mise à jour à chaque insertion ou émission d'instruction. Une autre solution consiste à éliminer les vides en compactant le ''scheduler'' à chaque cycle d'horloge. Des circuits se chargent de détecter les vides et de regrouper les micro-opérations en un unique bloc. Il faut signaler que certains processeurs arrivent à se passer de cette étape de compactage, mais au prix de ''scheduler'' nettement plus complexes. Autre problème : quand il faut choisir quelle instruction émettre, il y a toujours plusieurs candidats. Si on choisit mal, des instructions restent en attente trop longtemps parce que d'autres instructions plus jeunes leur passent devant. Pour éviter cela, les micro-opérations les plus vielles, les plus anciennes, sont prioritaires. Pour cela, on peut utiliser une FIFO un peu spéciale pour le ''scheduler''. Si les ajouts d'instruction se font dans l'ordre, les micro-opérations ne quittent pas forcément le ''scheduler'' dans l'ordre imposé par une FIFO : les micro-opérations restent triées dans leur ordre d'ajout, même s'il y a des vides entre elles. Dans ces conditions, il est préférable que le compactage conserve l'ordre FIFO des instructions. Dans ces conditions, la micro-opération la plus ancienne est celle qui est située à l'adresse la plus faible : le circuit de sélection peut donc être fabriqué avec des encodeurs, et est relativement simple. ==Les ''schedulers'' basées sur une matrice de dépendances== L'implémentation la plus simple étend le fonctionnement d'un pipeline dynamique usuel. Rappelez-vous le chapitre sur les pipelines dynamiques. Nous avions vu que de tels pipelines émettaient une instruction par cycle, quitte à émettre des bulles de pipeline en cas de dépendance bloquante. Et il est possible d'améliorer leur unité d'émission pour qu'elle soit compatible avec l'exécution dans le désordre. ===Rappels sur le registre de réservation/disponibilité=== L'émission d'une instruction est gouvernée par un ''registre de réservation'' qui indique quels registres sont réservés par une instruction, et ceux qui sont libres. Un registre réservé est un registre qui sera écrit par une instruction en cours d'exécution, mais qui n'a pas encore écrit son résultat. Les instructions candidates doivent avoir leurs opérandes dans des registres libres. Sinon, c'est signe que leurs opérandes sont réservés en écriture, donc pas encore écrites, donc pas disponibles. Si une instruction candidate veut lire ce registre, c'est signe qu'il y a une dépendance RAW : elle veut lire un registre réservé, qui est destiné à être écrit par une instruction en vol. Si elle veut écrire, c'est signe qu'elle veut écrire dans un registre où une autre instruction veut écrire : c'est une dépendance WAW. Dans les deux cas, la micro-opération n'est pas émise. Le registre de réservation encode les registres réservés comme suit : chaque bit est associé à un registre. Le bit numéro 0 est associé au registre numéro 0, le bit numéro 1 au registre numéro 1, etc. Là, En clair, les numéros de registres réservés sont encodés en représentation non pas binaire, mais en représentation ''one-hot'' (vue au premier chapitre). {|class="wikitable" |+ Registre de réservation |- ! Registre 7 !! Registre 6 !! Registre 5 !! Registre 4 !! Registre 3 !! Registre 2 !! Registre 1 !! Registre 0 |- | 0 || 0 || 1 || 0 || 0 || 1 || 0 || 0 |} Avant d'émettre une instruction, l'unité d'émission extrait les registres opérande/destination et les convertis dans la même représentation que le registre de réservation, à savoir en représentation ''one-hot''. Le circuit de traduction binaire vers ''one-hot'' est, pour rappel, un simple décodeur. Puis, on fait un OU logique entre les sorties des décodeurs. Le résultat est un masque qui indique quels registres sont lus par la micro-opération, encodé en représentation ''one-hot''. Appelons-le le '''masque d'opérandes'''. Le masque est alors comparé au registre de réservation pour vérifier si la micro-opération peut être émise. [[File:Unité d'émission simple, dans l'ordre.png|centre|vignette|upright=2|Unité d'émission simple, dans l'ordre]] Si l'émission est autorisée, le registre de réservation est là aussi mis à jour. Le registre de réservation est aussi mis à jour dès qu'une instruction enregistre son résultat dans les registres, ou alors dès qu'il est disponible pour le contournement. Le bit associé au registre repasse alors à 0 (ou à 1). Sans contournement, la mise à jour se fait alors à la toute fin de la micro-opération, quand elle se termine, lors de la dernière étape d'enregistrement, à la fin de son pipeline. Avec, elle se fait quand la micro-opération quitte l'unité de calcul. ===L'extension à l'exécution dans le désordre : l'éveil par matrice de bits=== La différence entre un pipeline dynamique et l'exécution dans le désordre est que l'on passe d'une instruction à émettre à plusieurs. Plusieurs instructions sont mises en attente dans un ''scheduler'', et y attendent leur tour. L'idée est alors d'envoyer le registre de disponibilité à toutes les entrées, à toutes les micro-opérations en attente. Ainsi, on sait quelles sont les micro-opérations qui peuvent s'exécuter et celles qui ne le peuvent pas. L'implémentation est assez simple, elle ressemble beaucoup à l'implémentation d'un pipeline dynamique simple, si ce n'est que des circuits sont dupliqués. L'implémentation utilise des ''scheduler'' légèrement différentes de celles introduites plus haut. Elles n'utilisent notamment pas de bits de disponibilité, mais autre chose. Lorsqu'une instruction est ajoutée à le ''scheduler'', le masque de disponibilité des opérandes est stocké dans le ''scheduler''. A chaque cycle, le registre de disponibilité est envoyé à toutes les entrées, et est comparé avec tous les masques de disponibilité des opérandes. Si une comparaison renvoie un 1, alors la micro-opération de l'entrée est une instruction candidate à l'émission. [[File:Unité d'émission dans le désordre basée sur un registre de disponibilité.png|centre|vignette|upright=2.5|Unité d'émission dans le désordre basée sur un registre de disponibilité]] L'ensemble est implémenté avec l'aide d'une '''matrice de bits''', où chaque ligne correspond à une entrée et chaque colonne à un registre. À chaque croisement entre une ligne et une colonne, on trouve un bit. Si le bit de la ligne n et de la colonne m est à 1, cela veut dire : la micro-opération dans l'entrée n a besoin de lire le registre m. S’il est à 0, alors cela veut dire que la micro-opération stockée dans la ligne n'a pas besoin de la donnée dans le registre m. [[File:Planificateur à matrice de bits.jpg|centre|vignette|upright=2|Planificateur à matrice de bits.]] Lorsqu'une instruction réserve une entrée, elle initialise la ligne en fonction des registres qu'elle souhaite lire. Pour vérifier si une instruction a ses opérandes prêts, le processeur compare le registre de disponibilité à la ligne associée à la micro-opération/entrée. A chaque intersection ligne-colonne, se trouve un comparateur de 1 bit, qui détecte si le registre est demandé et disponible. Les résultats de cette porte sont ensuite envoyés à une porte ET, qui fait le gros du travail. [[File:Logique de détection de la disponibilité d'une instruction.jpg|centre|vignette|upright=2|Logique de détection de la disponibilité d'une instruction.]] ==Les ''schedulers'' basées sur une mémoire associative== Les processeurs modernes utilisent une mémoire associative pour le ''scheduler''. Les mémoires associatives ont été abordées il y a quelques chapitres, mais faisons quelques rappels. Les mémoires associatives servent à accélérer la recherche de données dans un ensemble. Or, un ''scheduler'' vérifie régulièrement si chaque entrée est prête. Il s'agit d'un processus de recherche d'une instruction qui respecte une condition bien précise dans la mémoire, ce qui fait que les mémoires associatives sont donc tout indiquées. Comme vous le savez, les signaux de commande d'une instruction sont propagés avec celle-ci dans le pipeline, le nom du registre de destination ne faisant pas exception. Le nom de registre est envoyé à le ''scheduler'' lors de l'écriture du résultat dans les registres. S'il y a correspondance, l'opérande est disponible et son bit de disponibilité est mis à 1. On peut adapter cette méthode pour tenir compte du contournement assez simplement. [[File:Détection des dépendances par propagation du registre de destination.png|centre|vignette|upright=2|Détection des dépendances par propagation du registre de destination.]] En conséquence, le circuit de détection des dépendances est constitué d'un grand nombre de comparateurs : un par champ « nom de registre » dans chaque entrée. La logique d'éveil/''wake up'' regroupe tous les comparateurs, la logique de sélection est un circuit situé en-dehors de la mémoire associative. Les entrées sont dans la mémoire associative elle-même. [[File:Gestion des bits de validité.png|centre|vignette|upright=2|Gestion des bits de validité.]] L'implémentation la plus simple est celle du schéma précédent, où on utilise une mémoire associative unique. Une version plus élaborée sépare le ''scheduler'' en deux parties : une mémoire qui mémorise les registres des opérandes, une autre mémoire pour le reste. La mémoire pour les registres opérandes est la mémoire associative proprement dite, c'est elle qui est associée aux comparateurs, à la logique de ''wake-up''/réveil, etc. Par contre, l'autre mémoire est une mémoire RAM simplifiée, qui mémorise les informations qui n'ont pas besoin des comparateurs. L'opcode de la micro-opération est là-dedans, par exemple. le ''scheduler'' est donc une sorte de mémoire associative améliorée. Il se trouve que c'est aussi le cas du ROB. Et il est possible de fusionner le tampon de ré-ordonnancement avec le ''scheduler'' dans une structure unique. La différence avec un ''scheduler'' normal est que les entrées sont libérées non pas quand la micro-opération est exécutée/émise, mais quand elle termine son exécution et quitte le ROB. le ''scheduler'' incorpore des bits dans chaque entrée, pour savoir si la µops associée a été émise et est en cours de traitement dans les ALUs. La méthode a notamment été utilisée sur les processeurs d'architecture K6 d'AMD. Le tout donnait une structure appelée le '''DRIS''' (''deferred scheduling register renaming instruction shelf''). Les processeurs PA 8000 de HP étaient aussi vraisemblabment dans ce cas, aussi. ===Les optimisations de la consommation d'énergie : la désactivation des portions inutilisées=== Le problème avec des ''scheduler'' de ce type est leur forte consommation énergétique, ainsi que le grand nombre de portes logiques utilisées, qui deviennent prohibitifs pour des ''scheduler'' un peu grosses. Pour résoudre ce problème, certains ont optimisé les comparateurs. D'autres ont tenté de profiter du fait que la majorité des bits dans les entrées sont composés de zéros. Bref, les optimisations purement matérielles sont légion. Une première solution est de désactiver les entrées qui sont inutilisées, vides, sans instruction. Pour cela, on fait précéder les comparateurs par un circuit qui les connecte ou déconnecte des lignes de bit. Le circuit est commandé par le bit ''empty'' qui indique si une entrée est vide ou non. L'avantage est que la consommation d'énergie de le ''scheduler'' devient alors proportionnelle au nombre d'entrées non-vides, et non au nombre d'entrées total. Du moins, en apparence, les entrées non-utilisées doivent quand même être alimentées pour fonctionner, mais l'activité de comparaison disparait dans les entrées vides. Il est possible d'étendre cette technique aux entrées dont les opérandes sont prêts. Les gains sont généralement assez bons, avec une réduction de consommation variant entre 30 et 50%, avec une implémentation très simple et très économe en circuits. Une autre solution, assez simple à mettre en place, consiste à désactiver une partie de le ''scheduler'' sin elle est inutilisée. Pour cela, il faut segmenter le ''scheduler'' avec la technique du ''wire partitionning''. Pour rappel, un ''scheduler'' est une mémoire associative. Et comme toute mémoire associative, elle contient des fils, les lignes de bit, qui relient les entrées/sorties à toutes les cellules mémoire. Plus une ligne de bit est longue, plus elle consomme d'énergie et plus le temps de lecture/écriture est long. L'idée est de segmenter les lignes de bits en plaçant des répéteurs qui recopient la tension d'un segment au suivant. Les répéteurs sont des tampons trois-états, ce qui permet de déconnecter les portions inutilisées de la ligne de bit. Ce faisant, le ''scheduler'' est découpée en segments, qui peuvent être désactivés si besoin. S'il y a peu d'instructions chargées dans le ''scheduler'', les portions inutilisées sont désactivées. La technique marche d'autan mieux si les micro-opérations sont compactées au début de le ''scheduler''. [[File:Wire partitionning.png|centre|vignette|upright=2|Wire partitionning]] Tout le problème est de savoir quelles portions désactiver. La technique est assez simple si le ''scheduler'' est compactée, à savoir si toutes les micro-opérations sont régulièrement regroupées au début de la mémoire CAM. Mais même avec cette optimisation, la décision de désactiver une portion de le ''scheduler'' n'est pas à prendre à la légère. Il ne faut pas désactiver une portion contenant des instructions pouvant être émise sous peu. La décision dépend de paramètres variés : proportion d'entrée vides, quantité d'entrées récemment activées/désactivées récemment, présences d'entrées avec un ''match'' d'opérandes récent, etc. Il est important de préciser que les techniques en question fonctionnent aussi sur les autres types de ''scheduler'', qui ne sont pas basées sur des mémoires associatives. Nous allons voir celles-ci dans la suite du chapitre, mais gardez à l'esprit que ces optimisations, à savoir désactiver les entrées vides/prêts et partitionner le ''scheduler'', sont des optimisations générales qui marchent avec presque tout. ===L'ajout d'une FIFO pour les micro-opérations déjà prêtes à l'émission=== D'autres techniques permettent de réduire aussi bien le cout en circuits que la consommation d'énergie de le ''scheduler''. L'idée est d'utiliser une mémoire associative quand elle est réellement nécessaire, mais d'utiliser un ''scheduler'' "normale" dès que possible. La méthode la plus simple tient compte du fait que certaines µopsont déjà toutes leurs opérandes de disponibles à l'émission, mais doivent quand même être mises en attente, parce que l'ALU adéquate est occupée, parce que des dépendances WAW/WAR sont encore là, ou pour tout autre raison. Dans ce cas, elles sont mises en attente non pas dans le ''scheduler'', mais dans une mémoire FIFO toute simple. L'idée est qu'au lieu d'avoir une énorme mémoire associative pour le ''scheduler'', on déplace quelques entrées dans une petite FIFO annexe. Le résultat est un gain d'énergie et de circuits, au prix d'une perte de performance mineure. La perte de performance en question se manifeste si aucune instruction n'a ses opérandes de prêtes à l'émission : le programme n'utilise pas la FIFO et voit alors un ''scheduler'' plus petite. Une amélioration de cette technique tient compte du fait que certaines instructions sont dans un cas intermédiaire. Elles ont déjà un opérande de prête lors de l'émission, mais pas l'autre. Le nombre d'opérandes varie suivant l’instruction : certaines n'ont besoin que d'un seul opérande. De plus, il arrive qu'une opération tout juste décodée ait déjà un ou plusieurs de ses opérandes de prêts. Cette constatation permet d'éviter d'utiliser des comparateurs pour les opérandes déjà prêts. Par exemple, on peut parfaitement utiliser trois ''scheduler'' : * une pour les micro-opérations dont tous les opérandes sont prêts, mais qui sont quand même mises en attente, sans comparateur ; * une pour les micro-opérations dont un seul opérande manque, qui n'utilise qu'un comparateur par entrée ; * une pour les micro-opérations dont deux opérandes manquent à l'appel, qui utilise deux comparateurs par entrée. C'est beaucoup plus économique que d'utiliser une seule grosse ''scheduler'' qui contiendrait autant d'entrées que les trois précédentes réunies, avec deux comparateurs par entrée. Certains sont même allés plus loin, et ont proposé de supprimer le ''scheduler'' avec deux opérandes par entrée. les micro-opérations dont deux opérandes sont inconnus au décodage sont stockées dans le ''scheduler'' pour instructions avec un comparateur par entrée. Un circuit de prédiction se charge alors de prédire l'opérande manquant, cette prédiction étant vérifiée plus loin dans le pipeline. Il serait cependant étonnant qu'une telle proposition ait donné lieu à la moindre implémentation réelle. ===Les optimisations de la consommation d'énergie avancées=== D'autres chercheurs ont conservé un ''scheduler'' unique, avec autant de comparateurs par entrée qu'il y a d'opérandes possibles par instruction. Simplement, le processus de détection des opérandes prêts est légèrement ralenti : on ne vérifie qu'un opérande par cycle. Pour vérifier les deux opérandes d'une entrée, on doit attendre deux cycles. Enfin, certains chercheurs ont proposé des ''scheduler'' segmentées. les micro-opérations circulent à chaque cycle d'un segment vers le suivant : en conséquence, certains segments conservent les micro-opérations les plus anciennes, un autre les micro-opérations les plus jeunes, etc. Seul le denier segment, celui qui contient les micro-opérations les plus vielles, peut émettre une instruction : la détection des opérandes se fait seulement dans le dernier segment, qui contient les micro-opérations les plus anciennes. On économise ainsi beaucoup de comparateurs. Certains chercheurs ont tenté de pipeliner l'étape de sélection des opérandes, ainsi que l'étage d'arbitrage. Mais en faisant cela, il faut plusieurs cycles pour détecter qu'une instruction a ses opérandes prêts, ce qui pose problème face à de nombreuses dépendances RAW. Pour éviter de trop perdre en performances, certains chercheurs ont décidé d'utiliser des techniques pour prédire quelles seront les micro-opérations dont les opérandes seront bientôt prêts. Si détecter qu'une instruction est prête prend n cycles, le processeur devra tenter de prédire la future disponibilité des opérandes n cycles en avance pour obtenir des performances optimales. ===Remplacer la mémoire associative par une RAM=== Une autre optimisation possible est de remplacer le ''scheduler'' par une mémoire RAM, dont chaque mot mémoire correspondrait à une entrée. Une telle optimisation permet en théorie de se passer des comparateurs associés à chaque entrée, mais au prix de l'ajout de circuits annexes potentiellement couteux. La première de ces techniques, la '''recherche directe par étiquette''' (direct tag search) fut créée par Weiss et son collègue Smith. Ils cherchaient à améliorer l'algorithme de Tomasulo, un algorithme qu'on expliquera dans quelques chapitres. Rappelons que chaque instruction produit un résultat, qui devra être rapatrié dans une ou plusieurs entrées de le ''scheduler''. L'optimisation de la recherche directe par étiquette fonctionne dans le cas où le résultat de la micro-opération n'est utilisé que par une seule entrée, et pas plusieurs. Le principe est simple : chaque champ « opérande » d'une entrée est adressable via le nom de registre de cet opérande. Pour faire le lien entre entrée et nom de registre, la recherche directe par étiquette ajoute une table de correspondances matérielle, une mémoire RAM qui mémorise les adresses des champs « opérande » des entrées. Les adresses envoyées dans cette mémoire sont les noms de registres des résultats. Lors de l'émission, la table de correspondances est mise à jour. Les numéros des champs « opérande » réservés lors de l'émission sont mémorisés dans les mots mémoire qui correspondent aux deux registres sources. Toutefois, une petite vérification est faite lors de l'émission : s'il y a déjà une correspondance dans la table pour un registre source, alors une autre instruction compte lire ce registre. Pour éviter d'écraser les données de la micro-opération précédente dans la table de correspondances, l'émission de la micro-opération est bloquée. [[File:Recherche directe par étiquette.png|centre|vignette|upright=2|Recherche directe par étiquette.]] ==Les ''schedulers'' avec préplanification== Avec la '''préplanification''' (''prescheduling''), le ''scheduler'' est composée de mémoires FIFO dans lesquelles les micro-opérations sont triées dans l'ordre d'émission. Il n'y a pas de logique d’émission proprement dite, celle-ci se bornant à vérifier si la micro-opération située au début de la FIFO peut s’exécuter. Par contre, le préplanificateur détecte les dépendances et en déduit où insérer les micro-opérations dans le tampon d'émission, à l'endroit le plus adéquat. [[File:Préplanification.jpg|centre|vignette|upright=2|Préplanification.]] ===L'usage de FIFO multiples=== La technique de préplanification la plus simple utilise plusieurs FIFO. Quand une instruction a une dépendance avec une autre instruction, les deux sont placées dans la même FIFO. Pour cela, le préplanificateur détecte les chaines d'instructions dépendantes, et place les micro-opérations dans la FIFO adéquate. A chaque cycle, l'unité d'émission lit une micro-opération dans chaque FIFO et vérifie si elle peut l'émettre. Si la micro-opération n'a pas ses opérandes disponibles, ou qu'une dépendance structurelle survient, alors la FIFO est bloquée. La micro-opération attend que la dépendance soit résolue, bloquant toutes les micro-opérations précédentes. Mais les autres FIFO ne sont pas bloquées, laissant de la marge de manœuvre. [[File:Préplanification par FIFO multiples.png|centre|vignette|upright=1.5|Préplanification par FIFO multiples.]] ===La technique du tampon trié=== La technique du '''tampon trié''' trie les micro-opérations selon le temps d'attente avant leur exécution. les micro-opérations qui sont censées s’exécuter bientôt sont insérées au tout début de la FIFO, tandis que les micro-opérations qui s’exécuteront dans un long moment sont insérées vers la fin. Là encore, l'unité d'émission lit une micro-opération dans la FIFO, et détermine si elle peut être émise. Si une dépendance survient, l'émission est retardée, et la FIFO est bloquée. [[File:Préplanification par tampon trié.png|centre|vignette|upright=1.5|Préplanification par tampon trié.]] La technique a cependant quelques problèmes assez importants. Le premier problème est que la FIFO est bloquée lorsqu'une micro-opération ne peut être émise. Le second problème est que le temps avant exécution n'est pas toujours connu, notamment pour les micro-opérations d'accès mémoire. Et cela se répercute sur les micro-opérations dépendantes de celles-ci. Pour résoudre ce genre de problèmes, l'usage d'un pipeline à ''replay'' est possible, et est même l'une des meilleures solutions possible, malgré ses défauts. L'idée est que les lectures sont pré-planifiées en supposant qu'elles font un succès de cache L1. Si la prédiction est fausse, la lecture est ré-exécutée plusieurs cycles plus tard, en supposant qu'elle fait un succès dans le cache L2, et ainsi de suite. Elle est alors ré-insérée dans la FIFO, elle est pré-planifiée une seconde fois. Il en est de même si une micro-opération ne peut pas être émise : il suffit de la réinsérer dans la FIFO au bon endroit, en attendant que ses dépendances soient résolues. Ainsi, la micro-opération fautive ne bloque pas le ''scheduler'', et retente sa chance autant de fois qu'il le faut. [[File:Préplanification par fenêtre d’instruction scorebarodée.png|centre|vignette|upright=1.5|Préplanification par ''scheduler'' scorebarodé.]] Une autre solution utilise deux ''schedulers'' : une FIFO gérée par la préplanification, et une vraie ''scheduler'' pour les micro-opérations dont le temps d'attente ne peut pas être déterminé. Il est possible de mettre cette dernière avant la préplanification, afin de gérer les temps d'attente des instructions d'accès mémoire. Quand le temps d'attente d'une lecture devient connu, ses instructions dépendantes sont gérées avec préplanification. [[File:Préplanification avec fenêtre d’instruction.png|centre|vignette|upright=2.5|Préplanification avec ''scheduler''.]] ===Les ''scheduler'' avec allocation temporelle statique=== L''''allocation temporelle statique''' correspond à une technique utilisée sur les processeurs Cuzco de l'entreprise Condor. La technique en question a été présenté en 2025, mais des idées similaires ont été présentées dans la littérature académique. Elle ressemble beaucoup aux techniques de pré-planification, avec cependant quelques différences. L'idée est simple : le processeur dispose de plusieurs ''scheduler'', qui mettent en attente les micro-opérations. Lors de l'étape de renommage de registres, le processeur détermine dans combien de cycles d'horloge la micro-opération sera prête pour exécution. La micro-opération est alors mise en attente durant ce nombre de cycles, dans les ''scheduler'', puis est émise une fois ce nombre de cycles écoulés. Ce faisant, les ''scheduler'' n'ont pas besoin de détecter la disponibilité des opérandes à chaque cycle, pour chaque micro-opération en attente. Le ''timing'' de l'émission des micro-opérations est décidé à l'avance. L'implémentation exacte n'est pas connue, mais plusieurs solutions sont imaginables. Par exemple, le ''scheduler'' peut simplement être composée de plusieurs mémoires de petite taille, chacune contenant les micro-opérations destinées à être exécutées dans N cycles, N étant différent pour chaque mémoire. Une autre solution, plus réaliste, utilise un ''scheduler'' dans laquelle la micro-opération est couplée à des champs pour les opérandes, et un champ compteur. Le champ compteur est initialisé avec le nombre de cycles à attendre, et est décrémenté à chaque cycle d'horloge. Quand il atteint zéro, la micro-opération est émise. Vous remarquerez que la méthode ne marche que si toutes les micro-opérations prennent un nombre fixe de cycles d'horloge. Et autant c'est le cas pour les micro-opérations arithmétiques ou logiques, autant les accès mémoire ne rentrent pas dans ce cadre. En théorie, on ne sait pas combien de temps prendra un accès mémoire. Et cette incertitude se répercute sur les micro-opérations dépendantes d'un accès mémoire. Pour éviter cela, le processeur réutilise un pipeline à ''replay'' tel que vu dans le chapitre précédent. L'unité de renommage de registre suppose que tout accès mémoire fait un succès de cache L1, et décide des ''timings'' d'émission sous cette hypothèse. Si une lecture subit un défaut de cache, elle est ré-exécutée, de même que toutes les micro-opérations dépendantes. Pour cela, le registre de destination de la lecture est marqué comme invalide, grâce à un bit spécifique attaché au registre. Toute instruction qui lit un opérande invalide est elle aussi ré-executée de zéro. Pour simplifier, l'unité d'émission ressemble à une unité d'émission dans l'ordre, avec un registre de disponibilité, qu'on aurait amélioré pour aller au-delà de la simple détection des dépendances d'instruction. Pour déterminer les ''timings'' d'émission, à savoir quand émettre une micro-opération, le processeur utilise une unité d'émission à deux étages. Le premier étage est appelé le ''register scoreboard'', le second étage est appelé la ''Time Ressource Matrix''. Les deux étages communiquent entre eux, comme on va le voir, et leurs noms donnent une idée de ce qu'ils font. Le premier étage gère les dépendances de registres, le second gère les dépendances structurelles. Le premier étage est un registre de disponibilité amélioré, qui gère les dépendances de registre. Cet étage sait quand tel registre sera écrit, et donc que l'opérande écrit dedans sera disponible à partir de tel cycle d'horloge. Il le sait car l'étage suivant l'aura prévenu, mais laissons cela de côté pour le moment. Quand une micro-opération rentre dans cet étage, il vérifie les dépendances avec les registres et les micro-opérations antérieures. Vu qu'il sait quand les registres seront disponibles, il peut déterminer quand la micro-opération pourra s'exécuter. Par exemple, si une micro-opération lit les deux registres R7 et R15, qui sont disponibles respectivement dans 5 et 7 cycles, le premier étage sait que la micro-opération devra attendre 7 cycles. Mais tout cela ne suffit pas à déterminer quand émettre une micro-opération. En effet, il fait aussi gérer les dépendances structurelles, ce qui est le boulot du second étage. Le second étage utilise pour cela une ''Time Ressource Matrix'', qui mémorise l'occupation de diverses "ressources", pour les 256 cycles d'horloge à venir. Les ressources en question sont les ports de lecture/écriture du banc de registre, les ALUs utilisées, si la micro-opération utilise l'unité mémoire, etc. Le second étage prend en entrée une micro-opération, détermine quelles "ressources" elle utilise, puis regarde leur disponibilité. Elle détecte alors les dépendances structurelles et détermine alors quand peut s'exécuter la micro-opération. Elle peut retarder l'émission de quelques cycles, si une dépendance structurelle est détectée. Une fois sortie du second étage, on sait quand la micro-opération va être émise, à quel cycle précisément. Et vu que la durée de la micro-opération est fixe, on sait quand cette micro-opération va se terminer, quand son résultat sera disponible. Cela permet de mettre à jour la ''Time Ressource Matrix'', pour préciser que le port d'écriture sera occupé à tel moment. De plus, cette information est transmise au premier étage, qui sait alors quand est enregistré le résultat dans le registre de destination. C'est comme cela que le premier étage sait quand un registre est disponible : le second étage le prévient, quand il émet une instruction ! La ''Time Ressource Matrix''mémorise l'occupation des "ressources" pour les 256 cycles d'horloge à venir. Cependant, elle ne vérifie pas les dépendances pour les 256 cycles suivants. Quand elle reçoit une micro-opération, elle teste les dépendances structurelles pour seulement les 8 prochains cycles maximum. Si la micro-opération ne peut pas être émise pendant ces 8 cycles, le pipeline est bloqué, un ''pipeline stall'' est émis. Pour être plus précis, vu que le processeur peut décoder 8 micro-opérations en même temps, cela permet de ne consulter que 64 cycles d'horloge sur les 256. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les premiers processeurs Intel | prevText=Les premiers processeurs Intel | next=Le renommage de registres | nextText=Le renommage de registres }} </noinclude> r0z0b3b4occd1jp8pgt8bc90kyouia6 773687 773686 2026-09-29T23:29:10Z Mewtow 31375 773687 wikitext text/x-wiki Dans les chapitres précédents, nous avons parlé des techniques dites d''''émission dans l'ordre'''. L'idée est d’exécuter une nouvelle micro-opération à chaque cycle, dans des unités de calcul séparées. Les instructions sont émises consécutivement, mais les instructions s’exécutent en parallèle dans des unités de calcul séparées. Par contre, quand l'unité d'émission ne peut pas émettre une instruction, elle bloque tout le pipeline. Les instructions qui suivent sont elles aussi bloquées, elles doivent attendre leur tour, même si elles sont en capacité de s'exécuter. Les techniques d'exécution dans le désordre que nous allons voir dans ce chapitre corrigent ce point précis. Elles sont dites à '''émission dans le désordre'''. Elles se distinguent des précédentes sur un point précis : quand l'unité d'émission bloque l'émission d'une instruction, les instructions suivantes peuvent poursuivre. L'émission des instructions peut donc se faire dans le désordre, dans le sens où une instruction peut être émise alors qu'une instruction précédente ne l'est pas encore. Mais avant de poursuivre, quelques point niveaux terminologie : * L'émission dans le désordre est un terme parlant et assez précis. Malheureusement, la terminologie la plus utilisée par d''''exécution dans le désordre'''. Et nous utiliserons ce terme dans la suite du cours, histoire de ne pas trop dévier de la nomenclature habituelle. * Nous utiliserons parfois l'abréviation OOO pour parler d'exécution dans le désordre. L'abréviation est celle de ''Out Of Order Execution''. * Nous utiliserons aussi l'abréviation ''µop'' pour parler de micro-opération, ''µops'' au pluriel pour parler de plusieurs micro-opérations, ou des micro-opérations en général. L'exécution dans le désordre ne gère en effet que des µops, elle se situe après l'étape de décodage. Pour décrire comment est implémentée l'émission dans le désordre, il faut commencer par parler des processeurs sans. Les processeurs sans exécution dans le désordre ont une unité d'émission qui bloque tout le pipeline dès qu'une µop ne peut pas être émise. Pour limiter l'impact de ce blocage, quelques rares processeurs incorporent une '''file de micro-opération''', une mémoire FIFO qui met en attente les µops. Vu que c'est une mémoire FIFO, les µops sont émises dans l'ordre, à savoir l'ordre d'ajout, dans l'ordre de décodage. Le schéma ci-dessous illustre une telle file d'attente couplée à un ''scoreboard''. L'exécution dans le désordre améliore la file de µops sur un point : ce n'est plus une mémoire FIFO. Les µops sont insérées dans l'ordre, mais peuvent sortir dans le désordre (être émises dans le désordre). La file de µops devient alors un '''''scheduler''''', terme anglais que je ne compte pas traduire. Un terme équivalent est '''''scheduler''''', terme traduit directement de l'anglais ''instruction Window''. Terme assez trompeur, car elles mettent en attente des µops, pas des instructions. [[File:Différence file µops et fenêtres instruction.png|centre|vignette|upright=2|Différence file µops et ''schedulers'' ]] Le ''scheduler'' émet une µop dès que ses opérandes sont disponibles. Par disponible, on veut dire présent soit dans le réseau de contournement, soit dans les registres. Le ''scheduler'' détecte automatiquement quand les opérandes d'une µop sont disponibles, grâce à une unité d'émission intégrée. L'unité d'émission et la file d'attente de µops sont fusionnés ensemble, dans un seul circuit, mais nous allons dire qu'ils sont conceptuellement séparés pour le moment. À chaque cycle, l'unité d'émission consulte les µops en attente pour détecter lesquelles peuvent s'exécuter. Le ''scheduler'' est spécialement être conçue pour, c'est une sorte de mémoire associative très complexe, comme on le verra dans ce qui suit. [[File:OOO Issue.png|centre|vignette|upright=2.5|Exécution dans le désordre avec un ''scheduler'']] Une fois qu'une µop sort du décodeur d'instructions, elle est ajoutée en parallèle dans le ''scheduler'' et le ROB. La raison est que les µops quittent le ''scheduler'' dans le désordre, et qu'elles doivent être remises en ordre par la suite. Le ROB s'occupe de cette remise en ordre, mais il a besoin de savoir dans quel ordre les µops sont censées être, et cet ordre est celui du décodage. Aussi, pour remplir le ROB, la seule opportunité est en sortie de l'unité de décodage. Dans le cas où une instruction est décodée en plusieurs micro-opérations, elles sont toutes insérées en même temps dans le ''scheduler'' et le ROB, en tenant compte de leur ordre. L'implémentation la plus "simple" de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Les µops décodées sont accumulées dans le ''scheduler'', où elles attendent leur tour. Bien que simple en apparence, cette implémentation cache une complexité très importante, liée aux accès mémoire. Les micro-opérations mémoire sont à part des autres, pour ce qui est de leurs dépendances de données. Non seulement elles ont des dépendances de registre, mais elles sont aussi des dépendances d'adresse. Par exemple, deux écritures peuvent utiliser deux registres d'adresse différents, mais ceux-ci peuvent contenir la même adresse. Et autant on peut détecter les dépendances de registre lors de l'émission, autant c'est plus compliqué avec les dépendances d'adresse. De plus, rappelons que si les lectures peuvent s'exécuter dans le désordre, les écritures doivent s'exécuter dans l'ordre, ou du moins en donner l'illusion. Pour cela, le processeur remet les écritures dans l'ordre avec une sorte de mini-ROB intégré à l'unité mémoire, appelée la file d'écriture. Elle complémente le ROB, qui lui ne gère que les écritures dans les registres, mais les deux collaborent. La file d'écriture envoie une écriture à la mémoire RAM quand le ROB lui dit que c'est bon, les instructions précédentes sont terminées ''dans l'ordre du programme''. Les processeurs modernes ajoutent des techniques d'exécution dans le désordre des accès mémoire, mais nous les verrons dans un chapitre dédié. Elles permettent d'utiliser un ''scheduler'' unique, qui mémorise aussi les µops mémoire. Si elles sont mises en place, l'unité mémoire n'a pas besoin de file de µops séparée. Les dépendances de registre sont traitées par le ''scheduler'', alors que les dépendances d'adresse sont gérées par l'unité mémoire gére les dépendances d'adresse. Elle utilise pour cela des techniques de '''''désambiguïsation mémoire''''', qui auront droit à un chapitre dédié. [[File:Processeur avec exécution dans le désodre des accès mémoire.png|centre|vignette|upright=2|Processeur avec exécution dans le désodre des accès mémoire]] Les processeurs assez anciens n'autorisaient pas d'exécution dans le désordre des accès mémoire. Concrètement, les accès mémoire devaient se faire dans l'ordre, mais les autres µops pouvaient être exécutées dans le désordre. Pour garantir l'ordre des µops mémoire, les µops mémoire ne passent pas par le ''scheduler'', mais sont accumulées dans une file de micro-opérations séparée. Après le décodage, les µops sont réparties soit dans la file de µops mémoire, soit dans le ''scheduler''. Le décodeur classe les µops suivant que ce sont des µops mémoire ou non, et les envoient à la bonne destination. Dans ce chapitre, on supposera que c'est cette solution qui est utilisée. [[File:Processeur avec émission dans l'ordre des accès mémoire.png|centre|vignette|upright=2|Processeur avec émission dans l'ordre des accès mémoire]] ==L'implémentation d'un ''scheduler'' : généralités== Un ''scheduler'' est une mémoire qui mémorise des micro-opérations. Elle est cependant plus complexe qu'une mémoire RAM ou qu'une FIFO et ressemble un petit peu à une mémoire cache. Elle dispose d'un port d'écriture et d'un port de lecture, au minimum. Le port d'écriture permet à l'unité de décodage d'insérer une micro-opération dedans, d'ajouter la micro-opération qui vient d'être décodée. Aussi, il est appelé le '''port de décodage'''. Si une instruction machine est décodée en plusieurs micro-opérations, deux possibilités. La première est de les insérer un par un, ce qui fait qu'on peut se contenter d'un seul port d'écriture. L'autre possibilité est de les ajouter en même temps, ce qui demande plusieurs ports d'écriture. Le port de lecture sert à émettre une micro-opération, ce qui fait qu'il est appelé le '''port d'émission'''. Dans ce chapitre, on part du principe que le ''scheduler'' ne peut émettre qu'une seule micro-opération à la fois. Dans ce cas, le ''scheduler'' a un seul port de lecture. Mais nous verrons dans quelques chapitres qu'il existe des processeurs dits superscalaires, qui sont capables d'émettre plusieurs micro-opérations par cycle. Un processeur superscalaire a typiquement un port d'émission par unité de calcul, ce qui fait beaucoup plus. Les ''schedulers'' sont composées d''''entrées''', des mots mémoire qui stockent une micro-opération. Une micro-opération tout juste décodée réserve une entrée et la libère dès qu'elle est envoyée aux unités de calcul. Une entrée contient l'opcode (les signaux de commande à envoyer à l'ALU), le registre de destination du résultat, les registres de chaque opérande, et éventuellement des signaux de commande en plus. De plus, chaque opérande est couplée à un bit de disponibilité, qui indique si elle est disponible. Quand un opérande est écrit dans les registres, le bit de présence correspondant est mis à jour. Enfin, chaque entrée possède un bit ''empty'' qui indique si elle est vide, cette information étant utile pour réserver des entrées. [[File:Entrée d'une station de réservation - sans les tags.png|centre|vignette|upright=3|Entrée d'un ''scheduler'']] ===Les stations de réservation=== Les '''stations de réservation''' sont des ''scheduler'' particulières, qui sont capables de mémoriser les opérandes des micro-opérations. Les entrées des stations de réservation sont identiques à celle des autres ''scheduler'', si ce n'est que les opérandes de la micro-opération sont enregistrés directement dans des champs séparés. Il y a deux champs, un par opérande, pour stocker l'opérande elle-même, lue depuis les registres ou obtenue via le réseau de contournement. Notons que les champs pour les opérandes viennent en plus des champs pour les noms de registres, encore que les deux peuvent être fusionnés si on veut optimiser le tout. [[File:Entrée d'une station de réservation.png|centre|vignette|upright=3|Entrée d'une station de réservation.]] Précisons que la terminologie n'est pas très fiable. Les termes "''scheduler''" et "station de réservation" ne regroupent pas du tout la même chose d'un papier de recherche à l'autre, d'un bouquin à l'autre, d'un chercheur à l'autre, d'un ingénieur à l'autre, d'un professeur à l'autre. Le terme initial vient pourtant de l'article original sur l'algorithme de Tomasulo, où il désignait un ''scheduler'' associée à une unité de calcul précise. Mais le terme a ensuite été réutilisé, ce qui fait que certains processeurs avec plusieurs unités de calcul sont décrits comme ayant une unique station de réservation. En bref : c'est le bazar ! Mais nous en reparlerons dans le chapitre sur le renommage de registres, car c'est la place idéale pour les aborder. Toujours est-il que j'ai fait le choix de confondre les concepts de ''scheduler'' et de station de réservation avec les concepts de '''lecture avant émission''' et de '''lecture après émission'''. La différence entre les deux est que les registres sont lus après émission avec un ''scheduler'', avant avec des stations de réservation. Dans le cas "avant émission", les opérandes sont mémorisés dans la station de réservation. Et cette différence a une influence sur le pipeline du processeur, le banc de registres et tout ce qui s'ensuit. Un désavantage de la lecture avant émission est qu'il faut stocker les opérandes après lecture, ici dans les stations de réservation. Mais un avantage est que le banc de registre a besoin de moins de ports de lecture, car une bonne partie des opérandes sont fournies par le système de contournement. Nous verrons cela dans le détail dans le chapitre sur les processeurs superscalaires. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Lecture après émission.]] [[File:Read Before Issue.png|centre|vignette|upright=2.5|Lecture avant émission.]] ===La logique d'éveil et de sélection=== Dans le cas qui va suivre, on suppose que le processeur ne peut émettre qu'une micro-opération à la fois. Chaque cycle, une micro-opération est sélectionnée et est envoyée dans le chemin de données, soit à une ALU, soit à une unité d'accès mémoire. La sélection d'une micro-opération est effectuée par l'unité d'émission intégré au '''''scheduler'''''. Elle gère la disponibilité des opérandes et la disponibilité des unités de calcul adéquate. Le choix de la micro-opération émise doit être le plus pertinent possible, pour des raisons de performances. Pour le premier point, l'unité d'émission détermine quelles micro-opérations sont candidates pour l'émission. Les '''micro-opération candidates''' sont celles dont tous les opérandes sont prêts. Le processeur contient un circuit qui détecte les micro-opérations candidates : la '''logique d’éveil''' (''wake-up logic''). Une fois que la logique d'éveil a fait son travail, une micro-opération est choisie pour s’exécuter en fonction de la disponibilité des unités de calcul adéquates. Ce rôle est dévolu à un circuit qu'on appelle la '''logique de sélection''', ou ''select logic''. [[File:Fonctionnement complet de la logique d’émission.jpg|centre|vignette|upright=1.5|Fonctionnement complet de la logique d’émission.]] La logique de sélection doit gérer le fait que les unités de calcul du processeur ne sont pas toutes identiques. Déjà, un processeur a généralement des unités séparées pour les µops entières et flottantes, des unités spécialisées dans les accès mémoire, parfois des unités spécialisées pour les branchements. Une micro-opération doit être attribuée à la bonne unité de calcul, on ne doit pas envoyer une µop entière dans une unité de calcul flottante. De plus, parmi les unités de calcul entières, toutes ne sont pas identiques. Par exemple, il est fréquent d'avoir plusieurs unités de calcul spécialisées dans les opérations simples (additions, soustractions, opérations logiques), mais une seule unité pour les multiplications/divisions, une seule unité spécialisée pour les décalages/rotations, etc. Là encore, allouer la bonne micro-opération à la bonne ALU est complexe. Plus les unités de calcul sont hétérogènes, plus la logique de sélection est compliquée. Les logiques d'éveil comme de sélection sont assez complexes. Comme on le verra plus bas, la logique de sélection la plus simple, qui gère une seule unité de calcul, est basée sur un encodeur à priorité, couplé à d'autres circuits. Et pour gérer plusieurs ALUs, il faut mettre des encodeurs en cascade. Le résultat est que même en prenant une logique de sélection simple, elle sera assez lente et gourmande en circuits. Aussi, la logique de sélection met souvent un cycle d'horloge entier pour faire son travail, elle a son propre étage de pipeline attribué. La logique d'éveil est dans le même cas, ce qui fait qu'émettre une micro-opération demande deux cycles d'horloge. Le défaut est que cela rajoute des cycles d'horloges entre le ''scheduler'' et l'ALU, ce qui complique la gestion du pipeline. Ces cycles de retard sont à prendre en compte au moment d'émettre les micro-opérations, le ''scheduler'' doit en tenir compte pour des performances optimales. Sans tenir compte de ces cycles de retard, les micro-opérations arrivent en retard de quelques cycles à l'ALU, cycles de retard durant lesquels l'ALU n'a pas fait de calcul et a été sous-utilisée, sans compter que le système de contournement n'est pas utilisé au mieux. Et le problème est encore plus important sur les processeurs avec des stations de réservation, qui utilisent la "lecture après émission" : cela rajoute un cycle d'horloge en plus, un temps de retard en plus. ===La logique d'éveil : l'émission anticipée=== La logique d'éveil doit tenir compte du fait qu'il y a plusieurs étages entre l'émission et l'exécution sur une unité de calcul. Par exemple, un processeur a souvent entre un et à cinq étages entre la file d'attente et les unités de calcul. Il faut lire les registres, gérer le contournement, et cela peut prendre quelques cycles d'horloge. Sur le Pentium 4, on trouve 6 étages entre le ''scheduler'' et l'entrée de l'ALU. Si les micro-opérations sont émises quand les opérandes sont disponibles, il y aura un délai de quelques cycles avant qu'elles atteignent l'ALU. Alors qu'idéalement, on souhaiterait que la micro-opération atteigne l'ALU dès que ses opérandes sont disponibles, pour profiter des techniques de contournement. Pour cela, la logique d'éveil émet les micro-opérations quelques cycles en avance pour qu'elles arrivent au bon moment. Il s'agit d'une technique d''''émission anticipée''', dont nous avions parlé dans le chapitre sur le contournement. : Il faut noter que le problème se pose plus avec des ''schedulers'' qu'avec des stations de réservation. Les premières ont un étage en plus entre émission et ALU, vu qu'il faut lire des registres après l'émission. L'émission anticipée demande d'émettre un signal d'éveil en avance de quelques cycles, pile au bon moment. Par exemples, si on a deux étages entre l'ALU et l'unité d'émission, le signal de réveil sera généré deux cycles avant que le résultat soit effectivement calculé. L'implémentation varie, mais deux solutions sont possibles. La première est de générer le signal d'éveil dans l'ALU, ce qui n'a de sens que pour les opérations comme les multiplications ou les divisions, qui prennent plusieurs cycles. Une autre technique génère le signal de réveil dans une structure centralisée, spécialisée dans la génération des signaux d'éveil. L'unité de composée d'un registre à décalage par registre. Imaginons qu'une micro-opération est émise, que cette micro-opération mette N cycles à s'exécuter, et qu'elle écrive dans un registre de destination. L'unité sélectionne alors le registre à décalage associé au registre de destination, et met le bit numéro N à 1. Le registre décalé d'un cran à chaque cycle. Quand le bit sortant est un 1, alors le signal de validité pour l'opérande est généré. L'émission anticipée marche bien si la micro-opération a une durée fixe, connue à l'avance. Et autant c'est le cas pour les micro-opérations arithmétiques et logiques, autant ce n'est pas le cas pour les accès mémoire. Les accès mémoire ont une latence variable : quelques cycles pour un succès de cache, plusieurs dizaines de cycles pour un défaut de cache L1, pas loin de la centaine pour un défaut de cache L2, etc. Et cela pose des problèmes pour l'émission anticipée. L'émission en avance pour les accès mémoire est purement spéculative : le processeur émet des micro-opérations en supposant que la lecture entrainera un succès de cache, quitte à annuler la micro-opération en cas de défaut de cache. Mais faire ainsi demande non seulement d'annuler les micro-opérations émises en avance, mais aussi de ne pas retirer les micro-opérations émises en avance de le ''scheduler''. Elles sont émises, mais une copie de sauvegarde est conservée dans le ''scheduler''. Si le processeur détecte un défaut de cache, il peut alors ré-exécuter la micro-opération. S'il détecte un succès de cache, les micro-opérations lecture-dépendante sont retirées de le ''scheduler'', la copie de sauvegarde est devenue inutile et est donc jetée. ===La logique de sélection : âge ou position ?=== La logique de sélection est primordiale pour de bonnes performances. Il existe deux méthodes principales pour sélectionner la micro-opération à exécuter. La première est la plus simple : elle se base sur lé numéro de l'entrée. En effet, un ''scheduler'' est avant tout une sorte de mémoire, un mix entre mémoire associative, mémoire RAM, et FIFO. Et chaque entrée a un numéro, une adresse mémoire. Nous parlerons de numéro dans ce qui suit, car ce sera plus simple, le terme d'adresse mémoire étant peut-être un peu exagéré dans le contexte des ''scheduler''. Toujours est-il que le ''scheduler'' est adressable dans le sens où on peut lui envoyer le numéro de l'entrée voulue, et le ''scheduler'' renvoie le contenu de l'entrée sur son port de lecture. Et c'est ce que fait la logique de sélection : elle génère le numéro de l'entrée à lire. Le numéro est alors envoyé sur l'entrée d'adresse du ''scheduler'', et elle fournit la micro-opération associée sur son port de lecture, son '''port d'émission'''. La première méthode de sélection, donc. Elle est basée sur le numéro de l'entrée. Si plusieurs entrées sont éveillées, la logique de sélection prend celle avec le plus petit numéro. Elle porte le nom de '''sélection par position''', sous-entendu position dans le ''scheduler''. Vous l'avez peut-être deviné, mais la logique de sélection est alors un encodeur à priorité. Le circuit de sélection ne se résume donc pas seulement à un encodeur à priorité, mais c'est le circuit central. L'avantage d'une telle méthode de sélection est qu'elle est simple à implémenter : un encodeur à priorité est un circuit connu, facile à implémenter. Mais on remarque un défaut : un encodeur est un circuit assez rapide, mais qui utilise beaucoup de transistors, beaucoup de portes logiques, surtout si on veut qu'il soit rapide. Ce qui explique que la logique de sélection ait son propre étage de pipeline rien que pour elle. La seconde méthode s'appelle la '''sélection par âge''', au nom assez transparent. L'idée est de privilégier l'émission de la micro-opération la plus ancienne. Elle demande que le ''scheduler'' trie les micro-opérations par ordre d'insertion dans le ''scheduler'', ce qui en fait une pseudo-FIFO. Le tri est partiel, car les instructions peuvent sortir du ''scheduler'' à tout moment. Compacter le ''scheduler'', à savoir regrouper toutes les entrées valides est une idée, mais elle est compliquée à implémenter. Aussi, elles préfèrent encoder des informations sur l'ordre d'émission dans chaque entrée. L'encodeur à priorité doit alors travailler non pas sur des nombres entiers liés à l'ordre d'insertion dans la pseudo-FIFO. Elle est encore plus gourmande en circuits que la méthode précédente. Les processeurs haute performance utilisent souvent des méthodes hybrides. Par exemple, les processeurs AMD de microarchitecture Bulldozer utilisaient une méthode intermédiaire. Ils utilisaient un ''scheduler'' couplée à un encodeur à priorité pour la sélection par position, mais complémentaient le tout avec une unité qui mémorisait la micro-opération la plus ancienne dans le ''scheduler''. Le mécanisme de sélection par âge était utilisé en priorité. Mais si la micro-opération la plus ancienne n'était pas prête, le processeur basculait sur le mécanisme de sélection par position. ===La compaction des ''scheduler''=== À chaque cycle, les micro-opérations décodées sont ajoutées dans le ''scheduler'', dans des entrées vides. Vu que les micro-opérations quittent celle-ci dans le désordre, ces vides sont dispersés dans le ''scheduler'', ce qui pose problème pour déterminer où placer les nouvelles micro-opérations. La solution la plus triviale consiste à conserver une liste des vides, mise à jour à chaque insertion ou émission d'instruction. Une autre solution consiste à éliminer les vides en compactant le ''scheduler'' à chaque cycle d'horloge. Des circuits se chargent de détecter les vides et de regrouper les micro-opérations en un unique bloc. Il faut signaler que certains processeurs arrivent à se passer de cette étape de compactage, mais au prix de ''scheduler'' nettement plus complexes. Autre problème : quand il faut choisir quelle instruction émettre, il y a toujours plusieurs candidats. Si on choisit mal, des instructions restent en attente trop longtemps parce que d'autres instructions plus jeunes leur passent devant. Pour éviter cela, les micro-opérations les plus vielles, les plus anciennes, sont prioritaires. Pour cela, on peut utiliser une FIFO un peu spéciale pour le ''scheduler''. Si les ajouts d'instruction se font dans l'ordre, les micro-opérations ne quittent pas forcément le ''scheduler'' dans l'ordre imposé par une FIFO : les micro-opérations restent triées dans leur ordre d'ajout, même s'il y a des vides entre elles. Dans ces conditions, il est préférable que le compactage conserve l'ordre FIFO des instructions. Dans ces conditions, la micro-opération la plus ancienne est celle qui est située à l'adresse la plus faible : le circuit de sélection peut donc être fabriqué avec des encodeurs, et est relativement simple. ==Les ''schedulers'' basées sur une matrice de dépendances== L'implémentation la plus simple étend le fonctionnement d'un pipeline dynamique usuel. Rappelez-vous le chapitre sur les pipelines dynamiques. Nous avions vu que de tels pipelines émettaient une instruction par cycle, quitte à émettre des bulles de pipeline en cas de dépendance bloquante. Et il est possible d'améliorer leur unité d'émission pour qu'elle soit compatible avec l'exécution dans le désordre. ===Rappels sur le registre de réservation/disponibilité=== L'émission d'une instruction est gouvernée par un ''registre de réservation'' qui indique quels registres sont réservés par une instruction, et ceux qui sont libres. Un registre réservé est un registre qui sera écrit par une instruction en cours d'exécution, mais qui n'a pas encore écrit son résultat. Les instructions candidates doivent avoir leurs opérandes dans des registres libres. Sinon, c'est signe que leurs opérandes sont réservés en écriture, donc pas encore écrites, donc pas disponibles. Si une instruction candidate veut lire ce registre, c'est signe qu'il y a une dépendance RAW : elle veut lire un registre réservé, qui est destiné à être écrit par une instruction en vol. Si elle veut écrire, c'est signe qu'elle veut écrire dans un registre où une autre instruction veut écrire : c'est une dépendance WAW. Dans les deux cas, la micro-opération n'est pas émise. Le registre de réservation encode les registres réservés comme suit : chaque bit est associé à un registre. Le bit numéro 0 est associé au registre numéro 0, le bit numéro 1 au registre numéro 1, etc. Là, En clair, les numéros de registres réservés sont encodés en représentation non pas binaire, mais en représentation ''one-hot'' (vue au premier chapitre). {|class="wikitable" |+ Registre de réservation |- ! Registre 7 !! Registre 6 !! Registre 5 !! Registre 4 !! Registre 3 !! Registre 2 !! Registre 1 !! Registre 0 |- | 0 || 0 || 1 || 0 || 0 || 1 || 0 || 0 |} Avant d'émettre une instruction, l'unité d'émission extrait les registres opérande/destination et les convertis dans la même représentation que le registre de réservation, à savoir en représentation ''one-hot''. Le circuit de traduction binaire vers ''one-hot'' est, pour rappel, un simple décodeur. Puis, on fait un OU logique entre les sorties des décodeurs. Le résultat est un masque qui indique quels registres sont lus par la micro-opération, encodé en représentation ''one-hot''. Appelons-le le '''masque d'opérandes'''. Le masque est alors comparé au registre de réservation pour vérifier si la micro-opération peut être émise. [[File:Unité d'émission simple, dans l'ordre.png|centre|vignette|upright=2|Unité d'émission simple, dans l'ordre]] Si l'émission est autorisée, le registre de réservation est là aussi mis à jour. Le registre de réservation est aussi mis à jour dès qu'une instruction enregistre son résultat dans les registres, ou alors dès qu'il est disponible pour le contournement. Le bit associé au registre repasse alors à 0 (ou à 1). Sans contournement, la mise à jour se fait alors à la toute fin de la micro-opération, quand elle se termine, lors de la dernière étape d'enregistrement, à la fin de son pipeline. Avec, elle se fait quand la micro-opération quitte l'unité de calcul. ===L'extension à l'exécution dans le désordre : l'éveil par matrice de bits=== La différence entre un pipeline dynamique et l'exécution dans le désordre est que l'on passe d'une instruction à émettre à plusieurs. Plusieurs instructions sont mises en attente dans un ''scheduler'', et y attendent leur tour. L'idée est alors d'envoyer le registre de disponibilité à toutes les entrées, à toutes les micro-opérations en attente. Ainsi, on sait quelles sont les micro-opérations qui peuvent s'exécuter et celles qui ne le peuvent pas. L'implémentation est assez simple, elle ressemble beaucoup à l'implémentation d'un pipeline dynamique simple, si ce n'est que des circuits sont dupliqués. L'implémentation utilise des ''scheduler'' légèrement différentes de celles introduites plus haut. Elles n'utilisent notamment pas de bits de disponibilité, mais autre chose. Lorsqu'une instruction est ajoutée à le ''scheduler'', le masque de disponibilité des opérandes est stocké dans le ''scheduler''. A chaque cycle, le registre de disponibilité est envoyé à toutes les entrées, et est comparé avec tous les masques de disponibilité des opérandes. Si une comparaison renvoie un 1, alors la micro-opération de l'entrée est une instruction candidate à l'émission. [[File:Unité d'émission dans le désordre basée sur un registre de disponibilité.png|centre|vignette|upright=2.5|Unité d'émission dans le désordre basée sur un registre de disponibilité]] L'ensemble est implémenté avec l'aide d'une '''matrice de bits''', où chaque ligne correspond à une entrée et chaque colonne à un registre. À chaque croisement entre une ligne et une colonne, on trouve un bit. Si le bit de la ligne n et de la colonne m est à 1, cela veut dire : la micro-opération dans l'entrée n a besoin de lire le registre m. S’il est à 0, alors cela veut dire que la micro-opération stockée dans la ligne n'a pas besoin de la donnée dans le registre m. [[File:Planificateur à matrice de bits.jpg|centre|vignette|upright=2|Planificateur à matrice de bits.]] Lorsqu'une instruction réserve une entrée, elle initialise la ligne en fonction des registres qu'elle souhaite lire. Pour vérifier si une instruction a ses opérandes prêts, le processeur compare le registre de disponibilité à la ligne associée à la micro-opération/entrée. À chaque intersection ligne-colonne, se trouve un comparateur de 1 bit, qui détecte si le registre est demandé et disponible. Les résultats de cette porte sont ensuite envoyés à une porte ET, qui fait le gros du travail. [[File:Logique de détection de la disponibilité d'une instruction.jpg|centre|vignette|upright=2|Logique de détection de la disponibilité d'une instruction.]] ==Les ''schedulers'' basées sur une mémoire associative== Les processeurs modernes utilisent une mémoire associative pour le ''scheduler''. Les mémoires associatives ont été abordées il y a quelques chapitres, mais faisons quelques rappels. Les mémoires associatives servent à accélérer la recherche de données dans un ensemble. Or, un ''scheduler'' vérifie régulièrement si chaque entrée est prête. Il s'agit d'un processus de recherche d'une instruction qui respecte une condition bien précise dans la mémoire, ce qui fait que les mémoires associatives sont donc tout indiquées. Comme vous le savez, les signaux de commande d'une instruction sont propagés avec celle-ci dans le pipeline, le nom du registre de destination ne faisant pas exception. Le nom de registre est envoyé à le ''scheduler'' lors de l'écriture du résultat dans les registres. S'il y a correspondance, l'opérande est disponible et son bit de disponibilité est mis à 1. On peut adapter cette méthode pour tenir compte du contournement assez simplement. [[File:Détection des dépendances par propagation du registre de destination.png|centre|vignette|upright=2|Détection des dépendances par propagation du registre de destination.]] En conséquence, le circuit de détection des dépendances est constitué d'un grand nombre de comparateurs : un par champ « nom de registre » dans chaque entrée. La logique d'éveil/''wake up'' regroupe tous les comparateurs, la logique de sélection est un circuit situé en dehors de la mémoire associative. Les entrées sont dans la mémoire associative elle-même. [[File:Gestion des bits de validité.png|centre|vignette|upright=2|Gestion des bits de validité.]] L'implémentation la plus simple est celle du schéma précédent, où on utilise une mémoire associative unique. Une version plus élaborée sépare le ''scheduler'' en deux parties : une mémoire qui mémorise les registres des opérandes, une autre mémoire pour le reste. La mémoire pour les registres opérandes est la mémoire associative proprement dite, c'est elle qui est associée aux comparateurs, à la logique de ''wake-up''/réveil, etc. Par contre, l'autre mémoire est une mémoire RAM simplifiée, qui mémorise les informations qui n'ont pas besoin des comparateurs. L'opcode de la micro-opération est là-dedans, par exemple. Le ''scheduler'' est donc une sorte de mémoire associative améliorée. Il se trouve que c'est aussi le cas du ROB. Et il est possible de fusionner le tampon de ré-ordonnancement avec le ''scheduler'' dans une structure unique. La différence avec un ''scheduler'' normal est que les entrées sont libérées non pas quand la micro-opération est exécutée/émise, mais quand elle termine son exécution et quitte le ROB. le ''scheduler'' incorpore des bits dans chaque entrée, pour savoir si la µops associée a été émise et est en cours de traitement dans les ALUs. La méthode a notamment été utilisée sur les processeurs d'architecture K6 d'AMD. Le tout donnait une structure appelée le '''DRIS''' (''deferred scheduling register renaming instruction shelf''). Les processeurs PA 8000 de HP étaient aussi vraisemblabment dans ce cas, aussi. ===Les optimisations de la consommation d'énergie : la désactivation des portions inutilisées=== Le problème avec des ''scheduler'' de ce type est leur forte consommation énergétique, ainsi que le grand nombre de portes logiques utilisées, qui deviennent prohibitifs pour des ''scheduler'' un peu grosses. Pour résoudre ce problème, certains ont optimisé les comparateurs. D'autres ont tenté de profiter du fait que la majorité des bits dans les entrées sont composés de zéros. Bref, les optimisations purement matérielles sont légion. Une première solution est de désactiver les entrées qui sont inutilisées, vides, sans instruction. Pour cela, on fait précéder les comparateurs par un circuit qui les connecte ou déconnecte des lignes de bit. Le circuit est commandé par le bit ''empty'' qui indique si une entrée est vide ou non. L'avantage est que la consommation d'énergie de le ''scheduler'' devient alors proportionnelle au nombre d'entrées non-vides, et non au nombre d'entrées total. Du moins, en apparence, les entrées non-utilisées doivent quand même être alimentées pour fonctionner, mais l'activité de comparaison disparait dans les entrées vides. Il est possible d'étendre cette technique aux entrées dont les opérandes sont prêts. Les gains sont généralement assez bons, avec une réduction de consommation variant entre 30 et 50%, avec une implémentation très simple et très économe en circuits. Une autre solution, assez simple à mettre en place, consiste à désactiver une partie de le ''scheduler'' sin elle est inutilisée. Pour cela, il faut segmenter le ''scheduler'' avec la technique du ''wire partitionning''. Pour rappel, un ''scheduler'' est une mémoire associative. Et comme toute mémoire associative, elle contient des fils, les lignes de bit, qui relient les entrées/sorties à toutes les cellules mémoire. Plus une ligne de bit est longue, plus elle consomme d'énergie et plus le temps de lecture/écriture est long. L'idée est de segmenter les lignes de bits en plaçant des répéteurs qui recopient la tension d'un segment au suivant. Les répéteurs sont des tampons trois-états, ce qui permet de déconnecter les portions inutilisées de la ligne de bit. Ce faisant, le ''scheduler'' est découpée en segments, qui peuvent être désactivés si besoin. S'il y a peu d'instructions chargées dans le ''scheduler'', les portions inutilisées sont désactivées. La technique marche d'autan mieux si les micro-opérations sont compactées au début de le ''scheduler''. [[File:Wire partitionning.png|centre|vignette|upright=2|Wire partitionning]] Tout le problème est de savoir quelles portions désactiver. La technique est assez simple si le ''scheduler'' est compactée, à savoir si toutes les micro-opérations sont régulièrement regroupées au début de la mémoire CAM. Mais même avec cette optimisation, la décision de désactiver une portion de le ''scheduler'' n'est pas à prendre à la légère. Il ne faut pas désactiver une portion contenant des instructions pouvant être émise sous peu. La décision dépend de paramètres variés : proportion d'entrée vides, quantité d'entrées récemment activées/désactivées récemment, présences d'entrées avec un ''match'' d'opérandes récent, etc. Il est important de préciser que les techniques en question fonctionnent aussi sur les autres types de ''scheduler'', qui ne sont pas basées sur des mémoires associatives. Nous allons voir celles-ci dans la suite du chapitre, mais gardez à l'esprit que ces optimisations, à savoir désactiver les entrées vides/prêts et partitionner le ''scheduler'', sont des optimisations générales qui marchent avec presque tout. ===L'ajout d'une FIFO pour les micro-opérations déjà prêtes à l'émission=== D'autres techniques permettent de réduire aussi bien le cout en circuits que la consommation d'énergie de le ''scheduler''. L'idée est d'utiliser une mémoire associative quand elle est réellement nécessaire, mais d'utiliser un ''scheduler'' "normale" dès que possible. La méthode la plus simple tient compte du fait que certaines µops ont déjà tous leurs opérandes de disponibles à l'émission, mais doivent quand même être mises en attente, parce que l'ALU adéquate est occupée, parce que des dépendances WAW/WAR sont encore là, ou pour tout autre raison. Dans ce cas, elles sont mises en attente non pas dans le ''scheduler'', mais dans une mémoire FIFO toute simple. L'idée est qu'au lieu d'avoir une énorme mémoire associative pour le ''scheduler'', on déplace quelques entrées dans une petite FIFO annexe. Le résultat est un gain d'énergie et de circuits, au prix d'une perte de performance mineure. La perte de performance en question se manifeste si aucune instruction n'a ses opérandes de prêtes à l'émission : le programme n'utilise pas la FIFO et voit alors un ''scheduler'' plus petite. Une amélioration de cette technique tient compte du fait que certaines instructions sont dans un cas intermédiaire. Elles ont déjà un opérande de prête lors de l'émission, mais pas l'autre. Le nombre d'opérandes varie suivant l’instruction : certaines n'ont besoin que d'un seul opérande. De plus, il arrive qu'une opération tout juste décodée ait déjà un ou plusieurs de ses opérandes de prêts. Cette constatation permet d'éviter d'utiliser des comparateurs pour les opérandes déjà prêts. Par exemple, on peut parfaitement utiliser trois ''scheduler'' : * une pour les micro-opérations dont tous les opérandes sont prêts, mais qui sont quand même mises en attente, sans comparateur ; * une pour les micro-opérations dont un seul opérande manque, qui n'utilise qu'un comparateur par entrée ; * une pour les micro-opérations dont deux opérandes manquent à l'appel, qui utilise deux comparateurs par entrée. C'est beaucoup plus économique que d'utiliser une seule grosse ''scheduler'' qui contiendrait autant d'entrées que les trois précédentes réunies, avec deux comparateurs par entrée. Certains sont même allés plus loin, et ont proposé de supprimer le ''scheduler'' avec deux opérandes par entrée. Les micro-opérations dont deux opérandes sont inconnus au décodage sont stockées dans le ''scheduler'' pour instructions avec un comparateur par entrée. Un circuit de prédiction se charge alors de prédire l'opérande manquant, cette prédiction étant vérifiée plus loin dans le pipeline. Il serait cependant étonnant qu'une telle proposition ait donné lieu à la moindre implémentation réelle. ===Les optimisations de la consommation d'énergie avancées=== D'autres chercheurs ont conservé un ''scheduler'' unique, avec autant de comparateurs par entrée qu'il y a d'opérandes possibles par instruction. Simplement, le processus de détection des opérandes prêts est légèrement ralenti : on ne vérifie qu'un opérande par cycle. Pour vérifier les deux opérandes d'une entrée, on doit attendre deux cycles. Enfin, certains chercheurs ont proposé des ''scheduler'' segmentées. Les micro-opérations circulent à chaque cycle d'un segment vers le suivant : en conséquence, certains segments conservent les micro-opérations les plus anciennes, un autre les micro-opérations les plus jeunes, etc. Seul le denier segment, celui qui contient les micro-opérations les plus vielles, peut émettre une instruction : la détection des opérandes se fait seulement dans le dernier segment, qui contient les micro-opérations les plus anciennes. On économise ainsi beaucoup de comparateurs. Certains chercheurs ont tenté de pipeliner l'étape de sélection des opérandes, ainsi que l'étage d'arbitrage. Mais en faisant cela, il faut plusieurs cycles pour détecter qu'une instruction a ses opérandes prêts, ce qui pose problème face à de nombreuses dépendances RAW. Pour éviter de trop perdre en performances, certains chercheurs ont décidé d'utiliser des techniques pour prédire quelles seront les micro-opérations dont les opérandes seront bientôt prêts. Si détecter qu'une instruction est prête prend n cycles, le processeur devra tenter de prédire la future disponibilité des opérandes n cycles en avance pour obtenir des performances optimales. ===Remplacer la mémoire associative par une RAM=== Une autre optimisation possible est de remplacer le ''scheduler'' par une mémoire RAM, dont chaque mot mémoire correspondrait à une entrée. Une telle optimisation permet en théorie de se passer des comparateurs associés à chaque entrée, mais au prix de l'ajout de circuits annexes potentiellement couteux. La première de ces techniques, la '''recherche directe par étiquette''' (direct tag search) fut créée par Weiss et son collègue Smith. Ils cherchaient à améliorer l'algorithme de Tomasulo, un algorithme qu'on expliquera dans quelques chapitres. Rappelons que chaque instruction produit un résultat, qui devra être rapatrié dans une ou plusieurs entrées de le ''scheduler''. L'optimisation de la recherche directe par étiquette fonctionne dans le cas où le résultat de la micro-opération n'est utilisé que par une seule entrée, et pas plusieurs. Le principe est simple : chaque champ « opérande » d'une entrée est adressable via le nom de registre de cet opérande. Pour faire le lien entre entrée et nom de registre, la recherche directe par étiquette ajoute une table de correspondances matérielle, une mémoire RAM qui mémorise les adresses des champs « opérande » des entrées. Les adresses envoyées dans cette mémoire sont les noms de registres des résultats. Lors de l'émission, la table de correspondances est mise à jour. Les numéros des champs « opérande » réservés lors de l'émission sont mémorisés dans les mots mémoire qui correspondent aux deux registres sources. Toutefois, une petite vérification est faite lors de l'émission : s'il y a déjà une correspondance dans la table pour un registre source, alors une autre instruction compte lire ce registre. Pour éviter d'écraser les données de la micro-opération précédente dans la table de correspondances, l'émission de la micro-opération est bloquée. [[File:Recherche directe par étiquette.png|centre|vignette|upright=2|Recherche directe par étiquette.]] ==Les ''schedulers'' avec préplanification== Avec la '''préplanification''' (''prescheduling''), le ''scheduler'' est composée de mémoires FIFO dans lesquelles les micro-opérations sont triées dans l'ordre d'émission. Il n'y a pas de logique d’émission proprement dite, celle-ci se bornant à vérifier si la micro-opération située au début de la FIFO peut s’exécuter. Par contre, le préplanificateur détecte les dépendances et en déduit où insérer les micro-opérations dans le tampon d'émission, à l'endroit le plus adéquat. [[File:Préplanification.jpg|centre|vignette|upright=2|Préplanification.]] ===L'usage de FIFO multiples=== La technique de préplanification la plus simple utilise plusieurs FIFO. Quand une instruction a une dépendance avec une autre instruction, les deux sont placées dans la même FIFO. Pour cela, le préplanificateur détecte les chaines d'instructions dépendantes, et place les micro-opérations dans la FIFO adéquate. A chaque cycle, l'unité d'émission lit une micro-opération dans chaque FIFO et vérifie si elle peut l'émettre. Si la micro-opération n'a pas ses opérandes disponibles, ou qu'une dépendance structurelle survient, alors la FIFO est bloquée. La micro-opération attend que la dépendance soit résolue, bloquant toutes les micro-opérations précédentes. Mais les autres FIFO ne sont pas bloquées, laissant de la marge de manœuvre. [[File:Préplanification par FIFO multiples.png|centre|vignette|upright=1.5|Préplanification par FIFO multiples.]] ===La technique du tampon trié=== La technique du '''tampon trié''' trie les micro-opérations selon le temps d'attente avant leur exécution. Les micro-opérations qui sont censées s’exécuter bientôt sont insérées au tout début de la FIFO, tandis que les micro-opérations qui s’exécuteront dans un long moment sont insérées vers la fin. Là encore, l'unité d'émission lit une micro-opération dans la FIFO, et détermine si elle peut être émise. Si une dépendance survient, l'émission est retardée, et la FIFO est bloquée. [[File:Préplanification par tampon trié.png|centre|vignette|upright=1.5|Préplanification par tampon trié.]] La technique a cependant quelques problèmes assez importants. Le premier problème est que la FIFO est bloquée lorsqu'une micro-opération ne peut être émise. Le second problème est que le temps avant exécution n'est pas toujours connu, notamment pour les micro-opérations d'accès mémoire. Et cela se répercute sur les micro-opérations dépendantes de celles-ci. Pour résoudre ce genre de problèmes, l'usage d'un pipeline à ''replay'' est possible, et est même l'une des meilleures solutions possible, malgré ses défauts. L'idée est que les lectures sont pré-planifiées en supposant qu'elles font un succès de cache L1. Si la prédiction est fausse, la lecture est ré-exécutée plusieurs cycles plus tard, en supposant qu'elle fait un succès dans le cache L2, et ainsi de suite. Elle est alors ré-insérée dans la FIFO, elle est pré-planifiée une seconde fois. Il en est de même si une micro-opération ne peut pas être émise : il suffit de la réinsérer dans la FIFO au bon endroit, en attendant que ses dépendances soient résolues. Ainsi, la micro-opération fautive ne bloque pas le ''scheduler'', et retente sa chance autant de fois qu'il le faut. [[File:Préplanification par fenêtre d’instruction scorebarodée.png|centre|vignette|upright=1.5|Préplanification par ''scheduler'' scorebarodé.]] Une autre solution utilise deux ''schedulers'' : une FIFO gérée par la préplanification, et une vraie ''scheduler'' pour les micro-opérations dont le temps d'attente ne peut pas être déterminé. Il est possible de mettre cette dernière avant la préplanification, afin de gérer les temps d'attente des instructions d'accès mémoire. Quand le temps d'attente d'une lecture devient connu, ses instructions dépendantes sont gérées avec préplanification. [[File:Préplanification avec fenêtre d’instruction.png|centre|vignette|upright=2.5|Préplanification avec ''scheduler''.]] ===Les ''scheduler'' avec allocation temporelle statique=== L''''allocation temporelle statique''' correspond à une technique utilisée sur les processeurs Cuzco de l'entreprise Condor. La technique en question a été présenté en 2025, mais des idées similaires ont été présentées dans la littérature académique. Elle ressemble beaucoup aux techniques de pré-planification, avec cependant quelques différences. L'idée est simple : le processeur dispose de plusieurs ''scheduler'', qui mettent en attente les micro-opérations. Lors de l'étape de renommage de registres, le processeur détermine dans combien de cycles d'horloge la micro-opération sera prête pour exécution. La micro-opération est alors mise en attente durant ce nombre de cycles, dans les ''scheduler'', puis est émise une fois ce nombre de cycles écoulés. Ce faisant, les ''scheduler'' n'ont pas besoin de détecter la disponibilité des opérandes à chaque cycle, pour chaque micro-opération en attente. Le ''timing'' de l'émission des micro-opérations est décidé à l'avance. L'implémentation exacte n'est pas connue, mais plusieurs solutions sont imaginables. Par exemple, le ''scheduler'' peut simplement être composée de plusieurs mémoires de petite taille, chacune contenant les micro-opérations destinées à être exécutées dans N cycles, N étant différent pour chaque mémoire. Une autre solution, plus réaliste, utilise un ''scheduler'' dans laquelle la micro-opération est couplée à des champs pour les opérandes, et un champ compteur. Le champ compteur est initialisé avec le nombre de cycles à attendre, et est décrémenté à chaque cycle d'horloge. Quand il atteint zéro, la micro-opération est émise. Vous remarquerez que la méthode ne marche que si toutes les micro-opérations prennent un nombre fixe de cycles d'horloge. Et autant c'est le cas pour les micro-opérations arithmétiques ou logiques, autant les accès mémoire ne rentrent pas dans ce cadre. En théorie, on ne sait pas combien de temps prendra un accès mémoire. Et cette incertitude se répercute sur les micro-opérations dépendantes d'un accès mémoire. Pour éviter cela, le processeur réutilise un pipeline à ''replay'' tel que vu dans le chapitre précédent. L'unité de renommage de registre suppose que tout accès mémoire fait un succès de cache L1, et décide des ''timings'' d'émission sous cette hypothèse. Si une lecture subit un défaut de cache, elle est ré-exécutée, de même que toutes les micro-opérations dépendantes. Pour cela, le registre de destination de la lecture est marqué comme invalide, grâce à un bit spécifique attaché au registre. Toute instruction qui lit un opérande invalide est elle aussi ré-executée de zéro. Pour simplifier, l'unité d'émission ressemble à une unité d'émission dans l'ordre, avec un registre de disponibilité, qu'on aurait amélioré pour aller au-delà de la simple détection des dépendances d'instruction. Pour déterminer les ''timings'' d'émission, à savoir quand émettre une micro-opération, le processeur utilise une unité d'émission à deux étages. Le premier étage est appelé le ''register scoreboard'', le second étage est appelé la ''Time Ressource Matrix''. Les deux étages communiquent entre eux, comme on va le voir, et leurs noms donnent une idée de ce qu'ils font. Le premier étage gère les dépendances de registres, le second gère les dépendances structurelles. Le premier étage est un registre de disponibilité amélioré, qui gère les dépendances de registre. Cet étage sait quand tel registre sera écrit, et donc que l'opérande écrit dedans sera disponible à partir de tel cycle d'horloge. Il le sait, car l'étage suivant l'aura prévenu, mais laissons cela de côté pour le moment. Quand une micro-opération rentre dans cet étage, il vérifie les dépendances avec les registres et les micro-opérations antérieures. Vu qu'il sait quand les registres seront disponibles, il peut déterminer quand la micro-opération pourra s'exécuter. Par exemple, si une micro-opération lit les deux registres R7 et R15, qui sont disponibles respectivement dans 5 et 7 cycles, le premier étage sait que la micro-opération devra attendre 7 cycles. Mais tout cela ne suffit pas à déterminer quand émettre une micro-opération. En effet, il fait aussi gérer les dépendances structurelles, ce qui est le boulot du second étage. Le second étage utilise pour cela une ''Time Ressource Matrix'', qui mémorise l'occupation de diverses "ressources", pour les 256 cycles d'horloge à venir. Les ressources en question sont les ports de lecture/écriture du banc de registre, les ALUs utilisées, si la micro-opération utilise l'unité mémoire, etc. Le second étage prend en entrée une micro-opération, détermine quelles "ressources" elle utilise, puis regarde leur disponibilité. Elle détecte alors les dépendances structurelles et détermine alors quand peut s'exécuter la micro-opération. Elle peut retarder l'émission de quelques cycles, si une dépendance structurelle est détectée. Une fois sortie du second étage, on sait quand la micro-opération va être émise, à quel cycle précisément. Et vu que la durée de la micro-opération est fixe, on sait quand cette micro-opération va se terminer, quand son résultat sera disponible. Cela permet de mettre à jour la ''Time Ressource Matrix'', pour préciser que le port d'écriture sera occupé à tel moment. De plus, cette information est transmise au premier étage, qui sait alors quand est enregistré le résultat dans le registre de destination. C'est comme cela que le premier étage sait quand un registre est disponible : le second étage le prévient, quand il émet une instruction ! La ''Time Ressource Matrix''mémorise l'occupation des "ressources" pour les 256 cycles d'horloge à venir. Cependant, elle ne vérifie pas les dépendances pour les 256 cycles suivants. Quand elle reçoit une micro-opération, elle teste les dépendances structurelles pour seulement les 8 prochains cycles maximum. Si la micro-opération ne peut pas être émise pendant ces 8 cycles, le pipeline est bloqué, un ''pipeline stall'' est émis. Pour être plus précis, vu que le processeur peut décoder 8 micro-opérations en même temps, cela permet de ne consulter que 64 cycles d'horloge sur les 256. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les premiers processeurs Intel | prevText=Les premiers processeurs Intel | next=Le renommage de registres | nextText=Le renommage de registres }} </noinclude> m588of7k54masdnh45fod4outrgyfne Fonctionnement d'un ordinateur/Le scoreboarding et l'algorithme de Tomasulo 0 65891 773606 755763 2026-09-29T19:53:09Z Mewtow 31375 773606 wikitext text/x-wiki Dans ce chapitre, nous allons voir deux techniques d'exécution dans le désordre un peu à part. Il s'agit de deux techniques historiquesn utilisées sur des ordinateurs très anciens, qui portent les noms de ''scoreboarding'' et d'algorithme de Tomasulo. Les deux ne sont plus utilisés aujourd'hui, pour diverses raisons, la principale étant qu'elles ne gèrent pas les exceptions précises. En clair, impossible de les utiliser en même temps que la prédiction de branchement ou d'autres optimisations. Elles ne gèrent pas les exceptions précises, car elles utilisent des formes de renommage de registre assez originale. L'algorithme de Tomasulo renomme les registres dans les stations de réservation, chose qu'on n'a volontairement pas abordé dans le chapitre sur le renommage de registre. le ''scoreboarding'' utilise quant à lui une technique similaire, mais bien plus difficile à classer, qui est clairement idiosyncratique. Il est possible de les modifier pour leur adjoindre un ROB, mais le résultat ressemble beaucoup aux techniques de renommage dans le ROB. ==L'algorithme de Tomasulo et les stations de réservation== L''''algorithme de Tomasulo''' est un algorithme assez compliqué à expliquer, car il mélange exécution dans le désordre, contournement et renommage de registre implicite en un seul algorithme. L'algorithme de Tosmasulo a été implémenté une première fois sur les ordinateurs IBM 360/91, et quelques processeurs ont utilisé une variante de celui-ci. Beaucoup de processeurs modernes se sont sont inspiré de cet algorithme pour leur design. Il est antérieur au ''scoreboarding'' du CDC 6600, qui avait des fonctionnalités similaires, mais nous allons le voir avant, afin de mieux faire ressortir les ressemblances entre les deux algorithmes. Avec l'algorithme de Tomasulo, le renommage de registre se fait dans des '''stations de réservation'''. Pour rappel, ce sont des fenêtres d'instructions qui ont pour particularité de mémoriser non seulement les µops en attente, mais aussi leurs opérandes. Les opérandes peuvent provenir de deux sources différentes. Soit elles sont lues depuis les registres avant l'émission, soit elles sont obtenues par le réseau de contournement. Dans son acceptation la plus stricte, le terme station de réservation est réservé au cas où il y a une station de réservation par unité de calcul. Et c'est le cas avec l'algorithme de Tomasulo initial, qui a été utilisé pour la première fois sur un processeur avec trois stations de réservation : une pour le circuit multiplieur/diviseur flottant, une pour l'additionneur flottant, et une pour l'unité LOAD/STORE. Un autre point très important est que, dans le papier de Tomasulo, les stations de réservation ne conservent que les µops en attente d'émission. L'algorithme original n'avait pas de ROB et ne gérait pas du tout les exceptions précises. Il ne peut donc pas être utilisé sur les architectures modernes, qui utilisent de la prédiction de branchement. Il est possible d'ajouter un ROB à l'algorithme, mais il doit être modifié et on retombe alors sur une forme de renommage dans le ROB. ===Les stations de réservation et le contournement=== Les stations de réservation mémorisent les µops en attente d'exécution sur l'unité de calcul, tant qu'elles n'ont pas encore leurs opérandes prêtes. Par modifiées pour faciliter le contournement, je veux dire par là qu'elles mémorisent les opérandes d'une µop à exécuter. Si les opérandes sont dans les registres, elles sont lues depuis les registres avant ''issue/dispatch'', et mémorisées dans la station de réservation. Si elles ne sont pas encore disponibles au moment de l'''issue'', elles seront fournies plus tard par le système de contournement et seront alors enregistrées dans la station de réservation. Le fait que la fenêtre d'instruction incorpore les opérandes de la µop implique une forme de renommage de registres implicite, comme on le verra plus tard. Pour rappel, il s'agit d'une technique dite de '''lecture avant émission''', qui lit les registres d'une µop avant de l'émettre. Pour gérer le contournement, les résultats d'une µop sont non seulement envoyés vers le ROB et/ou les registres, mais ils sont aussi envoyés vers les stations de réservation, via un bus de contournement. La sortie de chaque unité de calcul est connectée à toutes les stations de réservation, dans le cas idéal. Pour cela, la sortie des unités de calcul est reliée aux stations de réservation via un bus, appelé le ''bus commun d’ordonnancement de la mémoire'' (''common memory-ordering bus''), que nous nommerons dorénavant ''bus de contournement''. [[File:Algorithme de Tomasulo.png|centre|vignette|upright=2|Algorithme de Tomasulo]] L'idée derrière le '''bus de contournement''' est que les sorties des unités de calcul sont reliées à un bus, qui est lui connecté aux entrées des ALU. La contrainte est qu'une seule unité de calcul peut envoyer des données sur ce bus. Rien d'étonnant : c'est un bus, il ne peut transférer qu'une donnée à la fois. Si plusieurs unités de calcul veulent transmettre leurs résultats sur ce bus, l'une d'entre elle est choisie et les autres doivent mettre en attente leurs résultats dans une mémoire tampon, soit un registre, soit une FIFO. Dans les deux cas, le registre ou la FIFO sont appelés des ''producers''. L'implémentation demande de bloquer des opérations dans l'ALU si le contournement doit être mis en attente, ce qui bloque tout le pipeline en cas de problème. [[File:Producteurs en sortie d'une ALU.jpg|centre|vignette|upright=2|Producteurs en sortie d'une ALU.]] Le bus de contournement est assez spécifique à l'algorithme de Tomasulo, dans le sens où c'est un des rares articles académique à utiliser un tel bus de contournement. ===Le renommage de registres dans les stations de réservation=== L'unité d'émission attribue à chaque résultat de calcul un '''identifiant de résultat'''. L'identifiant est une sorte de numéro de registre virtuel, qui est transmis sur le bus de contournement. L'identifiant est propagé comme tout signal de commande, il suit la µop sur son trajet dans le pipeline. Quand l'unité de calcul a fini son calcul, l'identifiant est envoyé avec le résultat sur le bus de contournement. Les stations de réservation contenant cet identifiant de résultat enregistrent alors le résultat dans le champ adéquat. De plus, le ROB a des entrées modifiées pour contenir l'identifiant de résultat, afin d'associer un identifiant de résultat à un registre de destination. Les entrées des stations de réservation sont structurées en plusieurs champs. Le premier mémorise l'opcode de l'instruction/µop. Il y a aussi un champ pour l'identifiant de résultat. Il y a aussi deux champs, un par opérande. Il peut contenir deux choses : l'opérande elle-même, l'identifiant de résultat associé. Pour faire la différence, les deux champs ont chacun un bit de présence, qui indique si l'opérande est présente dans le champ ou non (auquel cas, c'est un identifiant). [[File:Entrée d'une station de réservation.png|centre|vignette|upright=3|Entrée d'une station de réservation.]] Vous vous demandez certainement où sont les registres virtuels avec cette organisation. Et bien il ne s'agit ni plus ni moins que des stations de réservation. Et plus précisément les champs pour les opérandes. L'identifiant de résultat est l'équivalent d'un nom de registre virtuel. D'ailleurs, une fois la µop émise, il n'y a pas de noms de registre physique dans les stations de réservation, seulement des identifiants de résultat. En somme, le renommage de registre est pris en charge par les stations de réservation, et par le système de contournement. ===L'exécution d'une µop avec l'algorithme de Tomasulo=== L'exécution d'une µop avec des stations de réservation se fait en plusieurs étapes. Premièrement, la µop est émise, dans le sens où elle est transmise de l'unité d'émission aux stations de réservation. Deuxièmement, la µop est exécutée ou attend son exécution. Enfin, son résultat est enregistré dans les registres et envoyé aux stations de réservation pour contournement. L'émission se fait sous condition qu'une station de réservation pour l'unité de calcul voulue soit disponible. Si c'est le cas, l'unité d'émission vérifie si les opérandes sont disponibles dans le banc de registre architecturaux. Les opérandes disponibles sont alors traitées différemment des opérandes non-disponibles. Les opérandes non-disponibles, elles seront envoyées via contournement plus tard et le renommage de registre doit être utilisé. L'opérande est associée à l'identifiant de résultat qui permet de savoir quand elle sera calculée. À l'opposé, les opérandes disponibles sont lues depuis les registres et enregistrées dans la station de réservation, leur bit de présence est mis à 1. Il n'y a pas de renommage de registres, car il n'y en a pas besoin pour ces opérandes. Reprenons maintenant après l'émission de la µop, qui a été envoyée dans les stations de réservation. Elle attend alors que ses opérandes soient disponibles dans la station de réservation. Les opérandes non-disponibles sont alors calculées par des µops et sont envoyées sur le bus de contournement. La station de réservation reconnait alors l'identifiant et enregistre le résultat dans le champ adéquat. Une fois toutes les opérandes disponibles, la µop est exécutée. Une fois son résultat connu, il est envoyé sur le bus de contournement, mais aussi dans le banc de registres. Et le tout continue. ==Le ''scoreboarding'' du CDC 6600== L'implémentation du ''scoreboard'' sur le CDC 6600/7600 est appelée dans la suite du cours : le '''''scoreboarding'''''. La description que je vais donner du ''scoreboard'' est très différente de celle disponible dans les livres d'architecture des ordinateurs. La plupart des manuels, surtout les textbooks américains, donnent une description très haut niveau, très algorithmique du ''scoreboarding'', qui ne sera pas abordée. À la place, je vais donner une description alternative, différente autant sur l'approche que le fond. Le CDC 6600 n'existe plus, tous les exemplaires ont depuis longtemps été démontés, aussi il ne reste que des sources historiques pour savoir comment fonctionnait son ''scoreboard''. Heureusement, il existe un livre qui décrit dans les moindres détails cette architecture, écrit par un des concepteurs de l'ordinateur : [https://archive.computerhistory.org/resources/text/CDC/cdc.6600.thornton.design_of_a_computer_the_control_data_6600.1970.102630394.pdf Design of a computer : the CDC 6600]. Ce qui va suivre est majoritairement ité de cette source. ===Le chemin de données du CDC 6600 et sa relation avec le ''scoreboard''=== Le pipeline d'un processeur avec ''scoreboarding'' ressemble à celui du schéma suivant. Pour résumer, le chemin de donnée forme un pipeline à trois étages : lecture des registres, exécution dans l'ALU, écriture dans les registres. Les opérations à effectuer son envoyées aux ALUs, et elles attendent leurs opérandes dedans. [[File:Scoreboard avec exceptions imprécises.png|centre|vignette|upright=2|Scoreboard avec exceptions imprécises]] La séparation en trois étages fait qu'il y a des registres entre chaque étages. Les opérandes sont chargées dans des registres en amont de l'ALU, et le résultat est enregistré temporairement dans un registre en sortie de l'ALU. Nous les appellerons : '''registres opérandes''' et '''registre résultat'''. Entre les deux, l'ALU effectue une opération quand les opérandes sont disponibles dans les registres opérandes, et maintien le résultat dans le registre résultat si besoin. Il y a aussi un autre registre qui mémorise l'opcode de l'opération, lors de l'attente des opérandes, mais aussi lors de l'exécution. Nous l'omettrons dans ce qui suit, car il s'agit d'un registre de pipeline classique. Les registres opérande et résultat n'ont pas besoin d'être très complexes vu qu'ils servent juste à maintenir une donnée. Les registres ne sont pas connectés à l'horloge, les bascules ne sont pas synchrones, ils sont fabriqués à partir de simples ''latches'', de simples bascules D non-synchrones. Et il en est de même pour le registre d'opcode. Le ''scoreboard'' commande le signal Enable qui autorise les écritures dedans, rien de plus. Le pipeline est donc le suivant : [[File:Pipeline d'un processeur utilisant le scoreboarding.png|centre|vignette|upright=2|Pipeline d'un processeur utilisant le scoreboarding]] Les registres opérandes sont chacun associé à un bit READ FLAG qui précise si l'opérande du calcul est disponible. Les bits READ FLAG sont mis à jour par un mécanisme assez complexe, qui sera vu dans la suite. Le ''scoreboard'' gère les transferts entre les registres opérande/résultat et le reste du processeur. Il génère deux signaux de 1 bit nommés GO READ et GO STORE/GO WRITE. Le signal GO READ déclenche la copie d'un registre architectural dans un registre opérande. Le signal GO WRITE déclenche la copie du registre résultat dans le registre architectural adéquat. Pour effectuer une lecture ou une écriture, les noms des registres adéquats sont mémorisés dans deux registres notés Fi, Fj, et Fk. Fi mémorise le registre de destination de l'opération, Fj et Fk mémorisent les noms/numéros des registres opérandes. Les deux registres Qj et Qk sont utilisés pour la détection des opérandes disponibles, nous en reparlerons plus tard. Les registres Fi, FJ et Fk sont dans le ''scoreboard'', et ils sont envoyés sur les entrées d'adresse du banc de registre suivant les besoins, suivant qu'on fasse une lecture ou une écriture. La lecture et écriture des registres donc totalement le fait du ''scoreboard'', qui commande le banc de registres, comme le ferait un séquenceur normal. [[File:CDC 6600 datapath control.png|centre|vignette|upright=2|CDC 6600 datapath control]] Notez que les registres opérandes, couplés au registre d'opcode, peuvent être vus comme une station de réservation simplifiée, sans gestion du contournement. La différence principale avec l'algorithme de Tomasulo est que les champs pour les identifiants de résultat ont disparus, et que les bits de disponibilité des opérandes READ FLAG sont en réalité intégré au ''scoreboard'', comme on le verra plus tard, avec une gestion de la disponibilité des opérandes totalement différente. De plus, il n'y a qu'une seule station de réservation par ALU, donc un risque plus grand de dépendances structurelles. On ne peut mettre en attente qu'une seule µop par ALU, avec le ''scoreboard''. ===Les désignateurs utilisés par le ''scoreboard''=== Les registres opérandes et résultat ne sont pas des registres architecturaux, mais ce ne sont pas des registres de pipeline non plus. Il est possible de faire l'analogie avec une station de réservation, mais l'analogie est limitée pour une raison simple : le ''scoreboard'' attend que les deux opérandes sont disponibles pour déclencher la lecture avec le signal GO READ. En théorie, il est tout à fait possible de lire un registre opérande à la fois, dès que l'opérande est disponible, mais le ''scoreboard'' ne faisait pas comme ça. De plus, les opérandes ne sont pas vraiment transmises via un réseau de contournement depuis la sortie de l'ALU. Cependant, une rumeur veut que le processeur implémente un système de contournement, qui passe...par l'intermédiaire des registres. Paradoxal, mais qui s'explique pourtant très bien quand on connait le fonctionnement des registres utilisés. Le processeur utilisait une ancienne technologie de transistors, appelée ECL. Beaucoup de bancs de registres fabriqués avec cette technologie avaient une propriété intéressante : toute donnée écrite sur le port d'écriture était immédiatement disponible sur le port de lecture. Plus précisément, l'écriture se faisait sur front montant et la lecture sur front descendant. En faisant cela, une opérande pouvait être écrite dans les registres architecturaux, mais pourtant copiée dans les registres opérandes au même cycle. Le tout fonctionne presque comme un système de contournement, avec cependant quelques limitations ! Avec un vrai système de contournement, l'implémentation est beaucoup plus puissante. Quant à savoir si les registres opérandes sont nommés, c'est un peu compliqué et la réponse serait qu'ils sont nommés de manière implicite. Il est d'ailleurs débattable de savoir si le CDC 6600/7600 implémente le renommage de registres... Le point de discorde est lié au fait que le ''scoreboard'' attribue un numéro à chaque unité de calcul, appelé le '''désignateur Q'''. Et ces identifiants sont utilisés pour la lecture des opérandes et leur copie dans les registres, ils se comportent comme un nom de registre virtuel. Pour simplifier les explications, nous allons partir du principe que les désignateurs sont encodés en représentation unaire. Pour rappel, la représentation unaire représente un nombre sur plusieurs bits, dont un seul est à 1. Un zéro est codé en mettant tous les bits du nombre à zéro, la valeur 1 est encodée avec la valeur 000...0001, le deux avec 000...0010, etc. {|class="wikitable" |+ Désignateur d'ALU |- ! ALU ADD !! ALU MUL !! ALU DIV !! ALU SUB !! ALU CMP !! ALU MOV |- | 0 || 0 || 1 || 0 || 0 || 0 |} La réalité est que les désignateurs sont présents à plusieurs endroits et sont soit codés en unaires, soit codés en binaire, avec des traductions fréquentes entre les deux. Ils sont par exemple traduits du binaire vers l'unaire lors de la génération des signaux READ FLAG. Les traductions inverses sont aussi fréquentes. Les traductions se basent sur des décodeurs/encodeurs un peu modifiés. L'avantage de la représentation unaire est que les comparaisons sont légèrement plus simples, les comparateurs économisent quelques portes logiques. De plus, elle s'adapte assez bien avec le fait que chaque unité de calcul précise si elle est disponible ou non, ce qui deviendra plus clair dans la suite. ===Les réservations et la table de réservation=== Le ''scoreboard'' du CDC 6600 contient une table de '''réservation''', qui permet de réserver une unité de calcul pour une µop à émettre. La table de réservation est composée d'entrées, une par unité de calcul, qui peut mémoriser une µop. Une entrée mémorise pour chaque unité de calcul : * l'opcode de l'instruction à exécuter dessus ; * les noms/numéros des registres opérandes et destination ; * les désignateurs Q des unités de calcul qui fourniront les opérandes en résultat ; * deux bits READ FLAG qui disent si l'opérande associé est disponible. : Dans le livre utilisé comme source, il n'est pas clair si les noms des registres opérandes/résultat sont placés dans l'unité de calcul ou dans le ''scoreboard''. Les explications semblent indiquer que c'est juste à côté de l'ALU, mais les schémas se contredisent là-dessus. Dans la suite, je pars du principe qu'ils sont dans le ''scoreboard'', ce qui aurait bien plus de sens. Le ''scoreboard'' consulte la table de réservation pour émettre une µop. Avant d’émettre une µop, elle regarde si l'entrée est libre ou déjà occupée par une µop. Pour cela, chaque entrée est associée à un bit BUSY qui indique si l'entrée est vide ou occupée. Vu qu'il y a une entrée par unité de calcul, attribuer une entrée à une µop est asszz simple : chaque µop va dans une entrée bien précise, il suffit de vérifier celle-ci. Le bit BUSY est mis à 1 quand une µop est émise, ajoutée dans l'entrée, mis à zéro quand elle est terminée. La libération d'une entrée se fait quand le signal GO WRITE est émis, le signal RELEASE ne suffit pas. La réservation permet de réserver une ALU pour une opération. La µop est alors envoyée à l'ALU, où elle attend que ses opérandes soient disponibles. Une µop attend son tour et n'est émise qu'une fois que les deux bits READ FLAGS sont à 1. La conséquence est qu'une µop reste dans l'unité de calcul tant qu'elle a des dépendances RAW. Et seules les dépendances RAW, où une instruction pour opérande le résultat d'une instruction précédente, impliquent un blocage du pipeline et des bulles de pipeline. Les dépendances WAW ou WAR sont traitées autrement. La table de réservation ne stocke pas les opérandes, ce qui fait qu'on peut la voir comme une fenêtre d'instruction à une entrée, ou encore comme une station de réservation castrée. Un détail très important est que ce système de réservation met en attente une µop par ALU. Vu que toutes les ALUs du CDC 6600 sont très différentes, l'attribution d'une µop à une ALU est trivial. Par contre, si une µop veut utiliser une ALU réservée, elle ne peut pas et il faut bloquer le pipeline. Le système de réservation est donc une cause de dépendances structurelles qui bloquent l'émission des µops dans de nombreux cas. Ce ne serait pas le cas si on pouvait placer plusieurs réservations par unité de calcul, mais passons. Pour une dépendance WAR, la µop est émise, elle s'exécute, mais son résultat est maintenu dans le registre résultat le temps que ces dépendances soient résolues. Pour le dire autrement, Les dépendances WAR font que les µops sont retenues dans l'étage d'enregistrement des données, un peu comme sur un processeur à pipeline multicycle (de longueur fixe). Sauf que les pipeline multicycle, il y aurait plusieurs registres d'échelonnements qui se suivent, alors qu'on n'en a qu'un ici, ce qui fait que l'unité de calcul est bloquée si l'écriture est retardée. En théorie, les dépendances WAW devraient être traitées avec un mécanisme similaire, mais le processeur détectait ces dépendances à l'émission et bloquait l'émission si un registre lu était accédé en lecture. [[File:Enregistrement des données dans les registres avec un pipeline avec scoreboarding.png|centre|vignette|upright=2|Enregistrement des données dans les registres avec un pipeline avec scoreboarding]] ===La Q-table : l'unité de renommage de registres=== Quand une µop est émise, elle réserve une unité de calcul. Mais il faut pour cela remplir les champs pour les désignateurs d'ALU, même si on voit mal à quoi ils servent pour le moment. Il se trouve que les registres opérandes contiennent une valeur, qui est le résultat d'une µop soit déjà passée par une ALU, soit en cours d'exécution dans une ALU. Le désignateur pour un opérande est donc le désignateur de cette ALU. Reste à faire la correspondance entre un résultat/registre et l'ALU qui va le calculer ou l'a déjà calculé. Pour cela, le ''scoreboard'' mémorise la correspondance entre un registre/résultat et une unité de calcul dans une mémoire cache appelée la '''''Q-table'''''. Pour comprendre à quoi elle sert, prenons deux instructions consécutives, dont la seconde utilise le résultat de la première. La première instruction est lancée dans une unité de calcul enregistre son résultat dans un registre de destination. Le ''scoreboard'' mémorise alors dans la ''Q-table'' que le registre de destination est associé à telle unité de calcul, elle mémorise une correspondance entre le désignateur de l'ALU et le registre de destination. Par la suite, la seconde instruction est émise. Le ''scoreboard'' interroge la ''Q-table'' pour les deux opérandes de l'instruction, pour récupérer les deux désignateurs de l'ALU associés. Ils sont envoyés au banc de registres pour gérer la lecture des opérandes. Pour résumer, le ''scoreboard'' effectue les actions suivantes lors de l'émission. * Premièrement, il détermine si l'unité de calcul est disponible ou non, en utilisant le bit de disponibilité BUSY. * Deuxièmement, il mémorise les numéros de registres opérande et résultat pour commander la lecture des opérandes. * Troisièmement, il traduit les numéros de registres opérande en identifiants d'ALU. * Quatrièmement, il mémorise dans une ''Q-table'' la relation entre le registre de destination et l'unité de calcul choisie à l'étape 1. La troisième étape permet de faire le lien entre un résultat calculé mais pas encore enregistré dans les registres, et un registre opérande non-nommé. Le lien guide le chargement des opérandes et donc le système de contournement passant par des registres (ce qui est du renommage de registre implicite). ===La gestion des résultats : les signaux RELEASE et GOWRITE=== Une fois la µop exécutée, son résultat est enregistré dans le registre résultat. Une fois le résultat dans le registre résultat, l'unité de calcul envoie un signal REQUEST au ''scoreboard'' pour savoir si la donnée peut être enregistrée dans les registres architecturaux. L'ensemble des signaux REQUEST est regroupé dans un vecteur de bit, une sorte de nombre, dont chaque bit indique quelle unité veut écrire un résultat. L'ensemble des signaux RELEASE forment un nombre encodé en unaire qui indique quelle ALU a fournit le résultat. Là, le ''scoreboard'' effectue plusieurs opérations successives sur ce nombre, en appliquant plusieurs masques. Le premier masque appliqué vérifie pour chaque ALU si elle a le droit d'écrire son résultat en mémoire, sur la base des dépendances WAW et WAR. En cas de dépendances WAR ou WAW, l'écriture du résultat est retardé, ce qui fait que l'unité de calcul n'est pas considérée, son signal RELEASE est ignoré, il est masqué. Le masque qui permet cela est appelé le '''masque READ PENDING'''. Le second masque est un circuit de priorité qui sélectionne un bit seulement. Il est en effet possible que plusieurs unités de calcul fournissent un résultat en même temps. Ou encore que l'une ait son écriture retardée et ait un signal RELEASE à 1 depuis plusieurs cycles. Toujours est-il qu'on ne peut écrire qu'un résultat à la fois, ce qui fait qu'il faut sélectionner une unité de calcul. Pour cela, un circuit de priorité sélectionne un seul signal RELEASE à 1 et met les autres à zéro. C'est le second masque. {|class="wikitable" |+ Traitement des signaux REQUEST |- ! colspan="10 | Signaux REQUEST en sortie des ALUs |- | 0 || 1 || 0 || 1 || 1 || 1 || 0 || 0 || 0 || 0 |- ! colspan="10 | Application du masque READ PENDING pour les dépendances WAW/WAR |- | 0 || 0 || 0 || 1 || 1 || 0 || 0 || 0 || 0 || 0 |- ! colspan="10 | Sélection par un circuit de priorité |- | 0 || 0 || 0 || 1 || 0 || 0 || 0 || 0 || 0 || 0 |} Après l'application du second masque, il ne reste qu'un seul bit à un, qui indique quelle ALU a été sélectionnée pour l'écriture. Il se trouve que l'ensemble des bits forme un désignateur d'ALU, encodé en représentation unaire, en représentation ''one-hot''. Pour rappel, cela veut dire que seul un bit dans le nombre est à 1 et ce bit indique la valeur encodée. Si le bit numéro X est à 1, alors la valeur encodée vaut X. L'usage d'une représentation unaire/''one-hot'' fait que l'on a juste à concaténer les signaux REQUEST et appliquer des masques pour obtenir le désignateur adéquat, pas besoin d'encodeur compliqués, ni de circuits de sélection complexes. Le désignateur résultat est appelé '''désignateur d'ALU choisie'''. Une fois ce désignateur calculé, le ''désignateur d'ALU choisie'' est envoyé à la table de réservation, afin de récupérer le nom/numéro du registre résultat associé. Le ''scoreboard'' commande le port d'écriture du banc de registre, avec un signal GOWRITE et le nom/numéro du registre de destination récupéré. Le signal RELEASE est alors remis à zéro. Reste à générer le signal GO WRITE et faire les actions adéquates. Mais il reste deux opérations de maintenance pour terminer l'écriture. La première est de remettre en ordre la Q-table. L'entrée qui liait l'unité de calcul au registre de destination doit être remise à zéro. Le résultat ayant été écrit, il n'est plus associé à l'unité de calcul, le lien entre les deux dans la Q-table est donc effacé. La seconde est de gérer la disponibilité des opérandes. Pour cela, le résultat après application des deux masques est aussi utilisé pour détecter la disponibilité des opérandes, pour mettre à 1 le bit READ FLAG adéquat. Là encore, c'est la table de réservation qui s'en charge. ===La détection des opérandes disponibles : la génération des READ FLAG et du signal GOREAD=== Le désignateur d'ALU choise est envoyé à la table de réservation pour récupérer le nom de registre destination, mais aussi aux champs opérandes. Dans chaque entrée, il comparé aux deux désignateurs Qj et Qk, associés chacun à une opérande. Pour rappel, les désignateurs Qj et Qk sont des désignateurs d'unité de calcul, eux aussi encodés en unaire. S'il y a ''match'', alors l'opérande est disponible. Le comparateur génère un signal qui met à 1 le bit de disponibilité READ FLAG (i pour le numéro de l'unité de calcul), le bit est dans une bascule pour ne pas être effacé au cycle suivant. Le ''scoreboard'' contient donc une matrice de comparaison, qui compare le résultat de l'étape précédente avec tous les désignateurs associés à une opérande. L'avantage d'encoder les désignateurs en unaire fait que la comparaison est plus simple : elle se constitue uniquement de portes ET, pas besoin de portes XOR comme on en aurait eu besoin en utilisant des désignateurs en binaire. De plus, le calcul du désignateur à partir des signaux REQUEST est trivial, pas besoin de passer par un encodeur. [[File:Détection des dépendances CDC 6600.png|centre|vignette|upright=2|Détection des dépendances RAW CDC 6600]] Quand les deux bits READ FLAG d'une instruction sont à 1, le ''scoreboard'' envoie un signal GOREAD à la mémoire et aux unités de calcul. Les numéros/noms de registre, présents dans les registres Fj et Fk, sont envoyés au banc de registre. Le signal envoyé à l'ALU lui demande de copier ces opérandes dans les registres opérandes et de démarrer l'instruction. L'opcode de l'instruction est déjà mémorisé dans le registre d'opcode, ou alors il est envoyé à ce moment. Puis les bits READ FLAG de l'entrée associée à l'ALU sont remis à zéro. ===Le calcul du masque READ PENDING=== Plus haut, nous avions vu le masque READ PENDING qui interdit d'écrire un résultat dans un registre si les conditions ne sont pas réunies, en cas de dépendance WAR. Le nom du signal indique comment sont détectées les dépendances WAR : l'écriture est interdite si une lecture de ce registre est en attente. Le CDC 6600 lit les deux opérandes d'une instruction en même temps, ce qui fait qu'une opérande peut être disponible mais pas encore lue. Une opérande dans ce cas a un READ FLAG à 1 pour le registre associé. Chaque bit du signal READ PENDING se détermine donc en faisant un ET logique entre tous les bits READ FLAG associé à un registre, encore faut-il les sélectionner en fonction du registre voulu et de l'unité de calcul associée au registre. La méthode permet de gérer les dépendances WAR, mais pas les dépendances WAW. Le CDC 6600 bloquait l'instruction dans l'étage d'émission en cas de dépendance WAW. Si l'instruction à émettre avait pour registre de destination un registre de destination d'une instruction dans le pipeline, le processeur émettrait des bulles de pipeline tant que la première écriture n'a pas eu lieu. Son successeur, le CDC 7600 n'avait pas ce défaut et était capable de passer outre toutes les dépendances de données WAR et WAW. Une raison probable à cela est que le CDC 6600 a été terminé en cataastrophe et que ses concepteurs n'ont pas eu le temps d'implémenter une technique complexe de gestion des dépendances WAW. Mais ils ont eu le temps de terminer le design du ''scoreboard'' pour le successeur 7600. Une autre raison est que le pipeline étant court, les dépendances WAW avaient un effet très limité et que bloquer l'émission n'entrainait pas une baisse de performance notable. Mais on peut en théorie faire autrement. Le principe est que les instructions sont émises en absence de dépendances RAW, mais que l'écriture de leur résultat peut être retardée à l'étage d'écriture dans les registres. En cas de dépendances WAR ou WAW, le résultat à écrire est maintenu sur la sortie d'une unité de calcul, dans un registre tampon placé sur cette même sortie, comme illustré plus bas. Les instructions sont donc bloquées dans l'unité de calcul, qui n'est plus disponible pour d'autres instructions. Le ''scoreboard'' sait qu'il ne peut plus envoyer d'instruction sur cette unité de calcul. À chaque cycle, l'étage d'enregistrement choisit le résultat à enregistrer dans les registres, en respectant les dépendances de données. C'est le ''scoreboard'' qui autorise ou non cette écriture, en commandant l'étage d'enregistrement en fin de pipeline. En clair : l'enchainement des signaux GOWRITE impose un enregistrement des résultats qui suit l'ordre du programme. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Le renommage de registres | prevText=Le renommage de registres | next=La désambiguïsation mémoire | nextText=La désambiguïsation mémoire }} </noinclude> hyfrwmxef65ygrqp09gifvo8vv411yi 773618 773606 2026-09-29T20:52:09Z Mewtow 31375 773618 wikitext text/x-wiki Dans ce chapitre, nous allons voir deux techniques d'exécution dans le désordre un peu à part. Il s'agit de deux techniques historiquesn utilisées sur des ordinateurs très anciens, qui portent les noms de ''scoreboarding'' et d'algorithme de Tomasulo. Les deux ne sont plus utilisés aujourd'hui, pour diverses raisons, la principale étant qu'elles ne gèrent pas les exceptions précises. En clair, impossible de les utiliser en même temps que la prédiction de branchement ou d'autres optimisations. Elles ne gèrent pas les exceptions précises, car elles utilisent des formes de renommage de registre assez originale. L'algorithme de Tomasulo renomme les registres dans les stations de réservation, chose qu'on n'a volontairement pas abordé dans le chapitre sur le renommage de registre. le ''scoreboarding'' utilise quant à lui une technique similaire, mais bien plus difficile à classer, qui est clairement idiosyncratique. Il est possible de les modifier pour leur adjoindre un ROB, mais le résultat ressemble beaucoup aux techniques de renommage dans le ROB. ==L'algorithme de Tomasulo et les stations de réservation== L''''algorithme de Tomasulo''' est un algorithme assez compliqué à expliquer, car il mélange exécution dans le désordre, contournement et renommage de registre implicite en un seul algorithme. L'algorithme de Tosmasulo a été implémenté une première fois sur les ordinateurs IBM 360/91, et quelques processeurs ont utilisé une variante de celui-ci. Beaucoup de processeurs modernes se sont sont inspiré de cet algorithme pour leur design. Il est antérieur au ''scoreboarding'' du CDC 6600, qui avait des fonctionnalités similaires, mais nous allons le voir avant, afin de mieux faire ressortir les ressemblances entre les deux algorithmes. Avec l'algorithme de Tomasulo, le renommage de registre se fait dans des '''stations de réservation'''. Pour rappel, ce sont des ''schedulers'' qui ont pour particularité de mémoriser non seulement les µops en attente, mais aussi leurs opérandes. Les opérandes peuvent provenir de deux sources différentes. Soit elles sont lues depuis les registres avant l'émission, soit elles sont obtenues par le réseau de contournement. Dans son acceptation la plus stricte, le terme station de réservation est réservé au cas où il y a une station de réservation par unité de calcul. Et c'est le cas avec l'algorithme de Tomasulo initial, qui a été utilisé pour la première fois sur un processeur avec trois stations de réservation : une pour le circuit multiplieur/diviseur flottant, une pour l'additionneur flottant, et une pour l'unité LOAD/STORE. Un autre point très important est que, dans le papier de Tomasulo, les stations de réservation ne conservent que les µops en attente d'émission. L'algorithme original n'avait pas de ROB et ne gérait pas du tout les exceptions précises. Il ne peut donc pas être utilisé sur les architectures modernes, qui utilisent de la prédiction de branchement. Il est possible d'ajouter un ROB à l'algorithme, mais il doit être modifié et on retombe alors sur une forme de renommage dans le ROB. ===Les stations de réservation et le contournement=== Les stations de réservation mémorisent les µops en attente d'exécution sur l'unité de calcul, tant qu'elles n'ont pas encore leurs opérandes prêtes. Par modifiées pour faciliter le contournement, je veux dire par là qu'elles mémorisent les opérandes d'une µop à exécuter. Si les opérandes sont dans les registres, elles sont lues depuis les registres avant ''issue/dispatch'', et mémorisées dans la station de réservation. Si elles ne sont pas encore disponibles au moment de l'''issue'', elles seront fournies plus tard par le système de contournement et seront alors enregistrées dans la station de réservation. Le fait que le ''scheduler'' incorpore les opérandes de la µop implique une forme de renommage de registres implicite, comme on le verra plus tard. Pour rappel, il s'agit d'une technique dite de '''lecture avant émission''', qui lit les registres d'une µop avant de l'émettre. Pour gérer le contournement, les résultats d'une µop sont non seulement envoyés vers le ROB et/ou les registres, mais ils sont aussi envoyés vers les stations de réservation, via un bus de contournement. La sortie de chaque unité de calcul est connectée à toutes les stations de réservation, dans le cas idéal. Pour cela, la sortie des unités de calcul est reliée aux stations de réservation via un bus, appelé le ''bus commun d’ordonnancement de la mémoire'' (''common memory-ordering bus''), que nous nommerons dorénavant ''bus de contournement''. [[File:Algorithme de Tomasulo.png|centre|vignette|upright=2|Algorithme de Tomasulo]] L'idée derrière le '''bus de contournement''' est que les sorties des unités de calcul sont reliées à un bus, qui est lui connecté aux entrées des ALU. La contrainte est qu'une seule unité de calcul peut envoyer des données sur ce bus. Rien d'étonnant : c'est un bus, il ne peut transférer qu'une donnée à la fois. Si plusieurs unités de calcul veulent transmettre leurs résultats sur ce bus, l'une d'entre elle est choisie et les autres doivent mettre en attente leurs résultats dans une mémoire tampon, soit un registre, soit une FIFO. Dans les deux cas, le registre ou la FIFO sont appelés des ''producers''. L'implémentation demande de bloquer des opérations dans l'ALU si le contournement doit être mis en attente, ce qui bloque tout le pipeline en cas de problème. [[File:Producteurs en sortie d'une ALU.jpg|centre|vignette|upright=2|Producteurs en sortie d'une ALU.]] Le bus de contournement est assez spécifique à l'algorithme de Tomasulo, dans le sens où c'est un des rares articles académique à utiliser un tel bus de contournement. ===Le renommage de registres dans les stations de réservation=== L'unité d'émission attribue à chaque résultat de calcul un '''identifiant de résultat'''. L'identifiant est une sorte de numéro de registre virtuel, qui est transmis sur le bus de contournement. L'identifiant est propagé comme tout signal de commande, il suit la µop sur son trajet dans le pipeline. Quand l'unité de calcul a fini son calcul, l'identifiant est envoyé avec le résultat sur le bus de contournement. Les stations de réservation contenant cet identifiant de résultat enregistrent alors le résultat dans le champ adéquat. De plus, le ROB a des entrées modifiées pour contenir l'identifiant de résultat, afin d'associer un identifiant de résultat à un registre de destination. Les entrées des stations de réservation sont structurées en plusieurs champs. Le premier mémorise l'opcode de l'instruction/µop. Il y a aussi un champ pour l'identifiant de résultat. Il y a aussi deux champs, un par opérande. Il peut contenir deux choses : l'opérande elle-même, l'identifiant de résultat associé. Pour faire la différence, les deux champs ont chacun un bit de présence, qui indique si l'opérande est présente dans le champ ou non (auquel cas, c'est un identifiant). [[File:Entrée d'une station de réservation.png|centre|vignette|upright=3|Entrée d'une station de réservation.]] Vous vous demandez certainement où sont les registres virtuels avec cette organisation. Et bien il ne s'agit ni plus ni moins que des stations de réservation. Et plus précisément les champs pour les opérandes. L'identifiant de résultat est l'équivalent d'un nom de registre virtuel. D'ailleurs, une fois la µop émise, il n'y a pas de noms de registre physique dans les stations de réservation, seulement des identifiants de résultat. En somme, le renommage de registre est pris en charge par les stations de réservation, et par le système de contournement. ===L'exécution d'une µop avec l'algorithme de Tomasulo=== L'exécution d'une µop avec des stations de réservation se fait en plusieurs étapes. Premièrement, la µop est émise, dans le sens où elle est transmise de l'unité d'émission aux stations de réservation. Deuxièmement, la µop est exécutée ou attend son exécution. Enfin, son résultat est enregistré dans les registres et envoyé aux stations de réservation pour contournement. L'émission se fait sous condition qu'une station de réservation pour l'unité de calcul voulue soit disponible. Si c'est le cas, l'unité d'émission vérifie si les opérandes sont disponibles dans le banc de registre architecturaux. Les opérandes disponibles sont alors traitées différemment des opérandes non-disponibles. Les opérandes non-disponibles, elles seront envoyées via contournement plus tard et le renommage de registre doit être utilisé. L'opérande est associée à l'identifiant de résultat qui permet de savoir quand elle sera calculée. À l'opposé, les opérandes disponibles sont lues depuis les registres et enregistrées dans la station de réservation, leur bit de présence est mis à 1. Il n'y a pas de renommage de registres, car il n'y en a pas besoin pour ces opérandes. Reprenons maintenant après l'émission de la µop, qui a été envoyée dans les stations de réservation. Elle attend alors que ses opérandes soient disponibles dans la station de réservation. Les opérandes non-disponibles sont alors calculées par des µops et sont envoyées sur le bus de contournement. La station de réservation reconnait alors l'identifiant et enregistre le résultat dans le champ adéquat. Une fois toutes les opérandes disponibles, la µop est exécutée. Une fois son résultat connu, il est envoyé sur le bus de contournement, mais aussi dans le banc de registres. Et le tout continue. ==Le ''scoreboarding'' du CDC 6600== L'implémentation du ''scoreboard'' sur le CDC 6600/7600 est appelée dans la suite du cours : le '''''scoreboarding'''''. La description que je vais donner du ''scoreboard'' est très différente de celle disponible dans les livres d'architecture des ordinateurs. La plupart des manuels, surtout les textbooks américains, donnent une description très haut niveau, très algorithmique du ''scoreboarding'', qui ne sera pas abordée. À la place, je vais donner une description alternative, différente autant sur l'approche que le fond. Le CDC 6600 n'existe plus, tous les exemplaires ont depuis longtemps été démontés, aussi il ne reste que des sources historiques pour savoir comment fonctionnait son ''scoreboard''. Heureusement, il existe un livre qui décrit dans les moindres détails cette architecture, écrit par un des concepteurs de l'ordinateur : [https://archive.computerhistory.org/resources/text/CDC/cdc.6600.thornton.design_of_a_computer_the_control_data_6600.1970.102630394.pdf Design of a computer : the CDC 6600]. Ce qui va suivre est majoritairement ité de cette source. ===Le chemin de données du CDC 6600 et sa relation avec le ''scoreboard''=== Le pipeline d'un processeur avec ''scoreboarding'' ressemble à celui du schéma suivant. Pour résumer, le chemin de donnée forme un pipeline à trois étages : lecture des registres, exécution dans l'ALU, écriture dans les registres. Les opérations à effectuer son envoyées aux ALUs, et elles attendent leurs opérandes dedans. [[File:Scoreboard avec exceptions imprécises.png|centre|vignette|upright=2|Scoreboard avec exceptions imprécises]] La séparation en trois étages fait qu'il y a des registres entre chaque étages. Les opérandes sont chargées dans des registres en amont de l'ALU, et le résultat est enregistré temporairement dans un registre en sortie de l'ALU. Nous les appellerons : '''registres opérandes''' et '''registre résultat'''. Entre les deux, l'ALU effectue une opération quand les opérandes sont disponibles dans les registres opérandes, et maintien le résultat dans le registre résultat si besoin. Il y a aussi un autre registre qui mémorise l'opcode de l'opération, lors de l'attente des opérandes, mais aussi lors de l'exécution. Nous l'omettrons dans ce qui suit, car il s'agit d'un registre de pipeline classique. Les registres opérande et résultat n'ont pas besoin d'être très complexes vu qu'ils servent juste à maintenir une donnée. Les registres ne sont pas connectés à l'horloge, les bascules ne sont pas synchrones, ils sont fabriqués à partir de simples ''latches'', de simples bascules D non-synchrones. Et il en est de même pour le registre d'opcode. Le ''scoreboard'' commande le signal Enable qui autorise les écritures dedans, rien de plus. Le pipeline est donc le suivant : [[File:Pipeline d'un processeur utilisant le scoreboarding.png|centre|vignette|upright=2|Pipeline d'un processeur utilisant le scoreboarding]] Les registres opérandes sont chacun associé à un bit READ FLAG qui précise si l'opérande du calcul est disponible. Les bits READ FLAG sont mis à jour par un mécanisme assez complexe, qui sera vu dans la suite. Le ''scoreboard'' gère les transferts entre les registres opérande/résultat et le reste du processeur. Il génère deux signaux de 1 bit nommés GO READ et GO STORE/GO WRITE. Le signal GO READ déclenche la copie d'un registre architectural dans un registre opérande. Le signal GO WRITE déclenche la copie du registre résultat dans le registre architectural adéquat. Pour effectuer une lecture ou une écriture, les noms des registres adéquats sont mémorisés dans deux registres notés Fi, Fj, et Fk. Fi mémorise le registre de destination de l'opération, Fj et Fk mémorisent les noms/numéros des registres opérandes. Les deux registres Qj et Qk sont utilisés pour la détection des opérandes disponibles, nous en reparlerons plus tard. Les registres Fi, FJ et Fk sont dans le ''scoreboard'', et ils sont envoyés sur les entrées d'adresse du banc de registre suivant les besoins, suivant qu'on fasse une lecture ou une écriture. La lecture et écriture des registres donc totalement le fait du ''scoreboard'', qui commande le banc de registres, comme le ferait un séquenceur normal. [[File:CDC 6600 datapath control.png|centre|vignette|upright=2|CDC 6600 datapath control]] Notez que les registres opérandes, couplés au registre d'opcode, peuvent être vus comme une station de réservation simplifiée, sans gestion du contournement. La différence principale avec l'algorithme de Tomasulo est que les champs pour les identifiants de résultat ont disparus, et que les bits de disponibilité des opérandes READ FLAG sont en réalité intégré au ''scoreboard'', comme on le verra plus tard, avec une gestion de la disponibilité des opérandes totalement différente. De plus, il n'y a qu'une seule station de réservation par ALU, donc un risque plus grand de dépendances structurelles. On ne peut mettre en attente qu'une seule µop par ALU, avec le ''scoreboard''. ===Les désignateurs utilisés par le ''scoreboard''=== Les registres opérandes et résultat ne sont pas des registres architecturaux, mais ce ne sont pas des registres de pipeline non plus. Il est possible de faire l'analogie avec une station de réservation, mais l'analogie est limitée pour une raison simple : le ''scoreboard'' attend que les deux opérandes sont disponibles pour déclencher la lecture avec le signal GO READ. En théorie, il est tout à fait possible de lire un registre opérande à la fois, dès que l'opérande est disponible, mais le ''scoreboard'' ne faisait pas comme ça. De plus, les opérandes ne sont pas vraiment transmises via un réseau de contournement depuis la sortie de l'ALU. Cependant, une rumeur veut que le processeur implémente un système de contournement, qui passe...par l'intermédiaire des registres. Paradoxal, mais qui s'explique pourtant très bien quand on connait le fonctionnement des registres utilisés. Le processeur utilisait une ancienne technologie de transistors, appelée ECL. Beaucoup de bancs de registres fabriqués avec cette technologie avaient une propriété intéressante : toute donnée écrite sur le port d'écriture était immédiatement disponible sur le port de lecture. Plus précisément, l'écriture se faisait sur front montant et la lecture sur front descendant. En faisant cela, une opérande pouvait être écrite dans les registres architecturaux, mais pourtant copiée dans les registres opérandes au même cycle. Le tout fonctionne presque comme un système de contournement, avec cependant quelques limitations ! Avec un vrai système de contournement, l'implémentation est beaucoup plus puissante. Quant à savoir si les registres opérandes sont nommés, c'est un peu compliqué et la réponse serait qu'ils sont nommés de manière implicite. Il est d'ailleurs débattable de savoir si le CDC 6600/7600 implémente le renommage de registres... Le point de discorde est lié au fait que le ''scoreboard'' attribue un numéro à chaque unité de calcul, appelé le '''désignateur Q'''. Et ces identifiants sont utilisés pour la lecture des opérandes et leur copie dans les registres, ils se comportent comme un nom de registre virtuel. Pour simplifier les explications, nous allons partir du principe que les désignateurs sont encodés en représentation unaire. Pour rappel, la représentation unaire représente un nombre sur plusieurs bits, dont un seul est à 1. Un zéro est codé en mettant tous les bits du nombre à zéro, la valeur 1 est encodée avec la valeur 000...0001, le deux avec 000...0010, etc. {|class="wikitable" |+ Désignateur d'ALU |- ! ALU ADD !! ALU MUL !! ALU DIV !! ALU SUB !! ALU CMP !! ALU MOV |- | 0 || 0 || 1 || 0 || 0 || 0 |} La réalité est que les désignateurs sont présents à plusieurs endroits et sont soit codés en unaires, soit codés en binaire, avec des traductions fréquentes entre les deux. Ils sont par exemple traduits du binaire vers l'unaire lors de la génération des signaux READ FLAG. Les traductions inverses sont aussi fréquentes. Les traductions se basent sur des décodeurs/encodeurs un peu modifiés. L'avantage de la représentation unaire est que les comparaisons sont légèrement plus simples, les comparateurs économisent quelques portes logiques. De plus, elle s'adapte assez bien avec le fait que chaque unité de calcul précise si elle est disponible ou non, ce qui deviendra plus clair dans la suite. ===Les réservations et la table de réservation=== Le ''scoreboard'' du CDC 6600 contient une table de '''réservation''', qui permet de réserver une unité de calcul pour une µop à émettre. La table de réservation est composée d'entrées, une par unité de calcul, qui peut mémoriser une µop. Une entrée mémorise pour chaque unité de calcul : * l'opcode de l'instruction à exécuter dessus ; * les noms/numéros des registres opérandes et destination ; * les désignateurs Q des unités de calcul qui fourniront les opérandes en résultat ; * deux bits READ FLAG qui disent si l'opérande associé est disponible. : Dans le livre utilisé comme source, il n'est pas clair si les noms des registres opérandes/résultat sont placés dans l'unité de calcul ou dans le ''scoreboard''. Les explications semblent indiquer que c'est juste à côté de l'ALU, mais les schémas se contredisent là-dessus. Dans la suite, je pars du principe qu'ils sont dans le ''scoreboard'', ce qui aurait bien plus de sens. Le ''scoreboard'' consulte la table de réservation pour émettre une µop. Avant d’émettre une µop, elle regarde si l'entrée est libre ou déjà occupée par une µop. Pour cela, chaque entrée est associée à un bit BUSY qui indique si l'entrée est vide ou occupée. Vu qu'il y a une entrée par unité de calcul, attribuer une entrée à une µop est asszz simple : chaque µop va dans une entrée bien précise, il suffit de vérifier celle-ci. Le bit BUSY est mis à 1 quand une µop est émise, ajoutée dans l'entrée, mis à zéro quand elle est terminée. La libération d'une entrée se fait quand le signal GO WRITE est émis, le signal RELEASE ne suffit pas. La réservation permet de réserver une ALU pour une opération. La µop est alors envoyée à l'ALU, où elle attend que ses opérandes soient disponibles. Une µop attend son tour et n'est émise qu'une fois que les deux bits READ FLAGS sont à 1. La conséquence est qu'une µop reste dans l'unité de calcul tant qu'elle a des dépendances RAW. Et seules les dépendances RAW, où une instruction pour opérande le résultat d'une instruction précédente, impliquent un blocage du pipeline et des bulles de pipeline. Les dépendances WAW ou WAR sont traitées autrement. La table de réservation ne stocke pas les opérandes, ce qui fait qu'on peut la voir comme un ''scheduler'' à une entrée, ou encore comme une station de réservation castrée. Un détail très important est que ce système de réservation met en attente une µop par ALU. Vu que toutes les ALUs du CDC 6600 sont très différentes, l'attribution d'une µop à une ALU est trivial. Par contre, si une µop veut utiliser une ALU réservée, elle ne peut pas et il faut bloquer le pipeline. Le système de réservation est donc une cause de dépendances structurelles qui bloquent l'émission des µops dans de nombreux cas. Ce ne serait pas le cas si on pouvait placer plusieurs réservations par unité de calcul, mais passons. Pour une dépendance WAR, la µop est émise, elle s'exécute, mais son résultat est maintenu dans le registre résultat le temps que ces dépendances soient résolues. Pour le dire autrement, Les dépendances WAR font que les µops sont retenues dans l'étage d'enregistrement des données, un peu comme sur un processeur à pipeline multicycle (de longueur fixe). Sauf que les pipeline multicycle, il y aurait plusieurs registres d'échelonnements qui se suivent, alors qu'on n'en a qu'un ici, ce qui fait que l'unité de calcul est bloquée si l'écriture est retardée. En théorie, les dépendances WAW devraient être traitées avec un mécanisme similaire, mais le processeur détectait ces dépendances à l'émission et bloquait l'émission si un registre lu était accédé en lecture. [[File:Enregistrement des données dans les registres avec un pipeline avec scoreboarding.png|centre|vignette|upright=2|Enregistrement des données dans les registres avec un pipeline avec scoreboarding]] ===La Q-table : l'unité de renommage de registres=== Quand une µop est émise, elle réserve une unité de calcul. Mais il faut pour cela remplir les champs pour les désignateurs d'ALU, même si on voit mal à quoi ils servent pour le moment. Il se trouve que les registres opérandes contiennent une valeur, qui est le résultat d'une µop soit déjà passée par une ALU, soit en cours d'exécution dans une ALU. Le désignateur pour un opérande est donc le désignateur de cette ALU. Reste à faire la correspondance entre un résultat/registre et l'ALU qui va le calculer ou l'a déjà calculé. Pour cela, le ''scoreboard'' mémorise la correspondance entre un registre/résultat et une unité de calcul dans une mémoire cache appelée la '''''Q-table'''''. Pour comprendre à quoi elle sert, prenons deux instructions consécutives, dont la seconde utilise le résultat de la première. La première instruction est lancée dans une unité de calcul enregistre son résultat dans un registre de destination. Le ''scoreboard'' mémorise alors dans la ''Q-table'' que le registre de destination est associé à telle unité de calcul, elle mémorise une correspondance entre le désignateur de l'ALU et le registre de destination. Par la suite, la seconde instruction est émise. Le ''scoreboard'' interroge la ''Q-table'' pour les deux opérandes de l'instruction, pour récupérer les deux désignateurs de l'ALU associés. Ils sont envoyés au banc de registres pour gérer la lecture des opérandes. Pour résumer, le ''scoreboard'' effectue les actions suivantes lors de l'émission. * Premièrement, il détermine si l'unité de calcul est disponible ou non, en utilisant le bit de disponibilité BUSY. * Deuxièmement, il mémorise les numéros de registres opérande et résultat pour commander la lecture des opérandes. * Troisièmement, il traduit les numéros de registres opérande en identifiants d'ALU. * Quatrièmement, il mémorise dans une ''Q-table'' la relation entre le registre de destination et l'unité de calcul choisie à l'étape 1. La troisième étape permet de faire le lien entre un résultat calculé mais pas encore enregistré dans les registres, et un registre opérande non-nommé. Le lien guide le chargement des opérandes et donc le système de contournement passant par des registres (ce qui est du renommage de registre implicite). ===La gestion des résultats : les signaux RELEASE et GOWRITE=== Une fois la µop exécutée, son résultat est enregistré dans le registre résultat. Une fois le résultat dans le registre résultat, l'unité de calcul envoie un signal REQUEST au ''scoreboard'' pour savoir si la donnée peut être enregistrée dans les registres architecturaux. L'ensemble des signaux REQUEST est regroupé dans un vecteur de bit, une sorte de nombre, dont chaque bit indique quelle unité veut écrire un résultat. L'ensemble des signaux RELEASE forment un nombre encodé en unaire qui indique quelle ALU a fournit le résultat. Là, le ''scoreboard'' effectue plusieurs opérations successives sur ce nombre, en appliquant plusieurs masques. Le premier masque appliqué vérifie pour chaque ALU si elle a le droit d'écrire son résultat en mémoire, sur la base des dépendances WAW et WAR. En cas de dépendances WAR ou WAW, l'écriture du résultat est retardé, ce qui fait que l'unité de calcul n'est pas considérée, son signal RELEASE est ignoré, il est masqué. Le masque qui permet cela est appelé le '''masque READ PENDING'''. Le second masque est un circuit de priorité qui sélectionne un bit seulement. Il est en effet possible que plusieurs unités de calcul fournissent un résultat en même temps. Ou encore que l'une ait son écriture retardée et ait un signal RELEASE à 1 depuis plusieurs cycles. Toujours est-il qu'on ne peut écrire qu'un résultat à la fois, ce qui fait qu'il faut sélectionner une unité de calcul. Pour cela, un circuit de priorité sélectionne un seul signal RELEASE à 1 et met les autres à zéro. C'est le second masque. {|class="wikitable" |+ Traitement des signaux REQUEST |- ! colspan="10 | Signaux REQUEST en sortie des ALUs |- | 0 || 1 || 0 || 1 || 1 || 1 || 0 || 0 || 0 || 0 |- ! colspan="10 | Application du masque READ PENDING pour les dépendances WAW/WAR |- | 0 || 0 || 0 || 1 || 1 || 0 || 0 || 0 || 0 || 0 |- ! colspan="10 | Sélection par un circuit de priorité |- | 0 || 0 || 0 || 1 || 0 || 0 || 0 || 0 || 0 || 0 |} Après l'application du second masque, il ne reste qu'un seul bit à un, qui indique quelle ALU a été sélectionnée pour l'écriture. Il se trouve que l'ensemble des bits forme un désignateur d'ALU, encodé en représentation unaire, en représentation ''one-hot''. Pour rappel, cela veut dire que seul un bit dans le nombre est à 1 et ce bit indique la valeur encodée. Si le bit numéro X est à 1, alors la valeur encodée vaut X. L'usage d'une représentation unaire/''one-hot'' fait que l'on a juste à concaténer les signaux REQUEST et appliquer des masques pour obtenir le désignateur adéquat, pas besoin d'encodeur compliqués, ni de circuits de sélection complexes. Le désignateur résultat est appelé '''désignateur d'ALU choisie'''. Une fois ce désignateur calculé, le ''désignateur d'ALU choisie'' est envoyé à la table de réservation, afin de récupérer le nom/numéro du registre résultat associé. Le ''scoreboard'' commande le port d'écriture du banc de registre, avec un signal GOWRITE et le nom/numéro du registre de destination récupéré. Le signal RELEASE est alors remis à zéro. Reste à générer le signal GO WRITE et faire les actions adéquates. Mais il reste deux opérations de maintenance pour terminer l'écriture. La première est de remettre en ordre la Q-table. L'entrée qui liait l'unité de calcul au registre de destination doit être remise à zéro. Le résultat ayant été écrit, il n'est plus associé à l'unité de calcul, le lien entre les deux dans la Q-table est donc effacé. La seconde est de gérer la disponibilité des opérandes. Pour cela, le résultat après application des deux masques est aussi utilisé pour détecter la disponibilité des opérandes, pour mettre à 1 le bit READ FLAG adéquat. Là encore, c'est la table de réservation qui s'en charge. ===La détection des opérandes disponibles : la génération des READ FLAG et du signal GOREAD=== Le désignateur d'ALU choise est envoyé à la table de réservation pour récupérer le nom de registre destination, mais aussi aux champs opérandes. Dans chaque entrée, il comparé aux deux désignateurs Qj et Qk, associés chacun à une opérande. Pour rappel, les désignateurs Qj et Qk sont des désignateurs d'unité de calcul, eux aussi encodés en unaire. S'il y a ''match'', alors l'opérande est disponible. Le comparateur génère un signal qui met à 1 le bit de disponibilité READ FLAG (i pour le numéro de l'unité de calcul), le bit est dans une bascule pour ne pas être effacé au cycle suivant. Le ''scoreboard'' contient donc une matrice de comparaison, qui compare le résultat de l'étape précédente avec tous les désignateurs associés à une opérande. L'avantage d'encoder les désignateurs en unaire fait que la comparaison est plus simple : elle se constitue uniquement de portes ET, pas besoin de portes XOR comme on en aurait eu besoin en utilisant des désignateurs en binaire. De plus, le calcul du désignateur à partir des signaux REQUEST est trivial, pas besoin de passer par un encodeur. [[File:Détection des dépendances CDC 6600.png|centre|vignette|upright=2|Détection des dépendances RAW CDC 6600]] Quand les deux bits READ FLAG d'une instruction sont à 1, le ''scoreboard'' envoie un signal GOREAD à la mémoire et aux unités de calcul. Les numéros/noms de registre, présents dans les registres Fj et Fk, sont envoyés au banc de registre. Le signal envoyé à l'ALU lui demande de copier ces opérandes dans les registres opérandes et de démarrer l'instruction. L'opcode de l'instruction est déjà mémorisé dans le registre d'opcode, ou alors il est envoyé à ce moment. Puis les bits READ FLAG de l'entrée associée à l'ALU sont remis à zéro. ===Le calcul du masque READ PENDING=== Plus haut, nous avions vu le masque READ PENDING qui interdit d'écrire un résultat dans un registre si les conditions ne sont pas réunies, en cas de dépendance WAR. Le nom du signal indique comment sont détectées les dépendances WAR : l'écriture est interdite si une lecture de ce registre est en attente. Le CDC 6600 lit les deux opérandes d'une instruction en même temps, ce qui fait qu'une opérande peut être disponible mais pas encore lue. Une opérande dans ce cas a un READ FLAG à 1 pour le registre associé. Chaque bit du signal READ PENDING se détermine donc en faisant un ET logique entre tous les bits READ FLAG associé à un registre, encore faut-il les sélectionner en fonction du registre voulu et de l'unité de calcul associée au registre. La méthode permet de gérer les dépendances WAR, mais pas les dépendances WAW. Le CDC 6600 bloquait l'instruction dans l'étage d'émission en cas de dépendance WAW. Si l'instruction à émettre avait pour registre de destination un registre de destination d'une instruction dans le pipeline, le processeur émettrait des bulles de pipeline tant que la première écriture n'a pas eu lieu. Son successeur, le CDC 7600 n'avait pas ce défaut et était capable de passer outre toutes les dépendances de données WAR et WAW. Une raison probable à cela est que le CDC 6600 a été terminé en cataastrophe et que ses concepteurs n'ont pas eu le temps d'implémenter une technique complexe de gestion des dépendances WAW. Mais ils ont eu le temps de terminer le design du ''scoreboard'' pour le successeur 7600. Une autre raison est que le pipeline étant court, les dépendances WAW avaient un effet très limité et que bloquer l'émission n'entrainait pas une baisse de performance notable. Mais on peut en théorie faire autrement. Le principe est que les instructions sont émises en absence de dépendances RAW, mais que l'écriture de leur résultat peut être retardée à l'étage d'écriture dans les registres. En cas de dépendances WAR ou WAW, le résultat à écrire est maintenu sur la sortie d'une unité de calcul, dans un registre tampon placé sur cette même sortie, comme illustré plus bas. Les instructions sont donc bloquées dans l'unité de calcul, qui n'est plus disponible pour d'autres instructions. Le ''scoreboard'' sait qu'il ne peut plus envoyer d'instruction sur cette unité de calcul. À chaque cycle, l'étage d'enregistrement choisit le résultat à enregistrer dans les registres, en respectant les dépendances de données. C'est le ''scoreboard'' qui autorise ou non cette écriture, en commandant l'étage d'enregistrement en fin de pipeline. En clair : l'enchainement des signaux GOWRITE impose un enregistrement des résultats qui suit l'ordre du programme. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Le renommage de registres | prevText=Le renommage de registres | next=La désambiguïsation mémoire | nextText=La désambiguïsation mémoire }} </noinclude> 8z0pydopwcjaym4lhutcl4vhpourb8k 773631 773618 2026-09-29T21:08:49Z Mewtow 31375 /* Le calcul du masque READ PENDING */ 773631 wikitext text/x-wiki Dans ce chapitre, nous allons voir deux techniques d'exécution dans le désordre un peu à part. Il s'agit de deux techniques historiquesn utilisées sur des ordinateurs très anciens, qui portent les noms de ''scoreboarding'' et d'algorithme de Tomasulo. Les deux ne sont plus utilisés aujourd'hui, pour diverses raisons, la principale étant qu'elles ne gèrent pas les exceptions précises. En clair, impossible de les utiliser en même temps que la prédiction de branchement ou d'autres optimisations. Elles ne gèrent pas les exceptions précises, car elles utilisent des formes de renommage de registre assez originale. L'algorithme de Tomasulo renomme les registres dans les stations de réservation, chose qu'on n'a volontairement pas abordé dans le chapitre sur le renommage de registre. le ''scoreboarding'' utilise quant à lui une technique similaire, mais bien plus difficile à classer, qui est clairement idiosyncratique. Il est possible de les modifier pour leur adjoindre un ROB, mais le résultat ressemble beaucoup aux techniques de renommage dans le ROB. ==L'algorithme de Tomasulo et les stations de réservation== L''''algorithme de Tomasulo''' est un algorithme assez compliqué à expliquer, car il mélange exécution dans le désordre, contournement et renommage de registre implicite en un seul algorithme. L'algorithme de Tosmasulo a été implémenté une première fois sur les ordinateurs IBM 360/91, et quelques processeurs ont utilisé une variante de celui-ci. Beaucoup de processeurs modernes se sont sont inspiré de cet algorithme pour leur design. Il est antérieur au ''scoreboarding'' du CDC 6600, qui avait des fonctionnalités similaires, mais nous allons le voir avant, afin de mieux faire ressortir les ressemblances entre les deux algorithmes. Avec l'algorithme de Tomasulo, le renommage de registre se fait dans des '''stations de réservation'''. Pour rappel, ce sont des ''schedulers'' qui ont pour particularité de mémoriser non seulement les µops en attente, mais aussi leurs opérandes. Les opérandes peuvent provenir de deux sources différentes. Soit elles sont lues depuis les registres avant l'émission, soit elles sont obtenues par le réseau de contournement. Dans son acceptation la plus stricte, le terme station de réservation est réservé au cas où il y a une station de réservation par unité de calcul. Et c'est le cas avec l'algorithme de Tomasulo initial, qui a été utilisé pour la première fois sur un processeur avec trois stations de réservation : une pour le circuit multiplieur/diviseur flottant, une pour l'additionneur flottant, et une pour l'unité LOAD/STORE. Un autre point très important est que, dans le papier de Tomasulo, les stations de réservation ne conservent que les µops en attente d'émission. L'algorithme original n'avait pas de ROB et ne gérait pas du tout les exceptions précises. Il ne peut donc pas être utilisé sur les architectures modernes, qui utilisent de la prédiction de branchement. Il est possible d'ajouter un ROB à l'algorithme, mais il doit être modifié et on retombe alors sur une forme de renommage dans le ROB. ===Les stations de réservation et le contournement=== Les stations de réservation mémorisent les µops en attente d'exécution sur l'unité de calcul, tant qu'elles n'ont pas encore leurs opérandes prêtes. Par modifiées pour faciliter le contournement, je veux dire par là qu'elles mémorisent les opérandes d'une µop à exécuter. Si les opérandes sont dans les registres, elles sont lues depuis les registres avant ''issue/dispatch'', et mémorisées dans la station de réservation. Si elles ne sont pas encore disponibles au moment de l'''issue'', elles seront fournies plus tard par le système de contournement et seront alors enregistrées dans la station de réservation. Le fait que le ''scheduler'' incorpore les opérandes de la µop implique une forme de renommage de registres implicite, comme on le verra plus tard. Pour rappel, il s'agit d'une technique dite de '''lecture avant émission''', qui lit les registres d'une µop avant de l'émettre. Pour gérer le contournement, les résultats d'une µop sont non seulement envoyés vers le ROB et/ou les registres, mais ils sont aussi envoyés vers les stations de réservation, via un bus de contournement. La sortie de chaque unité de calcul est connectée à toutes les stations de réservation, dans le cas idéal. Pour cela, la sortie des unités de calcul est reliée aux stations de réservation via un bus, appelé le ''bus commun d’ordonnancement de la mémoire'' (''common memory-ordering bus''), que nous nommerons dorénavant ''bus de contournement''. [[File:Algorithme de Tomasulo.png|centre|vignette|upright=2|Algorithme de Tomasulo]] L'idée derrière le '''bus de contournement''' est que les sorties des unités de calcul sont reliées à un bus, qui est lui connecté aux entrées des ALU. La contrainte est qu'une seule unité de calcul peut envoyer des données sur ce bus. Rien d'étonnant : c'est un bus, il ne peut transférer qu'une donnée à la fois. Si plusieurs unités de calcul veulent transmettre leurs résultats sur ce bus, l'une d'entre elle est choisie et les autres doivent mettre en attente leurs résultats dans une mémoire tampon, soit un registre, soit une FIFO. Dans les deux cas, le registre ou la FIFO sont appelés des ''producers''. L'implémentation demande de bloquer des opérations dans l'ALU si le contournement doit être mis en attente, ce qui bloque tout le pipeline en cas de problème. [[File:Producteurs en sortie d'une ALU.jpg|centre|vignette|upright=2|Producteurs en sortie d'une ALU.]] Le bus de contournement est assez spécifique à l'algorithme de Tomasulo, dans le sens où c'est un des rares articles académique à utiliser un tel bus de contournement. ===Le renommage de registres dans les stations de réservation=== L'unité d'émission attribue à chaque résultat de calcul un '''identifiant de résultat'''. L'identifiant est une sorte de numéro de registre virtuel, qui est transmis sur le bus de contournement. L'identifiant est propagé comme tout signal de commande, il suit la µop sur son trajet dans le pipeline. Quand l'unité de calcul a fini son calcul, l'identifiant est envoyé avec le résultat sur le bus de contournement. Les stations de réservation contenant cet identifiant de résultat enregistrent alors le résultat dans le champ adéquat. De plus, le ROB a des entrées modifiées pour contenir l'identifiant de résultat, afin d'associer un identifiant de résultat à un registre de destination. Les entrées des stations de réservation sont structurées en plusieurs champs. Le premier mémorise l'opcode de l'instruction/µop. Il y a aussi un champ pour l'identifiant de résultat. Il y a aussi deux champs, un par opérande. Il peut contenir deux choses : l'opérande elle-même, l'identifiant de résultat associé. Pour faire la différence, les deux champs ont chacun un bit de présence, qui indique si l'opérande est présente dans le champ ou non (auquel cas, c'est un identifiant). [[File:Entrée d'une station de réservation.png|centre|vignette|upright=3|Entrée d'une station de réservation.]] Vous vous demandez certainement où sont les registres virtuels avec cette organisation. Et bien il ne s'agit ni plus ni moins que des stations de réservation. Et plus précisément les champs pour les opérandes. L'identifiant de résultat est l'équivalent d'un nom de registre virtuel. D'ailleurs, une fois la µop émise, il n'y a pas de noms de registre physique dans les stations de réservation, seulement des identifiants de résultat. En somme, le renommage de registre est pris en charge par les stations de réservation, et par le système de contournement. ===L'exécution d'une µop avec l'algorithme de Tomasulo=== L'exécution d'une µop avec des stations de réservation se fait en plusieurs étapes. Premièrement, la µop est émise, dans le sens où elle est transmise de l'unité d'émission aux stations de réservation. Deuxièmement, la µop est exécutée ou attend son exécution. Enfin, son résultat est enregistré dans les registres et envoyé aux stations de réservation pour contournement. L'émission se fait sous condition qu'une station de réservation pour l'unité de calcul voulue soit disponible. Si c'est le cas, l'unité d'émission vérifie si les opérandes sont disponibles dans le banc de registre architecturaux. Les opérandes disponibles sont alors traitées différemment des opérandes non-disponibles. Les opérandes non-disponibles, elles seront envoyées via contournement plus tard et le renommage de registre doit être utilisé. L'opérande est associée à l'identifiant de résultat qui permet de savoir quand elle sera calculée. À l'opposé, les opérandes disponibles sont lues depuis les registres et enregistrées dans la station de réservation, leur bit de présence est mis à 1. Il n'y a pas de renommage de registres, car il n'y en a pas besoin pour ces opérandes. Reprenons maintenant après l'émission de la µop, qui a été envoyée dans les stations de réservation. Elle attend alors que ses opérandes soient disponibles dans la station de réservation. Les opérandes non-disponibles sont alors calculées par des µops et sont envoyées sur le bus de contournement. La station de réservation reconnait alors l'identifiant et enregistre le résultat dans le champ adéquat. Une fois toutes les opérandes disponibles, la µop est exécutée. Une fois son résultat connu, il est envoyé sur le bus de contournement, mais aussi dans le banc de registres. Et le tout continue. ==Le ''scoreboarding'' du CDC 6600== L'implémentation du ''scoreboard'' sur le CDC 6600/7600 est appelée dans la suite du cours : le '''''scoreboarding'''''. La description que je vais donner du ''scoreboard'' est très différente de celle disponible dans les livres d'architecture des ordinateurs. La plupart des manuels, surtout les textbooks américains, donnent une description très haut niveau, très algorithmique du ''scoreboarding'', qui ne sera pas abordée. À la place, je vais donner une description alternative, différente autant sur l'approche que le fond. Le CDC 6600 n'existe plus, tous les exemplaires ont depuis longtemps été démontés, aussi il ne reste que des sources historiques pour savoir comment fonctionnait son ''scoreboard''. Heureusement, il existe un livre qui décrit dans les moindres détails cette architecture, écrit par un des concepteurs de l'ordinateur : [https://archive.computerhistory.org/resources/text/CDC/cdc.6600.thornton.design_of_a_computer_the_control_data_6600.1970.102630394.pdf Design of a computer : the CDC 6600]. Ce qui va suivre est majoritairement ité de cette source. ===Le chemin de données du CDC 6600 et sa relation avec le ''scoreboard''=== Le pipeline d'un processeur avec ''scoreboarding'' ressemble à celui du schéma suivant. Pour résumer, le chemin de donnée forme un pipeline à trois étages : lecture des registres, exécution dans l'ALU, écriture dans les registres. Les opérations à effectuer son envoyées aux ALUs, et elles attendent leurs opérandes dedans. [[File:Scoreboard avec exceptions imprécises.png|centre|vignette|upright=2|Scoreboard avec exceptions imprécises]] La séparation en trois étages fait qu'il y a des registres entre chaque étages. Les opérandes sont chargées dans des registres en amont de l'ALU, et le résultat est enregistré temporairement dans un registre en sortie de l'ALU. Nous les appellerons : '''registres opérandes''' et '''registre résultat'''. Entre les deux, l'ALU effectue une opération quand les opérandes sont disponibles dans les registres opérandes, et maintien le résultat dans le registre résultat si besoin. Il y a aussi un autre registre qui mémorise l'opcode de l'opération, lors de l'attente des opérandes, mais aussi lors de l'exécution. Nous l'omettrons dans ce qui suit, car il s'agit d'un registre de pipeline classique. Les registres opérande et résultat n'ont pas besoin d'être très complexes vu qu'ils servent juste à maintenir une donnée. Les registres ne sont pas connectés à l'horloge, les bascules ne sont pas synchrones, ils sont fabriqués à partir de simples ''latches'', de simples bascules D non-synchrones. Et il en est de même pour le registre d'opcode. Le ''scoreboard'' commande le signal Enable qui autorise les écritures dedans, rien de plus. Le pipeline est donc le suivant : [[File:Pipeline d'un processeur utilisant le scoreboarding.png|centre|vignette|upright=2|Pipeline d'un processeur utilisant le scoreboarding]] Les registres opérandes sont chacun associé à un bit READ FLAG qui précise si l'opérande du calcul est disponible. Les bits READ FLAG sont mis à jour par un mécanisme assez complexe, qui sera vu dans la suite. Le ''scoreboard'' gère les transferts entre les registres opérande/résultat et le reste du processeur. Il génère deux signaux de 1 bit nommés GO READ et GO STORE/GO WRITE. Le signal GO READ déclenche la copie d'un registre architectural dans un registre opérande. Le signal GO WRITE déclenche la copie du registre résultat dans le registre architectural adéquat. Pour effectuer une lecture ou une écriture, les noms des registres adéquats sont mémorisés dans deux registres notés Fi, Fj, et Fk. Fi mémorise le registre de destination de l'opération, Fj et Fk mémorisent les noms/numéros des registres opérandes. Les deux registres Qj et Qk sont utilisés pour la détection des opérandes disponibles, nous en reparlerons plus tard. Les registres Fi, FJ et Fk sont dans le ''scoreboard'', et ils sont envoyés sur les entrées d'adresse du banc de registre suivant les besoins, suivant qu'on fasse une lecture ou une écriture. La lecture et écriture des registres donc totalement le fait du ''scoreboard'', qui commande le banc de registres, comme le ferait un séquenceur normal. [[File:CDC 6600 datapath control.png|centre|vignette|upright=2|CDC 6600 datapath control]] Notez que les registres opérandes, couplés au registre d'opcode, peuvent être vus comme une station de réservation simplifiée, sans gestion du contournement. La différence principale avec l'algorithme de Tomasulo est que les champs pour les identifiants de résultat ont disparus, et que les bits de disponibilité des opérandes READ FLAG sont en réalité intégré au ''scoreboard'', comme on le verra plus tard, avec une gestion de la disponibilité des opérandes totalement différente. De plus, il n'y a qu'une seule station de réservation par ALU, donc un risque plus grand de dépendances structurelles. On ne peut mettre en attente qu'une seule µop par ALU, avec le ''scoreboard''. ===Les désignateurs utilisés par le ''scoreboard''=== Les registres opérandes et résultat ne sont pas des registres architecturaux, mais ce ne sont pas des registres de pipeline non plus. Il est possible de faire l'analogie avec une station de réservation, mais l'analogie est limitée pour une raison simple : le ''scoreboard'' attend que les deux opérandes sont disponibles pour déclencher la lecture avec le signal GO READ. En théorie, il est tout à fait possible de lire un registre opérande à la fois, dès que l'opérande est disponible, mais le ''scoreboard'' ne faisait pas comme ça. De plus, les opérandes ne sont pas vraiment transmises via un réseau de contournement depuis la sortie de l'ALU. Cependant, une rumeur veut que le processeur implémente un système de contournement, qui passe...par l'intermédiaire des registres. Paradoxal, mais qui s'explique pourtant très bien quand on connait le fonctionnement des registres utilisés. Le processeur utilisait une ancienne technologie de transistors, appelée ECL. Beaucoup de bancs de registres fabriqués avec cette technologie avaient une propriété intéressante : toute donnée écrite sur le port d'écriture était immédiatement disponible sur le port de lecture. Plus précisément, l'écriture se faisait sur front montant et la lecture sur front descendant. En faisant cela, une opérande pouvait être écrite dans les registres architecturaux, mais pourtant copiée dans les registres opérandes au même cycle. Le tout fonctionne presque comme un système de contournement, avec cependant quelques limitations ! Avec un vrai système de contournement, l'implémentation est beaucoup plus puissante. Quant à savoir si les registres opérandes sont nommés, c'est un peu compliqué et la réponse serait qu'ils sont nommés de manière implicite. Il est d'ailleurs débattable de savoir si le CDC 6600/7600 implémente le renommage de registres... Le point de discorde est lié au fait que le ''scoreboard'' attribue un numéro à chaque unité de calcul, appelé le '''désignateur Q'''. Et ces identifiants sont utilisés pour la lecture des opérandes et leur copie dans les registres, ils se comportent comme un nom de registre virtuel. Pour simplifier les explications, nous allons partir du principe que les désignateurs sont encodés en représentation unaire. Pour rappel, la représentation unaire représente un nombre sur plusieurs bits, dont un seul est à 1. Un zéro est codé en mettant tous les bits du nombre à zéro, la valeur 1 est encodée avec la valeur 000...0001, le deux avec 000...0010, etc. {|class="wikitable" |+ Désignateur d'ALU |- ! ALU ADD !! ALU MUL !! ALU DIV !! ALU SUB !! ALU CMP !! ALU MOV |- | 0 || 0 || 1 || 0 || 0 || 0 |} La réalité est que les désignateurs sont présents à plusieurs endroits et sont soit codés en unaires, soit codés en binaire, avec des traductions fréquentes entre les deux. Ils sont par exemple traduits du binaire vers l'unaire lors de la génération des signaux READ FLAG. Les traductions inverses sont aussi fréquentes. Les traductions se basent sur des décodeurs/encodeurs un peu modifiés. L'avantage de la représentation unaire est que les comparaisons sont légèrement plus simples, les comparateurs économisent quelques portes logiques. De plus, elle s'adapte assez bien avec le fait que chaque unité de calcul précise si elle est disponible ou non, ce qui deviendra plus clair dans la suite. ===Les réservations et la table de réservation=== Le ''scoreboard'' du CDC 6600 contient une table de '''réservation''', qui permet de réserver une unité de calcul pour une µop à émettre. La table de réservation est composée d'entrées, une par unité de calcul, qui peut mémoriser une µop. Une entrée mémorise pour chaque unité de calcul : * l'opcode de l'instruction à exécuter dessus ; * les noms/numéros des registres opérandes et destination ; * les désignateurs Q des unités de calcul qui fourniront les opérandes en résultat ; * deux bits READ FLAG qui disent si l'opérande associé est disponible. : Dans le livre utilisé comme source, il n'est pas clair si les noms des registres opérandes/résultat sont placés dans l'unité de calcul ou dans le ''scoreboard''. Les explications semblent indiquer que c'est juste à côté de l'ALU, mais les schémas se contredisent là-dessus. Dans la suite, je pars du principe qu'ils sont dans le ''scoreboard'', ce qui aurait bien plus de sens. Le ''scoreboard'' consulte la table de réservation pour émettre une µop. Avant d’émettre une µop, elle regarde si l'entrée est libre ou déjà occupée par une µop. Pour cela, chaque entrée est associée à un bit BUSY qui indique si l'entrée est vide ou occupée. Vu qu'il y a une entrée par unité de calcul, attribuer une entrée à une µop est asszz simple : chaque µop va dans une entrée bien précise, il suffit de vérifier celle-ci. Le bit BUSY est mis à 1 quand une µop est émise, ajoutée dans l'entrée, mis à zéro quand elle est terminée. La libération d'une entrée se fait quand le signal GO WRITE est émis, le signal RELEASE ne suffit pas. La réservation permet de réserver une ALU pour une opération. La µop est alors envoyée à l'ALU, où elle attend que ses opérandes soient disponibles. Une µop attend son tour et n'est émise qu'une fois que les deux bits READ FLAGS sont à 1. La conséquence est qu'une µop reste dans l'unité de calcul tant qu'elle a des dépendances RAW. Et seules les dépendances RAW, où une instruction pour opérande le résultat d'une instruction précédente, impliquent un blocage du pipeline et des bulles de pipeline. Les dépendances WAW ou WAR sont traitées autrement. La table de réservation ne stocke pas les opérandes, ce qui fait qu'on peut la voir comme un ''scheduler'' à une entrée, ou encore comme une station de réservation castrée. Un détail très important est que ce système de réservation met en attente une µop par ALU. Vu que toutes les ALUs du CDC 6600 sont très différentes, l'attribution d'une µop à une ALU est trivial. Par contre, si une µop veut utiliser une ALU réservée, elle ne peut pas et il faut bloquer le pipeline. Le système de réservation est donc une cause de dépendances structurelles qui bloquent l'émission des µops dans de nombreux cas. Ce ne serait pas le cas si on pouvait placer plusieurs réservations par unité de calcul, mais passons. Pour une dépendance WAR, la µop est émise, elle s'exécute, mais son résultat est maintenu dans le registre résultat le temps que ces dépendances soient résolues. Pour le dire autrement, Les dépendances WAR font que les µops sont retenues dans l'étage d'enregistrement des données, un peu comme sur un processeur à pipeline multicycle (de longueur fixe). Sauf que les pipeline multicycle, il y aurait plusieurs registres d'échelonnements qui se suivent, alors qu'on n'en a qu'un ici, ce qui fait que l'unité de calcul est bloquée si l'écriture est retardée. En théorie, les dépendances WAW devraient être traitées avec un mécanisme similaire, mais le processeur détectait ces dépendances à l'émission et bloquait l'émission si un registre lu était accédé en lecture. [[File:Enregistrement des données dans les registres avec un pipeline avec scoreboarding.png|centre|vignette|upright=2|Enregistrement des données dans les registres avec un pipeline avec scoreboarding]] ===La Q-table : l'unité de renommage de registres=== Quand une µop est émise, elle réserve une unité de calcul. Mais il faut pour cela remplir les champs pour les désignateurs d'ALU, même si on voit mal à quoi ils servent pour le moment. Il se trouve que les registres opérandes contiennent une valeur, qui est le résultat d'une µop soit déjà passée par une ALU, soit en cours d'exécution dans une ALU. Le désignateur pour un opérande est donc le désignateur de cette ALU. Reste à faire la correspondance entre un résultat/registre et l'ALU qui va le calculer ou l'a déjà calculé. Pour cela, le ''scoreboard'' mémorise la correspondance entre un registre/résultat et une unité de calcul dans une mémoire cache appelée la '''''Q-table'''''. Pour comprendre à quoi elle sert, prenons deux instructions consécutives, dont la seconde utilise le résultat de la première. La première instruction est lancée dans une unité de calcul enregistre son résultat dans un registre de destination. Le ''scoreboard'' mémorise alors dans la ''Q-table'' que le registre de destination est associé à telle unité de calcul, elle mémorise une correspondance entre le désignateur de l'ALU et le registre de destination. Par la suite, la seconde instruction est émise. Le ''scoreboard'' interroge la ''Q-table'' pour les deux opérandes de l'instruction, pour récupérer les deux désignateurs de l'ALU associés. Ils sont envoyés au banc de registres pour gérer la lecture des opérandes. Pour résumer, le ''scoreboard'' effectue les actions suivantes lors de l'émission. * Premièrement, il détermine si l'unité de calcul est disponible ou non, en utilisant le bit de disponibilité BUSY. * Deuxièmement, il mémorise les numéros de registres opérande et résultat pour commander la lecture des opérandes. * Troisièmement, il traduit les numéros de registres opérande en identifiants d'ALU. * Quatrièmement, il mémorise dans une ''Q-table'' la relation entre le registre de destination et l'unité de calcul choisie à l'étape 1. La troisième étape permet de faire le lien entre un résultat calculé mais pas encore enregistré dans les registres, et un registre opérande non-nommé. Le lien guide le chargement des opérandes et donc le système de contournement passant par des registres (ce qui est du renommage de registre implicite). ===La gestion des résultats : les signaux RELEASE et GOWRITE=== Une fois la µop exécutée, son résultat est enregistré dans le registre résultat. Une fois le résultat dans le registre résultat, l'unité de calcul envoie un signal REQUEST au ''scoreboard'' pour savoir si la donnée peut être enregistrée dans les registres architecturaux. L'ensemble des signaux REQUEST est regroupé dans un vecteur de bit, une sorte de nombre, dont chaque bit indique quelle unité veut écrire un résultat. L'ensemble des signaux RELEASE forment un nombre encodé en unaire qui indique quelle ALU a fournit le résultat. Là, le ''scoreboard'' effectue plusieurs opérations successives sur ce nombre, en appliquant plusieurs masques. Le premier masque appliqué vérifie pour chaque ALU si elle a le droit d'écrire son résultat en mémoire, sur la base des dépendances WAW et WAR. En cas de dépendances WAR ou WAW, l'écriture du résultat est retardé, ce qui fait que l'unité de calcul n'est pas considérée, son signal RELEASE est ignoré, il est masqué. Le masque qui permet cela est appelé le '''masque READ PENDING'''. Le second masque est un circuit de priorité qui sélectionne un bit seulement. Il est en effet possible que plusieurs unités de calcul fournissent un résultat en même temps. Ou encore que l'une ait son écriture retardée et ait un signal RELEASE à 1 depuis plusieurs cycles. Toujours est-il qu'on ne peut écrire qu'un résultat à la fois, ce qui fait qu'il faut sélectionner une unité de calcul. Pour cela, un circuit de priorité sélectionne un seul signal RELEASE à 1 et met les autres à zéro. C'est le second masque. {|class="wikitable" |+ Traitement des signaux REQUEST |- ! colspan="10 | Signaux REQUEST en sortie des ALUs |- | 0 || 1 || 0 || 1 || 1 || 1 || 0 || 0 || 0 || 0 |- ! colspan="10 | Application du masque READ PENDING pour les dépendances WAW/WAR |- | 0 || 0 || 0 || 1 || 1 || 0 || 0 || 0 || 0 || 0 |- ! colspan="10 | Sélection par un circuit de priorité |- | 0 || 0 || 0 || 1 || 0 || 0 || 0 || 0 || 0 || 0 |} Après l'application du second masque, il ne reste qu'un seul bit à un, qui indique quelle ALU a été sélectionnée pour l'écriture. Il se trouve que l'ensemble des bits forme un désignateur d'ALU, encodé en représentation unaire, en représentation ''one-hot''. Pour rappel, cela veut dire que seul un bit dans le nombre est à 1 et ce bit indique la valeur encodée. Si le bit numéro X est à 1, alors la valeur encodée vaut X. L'usage d'une représentation unaire/''one-hot'' fait que l'on a juste à concaténer les signaux REQUEST et appliquer des masques pour obtenir le désignateur adéquat, pas besoin d'encodeur compliqués, ni de circuits de sélection complexes. Le désignateur résultat est appelé '''désignateur d'ALU choisie'''. Une fois ce désignateur calculé, le ''désignateur d'ALU choisie'' est envoyé à la table de réservation, afin de récupérer le nom/numéro du registre résultat associé. Le ''scoreboard'' commande le port d'écriture du banc de registre, avec un signal GOWRITE et le nom/numéro du registre de destination récupéré. Le signal RELEASE est alors remis à zéro. Reste à générer le signal GO WRITE et faire les actions adéquates. Mais il reste deux opérations de maintenance pour terminer l'écriture. La première est de remettre en ordre la Q-table. L'entrée qui liait l'unité de calcul au registre de destination doit être remise à zéro. Le résultat ayant été écrit, il n'est plus associé à l'unité de calcul, le lien entre les deux dans la Q-table est donc effacé. La seconde est de gérer la disponibilité des opérandes. Pour cela, le résultat après application des deux masques est aussi utilisé pour détecter la disponibilité des opérandes, pour mettre à 1 le bit READ FLAG adéquat. Là encore, c'est la table de réservation qui s'en charge. ===La détection des opérandes disponibles : la génération des READ FLAG et du signal GOREAD=== Le désignateur d'ALU choise est envoyé à la table de réservation pour récupérer le nom de registre destination, mais aussi aux champs opérandes. Dans chaque entrée, il comparé aux deux désignateurs Qj et Qk, associés chacun à une opérande. Pour rappel, les désignateurs Qj et Qk sont des désignateurs d'unité de calcul, eux aussi encodés en unaire. S'il y a ''match'', alors l'opérande est disponible. Le comparateur génère un signal qui met à 1 le bit de disponibilité READ FLAG (i pour le numéro de l'unité de calcul), le bit est dans une bascule pour ne pas être effacé au cycle suivant. Le ''scoreboard'' contient donc une matrice de comparaison, qui compare le résultat de l'étape précédente avec tous les désignateurs associés à une opérande. L'avantage d'encoder les désignateurs en unaire fait que la comparaison est plus simple : elle se constitue uniquement de portes ET, pas besoin de portes XOR comme on en aurait eu besoin en utilisant des désignateurs en binaire. De plus, le calcul du désignateur à partir des signaux REQUEST est trivial, pas besoin de passer par un encodeur. [[File:Détection des dépendances CDC 6600.png|centre|vignette|upright=2|Détection des dépendances RAW CDC 6600]] Quand les deux bits READ FLAG d'une instruction sont à 1, le ''scoreboard'' envoie un signal GOREAD à la mémoire et aux unités de calcul. Les numéros/noms de registre, présents dans les registres Fj et Fk, sont envoyés au banc de registre. Le signal envoyé à l'ALU lui demande de copier ces opérandes dans les registres opérandes et de démarrer l'instruction. L'opcode de l'instruction est déjà mémorisé dans le registre d'opcode, ou alors il est envoyé à ce moment. Puis les bits READ FLAG de l'entrée associée à l'ALU sont remis à zéro. ===Le calcul du masque READ PENDING=== Plus haut, nous avions vu le masque READ PENDING qui interdit d'écrire un résultat dans un registre si les conditions ne sont pas réunies, en cas de dépendance WAR. Le nom du signal indique comment sont détectées les dépendances WAR : l'écriture est interdite si une lecture de ce registre est en attente. Le CDC 6600 lit les deux opérandes d'une instruction en même temps, ce qui fait qu'une opérande peut être disponible mais pas encore lue. Une opérande dans ce cas a un READ FLAG à 1 pour le registre associé. Chaque bit du signal READ PENDING se détermine donc en faisant un ET logique entre tous les bits READ FLAG associé à un registre, encore faut-il les sélectionner en fonction du registre voulu et de l'unité de calcul associée au registre. La méthode permet de gérer les dépendances WAR, mais pas les dépendances WAW. Le CDC 6600 bloquait l'instruction dans l'étage d'émission en cas de dépendance WAW. Si l'instruction à émettre avait pour registre de destination un registre de destination d'une instruction dans le pipeline, le processeur émettrait des bulles de pipeline tant que la première écriture n'a pas eu lieu. Son successeur, le CDC 7600 n'avait pas ce défaut et était capable de passer outre toutes les dépendances de données WAR et WAW. Une raison probable à cela est que le CDC 6600 a été terminé en cataastrophe et que ses concepteurs n'ont pas eu le temps d'implémenter une technique complexe de gestion des dépendances WAW. Mais ils ont eu le temps de terminer le design du ''scoreboard'' pour le successeur 7600. Une autre raison est que le pipeline étant court, les dépendances WAW avaient un effet très limité et que bloquer l'émission n'entrainait pas une baisse de performance notable. Mais on peut en théorie faire autrement. Le principe est que les instructions sont émises en absence de dépendances RAW, mais que l'écriture de leur résultat peut être retardée à l'étage d'écriture dans les registres. En cas de dépendances WAR ou WAW, le résultat à écrire est maintenu sur la sortie d'une unité de calcul, dans un registre tampon placé sur cette même sortie, comme illustré plus bas. Les instructions sont donc bloquées dans l'unité de calcul, qui n'est plus disponible pour d'autres instructions. Le ''scoreboard'' sait qu'il ne peut plus envoyer d'instruction sur cette unité de calcul. À chaque cycle, l'étage d'enregistrement choisit le résultat à enregistrer dans les registres, en respectant les dépendances de données. C'est le ''scoreboard'' qui autorise ou non cette écriture, en commandant l'étage d'enregistrement en fin de pipeline. En clair : l'enchainement des signaux GOWRITE impose un enregistrement des résultats qui suit l'ordre du programme. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Le renommage de registres | prevText=Le renommage de registres | next=Les implémentations modernes de l'OOO | nextText=Les implémentations modernes de l'OOO }} </noinclude> 75og0kf9r7qqqivkzor44wb2zvy9sbl 773665 773631 2026-09-29T22:19:10Z Mewtow 31375 /* Le calcul du masque READ PENDING */ 773665 wikitext text/x-wiki Dans ce chapitre, nous allons voir deux techniques d'exécution dans le désordre un peu à part. Il s'agit de deux techniques historiquesn utilisées sur des ordinateurs très anciens, qui portent les noms de ''scoreboarding'' et d'algorithme de Tomasulo. Les deux ne sont plus utilisés aujourd'hui, pour diverses raisons, la principale étant qu'elles ne gèrent pas les exceptions précises. En clair, impossible de les utiliser en même temps que la prédiction de branchement ou d'autres optimisations. Elles ne gèrent pas les exceptions précises, car elles utilisent des formes de renommage de registre assez originale. L'algorithme de Tomasulo renomme les registres dans les stations de réservation, chose qu'on n'a volontairement pas abordé dans le chapitre sur le renommage de registre. le ''scoreboarding'' utilise quant à lui une technique similaire, mais bien plus difficile à classer, qui est clairement idiosyncratique. Il est possible de les modifier pour leur adjoindre un ROB, mais le résultat ressemble beaucoup aux techniques de renommage dans le ROB. ==L'algorithme de Tomasulo et les stations de réservation== L''''algorithme de Tomasulo''' est un algorithme assez compliqué à expliquer, car il mélange exécution dans le désordre, contournement et renommage de registre implicite en un seul algorithme. L'algorithme de Tosmasulo a été implémenté une première fois sur les ordinateurs IBM 360/91, et quelques processeurs ont utilisé une variante de celui-ci. Beaucoup de processeurs modernes se sont sont inspiré de cet algorithme pour leur design. Il est antérieur au ''scoreboarding'' du CDC 6600, qui avait des fonctionnalités similaires, mais nous allons le voir avant, afin de mieux faire ressortir les ressemblances entre les deux algorithmes. Avec l'algorithme de Tomasulo, le renommage de registre se fait dans des '''stations de réservation'''. Pour rappel, ce sont des ''schedulers'' qui ont pour particularité de mémoriser non seulement les µops en attente, mais aussi leurs opérandes. Les opérandes peuvent provenir de deux sources différentes. Soit elles sont lues depuis les registres avant l'émission, soit elles sont obtenues par le réseau de contournement. Dans son acceptation la plus stricte, le terme station de réservation est réservé au cas où il y a une station de réservation par unité de calcul. Et c'est le cas avec l'algorithme de Tomasulo initial, qui a été utilisé pour la première fois sur un processeur avec trois stations de réservation : une pour le circuit multiplieur/diviseur flottant, une pour l'additionneur flottant, et une pour l'unité LOAD/STORE. Un autre point très important est que, dans le papier de Tomasulo, les stations de réservation ne conservent que les µops en attente d'émission. L'algorithme original n'avait pas de ROB et ne gérait pas du tout les exceptions précises. Il ne peut donc pas être utilisé sur les architectures modernes, qui utilisent de la prédiction de branchement. Il est possible d'ajouter un ROB à l'algorithme, mais il doit être modifié et on retombe alors sur une forme de renommage dans le ROB. ===Les stations de réservation et le contournement=== Les stations de réservation mémorisent les µops en attente d'exécution sur l'unité de calcul, tant qu'elles n'ont pas encore leurs opérandes prêtes. Par modifiées pour faciliter le contournement, je veux dire par là qu'elles mémorisent les opérandes d'une µop à exécuter. Si les opérandes sont dans les registres, elles sont lues depuis les registres avant ''issue/dispatch'', et mémorisées dans la station de réservation. Si elles ne sont pas encore disponibles au moment de l'''issue'', elles seront fournies plus tard par le système de contournement et seront alors enregistrées dans la station de réservation. Le fait que le ''scheduler'' incorpore les opérandes de la µop implique une forme de renommage de registres implicite, comme on le verra plus tard. Pour rappel, il s'agit d'une technique dite de '''lecture avant émission''', qui lit les registres d'une µop avant de l'émettre. Pour gérer le contournement, les résultats d'une µop sont non seulement envoyés vers le ROB et/ou les registres, mais ils sont aussi envoyés vers les stations de réservation, via un bus de contournement. La sortie de chaque unité de calcul est connectée à toutes les stations de réservation, dans le cas idéal. Pour cela, la sortie des unités de calcul est reliée aux stations de réservation via un bus, appelé le ''bus commun d’ordonnancement de la mémoire'' (''common memory-ordering bus''), que nous nommerons dorénavant ''bus de contournement''. [[File:Algorithme de Tomasulo.png|centre|vignette|upright=2|Algorithme de Tomasulo]] L'idée derrière le '''bus de contournement''' est que les sorties des unités de calcul sont reliées à un bus, qui est lui connecté aux entrées des ALU. La contrainte est qu'une seule unité de calcul peut envoyer des données sur ce bus. Rien d'étonnant : c'est un bus, il ne peut transférer qu'une donnée à la fois. Si plusieurs unités de calcul veulent transmettre leurs résultats sur ce bus, l'une d'entre elle est choisie et les autres doivent mettre en attente leurs résultats dans une mémoire tampon, soit un registre, soit une FIFO. Dans les deux cas, le registre ou la FIFO sont appelés des ''producers''. L'implémentation demande de bloquer des opérations dans l'ALU si le contournement doit être mis en attente, ce qui bloque tout le pipeline en cas de problème. [[File:Producteurs en sortie d'une ALU.jpg|centre|vignette|upright=2|Producteurs en sortie d'une ALU.]] Le bus de contournement est assez spécifique à l'algorithme de Tomasulo, dans le sens où c'est un des rares articles académique à utiliser un tel bus de contournement. ===Le renommage de registres dans les stations de réservation=== L'unité d'émission attribue à chaque résultat de calcul un '''identifiant de résultat'''. L'identifiant est une sorte de numéro de registre virtuel, qui est transmis sur le bus de contournement. L'identifiant est propagé comme tout signal de commande, il suit la µop sur son trajet dans le pipeline. Quand l'unité de calcul a fini son calcul, l'identifiant est envoyé avec le résultat sur le bus de contournement. Les stations de réservation contenant cet identifiant de résultat enregistrent alors le résultat dans le champ adéquat. De plus, le ROB a des entrées modifiées pour contenir l'identifiant de résultat, afin d'associer un identifiant de résultat à un registre de destination. Les entrées des stations de réservation sont structurées en plusieurs champs. Le premier mémorise l'opcode de l'instruction/µop. Il y a aussi un champ pour l'identifiant de résultat. Il y a aussi deux champs, un par opérande. Il peut contenir deux choses : l'opérande elle-même, l'identifiant de résultat associé. Pour faire la différence, les deux champs ont chacun un bit de présence, qui indique si l'opérande est présente dans le champ ou non (auquel cas, c'est un identifiant). [[File:Entrée d'une station de réservation.png|centre|vignette|upright=3|Entrée d'une station de réservation.]] Vous vous demandez certainement où sont les registres virtuels avec cette organisation. Et bien il ne s'agit ni plus ni moins que des stations de réservation. Et plus précisément les champs pour les opérandes. L'identifiant de résultat est l'équivalent d'un nom de registre virtuel. D'ailleurs, une fois la µop émise, il n'y a pas de noms de registre physique dans les stations de réservation, seulement des identifiants de résultat. En somme, le renommage de registre est pris en charge par les stations de réservation, et par le système de contournement. ===L'exécution d'une µop avec l'algorithme de Tomasulo=== L'exécution d'une µop avec des stations de réservation se fait en plusieurs étapes. Premièrement, la µop est émise, dans le sens où elle est transmise de l'unité d'émission aux stations de réservation. Deuxièmement, la µop est exécutée ou attend son exécution. Enfin, son résultat est enregistré dans les registres et envoyé aux stations de réservation pour contournement. L'émission se fait sous condition qu'une station de réservation pour l'unité de calcul voulue soit disponible. Si c'est le cas, l'unité d'émission vérifie si les opérandes sont disponibles dans le banc de registre architecturaux. Les opérandes disponibles sont alors traitées différemment des opérandes non-disponibles. Les opérandes non-disponibles, elles seront envoyées via contournement plus tard et le renommage de registre doit être utilisé. L'opérande est associée à l'identifiant de résultat qui permet de savoir quand elle sera calculée. À l'opposé, les opérandes disponibles sont lues depuis les registres et enregistrées dans la station de réservation, leur bit de présence est mis à 1. Il n'y a pas de renommage de registres, car il n'y en a pas besoin pour ces opérandes. Reprenons maintenant après l'émission de la µop, qui a été envoyée dans les stations de réservation. Elle attend alors que ses opérandes soient disponibles dans la station de réservation. Les opérandes non-disponibles sont alors calculées par des µops et sont envoyées sur le bus de contournement. La station de réservation reconnait alors l'identifiant et enregistre le résultat dans le champ adéquat. Une fois toutes les opérandes disponibles, la µop est exécutée. Une fois son résultat connu, il est envoyé sur le bus de contournement, mais aussi dans le banc de registres. Et le tout continue. ==Le ''scoreboarding'' du CDC 6600== L'implémentation du ''scoreboard'' sur le CDC 6600/7600 est appelée dans la suite du cours : le '''''scoreboarding'''''. La description que je vais donner du ''scoreboard'' est très différente de celle disponible dans les livres d'architecture des ordinateurs. La plupart des manuels, surtout les textbooks américains, donnent une description très haut niveau, très algorithmique du ''scoreboarding'', qui ne sera pas abordée. À la place, je vais donner une description alternative, différente autant sur l'approche que le fond. Le CDC 6600 n'existe plus, tous les exemplaires ont depuis longtemps été démontés, aussi il ne reste que des sources historiques pour savoir comment fonctionnait son ''scoreboard''. Heureusement, il existe un livre qui décrit dans les moindres détails cette architecture, écrit par un des concepteurs de l'ordinateur : [https://archive.computerhistory.org/resources/text/CDC/cdc.6600.thornton.design_of_a_computer_the_control_data_6600.1970.102630394.pdf Design of a computer : the CDC 6600]. Ce qui va suivre est majoritairement ité de cette source. ===Le chemin de données du CDC 6600 et sa relation avec le ''scoreboard''=== Le pipeline d'un processeur avec ''scoreboarding'' ressemble à celui du schéma suivant. Pour résumer, le chemin de donnée forme un pipeline à trois étages : lecture des registres, exécution dans l'ALU, écriture dans les registres. Les opérations à effectuer son envoyées aux ALUs, et elles attendent leurs opérandes dedans. [[File:Scoreboard avec exceptions imprécises.png|centre|vignette|upright=2|Scoreboard avec exceptions imprécises]] La séparation en trois étages fait qu'il y a des registres entre chaque étages. Les opérandes sont chargées dans des registres en amont de l'ALU, et le résultat est enregistré temporairement dans un registre en sortie de l'ALU. Nous les appellerons : '''registres opérandes''' et '''registre résultat'''. Entre les deux, l'ALU effectue une opération quand les opérandes sont disponibles dans les registres opérandes, et maintien le résultat dans le registre résultat si besoin. Il y a aussi un autre registre qui mémorise l'opcode de l'opération, lors de l'attente des opérandes, mais aussi lors de l'exécution. Nous l'omettrons dans ce qui suit, car il s'agit d'un registre de pipeline classique. Les registres opérande et résultat n'ont pas besoin d'être très complexes vu qu'ils servent juste à maintenir une donnée. Les registres ne sont pas connectés à l'horloge, les bascules ne sont pas synchrones, ils sont fabriqués à partir de simples ''latches'', de simples bascules D non-synchrones. Et il en est de même pour le registre d'opcode. Le ''scoreboard'' commande le signal Enable qui autorise les écritures dedans, rien de plus. Le pipeline est donc le suivant : [[File:Pipeline d'un processeur utilisant le scoreboarding.png|centre|vignette|upright=2|Pipeline d'un processeur utilisant le scoreboarding]] Les registres opérandes sont chacun associé à un bit READ FLAG qui précise si l'opérande du calcul est disponible. Les bits READ FLAG sont mis à jour par un mécanisme assez complexe, qui sera vu dans la suite. Le ''scoreboard'' gère les transferts entre les registres opérande/résultat et le reste du processeur. Il génère deux signaux de 1 bit nommés GO READ et GO STORE/GO WRITE. Le signal GO READ déclenche la copie d'un registre architectural dans un registre opérande. Le signal GO WRITE déclenche la copie du registre résultat dans le registre architectural adéquat. Pour effectuer une lecture ou une écriture, les noms des registres adéquats sont mémorisés dans deux registres notés Fi, Fj, et Fk. Fi mémorise le registre de destination de l'opération, Fj et Fk mémorisent les noms/numéros des registres opérandes. Les deux registres Qj et Qk sont utilisés pour la détection des opérandes disponibles, nous en reparlerons plus tard. Les registres Fi, FJ et Fk sont dans le ''scoreboard'', et ils sont envoyés sur les entrées d'adresse du banc de registre suivant les besoins, suivant qu'on fasse une lecture ou une écriture. La lecture et écriture des registres donc totalement le fait du ''scoreboard'', qui commande le banc de registres, comme le ferait un séquenceur normal. [[File:CDC 6600 datapath control.png|centre|vignette|upright=2|CDC 6600 datapath control]] Notez que les registres opérandes, couplés au registre d'opcode, peuvent être vus comme une station de réservation simplifiée, sans gestion du contournement. La différence principale avec l'algorithme de Tomasulo est que les champs pour les identifiants de résultat ont disparus, et que les bits de disponibilité des opérandes READ FLAG sont en réalité intégré au ''scoreboard'', comme on le verra plus tard, avec une gestion de la disponibilité des opérandes totalement différente. De plus, il n'y a qu'une seule station de réservation par ALU, donc un risque plus grand de dépendances structurelles. On ne peut mettre en attente qu'une seule µop par ALU, avec le ''scoreboard''. ===Les désignateurs utilisés par le ''scoreboard''=== Les registres opérandes et résultat ne sont pas des registres architecturaux, mais ce ne sont pas des registres de pipeline non plus. Il est possible de faire l'analogie avec une station de réservation, mais l'analogie est limitée pour une raison simple : le ''scoreboard'' attend que les deux opérandes sont disponibles pour déclencher la lecture avec le signal GO READ. En théorie, il est tout à fait possible de lire un registre opérande à la fois, dès que l'opérande est disponible, mais le ''scoreboard'' ne faisait pas comme ça. De plus, les opérandes ne sont pas vraiment transmises via un réseau de contournement depuis la sortie de l'ALU. Cependant, une rumeur veut que le processeur implémente un système de contournement, qui passe...par l'intermédiaire des registres. Paradoxal, mais qui s'explique pourtant très bien quand on connait le fonctionnement des registres utilisés. Le processeur utilisait une ancienne technologie de transistors, appelée ECL. Beaucoup de bancs de registres fabriqués avec cette technologie avaient une propriété intéressante : toute donnée écrite sur le port d'écriture était immédiatement disponible sur le port de lecture. Plus précisément, l'écriture se faisait sur front montant et la lecture sur front descendant. En faisant cela, une opérande pouvait être écrite dans les registres architecturaux, mais pourtant copiée dans les registres opérandes au même cycle. Le tout fonctionne presque comme un système de contournement, avec cependant quelques limitations ! Avec un vrai système de contournement, l'implémentation est beaucoup plus puissante. Quant à savoir si les registres opérandes sont nommés, c'est un peu compliqué et la réponse serait qu'ils sont nommés de manière implicite. Il est d'ailleurs débattable de savoir si le CDC 6600/7600 implémente le renommage de registres... Le point de discorde est lié au fait que le ''scoreboard'' attribue un numéro à chaque unité de calcul, appelé le '''désignateur Q'''. Et ces identifiants sont utilisés pour la lecture des opérandes et leur copie dans les registres, ils se comportent comme un nom de registre virtuel. Pour simplifier les explications, nous allons partir du principe que les désignateurs sont encodés en représentation unaire. Pour rappel, la représentation unaire représente un nombre sur plusieurs bits, dont un seul est à 1. Un zéro est codé en mettant tous les bits du nombre à zéro, la valeur 1 est encodée avec la valeur 000...0001, le deux avec 000...0010, etc. {|class="wikitable" |+ Désignateur d'ALU |- ! ALU ADD !! ALU MUL !! ALU DIV !! ALU SUB !! ALU CMP !! ALU MOV |- | 0 || 0 || 1 || 0 || 0 || 0 |} La réalité est que les désignateurs sont présents à plusieurs endroits et sont soit codés en unaires, soit codés en binaire, avec des traductions fréquentes entre les deux. Ils sont par exemple traduits du binaire vers l'unaire lors de la génération des signaux READ FLAG. Les traductions inverses sont aussi fréquentes. Les traductions se basent sur des décodeurs/encodeurs un peu modifiés. L'avantage de la représentation unaire est que les comparaisons sont légèrement plus simples, les comparateurs économisent quelques portes logiques. De plus, elle s'adapte assez bien avec le fait que chaque unité de calcul précise si elle est disponible ou non, ce qui deviendra plus clair dans la suite. ===Les réservations et la table de réservation=== Le ''scoreboard'' du CDC 6600 contient une table de '''réservation''', qui permet de réserver une unité de calcul pour une µop à émettre. La table de réservation est composée d'entrées, une par unité de calcul, qui peut mémoriser une µop. Une entrée mémorise pour chaque unité de calcul : * l'opcode de l'instruction à exécuter dessus ; * les noms/numéros des registres opérandes et destination ; * les désignateurs Q des unités de calcul qui fourniront les opérandes en résultat ; * deux bits READ FLAG qui disent si l'opérande associé est disponible. : Dans le livre utilisé comme source, il n'est pas clair si les noms des registres opérandes/résultat sont placés dans l'unité de calcul ou dans le ''scoreboard''. Les explications semblent indiquer que c'est juste à côté de l'ALU, mais les schémas se contredisent là-dessus. Dans la suite, je pars du principe qu'ils sont dans le ''scoreboard'', ce qui aurait bien plus de sens. Le ''scoreboard'' consulte la table de réservation pour émettre une µop. Avant d’émettre une µop, elle regarde si l'entrée est libre ou déjà occupée par une µop. Pour cela, chaque entrée est associée à un bit BUSY qui indique si l'entrée est vide ou occupée. Vu qu'il y a une entrée par unité de calcul, attribuer une entrée à une µop est asszz simple : chaque µop va dans une entrée bien précise, il suffit de vérifier celle-ci. Le bit BUSY est mis à 1 quand une µop est émise, ajoutée dans l'entrée, mis à zéro quand elle est terminée. La libération d'une entrée se fait quand le signal GO WRITE est émis, le signal RELEASE ne suffit pas. La réservation permet de réserver une ALU pour une opération. La µop est alors envoyée à l'ALU, où elle attend que ses opérandes soient disponibles. Une µop attend son tour et n'est émise qu'une fois que les deux bits READ FLAGS sont à 1. La conséquence est qu'une µop reste dans l'unité de calcul tant qu'elle a des dépendances RAW. Et seules les dépendances RAW, où une instruction pour opérande le résultat d'une instruction précédente, impliquent un blocage du pipeline et des bulles de pipeline. Les dépendances WAW ou WAR sont traitées autrement. La table de réservation ne stocke pas les opérandes, ce qui fait qu'on peut la voir comme un ''scheduler'' à une entrée, ou encore comme une station de réservation castrée. Un détail très important est que ce système de réservation met en attente une µop par ALU. Vu que toutes les ALUs du CDC 6600 sont très différentes, l'attribution d'une µop à une ALU est trivial. Par contre, si une µop veut utiliser une ALU réservée, elle ne peut pas et il faut bloquer le pipeline. Le système de réservation est donc une cause de dépendances structurelles qui bloquent l'émission des µops dans de nombreux cas. Ce ne serait pas le cas si on pouvait placer plusieurs réservations par unité de calcul, mais passons. Pour une dépendance WAR, la µop est émise, elle s'exécute, mais son résultat est maintenu dans le registre résultat le temps que ces dépendances soient résolues. Pour le dire autrement, Les dépendances WAR font que les µops sont retenues dans l'étage d'enregistrement des données, un peu comme sur un processeur à pipeline multicycle (de longueur fixe). Sauf que les pipeline multicycle, il y aurait plusieurs registres d'échelonnements qui se suivent, alors qu'on n'en a qu'un ici, ce qui fait que l'unité de calcul est bloquée si l'écriture est retardée. En théorie, les dépendances WAW devraient être traitées avec un mécanisme similaire, mais le processeur détectait ces dépendances à l'émission et bloquait l'émission si un registre lu était accédé en lecture. [[File:Enregistrement des données dans les registres avec un pipeline avec scoreboarding.png|centre|vignette|upright=2|Enregistrement des données dans les registres avec un pipeline avec scoreboarding]] ===La Q-table : l'unité de renommage de registres=== Quand une µop est émise, elle réserve une unité de calcul. Mais il faut pour cela remplir les champs pour les désignateurs d'ALU, même si on voit mal à quoi ils servent pour le moment. Il se trouve que les registres opérandes contiennent une valeur, qui est le résultat d'une µop soit déjà passée par une ALU, soit en cours d'exécution dans une ALU. Le désignateur pour un opérande est donc le désignateur de cette ALU. Reste à faire la correspondance entre un résultat/registre et l'ALU qui va le calculer ou l'a déjà calculé. Pour cela, le ''scoreboard'' mémorise la correspondance entre un registre/résultat et une unité de calcul dans une mémoire cache appelée la '''''Q-table'''''. Pour comprendre à quoi elle sert, prenons deux instructions consécutives, dont la seconde utilise le résultat de la première. La première instruction est lancée dans une unité de calcul enregistre son résultat dans un registre de destination. Le ''scoreboard'' mémorise alors dans la ''Q-table'' que le registre de destination est associé à telle unité de calcul, elle mémorise une correspondance entre le désignateur de l'ALU et le registre de destination. Par la suite, la seconde instruction est émise. Le ''scoreboard'' interroge la ''Q-table'' pour les deux opérandes de l'instruction, pour récupérer les deux désignateurs de l'ALU associés. Ils sont envoyés au banc de registres pour gérer la lecture des opérandes. Pour résumer, le ''scoreboard'' effectue les actions suivantes lors de l'émission. * Premièrement, il détermine si l'unité de calcul est disponible ou non, en utilisant le bit de disponibilité BUSY. * Deuxièmement, il mémorise les numéros de registres opérande et résultat pour commander la lecture des opérandes. * Troisièmement, il traduit les numéros de registres opérande en identifiants d'ALU. * Quatrièmement, il mémorise dans une ''Q-table'' la relation entre le registre de destination et l'unité de calcul choisie à l'étape 1. La troisième étape permet de faire le lien entre un résultat calculé mais pas encore enregistré dans les registres, et un registre opérande non-nommé. Le lien guide le chargement des opérandes et donc le système de contournement passant par des registres (ce qui est du renommage de registre implicite). ===La gestion des résultats : les signaux RELEASE et GOWRITE=== Une fois la µop exécutée, son résultat est enregistré dans le registre résultat. Une fois le résultat dans le registre résultat, l'unité de calcul envoie un signal REQUEST au ''scoreboard'' pour savoir si la donnée peut être enregistrée dans les registres architecturaux. L'ensemble des signaux REQUEST est regroupé dans un vecteur de bit, une sorte de nombre, dont chaque bit indique quelle unité veut écrire un résultat. L'ensemble des signaux RELEASE forment un nombre encodé en unaire qui indique quelle ALU a fournit le résultat. Là, le ''scoreboard'' effectue plusieurs opérations successives sur ce nombre, en appliquant plusieurs masques. Le premier masque appliqué vérifie pour chaque ALU si elle a le droit d'écrire son résultat en mémoire, sur la base des dépendances WAW et WAR. En cas de dépendances WAR ou WAW, l'écriture du résultat est retardé, ce qui fait que l'unité de calcul n'est pas considérée, son signal RELEASE est ignoré, il est masqué. Le masque qui permet cela est appelé le '''masque READ PENDING'''. Le second masque est un circuit de priorité qui sélectionne un bit seulement. Il est en effet possible que plusieurs unités de calcul fournissent un résultat en même temps. Ou encore que l'une ait son écriture retardée et ait un signal RELEASE à 1 depuis plusieurs cycles. Toujours est-il qu'on ne peut écrire qu'un résultat à la fois, ce qui fait qu'il faut sélectionner une unité de calcul. Pour cela, un circuit de priorité sélectionne un seul signal RELEASE à 1 et met les autres à zéro. C'est le second masque. {|class="wikitable" |+ Traitement des signaux REQUEST |- ! colspan="10 | Signaux REQUEST en sortie des ALUs |- | 0 || 1 || 0 || 1 || 1 || 1 || 0 || 0 || 0 || 0 |- ! colspan="10 | Application du masque READ PENDING pour les dépendances WAW/WAR |- | 0 || 0 || 0 || 1 || 1 || 0 || 0 || 0 || 0 || 0 |- ! colspan="10 | Sélection par un circuit de priorité |- | 0 || 0 || 0 || 1 || 0 || 0 || 0 || 0 || 0 || 0 |} Après l'application du second masque, il ne reste qu'un seul bit à un, qui indique quelle ALU a été sélectionnée pour l'écriture. Il se trouve que l'ensemble des bits forme un désignateur d'ALU, encodé en représentation unaire, en représentation ''one-hot''. Pour rappel, cela veut dire que seul un bit dans le nombre est à 1 et ce bit indique la valeur encodée. Si le bit numéro X est à 1, alors la valeur encodée vaut X. L'usage d'une représentation unaire/''one-hot'' fait que l'on a juste à concaténer les signaux REQUEST et appliquer des masques pour obtenir le désignateur adéquat, pas besoin d'encodeur compliqués, ni de circuits de sélection complexes. Le désignateur résultat est appelé '''désignateur d'ALU choisie'''. Une fois ce désignateur calculé, le ''désignateur d'ALU choisie'' est envoyé à la table de réservation, afin de récupérer le nom/numéro du registre résultat associé. Le ''scoreboard'' commande le port d'écriture du banc de registre, avec un signal GOWRITE et le nom/numéro du registre de destination récupéré. Le signal RELEASE est alors remis à zéro. Reste à générer le signal GO WRITE et faire les actions adéquates. Mais il reste deux opérations de maintenance pour terminer l'écriture. La première est de remettre en ordre la Q-table. L'entrée qui liait l'unité de calcul au registre de destination doit être remise à zéro. Le résultat ayant été écrit, il n'est plus associé à l'unité de calcul, le lien entre les deux dans la Q-table est donc effacé. La seconde est de gérer la disponibilité des opérandes. Pour cela, le résultat après application des deux masques est aussi utilisé pour détecter la disponibilité des opérandes, pour mettre à 1 le bit READ FLAG adéquat. Là encore, c'est la table de réservation qui s'en charge. ===La détection des opérandes disponibles : la génération des READ FLAG et du signal GOREAD=== Le désignateur d'ALU choise est envoyé à la table de réservation pour récupérer le nom de registre destination, mais aussi aux champs opérandes. Dans chaque entrée, il comparé aux deux désignateurs Qj et Qk, associés chacun à une opérande. Pour rappel, les désignateurs Qj et Qk sont des désignateurs d'unité de calcul, eux aussi encodés en unaire. S'il y a ''match'', alors l'opérande est disponible. Le comparateur génère un signal qui met à 1 le bit de disponibilité READ FLAG (i pour le numéro de l'unité de calcul), le bit est dans une bascule pour ne pas être effacé au cycle suivant. Le ''scoreboard'' contient donc une matrice de comparaison, qui compare le résultat de l'étape précédente avec tous les désignateurs associés à une opérande. L'avantage d'encoder les désignateurs en unaire fait que la comparaison est plus simple : elle se constitue uniquement de portes ET, pas besoin de portes XOR comme on en aurait eu besoin en utilisant des désignateurs en binaire. De plus, le calcul du désignateur à partir des signaux REQUEST est trivial, pas besoin de passer par un encodeur. [[File:Détection des dépendances CDC 6600.png|centre|vignette|upright=2|Détection des dépendances RAW CDC 6600]] Quand les deux bits READ FLAG d'une instruction sont à 1, le ''scoreboard'' envoie un signal GOREAD à la mémoire et aux unités de calcul. Les numéros/noms de registre, présents dans les registres Fj et Fk, sont envoyés au banc de registre. Le signal envoyé à l'ALU lui demande de copier ces opérandes dans les registres opérandes et de démarrer l'instruction. L'opcode de l'instruction est déjà mémorisé dans le registre d'opcode, ou alors il est envoyé à ce moment. Puis les bits READ FLAG de l'entrée associée à l'ALU sont remis à zéro. ===Le calcul du masque READ PENDING=== Plus haut, nous avions vu le masque READ PENDING qui interdit d'écrire un résultat dans un registre si les conditions ne sont pas réunies, en cas de dépendance WAR. Le nom du signal indique comment sont détectées les dépendances WAR : l'écriture est interdite si une lecture de ce registre est en attente. Le CDC 6600 lit les deux opérandes d'une instruction en même temps, ce qui fait qu'une opérande peut être disponible mais pas encore lue. Une opérande dans ce cas a un READ FLAG à 1 pour le registre associé. Chaque bit du signal READ PENDING se détermine donc en faisant un ET logique entre tous les bits READ FLAG associé à un registre, encore faut-il les sélectionner en fonction du registre voulu et de l'unité de calcul associée au registre. La méthode permet de gérer les dépendances WAR, mais pas les dépendances WAW. Le CDC 6600 bloquait l'instruction dans l'étage d'émission en cas de dépendance WAW. Si l'instruction à émettre avait pour registre de destination un registre de destination d'une instruction dans le pipeline, le processeur émettrait des bulles de pipeline tant que la première écriture n'a pas eu lieu. Son successeur, le CDC 7600 n'avait pas ce défaut et était capable de passer outre toutes les dépendances de données WAR et WAW. Une raison probable à cela est que le CDC 6600 a été terminé en cataastrophe et que ses concepteurs n'ont pas eu le temps d'implémenter une technique complexe de gestion des dépendances WAW. Mais ils ont eu le temps de terminer le design du ''scoreboard'' pour le successeur 7600. Une autre raison est que le pipeline étant court, les dépendances WAW avaient un effet très limité et que bloquer l'émission n'entrainait pas une baisse de performance notable. Mais on peut en théorie faire autrement. Le principe est que les instructions sont émises en absence de dépendances RAW, mais que l'écriture de leur résultat peut être retardée à l'étage d'écriture dans les registres. En cas de dépendances WAR ou WAW, le résultat à écrire est maintenu sur la sortie d'une unité de calcul, dans un registre tampon placé sur cette même sortie, comme illustré plus bas. Les instructions sont donc bloquées dans l'unité de calcul, qui n'est plus disponible pour d'autres instructions. Le ''scoreboard'' sait qu'il ne peut plus envoyer d'instruction sur cette unité de calcul. À chaque cycle, l'étage d'enregistrement choisit le résultat à enregistrer dans les registres, en respectant les dépendances de données. C'est le ''scoreboard'' qui autorise ou non cette écriture, en commandant l'étage d'enregistrement en fin de pipeline. En clair : l'enchainement des signaux GOWRITE impose un enregistrement des résultats qui suit l'ordre du programme. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les implémentations modernes de l'OOO | prevText=Les implémentations modernes de l'OOO | nextLa désambiguïsation mémoire | nextText=La désambiguïsation mémoire }} </noinclude> 2ddndhflsd8d3xpfzso3zn92fw3neyw 773670 773665 2026-09-29T22:33:56Z Mewtow 31375 /* L'algorithme de Tomasulo et les stations de réservation */ 773670 wikitext text/x-wiki Dans ce chapitre, nous allons voir deux techniques d'exécution dans le désordre un peu à part. Il s'agit de deux techniques historiquesn utilisées sur des ordinateurs très anciens, qui portent les noms de ''scoreboarding'' et d'algorithme de Tomasulo. Les deux ne sont plus utilisés aujourd'hui, pour diverses raisons, la principale étant qu'elles ne gèrent pas les exceptions précises. En clair, impossible de les utiliser en même temps que la prédiction de branchement ou d'autres optimisations. Elles ne gèrent pas les exceptions précises, car elles utilisent des formes de renommage de registre assez originale. L'algorithme de Tomasulo renomme les registres dans les stations de réservation, chose qu'on n'a volontairement pas abordé dans le chapitre sur le renommage de registre. le ''scoreboarding'' utilise quant à lui une technique similaire, mais bien plus difficile à classer, qui est clairement idiosyncratique. Il est possible de les modifier pour leur adjoindre un ROB, mais le résultat ressemble beaucoup aux techniques de renommage dans le ROB. ==L'algorithme de Tomasulo et les stations de réservation== L''''algorithme de Tomasulo''' est un algorithme assez compliqué à expliquer, car il mélange exécution dans le désordre, contournement et renommage de registre implicite en un seul algorithme. L'algorithme de Tosmasulo a été implémenté une première fois sur les ordinateurs IBM 360/91, et quelques processeurs ont utilisé une variante de celui-ci. Beaucoup de processeurs modernes se sont sont inspiré de cet algorithme pour leur design. Il est antérieur au ''scoreboarding'' du CDC 6600, qui avait des fonctionnalités similaires, mais nous allons le voir avant, afin de mieux faire ressortir les ressemblances entre les deux algorithmes. L'algorithme de Tosmasulo a été utilisé tel quel sur la FPU de l'IBM 360 modèle 90, et uniquement celle-ci. Les ALU entière étaient séparées de la FPU et n'étaient pas concerné par tout ce qui va suivre Le processeur n'utilisait l'exécution dans le désordre que pour sa FPU, pas le "pipeline" entier/mémoire. La FPU en question avait un additionneur flottant, un multiplieur flottant, et une unité mémoire pour les lectures/écritures flottantes. Les trois unités avaient leur propre ''scheduler''. [[File:Tomasulo Architecture.png|centre|vignette|upright=2|Algorithme de Tomasulo originel, de la FPU de l'IBM 360.]] Avec l'algorithme de Tomasulo, le renommage de registre se fait dans des '''stations de réservation'''. Pour rappel, ce sont des ''schedulers'' qui ont pour particularité de mémoriser non seulement les µops en attente, mais aussi leurs opérandes. Les opérandes peuvent provenir de deux sources différentes. Soit elles sont lues depuis les registres avant l'émission, soit elles sont obtenues par le réseau de contournement. Dans son acceptation la plus stricte, le terme station de réservation est réservé au cas où il y a une station de réservation par unité de calcul. Et c'est le cas avec l'algorithme de Tomasulo initial, qui a été utilisé pour la première fois sur un processeur avec trois stations de réservation : une pour le circuit multiplieur/diviseur flottant, une pour l'additionneur flottant, et une pour l'unité LOAD/STORE. Un autre point très important est que, dans le papier de Tomasulo, les stations de réservation ne conservent que les µops en attente d'émission. L'algorithme original n'avait pas de ROB et ne gérait pas du tout les exceptions précises. Il ne peut donc pas être utilisé sur les architectures modernes, qui utilisent de la prédiction de branchement. Il est possible d'ajouter un ROB à l'algorithme, mais il doit être modifié et on retombe alors sur une forme de renommage dans le ROB. ===Les stations de réservation et le contournement=== Les stations de réservation mémorisent les µops en attente d'exécution sur l'unité de calcul, tant qu'elles n'ont pas encore leurs opérandes prêtes. Par modifiées pour faciliter le contournement, je veux dire par là qu'elles mémorisent les opérandes d'une µop à exécuter. Si les opérandes sont dans les registres, elles sont lues depuis les registres avant ''issue/dispatch'', et mémorisées dans la station de réservation. Si elles ne sont pas encore disponibles au moment de l'''issue'', elles seront fournies plus tard par le système de contournement et seront alors enregistrées dans la station de réservation. Le fait que le ''scheduler'' incorpore les opérandes de la µop implique une forme de renommage de registres implicite, comme on le verra plus tard. Pour rappel, il s'agit d'une technique dite de '''lecture avant émission''', qui lit les registres d'une µop avant de l'émettre. Pour gérer le contournement, les résultats d'une µop sont non seulement envoyés vers le ROB et/ou les registres, mais ils sont aussi envoyés vers les stations de réservation, via un bus de contournement. La sortie de chaque unité de calcul est connectée à toutes les stations de réservation, dans le cas idéal. Pour cela, la sortie des unités de calcul est reliée aux stations de réservation via un bus, appelé le ''bus commun d’ordonnancement de la mémoire'' (''common memory-ordering bus''), que nous nommerons dorénavant ''bus de contournement''. [[File:Algorithme de Tomasulo.png|centre|vignette|upright=2|Algorithme de Tomasulo]] L'idée derrière le '''bus de contournement''' est que les sorties des unités de calcul sont reliées à un bus, qui est lui connecté aux entrées des ALU. La contrainte est qu'une seule unité de calcul peut envoyer des données sur ce bus. Rien d'étonnant : c'est un bus, il ne peut transférer qu'une donnée à la fois. Si plusieurs unités de calcul veulent transmettre leurs résultats sur ce bus, l'une d'entre elle est choisie et les autres doivent mettre en attente leurs résultats dans une mémoire tampon, soit un registre, soit une FIFO. Dans les deux cas, le registre ou la FIFO sont appelés des ''producers''. L'implémentation demande de bloquer des opérations dans l'ALU si le contournement doit être mis en attente, ce qui bloque tout le pipeline en cas de problème. [[File:Producteurs en sortie d'une ALU.jpg|centre|vignette|upright=2|Producteurs en sortie d'une ALU.]] Le bus de contournement est assez spécifique à l'algorithme de Tomasulo, dans le sens où c'est un des rares articles académique à utiliser un tel bus de contournement. ===Le renommage de registres dans les stations de réservation=== L'unité d'émission attribue à chaque résultat de calcul un '''identifiant de résultat'''. L'identifiant est une sorte de numéro de registre virtuel, qui est transmis sur le bus de contournement. L'identifiant est propagé comme tout signal de commande, il suit la µop sur son trajet dans le pipeline. Quand l'unité de calcul a fini son calcul, l'identifiant est envoyé avec le résultat sur le bus de contournement. Les stations de réservation contenant cet identifiant de résultat enregistrent alors le résultat dans le champ adéquat. De plus, le ROB a des entrées modifiées pour contenir l'identifiant de résultat, afin d'associer un identifiant de résultat à un registre de destination. Les entrées des stations de réservation sont structurées en plusieurs champs. Le premier mémorise l'opcode de l'instruction/µop. Il y a aussi un champ pour l'identifiant de résultat. Il y a aussi deux champs, un par opérande. Il peut contenir deux choses : l'opérande elle-même, l'identifiant de résultat associé. Pour faire la différence, les deux champs ont chacun un bit de présence, qui indique si l'opérande est présente dans le champ ou non (auquel cas, c'est un identifiant). [[File:Entrée d'une station de réservation.png|centre|vignette|upright=3|Entrée d'une station de réservation.]] Vous vous demandez certainement où sont les registres virtuels avec cette organisation. Et bien il ne s'agit ni plus ni moins que des stations de réservation. Et plus précisément les champs pour les opérandes. L'identifiant de résultat est l'équivalent d'un nom de registre virtuel. D'ailleurs, une fois la µop émise, il n'y a pas de noms de registre physique dans les stations de réservation, seulement des identifiants de résultat. En somme, le renommage de registre est pris en charge par les stations de réservation, et par le système de contournement. ===L'exécution d'une µop avec l'algorithme de Tomasulo=== L'exécution d'une µop avec des stations de réservation se fait en plusieurs étapes. Premièrement, la µop est émise, dans le sens où elle est transmise de l'unité d'émission aux stations de réservation. Deuxièmement, la µop est exécutée ou attend son exécution. Enfin, son résultat est enregistré dans les registres et envoyé aux stations de réservation pour contournement. L'émission se fait sous condition qu'une station de réservation pour l'unité de calcul voulue soit disponible. Si c'est le cas, l'unité d'émission vérifie si les opérandes sont disponibles dans le banc de registre architecturaux. Les opérandes disponibles sont alors traitées différemment des opérandes non-disponibles. Les opérandes non-disponibles, elles seront envoyées via contournement plus tard et le renommage de registre doit être utilisé. L'opérande est associée à l'identifiant de résultat qui permet de savoir quand elle sera calculée. À l'opposé, les opérandes disponibles sont lues depuis les registres et enregistrées dans la station de réservation, leur bit de présence est mis à 1. Il n'y a pas de renommage de registres, car il n'y en a pas besoin pour ces opérandes. Reprenons maintenant après l'émission de la µop, qui a été envoyée dans les stations de réservation. Elle attend alors que ses opérandes soient disponibles dans la station de réservation. Les opérandes non-disponibles sont alors calculées par des µops et sont envoyées sur le bus de contournement. La station de réservation reconnait alors l'identifiant et enregistre le résultat dans le champ adéquat. Une fois toutes les opérandes disponibles, la µop est exécutée. Une fois son résultat connu, il est envoyé sur le bus de contournement, mais aussi dans le banc de registres. Et le tout continue. ==Le ''scoreboarding'' du CDC 6600== L'implémentation du ''scoreboard'' sur le CDC 6600/7600 est appelée dans la suite du cours : le '''''scoreboarding'''''. La description que je vais donner du ''scoreboard'' est très différente de celle disponible dans les livres d'architecture des ordinateurs. La plupart des manuels, surtout les textbooks américains, donnent une description très haut niveau, très algorithmique du ''scoreboarding'', qui ne sera pas abordée. À la place, je vais donner une description alternative, différente autant sur l'approche que le fond. Le CDC 6600 n'existe plus, tous les exemplaires ont depuis longtemps été démontés, aussi il ne reste que des sources historiques pour savoir comment fonctionnait son ''scoreboard''. Heureusement, il existe un livre qui décrit dans les moindres détails cette architecture, écrit par un des concepteurs de l'ordinateur : [https://archive.computerhistory.org/resources/text/CDC/cdc.6600.thornton.design_of_a_computer_the_control_data_6600.1970.102630394.pdf Design of a computer : the CDC 6600]. Ce qui va suivre est majoritairement ité de cette source. ===Le chemin de données du CDC 6600 et sa relation avec le ''scoreboard''=== Le pipeline d'un processeur avec ''scoreboarding'' ressemble à celui du schéma suivant. Pour résumer, le chemin de donnée forme un pipeline à trois étages : lecture des registres, exécution dans l'ALU, écriture dans les registres. Les opérations à effectuer son envoyées aux ALUs, et elles attendent leurs opérandes dedans. [[File:Scoreboard avec exceptions imprécises.png|centre|vignette|upright=2|Scoreboard avec exceptions imprécises]] La séparation en trois étages fait qu'il y a des registres entre chaque étages. Les opérandes sont chargées dans des registres en amont de l'ALU, et le résultat est enregistré temporairement dans un registre en sortie de l'ALU. Nous les appellerons : '''registres opérandes''' et '''registre résultat'''. Entre les deux, l'ALU effectue une opération quand les opérandes sont disponibles dans les registres opérandes, et maintien le résultat dans le registre résultat si besoin. Il y a aussi un autre registre qui mémorise l'opcode de l'opération, lors de l'attente des opérandes, mais aussi lors de l'exécution. Nous l'omettrons dans ce qui suit, car il s'agit d'un registre de pipeline classique. Les registres opérande et résultat n'ont pas besoin d'être très complexes vu qu'ils servent juste à maintenir une donnée. Les registres ne sont pas connectés à l'horloge, les bascules ne sont pas synchrones, ils sont fabriqués à partir de simples ''latches'', de simples bascules D non-synchrones. Et il en est de même pour le registre d'opcode. Le ''scoreboard'' commande le signal Enable qui autorise les écritures dedans, rien de plus. Le pipeline est donc le suivant : [[File:Pipeline d'un processeur utilisant le scoreboarding.png|centre|vignette|upright=2|Pipeline d'un processeur utilisant le scoreboarding]] Les registres opérandes sont chacun associé à un bit READ FLAG qui précise si l'opérande du calcul est disponible. Les bits READ FLAG sont mis à jour par un mécanisme assez complexe, qui sera vu dans la suite. Le ''scoreboard'' gère les transferts entre les registres opérande/résultat et le reste du processeur. Il génère deux signaux de 1 bit nommés GO READ et GO STORE/GO WRITE. Le signal GO READ déclenche la copie d'un registre architectural dans un registre opérande. Le signal GO WRITE déclenche la copie du registre résultat dans le registre architectural adéquat. Pour effectuer une lecture ou une écriture, les noms des registres adéquats sont mémorisés dans deux registres notés Fi, Fj, et Fk. Fi mémorise le registre de destination de l'opération, Fj et Fk mémorisent les noms/numéros des registres opérandes. Les deux registres Qj et Qk sont utilisés pour la détection des opérandes disponibles, nous en reparlerons plus tard. Les registres Fi, FJ et Fk sont dans le ''scoreboard'', et ils sont envoyés sur les entrées d'adresse du banc de registre suivant les besoins, suivant qu'on fasse une lecture ou une écriture. La lecture et écriture des registres donc totalement le fait du ''scoreboard'', qui commande le banc de registres, comme le ferait un séquenceur normal. [[File:CDC 6600 datapath control.png|centre|vignette|upright=2|CDC 6600 datapath control]] Notez que les registres opérandes, couplés au registre d'opcode, peuvent être vus comme une station de réservation simplifiée, sans gestion du contournement. La différence principale avec l'algorithme de Tomasulo est que les champs pour les identifiants de résultat ont disparus, et que les bits de disponibilité des opérandes READ FLAG sont en réalité intégré au ''scoreboard'', comme on le verra plus tard, avec une gestion de la disponibilité des opérandes totalement différente. De plus, il n'y a qu'une seule station de réservation par ALU, donc un risque plus grand de dépendances structurelles. On ne peut mettre en attente qu'une seule µop par ALU, avec le ''scoreboard''. ===Les désignateurs utilisés par le ''scoreboard''=== Les registres opérandes et résultat ne sont pas des registres architecturaux, mais ce ne sont pas des registres de pipeline non plus. Il est possible de faire l'analogie avec une station de réservation, mais l'analogie est limitée pour une raison simple : le ''scoreboard'' attend que les deux opérandes sont disponibles pour déclencher la lecture avec le signal GO READ. En théorie, il est tout à fait possible de lire un registre opérande à la fois, dès que l'opérande est disponible, mais le ''scoreboard'' ne faisait pas comme ça. De plus, les opérandes ne sont pas vraiment transmises via un réseau de contournement depuis la sortie de l'ALU. Cependant, une rumeur veut que le processeur implémente un système de contournement, qui passe...par l'intermédiaire des registres. Paradoxal, mais qui s'explique pourtant très bien quand on connait le fonctionnement des registres utilisés. Le processeur utilisait une ancienne technologie de transistors, appelée ECL. Beaucoup de bancs de registres fabriqués avec cette technologie avaient une propriété intéressante : toute donnée écrite sur le port d'écriture était immédiatement disponible sur le port de lecture. Plus précisément, l'écriture se faisait sur front montant et la lecture sur front descendant. En faisant cela, une opérande pouvait être écrite dans les registres architecturaux, mais pourtant copiée dans les registres opérandes au même cycle. Le tout fonctionne presque comme un système de contournement, avec cependant quelques limitations ! Avec un vrai système de contournement, l'implémentation est beaucoup plus puissante. Quant à savoir si les registres opérandes sont nommés, c'est un peu compliqué et la réponse serait qu'ils sont nommés de manière implicite. Il est d'ailleurs débattable de savoir si le CDC 6600/7600 implémente le renommage de registres... Le point de discorde est lié au fait que le ''scoreboard'' attribue un numéro à chaque unité de calcul, appelé le '''désignateur Q'''. Et ces identifiants sont utilisés pour la lecture des opérandes et leur copie dans les registres, ils se comportent comme un nom de registre virtuel. Pour simplifier les explications, nous allons partir du principe que les désignateurs sont encodés en représentation unaire. Pour rappel, la représentation unaire représente un nombre sur plusieurs bits, dont un seul est à 1. Un zéro est codé en mettant tous les bits du nombre à zéro, la valeur 1 est encodée avec la valeur 000...0001, le deux avec 000...0010, etc. {|class="wikitable" |+ Désignateur d'ALU |- ! ALU ADD !! ALU MUL !! ALU DIV !! ALU SUB !! ALU CMP !! ALU MOV |- | 0 || 0 || 1 || 0 || 0 || 0 |} La réalité est que les désignateurs sont présents à plusieurs endroits et sont soit codés en unaires, soit codés en binaire, avec des traductions fréquentes entre les deux. Ils sont par exemple traduits du binaire vers l'unaire lors de la génération des signaux READ FLAG. Les traductions inverses sont aussi fréquentes. Les traductions se basent sur des décodeurs/encodeurs un peu modifiés. L'avantage de la représentation unaire est que les comparaisons sont légèrement plus simples, les comparateurs économisent quelques portes logiques. De plus, elle s'adapte assez bien avec le fait que chaque unité de calcul précise si elle est disponible ou non, ce qui deviendra plus clair dans la suite. ===Les réservations et la table de réservation=== Le ''scoreboard'' du CDC 6600 contient une table de '''réservation''', qui permet de réserver une unité de calcul pour une µop à émettre. La table de réservation est composée d'entrées, une par unité de calcul, qui peut mémoriser une µop. Une entrée mémorise pour chaque unité de calcul : * l'opcode de l'instruction à exécuter dessus ; * les noms/numéros des registres opérandes et destination ; * les désignateurs Q des unités de calcul qui fourniront les opérandes en résultat ; * deux bits READ FLAG qui disent si l'opérande associé est disponible. : Dans le livre utilisé comme source, il n'est pas clair si les noms des registres opérandes/résultat sont placés dans l'unité de calcul ou dans le ''scoreboard''. Les explications semblent indiquer que c'est juste à côté de l'ALU, mais les schémas se contredisent là-dessus. Dans la suite, je pars du principe qu'ils sont dans le ''scoreboard'', ce qui aurait bien plus de sens. Le ''scoreboard'' consulte la table de réservation pour émettre une µop. Avant d’émettre une µop, elle regarde si l'entrée est libre ou déjà occupée par une µop. Pour cela, chaque entrée est associée à un bit BUSY qui indique si l'entrée est vide ou occupée. Vu qu'il y a une entrée par unité de calcul, attribuer une entrée à une µop est asszz simple : chaque µop va dans une entrée bien précise, il suffit de vérifier celle-ci. Le bit BUSY est mis à 1 quand une µop est émise, ajoutée dans l'entrée, mis à zéro quand elle est terminée. La libération d'une entrée se fait quand le signal GO WRITE est émis, le signal RELEASE ne suffit pas. La réservation permet de réserver une ALU pour une opération. La µop est alors envoyée à l'ALU, où elle attend que ses opérandes soient disponibles. Une µop attend son tour et n'est émise qu'une fois que les deux bits READ FLAGS sont à 1. La conséquence est qu'une µop reste dans l'unité de calcul tant qu'elle a des dépendances RAW. Et seules les dépendances RAW, où une instruction pour opérande le résultat d'une instruction précédente, impliquent un blocage du pipeline et des bulles de pipeline. Les dépendances WAW ou WAR sont traitées autrement. La table de réservation ne stocke pas les opérandes, ce qui fait qu'on peut la voir comme un ''scheduler'' à une entrée, ou encore comme une station de réservation castrée. Un détail très important est que ce système de réservation met en attente une µop par ALU. Vu que toutes les ALUs du CDC 6600 sont très différentes, l'attribution d'une µop à une ALU est trivial. Par contre, si une µop veut utiliser une ALU réservée, elle ne peut pas et il faut bloquer le pipeline. Le système de réservation est donc une cause de dépendances structurelles qui bloquent l'émission des µops dans de nombreux cas. Ce ne serait pas le cas si on pouvait placer plusieurs réservations par unité de calcul, mais passons. Pour une dépendance WAR, la µop est émise, elle s'exécute, mais son résultat est maintenu dans le registre résultat le temps que ces dépendances soient résolues. Pour le dire autrement, Les dépendances WAR font que les µops sont retenues dans l'étage d'enregistrement des données, un peu comme sur un processeur à pipeline multicycle (de longueur fixe). Sauf que les pipeline multicycle, il y aurait plusieurs registres d'échelonnements qui se suivent, alors qu'on n'en a qu'un ici, ce qui fait que l'unité de calcul est bloquée si l'écriture est retardée. En théorie, les dépendances WAW devraient être traitées avec un mécanisme similaire, mais le processeur détectait ces dépendances à l'émission et bloquait l'émission si un registre lu était accédé en lecture. [[File:Enregistrement des données dans les registres avec un pipeline avec scoreboarding.png|centre|vignette|upright=2|Enregistrement des données dans les registres avec un pipeline avec scoreboarding]] ===La Q-table : l'unité de renommage de registres=== Quand une µop est émise, elle réserve une unité de calcul. Mais il faut pour cela remplir les champs pour les désignateurs d'ALU, même si on voit mal à quoi ils servent pour le moment. Il se trouve que les registres opérandes contiennent une valeur, qui est le résultat d'une µop soit déjà passée par une ALU, soit en cours d'exécution dans une ALU. Le désignateur pour un opérande est donc le désignateur de cette ALU. Reste à faire la correspondance entre un résultat/registre et l'ALU qui va le calculer ou l'a déjà calculé. Pour cela, le ''scoreboard'' mémorise la correspondance entre un registre/résultat et une unité de calcul dans une mémoire cache appelée la '''''Q-table'''''. Pour comprendre à quoi elle sert, prenons deux instructions consécutives, dont la seconde utilise le résultat de la première. La première instruction est lancée dans une unité de calcul enregistre son résultat dans un registre de destination. Le ''scoreboard'' mémorise alors dans la ''Q-table'' que le registre de destination est associé à telle unité de calcul, elle mémorise une correspondance entre le désignateur de l'ALU et le registre de destination. Par la suite, la seconde instruction est émise. Le ''scoreboard'' interroge la ''Q-table'' pour les deux opérandes de l'instruction, pour récupérer les deux désignateurs de l'ALU associés. Ils sont envoyés au banc de registres pour gérer la lecture des opérandes. Pour résumer, le ''scoreboard'' effectue les actions suivantes lors de l'émission. * Premièrement, il détermine si l'unité de calcul est disponible ou non, en utilisant le bit de disponibilité BUSY. * Deuxièmement, il mémorise les numéros de registres opérande et résultat pour commander la lecture des opérandes. * Troisièmement, il traduit les numéros de registres opérande en identifiants d'ALU. * Quatrièmement, il mémorise dans une ''Q-table'' la relation entre le registre de destination et l'unité de calcul choisie à l'étape 1. La troisième étape permet de faire le lien entre un résultat calculé mais pas encore enregistré dans les registres, et un registre opérande non-nommé. Le lien guide le chargement des opérandes et donc le système de contournement passant par des registres (ce qui est du renommage de registre implicite). ===La gestion des résultats : les signaux RELEASE et GOWRITE=== Une fois la µop exécutée, son résultat est enregistré dans le registre résultat. Une fois le résultat dans le registre résultat, l'unité de calcul envoie un signal REQUEST au ''scoreboard'' pour savoir si la donnée peut être enregistrée dans les registres architecturaux. L'ensemble des signaux REQUEST est regroupé dans un vecteur de bit, une sorte de nombre, dont chaque bit indique quelle unité veut écrire un résultat. L'ensemble des signaux RELEASE forment un nombre encodé en unaire qui indique quelle ALU a fournit le résultat. Là, le ''scoreboard'' effectue plusieurs opérations successives sur ce nombre, en appliquant plusieurs masques. Le premier masque appliqué vérifie pour chaque ALU si elle a le droit d'écrire son résultat en mémoire, sur la base des dépendances WAW et WAR. En cas de dépendances WAR ou WAW, l'écriture du résultat est retardé, ce qui fait que l'unité de calcul n'est pas considérée, son signal RELEASE est ignoré, il est masqué. Le masque qui permet cela est appelé le '''masque READ PENDING'''. Le second masque est un circuit de priorité qui sélectionne un bit seulement. Il est en effet possible que plusieurs unités de calcul fournissent un résultat en même temps. Ou encore que l'une ait son écriture retardée et ait un signal RELEASE à 1 depuis plusieurs cycles. Toujours est-il qu'on ne peut écrire qu'un résultat à la fois, ce qui fait qu'il faut sélectionner une unité de calcul. Pour cela, un circuit de priorité sélectionne un seul signal RELEASE à 1 et met les autres à zéro. C'est le second masque. {|class="wikitable" |+ Traitement des signaux REQUEST |- ! colspan="10 | Signaux REQUEST en sortie des ALUs |- | 0 || 1 || 0 || 1 || 1 || 1 || 0 || 0 || 0 || 0 |- ! colspan="10 | Application du masque READ PENDING pour les dépendances WAW/WAR |- | 0 || 0 || 0 || 1 || 1 || 0 || 0 || 0 || 0 || 0 |- ! colspan="10 | Sélection par un circuit de priorité |- | 0 || 0 || 0 || 1 || 0 || 0 || 0 || 0 || 0 || 0 |} Après l'application du second masque, il ne reste qu'un seul bit à un, qui indique quelle ALU a été sélectionnée pour l'écriture. Il se trouve que l'ensemble des bits forme un désignateur d'ALU, encodé en représentation unaire, en représentation ''one-hot''. Pour rappel, cela veut dire que seul un bit dans le nombre est à 1 et ce bit indique la valeur encodée. Si le bit numéro X est à 1, alors la valeur encodée vaut X. L'usage d'une représentation unaire/''one-hot'' fait que l'on a juste à concaténer les signaux REQUEST et appliquer des masques pour obtenir le désignateur adéquat, pas besoin d'encodeur compliqués, ni de circuits de sélection complexes. Le désignateur résultat est appelé '''désignateur d'ALU choisie'''. Une fois ce désignateur calculé, le ''désignateur d'ALU choisie'' est envoyé à la table de réservation, afin de récupérer le nom/numéro du registre résultat associé. Le ''scoreboard'' commande le port d'écriture du banc de registre, avec un signal GOWRITE et le nom/numéro du registre de destination récupéré. Le signal RELEASE est alors remis à zéro. Reste à générer le signal GO WRITE et faire les actions adéquates. Mais il reste deux opérations de maintenance pour terminer l'écriture. La première est de remettre en ordre la Q-table. L'entrée qui liait l'unité de calcul au registre de destination doit être remise à zéro. Le résultat ayant été écrit, il n'est plus associé à l'unité de calcul, le lien entre les deux dans la Q-table est donc effacé. La seconde est de gérer la disponibilité des opérandes. Pour cela, le résultat après application des deux masques est aussi utilisé pour détecter la disponibilité des opérandes, pour mettre à 1 le bit READ FLAG adéquat. Là encore, c'est la table de réservation qui s'en charge. ===La détection des opérandes disponibles : la génération des READ FLAG et du signal GOREAD=== Le désignateur d'ALU choise est envoyé à la table de réservation pour récupérer le nom de registre destination, mais aussi aux champs opérandes. Dans chaque entrée, il comparé aux deux désignateurs Qj et Qk, associés chacun à une opérande. Pour rappel, les désignateurs Qj et Qk sont des désignateurs d'unité de calcul, eux aussi encodés en unaire. S'il y a ''match'', alors l'opérande est disponible. Le comparateur génère un signal qui met à 1 le bit de disponibilité READ FLAG (i pour le numéro de l'unité de calcul), le bit est dans une bascule pour ne pas être effacé au cycle suivant. Le ''scoreboard'' contient donc une matrice de comparaison, qui compare le résultat de l'étape précédente avec tous les désignateurs associés à une opérande. L'avantage d'encoder les désignateurs en unaire fait que la comparaison est plus simple : elle se constitue uniquement de portes ET, pas besoin de portes XOR comme on en aurait eu besoin en utilisant des désignateurs en binaire. De plus, le calcul du désignateur à partir des signaux REQUEST est trivial, pas besoin de passer par un encodeur. [[File:Détection des dépendances CDC 6600.png|centre|vignette|upright=2|Détection des dépendances RAW CDC 6600]] Quand les deux bits READ FLAG d'une instruction sont à 1, le ''scoreboard'' envoie un signal GOREAD à la mémoire et aux unités de calcul. Les numéros/noms de registre, présents dans les registres Fj et Fk, sont envoyés au banc de registre. Le signal envoyé à l'ALU lui demande de copier ces opérandes dans les registres opérandes et de démarrer l'instruction. L'opcode de l'instruction est déjà mémorisé dans le registre d'opcode, ou alors il est envoyé à ce moment. Puis les bits READ FLAG de l'entrée associée à l'ALU sont remis à zéro. ===Le calcul du masque READ PENDING=== Plus haut, nous avions vu le masque READ PENDING qui interdit d'écrire un résultat dans un registre si les conditions ne sont pas réunies, en cas de dépendance WAR. Le nom du signal indique comment sont détectées les dépendances WAR : l'écriture est interdite si une lecture de ce registre est en attente. Le CDC 6600 lit les deux opérandes d'une instruction en même temps, ce qui fait qu'une opérande peut être disponible mais pas encore lue. Une opérande dans ce cas a un READ FLAG à 1 pour le registre associé. Chaque bit du signal READ PENDING se détermine donc en faisant un ET logique entre tous les bits READ FLAG associé à un registre, encore faut-il les sélectionner en fonction du registre voulu et de l'unité de calcul associée au registre. La méthode permet de gérer les dépendances WAR, mais pas les dépendances WAW. Le CDC 6600 bloquait l'instruction dans l'étage d'émission en cas de dépendance WAW. Si l'instruction à émettre avait pour registre de destination un registre de destination d'une instruction dans le pipeline, le processeur émettrait des bulles de pipeline tant que la première écriture n'a pas eu lieu. Son successeur, le CDC 7600 n'avait pas ce défaut et était capable de passer outre toutes les dépendances de données WAR et WAW. Une raison probable à cela est que le CDC 6600 a été terminé en cataastrophe et que ses concepteurs n'ont pas eu le temps d'implémenter une technique complexe de gestion des dépendances WAW. Mais ils ont eu le temps de terminer le design du ''scoreboard'' pour le successeur 7600. Une autre raison est que le pipeline étant court, les dépendances WAW avaient un effet très limité et que bloquer l'émission n'entrainait pas une baisse de performance notable. Mais on peut en théorie faire autrement. Le principe est que les instructions sont émises en absence de dépendances RAW, mais que l'écriture de leur résultat peut être retardée à l'étage d'écriture dans les registres. En cas de dépendances WAR ou WAW, le résultat à écrire est maintenu sur la sortie d'une unité de calcul, dans un registre tampon placé sur cette même sortie, comme illustré plus bas. Les instructions sont donc bloquées dans l'unité de calcul, qui n'est plus disponible pour d'autres instructions. Le ''scoreboard'' sait qu'il ne peut plus envoyer d'instruction sur cette unité de calcul. À chaque cycle, l'étage d'enregistrement choisit le résultat à enregistrer dans les registres, en respectant les dépendances de données. C'est le ''scoreboard'' qui autorise ou non cette écriture, en commandant l'étage d'enregistrement en fin de pipeline. En clair : l'enchainement des signaux GOWRITE impose un enregistrement des résultats qui suit l'ordre du programme. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les implémentations modernes de l'OOO | prevText=Les implémentations modernes de l'OOO | nextLa désambiguïsation mémoire | nextText=La désambiguïsation mémoire }} </noinclude> 3tl3g01i4yi1m3gteml3wzn5veqxa7o 773671 773670 2026-09-29T22:34:03Z Mewtow 31375 /* L'algorithme de Tomasulo et les stations de réservation */ 773671 wikitext text/x-wiki Dans ce chapitre, nous allons voir deux techniques d'exécution dans le désordre un peu à part. Il s'agit de deux techniques historiquesn utilisées sur des ordinateurs très anciens, qui portent les noms de ''scoreboarding'' et d'algorithme de Tomasulo. Les deux ne sont plus utilisés aujourd'hui, pour diverses raisons, la principale étant qu'elles ne gèrent pas les exceptions précises. En clair, impossible de les utiliser en même temps que la prédiction de branchement ou d'autres optimisations. Elles ne gèrent pas les exceptions précises, car elles utilisent des formes de renommage de registre assez originale. L'algorithme de Tomasulo renomme les registres dans les stations de réservation, chose qu'on n'a volontairement pas abordé dans le chapitre sur le renommage de registre. le ''scoreboarding'' utilise quant à lui une technique similaire, mais bien plus difficile à classer, qui est clairement idiosyncratique. Il est possible de les modifier pour leur adjoindre un ROB, mais le résultat ressemble beaucoup aux techniques de renommage dans le ROB. ==L'algorithme de Tomasulo et les stations de réservation== L''''algorithme de Tomasulo''' est un algorithme assez compliqué à expliquer, car il mélange exécution dans le désordre, contournement et renommage de registre implicite en un seul algorithme. L'algorithme de Tosmasulo a été implémenté une première fois sur les ordinateurs IBM 360/91, et quelques processeurs ont utilisé une variante de celui-ci. Beaucoup de processeurs modernes se sont sont inspiré de cet algorithme pour leur design. Il est antérieur au ''scoreboarding'' du CDC 6600, qui avait des fonctionnalités similaires, mais nous allons le voir avant, afin de mieux faire ressortir les ressemblances entre les deux algorithmes. L'algorithme de Tosmasulo a été utilisé tel quel sur la FPU de l'IBM 360 modèle 90, et uniquement celle-ci. Les ALU entière étaient séparées de la FPU et n'étaient pas concerné par tout ce qui va suivre Le processeur n'utilisait l'exécution dans le désordre que pour sa FPU, pas le "pipeline" entier/mémoire. La FPU en question avait un additionneur flottant, un multiplieur flottant, et une unité mémoire pour les lectures/écritures flottantes. Les trois unités avaient leur propre ''scheduler''. [[File:Tomasulo Architecture.png|centre|vignette|upright=2.5|Algorithme de Tomasulo originel, de la FPU de l'IBM 360.]] Avec l'algorithme de Tomasulo, le renommage de registre se fait dans des '''stations de réservation'''. Pour rappel, ce sont des ''schedulers'' qui ont pour particularité de mémoriser non seulement les µops en attente, mais aussi leurs opérandes. Les opérandes peuvent provenir de deux sources différentes. Soit elles sont lues depuis les registres avant l'émission, soit elles sont obtenues par le réseau de contournement. Dans son acceptation la plus stricte, le terme station de réservation est réservé au cas où il y a une station de réservation par unité de calcul. Et c'est le cas avec l'algorithme de Tomasulo initial, qui a été utilisé pour la première fois sur un processeur avec trois stations de réservation : une pour le circuit multiplieur/diviseur flottant, une pour l'additionneur flottant, et une pour l'unité LOAD/STORE. Un autre point très important est que, dans le papier de Tomasulo, les stations de réservation ne conservent que les µops en attente d'émission. L'algorithme original n'avait pas de ROB et ne gérait pas du tout les exceptions précises. Il ne peut donc pas être utilisé sur les architectures modernes, qui utilisent de la prédiction de branchement. Il est possible d'ajouter un ROB à l'algorithme, mais il doit être modifié et on retombe alors sur une forme de renommage dans le ROB. ===Les stations de réservation et le contournement=== Les stations de réservation mémorisent les µops en attente d'exécution sur l'unité de calcul, tant qu'elles n'ont pas encore leurs opérandes prêtes. Par modifiées pour faciliter le contournement, je veux dire par là qu'elles mémorisent les opérandes d'une µop à exécuter. Si les opérandes sont dans les registres, elles sont lues depuis les registres avant ''issue/dispatch'', et mémorisées dans la station de réservation. Si elles ne sont pas encore disponibles au moment de l'''issue'', elles seront fournies plus tard par le système de contournement et seront alors enregistrées dans la station de réservation. Le fait que le ''scheduler'' incorpore les opérandes de la µop implique une forme de renommage de registres implicite, comme on le verra plus tard. Pour rappel, il s'agit d'une technique dite de '''lecture avant émission''', qui lit les registres d'une µop avant de l'émettre. Pour gérer le contournement, les résultats d'une µop sont non seulement envoyés vers le ROB et/ou les registres, mais ils sont aussi envoyés vers les stations de réservation, via un bus de contournement. La sortie de chaque unité de calcul est connectée à toutes les stations de réservation, dans le cas idéal. Pour cela, la sortie des unités de calcul est reliée aux stations de réservation via un bus, appelé le ''bus commun d’ordonnancement de la mémoire'' (''common memory-ordering bus''), que nous nommerons dorénavant ''bus de contournement''. [[File:Algorithme de Tomasulo.png|centre|vignette|upright=2|Algorithme de Tomasulo]] L'idée derrière le '''bus de contournement''' est que les sorties des unités de calcul sont reliées à un bus, qui est lui connecté aux entrées des ALU. La contrainte est qu'une seule unité de calcul peut envoyer des données sur ce bus. Rien d'étonnant : c'est un bus, il ne peut transférer qu'une donnée à la fois. Si plusieurs unités de calcul veulent transmettre leurs résultats sur ce bus, l'une d'entre elle est choisie et les autres doivent mettre en attente leurs résultats dans une mémoire tampon, soit un registre, soit une FIFO. Dans les deux cas, le registre ou la FIFO sont appelés des ''producers''. L'implémentation demande de bloquer des opérations dans l'ALU si le contournement doit être mis en attente, ce qui bloque tout le pipeline en cas de problème. [[File:Producteurs en sortie d'une ALU.jpg|centre|vignette|upright=2|Producteurs en sortie d'une ALU.]] Le bus de contournement est assez spécifique à l'algorithme de Tomasulo, dans le sens où c'est un des rares articles académique à utiliser un tel bus de contournement. ===Le renommage de registres dans les stations de réservation=== L'unité d'émission attribue à chaque résultat de calcul un '''identifiant de résultat'''. L'identifiant est une sorte de numéro de registre virtuel, qui est transmis sur le bus de contournement. L'identifiant est propagé comme tout signal de commande, il suit la µop sur son trajet dans le pipeline. Quand l'unité de calcul a fini son calcul, l'identifiant est envoyé avec le résultat sur le bus de contournement. Les stations de réservation contenant cet identifiant de résultat enregistrent alors le résultat dans le champ adéquat. De plus, le ROB a des entrées modifiées pour contenir l'identifiant de résultat, afin d'associer un identifiant de résultat à un registre de destination. Les entrées des stations de réservation sont structurées en plusieurs champs. Le premier mémorise l'opcode de l'instruction/µop. Il y a aussi un champ pour l'identifiant de résultat. Il y a aussi deux champs, un par opérande. Il peut contenir deux choses : l'opérande elle-même, l'identifiant de résultat associé. Pour faire la différence, les deux champs ont chacun un bit de présence, qui indique si l'opérande est présente dans le champ ou non (auquel cas, c'est un identifiant). [[File:Entrée d'une station de réservation.png|centre|vignette|upright=3|Entrée d'une station de réservation.]] Vous vous demandez certainement où sont les registres virtuels avec cette organisation. Et bien il ne s'agit ni plus ni moins que des stations de réservation. Et plus précisément les champs pour les opérandes. L'identifiant de résultat est l'équivalent d'un nom de registre virtuel. D'ailleurs, une fois la µop émise, il n'y a pas de noms de registre physique dans les stations de réservation, seulement des identifiants de résultat. En somme, le renommage de registre est pris en charge par les stations de réservation, et par le système de contournement. ===L'exécution d'une µop avec l'algorithme de Tomasulo=== L'exécution d'une µop avec des stations de réservation se fait en plusieurs étapes. Premièrement, la µop est émise, dans le sens où elle est transmise de l'unité d'émission aux stations de réservation. Deuxièmement, la µop est exécutée ou attend son exécution. Enfin, son résultat est enregistré dans les registres et envoyé aux stations de réservation pour contournement. L'émission se fait sous condition qu'une station de réservation pour l'unité de calcul voulue soit disponible. Si c'est le cas, l'unité d'émission vérifie si les opérandes sont disponibles dans le banc de registre architecturaux. Les opérandes disponibles sont alors traitées différemment des opérandes non-disponibles. Les opérandes non-disponibles, elles seront envoyées via contournement plus tard et le renommage de registre doit être utilisé. L'opérande est associée à l'identifiant de résultat qui permet de savoir quand elle sera calculée. À l'opposé, les opérandes disponibles sont lues depuis les registres et enregistrées dans la station de réservation, leur bit de présence est mis à 1. Il n'y a pas de renommage de registres, car il n'y en a pas besoin pour ces opérandes. Reprenons maintenant après l'émission de la µop, qui a été envoyée dans les stations de réservation. Elle attend alors que ses opérandes soient disponibles dans la station de réservation. Les opérandes non-disponibles sont alors calculées par des µops et sont envoyées sur le bus de contournement. La station de réservation reconnait alors l'identifiant et enregistre le résultat dans le champ adéquat. Une fois toutes les opérandes disponibles, la µop est exécutée. Une fois son résultat connu, il est envoyé sur le bus de contournement, mais aussi dans le banc de registres. Et le tout continue. ==Le ''scoreboarding'' du CDC 6600== L'implémentation du ''scoreboard'' sur le CDC 6600/7600 est appelée dans la suite du cours : le '''''scoreboarding'''''. La description que je vais donner du ''scoreboard'' est très différente de celle disponible dans les livres d'architecture des ordinateurs. La plupart des manuels, surtout les textbooks américains, donnent une description très haut niveau, très algorithmique du ''scoreboarding'', qui ne sera pas abordée. À la place, je vais donner une description alternative, différente autant sur l'approche que le fond. Le CDC 6600 n'existe plus, tous les exemplaires ont depuis longtemps été démontés, aussi il ne reste que des sources historiques pour savoir comment fonctionnait son ''scoreboard''. Heureusement, il existe un livre qui décrit dans les moindres détails cette architecture, écrit par un des concepteurs de l'ordinateur : [https://archive.computerhistory.org/resources/text/CDC/cdc.6600.thornton.design_of_a_computer_the_control_data_6600.1970.102630394.pdf Design of a computer : the CDC 6600]. Ce qui va suivre est majoritairement ité de cette source. ===Le chemin de données du CDC 6600 et sa relation avec le ''scoreboard''=== Le pipeline d'un processeur avec ''scoreboarding'' ressemble à celui du schéma suivant. Pour résumer, le chemin de donnée forme un pipeline à trois étages : lecture des registres, exécution dans l'ALU, écriture dans les registres. Les opérations à effectuer son envoyées aux ALUs, et elles attendent leurs opérandes dedans. [[File:Scoreboard avec exceptions imprécises.png|centre|vignette|upright=2|Scoreboard avec exceptions imprécises]] La séparation en trois étages fait qu'il y a des registres entre chaque étages. Les opérandes sont chargées dans des registres en amont de l'ALU, et le résultat est enregistré temporairement dans un registre en sortie de l'ALU. Nous les appellerons : '''registres opérandes''' et '''registre résultat'''. Entre les deux, l'ALU effectue une opération quand les opérandes sont disponibles dans les registres opérandes, et maintien le résultat dans le registre résultat si besoin. Il y a aussi un autre registre qui mémorise l'opcode de l'opération, lors de l'attente des opérandes, mais aussi lors de l'exécution. Nous l'omettrons dans ce qui suit, car il s'agit d'un registre de pipeline classique. Les registres opérande et résultat n'ont pas besoin d'être très complexes vu qu'ils servent juste à maintenir une donnée. Les registres ne sont pas connectés à l'horloge, les bascules ne sont pas synchrones, ils sont fabriqués à partir de simples ''latches'', de simples bascules D non-synchrones. Et il en est de même pour le registre d'opcode. Le ''scoreboard'' commande le signal Enable qui autorise les écritures dedans, rien de plus. Le pipeline est donc le suivant : [[File:Pipeline d'un processeur utilisant le scoreboarding.png|centre|vignette|upright=2|Pipeline d'un processeur utilisant le scoreboarding]] Les registres opérandes sont chacun associé à un bit READ FLAG qui précise si l'opérande du calcul est disponible. Les bits READ FLAG sont mis à jour par un mécanisme assez complexe, qui sera vu dans la suite. Le ''scoreboard'' gère les transferts entre les registres opérande/résultat et le reste du processeur. Il génère deux signaux de 1 bit nommés GO READ et GO STORE/GO WRITE. Le signal GO READ déclenche la copie d'un registre architectural dans un registre opérande. Le signal GO WRITE déclenche la copie du registre résultat dans le registre architectural adéquat. Pour effectuer une lecture ou une écriture, les noms des registres adéquats sont mémorisés dans deux registres notés Fi, Fj, et Fk. Fi mémorise le registre de destination de l'opération, Fj et Fk mémorisent les noms/numéros des registres opérandes. Les deux registres Qj et Qk sont utilisés pour la détection des opérandes disponibles, nous en reparlerons plus tard. Les registres Fi, FJ et Fk sont dans le ''scoreboard'', et ils sont envoyés sur les entrées d'adresse du banc de registre suivant les besoins, suivant qu'on fasse une lecture ou une écriture. La lecture et écriture des registres donc totalement le fait du ''scoreboard'', qui commande le banc de registres, comme le ferait un séquenceur normal. [[File:CDC 6600 datapath control.png|centre|vignette|upright=2|CDC 6600 datapath control]] Notez que les registres opérandes, couplés au registre d'opcode, peuvent être vus comme une station de réservation simplifiée, sans gestion du contournement. La différence principale avec l'algorithme de Tomasulo est que les champs pour les identifiants de résultat ont disparus, et que les bits de disponibilité des opérandes READ FLAG sont en réalité intégré au ''scoreboard'', comme on le verra plus tard, avec une gestion de la disponibilité des opérandes totalement différente. De plus, il n'y a qu'une seule station de réservation par ALU, donc un risque plus grand de dépendances structurelles. On ne peut mettre en attente qu'une seule µop par ALU, avec le ''scoreboard''. ===Les désignateurs utilisés par le ''scoreboard''=== Les registres opérandes et résultat ne sont pas des registres architecturaux, mais ce ne sont pas des registres de pipeline non plus. Il est possible de faire l'analogie avec une station de réservation, mais l'analogie est limitée pour une raison simple : le ''scoreboard'' attend que les deux opérandes sont disponibles pour déclencher la lecture avec le signal GO READ. En théorie, il est tout à fait possible de lire un registre opérande à la fois, dès que l'opérande est disponible, mais le ''scoreboard'' ne faisait pas comme ça. De plus, les opérandes ne sont pas vraiment transmises via un réseau de contournement depuis la sortie de l'ALU. Cependant, une rumeur veut que le processeur implémente un système de contournement, qui passe...par l'intermédiaire des registres. Paradoxal, mais qui s'explique pourtant très bien quand on connait le fonctionnement des registres utilisés. Le processeur utilisait une ancienne technologie de transistors, appelée ECL. Beaucoup de bancs de registres fabriqués avec cette technologie avaient une propriété intéressante : toute donnée écrite sur le port d'écriture était immédiatement disponible sur le port de lecture. Plus précisément, l'écriture se faisait sur front montant et la lecture sur front descendant. En faisant cela, une opérande pouvait être écrite dans les registres architecturaux, mais pourtant copiée dans les registres opérandes au même cycle. Le tout fonctionne presque comme un système de contournement, avec cependant quelques limitations ! Avec un vrai système de contournement, l'implémentation est beaucoup plus puissante. Quant à savoir si les registres opérandes sont nommés, c'est un peu compliqué et la réponse serait qu'ils sont nommés de manière implicite. Il est d'ailleurs débattable de savoir si le CDC 6600/7600 implémente le renommage de registres... Le point de discorde est lié au fait que le ''scoreboard'' attribue un numéro à chaque unité de calcul, appelé le '''désignateur Q'''. Et ces identifiants sont utilisés pour la lecture des opérandes et leur copie dans les registres, ils se comportent comme un nom de registre virtuel. Pour simplifier les explications, nous allons partir du principe que les désignateurs sont encodés en représentation unaire. Pour rappel, la représentation unaire représente un nombre sur plusieurs bits, dont un seul est à 1. Un zéro est codé en mettant tous les bits du nombre à zéro, la valeur 1 est encodée avec la valeur 000...0001, le deux avec 000...0010, etc. {|class="wikitable" |+ Désignateur d'ALU |- ! ALU ADD !! ALU MUL !! ALU DIV !! ALU SUB !! ALU CMP !! ALU MOV |- | 0 || 0 || 1 || 0 || 0 || 0 |} La réalité est que les désignateurs sont présents à plusieurs endroits et sont soit codés en unaires, soit codés en binaire, avec des traductions fréquentes entre les deux. Ils sont par exemple traduits du binaire vers l'unaire lors de la génération des signaux READ FLAG. Les traductions inverses sont aussi fréquentes. Les traductions se basent sur des décodeurs/encodeurs un peu modifiés. L'avantage de la représentation unaire est que les comparaisons sont légèrement plus simples, les comparateurs économisent quelques portes logiques. De plus, elle s'adapte assez bien avec le fait que chaque unité de calcul précise si elle est disponible ou non, ce qui deviendra plus clair dans la suite. ===Les réservations et la table de réservation=== Le ''scoreboard'' du CDC 6600 contient une table de '''réservation''', qui permet de réserver une unité de calcul pour une µop à émettre. La table de réservation est composée d'entrées, une par unité de calcul, qui peut mémoriser une µop. Une entrée mémorise pour chaque unité de calcul : * l'opcode de l'instruction à exécuter dessus ; * les noms/numéros des registres opérandes et destination ; * les désignateurs Q des unités de calcul qui fourniront les opérandes en résultat ; * deux bits READ FLAG qui disent si l'opérande associé est disponible. : Dans le livre utilisé comme source, il n'est pas clair si les noms des registres opérandes/résultat sont placés dans l'unité de calcul ou dans le ''scoreboard''. Les explications semblent indiquer que c'est juste à côté de l'ALU, mais les schémas se contredisent là-dessus. Dans la suite, je pars du principe qu'ils sont dans le ''scoreboard'', ce qui aurait bien plus de sens. Le ''scoreboard'' consulte la table de réservation pour émettre une µop. Avant d’émettre une µop, elle regarde si l'entrée est libre ou déjà occupée par une µop. Pour cela, chaque entrée est associée à un bit BUSY qui indique si l'entrée est vide ou occupée. Vu qu'il y a une entrée par unité de calcul, attribuer une entrée à une µop est asszz simple : chaque µop va dans une entrée bien précise, il suffit de vérifier celle-ci. Le bit BUSY est mis à 1 quand une µop est émise, ajoutée dans l'entrée, mis à zéro quand elle est terminée. La libération d'une entrée se fait quand le signal GO WRITE est émis, le signal RELEASE ne suffit pas. La réservation permet de réserver une ALU pour une opération. La µop est alors envoyée à l'ALU, où elle attend que ses opérandes soient disponibles. Une µop attend son tour et n'est émise qu'une fois que les deux bits READ FLAGS sont à 1. La conséquence est qu'une µop reste dans l'unité de calcul tant qu'elle a des dépendances RAW. Et seules les dépendances RAW, où une instruction pour opérande le résultat d'une instruction précédente, impliquent un blocage du pipeline et des bulles de pipeline. Les dépendances WAW ou WAR sont traitées autrement. La table de réservation ne stocke pas les opérandes, ce qui fait qu'on peut la voir comme un ''scheduler'' à une entrée, ou encore comme une station de réservation castrée. Un détail très important est que ce système de réservation met en attente une µop par ALU. Vu que toutes les ALUs du CDC 6600 sont très différentes, l'attribution d'une µop à une ALU est trivial. Par contre, si une µop veut utiliser une ALU réservée, elle ne peut pas et il faut bloquer le pipeline. Le système de réservation est donc une cause de dépendances structurelles qui bloquent l'émission des µops dans de nombreux cas. Ce ne serait pas le cas si on pouvait placer plusieurs réservations par unité de calcul, mais passons. Pour une dépendance WAR, la µop est émise, elle s'exécute, mais son résultat est maintenu dans le registre résultat le temps que ces dépendances soient résolues. Pour le dire autrement, Les dépendances WAR font que les µops sont retenues dans l'étage d'enregistrement des données, un peu comme sur un processeur à pipeline multicycle (de longueur fixe). Sauf que les pipeline multicycle, il y aurait plusieurs registres d'échelonnements qui se suivent, alors qu'on n'en a qu'un ici, ce qui fait que l'unité de calcul est bloquée si l'écriture est retardée. En théorie, les dépendances WAW devraient être traitées avec un mécanisme similaire, mais le processeur détectait ces dépendances à l'émission et bloquait l'émission si un registre lu était accédé en lecture. [[File:Enregistrement des données dans les registres avec un pipeline avec scoreboarding.png|centre|vignette|upright=2|Enregistrement des données dans les registres avec un pipeline avec scoreboarding]] ===La Q-table : l'unité de renommage de registres=== Quand une µop est émise, elle réserve une unité de calcul. Mais il faut pour cela remplir les champs pour les désignateurs d'ALU, même si on voit mal à quoi ils servent pour le moment. Il se trouve que les registres opérandes contiennent une valeur, qui est le résultat d'une µop soit déjà passée par une ALU, soit en cours d'exécution dans une ALU. Le désignateur pour un opérande est donc le désignateur de cette ALU. Reste à faire la correspondance entre un résultat/registre et l'ALU qui va le calculer ou l'a déjà calculé. Pour cela, le ''scoreboard'' mémorise la correspondance entre un registre/résultat et une unité de calcul dans une mémoire cache appelée la '''''Q-table'''''. Pour comprendre à quoi elle sert, prenons deux instructions consécutives, dont la seconde utilise le résultat de la première. La première instruction est lancée dans une unité de calcul enregistre son résultat dans un registre de destination. Le ''scoreboard'' mémorise alors dans la ''Q-table'' que le registre de destination est associé à telle unité de calcul, elle mémorise une correspondance entre le désignateur de l'ALU et le registre de destination. Par la suite, la seconde instruction est émise. Le ''scoreboard'' interroge la ''Q-table'' pour les deux opérandes de l'instruction, pour récupérer les deux désignateurs de l'ALU associés. Ils sont envoyés au banc de registres pour gérer la lecture des opérandes. Pour résumer, le ''scoreboard'' effectue les actions suivantes lors de l'émission. * Premièrement, il détermine si l'unité de calcul est disponible ou non, en utilisant le bit de disponibilité BUSY. * Deuxièmement, il mémorise les numéros de registres opérande et résultat pour commander la lecture des opérandes. * Troisièmement, il traduit les numéros de registres opérande en identifiants d'ALU. * Quatrièmement, il mémorise dans une ''Q-table'' la relation entre le registre de destination et l'unité de calcul choisie à l'étape 1. La troisième étape permet de faire le lien entre un résultat calculé mais pas encore enregistré dans les registres, et un registre opérande non-nommé. Le lien guide le chargement des opérandes et donc le système de contournement passant par des registres (ce qui est du renommage de registre implicite). ===La gestion des résultats : les signaux RELEASE et GOWRITE=== Une fois la µop exécutée, son résultat est enregistré dans le registre résultat. Une fois le résultat dans le registre résultat, l'unité de calcul envoie un signal REQUEST au ''scoreboard'' pour savoir si la donnée peut être enregistrée dans les registres architecturaux. L'ensemble des signaux REQUEST est regroupé dans un vecteur de bit, une sorte de nombre, dont chaque bit indique quelle unité veut écrire un résultat. L'ensemble des signaux RELEASE forment un nombre encodé en unaire qui indique quelle ALU a fournit le résultat. Là, le ''scoreboard'' effectue plusieurs opérations successives sur ce nombre, en appliquant plusieurs masques. Le premier masque appliqué vérifie pour chaque ALU si elle a le droit d'écrire son résultat en mémoire, sur la base des dépendances WAW et WAR. En cas de dépendances WAR ou WAW, l'écriture du résultat est retardé, ce qui fait que l'unité de calcul n'est pas considérée, son signal RELEASE est ignoré, il est masqué. Le masque qui permet cela est appelé le '''masque READ PENDING'''. Le second masque est un circuit de priorité qui sélectionne un bit seulement. Il est en effet possible que plusieurs unités de calcul fournissent un résultat en même temps. Ou encore que l'une ait son écriture retardée et ait un signal RELEASE à 1 depuis plusieurs cycles. Toujours est-il qu'on ne peut écrire qu'un résultat à la fois, ce qui fait qu'il faut sélectionner une unité de calcul. Pour cela, un circuit de priorité sélectionne un seul signal RELEASE à 1 et met les autres à zéro. C'est le second masque. {|class="wikitable" |+ Traitement des signaux REQUEST |- ! colspan="10 | Signaux REQUEST en sortie des ALUs |- | 0 || 1 || 0 || 1 || 1 || 1 || 0 || 0 || 0 || 0 |- ! colspan="10 | Application du masque READ PENDING pour les dépendances WAW/WAR |- | 0 || 0 || 0 || 1 || 1 || 0 || 0 || 0 || 0 || 0 |- ! colspan="10 | Sélection par un circuit de priorité |- | 0 || 0 || 0 || 1 || 0 || 0 || 0 || 0 || 0 || 0 |} Après l'application du second masque, il ne reste qu'un seul bit à un, qui indique quelle ALU a été sélectionnée pour l'écriture. Il se trouve que l'ensemble des bits forme un désignateur d'ALU, encodé en représentation unaire, en représentation ''one-hot''. Pour rappel, cela veut dire que seul un bit dans le nombre est à 1 et ce bit indique la valeur encodée. Si le bit numéro X est à 1, alors la valeur encodée vaut X. L'usage d'une représentation unaire/''one-hot'' fait que l'on a juste à concaténer les signaux REQUEST et appliquer des masques pour obtenir le désignateur adéquat, pas besoin d'encodeur compliqués, ni de circuits de sélection complexes. Le désignateur résultat est appelé '''désignateur d'ALU choisie'''. Une fois ce désignateur calculé, le ''désignateur d'ALU choisie'' est envoyé à la table de réservation, afin de récupérer le nom/numéro du registre résultat associé. Le ''scoreboard'' commande le port d'écriture du banc de registre, avec un signal GOWRITE et le nom/numéro du registre de destination récupéré. Le signal RELEASE est alors remis à zéro. Reste à générer le signal GO WRITE et faire les actions adéquates. Mais il reste deux opérations de maintenance pour terminer l'écriture. La première est de remettre en ordre la Q-table. L'entrée qui liait l'unité de calcul au registre de destination doit être remise à zéro. Le résultat ayant été écrit, il n'est plus associé à l'unité de calcul, le lien entre les deux dans la Q-table est donc effacé. La seconde est de gérer la disponibilité des opérandes. Pour cela, le résultat après application des deux masques est aussi utilisé pour détecter la disponibilité des opérandes, pour mettre à 1 le bit READ FLAG adéquat. Là encore, c'est la table de réservation qui s'en charge. ===La détection des opérandes disponibles : la génération des READ FLAG et du signal GOREAD=== Le désignateur d'ALU choise est envoyé à la table de réservation pour récupérer le nom de registre destination, mais aussi aux champs opérandes. Dans chaque entrée, il comparé aux deux désignateurs Qj et Qk, associés chacun à une opérande. Pour rappel, les désignateurs Qj et Qk sont des désignateurs d'unité de calcul, eux aussi encodés en unaire. S'il y a ''match'', alors l'opérande est disponible. Le comparateur génère un signal qui met à 1 le bit de disponibilité READ FLAG (i pour le numéro de l'unité de calcul), le bit est dans une bascule pour ne pas être effacé au cycle suivant. Le ''scoreboard'' contient donc une matrice de comparaison, qui compare le résultat de l'étape précédente avec tous les désignateurs associés à une opérande. L'avantage d'encoder les désignateurs en unaire fait que la comparaison est plus simple : elle se constitue uniquement de portes ET, pas besoin de portes XOR comme on en aurait eu besoin en utilisant des désignateurs en binaire. De plus, le calcul du désignateur à partir des signaux REQUEST est trivial, pas besoin de passer par un encodeur. [[File:Détection des dépendances CDC 6600.png|centre|vignette|upright=2|Détection des dépendances RAW CDC 6600]] Quand les deux bits READ FLAG d'une instruction sont à 1, le ''scoreboard'' envoie un signal GOREAD à la mémoire et aux unités de calcul. Les numéros/noms de registre, présents dans les registres Fj et Fk, sont envoyés au banc de registre. Le signal envoyé à l'ALU lui demande de copier ces opérandes dans les registres opérandes et de démarrer l'instruction. L'opcode de l'instruction est déjà mémorisé dans le registre d'opcode, ou alors il est envoyé à ce moment. Puis les bits READ FLAG de l'entrée associée à l'ALU sont remis à zéro. ===Le calcul du masque READ PENDING=== Plus haut, nous avions vu le masque READ PENDING qui interdit d'écrire un résultat dans un registre si les conditions ne sont pas réunies, en cas de dépendance WAR. Le nom du signal indique comment sont détectées les dépendances WAR : l'écriture est interdite si une lecture de ce registre est en attente. Le CDC 6600 lit les deux opérandes d'une instruction en même temps, ce qui fait qu'une opérande peut être disponible mais pas encore lue. Une opérande dans ce cas a un READ FLAG à 1 pour le registre associé. Chaque bit du signal READ PENDING se détermine donc en faisant un ET logique entre tous les bits READ FLAG associé à un registre, encore faut-il les sélectionner en fonction du registre voulu et de l'unité de calcul associée au registre. La méthode permet de gérer les dépendances WAR, mais pas les dépendances WAW. Le CDC 6600 bloquait l'instruction dans l'étage d'émission en cas de dépendance WAW. Si l'instruction à émettre avait pour registre de destination un registre de destination d'une instruction dans le pipeline, le processeur émettrait des bulles de pipeline tant que la première écriture n'a pas eu lieu. Son successeur, le CDC 7600 n'avait pas ce défaut et était capable de passer outre toutes les dépendances de données WAR et WAW. Une raison probable à cela est que le CDC 6600 a été terminé en cataastrophe et que ses concepteurs n'ont pas eu le temps d'implémenter une technique complexe de gestion des dépendances WAW. Mais ils ont eu le temps de terminer le design du ''scoreboard'' pour le successeur 7600. Une autre raison est que le pipeline étant court, les dépendances WAW avaient un effet très limité et que bloquer l'émission n'entrainait pas une baisse de performance notable. Mais on peut en théorie faire autrement. Le principe est que les instructions sont émises en absence de dépendances RAW, mais que l'écriture de leur résultat peut être retardée à l'étage d'écriture dans les registres. En cas de dépendances WAR ou WAW, le résultat à écrire est maintenu sur la sortie d'une unité de calcul, dans un registre tampon placé sur cette même sortie, comme illustré plus bas. Les instructions sont donc bloquées dans l'unité de calcul, qui n'est plus disponible pour d'autres instructions. Le ''scoreboard'' sait qu'il ne peut plus envoyer d'instruction sur cette unité de calcul. À chaque cycle, l'étage d'enregistrement choisit le résultat à enregistrer dans les registres, en respectant les dépendances de données. C'est le ''scoreboard'' qui autorise ou non cette écriture, en commandant l'étage d'enregistrement en fin de pipeline. En clair : l'enchainement des signaux GOWRITE impose un enregistrement des résultats qui suit l'ordre du programme. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les implémentations modernes de l'OOO | prevText=Les implémentations modernes de l'OOO | nextLa désambiguïsation mémoire | nextText=La désambiguïsation mémoire }} </noinclude> r6vcgc5a8e5x5iwcgnda6qhc6w87ilt Fonctionnement d'un ordinateur/Les processeurs superscalaires in-order 0 65956 773576 773541 2026-09-29T16:04:19Z Mewtow 31375 /* Les CPU superscalaire à exécution dans le désordre */ 773576 wikitext text/x-wiki Les processeurs vus auparavant ne peuvent émettre au maximum qu'une instruction par cycle d'horloge. Ils peuvent avoir plusieurs instructions qui s'exécutent en même temps, dans des unités de calcul séparées. C'est le cas dès qu'une instruction multi-cycles s'exécute. Par contre, ils ne peuvent démarrer qu'une seule instruction par cycle. Et quand on court après la performance, ce n'est pas assez ! Les concepteurs de processeurs ont inventés des processeurs qui émettent plusieurs instructions par cycle : les '''processeurs à émissions multiples'''. Un processeur à émission multiple charge plusieurs instructions en même temps, les décode en parallèle, puis les émet en même temps sur des unités de calculs séparées. Pour cela, il faut gérer les dépendances entre instructions, répartir les instructions sur différentes unités de calcul, et cela n'est pas une mince affaire. En général, pour un processeur à émission multiple capable d'émettre N instructions en parallèle, on parle de '''processeur à N voies''', ou encore un ''processeur à N pipelines''. [[File:Superscalarpipeline.svg|centre|vignette|upright=1.5|Pipeline RISC classique à cinq étages sur un processeur superscalaire. On voit bien que plusieurs instructions sont chargées en même temps.]] Les processeurs à émission multiple sont de deux types : les processeurs VLIW et les '''processeurs superscalaires'''. Nous mettons les processeurs VLIW de côté en attendant le prochain chapitre. La raison est qu'ils ont un jeu d'instruction spécialisé qui expose le parallélisme d'instruction directement au niveau du jeu d'instructions, là où les processeurs superscalaires restent des processeurs au jeu d'instruction normal. La différence principale entre processeur VLIW et superscalaire est qu'un processeur superscalaire répartit les instructions sur les unités de calcul à l’exécution, là où un processeur VLIW délègue cette tâche au compilateur. ==Le nombre de voies d'un processeur superscalaire== Les processeurs superscalaires les plus simples ne permettent que d'émettre deux micro-opérations à la fois, d'où leur nom de processeur ''dual issue'', ce qui se traduit en '''processeur à double émission'''. Les processeurs triple émission permettent eux d’émettre trois instructions à la fois. A l'opposé, les CPU superscalaires les plus puissants peuvent émettre jusqu'à 8-10 instructions simultanément. En 2026, les CPU superscalaires peuvent monter jusqu’à 10 µops émises en même temps, ce qui est énorme ! Et cela nous amène à faire une distinction entre les processeurs superscalaires dits '''étroits''' et ceux dits '''larges'''. Dans ce wikilivre, on part du principe que les processeurs superscalaires étroits émettent jusqu'à 4-5 µops à la fois, alors que les larges peuvent en émettre plus, l'intervalle entre les deux est une zone grise. Le nombre exact n'est pas fixé dans le marbre, la distinction est volontairement vague. Nous parlerons de la '''largeur d'un CPU superscalaire''' pour parler du nombre de voies, du nombre de µops émises en même temps. Plus un CPU superscalaire est large, plus il est performant ''toute chose égale par ailleurs''. Mais dans les faits, vous pouvez oublier la partie en italique. Élargir un CPU superscalaire demande de rajouter beaucoup de circuits. Et ce cout en circuit aura un impact sur la performance. A budget en transistors limité, il y a un compromis entre élargir un CPU et rajouter du cache ou la taille des fenêtres d'instructions/ROB et autres. ===Les contraintes d’appariement=== Prenons un processeur double émission, capable d'émettre deux instructions simultanément. Émettre deux instructions en même temps n'est pas toujours possible. Par exemple, si deux instructions sont dépendantes, on ne peut pas les émettre en même temps. Mais oublions un instant ces histoires de dépendances de données, et partons du principe que le CPU ait affaire à deux instructions indépendantes, une paire idéale. Un CPU double émission "parfait" pourrait exécuter n'importe quelle paire d'instruction. Par exemple, il pourrait émettre deux multiplications consécutives, deux lectures consécutives, une lecture et une écriture en même temps, etc. En pratique, aucun processeur ne permet cela. Implémenter un CPU superscalaire "parfait" aurait un cout en circuit beaucoup trop conséquent. Par exemple, pour émettre deux multiplications en même temps, il faudrait deux multiplieurs séparés. Idem pour exécuter deux accès mémoire simultané : cela demande d'avoir deux unités mémoire et un cache multiport. Mais en pratique, aucun CPU superscalaire ne fait cela. La totalité des CPU double émission se débrouille avec un seul circuit multiplieur et une seule unité mémoire. Et cela entraine l'apparition de dépendances structurelles, qui font que certaines paires d'instructions sont impossibles. Par exemple, impossible d'émettre deux multiplications en même temps avec un seul circuit multiplieur. Mais émettre une multiplication en parallèle d'une addition est parfaitement possible. Il y a donc des paires d'instructions autorisées et des paires interdites. Et la logique est la même sur les CPU à triple ou quadruple émission, et au-delà. : des triplets ou quadruplet d'instructions sont impossibles à émettre simultanément, alors que d'autres le sont. Pour le dire autrement, il y a des '''contraintes d'appariement''' sur les instructions à émettre en même temps. ===L'impact des contraintes d’appariement sur la performance=== Ces contraintes d’appariement ont un impact sur les performance, mais celui-ci peut être grandement mitigé. Les programmes informatiques utilisent en pratique beaucoup plus d'opérations entières de base que de multiplication, branchements et accès mémoire. Il y a environ 5 opérations entières de base pour une multiplication entière. En pratique, il est rare de devoir exécuter deux multiplications à la fois. Idem pour les décalages et rotations, qui sont assez éloignés les uns des autres. Deux branchements consécutifs sont quant à eux plus fréquents. Deux accès mémoire consécutifs est assez rare, mais ils restent assez proches les uns des autres malgré tout. La conséquence est que certaines paires d'instructions sont privilégiées par rapport au reste. Les paires regroupant deux calculs basiques (additions, soustractions, ...) sont systématiquement supportées, car dupliquer des ALU entières est facile. Les paires regroupant un calcul et une autre instruction sont elles aussi systématiquement supportées. Par contre, les paires avec deux branchements, deux accès mémoire, deux décalages/rotations, ou deux multiplications/divisions sont fréquemment interdites. Seuls les CPU superscalaires larges peuvent les permettre, et encore : sous conditions. Le résultat est que le processeur peut se débrouiller avec une seule unité mémoire et une unité de branchement. ===Terminologie pour la suite du chapitre=== Décrire les contraintes d’appariement demande de dire quelles combinaisons d’instructions sont autorisées ou interdites. Et pour cela, nous allons introduire les abréviations suivantes : * INT est un raccourcis pour parler d'une opération entière simple, qu'une ALU entière peut exécuter. * MUL correspond à une opération entière complexe, typiquement une multiplication, éventuellement à une division. * FLOAT désigne une opération flottante, peut importe laquelle. * MEM désigne un accès mémoire, à savoir une instruction ou µop mémoire. * BRANCH désigne une instruction de branchement. Cette terminologie permettra de définir des paires d'instructions, qu'elles soient possibles ou interdites. Par exemple, l'expression INT + FLOAT désigne une paire d'instruction regroupant une instruction entière et une instruction flottante, peu importe l'ordre des deux instructions. Il en sera de même pour les triplets, quadruplets, ou plus. Par exemple, l'expression INT + INT + FLOAT + MUL désigne un quadruplet d'instructions regroupant : deux instructions entières, une instruction flottante, et une multiplication entière. J'utiliserais aussi des parenthèses pour regrouper certaines combinaisons. Par exemple, l'expression INT + (MUL /FLOAT) veut parler d'une paire d'instruction où la première est une opération entière basique, la seconde est : soit une multiplication, soit une opération flottante. ==Le ''front-end'' des processeurs superscalaires== Un processeur superscalaire doit charger, décoder, et exécuter plusieurs instructions par cycle. Par exemple, un processeur triple émission doit charger 3 instructions lors d'un premier cycle, puis les décoder au cycle suivant, et les exécuter au cycle suivant. Il travaille donc pas paquets de 3 instructions, dans cet exemple. Intuitivement, charger, décoder et exécuter plusieurs instructions à la fois demande de dupliquer des circuits. Par exemple, il faut dupliquer les décodeurs pour décoder plusieurs instructions. Les unités de calcul sont aussi dupliquées, sauf sur certaines processeurs qui arrivent à ruser, mais laissons cela de côté pour plus tard. Mais d'autres circuits sont simplement modifiés, comme l'unité de chargement ou l'unité d'émission. Voyons ce qu'il en est dans le détail. {|class="wikitable" |- ! rowspan="2" | Processeur sans émission multiple | rowspan="2" | Chargement | rowspan="2" | Décodage | rowspan="2" | Renommage | rowspan="2" | Émission | Exécution / ALU | rowspan="2" | ''Commit''/ROB |- | Exécution / ALU |- ! rowspan="4" | Processeur superscalaire | rowspan="4" | Chargement | rowspan="2" | Décodage | rowspan="4" | Renommage | rowspan="4" | Émission | Exécution / ALU | rowspan="4" | ''Commit''/ROB |- | Exécution / ALU |- | rowspan="2" | Décodage | Exécution / ALU |- | Exécution / ALU |} Nous allons d'abord voir ce qu'il en est pour le ''front-end'', à savoir la partie du CPU qui s'occupe de charger et décoder les instructions. Elle regroupe l'unité de chargement, les décodeurs, l'unité de prédiction de branchement, la file de µops, la file d'instruction, et divers caches. En soi, les changements portent surtout sur l'unité de chargement et les décodeurs. ===Le chargement de plusieurs instructions consécutives=== Un processeur superscalaire charge plusieurs instructions en même temps, ''en tenant compte de la présence de branchements''. La partie en italique est importante et elle a une conséquence très forte : la manière de faire est fortement différente entre un CPU superscalaire étroit et large. Un CPU superscalaire étroit fait au plus simple : il charge un bloc de 2, 3, 4 instructions consécutives en mémoire RAM. Il faut alors doubler/tripler/quadrupler la taille du bus connecté au cache d'instruction. Par exemple, pour charger quatre instructions de 32 bits chacune, il suffit de lire un bloc de 128 bits dans le cache d'instruction. Un bloc de 8, 16, 32 octets est donc lu depuis le cache et est ensuite découpé en instructions, envoyées chacun à un décodeur. Charger plusieurs instructions consécutives ne marche bien qu'en absence de branchements. La présence de branchements casse cette dynamique, et il faut gérer leur présence. * Sans prédiction de branchement, toutes les instructions d'un bloc sont décodées et exécutées en même temps, même s'il y a un branchement dans le tas. * Avec prédiction de branchement, les instructions situées après le branchement ne sont pas décodées ni exécutées. L'unité de chargement coupe le bloc chargé au niveau du premier branchement pris, remplit les vides avec des NOP, avant d'envoyer le tout à l'unité de décodage. Les instructions à l'adresse de destination seront chargées au cycle suivant, en chargeant un nouveau bloc. [[File:Fetch sur un processeur superscalaire avec prediction de branchements.png|centre|vignette|upright=2|Fetch sur un processeur superscalaire avec prédiction de branchements.]] Un autre défaut est que sur le CPU charge un bloc de 128 bits à la fois, les instructions doivent être alignées sur 128 bits. Et on peut généraliser à n'importe quelle taille de bloc. Si les instructions ne sont pas alignées, il faut gérer la situation. Il arrive qu'une instruction soit à cheval sur deux blocs, avec un morceau dans le premier bloc, un autre dans le second. Dans ce cas, l'instruction est chargée en deux fois, et des circuits doivent gérer la situation pour recoller les morceaux. Sur les CPU avec des instructions de taille fixe, le problème ne survient que rarement. Mais il est fréquent avec des instructions de taille variable. Un autre défaut est lié aux branchements. Imaginez qu'un branchement s'exécute et branche vers une instruction de destination. Rien n'indique que l'instruction de destination sera au tout début d'un bloc. Si ça se trouve, elle sera en troisième position d'un bloc de 4 instructions. Une solution simple charge le bloc en respectant l'alignement, et les deux premières instructions du bloc ne sont pas à exécuter. Il y a donc une petite perte de performance. Certains CPU, comme l'IBM RS/6000, ont la machinerie charger un bloc de N instructions même s'il n'est pas aligné. La machinerie en question se trouve dans le cache d'instruction et est tout sauf simple à expliquer,ce qui fait que je me permets de la passer sous silence. Un détail, cependant : elle ne permet pas de charger des blocs qui sont à cheval sur deux lignes de cache. ===Le décodage parallèle des instructions=== Pour le décodage des instructions, plusieurs instructions sont décodées en même temps. On parle alors de '''décodage parallèle'''. Pour ce faire, un processeur superscalaire contient plusieurs décodeurs, chacun pouvant décoder une instruction en parallèle des autres. Prenons par exemple un processeur superscalaire à 4 voies : le décodage se fera dans quatre décodeurs séparés, qui fonctionneront en parallèle. Cependant, cette implémentation ne marche bien que pour les processeurs RISC, les processeurs CISC devant faire avec un microcode gourmand en circuits. Les processeurs CISC utilisent des décodeurs hybrides, avec un microcode qui complémente un décodeur câblé. Dupliquer le microcode aurait un cout en transistors trop important, ce qui fait que seuls les décodeurs câblés sont dupliqués. Les CPU CISC superscalaires disposent donc de plusieurs décodeurs simples, capables de décoder les instructions les plus courantes, avec un seul microcode. La conséquence est qu'il n'est pas possible de décoder deux instructions microcodées en même temps. Par contre, il reste possible de décoder plusieurs instructions non-microcodées ou une instruction microcodée couplée à une instruction non-microcodée. Vu qu'il est rare que deux instructions microcodées se suivent dans un programme, le cout en performance est extrêmement mineur. Il faut noter qu'une instruction correspond à une ou plusieurs µops. Il est donc possible de charger 5 instructions et de se retrouver avec 8 µops en sortie des décodeurs. Et c'est la source d'une distinction très importante. Plus haut, j'ai parlé de processeurs superscalaires à N voies. La terminologie peut avoir deux interprétations. La première est que le processeur charge/décode N instructions à la fois. Une seconde est qu'il est capable d'exécuter/émettre N µops en même temps. Les deux ne sont pas équivalentes, vu qu'un processeur superscalaire peut, par exemple, charger/décoder N instructions et émettre/exécuter N+2 µops. La distinction est particulièrement importante sur les processeurs superscalaires larges. Certains d'entre eux sont capables de charger 5 instructions et d'en émettre le double ! Un exemple classique était les processeurs Athlon d'AMD, qui pouvaient décoder deux instructions par cycle, mais émettre 4 µops par cycle. Ce n'était pas un problème, car beaucoup d'instructions, même basiques, étaient décodées en 2 µops. ===L'émission parallèle des instructions=== La superscalarité modifie en profondeur l'unité d'émission, notamment au niveau de son interface. Avant, elle recevait une micro-opération sur son entrée, et fournissait la micro-opération émise sur une sortie. Et cela vaut aussi bien pour une unité d'émission simple, un ''scoreboard'', une fenêtre d'instruction ou des stations de réservation. Mais avec l'émission multiple, les sorties et entrées sont dupliquées. Pour la double émission, il y a deux entrées vu qu'elle doit recevoir deux micro-opération décodées/renommées, et deux sorties pour émettre deux micro-opérations. Dans ce qui suit, nous ne parlerons pas d'entrée et de sortie, mais de '''ports de décodage''' et de '''ports d'émission'''. Les ports de décodage reçoivent des micro-opérations provenant de l'unité de décodage, les ports d'émissions sont pour les micro-opérations émises. Les ports d'émission injectent les micro-opérations émises dans le pipeline, elle sont propagée au banc de registre, aux ALUs, etc. Un processeur superscalaire a forcément plusieurs ports d'émission (et de décodage). Si l'interface de l'unité d'émission change, l'intérieur est tout autant modifié. Sur un CPU non-superscalaire, l'unité d'émission reçoit une µop "candidate à l'émission", et détecte les dépendances entre avec les µops en vol, en cours d'exécution dans le pipeline. Et c'est toujours le cas sur les processeurs superscalaires : l'unité d'émission détecte les dépendances entre les µops candidates et les µops en vol. Mais avec la siperscalarité, elle doit en plus tester les dépendances entre les µops candidates. Si l'unité d'émission est un ''scoreboard'', il doit détecter les dépendances entre instructions émises simultanément et les sérialiser si besoin. Avec une fenêtre d'instruction, il n'y a pour ainsi dire rien à faire, vu que les dépendances sont éliminées par le renommage de registre et que les signaux de réveil gèrent les dépendances RAW. C'est la raison pour laquelle les processeurs superscalaires modernes n'utilisent pas de ''scoreboard''. ==Les processeurs implémentés avec plusieurs pipelines== Nous venons de voir comment la superscalarité impacte le ''front-end'', il est maintenant de voir ce qu'il en est de l'unité d'émission et des ''back-ends''. Un processeur superscalaire peut utiliser l'exécution dans le désordre et le renommage de registres, mais ce n'est pas une obligation. Historiquement, les premiers processeurs superscalaires n'utilisaient pas d'exécution dans le désordre. Le meilleur exemple est celui du Pentium 1 et 2 d'Intel. Ils étaient tous deux des processeurs superscalaires, mais n'avaient pas d'exécution dans le désordre, qui est apparue sur le Pentium 3. les explications sont plus simples si on met de côté l'exécution dans le désordre. Vous vous dites que l'implémentation d'un processeur superscalaire n'est pas la même suivant que le CPU utilise l'exécution dans le désordre, ou non. Mais dans les faits, la distinction est plus subtile que ca. Pour l'expliquer, je vais utiliser une classification originale, qui sépare les processeurs superscalaires en trois sous-types. La distinction se fait sur la manière dont la superscalarité est implémentée en matériel.La classification que j'utilise distingue : * Les processeurs avec plusieurs pipelines, sans exécution dans le désordre. * Les processeurs superscalaires avec un pipeline dynamique. * Les processeurs avec des fenêtres d'instruction décentralisées. La distinction n'est pas qu'une question d'implémentation matérielle. Elle impacte aussi le ratio entre instructions chargées/décodées et instructions émises. Vous vous dites que les deux sont égales, mais ce n'est le cas que sur les processeurs avec N pipelines ! Sur les autres processeurs, il est possible de décoder 4 instructions, mais d'en émettre maximum 6 par cycle ! Et sur les CPU avec des fenêtres d'instruction décentralisées, il y a aussi une différence entre le nombre d'instructions qui sont ''dispatch'' et ''schedule''. La catégorie la plus simple est celle des '''processeurs avec plusieurs pipelines'''. Ce sont des processeurs superscalaires sans exécution dans le désordre. Ils partent d'un processeur non-superscalaire, et ajoutent un second pipeline, en sortie de l'unité d'émission. Le second pipeline permet l'émission parallèle d'une seconde instruction. Le second pipeline n'est pas identique au pipeline originel, sur plusieurs points. Premièrement, il n'a pas exactement les mêmes circuits. Le second pipeline est généralement composé d'une unité de calcul, d'une FPU, éventuellement d'un second banc de registres, guère plus. Il permet d'exécuter une seconde opération de calcul, pas plus, ce qui est à l'origine de contraintes d'appariemment assez fortes. De plus, il n'a pas forcément la même longueur, il peut avoir des étages en moins ou en plus. Il s'agit de la forme la plus simple de processeur superscalaire et nous allons leur consacrer cette section. ===La double émission entière-flottante=== L'exemple le plus simple utilise un second pipeline pour les opérations flottantes, séparé du pipeline originel. L'ajout d'un pipeline flottant permet d'émettre une micro-opération entière en même temps qu'une micro-opération flottante, ce qui s'appelle la '''double émission entière-flottante'''. La micro-opération entière s'exécute dans l'ALU entière, la micro-opération flottante dans la FPU. Les exemples les plus notables sont le PA-RISC 7100, le POWER 1 (RIOS .& et .9) et le PowerPC 601. L'Apollo DN10000 et l'Intel i860 utilisaient aussi cette forme de double émission, mais étaient des prototypes de CPU VLIW. [[File:Double émission entière-flottante.png|centre|vignette|upright=2|Double émission entière-flottante]] Pour bien expliquer les choses, prenons le processeur illustré ci-dessous, avec deux ''back-end'' séparés : un pour la FPU, et un autre pour le reste. Les instructions entières et mémoire passent toutes par le ''back-end'' généraliste. [[File:CPU non-superscalaire basique, avec une FPU.png|centre|vignette|upright=1.5|CPU non-superscalaire basique, avec une FPU]] Les deux ''back-end'' sont des pipelines séparés, mais il faut que l'unité d'émission soit spécialement conçue pour en profiter. Un processeur simple émission peut démarrer une seule µop par cycle : soit la µop est envoyée au ''back-end'' flottant, soit elle est envoyée au ''back-end'' général. Avec la double émission entière-flottante, le processeur peut envoyer une µop dans chaque pipeline, à chaque cycle. Vu que la FPU et son banc de registre forment déjà un pipeline séparé, les seules modifications se font au niveau du ''front-end'', unité d'émission inclue. {| |- |[[File:CPU simple émission avec une FPU.png|centre|vignette|upright=1.5|CPU simple émission avec une FPU.]] |[[File:Double émission entière flottante avec un second pipeline.png|centre|vignette|upright=1.5|CPU avec un second pipeline flottant.]] |} Notez que le terme double émission ''entière''-flottante est un peu trompeur. En réalité, la technique permet d'émettre une instruction flottante avec n'importe quelle autre instruction non-flottante, avec des restrictions pour les branchements. Il est par exemple possible d'exécuter un calcul flottant en parallèle d'un accès mémoire. Sur les CPU 32 bits, il est possible de faire les multiplications dans la FPU. Pour rappel, la FPU contient un multiplieur entier 53-54 bits, pour multiplier les mantisses de deux flottants 64 bits, qu'on peut utiliser pour faire les multiplications entières 32 bits. Cela permet d'émettre une multiplication en même temps qu'une opération entière dans l'ALU. Ainsi, le CPU pouvait émettre deux instructions : une opération entière de base, avec soit une multiplication, soit une opération flottante. En clair, une émission de type INT + (MUL /FLOAT). Par contre, on perd la possibilité d'émettre une multiplication entière avec une opération flottante, mais c'était un compromis qui en valait la peine. Le CPU PA-RISC 7100 implémentait cette optimisation. Il s'agissait d'un CPU double émission entière-flottante, qui utilisait donc un partitionnement assez simple. Le combo partitionnement + reconditionnement permettait ici de gagner en performance, pour un cout en matériel très limité. D’autant plus limité que le jeu d'instruction prévoyait le reconditionnement de la FPU. Les multiplications ne lisaient pas leurs opérandes dans les registres entiers, mais dans les registres flottants. ===La double émission entière=== Une autre possibilité ajoute un second pipeline, capable d'exécuter des opérations entières simples, appelé le pipeline entier. Le processeur supporte alors la '''double émission entière''', à savoir qu'ils peuvent émettre une opération entière en plus d'une autre instruction. L'opération entière en question est une opération simple, comme une addition, une soustraction, une opération bit à bit, une comparaison, etc. Les exemples classiques sont les processeurs Intel i960 et Pentium. L'implémentation était différente entre l'i960 et le Pentium : Le Pentium avait une seconde ALU entière, alors que le i960 rusait. Le Pentium dupliquait l'ALU entière, pour créer un second pipeline entier. Sur le Pentium originel, les contraintes d'appariement étaient assez strictes. Le Pentium avait une FPU, mais ne pouvait pas l'utiliser en double émission. Il lui était impossible d'exécuter une opération flottante en même temps qu'une opération entière (branchements inclus). Le Cyrix 6x86 était une sorte de Pentium produit par l'entreprise Cyrix, avec une microarchitecture différente. Il avait des contraintes d’appariement réduites. Par exemple, il pouvait émettre une opération flottante en parallèle d'une opération entière. Nous détaillerons ces processeurs dans le prochain chapitre, qui porte justement sur les CPU superscalaires x86. [[File:CPU simple et double émission avec un second pipeline entier.png|centre|vignette|upright=2.5|CPU simple et double émission avec un second pipeline entier.]] L'Intel i960 n'avait pas de FPU, juste une ALU entière et une unité mémoire. Il utilisait l'unité mémoire comme une seconde ALU entière limitée. Pour rappel, une unité mémoire contient une AGU, à savoir une ALU spécialisée dans les calculs d'adresse. Elle est capable de faire des additions, soustractions, et quelques décalages limités (des décalages par 2, 4, 8, pas plus). L'Intel i960 ajoutait des connexions entre AGU et banc de registre, afin que celle-ci serve de seconde unité de calcul. L'AGU est déjà reliée aux deux ports de lecture, pour lire les opérandes du calcul d'adresse, il suffit de la connecter sur le port d'écriture. Le processeur peut alors émettre deux instructions/µops entières, sous certaines conditions. [[File:Emission multiple des opérations entières, double émission.png|centre|vignette|upright=2|Émission multiple des opérations entières, double émission.]] ==Les processeurs superscalaires dynamiques== Les processeurs précédents, avec 2 pipelines, avaient une unité d'émission assez simple. Elle avait deux ports de décodage, et deux ports d'émission. Le nombre de ports de décodage et d'émission étaient identiques. Vous vous dites que c'est naturel, et intuitif, que c'est normal pour un processeur superscalaire. Mais en réalité, la majorité des processeurs superscalaires a plus de ports d'émission que de décodage. Expliquer pourquoi va cependant nous demander de parler de comment la superscalarité exploite les unités de calcul. Posons-nous cette question : de combien d'unités un processeur superscalaire a besoin ? Les unités en question ne sont nécessairement des unité de calcul, l'unité mémoire et l'unité de branchement comptent aussi. La réponse dépend du nombre de voies. Si le ''front-end'' charge et décode un paquet de N instructions, exécuter ces N instructions simultanément demandera là aussi au moins N unités de calcul. Notez le terme : ''au moins'', car c'est là tout l'enjeu de cette section. La réponse dépend aussi des contraintes d’appariement. Pour un CPU superscalaire "parfait", sans contraintes d’appariement, toutes les unités doivent être dupliquées, y compris l'unité mémoire. Un processeur à double émission parfaite devrait dupliquer l'ALU entière, le ''barrel shifter'', le circuit multiplieur, la FPU, l'unité mémoire, et l'unité de branchement, ce qui ferait passer de 6 unités à 12. Le cout en circuit est énorme, même pour de la double émission ! Et pour un CPU à N pipelines, le cout en circuit encore plus prohibitif ! En pratique, les processeurs superscalaires qui font ça sont très rares. La majeure partie des processeurs superscalaires utilisent d'autres techniques : le partitionnement, la duplication partielle des ALUs, la duplication des autres unités. ===Le partitionnement des unités fonctionnelles=== Les CPU superscalaires les plus simples ne dupliquent pas leurs unités de calcul, ils se contentent d'exploiter les unités existantes. Et pour expliquer comment, nous allons partir de l'exemple d'un processeur non-superscalaire contient une ALU entière, une FPU, une unité mémoire et une unité de branchement. Les quatre unités peuvent fonctionner en parallèle, à savoir qu'une unité peut exécuter une instruction à elle toute seule, sans interagir avec les autres. Cela suffit pour créer un processeur quadruple émission, qui peut émettre en même temps : une opération entière, une opération flottante, un branchement, un accès mémoire. Le principe marche aussi sur un processeur avec moins de 4 unités, par exemple sans FPU et/ou sans unité de branchement, ou avec au contraire des unités en plus. L'idée générale est d’émettre une µops séparée dans chaque unité fonctionnelle. Utiliser ainsi les unités existantes, pour rendre un CPU superscalaire, s'appelle le '''partitionnement superscalaire'''. Le terme n'est pas beaucoup utilisé en-dehors de quelques vieux articles académiques. Le partitionnement est fortement dépendant du jeu d'instruction, car il demande de bien séparer instructions entières, flottantes, branchements et instructions mémoire. Et autant c'est bien le cas sur les CPU RISC, autant les CPU CISC ne sont pas dans ce cas. Les CPU CISC ont des instructions ''load-op'', qui effectuent une instruction arithmétique et une µop mémoire. Et ces instructions sont très compliquées à implémenter avec le partitionnement. Et au-delà de ça, les CPU CISC ont beaucoup d'instructions qui sont décodées en plusieurs µops, à exécuter dans un ordre bien précis. On peut pas émettre les µops en question simultanément. Le partitionnement a un cout en circuit très limité, pour un gain en performance lui aussi limité. Pour reprendre le CPU de l'exemple précédent, il est rare que l'on ait à exécuter ces quatre instructions en même temps. En pratique, les combinaisons fréquentes sont les combinaisons calcul + accès mémoire, calcul + branchement, calcul entier + calcul flottant. Utiliser une quadruple émission de ce type n'est donc pas une bonne idée, alors que la double émission parait plus adaptée. Et c'est là que la différence entre ports d'émission et de décodage devient intéressante. L'idée est d'avoir une unité d'émission avec deux ports de décodage, et 4 port d'émission (un par unité). Les contraintes d’appariement varient alors suivant le processeur, mais la règle générale est que si deux micro-opérations tombent dans deux unités différentes, on peut les émettre en même temps. En clair, on peut émettre une opération entière avec une opération flottante, une opération entière avec un branchement, un accès mémoire avec un branchement, etc. Et cela rend le partitionnement bien plus intéressant que prévu. Les tout premiers CPU superscalaires étaient des CPU double émission, qui utilisaient le partitionnement avec : une ALU entière, une unité mémoire et une FPU. Nous parlerons de '''partitionnement INT-FLOAT-MEM'''. L'avantage sur la double émission flottante est que les combinaisons INT + MEM et FLOAT + MEM étaient autorisées. L'intérêt était d'émettre une opération en parallèle d'un accès mémoire, ce qui est un doublet d'instruction assez fréquent. Les exemples classiques sont l'HyperSPARC, de l'alpha 21064 et du PowerPC 603. Les contraintes d’appariement variaient grandement suivant le processeur. Le PowerPC 603 implémentait une double émission "parfaite". C'est à dire que toutes les combinaisons possibles à deux instructions étaient possibles, que ce soit INT + FLOAT, INT + MEM, FLOAT + MEM. En plus de cette double émission "parfaite", le CPU utilisait la technique dite de ''branch folding'', qui permettait d'exécuter un branchement sans utiliser d'unité de calcul, ce qui fait qu'il était qualifié de ''CPU 2-way + Branch''. A l'opposé, le processeur alpha 21064 avait pas mal de contraintes d’appariement, à savoir que certaines combinaisons de deux instructions étaient interdites, bien que compatibles avec les unités disponibles. Une des raisons est que le banc de registre n'avait pas assez de ports de lectures, ce qui fait que certaines combinaisons avec une écriture mémoire n'étaient pas permises. Les concepteurs avaient volontairement inséré ces contraintes afin de simplifier le design du processeur. Avant de poursuivre, précisons que la FPU regroupe un additionneur flottant et un multiplieur flottant. Et ce fait peut être exploité pour approfondir le partitionnement. La '''double émission FADD/FMUL''' permet d'émettre une addition flottante en même temps qu'une multiplication flottante. Elle a été utilisée sur les processeurs x86, Alpha et SPARC. Les autres circuits de calcul flottant sont souvent regroupés avec l'additionneur. La division est parfois e même port que le multiplieur flottant, parfois sur celui de l'additionneur (quand elle est microcodée et exécutée en enchainant les soustractions). ===La duplication des ALU entières=== Le partitionnement est une technique élégante, simple, facile à implémenter et au cout en circuits modeste. Mais il faut avouer que cela ne donne pas des CPU superscalaires très efficaces. La raison est que le partitionnement permet d'émettre des paires, triplets, quadruplets de micro-opérations qui sont rares en pratique. Les combinaisons les plus fréquentes en pratique sont des paires/triplets d'opérations entières, souvent des paires/triplets d'additions ou d'opérations entières simples. Il est donc primordial d'émettre plusieurs opérations entières simultanément. Le fait d'émettre et d'exécuter plusieurs opérations entières en même temps s'appelle l''''émission entière multiple'''. Pour exécuter la seconde/troisième opération entière, il faut dupliquer les ALU entières (ou réutiliser l'AGU comme ALU entière comme le fait l'Intel i960). Le processeur doit avoir deux ALU entières pour de la double émission entière, trois pour de triple émission entière, etc. De plus, il faut ajouter des ports au banc de registre, pour lire deux fois plus d'opérandes et décrire deux résultats. Et enfin, il faut rajouter un port d'émission pour pouvoir émettre une micro-opération entière en plus. [[File:Processeur non-superscalaire basique 03.png|centre|vignette|upright=2|Processeur non-superscalaire basique]] La tendance est de multiplier les ALU entières, mais pas le circuit multiplieur. Le cout en transistors est alors grandement réduit, au prix de l'apparition de dépendances structurelles. Le CPU peut émettre deux additions en même temps, ou une addition et une multiplication, mais pas deux multiplications. Il en est de même avec le ''barrel shifter'', qui n'est pas dupliqué. Il est donc possible d'émettre un décalage avec une opération de base, mais pas deux décalages en parallèle. Mais ces contraintes d’appariement ne sont pas un problème, car il est rare de devoir émettre deux multiplications/décalages en même temps. La plupart des programmes sont majoritairement remplis d'additions, avec des multiplications assez rares et des décalages qui le sont encore plus. La moyenne est proche d'une multiplication pour 4/5 additions. Vu que des multiplications consécutives sont très rares, dupliquer le multiplieur est presque inutile. Disposer de plusieurs circuits multiplieurs ou de plusieurs ''barrel shifters'' serait donc un cout en circuits qui ne servirait que rarement et n'en vaut pas la chandelle. Il faut noter que sur les CPU 32 bits, les multiplications peuvent être exécutées dans la FPU ou dans un multiplieur séparé, tout dépend de si le CPU exécute les multiplications dans la FPU ou pas. {|class="wikitable" |- ! Voie d'émission n°1 !! Voie d'émission n°2 !! Voie d'émission n°3 |- | ALU entière || ALU entière || FPU |} Reste à connecter les unités de calcul à l'unité d'émission (indirectement, car il y a des étages de pipeline entre les deux). Une implémentation basique utilisée un port d'émission par unité. Prenons l'exemple d'un CPU superscalaire avec 4 ALU entières, une FPU, et une unité mémoire. Vu qu'il y a 6 unités, cela fait donc 6 ports d'émission. L'exemple historique le plus impressionnant est celui du Motorola 88110, un CPU double émission qui possède 10 unités. Il contient deux ALU entières, un circuit multiplieur, un circuit diviseur, une unité de manipulation de bits, une unité mémoire, un additionneur flottant, et deux unités graphiques pour des calculs impliquant des pixels. Le multiplieur est utilisé à la fois pour les multiplications entières, flottantes et le produit de deux pixels. Idem pour le diviseur, qui sert pour les divisions entières et flottantes. Et chaque unité a son propre port d'émission. La conséquence est que les contraintes d'appariement du Motorola 88110 sont simples : tant que deux µops atterrissent dans des unités séparées, la paire est permise. Il est par exemple possible d'émettre simultanément deux opérations entières simples, vu qu'il y a deux ALU. Par contre, impossible d'émettre simultanément deux multiplications, deux divisions, deux opérations flottantes, deux manipulations de bit, deux accès mémoire, etc. De plus, le partage du multiplieur fait qu'on ne peut pas émettre une multiplication entière avec une multiplication flottante. Idem avec les divisions, vu que le diviseur est aussi partagé. Ce sont les seules contraintes. ===Le partage des ports d'émission=== La présence d'un circuit multiplieur et d'un ''barrel shifter'' pose des problèmes pour le partitionnement. Il est possible d'avoir un port d'émission dédié au multiplieur, et un autre au ''barrel shifter'', qui sont séparés de ceux pour l'ALU entière. Il est alors possible d'émettre une opération entière, une multiplication et un décalage, simultanément. Nous parlerons de '''partitionnement entier''' pour désigner cette possibilité. [[File:Partitionnement superscalaire entier.png|centre|vignette|upright=2|Partitionnement superscalaire entier.]] Le partitionnement entier est cependant très rare, car le gain en performance serait trop faible au regard des couts en circuit. Quelques processeurs historiques l'utilisaient, mais ce n'est plus le cas de nos jours. La raison est que les multiplications et les décalages sont assez rares dans le code, ce qui fait que le port d'émission associés sont sous-utilisés. Et un port d'émission a un cout en circuit assez important. Et c'est sans compter qu'ajouter des ports sur le banc de registres juste pour un multiplier sous-utilisé n'en vaut pas la peine. L'idéal serait de trouver un moyen de réduire le nombre de ports d'émissions, sans réduire le nombre d'unités de calcul. [[File:Emission multiple des opérations entières, implémentation naive.png|vignette|Émission multiple des opérations entières, implémentation naive]] La solution consiste à '''partager les ports d'émission''', à savoir connecter un port d'émission à plusieurs unités de calcul. L'exemple classique est justement lié aux circuits multiplieur et ''barrel shifters''. L'idée est que le multiplieur et le ''barrel shifter'' sont mis sur le même port d'émission qu'une ALU entière. Prenons par exemple le processeur à double émission entière illustré ci-contre. Un port d'émission est relié à une ALU entière seule, et l'autre port d'émission alimente la seconde ALU entière et le multiplieur. La conséquence est que le processeur peut émettre deux opérations entières, dont une multiplication. Si on avait utilisé un port d'émission dédié au multiplieur, il aurait été possible d'émettre deux opérations entières et une multiplication. On perd donc une voie, mais on gagne en flexibilité et on économise des circuits. Notons que ce partage signifie aussi que le multiplieur partage les ports sur le banc de registre, ce qui fait une double économie. [[File:Emission multiple des opérations entières, implémentation courante.png|centre|vignette|upright=1.5|Émission multiple des opérations entières, implémentation courante]] En général, le ''barrel shifter'' et le multiplieur sont placés sur deux voies d'émission séparés, ce qui permet d'émettre un décalage et une multiplication en même temps. Les mettre sur le même port ne le permettrait pas. {|class="wikitable" |- ! Voie d'émission n°1 !! Voie d'émission n°2 !! Voie d'émission n°3 |- | * ALU entière * Multiplieur | * ALU entière * Barrel shifter | FPU |- | * Additions, soustractions, opérations bit à bit, etc. * Multiplication | * Additions, soustractions, opérations bit à bit, etc. * Décalages et rotations | Opération flottante |} Terminons concernant les multiplieurs avec une dernière subtilité. Pour rappel, les processeurs modernes intégrent en réalité deux multiplieurs différents. Le résultat d'une multiplication est très large et prend deux registres. Par exemple, une multiplication de deux opérandes 64 bits donne un résultat sur 128 bits, ce qui ne tient pas dans un registre, mais en prend deux. L'instruction de multiplication classique ne calcule que les 64 bits de poids faible. mais elle est complétée par d'autres instructions de multiplication qui peuvent faire le calcul complet. Pour résoudre le problème, les processeurs modernes intègrent deux instructions de multiplications : une qui calcule les bits de poids faible du résultat, une autre qui calcule les bits de poids fort. Et ces deux instructions sont associées à deux multiplieurs séparés, aux circuits différent. Le multiplieur qui calcule les bits de poids faible du résultat est appelé le ''low multiplier'', l'autre est appelé le ''high multiplier''. Le second multiplieur est souvent placé sur un second port d'émission, différent du premier multiplieur, partagé avec une ALU. L’avantage de mettre les deux multiplieurs sur deux ports d'émission différents est qu'une multiplication complète peut être réalisée en utilisant les deux multiplieurs en parallèle. Les deux sous-multiplications sont émises en même temps, exécutées en même temps. pas besoin d'exécuter l'une puis la seconde, d'où un gain performance appréciable. Nous venons de voir comment partager un port d'émission entre une ALU et un multiplieur. Mais au-delà de cet exemple, le partage des ports d'émission peut appliquer à n'importe quelle unité. Prenons l'exemple d'un CPU superscalaire avec 4 ALU entières, une FPU, et une unité mémoire. Vu qu'il y a 6 unités, cela fait donc 6 ports d'émission. Cependant, il est rare qu'un bloc de 6 instructions contienne exactement 4 opérations entières, une opération flottante, et un accès mémoire. Beaucoup de ports d'émission seraient sous-utilisés. La solution est de partager des ports d'émission, pour passer à la quadruple émission. Le CPU peut alors répartir 4 instructions sur les ports d'émission adéquats, à chaque cycle. Le CPU a donc 4 ports de décodage et 6 ports d'émission. Une implémentation classique permet n'importe quelle combinaison de 4 instructions compatible avec les 6 unités. Par exemple, il devient possible d'émettre simultanément 4 additions, la combinaison 2 * INT + FLOAT + MEM, 3 * INT + MEM, et bien d'autres. L'exemple relie une ALU entière, la FPU et l'unité mémoire sur le même port. Le CPU a alors quatre ports d'émission, qui ne sont pas "identiques". Trois d'entre eux sont reliés à une ALU entière chacun, rien d'autre. Le quatrième est lui relié à une ALU entière, la FPU et l'unité mémoire. On économise alors deux ports d'émission, mais cela entraine l'apparition de contraintes d’appariement. Le CPU peut émettre 3 opérations entières + n'importe quelle autre opération. Mais les autres combinaisons sont interdites. Le CPU peut émettre 6 opérations entières simultanément, grâce à 6 ALU entières. Les accès mémoire ou opérations flottantes ne viennent pas en plus, mais en remplacement des opérations entières. Regrouper plusieurs ALU sur un même port d'émission est donc à l'origine de dépendances structurelles, de nouvelles contraintes d’appariement. Dans certaines situations de '''''port contention''''', on a assez d'ALU pour exécuter N micro-opérations, mais la répartition des ALUs sur les ports l'empêche. Impossible d'émettre deux micro-opérations sur deux ALU si elles sont sur le même port d'émission. On peut réduire les cas de ''port contention'' en répartissant correctement les ALU sur les ports d'émission, mais sans jamais les supprimer complétement. Un exemple est celui du PowerPC 604. Il implémentait la quadruple émission, alors qu'il avait 5 unités de calcul. Mais deux unités partageaient un même port d'émission. Dans le détail, il avait deux ALU entières, un circuit multiplieur/diviseur, une FPU, une unité mémoire. La FPU et le multiplieur étaient sur le même port d'émission. En conséquence, le CPU pouvait émettre seulement les combinaisons INT + INT + MEM + (MUL/FLOAT). : Il est intéressant de voir l'exemple d'un processeur superscalaire parfait, sans contraintes d'appariement, à N voies. Pour cela, on part d'un processeur non-superscalaire, avec M unités de calcul. Un tel processeur peut s'implémenter avec N ports d'émission, chacun relié à M unités de calcul possibles, ce qui fait que les M unités de calcul sont dupliquées en N exemplaires. Si on prend par exemple un CPU non-superscalaire avec une ALU, une FPU, une unité mémoire et une unité de branchement, un port d'émission sera relié à une ALU, une FPU, une unité mémoire et une unité de branchement. ===La duplication des autres unités fonctionnelles=== Dupliquer les ALU entière est une première étape, mais il est aussi possible de dupliquer les autres unités fonctionnelles. Par exemple, il est possible de dupliquer l'unité mémoire ou l'unité de branchement. Reste à voir quelles unités dupliquer, et pourquoi. Précisons que dans ce qui va suivre, nous allons parler de la duplication des unités en général, pas seulement des unités mémoire/branchement. Nous allons continuer de parler de la duplication des ALU entières dans ce qui suit, mais de manière plus générale. Pour un processeur à N voies, il est théoriquement possible de dupliquer toutes les unités en N exemplaires. Mais ce n'est jamais fait en pratique, car le cout en circuits serait trop important et le gain en performance trop faible. Mieux vaut dupliquer certaines unités bien précises, quitte à avoir des contraintes d'appariement. Et à ce petit jeu, toutes les duplications ne se valent pas, certaines sont plus rentables en matière de performance, le cout en circuit n'est pas le même selon l'unité, etc. La rentabilité en performance dépend surtout des contraintes d'appariement. Les contraintes d'appariement entrainent une baisse de performance significatives si elles interdisent des paires d'instructions fréquentes. Aussi, les opérations très fréquentes, souvent appairées, gagnent à dupliquer l'unité associée. Et au contraire, les unités rarement utilisées ne doivent pas être dupliquées. Il se trouve que les unités les plus utilisées sont les ALU entières, suivies par les unités mémoire et l'unité de branchement. Le cout en circuit n'est aussi pas le même. Dupliquer les ALU entière est trivial, car elles ont un budget en transistors assez faible. Les circuits multiplieurs, diviseurs, et les ''barrel shifter'' ont eux un cout en transistor plus élevés. Si on devait faire un classement, on aurait : ALU entière < ''barrel shifter'' < multiplieur. Pour les unités mémoire, le cout en transistor est là aussi conséquent. Le résultat final est que dupliquer les ALU entières est privilégié sur le reste, comme l'a vu dans la section précédente. Les unités mémoire arrivent en seconde place, suivie par les multiplieurs/''barrel shifter'' à la troisième place, et les unités de branchement à la quatrième place. Les CPU superscalaires larges ont donc tendance à multiplier les unités mémoire en second. Les multiplieurs et ''barrel shifters'' sont eux aussi dupliqués sur les CPU superscalaires larges, mais cela vient souvent après avoir dupliqué les unités mémoire. La raison est que les accès mémoire sont critiques pour la performance des CPU à exécution dans le désordre, pas les multiplications. Pour les unités de branchement, une subtilité complique le fait d'en installer plusieurs. Que faire quand deux branchements sont pris ? La solution la plus simple est de ne pas se trouver dans cette situation : on n'utilise qu'une seule unité de branchement et on n’exécute qu'un seul branchement par cycle. La majorité des processeurs superscalaires étroits font ainsi. Les processeurs superscalaires larges ont cependant deux unités de branchements, mais ils n'acceptent qu'un seul branchement pris à la fois. Si les deux branchements pris sont exécutés en même temps, le processeur n’exécute que le plus récent, dans l'ordre du programme. ===Les CPU superscalaires mélangent les trois techniques=== Les CPU superscalaires utilisent toutes les techniques à la fois : partitionnement, duplication de l'ALU entière, duplication des autre unités fonctionnelles. Chaque processeur utilise ces trois stratégies à sa sauce, en fonction de son budget en transistor. Les quatre techniques ont cependant un cout en circuit différent, et donnent des gains de performances eux aussi forts différents. * Le '''partitionnement superscalaire''' a un cout en circuit modéré, car on n'a pas besoin de dupliquer d'ALU. * La '''duplication des ALU entières''' est la technique la plus importante : elle a un cout en circuit modéré, et donne des gains en performance impressionnants. * La '''duplication des autres unités''' a un cout en circuit variable, pour des gains en performance eux aussi variables. * Le '''partage des ports d'émission''' réduit le cout en circuit du CPU, pour des pertes de performances mineures si bien fait. L'usage du partitionnement seul, sans duplication, était surtout le fait des processeurs commercialisés entre les années 1989 et 1993. Le partage des ports d'émission a lui aussi mis un peu de temps pour s'imposer. Globalement, les processeurs superscalaires ont évolués progressivement, pour se rapprocher d'une sorte de standard. Mais pour comprendre ce qu'est ce standard, et en quoi les CPU historiques s'en sont progressivement rapprochés, il faut étudier l'histoire des CPU superscalaires. L'histoire des CPU superscalaires a commencé dès 1960, mais est resté un projet de recherche pendant plusieurs décennies. De nombreux designs ont été conçus, mais abandonnés avant la production, comme l'ACS-1 d'IBM. Les années 1980 ont vu l'arrivée de prototypes de processeurs VLIW, mais qui n'étaient pas superscalaires. Par exemple, l'Apollo DN10000 et l'Intel i860 pouvaient émettre deux instructions à la fois, sous conditions, mais demandaient que le compilateur fasse une bonne partie du travail. Les premiers CPU superscalaires commercialisés sont sortis en 1989. Deux CPUs superscalaires sont sortis cette année là : le RS/6000 d'IBM et l'i960CA d'Intel. Puis, la compétition s'est aussi lancée dans la bataille. Les CPU commercialisés avant l'année 1993 étaient à double émission, à l'exception du SuperSPARC qui utilisait la triple émission. Les modèles après 1993 hésitaient entre double et quadruple émission. Dans le tableau ci-dessous, les processeurs quadruple émission sont en bleu, les triple émission sont en rouge, les autres ne sont pas en couleur. {|class="wikitable" |- ! !! IBM !! HP PA-RISC !! SPARC !! Intel!! Alpha !! Autres |- ! 1989 | RS/6000 || || || i960CA || || |- ! 1990 | || || || || || |- ! 1991 | || || || || || Motorola 88110 |- ! 1992 | RSC || PA 7100 || class="f_rouge | SuperSPARC || || 21064 || |- ! 1993 | PPC 601 || || HyperSPARC || Pentium || || |- ! 1994 | class="f_bleu | POWER 2 || PA 7200 || || || class="f_bleu | 21164 || |- ! 1995 | 603/604 || class="f_bleu | PA 8000 || class="f_bleu | UltraSPARC 1 || Microarchitecture P6 (+ concurrence AMD) || || class="f_bleu | MIPS R1000 |- ! 1996 | class="f_bleu | 620 || || || || class="f_bleu | 21264 || |- ! ... || ... || ... || ... || ... || ... || ... |} Les premiers CPU à double émission sont assez représentatifs des CPU à double émission modernes. Il faut dire que se limiter à deux voies ne permet pas de faire beaucoup de choses. Voici le tableau chronologique disant quel CPU utilisait quelle technique. * Les CPU en vert utilisaient la double émission entière-flottante. * Les CPU en rouge utilisaient la double émission entière "pure". * Les CPU en jaune utilisaient un ''partitionnement complet'' entre ALU, FPU et unité mémoire. * Les CPU sans couleur utilisaient un grand nombre d'unités, avec beaucoup de ports d'émission. * Les CPU barrés utilisent la triple ou quadruple émission et seront vu dans la section suivante. {|class="wikitable" |- ! !! IBM !! HP PA-RISC !! SPARC !! Intel!! Alpha !! Autres |- ! 1989 | class="f_vert | RS/6000 || || || class="f_rouge | i960CA || || |- ! 1990 | || || || || || |- ! 1991 | || || || || || Motorola 88110 |- ! 1992 | class="f_vert | RSC || class="f_vert | PA 7100 || <s>SuperSPARC</s> || || class="f_jaune | 21064 || |- ! 1993 | class="f_vert | PPC 601 || || class="f_jaune | HyperSPARC || class="f_rouge | Pentium || || |- ! 1994 | <s>POWER 2</s> || PA 7200 || || || <s>21164</s> || |} C'est en 1994, que la quadruple émission est arrivée et que les CPU ont essayé divers implémentations. Il y avait alors trois stratégies pour la double/triple/quadruple émission, qui partageaient des problèmes similaires. La première implémentation dupliquait les ALUs et les FPUs, ce qui permettait d'émettre deux opérations flottantes avec deux opérations entières. Le POWER 2 dupliquait ses FPUs à la perfection, alors que le 21264 séparait l'additionneur et le multiplieur flottant. Les accès mémoire étaient traités comme des opérations entières et le processeur pouvait souvent en émettre deux à la fois. Mais une telle organisation n'est plus utilisée de nos jours, car, sans instructions flottantes à exécuter, elle est équivalente à de la double émission. La seconde implémentation utilisait deux ALU entières (dont un multiplieur), une unité mémoire et une FPU.Cette organisation est intéressante, mais encore trop stricte pour donner de bons résultats, les quadruplets avec exactement deux opérations entières, un accès mémoire et une opération flottante étant trop rares. L'usage de ces 4 unités en double ou triple émission a été utilisé sur le PA 7200 et le SuperSPARC. Malheureusement, en plus de problèmes au niveau de son cache, le SuperSPARC avait de nombreuses contraintes d’appariement, car le banc de registre n'avait pas assez de ports pour alimenter certaines combinaisons d'instructions. De plus, s'il émettait une multiplication, il ne pouvait pas émettre de seconde µop. Enfin, une troisième implémentation utilisait un grand nombre d'unités fort différentes, bien plus que quatre, avec au minimum deux ALU entières. Prenons l'exemple de l'UltraSPARC, qui avait : deux ALU entières, une unité mémoire, une unité de branchement, un additionneur flottant, un multiplieur flottant, un diviseur flottant (aussi utilisé pour le calcul des racines carrées), et 2 unités graphiques pour les calculs sur des pixels. En tout, cela fait 9 unités différentes, pour de la quadruple émission. Dans le même genre, les processeurs MIPS R8000 et R10000 avaient une implémentation plus moderne, dans le sens où toutes les unités étaient dupliquées. Le CPU avait deux ALU, deux FPU et deux unités mémoire. Il pouvait donc émettre quatre instructions à la fois, tant que le paquet collait avec ces six unités. Moitié opérations entières, moitié opérations mémoire, avec de quoi remplacer les opérations entières par des opérations flottantes. Le PA 8000, lui, dupliquait toutes ses unités en deux exemplaires, ce qui n'est pas l'idéal, aucun processeur moderne ne fait cela aujourd'hui. Le tout est résumé dans le tableau ci-dessous, avec : * en vert les CPU utilisant la première stratégie ; * en rouge les CPU utilisant la seconde stratégie ; * en jaune les CPU utilisant la troisième stratégie. {|class="wikitable" |+ Processeurs quadruple émission historiques |- ! Année !! Processeur !! Unités |- ! 1991 | class="f_jaune | Motorola 88110 || class="f_jaune | 2 ALU + MUL + DIV + BIT + MEM + FADD + 2 unités graphiques |- |- ! rowspan="2" | 1994 | class="f_vert | POWER 2 || class="f_vert | 2 ALU/MEM + 2 FPU (+ 2 Branchements via ''branch folding'') |- | class="f_rouge | 21164 || class="f_rouge | 2 ALU + FPU + MEM |- ! rowspan="3" | 1995 | PA 8000 || 2 ALU + 2 ''barrel shifters'' + 2 MEM + 2 FPU (FMA) + 2 FPU (DIV et SQRT) + 2 SIMD |- | class="f_jaune | UltraSPARC 1 || class="f_jaune | 2 ALU + MEM + BRANCH + FADD + FMULFDIV + 2 unités graphiques |- | MIPS R8000 et R10000 || 2 ALU + 2 FPU + 2 MEM |- ! rowspan="2" | 1996 | class="f_rouge | 620 || class="f_rouge | 2 ALU + FPU + MEM |- | class="f_vert | 21264 || class="f_vert | 2 ALU/MEM + 2 FPU (FADD + FMUL) |} Malheureusement, ces CPUs historiques n'avaient ni assez d'unités de calcul entières, ni d'unités mémoire, pour remplir la quadruple émission. Environ la moitié des instructions d'un programme correspond à des instructions entières. Pour en profiter, un processeur à N voies doit disposer d'au minimum N/2 ALU entières, l'idéal étant d'aller au-delà. Les CPU superscalaires historiques avaient 2 ALU pour de la quadruple émission, ce qui était très limite. En comparaison, les CPU superscalaires modernes mettent le paquet niveau ALU entière. La plupart des CPU x86 modernes descendent rarement sous les 2/3, la plupart remplit presque la totalité de la largeur du CPU. Pour donner un exemple, la microarchitecture Golden Cove d'Intel est un processeur à 6 voies, avec 5 ALU entières. Pour être précis, un programme informatique exécute environ 40% de son code dans des instructions arithmétiques, un autre 40% dans les accès mémoire, et un le reste pour... le reste. La conséquence est que les processeurs modernes dupliquent leurs unités mémoire. Par exemple, la microarchitecture ''Golden Cove'' d'Intel dispose de trois unités mémoire : deux spécialisées dans les écritures, trois dans les lectures. La microarchitecture ''Gracemont'' utilise la pentuple émission et peut émettre 4 µops entières et 4 µops mémoire. Notez que le ratio est équilibré entre opérations entières et mémoire, avec soit égalité, soit un avantage pour les ALU entières. Une autre régularité est que la largeur totale du processeur peut être occupée par des opérations entières/mémoire. Pour le dire autrement, sur un processeur quadruple émission, il pourra émettre un mix de 4 instructions entière/mémoire, avec zéro opération flottante. Idem avec des processeurs triples ou pentuple émission, voire plus. Si le processeur émet une opération flottante, elle remplace une opération entière. Prenons l'exemple des processeurs AMD K6, sortis en 1997, juste avant les AMD Athlon. Ils avaient 10 unités de calcul, 6 ports d'émission, 4 ports de décodage. Voici exactement comment étaient répartie les unités de calcul sur les ports d'émission. C'était des processeurs quadruple émission, ce qui fait que la moitié de la largeur du processeur sert pour des opérations entières, et l'autre moitié pour les accès mémoire. {|class="wikitable" |- ! Port d'émission n°1 !! Port d'émission n°2 !! Port d'émission n°3 !! Port d'émission n°4 !! Port d'émission n°5 !! Port d'émission n°6 ! |- | ALU entière || ALU entière || FPU || Unité de branchement || Unité LOAD || Unité STORE |- | || Multiplieur || || || || Unité de calcul d'adresse (instruction LEA) |- | || ''Barrel shifter'' || || || || Unité pour les instructions PUSH |} Les microarchitectures K7, K8 et K10, utilisées sur les anciens CPU AMD Athlon, sont un exemple moins représentatif. Ces microarchitectures utilisent le partage des ports d'émission au maximum. C'était des microarchitectures à triple émission, avec six ports d’émission. Il y avait trois ports d'émission pour les opérations flottantes, et trois ports d'émission pour les micro-opérations entières/mémoire. Il y avait trois ALU entières et trois unités mémoire, chaque ALU partageait un port d'émission avec une unité mémoire. Elle pouvait donc émettre soit trois opérations entières, soit trois µops mémoire, soit un mix des deux. En plus des mix avec les opérations flottantes et branchements. {|class="wikitable" |- ! Port d'émission n°1 !! Port d'émission n°2 !! Port d'émission n°3 !! Port d'émission n°4 !! Port d'émission n°5 !! Port d'émission n°6 ! |- | ALU entière || ALU entière || ALU entière || FADD || FMUL || FPU (autres opérations) |- | Multiplieur || || || || || |- | LOAD/STORE || LOAD/STORE || LOAD/STORE || || || |} Les CPU superscalaires larges dupliquent les multiplieurs et/ou les ''barrel shifters'', et même les unités de branchement. La raison est que quand la largeur du CPU augmente, le processeur traite des paquets d'instructions de plus en plus gros. Par exemple, pour un CPU à 10 voies, cela veut dire émettre 10 instructions en même temps. Il est alors plus fréquent d'avoir deux multiplications, deux décalages, deux accès mémoire, deux branchements. Par exemple, la moyenne est d'une multiplication tous les 5 instructions. Les CPU superscalaires à 10 voies ont donc tendance à avoir deux multiplications par paquet d'instruction, en moyenne. Avoir deux multiplieurs est alors un gain en performance clair. Par exemple, la microarchitecture ''Golden Cove'' a deux ''barrel shifters''. C'est une architecture à 6 voies. {|class="wikitable" |- ! Port d'émission n°1 !! Port d'émission n°2 !! Port d'émission n°3 !! Port d'émission n°4 !! Port d'émission n°5 !! Port d'émission n°6 !! Port d'émission n°7 !! Port d'émission n°8 !! Port d'émission n°9 !! Port d'émission n°10 |- | ALU entière || ALU entière || ALU entière || ALU entière || ALU entière || LOAD || LOAD || LOAD || STORE || STORE |- | ''Barrel shifter'' || Multiplieur || Multiplieur || ''Barrel shifter'' || || || || || || |- | Branchements || Diviseur || || Branchements || || || || || || |} ==Les µops mémoire sur les processeurs superscalaires== Plus haut, nous avons volontairement passé sous silence les accès mémoire. La raison à cela est que leur support sur les CPU superscalaire peut se faire de plusieurs manières différentes, qu'il vaut mieux expliquer dans une section dédiée. Les différentes implémentations sont décrites dans la liste suivante, nous allons les voir une par une. * Avec la première méthode, les accès mémoire sont exécutés par le pipeline pour les opérations entières. * Avec la seconde méthode, les accès mémoire ont un pipeline dédié ; c'est l'''émission parallèle des accès mémoire''. * Avec la troisième méthode, il est possible d'émettre plusieurs accès mémoire simultanément : c'est l'''émission multiple des accès mémoire''. Voyons ces trois cas dans le détail. Nous verrons notamment les différentes formes d'émission multiple des accès mémoire. ===Les accès mémoire traités dans le pipeline entier=== Dans le cas le plus simple, les accès mémoire sont traités comme des opérations entières un peu spéciales. L'unité mémoire est sur le même port d'émission que l'ALU entière, ce qui fait que les accès mémoire remplacent des opérations entières. Faire ainsi permet d'utiliser une ALU entière pour les calculs d'adresse, pas besoin de rajouter une unité de calcul d'adresse séparée. Typiquement, un processeur de ce type place l'unité mémoire après l'unité de calcul. Les opérations entières n'utilisent que l'ALU entière, mais pas l'unité mémoire. Les accès mémoire exécutent un calcul d'adresse dans l'ALU entière, puis l'adresse calculée est envoyée à l'unité mémoire. Le tout est illustré ci-dessous, dans le cas d'un processeur historique à double émission entière-flottante. [[File:Processeur non-superscalaire basique 01.png|centre|vignette|upright=1.5|Processeur non-superscalaire basique]] Un exemple de CPU double émission de ce type est celui du Power PC 440, un CPU destiné à l'embarqué. Vu qu'il était destiné à l'embarqué, il n'avait pas de FPU, il n'avait pas besoin de manipuler de nombres flottants. Il n'a donc que des ALU entières, un multiplieur et une unité mémoire. Il dispose de deux ports d'émission. Le premier est connecté à une ALU entière et un circuit multiplieur, le second est relié à l'unité mémoire et une seconde ALU entière. Une organisation simple, mais très efficace ! [[File:PowerPC 440.png|centre|vignette|upright=2|Microarchitecture du PowerPC 440.]] L'implémentation économise une unité de calcul d'adresse, mais n'a pas de cout en performance significatif. Les accès mémoire étant très lents, émettre une µop entière en parallèle d'un accès mémoire ne sert pas à grand-chose. On peut émettre cette µop entière un cycle plus tard, elle sera terminée avant même que l'accès mémoire soit terminé, même si l'accès mémoire se fait dans le cache L1 ou L2. Pour comprendre pourquoi, faisons quelques calculs. Un accès mémoire prend deux-trois cycles quand il tombe dans le cache L1. Et on doit attendre qu'il soit terminé pour en émettre un nouveau. Combien d'instructions arithmétiques peut-on lancer pendant ce temps, sur un CPU triple émission ? Au premier cycle, on peut en émettre 2 (l'instruction mémoire prend une place, donc 3-1), puis 3 au second cycle. Ce qui fait 5 instructions arithmétiques au total. Or, il se trouve qu'il y a une instruction d'accès mémoire pour 5 instructions arithmétiques, environ. Par contre, ce compromis change quand on passe à la quadruple émission, voire au-delà. Dans ce cas, il devient intéressant de pouvoir émettre une nouvelle instruction mémoire à chaque cycle. Ce qui nous amène à la section suivante... ===L'émission parallèle des accès mémoire=== A partir de la quadruple émission, la tendance a été de séparer l'unité mémoire des ALU entières. Cela permet d'émettre des µops mémoire en même temps que des µops entières et/ou flottantes., ce qui porte le nom d''''émission parallèle des µops mémoire''', ou encore ''émission mémoire parallèle''. Par exemple, un processeur quadruple émission peut émettre en même temps deux opérations entières, une opération flottante et un accès mémoire. L'accès mémoire vient en plus des opérations entières, il n'est pas possible de remplacer l'accès mémoire par une opération entière. La technique ne permet pas de faire les calculs d'adresse dans l'ALU entière. Il faut donc utiliser une unité de calcul d'adresse séparée. Elle est intégrée dans l'unité mémoire, qui fait l'interface entre le cache et le banc de registres. Le cout en circuits est très faible, car les unités de calcul d'adresse n'utilisent guère plus qu'un additionneur et un circuit de décalage très simple. L'émission mémoire parallèle est plus facile à implémenter sur les CPU RISC, qui ont des instructions mémoire séparées du reste. Les CPU CISC ne sont pas dans ce cas, ce qui fait que séparer l'unité mémoire du pipeline entier est compliqué. Les CPU superscalaires historiques étaient pour moité des CPU RISC et pour moitié des CPU CISC, ce qui fait qu'ils n'utilisaient pas ou peu l'émission mémoire parallèle. Les premiers processeurs superscalaires se contenaient de l'émission parallèle mémoire, ils ne pouvaient émettre qu'un seul accès mémoire à la fois, l'unité mémoire n'était pas dupliquée. Et ce n'est pas tant un problème que ça, du moins sur les processeurs à double ou triple émission. En effet, il est rare que l'unité mémoire doive faire deux accès simultanés. Notons que le processeur peut exécuter une instruction mémoire en parallèle d'un calcul ou d'un branchement, seuls les accès mémoire simultanés sont impossibles. ===L'émission multiple des accès mémoire avec une LSQ=== Les processeurs superscalaires larges travaillent sur des paquets de 8 à 10 instructions, il est plus fréquent d'avoir plusieurs accès mémoire par paquet. Dans ces conditions, il est utile d'avoir une '''émission multiple des accès mémoire''', à savoir d'émettre plusieurs micro-opérations mémoire en même temps. Les processeurs superscalaires modernes sont capables d'émettre plusieurs lectures/écritures simultanément. Par exemple, ils peuvent émettre une lecture en même temps qu'une écriture, ou plusieurs lectures, ou plusieurs écritures. Il faut noter que selon le processeur, il peut y avoir des restrictions quant aux accès mémoire émis en même temps. Par exemple, certains processeurs peuvent émettre une lecture avec une écriture en même temps, mais pas deux lectures ni deux écritures. Ou encore, ils peuvent émettre deux lectures, une lecture et une écriture, mais pas deux écritures en même temps. Dans la majorité des cas, les processeurs ne permettent pas d'émettre deux écritures en même temps, alors qu'ils supportent plusieurs lectures. Il faut dire que les lectures sont plus fréquentes que les écritures. Les processeurs qui autorisent toutes les combinaisons de lecture/écriture possibles, sont rares. L'émission multiple des accès mémoire s'implémente dans l'unité mémoire. Pour rappel, l'unité mémoire s'interpose entre le cache L1 et le reste du pipeline. Dans le cas le plus simple, elle incorpore une ''load/store queue'' et des unités de calcul d'adresse. L'émission multiple des accès mémoire demande de rendre la ''Load-store queue'' multi-ports, afin de gérer plusieurs micro-opérations mémoire simultanées. Il faut aussi dupliquer les unités de calcul d'adresse reliées à la LSQ, chaque port d'émission mémoire devant avoir sa propre unité de calcul d'adresse. : Dans ce qui suit, nous parlerons d'AGU (''Adress Generation Unit'') pour désigner les unités de calcul d'adresse, et de LSQ pour designer la ''Load-store queue''. [[File:Processeur non-superscalaire basique 02.png|vignette|upright=1|Processeur non-superscalaire basique]] Dupliquer les ports de la LSQ et les AGU est nécessaire. Mais qu'en est-il du cache ? La réponse varie suivant le processeur. Il y a deux grandes méthodes pour implémenter l'émission multiple des accès mémoire. La première méthode ajoute des ports de lecture/écriture au cache de données, pour faire des lectures/écritures simultanées. Il faut alors dupliquer des unités de calcul, rajouter les ports sur le cache, mais aussi rajouter des ports sur la ''load/store queue'', pour qu'elle échange des données/commandes mémoire avec le cache. Le cout en circuits est alors conséquent La seconde duplique les unités de calcul, mais pas les ports d'accès au cache. Les accès mémoire sont alors accumulés dans la ''load/store queue'', qui sont ensuite traités un par un par le cache. Un exemple est celui des processeurs AMD de micro-architecture K7 K8, à savoir les anciens AMD Athlon et AMD Athlon 64, qui pouvaient calculer trois adresses simultanément, mais ne pouvaient faire qu'un seul accès au cache par cycle. Le cout en circuit est modéré : les unités de calcul coutent très peu, les ports de la ''load/store queue'' coutent déjà un peu plus. Quelques processeurs utilisaient des solutions intermédiaires. Un processeur utilisant cette technique est, par exemple, capable d'émettre quatre µops mémoire en même temps, mais avec seulement deux ports sur le cache. Un exemple classique étant les Pentium 1 et 2 d'Intel, dont nous parlerons dans le chapitre suivant. ===L'émission séparée des LOAD et STORE=== De rares processeurs ont des ports d'émission qui peuvent faire indifféremment lecture comme écritures. Mais les processeurs modernes préfèrent séparer ports d'émission pour les lectures et les écritures. Un exemple est celui des processeurs Intel de micro-architecture Nehalem, qui avaient un port de lecture et un port d'écriture tous deux reliés à la ''Load-store queue'', chacun avec leur propre unité de calcul d'adresse. Comme autre exemple, les processeurs skylake ont une LSQ avec deux ports de lecture et un port d'écriture, ce qui permet d'émettre deux lectures en même temps qu'une écriture. Dans cette section, nous allons étudier le cas avec des ports séparés pour les lectures et écritures. En général, les processeurs ont un peu plus de ports de lectures que d'écritures. Une raison est qu'un programme a, en moyenne, un tout petit peu plus de lectures que d'écritures. Mais la différence n'est pas énorme, c'est un léger déséquilibre. Une seconde raison est que l'exécution dans le désordre marche bien mieux quand les lectures ont lieu le plus tôt possible. Donc mieux vaut privilégier les lectures à l'émission, pour qu'elles se fassent un peu en avance. En pratique, la différence n'est pas très marquée. Il est courant d'avoir un port de lecture et un d'écriture, les CPU superscalaires très larges ont souvent deux ports de lecture et deux d'écriture. A la rigueur, quelques CPU ont trois ports de lecture et deux d'écriture. Le cas le plus simple est celui où on peut émettre une lecture et une écriture en même temps. Il s'implémente facilement si la LSQ est en réalité une simple ''Store queue'', à savoir qu'elle met en avance les écritures uniquement. Pour rappel, les écritures sont mises en attente dans la ''Store queue'', mais les lectures sont exécutées immédiatement. Une fois l'adresse à lire connue, la lecture consulte la ''Store queue'' pour détecter les dépendances de données, puis s'exécute. La donnée à lire est lue soit depuis la ''Store queue'', soit depuis le cache. [[File:Emission LOAD - Store séparée.png|vignette|upright=1|Émission LOAD - Store séparée]] L'implémentation de l'émission multiple est alors très simple. La ''Store queue'' a déjà deux ports, avec un pour les lectures et un autre pour les écritures. Idem pour le cache, qui a naturellement un port de lecture et un d'écriture. Émettre une lecture et une écriture simultanément ne demande donc pas de modification digne de ce nom. La ''Store queue'' doit juste supporter une lecture et une écriture simultanée. Ajouter l'émission d'une seconde lecture n'est pas compliquée : il faut juste rajouter un second port de lecture sur le cache et la ''Store queue''. Pour rappel, l'unité mémoire est précédée par une structure qui met en attente les micro-opérations mémoire avant leur émission finale. La structure en question varie suivant l'implémentation, mais un cas particulier se marie bien avec l'émission multiple des µops mémoire. Il s'agit du cas avec une file de µops séparée pour les lectures et une autre pour les écritures, appelées respectivement la ''file de µops LOAD'' et la ''file de µops STORE''. Il est alors possible d'émettre une lecture et une écriture lors du même cycle d'horloge. Le port de lecture alimente une unité de calcul d'adresse dédiée, directement reliée au cache. Le port d'écriture du cache alimente une unité de calcul, qui est suivie par une file d'écriture, elle-même reliée au cache. Les processeurs AMD de micro-architecture K6 utilisaient cette technique. [[File:Double émission avec le Load Ordering, Store Ordering.jpg|centre|vignette|upright=2.5|Double émission avec le Load Ordering, Store Ordering]] ==Les CPU superscalaire à exécution dans le désordre== La superscalarité modifie aussi les circuits dédiés à l'exécution dans le désordre. Elle modifie les unités de renommage de registre, le ROB et les autres structures liées à l'exécution dans le désordre, au sens large. Aucune structure n'est épargnée. Elles ont tous des prots de lecture/écriture en plus, afin d'encaisser l'émission, le ''commit'' ou le renommage simultané de plusieurs µops. Par exemple, le ROB doit être modifié pour émettre et terminer plusieurs instructions en même temps, en ajoutant des ports de lecture/écriture. Pour un CPU superscalaire à 8 voies, on se dit que le ROB peut retirer 8 µops par cycle maximum. Mais certains processeurs récents ont un ROB qui peut retirer le double ! Un exemple est celui des CPU de micro-architecture Skymont, qui peuvent émettre 8 µops par cycle, mais en retirer 16. Quelques CPU de marque AMD étaient aussi dans ce cas. L'avantage est que cela permet de réduire la taille du ROB, du banc de registre et de quelques autres structures matérielles liées à l'exécution dans le désordre. Le gain sur-compense le cout en transistor nécessaire pour retirer 16 µops par cycle. Dans cette section, nous allons voir comment les étages du pipeline dédiés à l'exécution dans le désordre sont modifiées sur un CPU superscalaire. ===L'exemple du PA-RISC PA 8000=== Avant de commencer, nous allons voir un processeur superscalaire assez simple, le PA 8000, de HP, qui implémente le jeu d'instruction PA-RISC. Bien que très ancien, il implémentait l'exécution dans le désordre et le renommage de registre. Le peu d'informations que nous avons sur ce processeurs proviennent des documents "THE HP PA-8000 RISC CPU" par Ashok Kumar, et l'article de microprocessor report "PA-8000 Combines Complexity and Speed". Ils ne donnent malheureusement pas énormémment d'informations et je devrais être amené à faire quelques suppositions dans ce qui suit. Avant de commencer, parlons de détails sans lien avec la superscalairité. Ce processeur, comme beaucoup de processeurs PA-RISC, n'intégrait pas de cache de niveau L2 dans le processeur, qui était déporté en-dehors du CPU, sur la carte mère. Le processeur préférait utiliser ses transistors pour avoir un cache L1 assez large, quitte à ce qu'il soit plus lent. La lenteur du cache était prévue, le processeur compensait celle-ci en utilisant l'exécution dans le désordre, bien que ce ne soit pas parfait. Les CPU PA-RISC avant le PA 8000 utilisaient un pipeline à vagues ''wave pipeline'', ce qui était assez peu commun, mais le PA 8000 repasse à un pipeline synchrone classique. Passons maintenant à la superscalarité. Le PA 8000 est un processeur quadruple émission, qui peut émettre, à chaque cycle, deux opérations et deux accès mémoire. Le renommage de registre utilise des registres de renommage séparés des registres architecturaux, comme c'était la mode à l'époque. Le budget en transistor faisait que c'était soit ça, soit le renommage dans le ROB, faute de mieux. L'exécution dans le désordre, quant à elle, est prise en charge par une structure matérielle unique, qui ressemble à une fusion entre un ROB et une fenêtre d'instruction. Et c'est là que je vais devoir faire des suppositions. Le document "THE HP PA-8000 RISC CPU" nomme cette structure : le ''Instruction Reorder Buffer''. Il est décrit comme une fenêtre d'instruction dans le texte, à savoir qu'il détecte les dépendances entre instruction et se charge de les émettre. Il gère aussi la détection des mauvaises prédictions de branchement et peut annuler les instructions chargées à tord, en les retirant de la fenêtre d'instruction. Il utilise pas moins de 850 000 transistors, et prend 20% de la taille du ''die''. La fenêtre d'instruction peut mémoriser 56 µops, dans 56 entrées. La moitié d'entre elles est réservée aux instructions de calcul entier/flottant, l'autre est réservée aux µops mémoire. Une manière de voir les choses est qu'il y avait deux fenêtres d'instructions, de 28 entrées/µops chacune. L'une était spécialisée pour les ALU/FPU, l'autre pour les µops LOAD et STORE. Cependant, il s'agit là d'une interprétation, il n'est pas dit si les deux étaient séparées ou au contraire fusionnées en un seul circuit. Chaque fenêtre d'instruction pouvait recevoir 4 µops par cycle de la part des décodeurs, et répartissait ces 4 µops dans les deux fenêtres d'instructions. ===La superscalarité avec une file/fenêtre d'instruction centralisée=== Plus haut, nous avons montré qu'un processeur pouvait avoir plus de ports d'émission que de ports de décodage. On dit aussi que sa ''largeur de décodage'' était supérieure à sa ''largeur d'émission''. La '''largeur de décodage''' est le nombre de µops fournies par l'unité de décodage par cycle d'horloge, la '''largeur d'émission''' est le nombre maximal de µops émises par cycle d'horloge. Et n'allez pas croire qu'un surplus de ports d'émission est du gâchis. Sur les processeurs avec exécution dans le désordre, ce surplus peut être utilisé. Mais avant toute chose, évacuons un détail. Vous avez sans doute pensé que le surplus peut être exploité par les instructions machines décodées en plusieurs µops . Par exemple, si une instruction est décodée en deux µops, on pourrait avoir un port d'émission en plus pour en profiter. Mais les ports de décodage sont *en sortie du décodeur*, et contiennent des µops, pas des instructions. Le surplus de ports d'émission peut occasionnellement utiliser le surplus de ports de décodage, mais cela implique que des µops ont été mises en attente dans l'unité d'émission, pour être émises par la suite. Et cela implique l'usage d'une fenêtre d'instruction ou d'une file de µops. Le principe est que les µops sont accumulées dans la fenêtre d'instruction, en attendant leurs opérandes ou la résolution d'une dépendance. Et si l'occasion se présente, une µops est émise sur chaque port d'émission. Il y a donc un gain en performances, mais il faut faire quelques précisions sur son origine. La largeur d'émission utilisée ne peut pas dépasser, *en moyenne*, la largeur de décodage. Et c'est intuitif : un CPU qui décode 4 µops par cycle ne peut pas émettre 6 par cycle en moyenne, sur le temps long, il n'y a pas de µops en surplus qui sortent du vide. Par exemple, sur un processeur quadruple émission, si on analyse combien d'instructions sont émises par cycle, il peut y avoir des cycles où la largeur d'émission est totalement utilisée, mais ce sera compensé par des périodes où elle est fortement sous-utilisée. Les µops sont accumulées en cas de sous-utilisation, puis consommées en cas d'utilisation complète. Les deux périodes se compensent. Et c'est là que l'on peut comprendre d'où vient le gain en performance. Les cycles où les ports d'émission sont sous-utilisés existent systématiquement, que le processeur utilise l'exécution dans le désordre ou pas. Ils sont liés à la présence de dépendances de données, aux contraintes d’appariement, etc. Elles tendent à réduire la moyenne du nombre de µops émises par cycle. Par contre, ce sont les cycles de rattrapage, où les ports en surplus sont utilisés, qui font remonter la moyenne. Le gain en performance est donc lié à ces cycles de rattrapage, où les µops accumulées sont émises dans les ports en surplus. Et ils n'existent que sur les processeurs avec une file/fenêtre d'instruction. Réduire le nombre de ports d'émission permet de garder des fenêtres d'instruction et un ROB simples, rapides et économes en énergie. Et mine de rien, c'est là un compromis important : à quoi bon augmenter le nombre de ports d'émission si c'est pour que ce soit compensé par une fréquence plus faible ? Par contre, réduire le nombre de ports augmente la ''port contention'', surtout si on a mal réparti les ALU. Il faut donc trouver un compromis entre réduire le nombre de ports d'émission d'un côté, réduire la ''port contention'' de l'autre. La différence entre largeur de décodage et d'émission a un impact assez fort sur le banc de registre, et précisément sur son nombre de ports de lecture. Le banc de registre a besoin de plus de ports de lecture avec une fenêtre d’instruction qu'avec des stations de réservation. Rappelons la terminologie utilisée dans ce cours. Les fenêtres d'instruction se contentent de mémoriser la micro-opération et quelques bits pour détecter la disponibilité des opérandes. Par contre, les stations de réservations mémorisent aussi les opérandes des instructions. Et cette différence a une influence le nombre de ports de lecture du banc de registre. Supposons que toutes les instructions sont dyadiques, à deux opérandes. Comptons le nombre de ports nécessaires pour alimenter les unités de calcul, sans utiliser d'arbitre de banc de registre. Avec une fenêtre d'instruction, il faut le double du nombre de ports d'émission. Mais avec des stations de réservation, il faut le double des ports de décodage. La raison est que les registres sont lus après émission avec une fenêtre d'instruction, avant avec des stations de réservation (sous-entendu, après le décodage). Or, comme dit plus haut, les processeurs superscalaires larges ont souvent plus de ports d'émission que de décodage. ===La superscalarité à fenêtres d'instruction décentralisées=== Les processeurs précédents utilisaient une unité d'émission simple, qui pouvait utiliser l'émission dans l'ordre ou dans le désordre. Elle peut être remplacée par une fenêtre d'instruction centralisée dans que cela quoi que ce soit aux explications précédentes, idem avec une station de réservation centralisée. En soi, l'exécution dans le désordre est donc totalement compatible avec une implémentation simple de la superscalarité. Par contre, des subtilités surviennent avec les fenêtres d'instruction décentralisées. Pour rappel, sur ces processeurs, les µops sont émises en deux phases. Une première phase de ''dispatch'' qui envoie les µops vers la fenêtre d'instruction adéquate, sans détecter les dépendances de données. La seconde phase de ''schedule'' gère les dépendances de données, elle met en attente les µops en attendant que l'unité soit disponible pour les exécuter, en attendant aussi que les opérandes soient disponibles. Et à ce petit jeu, il y a une différence entre le nombre de µops qui sont ''dispatch par cycle'' et celles qui sont ''schedule''. Dit autrement, la largeur d'émission est scindée en une '''largeur de ''dispatch''''' et une '''largeur de ''schedule''. Par exemple, prenons un processeur triple émission avec deux stations de réservation : une pour les µops entières/mémoire, et une autre pour les µops flottantes. L'unité d'émission peut ''dispatch'' maximum trois µops par cycle : soit trois µops entières/mémoire, soit trois flottantes, soit un mix de trois µops différentes. Les stations de réservation, quant à elles, peuvent chacune ''schedule'' 3 µops par cycle, vers trois ALUs entières pour la station de réservation entière/mémoire, vers trois FPS pour la station de réservation flottante. De quoi ''dispatch'' trois µops, mais d'en ''schedule'' six, à chaque cycle. Et cet exemple ne sort pas de nulle part : les CPU x86 d'Intel et AMD sont globalement dans ce cas, même si les chiffres varient d'une microarchitecture à l'autre. L'exemple précédent colle parfaitement à la microarchitecture K7 d'AMD, utilisée sur les processeurs Athlon dans les années 2000. [[File:AMD K7.png|centre|vignette|upright=2.5|AMD K7, microarchitecture.]] L'exemple précédent avait assez d'unités entières/flottantes pour couvrir toute la largeur de décodage/''Dispatch''. Mais ce n'est pas toujours le cas, comme va le montrer l'exemple suivant. Le MIPS R10000, qui utilisait un mélange de files de µops et de fenêtres d'instructions : une file de µops les accès mémoire, une fenêtre pour les instructions entières et une autre pour les opérations flottantes. Les branchements et NOPs étaient exécutés dans une unité de branchement distincte. Les trois files/fenêtres peuvent mémoriser 16 µops. Le processeur avait deux ALU entières, une AGU de calcul d'adresse, un additionneur flottant et un multiplieur/diviseur flottant. Il y avait un multiplieur entier sur le port d'émission l'ALU 2. Le processeur décodait 4 instructions par cycle et produisait jusqu'à 4µops, qui étaient redistribuées sur les trois fenêtres d'instructions. Chacune pouvait accepter 4 µops par cycle, ce qui fait que processeur pouvait ''dispatch'' 4 µops entières, ou 4 µops flottantes, ou 4 µops mémoire, ou un mélange de deux ou trois types de µops. Pour ce qui est du ''schedule'', la fenêtre d'instruction entière pouvait émettre 2 µops, la fenêtre flottante pouvait émettre une addition en même temps qu'une multiplication/divison flottante et qu'un branchement conditionnel flottant, et la file de µops mémoire ne pouvait émettre qu'une µop mémoire à la fois. En tout, cela fait 6 µops ''schedule'' pour 4 µops au ''dispatch''. [[File:R 10000.png|centre|vignette|upright=2.5|MIPS R10000, microarchitecture.]] ===La superscalarité à fenêtres d'instruction totalement décentralisées=== Prenons un cas extrême de fenêtre d'instruction décentralisée : celui où chaque ALU entière a sa propre station de réservation. En clair : une fenêtre d'instruction par ALU/FPU ! On parle de '''fenêtres d'instruction totalement décentralisées'''. Vous vous dites que ce cas est un peu trop extrême pour être réaliste, mais il n'en est rien. C'est même très courant sur les architectures basse consommation, et sur pas mal de CPU x86 modernes. Une telle organisation entraine une légère perte de performance, comparé à une fenêtre d'instruction centralisée ou partiellement décentralisée. Et cela peut se comprendre par un exemple. Imaginez un processeur avec deux ALU, donc deux stations de réservation. Il arrivera qu'une station de réservation ait plusieurs µops prêtes, alors que l'autre en ait zéro. Dans une telle situation, une seule µop sera émise au cycle suivant, vu que chaque station de réservation a un seul port d'émission vers une seule ALU entière. Par contre, avec une fenêtre d'instruction centralisée double port, on aurait pu émettre les deux µops en même temps sur deux ALUs séparées. La perte de performance est donc liée au fait que les µops '''''prêtes''''' sont mal réparties dans les différentes stations de réservation. Il arrivera que des µops prêtes s'accumulent dans une station de réservation, alors que d'autres seront pleines, ou du moins sous-utilisées. Et ce n'est pas quelque chose qui peut être réglé à l'étape de ''dispatch'', car on ne sait pas encore quand les µops auront leurs opérandes de disponibles. [[File:Comparaison entre une station de réservation totalement décentralisée et une autre qui ne l'est pas.png|centre|vignette|upright=2.5|Comparaison entre une station de réservation totalement décentralisée et une autre qui ne l'est pas.]] Par contre, décentraliser totalement les fenêtres d'instruction entraine aussi un gain considérable en termes de consommation énergétique. Et c'est la raison pour laquelle les fenêtres d'instructions totalement décentralisées sont utilisées sur les architectures basse consommation. La perte de performance ne peut pas s'expliquer clairement à ce stade du cours, car il nous faudrait parler d'émission superscalaire. Le gain en matière d'énergie vient de l'économie de circuits, qui est assez drastique. Le gain en matière d'énergie vient de l'économie de circuits, qui est assez drastique. Je rappelle qu'une station de réservation a besoin, pour N instructions, d'environ N^2 circuits (des comparateurs, notamment). Prenons une station de réservation centralisée de 64 entrées et comparons avec 8 stations de 8 entrées chacune. Les deux donneront 64 entrées, mais la première aura un cout en circuit proportionnel à 64², alors que le second aura un cout en circuit de 8 *(8²). Entre les deux, le choix est clair : la seconde solution est plus économe. D'où l'utilisation de cette solution sur les microarchitectures basse consommation. ===L'unité de renommage superscalaire=== Avec la superscalarité, l'unité de renommage de registre doit gérer le cas où des instructions consécutives ont des dépendances de registre. Par exemple, prenons un processeur à double émission, qui renomme deux instructions consécutives. Si elles ont une dépendance de registre, le renommage de la seconde instruction dépend du renommage de la première. La première doit être renommée et le résultat du renommage est utilisé pour renommer la seconde, ce qui empêche d'utiliser deux unités de renommage séparées. Pour cela, elle renomme les registres sans tenir compte des dépendances, pour ensuite corriger le résultat. [[File:Unité de renommage superscalaire.png|centre|vignette|upright=2|Unité de renommage superscalaire.]] Seules les dépendances lecture-après-écriture doivent être détectées, les autres étant supprimées par le renommage de registres. Repérer ce genre de dépendances se fait assez simplement : il suffit de regarder si un registre de destination d'une instruction est un opérande d'une instruction suivante. [[File:Détection des dépendances sur un processeur superscalaire.png|centre|vignette|upright=2|Détection des dépendances sur un processeur superscalaire.]] Ensuite, il faut corriger le résultat du renommage en fonction des dépendances. Si une instruction n'a pas de dépendance avec une autre, on la laisse telle quelle. Dans le cas contraire, un registre opérande sera identique avec le registre de destination d'une instruction précédente. Dans ce cas, le registre opérande n'est pas le bon après renommage : on doit le remplacer par le registre de destination de l'instruction avec laquelle il y a dépendance. Cela se fait simplement en utilisant un multiplexeur dont les entrées sont reliées à l'unité de détection des dépendances. On doit faire ce replacement pour chaque registre opérande. [[File:Correction des dépendances sur un processeur superscalaire.png|centre|vignette|upright=2|Correction des dépendances sur un processeur superscalaire.]] ==Les optimisations des processeurs superscalaires larges== Les processeurs superscalaires larges ont des optimisations spécifiques, qui n'ont pas de sens sur les processeurs superscalaires étroits. Dans les grandes lignes, elles se classent en deux types. Les premières permettent de charger/décoder plus de 5-10 instructions simultanément. Le problème est alors que les branchements viennent mettre leur grain de sel et qu'il faut en tenir compte. Les secondes corrigent des problèmes qui apparaissent quand un CPU intègre plus de 5 à 10 unités de calcul. ===L'étape de chargement d'un CPU superscalaire large=== Charger plusieurs instructions pose de nombreux problèmes sur les processeurs superscalaires larges, qui émettent de 5 à 10 instructions simultanées. Pour rappel, la stratégie basique pour charger N instructions est de charger un bloc de N instructions consécutives. Les instructions après un branchement ne sont pas décodées ni exécutées, ce qui entraine une petite baisse de performance. Pour un N petit, la perte de performance est mineure. Mais pour un N large, elle devient suffisamment importante pour que la conception du CPU doit alors être repensée de fond en comble. Les analyses statistiques disent qu'il y a environ un branchement tous les 4 à 6 instructions. Un CPU a donc tendance à décoder des paquets de 3 à 5 instructions consécutives, avant qu'un branchement casse la dynamique. Or, cela pose des problèmes pour utiliser plusieurs décodeurs. L'implémentation basique, qui charge N instructions consécutives pour alimenter N décodeurs, fonctionne donc jusqu'à 4/6 décodeurs. Au-delà de 5 instructions, un CPU superscalaire doit être adapté pour gérer les branchements dans les paquets d'instruction qu'il émet. Le nombre de 5 instructions ne sort donc pas de nulle part. La première solution utilise un cache de µops, avec un ''front-end'' capable de charger/décoder 4/5 instructions à la fois, pas plus. L'idée est que la majorité des instructions proviennent du cache de µops (plus de 80%), ce qui fait qu'on peut émettre environ 10 instructions à partir du cache de µops, pas besoin d'avoir beaucoup de décodeurs. Les performances sont cependant dégradées lors d'un défaut de cache de µops. Les instructions doivent alors être chargées depuis le cache d'instruction, par paquets de 4-5, puis sont décodées par 4-5 décodeurs, ce qui ne permet pas d’alimenter les unités de calcul à plein régime. La solution précédente joue sur la distinction entre pots de décodage et d'émission. Elle permet d'émettre un grand nombre de µops sans pour autant charger un grand nombre d'instructions en même temps. En quelque sorte, ce n'est qu'une méthode de contournement, le CPU superscalaire reste de type étroit. Mais il est aussi possible d'utiliser un '''''front-end large''''', capable de charger une bonne dizaine d'instructions en même temps. La seule difficulté est de tenir compte de la présence de branchements. Pour rappel, avec un ''front-end'' étroit, les instructions situées après le premier branchement pris sont annulées, elles ne sont pas décodées ni exécutées. [[File:Fetch sur un processeur superscalaire avec prediction de branchements.png|centre|vignette|upright=2|Fetch sur un processeur superscalaire avec prédiction de branchements.]] Un ''front-end'' large charge les instructions de destination du branchement et les placent à sa suite. Ils chargent deux blocs à la fois et les fusionnent en un seul qui ne contient que les instructions présumées utiles. [[File:Cache d'instructions autoaligné.png|centre|vignette|upright=2|Cache d'instructions auto-aligné.]] Mais cela demande de charger deux blocs de mémoire en une fois, ce qui demande un cache d'instruction multiports. Il faut aussi ajouter un circuit pour assembler plusieurs morceaux de blocs en un seul : le fusionneur (''merger''). En pratique, cette solution demande d'ajouter un second port de lecture au cache, pour un cout en hardware important, avec un impact négatif sur le temps d'accès au cache. Et il faut rajouter le fusionneur, qui prend un étage de pipeline à lui tout seul. Et encore, cette solution ne gère pas le cas où un bloc contient plusieurs branchements ! [[File:Implémentation d'un cache d'instructions autoaligné.png|centre|vignette|upright=2|Implémentation d'un cache d'instructions auto-aligné.]] Les exemples précédents partent du principe qu'il n'y a qu'un seul branchement dans un bloc. Mais quand les blocs deviennent assez longs, il est fréquent d'avoir plusieurs branchements dans un bloc. Et il est même possible d'avoir plusieurs branchements pris. Dans un bloc de 8-10 instructions, ce n'est pas rare, et les CPU superscalaires à 8-10 voies sont la règle dans les CPU des années 2020. Pour gérer ce cas, il faut ajouter des ports supplémentaires au cache d'instruction et adapter le fusionneur, pour qu'il puisse fusionner trois ou quatre blocs. De plus, il faut utiliser une unité de prédiction de branchement capable de ''prédire plusieurs branchements par cycle''. ===Le décodage superscalaire large=== Le décodage des instructions n'est pas censé dépendre de l'implémentation du chargement. En théorie, une fois plusieurs blocs d'instruction fusionnés, on peut décoder les instructions en parallèle. Cependant, certains processeurs effectuent le décodage en tenant compte de la manière dont les branchements découpent les blocs. Les processeurs Atom d'Intel utilisent une solution de ce type, qui couple prédiction de branchement et décodage parallèle. Ils chargent/décodent des paquets de 3 instructions consécutives, chaque paquet étant séparé du précédent par un branchement. Pour cela, en plus d'avoir un fusionneur adapté, ils regroupent les décodeurs en ''clusters'', chacun regroupant 3 décodeurs, et pouvant décoder trois instructions consécutives. Les micro-architectures Tremont et Crestmont avaient deux ''clusters'' (6 décodeurs au total), la micro-architecture Darkmont en intègre trois (9 décodeurs au total). Avec deux ''clusters'', le fonctionnement est le suivant. Si le code est composé d'une suite d'instruction sans branchements, seul le premier ''cluster'' est utilisé, limitant le décodage à trois instructions par cycle. Par contre, si l'une des trois instructions décodée est un branchement, alors le second ''cluster'' décode les trois instructions situées après ce branchement, à partir de l'adresse de destination. Avec un troisième ''cluster'', c'est la même chose, sauf qu'il faut qu'il y ait un branchement dans les trois instructions décodées par le second ''cluster''. Mais comment faire pour savoir quels décodeurs activés, quels ''clusters'' sont actifs ? C'est la prédiction de branchement qui commande. Avec deux ''clusters'', elle détermine si un branchement est présent dans les trois instructions à charger, et quelle est son adresse de destination. Sans branchement, elle prévient les décodeurs et les trois instructions chargées sont décodées dans un ''cluster'' libre. Si elle prédit un branchement, elle charge les instructions adéquates, et active les deux ''clusters''. Avec trois branchements, c'est le même mécanisme, sauf que l'unité de prédiction de branchement doit être capable de prédire deux branchements par cycle. [[File:Front-end découplé de la microarchitecture Tremont.png|centre|vignette|upright=3|Front-end découplé de la microarchitecture Tremont.]] Il faut noter que les décodeurs d'un ''cluster'' sont des décodeurs simples, sans microcode. Sur les processeurs Tremont et Crestmont, le microcode était unique et était partagé entre tous les ''clusters''. Un seul ''cluster'' pouvait décoder une instruction complexe avec le microcode, l'autre devait se limiter à des instructions simples uniquement. Depuis Skymont, le microcode est partiellement dupliqué, avec un microcode par ''cluster''. Le cout en hardware peut paraitre prohibitif, pour un gain en performance faible. Sauf que c'est oublier que ce sont des processeurs Atom, sur lesquels beaucoup d'instructions sont microcodées. Les processeurs Atom ont un budget en transistor limité, ce qui fait qu'il est préférable pour eux d'implémenter des instructions en microcode que d'utiliser des unités de calcul dédiées ou des circuits de décodage complexes. Pour limiter la casse, le microcode n'est que partiellement dupliqué. Seul le microcode pour les instructions fréquente est dupliqué. Il y a un microcode secondaire pour certaines instructions, qui est lui unique et partagé par tous les ''clusters''. ===Le contournement sur les processeurs superscalaires larges=== Pour rappel, la technique du contournement (''register bypass'') permet au résultat d'une instruction d'être immédiatement utilisable en sortie de l'ALU, avant même d'être enregistré dans les registres. Implémenter la technique du contournement demande d'utiliser des multiplexeurs pour relier la sortie de l'unité de calcul sur son entrée si besoin. Il faut aussi des comparateurs pour détecter des dépendances de données. [[File:Pipeline Bypass.png|centre|vignette|upright=1|Pipeline Bypass]] La sortie de chaque ALU doit être reliée aux entrées de toutes les autres, avec les comparateurs qui vont avec. Sur les processeurs ayant plusieurs d'unités de calculs, cela demande beaucoup d’interconnexions et de comparateurs. Pour N unités de calcul, cela demande 2 * N² interconnexions, implémentées avec 2N multiplexeurs de N entrées chacun. Si c'est faisable pour 2 ou 3 ALUs, la solution est impraticable au-delà. Non seulement ce serait un enfer à câbler, mais les fils seraient tellement longs que la fréquence du processeur en prendrait un coup. Notez que cela vaut pour les processeurs superscalaires, mais aussi pour tout processeur avec beaucoup d'unités de calcul. En théorie, un CPU à exécution dans le désordre, non-superscalaire, mais avec beaucoup d'unités de calcul, fait face au même problème. En pratique, avoir une dizaine d'ALU implique processeur superscalaire à exécution dans le désordre. D'où le fait qu'on parle du problème maintenant. La seule solution praticable est de ne pas relier toutes les unités de calcul ensemble. À la place, on préfère regrouper les unités de calcul dans différents '''agglomérats''' ('''cluster'''). Le contournement est alors possible entre les unités d'un même agglomérat, mais pas entre agglomérats différents. Évidemment, certaines possibilités de contournement sont perdues, mais c'est compensé par un gain en fréquence et un cout en circuit/fils réduit. C'est un bon compromis, ce qui explique que presque tous les processeurs modernes l'utilisent. Les rares exceptions sont les processeurs POWER 4 et POWER 5, qui ont préféré se passer de contournement pour garder un processeur très simple et une fréquence élevée. ===Le banc de registre des processeurs superscalaires larges=== Pour émettre deux opérations entières simultanément, il faut lire deux fois plus d'opérandes. Et il faut aussi écrire deux résultats dans les registres, en même temps. Pour cela, on double les ports du banc de registre. En général, il faut au maximum 2 ports de lecture et un port d'écriture par unité de calcul. Le problème, c'est que plus un banc de registres a de ports, plus il utilise de circuits, est compliqué à concevoir, consomme de courant et chauffe. Avec plusieurs dizaines d'unités de calcul différentes, ajouter autant de ports impacterait la fréquence du banc de registres et réduirait les performances, voire est totalement impraticable à cause des contraintes thermiques. Les processeurs superscalaires larges doivent donc trouver des solutions. La première solution utilise un banc de registre unique, mais n'utilise pas autant de ports que le pire des cas le demanderait. Le processeur détecte quand il n'y a pas assez de ports pour servir toutes les micro-opérations. Quand ça arrive, l'unité d'émission émet assez de micro-opérations pour exploiter les ports disponibles, mais met en attente les micro-opérations en trop, le temps que les ports se libèrent. Pour cela, le banc de registre est géré par un circuit d'arbitrage spécialisé, intégré à l'unité d'émission, l’'''arbitre du banc de registres''' (''register file arbiter''). Une autre solution est de dupliquer le banc de registres en plusieurs exemplaires qui contiennent exactement les mêmes données, mais avec moins de ports de lecture/écriture. Un exemple est celui des processeurs POWER, Alpha 21264 et Alpha 21464. Sur ces processeurs, le banc de registre est dupliqué en plusieurs exemplaires, qui contiennent exactement les mêmes données. Les écritures dans les registres sont envoyées à tous les bancs de registres, afin de garantir que leur contenu est identique. Chaque exemplaire a exactement deux ports de lecture. La conception du processeur est simplifiée, que ce soit au niveau du câblage, que de la conception des bancs de registres. Une dernière solution découpe le banc de registres en plusieurs bancs de registres plus petits, avec un réseau d'interconnexions pour échanger des données entre bancs de registres. Dans la plupart des cas, cette séparation est invisible du point de vue de l'assembleur et du langage machine. Le processeur se charge de transférer les données entre bancs de registres suivant les besoins. Sur d'autres processeurs, les transferts de données se font via une instruction spéciale, souvent appelée ''COPY''. [[File:Banc de registres distribué.png|centre|vignette|upright=2|Banc de registres distribué.]] Sur de certains processeurs, un branchement est exécuté par une unité de calcul spécialisée. Or les registres à lire pour déterminer l'adresse de destination du branchement ne sont pas forcément dans le même agglomérat que cette unité de calcul. Pour éviter cela, certains processeurs disposent d'une unité de calcul des branchements dans chaque agglomérat. Dans les cas où plusieurs unités veulent modifier le ''program counter'' en même temps, un système de contrôle général décide quelle unité a la priorité sur les autres. Mais d'autres processeurs fonctionnent autrement : seul un agglomérat possède une unité de branchement, qui peut recevoir des résultats de tests de toutes les autres unités de calcul, quel que soit l’agglomérat. ==La macro-fusion : une optimisation du décodage parallèle== Les processeurs superscalaires supportent la technique dite de '''macro-fusion''', qui permet de fusionner deux-trois instructions consécutives en une seule micro-opération. Par exemple, il est possible fusionner une instruction de test et une instruction de saut en une seule micro-opération de branchement. Il s'agit là de l'utilisation la plus importante de la macro-fusion sur les processeurs x86 modernes. La macro-fusion est utilisée pour fusionner un test et un saut en un branchement unique. L'optimisation est présente sur la plupart des CPU superscalaires modernes. Les CPU x86 l'implémentent, mais aussi quelques CPU ARM et les processeurs Apple de série M (M1 à M5, et potentiellement plus quand ils seront sortis). La fusion des instructions se fait lors du décodage des instructions, grâce à la coopération des décodeurs. Elle marche systématiquement si l'instruction de test et le saut sont consécutives, qu'elles forment bien une paire d'instruction. Par contre, insérer une instruction entre les deux empêche la macro-fusion de faire son travail, sauf si l'instruction insérée est un NOP. Les processeurs ARM64 avaient une forme spécifique de macro-fusion, utilisée pour un cas très précis : charger une constante immédiate de 32 ou 64 bits, dans un registre 64 bits. Les CPU ARM 64 bits utilisent des instructions codées sur 32 bits, qui ne peuvent encoder que des constantes immédiates de 16 bits. Pour charger une constante de 32/64 bits, il faut s'y prendre en plusieurs fois. Une première instruction MOVZ charge les 16 premiers bits, puis 2 à 4 instructions MOVK remplissent le reste. MOVZ met à zéro les 48 bits de poids fort, MOVK permet de sélectionner le doublet à modifier dans le registre (on modifie 16 bits, dont on choisit la place, le reste du registre est laissé tel quel). ARM permet de fusionner cette suite d'instructions en une seule µop MOV avec une constante immédiate. On parle alors de '''''MOVZ + MOVK fusion'''''. Une dernière utilisation, [https://www2.eecs.berkeley.edu/Pubs/TechRpts/2016/EECS-2016-130.pdf proposées pour le jeu d'instruction RISC-V], fusionnait un calcul d'adresse et une instruction LOAD/STORE en une seule instruction d'accès mémoire. Elle a été envisagée à une époque où le jeu d'instruction RISC-V ne gérait pas les modes d'adressage base + indice. L'idée était d'avoir une unité mémoire qui gérait le mode d'adressage base + indice et de fusionner des instructions pour l'exploiter. Mais de nos jours, le jeu d'instruction RISC-V intègre le mode d'adressage base + indice, ce qui fait que la macro-fusion n'a aucun intérêt pour ce cas précis. La macro-fusion a de nombreuses limitations en pratique. En théorie, on pourrait l'utiliser au-delà des deux situations mentionnées plus haut. Par exemple, pour fusionner une addition et une multiplication en une seule instruction MAD. Mais l'intérêt est assez faible. Notons que la macro-fusion ne permet que de fusionner des paires d'instructions. Aller au-delà demanderait un cout en circuit trop important. Déjà que tester deux paires utilise pas mal de comparateurs... ==Le ''stack engine'' : une optimisation de la pile d'appel== Les processeurs modernes intègrent une optimisation liée au pointeur de pile. Pour rappel, sur les architectures modernes, le pointeur de pile est un registre utilisé pour gérer la pile d'appel, précisément pour savoir où se trouve le sommet de la pile. Il est manipulé par les instructions CALL, RET, PUSH et POP, mais aussi par les instructions d'addition/soustraction pour gérer des cadres de pile de taille variable. De plus, il peut servir d'opérande pour des instructions LOAD/STORE, afin de lire/écrire des variables locales, les arguments d'une fonction, et autres. C'est donc un registre général adressable, intégré au banc de registre, altéré par l'unité de calcul entière. L'incrémentation/décrémentation du pointeur de pile passe donc par l'unité de calcul, lors des instructions CALL, RET, PUSH et POP. Mais, l'optimisation que nous allons voir permet d'incrémenter/décrémenter le pointeur de pile sans passer par l'ALU, ou presque. L'idée est de s'inspirer des architectures avec une pile d'adresse de retour, qui intègrent le pointeur de pile dans le séquenceur et l'incrémentent avec un incrémenteur dédié. ===Le ''stack engine''=== L'optimisation que nous allons voir utilise un '''''stack engine''''' intégré à l'unité de contrôle, au séquenceur. Le processeur contient toujours un pointeur de pile dans le banc de registre, cela ne change pas. Par contre, il n'est pas incrémenté/décrémenté à chaque instruction CALL, RET, PUSH, POP. Un compteur intégré au séquenceur est incrémenté à la place, nous l’appellerons le '''compteur delta'''. La vraie valeur du pointeur de pile s'obtient en additionnant le compteur delta avec le registre dans le banc de registre. Précisons que si le compteur delta vaut zéro, la vraie valeur est dans le banc de registre et peut s'utiliser telle quelle. Lorsqu'une instruction ADD/SUB/LOAD/STORE utilise le pointeur de pile comme opérande, elle a besoin de la vraie valeur. Si elle n'est pas dans le banc de registre, le séquenceur déclenche l'addition compteur-registre pour calculer la vraie valeur. Finalement, le banc de registre contient alors la bonne valeur et l'instruction peut s'exécuter sans encombre. L'idée est que le pointeur de pile est généralement altéré par une série d'instruction PUSH/POP consécutives, puis des instructions LOAD/STORE/ADD/SUB utilisent le pointeur de pile final comme opérande. En clair, une bonne partie des incrémentations/décrémentation est accumulée dans le compteur delta, puis la vraie valeur est calculée une fois pour toutes et est utilisée comme opérande. On accumule un delta dans le compteur delta, et ce compteur delta est additionné quand nécessaire. Précisons que le compteur delta est placé juste après le décodeur d'instruction, avant même le cache de micro-opération, l'unité de renommage et l'unité d'émission. Ainsi, les incrémentations/décrémentations du pointeur de pile disparaissent dès l'unité de décodage. Elles ne prennent pas de place dans le cache de micro-opération, ni dans la fenêtre d'instruction, ni dans la suite du pipeline. De nombreuses ressources sont économisées dans le ''front-end''. Mais utiliser un ''stack engine'' a aussi de nombreux avantages au niveau du chemin de données/''back-end''. Déjà, sur les processeurs à exécution dans le désordre, cela libère une unité de calcul qui peut être utilisée pour faire d'autres calculs. Ensuite, le compteur delta mémorise un delta assez court, de 8 bits sur le processeur Pentium M, un peu plus pour les suivants. L'incrémentation se fait donc via un incrémenteur 8 bits, pas une grosse ALU 32/64 bits. Il y a un gain en termes de consommation d'énergie, un incrémenteur 8 bits étant moins gourmand qu'une grosse ALU 32/64 bits. ===Les points de synchronisation du delta=== La technique ne fonctionne que si la vraie valeur du pointeur de pile est calculée au bon moment, avant chaque utilisation pertinente. Il y a donc des '''points de synchronisation''' qui forcent le calcul de la vraie valeur. Plus haut, nous avions dit que c'était à chaque fois qu'une instruction adresse le pointeur de pile explicitement, qui l'utilise comme opérande. Les instructions CALL, RET, PUSH et POP ne sont pas concernées par elles utilisent le pointeur de pile de manière implicite et ne font que l'incrémenter/décrémenter. Mais dans les faits, c'est plus compliqué. D'autres situations peuvent forcer une synchronisation, notamment un débordement du compteur delta. Le compteur delta est généralement un compteur de 8 bits, ce qui fait qu'il peut déborder. En cas de débordement du compteur, le séquenceur déclenche le calcul de la vraie valeur, puis réinitialise le compteur delta. La vraie valeur est donc calculée en avance dans ce cas précis. Précisons qu'un compteur delta de 8 bits permet de gérer environ 30 instructions PUSH/POP consécutives, ce qui rend les débordements de compteur delta assez peu fréquent. À noter que si le compteur delta vaut zéro, il n'y a pas besoin de calculer la vraie valeur, le séquenceur prend cette situation en compte. Un autre point de synchronisation est celui des interruptions et exceptions matérielles. Il faut que le compteur delta soit sauvegardé lors d'une interruption et restauré quand elle se termine. Idem lors d'une commutation de contexte, quand on passe d'un programme à un autre. Pour cela, le processeur peut déclencher le calcul de la vraie valeur lors d'une interruption, avant de sauvegarder les registres. Pour cela, le processeur intègre un mécanisme de sauvegarde automatique, qui mémorise la valeur de ce compteur dans le tampon de réordonnancement, pour forcer le calcul de la vraie valeur en cas de problème. La technique du ''stack engine'' est apparue sur les processeurs Pentium M d'Intel et les processeurs K10 d'AMD, et a été conservée sur tous les modèles ultérieurs. L'implémentation est cependant différente selon les processeurs, bien qu'on n'en connaisse pas les détails et que l'on doive se contenter des résultats de micro-benchmarks et des détails fournit par Intel et AMD. Selon certaines sources, dont les manuels d'optimisation d'Agner Fog, les processeurs AMD auraient moins de points de synchronisation que les processeurs Intel. De plus, leur ''stack engine'' serait placé plus loin que prévu dans le pipeline, après la file de micro-opération. ==La micro-fusion et la délamination== La '''micro-fusion''' est une optimisation qui retarde le décodage réel de certaines instructions assez loin dans le pipeline. Elle concerne surtout les instructions ''load-op'', mais pas que. D'autres instructions mémoire peuvent subir cette optimisation. L'essentiel est que, sans micro-fusion, ces instructions sont décodées en plusieurs micro-opérations. La micro-fusion retarde le décodage final de ces instructions, qui se fait assez tard dans le pipeline. Pour comprendre l'intérêt, nous allons devoir faire quelques explications. L'optimisation en question fait le décodage en deux temps. Prenons l'exemple d'une opération ''load-op'', qui est censée être décodée en deux micro-opérations : une lecture, puis une opération. Le décodage produit une '''macro-opération''' (terme d'Intel), qui est propagée dans le pipeline, pour être scindée en deux micro-opérations un peu avant les ALU et l'unité mémoire. La macro-opération est techniquement une micro-opération comme une autre, sauf que ce n'est pas la micro-opération finale. L'unité d'émission découpe cette macro-opération en deux micro-opérations, qui sont émises l'une après l'autre. Pour résumer, les instructions ''load-op'' ne sont complétement découpées en micro-opération lors de l'émission, pas lors du décodage. L'optimisation impacte ce qui se situe entre le décodeur d'instruction et l'unité d'émission : l'unité de renommage, la file de micro-opérations, le ''Loop Stream Detector'' et/ou le cache de micro-opération. L'intérêt de l'optimisation est que l'on fusionne deux micro-opérations en une seule macro-opération. Le cache de micro-opération et la file de micro-opération peuvent mémoriser plus de micro-opérations, vu que certaines sont fusionnées. Quant à l'unité de renommage, elle renomme une seule macro-opération au lieu de renommer deux micro-opérations, ce qui augmente le débit du renommage de registre. Par contre, cela complique un peu le travail de l'unité d'émission, qui doit découper les instructions ''load-op'' en deux et émettre les micro-opérations l'une après l'autre. Il faut noter qu'il n'y a pas de fusion proprement dite. Le décodeur ne décode pas deux micro-opérations séparées, avant de les fusionner. En réalité, il génère directement une macro-opération, qui correspond à deux micro-opérations, que ce soit plus tard dans le pipeline ou sur une autre architecture. D'ailleurs, la micro-fusion a lieu à l'intérieur d'une instruction, qui est censée être traduite en plusieurs micro-opérations. Et encore : pas toutes. La conséquence est que la technique n'a de sens que sur les processeurs CISC, avec des instructions assez complexes pour être décodées en plusieurs micro-opérations. En pratique, seuls les CPU x86 sont concernés. ===Les domaines de fusion=== La micro-fusion n'est pas spécifique aux processeurs superscalaires. En théorie, on peut l'implémenter sur un processeur non-superscalaire à émission dans l'ordre. Cependant, je ne connais aucun processeur à émission dans l'ordre qui implémente la micro-fusion, même si son implémentation est en théorie possible sur de tels processeurs. La micro-fusion est implémentée différemment selon que l'émission se fasse dans l'ordre, dans le désordre, avec une fenêtre d'instruction, avec des stations de réservation, etc. J'ai dit plus haut que les micro-opérations sont générées lors de l'émission, mais le moment exact varie suivant le processeur. Pour simplifier le tout, nous parlerons de '''scission''' quand le processeur traduit une macro-opération en deux/trois micro-opérations. Le moment où a lieu la scission est théoriquement dans l'unité d'émission, mais celle-ci prend plusieurs formes selon que le processeur utilise l'émission dans l'ordre, dans le désordre, avec une fenêtre d'instruction, avec des stations de réservation, etc. Les processeurs à exécution dans l'ordre sont le cas le plus simple. L'unité d'émission est alors en charge du découpage des macro-opérations en micro-opérations. La file de micro-opération ou le cache de micro-opérations mémorisent des macro-opérations. À l'opposé, le tampon de ré-ordonnancement mémorise lui des micro-opérations. Le reste du processeur n'est pas affecté. Sur les processeurs à exécution dans le désordre, les différences sont nombreuses. Le tampon de ré-ordonnancement peut mémoriser soit les micro-opérations finales, soit des macro-opérations. Il en est de même avec la fenêtre d'instruction et/ou les stations de réservation, qu'elles soient centralisées ou décentralisées. Tout dépend de comment se fait l'implémentation. Une implémentation simple effectue la scission des macro-opérations dans l'unité d'émission, comme sur les processeurs à exécution dans l'ordre. Sur de nombreux processeurs, l'unité d'émission et de renommage sont simplement fusionnées, ce qui fait que la scission a lieu juste après le renommage de registres. En conséquence, le tampon de re-ordonnancement et les fenêtres d'instruction ne voient que des micro-opérations. Les macro-opérations disparaissent juste avant. Cette implémentation est préférée avec une fenêtre d'instruction centralisée, car on voit mal comment scinder une macro-opération juste avant l'ALU. Une autre implémentation fait la scission en sortie de la fenêtre d'instruction ou des stations de réservation, qu'elles soient centralisées ou décentralisées. Dans ce cas, le tampon de re-ordonnancement fait de même. L'avantage est que le tampon de ré-ordonnancement stocke des macro-opérations, ce qui augmente sa taille effective. Par exemple, il utilise une seule entrée pour une instruction ''load-op'', au lieu de deux sans micro-fusion de ce type. ===La délamination=== La scission peut parfois avoir lieu plus tôt, dans des circonstances très précises. Concrètement, cela ne concerne que quelques micro-architectures d'Intel, pour des instructions très précises. La raison est les limitations du format des micro-opérations, pas une histoire d'optimisation. Le processeur aimerait pouvoir faire la micro-fusion, mais ne peut pas à cause de ces limitations. Une telle situation cause alors une '''délamination''' : les micro-opérations sont scindées précocement. Par exemple, sur la micro-architecture SandyBridge d'Intel, les opérations ''load-op'' sont fusionnées, sauf si elles utilisent l'adressage indicé. Les micro-opérations de ce processeur ne peuvent avoir que deux opérandes. Trois opérandes est de trop, et les opérations ''load-op'' en adressage indicé dépassent cette limite. Dans ce cas, les micro-opérations sont fusionnées en sortie du décodeur, mais sont scindés avant d’entrer dans la file de micro-opération. L'avantage n'est pas évident, vu que l'unité de renommage suit de près le décodeur d'instruction. Il est que le cache de micro-opérations mémorise des macro-opérations, pas deux micro-opérations. ===La micro-fusion des processeurs Intel et AMD=== La micro-fusion est apparue sur le Pentium M d'Intel, et a été conservée telle quelle sur les processeurs Intel suivants. Les processeurs AMD supportent la micro-fusion depuis au moins la micro-architecture AMD K8. Mieux que ça, la délamination n'était pas utilisée car les micro-opérations acceptaient plus de 2 opérandes. Que ce soit chez AMD ou Intel, elle concerne deux types d'instructions : les écritures mémoire et les instructions ''load-op''. Sur le Pentium M, il y avait quelques limitations, l'optimisation se limitant par exemple aux registres entiers et flottants, mais pas aux registres MMX, mais pas les registres SSE (nous verrons ces registres dans quelques chapitres). Mais les processeurs modernes n'ont plus cette limitation. La micro-fusion des CPU Intel concerne deux types d'instructions : les écritures mémoire et les instructions ''load-op''. Pour les écritures, la situation est plus complexe que pour les instructions ''load-op''. Sur les processeurs Intel précédents, les écritures étaient réalisées dans deux unités séparées : le calcul d'adresse dans une unité de calcul, l'écriture proprement dite dans l'unité mémoire. Elles prenaient donc deux micro-opérations. Le processeur a changé ses unités mémoire, ce qui fait qu'elle pouvait faire les deux en une seule micro-opération. Il s'agissait alors d'une optimisation du chemin de données, plus que de la micro-fusion proprement dite, mais je la mentionne ici malgré tout. La micro-fusion sur ce processeur avait un avantage en plus des avantages usuels : elle utilisait mieux les décodeurs. Les Pentium M avaient trois décodeurs pour décoder plusieurs instructions en même temps, chose qu'on détaillera dans le chapitre sur les processeurs superscalaires. Un seul décodeur pouvait décoder toutes les instructions, les deux autres ne peuvent décoder que les instructions simples, qui se décodent en une seule micro-opération. Avec la micro-fusion, les trois décodeurs peuvent gérer les écritures mémoire et les opérations ''load-op'', vu qu'elles deviennent des instructions simples. Sans cela, elles auraient été limitées au premier décodeur. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Le parallélisme mémoire | prevText=Le parallélisme mémoire | next=Les microarchitectures pour le x86 : haute performance | nextText=Les microarchitectures pour le x86 : haute performance }} </noinclude> 8h1zfc14rpmzuc435nk9rtuz0gtfnq3 773577 773576 2026-09-29T16:11:48Z Mewtow 31375 /* L'exemple du PA-RISC PA 8000 */ 773577 wikitext text/x-wiki Les processeurs vus auparavant ne peuvent émettre au maximum qu'une instruction par cycle d'horloge. Ils peuvent avoir plusieurs instructions qui s'exécutent en même temps, dans des unités de calcul séparées. C'est le cas dès qu'une instruction multi-cycles s'exécute. Par contre, ils ne peuvent démarrer qu'une seule instruction par cycle. Et quand on court après la performance, ce n'est pas assez ! Les concepteurs de processeurs ont inventés des processeurs qui émettent plusieurs instructions par cycle : les '''processeurs à émissions multiples'''. Un processeur à émission multiple charge plusieurs instructions en même temps, les décode en parallèle, puis les émet en même temps sur des unités de calculs séparées. Pour cela, il faut gérer les dépendances entre instructions, répartir les instructions sur différentes unités de calcul, et cela n'est pas une mince affaire. En général, pour un processeur à émission multiple capable d'émettre N instructions en parallèle, on parle de '''processeur à N voies''', ou encore un ''processeur à N pipelines''. [[File:Superscalarpipeline.svg|centre|vignette|upright=1.5|Pipeline RISC classique à cinq étages sur un processeur superscalaire. On voit bien que plusieurs instructions sont chargées en même temps.]] Les processeurs à émission multiple sont de deux types : les processeurs VLIW et les '''processeurs superscalaires'''. Nous mettons les processeurs VLIW de côté en attendant le prochain chapitre. La raison est qu'ils ont un jeu d'instruction spécialisé qui expose le parallélisme d'instruction directement au niveau du jeu d'instructions, là où les processeurs superscalaires restent des processeurs au jeu d'instruction normal. La différence principale entre processeur VLIW et superscalaire est qu'un processeur superscalaire répartit les instructions sur les unités de calcul à l’exécution, là où un processeur VLIW délègue cette tâche au compilateur. ==Le nombre de voies d'un processeur superscalaire== Les processeurs superscalaires les plus simples ne permettent que d'émettre deux micro-opérations à la fois, d'où leur nom de processeur ''dual issue'', ce qui se traduit en '''processeur à double émission'''. Les processeurs triple émission permettent eux d’émettre trois instructions à la fois. A l'opposé, les CPU superscalaires les plus puissants peuvent émettre jusqu'à 8-10 instructions simultanément. En 2026, les CPU superscalaires peuvent monter jusqu’à 10 µops émises en même temps, ce qui est énorme ! Et cela nous amène à faire une distinction entre les processeurs superscalaires dits '''étroits''' et ceux dits '''larges'''. Dans ce wikilivre, on part du principe que les processeurs superscalaires étroits émettent jusqu'à 4-5 µops à la fois, alors que les larges peuvent en émettre plus, l'intervalle entre les deux est une zone grise. Le nombre exact n'est pas fixé dans le marbre, la distinction est volontairement vague. Nous parlerons de la '''largeur d'un CPU superscalaire''' pour parler du nombre de voies, du nombre de µops émises en même temps. Plus un CPU superscalaire est large, plus il est performant ''toute chose égale par ailleurs''. Mais dans les faits, vous pouvez oublier la partie en italique. Élargir un CPU superscalaire demande de rajouter beaucoup de circuits. Et ce cout en circuit aura un impact sur la performance. A budget en transistors limité, il y a un compromis entre élargir un CPU et rajouter du cache ou la taille des fenêtres d'instructions/ROB et autres. ===Les contraintes d’appariement=== Prenons un processeur double émission, capable d'émettre deux instructions simultanément. Émettre deux instructions en même temps n'est pas toujours possible. Par exemple, si deux instructions sont dépendantes, on ne peut pas les émettre en même temps. Mais oublions un instant ces histoires de dépendances de données, et partons du principe que le CPU ait affaire à deux instructions indépendantes, une paire idéale. Un CPU double émission "parfait" pourrait exécuter n'importe quelle paire d'instruction. Par exemple, il pourrait émettre deux multiplications consécutives, deux lectures consécutives, une lecture et une écriture en même temps, etc. En pratique, aucun processeur ne permet cela. Implémenter un CPU superscalaire "parfait" aurait un cout en circuit beaucoup trop conséquent. Par exemple, pour émettre deux multiplications en même temps, il faudrait deux multiplieurs séparés. Idem pour exécuter deux accès mémoire simultané : cela demande d'avoir deux unités mémoire et un cache multiport. Mais en pratique, aucun CPU superscalaire ne fait cela. La totalité des CPU double émission se débrouille avec un seul circuit multiplieur et une seule unité mémoire. Et cela entraine l'apparition de dépendances structurelles, qui font que certaines paires d'instructions sont impossibles. Par exemple, impossible d'émettre deux multiplications en même temps avec un seul circuit multiplieur. Mais émettre une multiplication en parallèle d'une addition est parfaitement possible. Il y a donc des paires d'instructions autorisées et des paires interdites. Et la logique est la même sur les CPU à triple ou quadruple émission, et au-delà. : des triplets ou quadruplet d'instructions sont impossibles à émettre simultanément, alors que d'autres le sont. Pour le dire autrement, il y a des '''contraintes d'appariement''' sur les instructions à émettre en même temps. ===L'impact des contraintes d’appariement sur la performance=== Ces contraintes d’appariement ont un impact sur les performance, mais celui-ci peut être grandement mitigé. Les programmes informatiques utilisent en pratique beaucoup plus d'opérations entières de base que de multiplication, branchements et accès mémoire. Il y a environ 5 opérations entières de base pour une multiplication entière. En pratique, il est rare de devoir exécuter deux multiplications à la fois. Idem pour les décalages et rotations, qui sont assez éloignés les uns des autres. Deux branchements consécutifs sont quant à eux plus fréquents. Deux accès mémoire consécutifs est assez rare, mais ils restent assez proches les uns des autres malgré tout. La conséquence est que certaines paires d'instructions sont privilégiées par rapport au reste. Les paires regroupant deux calculs basiques (additions, soustractions, ...) sont systématiquement supportées, car dupliquer des ALU entières est facile. Les paires regroupant un calcul et une autre instruction sont elles aussi systématiquement supportées. Par contre, les paires avec deux branchements, deux accès mémoire, deux décalages/rotations, ou deux multiplications/divisions sont fréquemment interdites. Seuls les CPU superscalaires larges peuvent les permettre, et encore : sous conditions. Le résultat est que le processeur peut se débrouiller avec une seule unité mémoire et une unité de branchement. ===Terminologie pour la suite du chapitre=== Décrire les contraintes d’appariement demande de dire quelles combinaisons d’instructions sont autorisées ou interdites. Et pour cela, nous allons introduire les abréviations suivantes : * INT est un raccourcis pour parler d'une opération entière simple, qu'une ALU entière peut exécuter. * MUL correspond à une opération entière complexe, typiquement une multiplication, éventuellement à une division. * FLOAT désigne une opération flottante, peut importe laquelle. * MEM désigne un accès mémoire, à savoir une instruction ou µop mémoire. * BRANCH désigne une instruction de branchement. Cette terminologie permettra de définir des paires d'instructions, qu'elles soient possibles ou interdites. Par exemple, l'expression INT + FLOAT désigne une paire d'instruction regroupant une instruction entière et une instruction flottante, peu importe l'ordre des deux instructions. Il en sera de même pour les triplets, quadruplets, ou plus. Par exemple, l'expression INT + INT + FLOAT + MUL désigne un quadruplet d'instructions regroupant : deux instructions entières, une instruction flottante, et une multiplication entière. J'utiliserais aussi des parenthèses pour regrouper certaines combinaisons. Par exemple, l'expression INT + (MUL /FLOAT) veut parler d'une paire d'instruction où la première est une opération entière basique, la seconde est : soit une multiplication, soit une opération flottante. ==Le ''front-end'' des processeurs superscalaires== Un processeur superscalaire doit charger, décoder, et exécuter plusieurs instructions par cycle. Par exemple, un processeur triple émission doit charger 3 instructions lors d'un premier cycle, puis les décoder au cycle suivant, et les exécuter au cycle suivant. Il travaille donc pas paquets de 3 instructions, dans cet exemple. Intuitivement, charger, décoder et exécuter plusieurs instructions à la fois demande de dupliquer des circuits. Par exemple, il faut dupliquer les décodeurs pour décoder plusieurs instructions. Les unités de calcul sont aussi dupliquées, sauf sur certaines processeurs qui arrivent à ruser, mais laissons cela de côté pour plus tard. Mais d'autres circuits sont simplement modifiés, comme l'unité de chargement ou l'unité d'émission. Voyons ce qu'il en est dans le détail. {|class="wikitable" |- ! rowspan="2" | Processeur sans émission multiple | rowspan="2" | Chargement | rowspan="2" | Décodage | rowspan="2" | Renommage | rowspan="2" | Émission | Exécution / ALU | rowspan="2" | ''Commit''/ROB |- | Exécution / ALU |- ! rowspan="4" | Processeur superscalaire | rowspan="4" | Chargement | rowspan="2" | Décodage | rowspan="4" | Renommage | rowspan="4" | Émission | Exécution / ALU | rowspan="4" | ''Commit''/ROB |- | Exécution / ALU |- | rowspan="2" | Décodage | Exécution / ALU |- | Exécution / ALU |} Nous allons d'abord voir ce qu'il en est pour le ''front-end'', à savoir la partie du CPU qui s'occupe de charger et décoder les instructions. Elle regroupe l'unité de chargement, les décodeurs, l'unité de prédiction de branchement, la file de µops, la file d'instruction, et divers caches. En soi, les changements portent surtout sur l'unité de chargement et les décodeurs. ===Le chargement de plusieurs instructions consécutives=== Un processeur superscalaire charge plusieurs instructions en même temps, ''en tenant compte de la présence de branchements''. La partie en italique est importante et elle a une conséquence très forte : la manière de faire est fortement différente entre un CPU superscalaire étroit et large. Un CPU superscalaire étroit fait au plus simple : il charge un bloc de 2, 3, 4 instructions consécutives en mémoire RAM. Il faut alors doubler/tripler/quadrupler la taille du bus connecté au cache d'instruction. Par exemple, pour charger quatre instructions de 32 bits chacune, il suffit de lire un bloc de 128 bits dans le cache d'instruction. Un bloc de 8, 16, 32 octets est donc lu depuis le cache et est ensuite découpé en instructions, envoyées chacun à un décodeur. Charger plusieurs instructions consécutives ne marche bien qu'en absence de branchements. La présence de branchements casse cette dynamique, et il faut gérer leur présence. * Sans prédiction de branchement, toutes les instructions d'un bloc sont décodées et exécutées en même temps, même s'il y a un branchement dans le tas. * Avec prédiction de branchement, les instructions situées après le branchement ne sont pas décodées ni exécutées. L'unité de chargement coupe le bloc chargé au niveau du premier branchement pris, remplit les vides avec des NOP, avant d'envoyer le tout à l'unité de décodage. Les instructions à l'adresse de destination seront chargées au cycle suivant, en chargeant un nouveau bloc. [[File:Fetch sur un processeur superscalaire avec prediction de branchements.png|centre|vignette|upright=2|Fetch sur un processeur superscalaire avec prédiction de branchements.]] Un autre défaut est que sur le CPU charge un bloc de 128 bits à la fois, les instructions doivent être alignées sur 128 bits. Et on peut généraliser à n'importe quelle taille de bloc. Si les instructions ne sont pas alignées, il faut gérer la situation. Il arrive qu'une instruction soit à cheval sur deux blocs, avec un morceau dans le premier bloc, un autre dans le second. Dans ce cas, l'instruction est chargée en deux fois, et des circuits doivent gérer la situation pour recoller les morceaux. Sur les CPU avec des instructions de taille fixe, le problème ne survient que rarement. Mais il est fréquent avec des instructions de taille variable. Un autre défaut est lié aux branchements. Imaginez qu'un branchement s'exécute et branche vers une instruction de destination. Rien n'indique que l'instruction de destination sera au tout début d'un bloc. Si ça se trouve, elle sera en troisième position d'un bloc de 4 instructions. Une solution simple charge le bloc en respectant l'alignement, et les deux premières instructions du bloc ne sont pas à exécuter. Il y a donc une petite perte de performance. Certains CPU, comme l'IBM RS/6000, ont la machinerie charger un bloc de N instructions même s'il n'est pas aligné. La machinerie en question se trouve dans le cache d'instruction et est tout sauf simple à expliquer,ce qui fait que je me permets de la passer sous silence. Un détail, cependant : elle ne permet pas de charger des blocs qui sont à cheval sur deux lignes de cache. ===Le décodage parallèle des instructions=== Pour le décodage des instructions, plusieurs instructions sont décodées en même temps. On parle alors de '''décodage parallèle'''. Pour ce faire, un processeur superscalaire contient plusieurs décodeurs, chacun pouvant décoder une instruction en parallèle des autres. Prenons par exemple un processeur superscalaire à 4 voies : le décodage se fera dans quatre décodeurs séparés, qui fonctionneront en parallèle. Cependant, cette implémentation ne marche bien que pour les processeurs RISC, les processeurs CISC devant faire avec un microcode gourmand en circuits. Les processeurs CISC utilisent des décodeurs hybrides, avec un microcode qui complémente un décodeur câblé. Dupliquer le microcode aurait un cout en transistors trop important, ce qui fait que seuls les décodeurs câblés sont dupliqués. Les CPU CISC superscalaires disposent donc de plusieurs décodeurs simples, capables de décoder les instructions les plus courantes, avec un seul microcode. La conséquence est qu'il n'est pas possible de décoder deux instructions microcodées en même temps. Par contre, il reste possible de décoder plusieurs instructions non-microcodées ou une instruction microcodée couplée à une instruction non-microcodée. Vu qu'il est rare que deux instructions microcodées se suivent dans un programme, le cout en performance est extrêmement mineur. Il faut noter qu'une instruction correspond à une ou plusieurs µops. Il est donc possible de charger 5 instructions et de se retrouver avec 8 µops en sortie des décodeurs. Et c'est la source d'une distinction très importante. Plus haut, j'ai parlé de processeurs superscalaires à N voies. La terminologie peut avoir deux interprétations. La première est que le processeur charge/décode N instructions à la fois. Une seconde est qu'il est capable d'exécuter/émettre N µops en même temps. Les deux ne sont pas équivalentes, vu qu'un processeur superscalaire peut, par exemple, charger/décoder N instructions et émettre/exécuter N+2 µops. La distinction est particulièrement importante sur les processeurs superscalaires larges. Certains d'entre eux sont capables de charger 5 instructions et d'en émettre le double ! Un exemple classique était les processeurs Athlon d'AMD, qui pouvaient décoder deux instructions par cycle, mais émettre 4 µops par cycle. Ce n'était pas un problème, car beaucoup d'instructions, même basiques, étaient décodées en 2 µops. ===L'émission parallèle des instructions=== La superscalarité modifie en profondeur l'unité d'émission, notamment au niveau de son interface. Avant, elle recevait une micro-opération sur son entrée, et fournissait la micro-opération émise sur une sortie. Et cela vaut aussi bien pour une unité d'émission simple, un ''scoreboard'', une fenêtre d'instruction ou des stations de réservation. Mais avec l'émission multiple, les sorties et entrées sont dupliquées. Pour la double émission, il y a deux entrées vu qu'elle doit recevoir deux micro-opération décodées/renommées, et deux sorties pour émettre deux micro-opérations. Dans ce qui suit, nous ne parlerons pas d'entrée et de sortie, mais de '''ports de décodage''' et de '''ports d'émission'''. Les ports de décodage reçoivent des micro-opérations provenant de l'unité de décodage, les ports d'émissions sont pour les micro-opérations émises. Les ports d'émission injectent les micro-opérations émises dans le pipeline, elle sont propagée au banc de registre, aux ALUs, etc. Un processeur superscalaire a forcément plusieurs ports d'émission (et de décodage). Si l'interface de l'unité d'émission change, l'intérieur est tout autant modifié. Sur un CPU non-superscalaire, l'unité d'émission reçoit une µop "candidate à l'émission", et détecte les dépendances entre avec les µops en vol, en cours d'exécution dans le pipeline. Et c'est toujours le cas sur les processeurs superscalaires : l'unité d'émission détecte les dépendances entre les µops candidates et les µops en vol. Mais avec la siperscalarité, elle doit en plus tester les dépendances entre les µops candidates. Si l'unité d'émission est un ''scoreboard'', il doit détecter les dépendances entre instructions émises simultanément et les sérialiser si besoin. Avec une fenêtre d'instruction, il n'y a pour ainsi dire rien à faire, vu que les dépendances sont éliminées par le renommage de registre et que les signaux de réveil gèrent les dépendances RAW. C'est la raison pour laquelle les processeurs superscalaires modernes n'utilisent pas de ''scoreboard''. ==Les processeurs implémentés avec plusieurs pipelines== Nous venons de voir comment la superscalarité impacte le ''front-end'', il est maintenant de voir ce qu'il en est de l'unité d'émission et des ''back-ends''. Un processeur superscalaire peut utiliser l'exécution dans le désordre et le renommage de registres, mais ce n'est pas une obligation. Historiquement, les premiers processeurs superscalaires n'utilisaient pas d'exécution dans le désordre. Le meilleur exemple est celui du Pentium 1 et 2 d'Intel. Ils étaient tous deux des processeurs superscalaires, mais n'avaient pas d'exécution dans le désordre, qui est apparue sur le Pentium 3. les explications sont plus simples si on met de côté l'exécution dans le désordre. Vous vous dites que l'implémentation d'un processeur superscalaire n'est pas la même suivant que le CPU utilise l'exécution dans le désordre, ou non. Mais dans les faits, la distinction est plus subtile que ca. Pour l'expliquer, je vais utiliser une classification originale, qui sépare les processeurs superscalaires en trois sous-types. La distinction se fait sur la manière dont la superscalarité est implémentée en matériel.La classification que j'utilise distingue : * Les processeurs avec plusieurs pipelines, sans exécution dans le désordre. * Les processeurs superscalaires avec un pipeline dynamique. * Les processeurs avec des fenêtres d'instruction décentralisées. La distinction n'est pas qu'une question d'implémentation matérielle. Elle impacte aussi le ratio entre instructions chargées/décodées et instructions émises. Vous vous dites que les deux sont égales, mais ce n'est le cas que sur les processeurs avec N pipelines ! Sur les autres processeurs, il est possible de décoder 4 instructions, mais d'en émettre maximum 6 par cycle ! Et sur les CPU avec des fenêtres d'instruction décentralisées, il y a aussi une différence entre le nombre d'instructions qui sont ''dispatch'' et ''schedule''. La catégorie la plus simple est celle des '''processeurs avec plusieurs pipelines'''. Ce sont des processeurs superscalaires sans exécution dans le désordre. Ils partent d'un processeur non-superscalaire, et ajoutent un second pipeline, en sortie de l'unité d'émission. Le second pipeline permet l'émission parallèle d'une seconde instruction. Le second pipeline n'est pas identique au pipeline originel, sur plusieurs points. Premièrement, il n'a pas exactement les mêmes circuits. Le second pipeline est généralement composé d'une unité de calcul, d'une FPU, éventuellement d'un second banc de registres, guère plus. Il permet d'exécuter une seconde opération de calcul, pas plus, ce qui est à l'origine de contraintes d'appariemment assez fortes. De plus, il n'a pas forcément la même longueur, il peut avoir des étages en moins ou en plus. Il s'agit de la forme la plus simple de processeur superscalaire et nous allons leur consacrer cette section. ===La double émission entière-flottante=== L'exemple le plus simple utilise un second pipeline pour les opérations flottantes, séparé du pipeline originel. L'ajout d'un pipeline flottant permet d'émettre une micro-opération entière en même temps qu'une micro-opération flottante, ce qui s'appelle la '''double émission entière-flottante'''. La micro-opération entière s'exécute dans l'ALU entière, la micro-opération flottante dans la FPU. Les exemples les plus notables sont le PA-RISC 7100, le POWER 1 (RIOS .& et .9) et le PowerPC 601. L'Apollo DN10000 et l'Intel i860 utilisaient aussi cette forme de double émission, mais étaient des prototypes de CPU VLIW. [[File:Double émission entière-flottante.png|centre|vignette|upright=2|Double émission entière-flottante]] Pour bien expliquer les choses, prenons le processeur illustré ci-dessous, avec deux ''back-end'' séparés : un pour la FPU, et un autre pour le reste. Les instructions entières et mémoire passent toutes par le ''back-end'' généraliste. [[File:CPU non-superscalaire basique, avec une FPU.png|centre|vignette|upright=1.5|CPU non-superscalaire basique, avec une FPU]] Les deux ''back-end'' sont des pipelines séparés, mais il faut que l'unité d'émission soit spécialement conçue pour en profiter. Un processeur simple émission peut démarrer une seule µop par cycle : soit la µop est envoyée au ''back-end'' flottant, soit elle est envoyée au ''back-end'' général. Avec la double émission entière-flottante, le processeur peut envoyer une µop dans chaque pipeline, à chaque cycle. Vu que la FPU et son banc de registre forment déjà un pipeline séparé, les seules modifications se font au niveau du ''front-end'', unité d'émission inclue. {| |- |[[File:CPU simple émission avec une FPU.png|centre|vignette|upright=1.5|CPU simple émission avec une FPU.]] |[[File:Double émission entière flottante avec un second pipeline.png|centre|vignette|upright=1.5|CPU avec un second pipeline flottant.]] |} Notez que le terme double émission ''entière''-flottante est un peu trompeur. En réalité, la technique permet d'émettre une instruction flottante avec n'importe quelle autre instruction non-flottante, avec des restrictions pour les branchements. Il est par exemple possible d'exécuter un calcul flottant en parallèle d'un accès mémoire. Sur les CPU 32 bits, il est possible de faire les multiplications dans la FPU. Pour rappel, la FPU contient un multiplieur entier 53-54 bits, pour multiplier les mantisses de deux flottants 64 bits, qu'on peut utiliser pour faire les multiplications entières 32 bits. Cela permet d'émettre une multiplication en même temps qu'une opération entière dans l'ALU. Ainsi, le CPU pouvait émettre deux instructions : une opération entière de base, avec soit une multiplication, soit une opération flottante. En clair, une émission de type INT + (MUL /FLOAT). Par contre, on perd la possibilité d'émettre une multiplication entière avec une opération flottante, mais c'était un compromis qui en valait la peine. Le CPU PA-RISC 7100 implémentait cette optimisation. Il s'agissait d'un CPU double émission entière-flottante, qui utilisait donc un partitionnement assez simple. Le combo partitionnement + reconditionnement permettait ici de gagner en performance, pour un cout en matériel très limité. D’autant plus limité que le jeu d'instruction prévoyait le reconditionnement de la FPU. Les multiplications ne lisaient pas leurs opérandes dans les registres entiers, mais dans les registres flottants. ===La double émission entière=== Une autre possibilité ajoute un second pipeline, capable d'exécuter des opérations entières simples, appelé le pipeline entier. Le processeur supporte alors la '''double émission entière''', à savoir qu'ils peuvent émettre une opération entière en plus d'une autre instruction. L'opération entière en question est une opération simple, comme une addition, une soustraction, une opération bit à bit, une comparaison, etc. Les exemples classiques sont les processeurs Intel i960 et Pentium. L'implémentation était différente entre l'i960 et le Pentium : Le Pentium avait une seconde ALU entière, alors que le i960 rusait. Le Pentium dupliquait l'ALU entière, pour créer un second pipeline entier. Sur le Pentium originel, les contraintes d'appariement étaient assez strictes. Le Pentium avait une FPU, mais ne pouvait pas l'utiliser en double émission. Il lui était impossible d'exécuter une opération flottante en même temps qu'une opération entière (branchements inclus). Le Cyrix 6x86 était une sorte de Pentium produit par l'entreprise Cyrix, avec une microarchitecture différente. Il avait des contraintes d’appariement réduites. Par exemple, il pouvait émettre une opération flottante en parallèle d'une opération entière. Nous détaillerons ces processeurs dans le prochain chapitre, qui porte justement sur les CPU superscalaires x86. [[File:CPU simple et double émission avec un second pipeline entier.png|centre|vignette|upright=2.5|CPU simple et double émission avec un second pipeline entier.]] L'Intel i960 n'avait pas de FPU, juste une ALU entière et une unité mémoire. Il utilisait l'unité mémoire comme une seconde ALU entière limitée. Pour rappel, une unité mémoire contient une AGU, à savoir une ALU spécialisée dans les calculs d'adresse. Elle est capable de faire des additions, soustractions, et quelques décalages limités (des décalages par 2, 4, 8, pas plus). L'Intel i960 ajoutait des connexions entre AGU et banc de registre, afin que celle-ci serve de seconde unité de calcul. L'AGU est déjà reliée aux deux ports de lecture, pour lire les opérandes du calcul d'adresse, il suffit de la connecter sur le port d'écriture. Le processeur peut alors émettre deux instructions/µops entières, sous certaines conditions. [[File:Emission multiple des opérations entières, double émission.png|centre|vignette|upright=2|Émission multiple des opérations entières, double émission.]] ==Les processeurs superscalaires dynamiques== Les processeurs précédents, avec 2 pipelines, avaient une unité d'émission assez simple. Elle avait deux ports de décodage, et deux ports d'émission. Le nombre de ports de décodage et d'émission étaient identiques. Vous vous dites que c'est naturel, et intuitif, que c'est normal pour un processeur superscalaire. Mais en réalité, la majorité des processeurs superscalaires a plus de ports d'émission que de décodage. Expliquer pourquoi va cependant nous demander de parler de comment la superscalarité exploite les unités de calcul. Posons-nous cette question : de combien d'unités un processeur superscalaire a besoin ? Les unités en question ne sont nécessairement des unité de calcul, l'unité mémoire et l'unité de branchement comptent aussi. La réponse dépend du nombre de voies. Si le ''front-end'' charge et décode un paquet de N instructions, exécuter ces N instructions simultanément demandera là aussi au moins N unités de calcul. Notez le terme : ''au moins'', car c'est là tout l'enjeu de cette section. La réponse dépend aussi des contraintes d’appariement. Pour un CPU superscalaire "parfait", sans contraintes d’appariement, toutes les unités doivent être dupliquées, y compris l'unité mémoire. Un processeur à double émission parfaite devrait dupliquer l'ALU entière, le ''barrel shifter'', le circuit multiplieur, la FPU, l'unité mémoire, et l'unité de branchement, ce qui ferait passer de 6 unités à 12. Le cout en circuit est énorme, même pour de la double émission ! Et pour un CPU à N pipelines, le cout en circuit encore plus prohibitif ! En pratique, les processeurs superscalaires qui font ça sont très rares. La majeure partie des processeurs superscalaires utilisent d'autres techniques : le partitionnement, la duplication partielle des ALUs, la duplication des autres unités. ===Le partitionnement des unités fonctionnelles=== Les CPU superscalaires les plus simples ne dupliquent pas leurs unités de calcul, ils se contentent d'exploiter les unités existantes. Et pour expliquer comment, nous allons partir de l'exemple d'un processeur non-superscalaire contient une ALU entière, une FPU, une unité mémoire et une unité de branchement. Les quatre unités peuvent fonctionner en parallèle, à savoir qu'une unité peut exécuter une instruction à elle toute seule, sans interagir avec les autres. Cela suffit pour créer un processeur quadruple émission, qui peut émettre en même temps : une opération entière, une opération flottante, un branchement, un accès mémoire. Le principe marche aussi sur un processeur avec moins de 4 unités, par exemple sans FPU et/ou sans unité de branchement, ou avec au contraire des unités en plus. L'idée générale est d’émettre une µops séparée dans chaque unité fonctionnelle. Utiliser ainsi les unités existantes, pour rendre un CPU superscalaire, s'appelle le '''partitionnement superscalaire'''. Le terme n'est pas beaucoup utilisé en-dehors de quelques vieux articles académiques. Le partitionnement est fortement dépendant du jeu d'instruction, car il demande de bien séparer instructions entières, flottantes, branchements et instructions mémoire. Et autant c'est bien le cas sur les CPU RISC, autant les CPU CISC ne sont pas dans ce cas. Les CPU CISC ont des instructions ''load-op'', qui effectuent une instruction arithmétique et une µop mémoire. Et ces instructions sont très compliquées à implémenter avec le partitionnement. Et au-delà de ça, les CPU CISC ont beaucoup d'instructions qui sont décodées en plusieurs µops, à exécuter dans un ordre bien précis. On peut pas émettre les µops en question simultanément. Le partitionnement a un cout en circuit très limité, pour un gain en performance lui aussi limité. Pour reprendre le CPU de l'exemple précédent, il est rare que l'on ait à exécuter ces quatre instructions en même temps. En pratique, les combinaisons fréquentes sont les combinaisons calcul + accès mémoire, calcul + branchement, calcul entier + calcul flottant. Utiliser une quadruple émission de ce type n'est donc pas une bonne idée, alors que la double émission parait plus adaptée. Et c'est là que la différence entre ports d'émission et de décodage devient intéressante. L'idée est d'avoir une unité d'émission avec deux ports de décodage, et 4 port d'émission (un par unité). Les contraintes d’appariement varient alors suivant le processeur, mais la règle générale est que si deux micro-opérations tombent dans deux unités différentes, on peut les émettre en même temps. En clair, on peut émettre une opération entière avec une opération flottante, une opération entière avec un branchement, un accès mémoire avec un branchement, etc. Et cela rend le partitionnement bien plus intéressant que prévu. Les tout premiers CPU superscalaires étaient des CPU double émission, qui utilisaient le partitionnement avec : une ALU entière, une unité mémoire et une FPU. Nous parlerons de '''partitionnement INT-FLOAT-MEM'''. L'avantage sur la double émission flottante est que les combinaisons INT + MEM et FLOAT + MEM étaient autorisées. L'intérêt était d'émettre une opération en parallèle d'un accès mémoire, ce qui est un doublet d'instruction assez fréquent. Les exemples classiques sont l'HyperSPARC, de l'alpha 21064 et du PowerPC 603. Les contraintes d’appariement variaient grandement suivant le processeur. Le PowerPC 603 implémentait une double émission "parfaite". C'est à dire que toutes les combinaisons possibles à deux instructions étaient possibles, que ce soit INT + FLOAT, INT + MEM, FLOAT + MEM. En plus de cette double émission "parfaite", le CPU utilisait la technique dite de ''branch folding'', qui permettait d'exécuter un branchement sans utiliser d'unité de calcul, ce qui fait qu'il était qualifié de ''CPU 2-way + Branch''. A l'opposé, le processeur alpha 21064 avait pas mal de contraintes d’appariement, à savoir que certaines combinaisons de deux instructions étaient interdites, bien que compatibles avec les unités disponibles. Une des raisons est que le banc de registre n'avait pas assez de ports de lectures, ce qui fait que certaines combinaisons avec une écriture mémoire n'étaient pas permises. Les concepteurs avaient volontairement inséré ces contraintes afin de simplifier le design du processeur. Avant de poursuivre, précisons que la FPU regroupe un additionneur flottant et un multiplieur flottant. Et ce fait peut être exploité pour approfondir le partitionnement. La '''double émission FADD/FMUL''' permet d'émettre une addition flottante en même temps qu'une multiplication flottante. Elle a été utilisée sur les processeurs x86, Alpha et SPARC. Les autres circuits de calcul flottant sont souvent regroupés avec l'additionneur. La division est parfois e même port que le multiplieur flottant, parfois sur celui de l'additionneur (quand elle est microcodée et exécutée en enchainant les soustractions). ===La duplication des ALU entières=== Le partitionnement est une technique élégante, simple, facile à implémenter et au cout en circuits modeste. Mais il faut avouer que cela ne donne pas des CPU superscalaires très efficaces. La raison est que le partitionnement permet d'émettre des paires, triplets, quadruplets de micro-opérations qui sont rares en pratique. Les combinaisons les plus fréquentes en pratique sont des paires/triplets d'opérations entières, souvent des paires/triplets d'additions ou d'opérations entières simples. Il est donc primordial d'émettre plusieurs opérations entières simultanément. Le fait d'émettre et d'exécuter plusieurs opérations entières en même temps s'appelle l''''émission entière multiple'''. Pour exécuter la seconde/troisième opération entière, il faut dupliquer les ALU entières (ou réutiliser l'AGU comme ALU entière comme le fait l'Intel i960). Le processeur doit avoir deux ALU entières pour de la double émission entière, trois pour de triple émission entière, etc. De plus, il faut ajouter des ports au banc de registre, pour lire deux fois plus d'opérandes et décrire deux résultats. Et enfin, il faut rajouter un port d'émission pour pouvoir émettre une micro-opération entière en plus. [[File:Processeur non-superscalaire basique 03.png|centre|vignette|upright=2|Processeur non-superscalaire basique]] La tendance est de multiplier les ALU entières, mais pas le circuit multiplieur. Le cout en transistors est alors grandement réduit, au prix de l'apparition de dépendances structurelles. Le CPU peut émettre deux additions en même temps, ou une addition et une multiplication, mais pas deux multiplications. Il en est de même avec le ''barrel shifter'', qui n'est pas dupliqué. Il est donc possible d'émettre un décalage avec une opération de base, mais pas deux décalages en parallèle. Mais ces contraintes d’appariement ne sont pas un problème, car il est rare de devoir émettre deux multiplications/décalages en même temps. La plupart des programmes sont majoritairement remplis d'additions, avec des multiplications assez rares et des décalages qui le sont encore plus. La moyenne est proche d'une multiplication pour 4/5 additions. Vu que des multiplications consécutives sont très rares, dupliquer le multiplieur est presque inutile. Disposer de plusieurs circuits multiplieurs ou de plusieurs ''barrel shifters'' serait donc un cout en circuits qui ne servirait que rarement et n'en vaut pas la chandelle. Il faut noter que sur les CPU 32 bits, les multiplications peuvent être exécutées dans la FPU ou dans un multiplieur séparé, tout dépend de si le CPU exécute les multiplications dans la FPU ou pas. {|class="wikitable" |- ! Voie d'émission n°1 !! Voie d'émission n°2 !! Voie d'émission n°3 |- | ALU entière || ALU entière || FPU |} Reste à connecter les unités de calcul à l'unité d'émission (indirectement, car il y a des étages de pipeline entre les deux). Une implémentation basique utilisée un port d'émission par unité. Prenons l'exemple d'un CPU superscalaire avec 4 ALU entières, une FPU, et une unité mémoire. Vu qu'il y a 6 unités, cela fait donc 6 ports d'émission. L'exemple historique le plus impressionnant est celui du Motorola 88110, un CPU double émission qui possède 10 unités. Il contient deux ALU entières, un circuit multiplieur, un circuit diviseur, une unité de manipulation de bits, une unité mémoire, un additionneur flottant, et deux unités graphiques pour des calculs impliquant des pixels. Le multiplieur est utilisé à la fois pour les multiplications entières, flottantes et le produit de deux pixels. Idem pour le diviseur, qui sert pour les divisions entières et flottantes. Et chaque unité a son propre port d'émission. La conséquence est que les contraintes d'appariement du Motorola 88110 sont simples : tant que deux µops atterrissent dans des unités séparées, la paire est permise. Il est par exemple possible d'émettre simultanément deux opérations entières simples, vu qu'il y a deux ALU. Par contre, impossible d'émettre simultanément deux multiplications, deux divisions, deux opérations flottantes, deux manipulations de bit, deux accès mémoire, etc. De plus, le partage du multiplieur fait qu'on ne peut pas émettre une multiplication entière avec une multiplication flottante. Idem avec les divisions, vu que le diviseur est aussi partagé. Ce sont les seules contraintes. ===Le partage des ports d'émission=== La présence d'un circuit multiplieur et d'un ''barrel shifter'' pose des problèmes pour le partitionnement. Il est possible d'avoir un port d'émission dédié au multiplieur, et un autre au ''barrel shifter'', qui sont séparés de ceux pour l'ALU entière. Il est alors possible d'émettre une opération entière, une multiplication et un décalage, simultanément. Nous parlerons de '''partitionnement entier''' pour désigner cette possibilité. [[File:Partitionnement superscalaire entier.png|centre|vignette|upright=2|Partitionnement superscalaire entier.]] Le partitionnement entier est cependant très rare, car le gain en performance serait trop faible au regard des couts en circuit. Quelques processeurs historiques l'utilisaient, mais ce n'est plus le cas de nos jours. La raison est que les multiplications et les décalages sont assez rares dans le code, ce qui fait que le port d'émission associés sont sous-utilisés. Et un port d'émission a un cout en circuit assez important. Et c'est sans compter qu'ajouter des ports sur le banc de registres juste pour un multiplier sous-utilisé n'en vaut pas la peine. L'idéal serait de trouver un moyen de réduire le nombre de ports d'émissions, sans réduire le nombre d'unités de calcul. [[File:Emission multiple des opérations entières, implémentation naive.png|vignette|Émission multiple des opérations entières, implémentation naive]] La solution consiste à '''partager les ports d'émission''', à savoir connecter un port d'émission à plusieurs unités de calcul. L'exemple classique est justement lié aux circuits multiplieur et ''barrel shifters''. L'idée est que le multiplieur et le ''barrel shifter'' sont mis sur le même port d'émission qu'une ALU entière. Prenons par exemple le processeur à double émission entière illustré ci-contre. Un port d'émission est relié à une ALU entière seule, et l'autre port d'émission alimente la seconde ALU entière et le multiplieur. La conséquence est que le processeur peut émettre deux opérations entières, dont une multiplication. Si on avait utilisé un port d'émission dédié au multiplieur, il aurait été possible d'émettre deux opérations entières et une multiplication. On perd donc une voie, mais on gagne en flexibilité et on économise des circuits. Notons que ce partage signifie aussi que le multiplieur partage les ports sur le banc de registre, ce qui fait une double économie. [[File:Emission multiple des opérations entières, implémentation courante.png|centre|vignette|upright=1.5|Émission multiple des opérations entières, implémentation courante]] En général, le ''barrel shifter'' et le multiplieur sont placés sur deux voies d'émission séparés, ce qui permet d'émettre un décalage et une multiplication en même temps. Les mettre sur le même port ne le permettrait pas. {|class="wikitable" |- ! Voie d'émission n°1 !! Voie d'émission n°2 !! Voie d'émission n°3 |- | * ALU entière * Multiplieur | * ALU entière * Barrel shifter | FPU |- | * Additions, soustractions, opérations bit à bit, etc. * Multiplication | * Additions, soustractions, opérations bit à bit, etc. * Décalages et rotations | Opération flottante |} Terminons concernant les multiplieurs avec une dernière subtilité. Pour rappel, les processeurs modernes intégrent en réalité deux multiplieurs différents. Le résultat d'une multiplication est très large et prend deux registres. Par exemple, une multiplication de deux opérandes 64 bits donne un résultat sur 128 bits, ce qui ne tient pas dans un registre, mais en prend deux. L'instruction de multiplication classique ne calcule que les 64 bits de poids faible. mais elle est complétée par d'autres instructions de multiplication qui peuvent faire le calcul complet. Pour résoudre le problème, les processeurs modernes intègrent deux instructions de multiplications : une qui calcule les bits de poids faible du résultat, une autre qui calcule les bits de poids fort. Et ces deux instructions sont associées à deux multiplieurs séparés, aux circuits différent. Le multiplieur qui calcule les bits de poids faible du résultat est appelé le ''low multiplier'', l'autre est appelé le ''high multiplier''. Le second multiplieur est souvent placé sur un second port d'émission, différent du premier multiplieur, partagé avec une ALU. L’avantage de mettre les deux multiplieurs sur deux ports d'émission différents est qu'une multiplication complète peut être réalisée en utilisant les deux multiplieurs en parallèle. Les deux sous-multiplications sont émises en même temps, exécutées en même temps. pas besoin d'exécuter l'une puis la seconde, d'où un gain performance appréciable. Nous venons de voir comment partager un port d'émission entre une ALU et un multiplieur. Mais au-delà de cet exemple, le partage des ports d'émission peut appliquer à n'importe quelle unité. Prenons l'exemple d'un CPU superscalaire avec 4 ALU entières, une FPU, et une unité mémoire. Vu qu'il y a 6 unités, cela fait donc 6 ports d'émission. Cependant, il est rare qu'un bloc de 6 instructions contienne exactement 4 opérations entières, une opération flottante, et un accès mémoire. Beaucoup de ports d'émission seraient sous-utilisés. La solution est de partager des ports d'émission, pour passer à la quadruple émission. Le CPU peut alors répartir 4 instructions sur les ports d'émission adéquats, à chaque cycle. Le CPU a donc 4 ports de décodage et 6 ports d'émission. Une implémentation classique permet n'importe quelle combinaison de 4 instructions compatible avec les 6 unités. Par exemple, il devient possible d'émettre simultanément 4 additions, la combinaison 2 * INT + FLOAT + MEM, 3 * INT + MEM, et bien d'autres. L'exemple relie une ALU entière, la FPU et l'unité mémoire sur le même port. Le CPU a alors quatre ports d'émission, qui ne sont pas "identiques". Trois d'entre eux sont reliés à une ALU entière chacun, rien d'autre. Le quatrième est lui relié à une ALU entière, la FPU et l'unité mémoire. On économise alors deux ports d'émission, mais cela entraine l'apparition de contraintes d’appariement. Le CPU peut émettre 3 opérations entières + n'importe quelle autre opération. Mais les autres combinaisons sont interdites. Le CPU peut émettre 6 opérations entières simultanément, grâce à 6 ALU entières. Les accès mémoire ou opérations flottantes ne viennent pas en plus, mais en remplacement des opérations entières. Regrouper plusieurs ALU sur un même port d'émission est donc à l'origine de dépendances structurelles, de nouvelles contraintes d’appariement. Dans certaines situations de '''''port contention''''', on a assez d'ALU pour exécuter N micro-opérations, mais la répartition des ALUs sur les ports l'empêche. Impossible d'émettre deux micro-opérations sur deux ALU si elles sont sur le même port d'émission. On peut réduire les cas de ''port contention'' en répartissant correctement les ALU sur les ports d'émission, mais sans jamais les supprimer complétement. Un exemple est celui du PowerPC 604. Il implémentait la quadruple émission, alors qu'il avait 5 unités de calcul. Mais deux unités partageaient un même port d'émission. Dans le détail, il avait deux ALU entières, un circuit multiplieur/diviseur, une FPU, une unité mémoire. La FPU et le multiplieur étaient sur le même port d'émission. En conséquence, le CPU pouvait émettre seulement les combinaisons INT + INT + MEM + (MUL/FLOAT). : Il est intéressant de voir l'exemple d'un processeur superscalaire parfait, sans contraintes d'appariement, à N voies. Pour cela, on part d'un processeur non-superscalaire, avec M unités de calcul. Un tel processeur peut s'implémenter avec N ports d'émission, chacun relié à M unités de calcul possibles, ce qui fait que les M unités de calcul sont dupliquées en N exemplaires. Si on prend par exemple un CPU non-superscalaire avec une ALU, une FPU, une unité mémoire et une unité de branchement, un port d'émission sera relié à une ALU, une FPU, une unité mémoire et une unité de branchement. ===La duplication des autres unités fonctionnelles=== Dupliquer les ALU entière est une première étape, mais il est aussi possible de dupliquer les autres unités fonctionnelles. Par exemple, il est possible de dupliquer l'unité mémoire ou l'unité de branchement. Reste à voir quelles unités dupliquer, et pourquoi. Précisons que dans ce qui va suivre, nous allons parler de la duplication des unités en général, pas seulement des unités mémoire/branchement. Nous allons continuer de parler de la duplication des ALU entières dans ce qui suit, mais de manière plus générale. Pour un processeur à N voies, il est théoriquement possible de dupliquer toutes les unités en N exemplaires. Mais ce n'est jamais fait en pratique, car le cout en circuits serait trop important et le gain en performance trop faible. Mieux vaut dupliquer certaines unités bien précises, quitte à avoir des contraintes d'appariement. Et à ce petit jeu, toutes les duplications ne se valent pas, certaines sont plus rentables en matière de performance, le cout en circuit n'est pas le même selon l'unité, etc. La rentabilité en performance dépend surtout des contraintes d'appariement. Les contraintes d'appariement entrainent une baisse de performance significatives si elles interdisent des paires d'instructions fréquentes. Aussi, les opérations très fréquentes, souvent appairées, gagnent à dupliquer l'unité associée. Et au contraire, les unités rarement utilisées ne doivent pas être dupliquées. Il se trouve que les unités les plus utilisées sont les ALU entières, suivies par les unités mémoire et l'unité de branchement. Le cout en circuit n'est aussi pas le même. Dupliquer les ALU entière est trivial, car elles ont un budget en transistors assez faible. Les circuits multiplieurs, diviseurs, et les ''barrel shifter'' ont eux un cout en transistor plus élevés. Si on devait faire un classement, on aurait : ALU entière < ''barrel shifter'' < multiplieur. Pour les unités mémoire, le cout en transistor est là aussi conséquent. Le résultat final est que dupliquer les ALU entières est privilégié sur le reste, comme l'a vu dans la section précédente. Les unités mémoire arrivent en seconde place, suivie par les multiplieurs/''barrel shifter'' à la troisième place, et les unités de branchement à la quatrième place. Les CPU superscalaires larges ont donc tendance à multiplier les unités mémoire en second. Les multiplieurs et ''barrel shifters'' sont eux aussi dupliqués sur les CPU superscalaires larges, mais cela vient souvent après avoir dupliqué les unités mémoire. La raison est que les accès mémoire sont critiques pour la performance des CPU à exécution dans le désordre, pas les multiplications. Pour les unités de branchement, une subtilité complique le fait d'en installer plusieurs. Que faire quand deux branchements sont pris ? La solution la plus simple est de ne pas se trouver dans cette situation : on n'utilise qu'une seule unité de branchement et on n’exécute qu'un seul branchement par cycle. La majorité des processeurs superscalaires étroits font ainsi. Les processeurs superscalaires larges ont cependant deux unités de branchements, mais ils n'acceptent qu'un seul branchement pris à la fois. Si les deux branchements pris sont exécutés en même temps, le processeur n’exécute que le plus récent, dans l'ordre du programme. ===Les CPU superscalaires mélangent les trois techniques=== Les CPU superscalaires utilisent toutes les techniques à la fois : partitionnement, duplication de l'ALU entière, duplication des autre unités fonctionnelles. Chaque processeur utilise ces trois stratégies à sa sauce, en fonction de son budget en transistor. Les quatre techniques ont cependant un cout en circuit différent, et donnent des gains de performances eux aussi forts différents. * Le '''partitionnement superscalaire''' a un cout en circuit modéré, car on n'a pas besoin de dupliquer d'ALU. * La '''duplication des ALU entières''' est la technique la plus importante : elle a un cout en circuit modéré, et donne des gains en performance impressionnants. * La '''duplication des autres unités''' a un cout en circuit variable, pour des gains en performance eux aussi variables. * Le '''partage des ports d'émission''' réduit le cout en circuit du CPU, pour des pertes de performances mineures si bien fait. L'usage du partitionnement seul, sans duplication, était surtout le fait des processeurs commercialisés entre les années 1989 et 1993. Le partage des ports d'émission a lui aussi mis un peu de temps pour s'imposer. Globalement, les processeurs superscalaires ont évolués progressivement, pour se rapprocher d'une sorte de standard. Mais pour comprendre ce qu'est ce standard, et en quoi les CPU historiques s'en sont progressivement rapprochés, il faut étudier l'histoire des CPU superscalaires. L'histoire des CPU superscalaires a commencé dès 1960, mais est resté un projet de recherche pendant plusieurs décennies. De nombreux designs ont été conçus, mais abandonnés avant la production, comme l'ACS-1 d'IBM. Les années 1980 ont vu l'arrivée de prototypes de processeurs VLIW, mais qui n'étaient pas superscalaires. Par exemple, l'Apollo DN10000 et l'Intel i860 pouvaient émettre deux instructions à la fois, sous conditions, mais demandaient que le compilateur fasse une bonne partie du travail. Les premiers CPU superscalaires commercialisés sont sortis en 1989. Deux CPUs superscalaires sont sortis cette année là : le RS/6000 d'IBM et l'i960CA d'Intel. Puis, la compétition s'est aussi lancée dans la bataille. Les CPU commercialisés avant l'année 1993 étaient à double émission, à l'exception du SuperSPARC qui utilisait la triple émission. Les modèles après 1993 hésitaient entre double et quadruple émission. Dans le tableau ci-dessous, les processeurs quadruple émission sont en bleu, les triple émission sont en rouge, les autres ne sont pas en couleur. {|class="wikitable" |- ! !! IBM !! HP PA-RISC !! SPARC !! Intel!! Alpha !! Autres |- ! 1989 | RS/6000 || || || i960CA || || |- ! 1990 | || || || || || |- ! 1991 | || || || || || Motorola 88110 |- ! 1992 | RSC || PA 7100 || class="f_rouge | SuperSPARC || || 21064 || |- ! 1993 | PPC 601 || || HyperSPARC || Pentium || || |- ! 1994 | class="f_bleu | POWER 2 || PA 7200 || || || class="f_bleu | 21164 || |- ! 1995 | 603/604 || class="f_bleu | PA 8000 || class="f_bleu | UltraSPARC 1 || Microarchitecture P6 (+ concurrence AMD) || || class="f_bleu | MIPS R1000 |- ! 1996 | class="f_bleu | 620 || || || || class="f_bleu | 21264 || |- ! ... || ... || ... || ... || ... || ... || ... |} Les premiers CPU à double émission sont assez représentatifs des CPU à double émission modernes. Il faut dire que se limiter à deux voies ne permet pas de faire beaucoup de choses. Voici le tableau chronologique disant quel CPU utilisait quelle technique. * Les CPU en vert utilisaient la double émission entière-flottante. * Les CPU en rouge utilisaient la double émission entière "pure". * Les CPU en jaune utilisaient un ''partitionnement complet'' entre ALU, FPU et unité mémoire. * Les CPU sans couleur utilisaient un grand nombre d'unités, avec beaucoup de ports d'émission. * Les CPU barrés utilisent la triple ou quadruple émission et seront vu dans la section suivante. {|class="wikitable" |- ! !! IBM !! HP PA-RISC !! SPARC !! Intel!! Alpha !! Autres |- ! 1989 | class="f_vert | RS/6000 || || || class="f_rouge | i960CA || || |- ! 1990 | || || || || || |- ! 1991 | || || || || || Motorola 88110 |- ! 1992 | class="f_vert | RSC || class="f_vert | PA 7100 || <s>SuperSPARC</s> || || class="f_jaune | 21064 || |- ! 1993 | class="f_vert | PPC 601 || || class="f_jaune | HyperSPARC || class="f_rouge | Pentium || || |- ! 1994 | <s>POWER 2</s> || PA 7200 || || || <s>21164</s> || |} C'est en 1994, que la quadruple émission est arrivée et que les CPU ont essayé divers implémentations. Il y avait alors trois stratégies pour la double/triple/quadruple émission, qui partageaient des problèmes similaires. La première implémentation dupliquait les ALUs et les FPUs, ce qui permettait d'émettre deux opérations flottantes avec deux opérations entières. Le POWER 2 dupliquait ses FPUs à la perfection, alors que le 21264 séparait l'additionneur et le multiplieur flottant. Les accès mémoire étaient traités comme des opérations entières et le processeur pouvait souvent en émettre deux à la fois. Mais une telle organisation n'est plus utilisée de nos jours, car, sans instructions flottantes à exécuter, elle est équivalente à de la double émission. La seconde implémentation utilisait deux ALU entières (dont un multiplieur), une unité mémoire et une FPU.Cette organisation est intéressante, mais encore trop stricte pour donner de bons résultats, les quadruplets avec exactement deux opérations entières, un accès mémoire et une opération flottante étant trop rares. L'usage de ces 4 unités en double ou triple émission a été utilisé sur le PA 7200 et le SuperSPARC. Malheureusement, en plus de problèmes au niveau de son cache, le SuperSPARC avait de nombreuses contraintes d’appariement, car le banc de registre n'avait pas assez de ports pour alimenter certaines combinaisons d'instructions. De plus, s'il émettait une multiplication, il ne pouvait pas émettre de seconde µop. Enfin, une troisième implémentation utilisait un grand nombre d'unités fort différentes, bien plus que quatre, avec au minimum deux ALU entières. Prenons l'exemple de l'UltraSPARC, qui avait : deux ALU entières, une unité mémoire, une unité de branchement, un additionneur flottant, un multiplieur flottant, un diviseur flottant (aussi utilisé pour le calcul des racines carrées), et 2 unités graphiques pour les calculs sur des pixels. En tout, cela fait 9 unités différentes, pour de la quadruple émission. Dans le même genre, les processeurs MIPS R8000 et R10000 avaient une implémentation plus moderne, dans le sens où toutes les unités étaient dupliquées. Le CPU avait deux ALU, deux FPU et deux unités mémoire. Il pouvait donc émettre quatre instructions à la fois, tant que le paquet collait avec ces six unités. Moitié opérations entières, moitié opérations mémoire, avec de quoi remplacer les opérations entières par des opérations flottantes. Le PA 8000, lui, dupliquait toutes ses unités en deux exemplaires, ce qui n'est pas l'idéal, aucun processeur moderne ne fait cela aujourd'hui. Le tout est résumé dans le tableau ci-dessous, avec : * en vert les CPU utilisant la première stratégie ; * en rouge les CPU utilisant la seconde stratégie ; * en jaune les CPU utilisant la troisième stratégie. {|class="wikitable" |+ Processeurs quadruple émission historiques |- ! Année !! Processeur !! Unités |- ! 1991 | class="f_jaune | Motorola 88110 || class="f_jaune | 2 ALU + MUL + DIV + BIT + MEM + FADD + 2 unités graphiques |- |- ! rowspan="2" | 1994 | class="f_vert | POWER 2 || class="f_vert | 2 ALU/MEM + 2 FPU (+ 2 Branchements via ''branch folding'') |- | class="f_rouge | 21164 || class="f_rouge | 2 ALU + FPU + MEM |- ! rowspan="3" | 1995 | PA 8000 || 2 ALU + 2 ''barrel shifters'' + 2 MEM + 2 FPU (FMA) + 2 FPU (DIV et SQRT) + 2 SIMD |- | class="f_jaune | UltraSPARC 1 || class="f_jaune | 2 ALU + MEM + BRANCH + FADD + FMULFDIV + 2 unités graphiques |- | MIPS R8000 et R10000 || 2 ALU + 2 FPU + 2 MEM |- ! rowspan="2" | 1996 | class="f_rouge | 620 || class="f_rouge | 2 ALU + FPU + MEM |- | class="f_vert | 21264 || class="f_vert | 2 ALU/MEM + 2 FPU (FADD + FMUL) |} Malheureusement, ces CPUs historiques n'avaient ni assez d'unités de calcul entières, ni d'unités mémoire, pour remplir la quadruple émission. Environ la moitié des instructions d'un programme correspond à des instructions entières. Pour en profiter, un processeur à N voies doit disposer d'au minimum N/2 ALU entières, l'idéal étant d'aller au-delà. Les CPU superscalaires historiques avaient 2 ALU pour de la quadruple émission, ce qui était très limite. En comparaison, les CPU superscalaires modernes mettent le paquet niveau ALU entière. La plupart des CPU x86 modernes descendent rarement sous les 2/3, la plupart remplit presque la totalité de la largeur du CPU. Pour donner un exemple, la microarchitecture Golden Cove d'Intel est un processeur à 6 voies, avec 5 ALU entières. Pour être précis, un programme informatique exécute environ 40% de son code dans des instructions arithmétiques, un autre 40% dans les accès mémoire, et un le reste pour... le reste. La conséquence est que les processeurs modernes dupliquent leurs unités mémoire. Par exemple, la microarchitecture ''Golden Cove'' d'Intel dispose de trois unités mémoire : deux spécialisées dans les écritures, trois dans les lectures. La microarchitecture ''Gracemont'' utilise la pentuple émission et peut émettre 4 µops entières et 4 µops mémoire. Notez que le ratio est équilibré entre opérations entières et mémoire, avec soit égalité, soit un avantage pour les ALU entières. Une autre régularité est que la largeur totale du processeur peut être occupée par des opérations entières/mémoire. Pour le dire autrement, sur un processeur quadruple émission, il pourra émettre un mix de 4 instructions entière/mémoire, avec zéro opération flottante. Idem avec des processeurs triples ou pentuple émission, voire plus. Si le processeur émet une opération flottante, elle remplace une opération entière. Prenons l'exemple des processeurs AMD K6, sortis en 1997, juste avant les AMD Athlon. Ils avaient 10 unités de calcul, 6 ports d'émission, 4 ports de décodage. Voici exactement comment étaient répartie les unités de calcul sur les ports d'émission. C'était des processeurs quadruple émission, ce qui fait que la moitié de la largeur du processeur sert pour des opérations entières, et l'autre moitié pour les accès mémoire. {|class="wikitable" |- ! Port d'émission n°1 !! Port d'émission n°2 !! Port d'émission n°3 !! Port d'émission n°4 !! Port d'émission n°5 !! Port d'émission n°6 ! |- | ALU entière || ALU entière || FPU || Unité de branchement || Unité LOAD || Unité STORE |- | || Multiplieur || || || || Unité de calcul d'adresse (instruction LEA) |- | || ''Barrel shifter'' || || || || Unité pour les instructions PUSH |} Les microarchitectures K7, K8 et K10, utilisées sur les anciens CPU AMD Athlon, sont un exemple moins représentatif. Ces microarchitectures utilisent le partage des ports d'émission au maximum. C'était des microarchitectures à triple émission, avec six ports d’émission. Il y avait trois ports d'émission pour les opérations flottantes, et trois ports d'émission pour les micro-opérations entières/mémoire. Il y avait trois ALU entières et trois unités mémoire, chaque ALU partageait un port d'émission avec une unité mémoire. Elle pouvait donc émettre soit trois opérations entières, soit trois µops mémoire, soit un mix des deux. En plus des mix avec les opérations flottantes et branchements. {|class="wikitable" |- ! Port d'émission n°1 !! Port d'émission n°2 !! Port d'émission n°3 !! Port d'émission n°4 !! Port d'émission n°5 !! Port d'émission n°6 ! |- | ALU entière || ALU entière || ALU entière || FADD || FMUL || FPU (autres opérations) |- | Multiplieur || || || || || |- | LOAD/STORE || LOAD/STORE || LOAD/STORE || || || |} Les CPU superscalaires larges dupliquent les multiplieurs et/ou les ''barrel shifters'', et même les unités de branchement. La raison est que quand la largeur du CPU augmente, le processeur traite des paquets d'instructions de plus en plus gros. Par exemple, pour un CPU à 10 voies, cela veut dire émettre 10 instructions en même temps. Il est alors plus fréquent d'avoir deux multiplications, deux décalages, deux accès mémoire, deux branchements. Par exemple, la moyenne est d'une multiplication tous les 5 instructions. Les CPU superscalaires à 10 voies ont donc tendance à avoir deux multiplications par paquet d'instruction, en moyenne. Avoir deux multiplieurs est alors un gain en performance clair. Par exemple, la microarchitecture ''Golden Cove'' a deux ''barrel shifters''. C'est une architecture à 6 voies. {|class="wikitable" |- ! Port d'émission n°1 !! Port d'émission n°2 !! Port d'émission n°3 !! Port d'émission n°4 !! Port d'émission n°5 !! Port d'émission n°6 !! Port d'émission n°7 !! Port d'émission n°8 !! Port d'émission n°9 !! Port d'émission n°10 |- | ALU entière || ALU entière || ALU entière || ALU entière || ALU entière || LOAD || LOAD || LOAD || STORE || STORE |- | ''Barrel shifter'' || Multiplieur || Multiplieur || ''Barrel shifter'' || || || || || || |- | Branchements || Diviseur || || Branchements || || || || || || |} ==Les µops mémoire sur les processeurs superscalaires== Plus haut, nous avons volontairement passé sous silence les accès mémoire. La raison à cela est que leur support sur les CPU superscalaire peut se faire de plusieurs manières différentes, qu'il vaut mieux expliquer dans une section dédiée. Les différentes implémentations sont décrites dans la liste suivante, nous allons les voir une par une. * Avec la première méthode, les accès mémoire sont exécutés par le pipeline pour les opérations entières. * Avec la seconde méthode, les accès mémoire ont un pipeline dédié ; c'est l'''émission parallèle des accès mémoire''. * Avec la troisième méthode, il est possible d'émettre plusieurs accès mémoire simultanément : c'est l'''émission multiple des accès mémoire''. Voyons ces trois cas dans le détail. Nous verrons notamment les différentes formes d'émission multiple des accès mémoire. ===Les accès mémoire traités dans le pipeline entier=== Dans le cas le plus simple, les accès mémoire sont traités comme des opérations entières un peu spéciales. L'unité mémoire est sur le même port d'émission que l'ALU entière, ce qui fait que les accès mémoire remplacent des opérations entières. Faire ainsi permet d'utiliser une ALU entière pour les calculs d'adresse, pas besoin de rajouter une unité de calcul d'adresse séparée. Typiquement, un processeur de ce type place l'unité mémoire après l'unité de calcul. Les opérations entières n'utilisent que l'ALU entière, mais pas l'unité mémoire. Les accès mémoire exécutent un calcul d'adresse dans l'ALU entière, puis l'adresse calculée est envoyée à l'unité mémoire. Le tout est illustré ci-dessous, dans le cas d'un processeur historique à double émission entière-flottante. [[File:Processeur non-superscalaire basique 01.png|centre|vignette|upright=1.5|Processeur non-superscalaire basique]] Un exemple de CPU double émission de ce type est celui du Power PC 440, un CPU destiné à l'embarqué. Vu qu'il était destiné à l'embarqué, il n'avait pas de FPU, il n'avait pas besoin de manipuler de nombres flottants. Il n'a donc que des ALU entières, un multiplieur et une unité mémoire. Il dispose de deux ports d'émission. Le premier est connecté à une ALU entière et un circuit multiplieur, le second est relié à l'unité mémoire et une seconde ALU entière. Une organisation simple, mais très efficace ! [[File:PowerPC 440.png|centre|vignette|upright=2|Microarchitecture du PowerPC 440.]] L'implémentation économise une unité de calcul d'adresse, mais n'a pas de cout en performance significatif. Les accès mémoire étant très lents, émettre une µop entière en parallèle d'un accès mémoire ne sert pas à grand-chose. On peut émettre cette µop entière un cycle plus tard, elle sera terminée avant même que l'accès mémoire soit terminé, même si l'accès mémoire se fait dans le cache L1 ou L2. Pour comprendre pourquoi, faisons quelques calculs. Un accès mémoire prend deux-trois cycles quand il tombe dans le cache L1. Et on doit attendre qu'il soit terminé pour en émettre un nouveau. Combien d'instructions arithmétiques peut-on lancer pendant ce temps, sur un CPU triple émission ? Au premier cycle, on peut en émettre 2 (l'instruction mémoire prend une place, donc 3-1), puis 3 au second cycle. Ce qui fait 5 instructions arithmétiques au total. Or, il se trouve qu'il y a une instruction d'accès mémoire pour 5 instructions arithmétiques, environ. Par contre, ce compromis change quand on passe à la quadruple émission, voire au-delà. Dans ce cas, il devient intéressant de pouvoir émettre une nouvelle instruction mémoire à chaque cycle. Ce qui nous amène à la section suivante... ===L'émission parallèle des accès mémoire=== A partir de la quadruple émission, la tendance a été de séparer l'unité mémoire des ALU entières. Cela permet d'émettre des µops mémoire en même temps que des µops entières et/ou flottantes., ce qui porte le nom d''''émission parallèle des µops mémoire''', ou encore ''émission mémoire parallèle''. Par exemple, un processeur quadruple émission peut émettre en même temps deux opérations entières, une opération flottante et un accès mémoire. L'accès mémoire vient en plus des opérations entières, il n'est pas possible de remplacer l'accès mémoire par une opération entière. La technique ne permet pas de faire les calculs d'adresse dans l'ALU entière. Il faut donc utiliser une unité de calcul d'adresse séparée. Elle est intégrée dans l'unité mémoire, qui fait l'interface entre le cache et le banc de registres. Le cout en circuits est très faible, car les unités de calcul d'adresse n'utilisent guère plus qu'un additionneur et un circuit de décalage très simple. L'émission mémoire parallèle est plus facile à implémenter sur les CPU RISC, qui ont des instructions mémoire séparées du reste. Les CPU CISC ne sont pas dans ce cas, ce qui fait que séparer l'unité mémoire du pipeline entier est compliqué. Les CPU superscalaires historiques étaient pour moité des CPU RISC et pour moitié des CPU CISC, ce qui fait qu'ils n'utilisaient pas ou peu l'émission mémoire parallèle. Les premiers processeurs superscalaires se contenaient de l'émission parallèle mémoire, ils ne pouvaient émettre qu'un seul accès mémoire à la fois, l'unité mémoire n'était pas dupliquée. Et ce n'est pas tant un problème que ça, du moins sur les processeurs à double ou triple émission. En effet, il est rare que l'unité mémoire doive faire deux accès simultanés. Notons que le processeur peut exécuter une instruction mémoire en parallèle d'un calcul ou d'un branchement, seuls les accès mémoire simultanés sont impossibles. ===L'émission multiple des accès mémoire avec une LSQ=== Les processeurs superscalaires larges travaillent sur des paquets de 8 à 10 instructions, il est plus fréquent d'avoir plusieurs accès mémoire par paquet. Dans ces conditions, il est utile d'avoir une '''émission multiple des accès mémoire''', à savoir d'émettre plusieurs micro-opérations mémoire en même temps. Les processeurs superscalaires modernes sont capables d'émettre plusieurs lectures/écritures simultanément. Par exemple, ils peuvent émettre une lecture en même temps qu'une écriture, ou plusieurs lectures, ou plusieurs écritures. Il faut noter que selon le processeur, il peut y avoir des restrictions quant aux accès mémoire émis en même temps. Par exemple, certains processeurs peuvent émettre une lecture avec une écriture en même temps, mais pas deux lectures ni deux écritures. Ou encore, ils peuvent émettre deux lectures, une lecture et une écriture, mais pas deux écritures en même temps. Dans la majorité des cas, les processeurs ne permettent pas d'émettre deux écritures en même temps, alors qu'ils supportent plusieurs lectures. Il faut dire que les lectures sont plus fréquentes que les écritures. Les processeurs qui autorisent toutes les combinaisons de lecture/écriture possibles, sont rares. L'émission multiple des accès mémoire s'implémente dans l'unité mémoire. Pour rappel, l'unité mémoire s'interpose entre le cache L1 et le reste du pipeline. Dans le cas le plus simple, elle incorpore une ''load/store queue'' et des unités de calcul d'adresse. L'émission multiple des accès mémoire demande de rendre la ''Load-store queue'' multi-ports, afin de gérer plusieurs micro-opérations mémoire simultanées. Il faut aussi dupliquer les unités de calcul d'adresse reliées à la LSQ, chaque port d'émission mémoire devant avoir sa propre unité de calcul d'adresse. : Dans ce qui suit, nous parlerons d'AGU (''Adress Generation Unit'') pour désigner les unités de calcul d'adresse, et de LSQ pour designer la ''Load-store queue''. [[File:Processeur non-superscalaire basique 02.png|vignette|upright=1|Processeur non-superscalaire basique]] Dupliquer les ports de la LSQ et les AGU est nécessaire. Mais qu'en est-il du cache ? La réponse varie suivant le processeur. Il y a deux grandes méthodes pour implémenter l'émission multiple des accès mémoire. La première méthode ajoute des ports de lecture/écriture au cache de données, pour faire des lectures/écritures simultanées. Il faut alors dupliquer des unités de calcul, rajouter les ports sur le cache, mais aussi rajouter des ports sur la ''load/store queue'', pour qu'elle échange des données/commandes mémoire avec le cache. Le cout en circuits est alors conséquent La seconde duplique les unités de calcul, mais pas les ports d'accès au cache. Les accès mémoire sont alors accumulés dans la ''load/store queue'', qui sont ensuite traités un par un par le cache. Un exemple est celui des processeurs AMD de micro-architecture K7 K8, à savoir les anciens AMD Athlon et AMD Athlon 64, qui pouvaient calculer trois adresses simultanément, mais ne pouvaient faire qu'un seul accès au cache par cycle. Le cout en circuit est modéré : les unités de calcul coutent très peu, les ports de la ''load/store queue'' coutent déjà un peu plus. Quelques processeurs utilisaient des solutions intermédiaires. Un processeur utilisant cette technique est, par exemple, capable d'émettre quatre µops mémoire en même temps, mais avec seulement deux ports sur le cache. Un exemple classique étant les Pentium 1 et 2 d'Intel, dont nous parlerons dans le chapitre suivant. ===L'émission séparée des LOAD et STORE=== De rares processeurs ont des ports d'émission qui peuvent faire indifféremment lecture comme écritures. Mais les processeurs modernes préfèrent séparer ports d'émission pour les lectures et les écritures. Un exemple est celui des processeurs Intel de micro-architecture Nehalem, qui avaient un port de lecture et un port d'écriture tous deux reliés à la ''Load-store queue'', chacun avec leur propre unité de calcul d'adresse. Comme autre exemple, les processeurs skylake ont une LSQ avec deux ports de lecture et un port d'écriture, ce qui permet d'émettre deux lectures en même temps qu'une écriture. Dans cette section, nous allons étudier le cas avec des ports séparés pour les lectures et écritures. En général, les processeurs ont un peu plus de ports de lectures que d'écritures. Une raison est qu'un programme a, en moyenne, un tout petit peu plus de lectures que d'écritures. Mais la différence n'est pas énorme, c'est un léger déséquilibre. Une seconde raison est que l'exécution dans le désordre marche bien mieux quand les lectures ont lieu le plus tôt possible. Donc mieux vaut privilégier les lectures à l'émission, pour qu'elles se fassent un peu en avance. En pratique, la différence n'est pas très marquée. Il est courant d'avoir un port de lecture et un d'écriture, les CPU superscalaires très larges ont souvent deux ports de lecture et deux d'écriture. A la rigueur, quelques CPU ont trois ports de lecture et deux d'écriture. Le cas le plus simple est celui où on peut émettre une lecture et une écriture en même temps. Il s'implémente facilement si la LSQ est en réalité une simple ''Store queue'', à savoir qu'elle met en avance les écritures uniquement. Pour rappel, les écritures sont mises en attente dans la ''Store queue'', mais les lectures sont exécutées immédiatement. Une fois l'adresse à lire connue, la lecture consulte la ''Store queue'' pour détecter les dépendances de données, puis s'exécute. La donnée à lire est lue soit depuis la ''Store queue'', soit depuis le cache. [[File:Emission LOAD - Store séparée.png|vignette|upright=1|Émission LOAD - Store séparée]] L'implémentation de l'émission multiple est alors très simple. La ''Store queue'' a déjà deux ports, avec un pour les lectures et un autre pour les écritures. Idem pour le cache, qui a naturellement un port de lecture et un d'écriture. Émettre une lecture et une écriture simultanément ne demande donc pas de modification digne de ce nom. La ''Store queue'' doit juste supporter une lecture et une écriture simultanée. Ajouter l'émission d'une seconde lecture n'est pas compliquée : il faut juste rajouter un second port de lecture sur le cache et la ''Store queue''. Pour rappel, l'unité mémoire est précédée par une structure qui met en attente les micro-opérations mémoire avant leur émission finale. La structure en question varie suivant l'implémentation, mais un cas particulier se marie bien avec l'émission multiple des µops mémoire. Il s'agit du cas avec une file de µops séparée pour les lectures et une autre pour les écritures, appelées respectivement la ''file de µops LOAD'' et la ''file de µops STORE''. Il est alors possible d'émettre une lecture et une écriture lors du même cycle d'horloge. Le port de lecture alimente une unité de calcul d'adresse dédiée, directement reliée au cache. Le port d'écriture du cache alimente une unité de calcul, qui est suivie par une file d'écriture, elle-même reliée au cache. Les processeurs AMD de micro-architecture K6 utilisaient cette technique. [[File:Double émission avec le Load Ordering, Store Ordering.jpg|centre|vignette|upright=2.5|Double émission avec le Load Ordering, Store Ordering]] ==Les CPU superscalaire à exécution dans le désordre== La superscalarité modifie aussi les circuits dédiés à l'exécution dans le désordre. Elle modifie les unités de renommage de registre, le ROB et les autres structures liées à l'exécution dans le désordre, au sens large. Aucune structure n'est épargnée. Elles ont tous des prots de lecture/écriture en plus, afin d'encaisser l'émission, le ''commit'' ou le renommage simultané de plusieurs µops. Par exemple, le ROB doit être modifié pour émettre et terminer plusieurs instructions en même temps, en ajoutant des ports de lecture/écriture. Pour un CPU superscalaire à 8 voies, on se dit que le ROB peut retirer 8 µops par cycle maximum. Mais certains processeurs récents ont un ROB qui peut retirer le double ! Un exemple est celui des CPU de micro-architecture Skymont, qui peuvent émettre 8 µops par cycle, mais en retirer 16. Quelques CPU de marque AMD étaient aussi dans ce cas. L'avantage est que cela permet de réduire la taille du ROB, du banc de registre et de quelques autres structures matérielles liées à l'exécution dans le désordre. Le gain sur-compense le cout en transistor nécessaire pour retirer 16 µops par cycle. Dans cette section, nous allons voir comment les étages du pipeline dédiés à l'exécution dans le désordre sont modifiées sur un CPU superscalaire. ===L'exemple du PA-RISC PA 8000=== Avant de commencer, nous allons voir un processeur superscalaire assez simple, le PA 8000, de HP, qui implémente le jeu d'instruction PA-RISC. Bien que très ancien, il implémentait l'exécution dans le désordre et le renommage de registre. Le peu d'informations que nous avons sur ce processeurs proviennent des documents "THE HP PA-8000 RISC CPU" par Ashok Kumar, et l'article de microprocessor report "PA-8000 Combines Complexity and Speed". Ils ne donnent malheureusement pas énormémment d'informations et je devrais être amené à faire quelques suppositions dans ce qui suit. Avant de commencer, parlons de détails sans lien avec la superscalairité. Ce processeur, comme beaucoup de processeurs PA-RISC, n'intégrait pas de cache de niveau L2 dans le processeur, qui était déporté en-dehors du CPU, sur la carte mère. Le processeur préférait utiliser ses transistors pour avoir un cache L1 assez large, quitte à ce qu'il soit plus lent. La lenteur du cache était prévue, le processeur compensait celle-ci en utilisant l'exécution dans le désordre, bien que ce ne soit pas parfait. Les CPU PA-RISC avant le PA 8000 utilisaient un pipeline à vagues ''wave pipeline'', ce qui était assez peu commun, mais le PA 8000 repasse à un pipeline synchrone classique. Passons maintenant à la superscalarité. Le PA 8000 est un processeur quadruple émission, qui peut émettre, à chaque cycle, deux opérations et deux accès mémoire. Le renommage de registre utilise des registres de renommage séparés des registres architecturaux, comme c'était la mode à l'époque. Le budget en transistor faisait que c'était soit ça, soit le renommage dans le ROB, faute de mieux. L'exécution dans le désordre, quant à elle, est prise en charge par une structure matérielle unique, qui ressemble à une fusion entre un ROB et une fenêtre d'instruction. Et c'est là que je vais devoir faire des suppositions. Le document "THE HP PA-8000 RISC CPU" nomme cette structure : l'''Instruction Reorder Buffer''. Il est décrit comme une fenêtre d'instruction dans le texte, à savoir qu'il détecte les dépendances entre instruction et se charge de les émettre. Il gère aussi la détection des mauvaises prédictions de branchement et peut annuler les instructions chargées à tord, en les retirant de la fenêtre d'instruction. Il utilise pas moins de 850 000 transistors, et prend 20% de la taille du ''die''. La fenêtre d'instruction peut mémoriser 56 µops, dans 56 entrées. La moitié d'entre elles est réservée aux instructions de calcul entier/flottant, l'autre est réservée aux µops mémoire. Une manière de voir les choses est qu'il y avait deux fenêtres d'instructions, de 28 entrées/µops chacune. L'une était spécialisée pour les ALU/FPU, l'autre pour les µops LOAD et STORE. Cependant, il s'agit là d'une interprétation, il n'est pas dit si les deux étaient séparées ou au contraire fusionnées en un seul circuit. Chaque fenêtre d'instruction pouvait recevoir 4 µops par cycle de la part des décodeurs, et répartissait ces 4 µops dans les deux fenêtres d'instructions. A chaque cycle, la fenêtre d'instruction émet les deux µops les plus anciennes qui sont prête à être exécutées. La documentation dit que la fenêtre émet "la plus vielle instruction paire, et la plus vielle instruction impaire", ce qui sous-entend que la fenêtre d'instruction est en réalité composée de deux sous-fenêtres, une fenêtre paire et une impaire. Les µops sont insérées après le décodage dans ces sous-fenêtres : les deux µops sont réparties dans les deux. Et lors de l'émission, une µops vient d'une sous-fenêtre, une autre µops vient de l'autre. La fenêtre d'isntruction a donc une structure partitionnée, avec une logique d'éveil segmentée, une partie gérant la moité de la fenêtre d'instruction, l'autre gérant le reste. Les instructions quittent l'''Instruction Reorder Buffer'' dans l'ordre du programme, ce qui fait qu'il se comporte comme un ROB de ce point de vue là. Elles ne peuvent en sortir que quand elles ont été exécutées et qu'elles n'ont causé aucune exception. ===La superscalarité avec une file/fenêtre d'instruction centralisée=== Plus haut, nous avons montré qu'un processeur pouvait avoir plus de ports d'émission que de ports de décodage. On dit aussi que sa ''largeur de décodage'' était supérieure à sa ''largeur d'émission''. La '''largeur de décodage''' est le nombre de µops fournies par l'unité de décodage par cycle d'horloge, la '''largeur d'émission''' est le nombre maximal de µops émises par cycle d'horloge. Et n'allez pas croire qu'un surplus de ports d'émission est du gâchis. Sur les processeurs avec exécution dans le désordre, ce surplus peut être utilisé. Mais avant toute chose, évacuons un détail. Vous avez sans doute pensé que le surplus peut être exploité par les instructions machines décodées en plusieurs µops . Par exemple, si une instruction est décodée en deux µops, on pourrait avoir un port d'émission en plus pour en profiter. Mais les ports de décodage sont *en sortie du décodeur*, et contiennent des µops, pas des instructions. Le surplus de ports d'émission peut occasionnellement utiliser le surplus de ports de décodage, mais cela implique que des µops ont été mises en attente dans l'unité d'émission, pour être émises par la suite. Et cela implique l'usage d'une fenêtre d'instruction ou d'une file de µops. Le principe est que les µops sont accumulées dans la fenêtre d'instruction, en attendant leurs opérandes ou la résolution d'une dépendance. Et si l'occasion se présente, une µops est émise sur chaque port d'émission. Il y a donc un gain en performances, mais il faut faire quelques précisions sur son origine. La largeur d'émission utilisée ne peut pas dépasser, *en moyenne*, la largeur de décodage. Et c'est intuitif : un CPU qui décode 4 µops par cycle ne peut pas émettre 6 par cycle en moyenne, sur le temps long, il n'y a pas de µops en surplus qui sortent du vide. Par exemple, sur un processeur quadruple émission, si on analyse combien d'instructions sont émises par cycle, il peut y avoir des cycles où la largeur d'émission est totalement utilisée, mais ce sera compensé par des périodes où elle est fortement sous-utilisée. Les µops sont accumulées en cas de sous-utilisation, puis consommées en cas d'utilisation complète. Les deux périodes se compensent. Et c'est là que l'on peut comprendre d'où vient le gain en performance. Les cycles où les ports d'émission sont sous-utilisés existent systématiquement, que le processeur utilise l'exécution dans le désordre ou pas. Ils sont liés à la présence de dépendances de données, aux contraintes d’appariement, etc. Elles tendent à réduire la moyenne du nombre de µops émises par cycle. Par contre, ce sont les cycles de rattrapage, où les ports en surplus sont utilisés, qui font remonter la moyenne. Le gain en performance est donc lié à ces cycles de rattrapage, où les µops accumulées sont émises dans les ports en surplus. Et ils n'existent que sur les processeurs avec une file/fenêtre d'instruction. Réduire le nombre de ports d'émission permet de garder des fenêtres d'instruction et un ROB simples, rapides et économes en énergie. Et mine de rien, c'est là un compromis important : à quoi bon augmenter le nombre de ports d'émission si c'est pour que ce soit compensé par une fréquence plus faible ? Par contre, réduire le nombre de ports augmente la ''port contention'', surtout si on a mal réparti les ALU. Il faut donc trouver un compromis entre réduire le nombre de ports d'émission d'un côté, réduire la ''port contention'' de l'autre. La différence entre largeur de décodage et d'émission a un impact assez fort sur le banc de registre, et précisément sur son nombre de ports de lecture. Le banc de registre a besoin de plus de ports de lecture avec une fenêtre d’instruction qu'avec des stations de réservation. Rappelons la terminologie utilisée dans ce cours. Les fenêtres d'instruction se contentent de mémoriser la micro-opération et quelques bits pour détecter la disponibilité des opérandes. Par contre, les stations de réservations mémorisent aussi les opérandes des instructions. Et cette différence a une influence le nombre de ports de lecture du banc de registre. Supposons que toutes les instructions sont dyadiques, à deux opérandes. Comptons le nombre de ports nécessaires pour alimenter les unités de calcul, sans utiliser d'arbitre de banc de registre. Avec une fenêtre d'instruction, il faut le double du nombre de ports d'émission. Mais avec des stations de réservation, il faut le double des ports de décodage. La raison est que les registres sont lus après émission avec une fenêtre d'instruction, avant avec des stations de réservation (sous-entendu, après le décodage). Or, comme dit plus haut, les processeurs superscalaires larges ont souvent plus de ports d'émission que de décodage. ===La superscalarité à fenêtres d'instruction décentralisées=== Les processeurs précédents utilisaient une unité d'émission simple, qui pouvait utiliser l'émission dans l'ordre ou dans le désordre. Elle peut être remplacée par une fenêtre d'instruction centralisée dans que cela quoi que ce soit aux explications précédentes, idem avec une station de réservation centralisée. En soi, l'exécution dans le désordre est donc totalement compatible avec une implémentation simple de la superscalarité. Par contre, des subtilités surviennent avec les fenêtres d'instruction décentralisées. Pour rappel, sur ces processeurs, les µops sont émises en deux phases. Une première phase de ''dispatch'' qui envoie les µops vers la fenêtre d'instruction adéquate, sans détecter les dépendances de données. La seconde phase de ''schedule'' gère les dépendances de données, elle met en attente les µops en attendant que l'unité soit disponible pour les exécuter, en attendant aussi que les opérandes soient disponibles. Et à ce petit jeu, il y a une différence entre le nombre de µops qui sont ''dispatch par cycle'' et celles qui sont ''schedule''. Dit autrement, la largeur d'émission est scindée en une '''largeur de ''dispatch''''' et une '''largeur de ''schedule''. Par exemple, prenons un processeur triple émission avec deux stations de réservation : une pour les µops entières/mémoire, et une autre pour les µops flottantes. L'unité d'émission peut ''dispatch'' maximum trois µops par cycle : soit trois µops entières/mémoire, soit trois flottantes, soit un mix de trois µops différentes. Les stations de réservation, quant à elles, peuvent chacune ''schedule'' 3 µops par cycle, vers trois ALUs entières pour la station de réservation entière/mémoire, vers trois FPS pour la station de réservation flottante. De quoi ''dispatch'' trois µops, mais d'en ''schedule'' six, à chaque cycle. Et cet exemple ne sort pas de nulle part : les CPU x86 d'Intel et AMD sont globalement dans ce cas, même si les chiffres varient d'une microarchitecture à l'autre. L'exemple précédent colle parfaitement à la microarchitecture K7 d'AMD, utilisée sur les processeurs Athlon dans les années 2000. [[File:AMD K7.png|centre|vignette|upright=2.5|AMD K7, microarchitecture.]] L'exemple précédent avait assez d'unités entières/flottantes pour couvrir toute la largeur de décodage/''Dispatch''. Mais ce n'est pas toujours le cas, comme va le montrer l'exemple suivant. Le MIPS R10000, qui utilisait un mélange de files de µops et de fenêtres d'instructions : une file de µops les accès mémoire, une fenêtre pour les instructions entières et une autre pour les opérations flottantes. Les branchements et NOPs étaient exécutés dans une unité de branchement distincte. Les trois files/fenêtres peuvent mémoriser 16 µops. Le processeur avait deux ALU entières, une AGU de calcul d'adresse, un additionneur flottant et un multiplieur/diviseur flottant. Il y avait un multiplieur entier sur le port d'émission l'ALU 2. Le processeur décodait 4 instructions par cycle et produisait jusqu'à 4µops, qui étaient redistribuées sur les trois fenêtres d'instructions. Chacune pouvait accepter 4 µops par cycle, ce qui fait que processeur pouvait ''dispatch'' 4 µops entières, ou 4 µops flottantes, ou 4 µops mémoire, ou un mélange de deux ou trois types de µops. Pour ce qui est du ''schedule'', la fenêtre d'instruction entière pouvait émettre 2 µops, la fenêtre flottante pouvait émettre une addition en même temps qu'une multiplication/divison flottante et qu'un branchement conditionnel flottant, et la file de µops mémoire ne pouvait émettre qu'une µop mémoire à la fois. En tout, cela fait 6 µops ''schedule'' pour 4 µops au ''dispatch''. [[File:R 10000.png|centre|vignette|upright=2.5|MIPS R10000, microarchitecture.]] ===La superscalarité à fenêtres d'instruction totalement décentralisées=== Prenons un cas extrême de fenêtre d'instruction décentralisée : celui où chaque ALU entière a sa propre station de réservation. En clair : une fenêtre d'instruction par ALU/FPU ! On parle de '''fenêtres d'instruction totalement décentralisées'''. Vous vous dites que ce cas est un peu trop extrême pour être réaliste, mais il n'en est rien. C'est même très courant sur les architectures basse consommation, et sur pas mal de CPU x86 modernes. Une telle organisation entraine une légère perte de performance, comparé à une fenêtre d'instruction centralisée ou partiellement décentralisée. Et cela peut se comprendre par un exemple. Imaginez un processeur avec deux ALU, donc deux stations de réservation. Il arrivera qu'une station de réservation ait plusieurs µops prêtes, alors que l'autre en ait zéro. Dans une telle situation, une seule µop sera émise au cycle suivant, vu que chaque station de réservation a un seul port d'émission vers une seule ALU entière. Par contre, avec une fenêtre d'instruction centralisée double port, on aurait pu émettre les deux µops en même temps sur deux ALUs séparées. La perte de performance est donc liée au fait que les µops '''''prêtes''''' sont mal réparties dans les différentes stations de réservation. Il arrivera que des µops prêtes s'accumulent dans une station de réservation, alors que d'autres seront pleines, ou du moins sous-utilisées. Et ce n'est pas quelque chose qui peut être réglé à l'étape de ''dispatch'', car on ne sait pas encore quand les µops auront leurs opérandes de disponibles. [[File:Comparaison entre une station de réservation totalement décentralisée et une autre qui ne l'est pas.png|centre|vignette|upright=2.5|Comparaison entre une station de réservation totalement décentralisée et une autre qui ne l'est pas.]] Par contre, décentraliser totalement les fenêtres d'instruction entraine aussi un gain considérable en termes de consommation énergétique. Et c'est la raison pour laquelle les fenêtres d'instructions totalement décentralisées sont utilisées sur les architectures basse consommation. La perte de performance ne peut pas s'expliquer clairement à ce stade du cours, car il nous faudrait parler d'émission superscalaire. Le gain en matière d'énergie vient de l'économie de circuits, qui est assez drastique. Le gain en matière d'énergie vient de l'économie de circuits, qui est assez drastique. Je rappelle qu'une station de réservation a besoin, pour N instructions, d'environ N^2 circuits (des comparateurs, notamment). Prenons une station de réservation centralisée de 64 entrées et comparons avec 8 stations de 8 entrées chacune. Les deux donneront 64 entrées, mais la première aura un cout en circuit proportionnel à 64², alors que le second aura un cout en circuit de 8 *(8²). Entre les deux, le choix est clair : la seconde solution est plus économe. D'où l'utilisation de cette solution sur les microarchitectures basse consommation. ===L'unité de renommage superscalaire=== Avec la superscalarité, l'unité de renommage de registre doit gérer le cas où des instructions consécutives ont des dépendances de registre. Par exemple, prenons un processeur à double émission, qui renomme deux instructions consécutives. Si elles ont une dépendance de registre, le renommage de la seconde instruction dépend du renommage de la première. La première doit être renommée et le résultat du renommage est utilisé pour renommer la seconde, ce qui empêche d'utiliser deux unités de renommage séparées. Pour cela, elle renomme les registres sans tenir compte des dépendances, pour ensuite corriger le résultat. [[File:Unité de renommage superscalaire.png|centre|vignette|upright=2|Unité de renommage superscalaire.]] Seules les dépendances lecture-après-écriture doivent être détectées, les autres étant supprimées par le renommage de registres. Repérer ce genre de dépendances se fait assez simplement : il suffit de regarder si un registre de destination d'une instruction est un opérande d'une instruction suivante. [[File:Détection des dépendances sur un processeur superscalaire.png|centre|vignette|upright=2|Détection des dépendances sur un processeur superscalaire.]] Ensuite, il faut corriger le résultat du renommage en fonction des dépendances. Si une instruction n'a pas de dépendance avec une autre, on la laisse telle quelle. Dans le cas contraire, un registre opérande sera identique avec le registre de destination d'une instruction précédente. Dans ce cas, le registre opérande n'est pas le bon après renommage : on doit le remplacer par le registre de destination de l'instruction avec laquelle il y a dépendance. Cela se fait simplement en utilisant un multiplexeur dont les entrées sont reliées à l'unité de détection des dépendances. On doit faire ce replacement pour chaque registre opérande. [[File:Correction des dépendances sur un processeur superscalaire.png|centre|vignette|upright=2|Correction des dépendances sur un processeur superscalaire.]] ==Les optimisations des processeurs superscalaires larges== Les processeurs superscalaires larges ont des optimisations spécifiques, qui n'ont pas de sens sur les processeurs superscalaires étroits. Dans les grandes lignes, elles se classent en deux types. Les premières permettent de charger/décoder plus de 5-10 instructions simultanément. Le problème est alors que les branchements viennent mettre leur grain de sel et qu'il faut en tenir compte. Les secondes corrigent des problèmes qui apparaissent quand un CPU intègre plus de 5 à 10 unités de calcul. ===L'étape de chargement d'un CPU superscalaire large=== Charger plusieurs instructions pose de nombreux problèmes sur les processeurs superscalaires larges, qui émettent de 5 à 10 instructions simultanées. Pour rappel, la stratégie basique pour charger N instructions est de charger un bloc de N instructions consécutives. Les instructions après un branchement ne sont pas décodées ni exécutées, ce qui entraine une petite baisse de performance. Pour un N petit, la perte de performance est mineure. Mais pour un N large, elle devient suffisamment importante pour que la conception du CPU doit alors être repensée de fond en comble. Les analyses statistiques disent qu'il y a environ un branchement tous les 4 à 6 instructions. Un CPU a donc tendance à décoder des paquets de 3 à 5 instructions consécutives, avant qu'un branchement casse la dynamique. Or, cela pose des problèmes pour utiliser plusieurs décodeurs. L'implémentation basique, qui charge N instructions consécutives pour alimenter N décodeurs, fonctionne donc jusqu'à 4/6 décodeurs. Au-delà de 5 instructions, un CPU superscalaire doit être adapté pour gérer les branchements dans les paquets d'instruction qu'il émet. Le nombre de 5 instructions ne sort donc pas de nulle part. La première solution utilise un cache de µops, avec un ''front-end'' capable de charger/décoder 4/5 instructions à la fois, pas plus. L'idée est que la majorité des instructions proviennent du cache de µops (plus de 80%), ce qui fait qu'on peut émettre environ 10 instructions à partir du cache de µops, pas besoin d'avoir beaucoup de décodeurs. Les performances sont cependant dégradées lors d'un défaut de cache de µops. Les instructions doivent alors être chargées depuis le cache d'instruction, par paquets de 4-5, puis sont décodées par 4-5 décodeurs, ce qui ne permet pas d’alimenter les unités de calcul à plein régime. La solution précédente joue sur la distinction entre pots de décodage et d'émission. Elle permet d'émettre un grand nombre de µops sans pour autant charger un grand nombre d'instructions en même temps. En quelque sorte, ce n'est qu'une méthode de contournement, le CPU superscalaire reste de type étroit. Mais il est aussi possible d'utiliser un '''''front-end large''''', capable de charger une bonne dizaine d'instructions en même temps. La seule difficulté est de tenir compte de la présence de branchements. Pour rappel, avec un ''front-end'' étroit, les instructions situées après le premier branchement pris sont annulées, elles ne sont pas décodées ni exécutées. [[File:Fetch sur un processeur superscalaire avec prediction de branchements.png|centre|vignette|upright=2|Fetch sur un processeur superscalaire avec prédiction de branchements.]] Un ''front-end'' large charge les instructions de destination du branchement et les placent à sa suite. Ils chargent deux blocs à la fois et les fusionnent en un seul qui ne contient que les instructions présumées utiles. [[File:Cache d'instructions autoaligné.png|centre|vignette|upright=2|Cache d'instructions auto-aligné.]] Mais cela demande de charger deux blocs de mémoire en une fois, ce qui demande un cache d'instruction multiports. Il faut aussi ajouter un circuit pour assembler plusieurs morceaux de blocs en un seul : le fusionneur (''merger''). En pratique, cette solution demande d'ajouter un second port de lecture au cache, pour un cout en hardware important, avec un impact négatif sur le temps d'accès au cache. Et il faut rajouter le fusionneur, qui prend un étage de pipeline à lui tout seul. Et encore, cette solution ne gère pas le cas où un bloc contient plusieurs branchements ! [[File:Implémentation d'un cache d'instructions autoaligné.png|centre|vignette|upright=2|Implémentation d'un cache d'instructions auto-aligné.]] Les exemples précédents partent du principe qu'il n'y a qu'un seul branchement dans un bloc. Mais quand les blocs deviennent assez longs, il est fréquent d'avoir plusieurs branchements dans un bloc. Et il est même possible d'avoir plusieurs branchements pris. Dans un bloc de 8-10 instructions, ce n'est pas rare, et les CPU superscalaires à 8-10 voies sont la règle dans les CPU des années 2020. Pour gérer ce cas, il faut ajouter des ports supplémentaires au cache d'instruction et adapter le fusionneur, pour qu'il puisse fusionner trois ou quatre blocs. De plus, il faut utiliser une unité de prédiction de branchement capable de ''prédire plusieurs branchements par cycle''. ===Le décodage superscalaire large=== Le décodage des instructions n'est pas censé dépendre de l'implémentation du chargement. En théorie, une fois plusieurs blocs d'instruction fusionnés, on peut décoder les instructions en parallèle. Cependant, certains processeurs effectuent le décodage en tenant compte de la manière dont les branchements découpent les blocs. Les processeurs Atom d'Intel utilisent une solution de ce type, qui couple prédiction de branchement et décodage parallèle. Ils chargent/décodent des paquets de 3 instructions consécutives, chaque paquet étant séparé du précédent par un branchement. Pour cela, en plus d'avoir un fusionneur adapté, ils regroupent les décodeurs en ''clusters'', chacun regroupant 3 décodeurs, et pouvant décoder trois instructions consécutives. Les micro-architectures Tremont et Crestmont avaient deux ''clusters'' (6 décodeurs au total), la micro-architecture Darkmont en intègre trois (9 décodeurs au total). Avec deux ''clusters'', le fonctionnement est le suivant. Si le code est composé d'une suite d'instruction sans branchements, seul le premier ''cluster'' est utilisé, limitant le décodage à trois instructions par cycle. Par contre, si l'une des trois instructions décodée est un branchement, alors le second ''cluster'' décode les trois instructions situées après ce branchement, à partir de l'adresse de destination. Avec un troisième ''cluster'', c'est la même chose, sauf qu'il faut qu'il y ait un branchement dans les trois instructions décodées par le second ''cluster''. Mais comment faire pour savoir quels décodeurs activés, quels ''clusters'' sont actifs ? C'est la prédiction de branchement qui commande. Avec deux ''clusters'', elle détermine si un branchement est présent dans les trois instructions à charger, et quelle est son adresse de destination. Sans branchement, elle prévient les décodeurs et les trois instructions chargées sont décodées dans un ''cluster'' libre. Si elle prédit un branchement, elle charge les instructions adéquates, et active les deux ''clusters''. Avec trois branchements, c'est le même mécanisme, sauf que l'unité de prédiction de branchement doit être capable de prédire deux branchements par cycle. [[File:Front-end découplé de la microarchitecture Tremont.png|centre|vignette|upright=3|Front-end découplé de la microarchitecture Tremont.]] Il faut noter que les décodeurs d'un ''cluster'' sont des décodeurs simples, sans microcode. Sur les processeurs Tremont et Crestmont, le microcode était unique et était partagé entre tous les ''clusters''. Un seul ''cluster'' pouvait décoder une instruction complexe avec le microcode, l'autre devait se limiter à des instructions simples uniquement. Depuis Skymont, le microcode est partiellement dupliqué, avec un microcode par ''cluster''. Le cout en hardware peut paraitre prohibitif, pour un gain en performance faible. Sauf que c'est oublier que ce sont des processeurs Atom, sur lesquels beaucoup d'instructions sont microcodées. Les processeurs Atom ont un budget en transistor limité, ce qui fait qu'il est préférable pour eux d'implémenter des instructions en microcode que d'utiliser des unités de calcul dédiées ou des circuits de décodage complexes. Pour limiter la casse, le microcode n'est que partiellement dupliqué. Seul le microcode pour les instructions fréquente est dupliqué. Il y a un microcode secondaire pour certaines instructions, qui est lui unique et partagé par tous les ''clusters''. ===Le contournement sur les processeurs superscalaires larges=== Pour rappel, la technique du contournement (''register bypass'') permet au résultat d'une instruction d'être immédiatement utilisable en sortie de l'ALU, avant même d'être enregistré dans les registres. Implémenter la technique du contournement demande d'utiliser des multiplexeurs pour relier la sortie de l'unité de calcul sur son entrée si besoin. Il faut aussi des comparateurs pour détecter des dépendances de données. [[File:Pipeline Bypass.png|centre|vignette|upright=1|Pipeline Bypass]] La sortie de chaque ALU doit être reliée aux entrées de toutes les autres, avec les comparateurs qui vont avec. Sur les processeurs ayant plusieurs d'unités de calculs, cela demande beaucoup d’interconnexions et de comparateurs. Pour N unités de calcul, cela demande 2 * N² interconnexions, implémentées avec 2N multiplexeurs de N entrées chacun. Si c'est faisable pour 2 ou 3 ALUs, la solution est impraticable au-delà. Non seulement ce serait un enfer à câbler, mais les fils seraient tellement longs que la fréquence du processeur en prendrait un coup. Notez que cela vaut pour les processeurs superscalaires, mais aussi pour tout processeur avec beaucoup d'unités de calcul. En théorie, un CPU à exécution dans le désordre, non-superscalaire, mais avec beaucoup d'unités de calcul, fait face au même problème. En pratique, avoir une dizaine d'ALU implique processeur superscalaire à exécution dans le désordre. D'où le fait qu'on parle du problème maintenant. La seule solution praticable est de ne pas relier toutes les unités de calcul ensemble. À la place, on préfère regrouper les unités de calcul dans différents '''agglomérats''' ('''cluster'''). Le contournement est alors possible entre les unités d'un même agglomérat, mais pas entre agglomérats différents. Évidemment, certaines possibilités de contournement sont perdues, mais c'est compensé par un gain en fréquence et un cout en circuit/fils réduit. C'est un bon compromis, ce qui explique que presque tous les processeurs modernes l'utilisent. Les rares exceptions sont les processeurs POWER 4 et POWER 5, qui ont préféré se passer de contournement pour garder un processeur très simple et une fréquence élevée. ===Le banc de registre des processeurs superscalaires larges=== Pour émettre deux opérations entières simultanément, il faut lire deux fois plus d'opérandes. Et il faut aussi écrire deux résultats dans les registres, en même temps. Pour cela, on double les ports du banc de registre. En général, il faut au maximum 2 ports de lecture et un port d'écriture par unité de calcul. Le problème, c'est que plus un banc de registres a de ports, plus il utilise de circuits, est compliqué à concevoir, consomme de courant et chauffe. Avec plusieurs dizaines d'unités de calcul différentes, ajouter autant de ports impacterait la fréquence du banc de registres et réduirait les performances, voire est totalement impraticable à cause des contraintes thermiques. Les processeurs superscalaires larges doivent donc trouver des solutions. La première solution utilise un banc de registre unique, mais n'utilise pas autant de ports que le pire des cas le demanderait. Le processeur détecte quand il n'y a pas assez de ports pour servir toutes les micro-opérations. Quand ça arrive, l'unité d'émission émet assez de micro-opérations pour exploiter les ports disponibles, mais met en attente les micro-opérations en trop, le temps que les ports se libèrent. Pour cela, le banc de registre est géré par un circuit d'arbitrage spécialisé, intégré à l'unité d'émission, l’'''arbitre du banc de registres''' (''register file arbiter''). Une autre solution est de dupliquer le banc de registres en plusieurs exemplaires qui contiennent exactement les mêmes données, mais avec moins de ports de lecture/écriture. Un exemple est celui des processeurs POWER, Alpha 21264 et Alpha 21464. Sur ces processeurs, le banc de registre est dupliqué en plusieurs exemplaires, qui contiennent exactement les mêmes données. Les écritures dans les registres sont envoyées à tous les bancs de registres, afin de garantir que leur contenu est identique. Chaque exemplaire a exactement deux ports de lecture. La conception du processeur est simplifiée, que ce soit au niveau du câblage, que de la conception des bancs de registres. Une dernière solution découpe le banc de registres en plusieurs bancs de registres plus petits, avec un réseau d'interconnexions pour échanger des données entre bancs de registres. Dans la plupart des cas, cette séparation est invisible du point de vue de l'assembleur et du langage machine. Le processeur se charge de transférer les données entre bancs de registres suivant les besoins. Sur d'autres processeurs, les transferts de données se font via une instruction spéciale, souvent appelée ''COPY''. [[File:Banc de registres distribué.png|centre|vignette|upright=2|Banc de registres distribué.]] Sur de certains processeurs, un branchement est exécuté par une unité de calcul spécialisée. Or les registres à lire pour déterminer l'adresse de destination du branchement ne sont pas forcément dans le même agglomérat que cette unité de calcul. Pour éviter cela, certains processeurs disposent d'une unité de calcul des branchements dans chaque agglomérat. Dans les cas où plusieurs unités veulent modifier le ''program counter'' en même temps, un système de contrôle général décide quelle unité a la priorité sur les autres. Mais d'autres processeurs fonctionnent autrement : seul un agglomérat possède une unité de branchement, qui peut recevoir des résultats de tests de toutes les autres unités de calcul, quel que soit l’agglomérat. ==La macro-fusion : une optimisation du décodage parallèle== Les processeurs superscalaires supportent la technique dite de '''macro-fusion''', qui permet de fusionner deux-trois instructions consécutives en une seule micro-opération. Par exemple, il est possible fusionner une instruction de test et une instruction de saut en une seule micro-opération de branchement. Il s'agit là de l'utilisation la plus importante de la macro-fusion sur les processeurs x86 modernes. La macro-fusion est utilisée pour fusionner un test et un saut en un branchement unique. L'optimisation est présente sur la plupart des CPU superscalaires modernes. Les CPU x86 l'implémentent, mais aussi quelques CPU ARM et les processeurs Apple de série M (M1 à M5, et potentiellement plus quand ils seront sortis). La fusion des instructions se fait lors du décodage des instructions, grâce à la coopération des décodeurs. Elle marche systématiquement si l'instruction de test et le saut sont consécutives, qu'elles forment bien une paire d'instruction. Par contre, insérer une instruction entre les deux empêche la macro-fusion de faire son travail, sauf si l'instruction insérée est un NOP. Les processeurs ARM64 avaient une forme spécifique de macro-fusion, utilisée pour un cas très précis : charger une constante immédiate de 32 ou 64 bits, dans un registre 64 bits. Les CPU ARM 64 bits utilisent des instructions codées sur 32 bits, qui ne peuvent encoder que des constantes immédiates de 16 bits. Pour charger une constante de 32/64 bits, il faut s'y prendre en plusieurs fois. Une première instruction MOVZ charge les 16 premiers bits, puis 2 à 4 instructions MOVK remplissent le reste. MOVZ met à zéro les 48 bits de poids fort, MOVK permet de sélectionner le doublet à modifier dans le registre (on modifie 16 bits, dont on choisit la place, le reste du registre est laissé tel quel). ARM permet de fusionner cette suite d'instructions en une seule µop MOV avec une constante immédiate. On parle alors de '''''MOVZ + MOVK fusion'''''. Une dernière utilisation, [https://www2.eecs.berkeley.edu/Pubs/TechRpts/2016/EECS-2016-130.pdf proposées pour le jeu d'instruction RISC-V], fusionnait un calcul d'adresse et une instruction LOAD/STORE en une seule instruction d'accès mémoire. Elle a été envisagée à une époque où le jeu d'instruction RISC-V ne gérait pas les modes d'adressage base + indice. L'idée était d'avoir une unité mémoire qui gérait le mode d'adressage base + indice et de fusionner des instructions pour l'exploiter. Mais de nos jours, le jeu d'instruction RISC-V intègre le mode d'adressage base + indice, ce qui fait que la macro-fusion n'a aucun intérêt pour ce cas précis. La macro-fusion a de nombreuses limitations en pratique. En théorie, on pourrait l'utiliser au-delà des deux situations mentionnées plus haut. Par exemple, pour fusionner une addition et une multiplication en une seule instruction MAD. Mais l'intérêt est assez faible. Notons que la macro-fusion ne permet que de fusionner des paires d'instructions. Aller au-delà demanderait un cout en circuit trop important. Déjà que tester deux paires utilise pas mal de comparateurs... ==Le ''stack engine'' : une optimisation de la pile d'appel== Les processeurs modernes intègrent une optimisation liée au pointeur de pile. Pour rappel, sur les architectures modernes, le pointeur de pile est un registre utilisé pour gérer la pile d'appel, précisément pour savoir où se trouve le sommet de la pile. Il est manipulé par les instructions CALL, RET, PUSH et POP, mais aussi par les instructions d'addition/soustraction pour gérer des cadres de pile de taille variable. De plus, il peut servir d'opérande pour des instructions LOAD/STORE, afin de lire/écrire des variables locales, les arguments d'une fonction, et autres. C'est donc un registre général adressable, intégré au banc de registre, altéré par l'unité de calcul entière. L'incrémentation/décrémentation du pointeur de pile passe donc par l'unité de calcul, lors des instructions CALL, RET, PUSH et POP. Mais, l'optimisation que nous allons voir permet d'incrémenter/décrémenter le pointeur de pile sans passer par l'ALU, ou presque. L'idée est de s'inspirer des architectures avec une pile d'adresse de retour, qui intègrent le pointeur de pile dans le séquenceur et l'incrémentent avec un incrémenteur dédié. ===Le ''stack engine''=== L'optimisation que nous allons voir utilise un '''''stack engine''''' intégré à l'unité de contrôle, au séquenceur. Le processeur contient toujours un pointeur de pile dans le banc de registre, cela ne change pas. Par contre, il n'est pas incrémenté/décrémenté à chaque instruction CALL, RET, PUSH, POP. Un compteur intégré au séquenceur est incrémenté à la place, nous l’appellerons le '''compteur delta'''. La vraie valeur du pointeur de pile s'obtient en additionnant le compteur delta avec le registre dans le banc de registre. Précisons que si le compteur delta vaut zéro, la vraie valeur est dans le banc de registre et peut s'utiliser telle quelle. Lorsqu'une instruction ADD/SUB/LOAD/STORE utilise le pointeur de pile comme opérande, elle a besoin de la vraie valeur. Si elle n'est pas dans le banc de registre, le séquenceur déclenche l'addition compteur-registre pour calculer la vraie valeur. Finalement, le banc de registre contient alors la bonne valeur et l'instruction peut s'exécuter sans encombre. L'idée est que le pointeur de pile est généralement altéré par une série d'instruction PUSH/POP consécutives, puis des instructions LOAD/STORE/ADD/SUB utilisent le pointeur de pile final comme opérande. En clair, une bonne partie des incrémentations/décrémentation est accumulée dans le compteur delta, puis la vraie valeur est calculée une fois pour toutes et est utilisée comme opérande. On accumule un delta dans le compteur delta, et ce compteur delta est additionné quand nécessaire. Précisons que le compteur delta est placé juste après le décodeur d'instruction, avant même le cache de micro-opération, l'unité de renommage et l'unité d'émission. Ainsi, les incrémentations/décrémentations du pointeur de pile disparaissent dès l'unité de décodage. Elles ne prennent pas de place dans le cache de micro-opération, ni dans la fenêtre d'instruction, ni dans la suite du pipeline. De nombreuses ressources sont économisées dans le ''front-end''. Mais utiliser un ''stack engine'' a aussi de nombreux avantages au niveau du chemin de données/''back-end''. Déjà, sur les processeurs à exécution dans le désordre, cela libère une unité de calcul qui peut être utilisée pour faire d'autres calculs. Ensuite, le compteur delta mémorise un delta assez court, de 8 bits sur le processeur Pentium M, un peu plus pour les suivants. L'incrémentation se fait donc via un incrémenteur 8 bits, pas une grosse ALU 32/64 bits. Il y a un gain en termes de consommation d'énergie, un incrémenteur 8 bits étant moins gourmand qu'une grosse ALU 32/64 bits. ===Les points de synchronisation du delta=== La technique ne fonctionne que si la vraie valeur du pointeur de pile est calculée au bon moment, avant chaque utilisation pertinente. Il y a donc des '''points de synchronisation''' qui forcent le calcul de la vraie valeur. Plus haut, nous avions dit que c'était à chaque fois qu'une instruction adresse le pointeur de pile explicitement, qui l'utilise comme opérande. Les instructions CALL, RET, PUSH et POP ne sont pas concernées par elles utilisent le pointeur de pile de manière implicite et ne font que l'incrémenter/décrémenter. Mais dans les faits, c'est plus compliqué. D'autres situations peuvent forcer une synchronisation, notamment un débordement du compteur delta. Le compteur delta est généralement un compteur de 8 bits, ce qui fait qu'il peut déborder. En cas de débordement du compteur, le séquenceur déclenche le calcul de la vraie valeur, puis réinitialise le compteur delta. La vraie valeur est donc calculée en avance dans ce cas précis. Précisons qu'un compteur delta de 8 bits permet de gérer environ 30 instructions PUSH/POP consécutives, ce qui rend les débordements de compteur delta assez peu fréquent. À noter que si le compteur delta vaut zéro, il n'y a pas besoin de calculer la vraie valeur, le séquenceur prend cette situation en compte. Un autre point de synchronisation est celui des interruptions et exceptions matérielles. Il faut que le compteur delta soit sauvegardé lors d'une interruption et restauré quand elle se termine. Idem lors d'une commutation de contexte, quand on passe d'un programme à un autre. Pour cela, le processeur peut déclencher le calcul de la vraie valeur lors d'une interruption, avant de sauvegarder les registres. Pour cela, le processeur intègre un mécanisme de sauvegarde automatique, qui mémorise la valeur de ce compteur dans le tampon de réordonnancement, pour forcer le calcul de la vraie valeur en cas de problème. La technique du ''stack engine'' est apparue sur les processeurs Pentium M d'Intel et les processeurs K10 d'AMD, et a été conservée sur tous les modèles ultérieurs. L'implémentation est cependant différente selon les processeurs, bien qu'on n'en connaisse pas les détails et que l'on doive se contenter des résultats de micro-benchmarks et des détails fournit par Intel et AMD. Selon certaines sources, dont les manuels d'optimisation d'Agner Fog, les processeurs AMD auraient moins de points de synchronisation que les processeurs Intel. De plus, leur ''stack engine'' serait placé plus loin que prévu dans le pipeline, après la file de micro-opération. ==La micro-fusion et la délamination== La '''micro-fusion''' est une optimisation qui retarde le décodage réel de certaines instructions assez loin dans le pipeline. Elle concerne surtout les instructions ''load-op'', mais pas que. D'autres instructions mémoire peuvent subir cette optimisation. L'essentiel est que, sans micro-fusion, ces instructions sont décodées en plusieurs micro-opérations. La micro-fusion retarde le décodage final de ces instructions, qui se fait assez tard dans le pipeline. Pour comprendre l'intérêt, nous allons devoir faire quelques explications. L'optimisation en question fait le décodage en deux temps. Prenons l'exemple d'une opération ''load-op'', qui est censée être décodée en deux micro-opérations : une lecture, puis une opération. Le décodage produit une '''macro-opération''' (terme d'Intel), qui est propagée dans le pipeline, pour être scindée en deux micro-opérations un peu avant les ALU et l'unité mémoire. La macro-opération est techniquement une micro-opération comme une autre, sauf que ce n'est pas la micro-opération finale. L'unité d'émission découpe cette macro-opération en deux micro-opérations, qui sont émises l'une après l'autre. Pour résumer, les instructions ''load-op'' ne sont complétement découpées en micro-opération lors de l'émission, pas lors du décodage. L'optimisation impacte ce qui se situe entre le décodeur d'instruction et l'unité d'émission : l'unité de renommage, la file de micro-opérations, le ''Loop Stream Detector'' et/ou le cache de micro-opération. L'intérêt de l'optimisation est que l'on fusionne deux micro-opérations en une seule macro-opération. Le cache de micro-opération et la file de micro-opération peuvent mémoriser plus de micro-opérations, vu que certaines sont fusionnées. Quant à l'unité de renommage, elle renomme une seule macro-opération au lieu de renommer deux micro-opérations, ce qui augmente le débit du renommage de registre. Par contre, cela complique un peu le travail de l'unité d'émission, qui doit découper les instructions ''load-op'' en deux et émettre les micro-opérations l'une après l'autre. Il faut noter qu'il n'y a pas de fusion proprement dite. Le décodeur ne décode pas deux micro-opérations séparées, avant de les fusionner. En réalité, il génère directement une macro-opération, qui correspond à deux micro-opérations, que ce soit plus tard dans le pipeline ou sur une autre architecture. D'ailleurs, la micro-fusion a lieu à l'intérieur d'une instruction, qui est censée être traduite en plusieurs micro-opérations. Et encore : pas toutes. La conséquence est que la technique n'a de sens que sur les processeurs CISC, avec des instructions assez complexes pour être décodées en plusieurs micro-opérations. En pratique, seuls les CPU x86 sont concernés. ===Les domaines de fusion=== La micro-fusion n'est pas spécifique aux processeurs superscalaires. En théorie, on peut l'implémenter sur un processeur non-superscalaire à émission dans l'ordre. Cependant, je ne connais aucun processeur à émission dans l'ordre qui implémente la micro-fusion, même si son implémentation est en théorie possible sur de tels processeurs. La micro-fusion est implémentée différemment selon que l'émission se fasse dans l'ordre, dans le désordre, avec une fenêtre d'instruction, avec des stations de réservation, etc. J'ai dit plus haut que les micro-opérations sont générées lors de l'émission, mais le moment exact varie suivant le processeur. Pour simplifier le tout, nous parlerons de '''scission''' quand le processeur traduit une macro-opération en deux/trois micro-opérations. Le moment où a lieu la scission est théoriquement dans l'unité d'émission, mais celle-ci prend plusieurs formes selon que le processeur utilise l'émission dans l'ordre, dans le désordre, avec une fenêtre d'instruction, avec des stations de réservation, etc. Les processeurs à exécution dans l'ordre sont le cas le plus simple. L'unité d'émission est alors en charge du découpage des macro-opérations en micro-opérations. La file de micro-opération ou le cache de micro-opérations mémorisent des macro-opérations. À l'opposé, le tampon de ré-ordonnancement mémorise lui des micro-opérations. Le reste du processeur n'est pas affecté. Sur les processeurs à exécution dans le désordre, les différences sont nombreuses. Le tampon de ré-ordonnancement peut mémoriser soit les micro-opérations finales, soit des macro-opérations. Il en est de même avec la fenêtre d'instruction et/ou les stations de réservation, qu'elles soient centralisées ou décentralisées. Tout dépend de comment se fait l'implémentation. Une implémentation simple effectue la scission des macro-opérations dans l'unité d'émission, comme sur les processeurs à exécution dans l'ordre. Sur de nombreux processeurs, l'unité d'émission et de renommage sont simplement fusionnées, ce qui fait que la scission a lieu juste après le renommage de registres. En conséquence, le tampon de re-ordonnancement et les fenêtres d'instruction ne voient que des micro-opérations. Les macro-opérations disparaissent juste avant. Cette implémentation est préférée avec une fenêtre d'instruction centralisée, car on voit mal comment scinder une macro-opération juste avant l'ALU. Une autre implémentation fait la scission en sortie de la fenêtre d'instruction ou des stations de réservation, qu'elles soient centralisées ou décentralisées. Dans ce cas, le tampon de re-ordonnancement fait de même. L'avantage est que le tampon de ré-ordonnancement stocke des macro-opérations, ce qui augmente sa taille effective. Par exemple, il utilise une seule entrée pour une instruction ''load-op'', au lieu de deux sans micro-fusion de ce type. ===La délamination=== La scission peut parfois avoir lieu plus tôt, dans des circonstances très précises. Concrètement, cela ne concerne que quelques micro-architectures d'Intel, pour des instructions très précises. La raison est les limitations du format des micro-opérations, pas une histoire d'optimisation. Le processeur aimerait pouvoir faire la micro-fusion, mais ne peut pas à cause de ces limitations. Une telle situation cause alors une '''délamination''' : les micro-opérations sont scindées précocement. Par exemple, sur la micro-architecture SandyBridge d'Intel, les opérations ''load-op'' sont fusionnées, sauf si elles utilisent l'adressage indicé. Les micro-opérations de ce processeur ne peuvent avoir que deux opérandes. Trois opérandes est de trop, et les opérations ''load-op'' en adressage indicé dépassent cette limite. Dans ce cas, les micro-opérations sont fusionnées en sortie du décodeur, mais sont scindés avant d’entrer dans la file de micro-opération. L'avantage n'est pas évident, vu que l'unité de renommage suit de près le décodeur d'instruction. Il est que le cache de micro-opérations mémorise des macro-opérations, pas deux micro-opérations. ===La micro-fusion des processeurs Intel et AMD=== La micro-fusion est apparue sur le Pentium M d'Intel, et a été conservée telle quelle sur les processeurs Intel suivants. Les processeurs AMD supportent la micro-fusion depuis au moins la micro-architecture AMD K8. Mieux que ça, la délamination n'était pas utilisée car les micro-opérations acceptaient plus de 2 opérandes. Que ce soit chez AMD ou Intel, elle concerne deux types d'instructions : les écritures mémoire et les instructions ''load-op''. Sur le Pentium M, il y avait quelques limitations, l'optimisation se limitant par exemple aux registres entiers et flottants, mais pas aux registres MMX, mais pas les registres SSE (nous verrons ces registres dans quelques chapitres). Mais les processeurs modernes n'ont plus cette limitation. La micro-fusion des CPU Intel concerne deux types d'instructions : les écritures mémoire et les instructions ''load-op''. Pour les écritures, la situation est plus complexe que pour les instructions ''load-op''. Sur les processeurs Intel précédents, les écritures étaient réalisées dans deux unités séparées : le calcul d'adresse dans une unité de calcul, l'écriture proprement dite dans l'unité mémoire. Elles prenaient donc deux micro-opérations. Le processeur a changé ses unités mémoire, ce qui fait qu'elle pouvait faire les deux en une seule micro-opération. Il s'agissait alors d'une optimisation du chemin de données, plus que de la micro-fusion proprement dite, mais je la mentionne ici malgré tout. La micro-fusion sur ce processeur avait un avantage en plus des avantages usuels : elle utilisait mieux les décodeurs. Les Pentium M avaient trois décodeurs pour décoder plusieurs instructions en même temps, chose qu'on détaillera dans le chapitre sur les processeurs superscalaires. Un seul décodeur pouvait décoder toutes les instructions, les deux autres ne peuvent décoder que les instructions simples, qui se décodent en une seule micro-opération. Avec la micro-fusion, les trois décodeurs peuvent gérer les écritures mémoire et les opérations ''load-op'', vu qu'elles deviennent des instructions simples. Sans cela, elles auraient été limitées au premier décodeur. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Le parallélisme mémoire | prevText=Le parallélisme mémoire | next=Les microarchitectures pour le x86 : haute performance | nextText=Les microarchitectures pour le x86 : haute performance }} </noinclude> frl4unlp6jr8ctk00as0kyzek42vc4d 773578 773577 2026-09-29T16:35:34Z Mewtow 31375 /* L'exemple du PA-RISC PA 8000 */ 773578 wikitext text/x-wiki Les processeurs vus auparavant ne peuvent émettre au maximum qu'une instruction par cycle d'horloge. Ils peuvent avoir plusieurs instructions qui s'exécutent en même temps, dans des unités de calcul séparées. C'est le cas dès qu'une instruction multi-cycles s'exécute. Par contre, ils ne peuvent démarrer qu'une seule instruction par cycle. Et quand on court après la performance, ce n'est pas assez ! Les concepteurs de processeurs ont inventés des processeurs qui émettent plusieurs instructions par cycle : les '''processeurs à émissions multiples'''. Un processeur à émission multiple charge plusieurs instructions en même temps, les décode en parallèle, puis les émet en même temps sur des unités de calculs séparées. Pour cela, il faut gérer les dépendances entre instructions, répartir les instructions sur différentes unités de calcul, et cela n'est pas une mince affaire. En général, pour un processeur à émission multiple capable d'émettre N instructions en parallèle, on parle de '''processeur à N voies''', ou encore un ''processeur à N pipelines''. [[File:Superscalarpipeline.svg|centre|vignette|upright=1.5|Pipeline RISC classique à cinq étages sur un processeur superscalaire. On voit bien que plusieurs instructions sont chargées en même temps.]] Les processeurs à émission multiple sont de deux types : les processeurs VLIW et les '''processeurs superscalaires'''. Nous mettons les processeurs VLIW de côté en attendant le prochain chapitre. La raison est qu'ils ont un jeu d'instruction spécialisé qui expose le parallélisme d'instruction directement au niveau du jeu d'instructions, là où les processeurs superscalaires restent des processeurs au jeu d'instruction normal. La différence principale entre processeur VLIW et superscalaire est qu'un processeur superscalaire répartit les instructions sur les unités de calcul à l’exécution, là où un processeur VLIW délègue cette tâche au compilateur. ==Le nombre de voies d'un processeur superscalaire== Les processeurs superscalaires les plus simples ne permettent que d'émettre deux micro-opérations à la fois, d'où leur nom de processeur ''dual issue'', ce qui se traduit en '''processeur à double émission'''. Les processeurs triple émission permettent eux d’émettre trois instructions à la fois. A l'opposé, les CPU superscalaires les plus puissants peuvent émettre jusqu'à 8-10 instructions simultanément. En 2026, les CPU superscalaires peuvent monter jusqu’à 10 µops émises en même temps, ce qui est énorme ! Et cela nous amène à faire une distinction entre les processeurs superscalaires dits '''étroits''' et ceux dits '''larges'''. Dans ce wikilivre, on part du principe que les processeurs superscalaires étroits émettent jusqu'à 4-5 µops à la fois, alors que les larges peuvent en émettre plus, l'intervalle entre les deux est une zone grise. Le nombre exact n'est pas fixé dans le marbre, la distinction est volontairement vague. Nous parlerons de la '''largeur d'un CPU superscalaire''' pour parler du nombre de voies, du nombre de µops émises en même temps. Plus un CPU superscalaire est large, plus il est performant ''toute chose égale par ailleurs''. Mais dans les faits, vous pouvez oublier la partie en italique. Élargir un CPU superscalaire demande de rajouter beaucoup de circuits. Et ce cout en circuit aura un impact sur la performance. A budget en transistors limité, il y a un compromis entre élargir un CPU et rajouter du cache ou la taille des fenêtres d'instructions/ROB et autres. ===Les contraintes d’appariement=== Prenons un processeur double émission, capable d'émettre deux instructions simultanément. Émettre deux instructions en même temps n'est pas toujours possible. Par exemple, si deux instructions sont dépendantes, on ne peut pas les émettre en même temps. Mais oublions un instant ces histoires de dépendances de données, et partons du principe que le CPU ait affaire à deux instructions indépendantes, une paire idéale. Un CPU double émission "parfait" pourrait exécuter n'importe quelle paire d'instruction. Par exemple, il pourrait émettre deux multiplications consécutives, deux lectures consécutives, une lecture et une écriture en même temps, etc. En pratique, aucun processeur ne permet cela. Implémenter un CPU superscalaire "parfait" aurait un cout en circuit beaucoup trop conséquent. Par exemple, pour émettre deux multiplications en même temps, il faudrait deux multiplieurs séparés. Idem pour exécuter deux accès mémoire simultané : cela demande d'avoir deux unités mémoire et un cache multiport. Mais en pratique, aucun CPU superscalaire ne fait cela. La totalité des CPU double émission se débrouille avec un seul circuit multiplieur et une seule unité mémoire. Et cela entraine l'apparition de dépendances structurelles, qui font que certaines paires d'instructions sont impossibles. Par exemple, impossible d'émettre deux multiplications en même temps avec un seul circuit multiplieur. Mais émettre une multiplication en parallèle d'une addition est parfaitement possible. Il y a donc des paires d'instructions autorisées et des paires interdites. Et la logique est la même sur les CPU à triple ou quadruple émission, et au-delà. : des triplets ou quadruplet d'instructions sont impossibles à émettre simultanément, alors que d'autres le sont. Pour le dire autrement, il y a des '''contraintes d'appariement''' sur les instructions à émettre en même temps. ===L'impact des contraintes d’appariement sur la performance=== Ces contraintes d’appariement ont un impact sur les performance, mais celui-ci peut être grandement mitigé. Les programmes informatiques utilisent en pratique beaucoup plus d'opérations entières de base que de multiplication, branchements et accès mémoire. Il y a environ 5 opérations entières de base pour une multiplication entière. En pratique, il est rare de devoir exécuter deux multiplications à la fois. Idem pour les décalages et rotations, qui sont assez éloignés les uns des autres. Deux branchements consécutifs sont quant à eux plus fréquents. Deux accès mémoire consécutifs est assez rare, mais ils restent assez proches les uns des autres malgré tout. La conséquence est que certaines paires d'instructions sont privilégiées par rapport au reste. Les paires regroupant deux calculs basiques (additions, soustractions, ...) sont systématiquement supportées, car dupliquer des ALU entières est facile. Les paires regroupant un calcul et une autre instruction sont elles aussi systématiquement supportées. Par contre, les paires avec deux branchements, deux accès mémoire, deux décalages/rotations, ou deux multiplications/divisions sont fréquemment interdites. Seuls les CPU superscalaires larges peuvent les permettre, et encore : sous conditions. Le résultat est que le processeur peut se débrouiller avec une seule unité mémoire et une unité de branchement. ===Terminologie pour la suite du chapitre=== Décrire les contraintes d’appariement demande de dire quelles combinaisons d’instructions sont autorisées ou interdites. Et pour cela, nous allons introduire les abréviations suivantes : * INT est un raccourcis pour parler d'une opération entière simple, qu'une ALU entière peut exécuter. * MUL correspond à une opération entière complexe, typiquement une multiplication, éventuellement à une division. * FLOAT désigne une opération flottante, peut importe laquelle. * MEM désigne un accès mémoire, à savoir une instruction ou µop mémoire. * BRANCH désigne une instruction de branchement. Cette terminologie permettra de définir des paires d'instructions, qu'elles soient possibles ou interdites. Par exemple, l'expression INT + FLOAT désigne une paire d'instruction regroupant une instruction entière et une instruction flottante, peu importe l'ordre des deux instructions. Il en sera de même pour les triplets, quadruplets, ou plus. Par exemple, l'expression INT + INT + FLOAT + MUL désigne un quadruplet d'instructions regroupant : deux instructions entières, une instruction flottante, et une multiplication entière. J'utiliserais aussi des parenthèses pour regrouper certaines combinaisons. Par exemple, l'expression INT + (MUL /FLOAT) veut parler d'une paire d'instruction où la première est une opération entière basique, la seconde est : soit une multiplication, soit une opération flottante. ==Le ''front-end'' des processeurs superscalaires== Un processeur superscalaire doit charger, décoder, et exécuter plusieurs instructions par cycle. Par exemple, un processeur triple émission doit charger 3 instructions lors d'un premier cycle, puis les décoder au cycle suivant, et les exécuter au cycle suivant. Il travaille donc pas paquets de 3 instructions, dans cet exemple. Intuitivement, charger, décoder et exécuter plusieurs instructions à la fois demande de dupliquer des circuits. Par exemple, il faut dupliquer les décodeurs pour décoder plusieurs instructions. Les unités de calcul sont aussi dupliquées, sauf sur certaines processeurs qui arrivent à ruser, mais laissons cela de côté pour plus tard. Mais d'autres circuits sont simplement modifiés, comme l'unité de chargement ou l'unité d'émission. Voyons ce qu'il en est dans le détail. {|class="wikitable" |- ! rowspan="2" | Processeur sans émission multiple | rowspan="2" | Chargement | rowspan="2" | Décodage | rowspan="2" | Renommage | rowspan="2" | Émission | Exécution / ALU | rowspan="2" | ''Commit''/ROB |- | Exécution / ALU |- ! rowspan="4" | Processeur superscalaire | rowspan="4" | Chargement | rowspan="2" | Décodage | rowspan="4" | Renommage | rowspan="4" | Émission | Exécution / ALU | rowspan="4" | ''Commit''/ROB |- | Exécution / ALU |- | rowspan="2" | Décodage | Exécution / ALU |- | Exécution / ALU |} Nous allons d'abord voir ce qu'il en est pour le ''front-end'', à savoir la partie du CPU qui s'occupe de charger et décoder les instructions. Elle regroupe l'unité de chargement, les décodeurs, l'unité de prédiction de branchement, la file de µops, la file d'instruction, et divers caches. En soi, les changements portent surtout sur l'unité de chargement et les décodeurs. ===Le chargement de plusieurs instructions consécutives=== Un processeur superscalaire charge plusieurs instructions en même temps, ''en tenant compte de la présence de branchements''. La partie en italique est importante et elle a une conséquence très forte : la manière de faire est fortement différente entre un CPU superscalaire étroit et large. Un CPU superscalaire étroit fait au plus simple : il charge un bloc de 2, 3, 4 instructions consécutives en mémoire RAM. Il faut alors doubler/tripler/quadrupler la taille du bus connecté au cache d'instruction. Par exemple, pour charger quatre instructions de 32 bits chacune, il suffit de lire un bloc de 128 bits dans le cache d'instruction. Un bloc de 8, 16, 32 octets est donc lu depuis le cache et est ensuite découpé en instructions, envoyées chacun à un décodeur. Charger plusieurs instructions consécutives ne marche bien qu'en absence de branchements. La présence de branchements casse cette dynamique, et il faut gérer leur présence. * Sans prédiction de branchement, toutes les instructions d'un bloc sont décodées et exécutées en même temps, même s'il y a un branchement dans le tas. * Avec prédiction de branchement, les instructions situées après le branchement ne sont pas décodées ni exécutées. L'unité de chargement coupe le bloc chargé au niveau du premier branchement pris, remplit les vides avec des NOP, avant d'envoyer le tout à l'unité de décodage. Les instructions à l'adresse de destination seront chargées au cycle suivant, en chargeant un nouveau bloc. [[File:Fetch sur un processeur superscalaire avec prediction de branchements.png|centre|vignette|upright=2|Fetch sur un processeur superscalaire avec prédiction de branchements.]] Un autre défaut est que sur le CPU charge un bloc de 128 bits à la fois, les instructions doivent être alignées sur 128 bits. Et on peut généraliser à n'importe quelle taille de bloc. Si les instructions ne sont pas alignées, il faut gérer la situation. Il arrive qu'une instruction soit à cheval sur deux blocs, avec un morceau dans le premier bloc, un autre dans le second. Dans ce cas, l'instruction est chargée en deux fois, et des circuits doivent gérer la situation pour recoller les morceaux. Sur les CPU avec des instructions de taille fixe, le problème ne survient que rarement. Mais il est fréquent avec des instructions de taille variable. Un autre défaut est lié aux branchements. Imaginez qu'un branchement s'exécute et branche vers une instruction de destination. Rien n'indique que l'instruction de destination sera au tout début d'un bloc. Si ça se trouve, elle sera en troisième position d'un bloc de 4 instructions. Une solution simple charge le bloc en respectant l'alignement, et les deux premières instructions du bloc ne sont pas à exécuter. Il y a donc une petite perte de performance. Certains CPU, comme l'IBM RS/6000, ont la machinerie charger un bloc de N instructions même s'il n'est pas aligné. La machinerie en question se trouve dans le cache d'instruction et est tout sauf simple à expliquer,ce qui fait que je me permets de la passer sous silence. Un détail, cependant : elle ne permet pas de charger des blocs qui sont à cheval sur deux lignes de cache. ===Le décodage parallèle des instructions=== Pour le décodage des instructions, plusieurs instructions sont décodées en même temps. On parle alors de '''décodage parallèle'''. Pour ce faire, un processeur superscalaire contient plusieurs décodeurs, chacun pouvant décoder une instruction en parallèle des autres. Prenons par exemple un processeur superscalaire à 4 voies : le décodage se fera dans quatre décodeurs séparés, qui fonctionneront en parallèle. Cependant, cette implémentation ne marche bien que pour les processeurs RISC, les processeurs CISC devant faire avec un microcode gourmand en circuits. Les processeurs CISC utilisent des décodeurs hybrides, avec un microcode qui complémente un décodeur câblé. Dupliquer le microcode aurait un cout en transistors trop important, ce qui fait que seuls les décodeurs câblés sont dupliqués. Les CPU CISC superscalaires disposent donc de plusieurs décodeurs simples, capables de décoder les instructions les plus courantes, avec un seul microcode. La conséquence est qu'il n'est pas possible de décoder deux instructions microcodées en même temps. Par contre, il reste possible de décoder plusieurs instructions non-microcodées ou une instruction microcodée couplée à une instruction non-microcodée. Vu qu'il est rare que deux instructions microcodées se suivent dans un programme, le cout en performance est extrêmement mineur. Il faut noter qu'une instruction correspond à une ou plusieurs µops. Il est donc possible de charger 5 instructions et de se retrouver avec 8 µops en sortie des décodeurs. Et c'est la source d'une distinction très importante. Plus haut, j'ai parlé de processeurs superscalaires à N voies. La terminologie peut avoir deux interprétations. La première est que le processeur charge/décode N instructions à la fois. Une seconde est qu'il est capable d'exécuter/émettre N µops en même temps. Les deux ne sont pas équivalentes, vu qu'un processeur superscalaire peut, par exemple, charger/décoder N instructions et émettre/exécuter N+2 µops. La distinction est particulièrement importante sur les processeurs superscalaires larges. Certains d'entre eux sont capables de charger 5 instructions et d'en émettre le double ! Un exemple classique était les processeurs Athlon d'AMD, qui pouvaient décoder deux instructions par cycle, mais émettre 4 µops par cycle. Ce n'était pas un problème, car beaucoup d'instructions, même basiques, étaient décodées en 2 µops. ===L'émission parallèle des instructions=== La superscalarité modifie en profondeur l'unité d'émission, notamment au niveau de son interface. Avant, elle recevait une micro-opération sur son entrée, et fournissait la micro-opération émise sur une sortie. Et cela vaut aussi bien pour une unité d'émission simple, un ''scoreboard'', une fenêtre d'instruction ou des stations de réservation. Mais avec l'émission multiple, les sorties et entrées sont dupliquées. Pour la double émission, il y a deux entrées vu qu'elle doit recevoir deux micro-opération décodées/renommées, et deux sorties pour émettre deux micro-opérations. Dans ce qui suit, nous ne parlerons pas d'entrée et de sortie, mais de '''ports de décodage''' et de '''ports d'émission'''. Les ports de décodage reçoivent des micro-opérations provenant de l'unité de décodage, les ports d'émissions sont pour les micro-opérations émises. Les ports d'émission injectent les micro-opérations émises dans le pipeline, elle sont propagée au banc de registre, aux ALUs, etc. Un processeur superscalaire a forcément plusieurs ports d'émission (et de décodage). Si l'interface de l'unité d'émission change, l'intérieur est tout autant modifié. Sur un CPU non-superscalaire, l'unité d'émission reçoit une µop "candidate à l'émission", et détecte les dépendances entre avec les µops en vol, en cours d'exécution dans le pipeline. Et c'est toujours le cas sur les processeurs superscalaires : l'unité d'émission détecte les dépendances entre les µops candidates et les µops en vol. Mais avec la siperscalarité, elle doit en plus tester les dépendances entre les µops candidates. Si l'unité d'émission est un ''scoreboard'', il doit détecter les dépendances entre instructions émises simultanément et les sérialiser si besoin. Avec une fenêtre d'instruction, il n'y a pour ainsi dire rien à faire, vu que les dépendances sont éliminées par le renommage de registre et que les signaux de réveil gèrent les dépendances RAW. C'est la raison pour laquelle les processeurs superscalaires modernes n'utilisent pas de ''scoreboard''. ==Les processeurs implémentés avec plusieurs pipelines== Nous venons de voir comment la superscalarité impacte le ''front-end'', il est maintenant de voir ce qu'il en est de l'unité d'émission et des ''back-ends''. Un processeur superscalaire peut utiliser l'exécution dans le désordre et le renommage de registres, mais ce n'est pas une obligation. Historiquement, les premiers processeurs superscalaires n'utilisaient pas d'exécution dans le désordre. Le meilleur exemple est celui du Pentium 1 et 2 d'Intel. Ils étaient tous deux des processeurs superscalaires, mais n'avaient pas d'exécution dans le désordre, qui est apparue sur le Pentium 3. les explications sont plus simples si on met de côté l'exécution dans le désordre. Vous vous dites que l'implémentation d'un processeur superscalaire n'est pas la même suivant que le CPU utilise l'exécution dans le désordre, ou non. Mais dans les faits, la distinction est plus subtile que ca. Pour l'expliquer, je vais utiliser une classification originale, qui sépare les processeurs superscalaires en trois sous-types. La distinction se fait sur la manière dont la superscalarité est implémentée en matériel.La classification que j'utilise distingue : * Les processeurs avec plusieurs pipelines, sans exécution dans le désordre. * Les processeurs superscalaires avec un pipeline dynamique. * Les processeurs avec des fenêtres d'instruction décentralisées. La distinction n'est pas qu'une question d'implémentation matérielle. Elle impacte aussi le ratio entre instructions chargées/décodées et instructions émises. Vous vous dites que les deux sont égales, mais ce n'est le cas que sur les processeurs avec N pipelines ! Sur les autres processeurs, il est possible de décoder 4 instructions, mais d'en émettre maximum 6 par cycle ! Et sur les CPU avec des fenêtres d'instruction décentralisées, il y a aussi une différence entre le nombre d'instructions qui sont ''dispatch'' et ''schedule''. La catégorie la plus simple est celle des '''processeurs avec plusieurs pipelines'''. Ce sont des processeurs superscalaires sans exécution dans le désordre. Ils partent d'un processeur non-superscalaire, et ajoutent un second pipeline, en sortie de l'unité d'émission. Le second pipeline permet l'émission parallèle d'une seconde instruction. Le second pipeline n'est pas identique au pipeline originel, sur plusieurs points. Premièrement, il n'a pas exactement les mêmes circuits. Le second pipeline est généralement composé d'une unité de calcul, d'une FPU, éventuellement d'un second banc de registres, guère plus. Il permet d'exécuter une seconde opération de calcul, pas plus, ce qui est à l'origine de contraintes d'appariemment assez fortes. De plus, il n'a pas forcément la même longueur, il peut avoir des étages en moins ou en plus. Il s'agit de la forme la plus simple de processeur superscalaire et nous allons leur consacrer cette section. ===La double émission entière-flottante=== L'exemple le plus simple utilise un second pipeline pour les opérations flottantes, séparé du pipeline originel. L'ajout d'un pipeline flottant permet d'émettre une micro-opération entière en même temps qu'une micro-opération flottante, ce qui s'appelle la '''double émission entière-flottante'''. La micro-opération entière s'exécute dans l'ALU entière, la micro-opération flottante dans la FPU. Les exemples les plus notables sont le PA-RISC 7100, le POWER 1 (RIOS .& et .9) et le PowerPC 601. L'Apollo DN10000 et l'Intel i860 utilisaient aussi cette forme de double émission, mais étaient des prototypes de CPU VLIW. [[File:Double émission entière-flottante.png|centre|vignette|upright=2|Double émission entière-flottante]] Pour bien expliquer les choses, prenons le processeur illustré ci-dessous, avec deux ''back-end'' séparés : un pour la FPU, et un autre pour le reste. Les instructions entières et mémoire passent toutes par le ''back-end'' généraliste. [[File:CPU non-superscalaire basique, avec une FPU.png|centre|vignette|upright=1.5|CPU non-superscalaire basique, avec une FPU]] Les deux ''back-end'' sont des pipelines séparés, mais il faut que l'unité d'émission soit spécialement conçue pour en profiter. Un processeur simple émission peut démarrer une seule µop par cycle : soit la µop est envoyée au ''back-end'' flottant, soit elle est envoyée au ''back-end'' général. Avec la double émission entière-flottante, le processeur peut envoyer une µop dans chaque pipeline, à chaque cycle. Vu que la FPU et son banc de registre forment déjà un pipeline séparé, les seules modifications se font au niveau du ''front-end'', unité d'émission inclue. {| |- |[[File:CPU simple émission avec une FPU.png|centre|vignette|upright=1.5|CPU simple émission avec une FPU.]] |[[File:Double émission entière flottante avec un second pipeline.png|centre|vignette|upright=1.5|CPU avec un second pipeline flottant.]] |} Notez que le terme double émission ''entière''-flottante est un peu trompeur. En réalité, la technique permet d'émettre une instruction flottante avec n'importe quelle autre instruction non-flottante, avec des restrictions pour les branchements. Il est par exemple possible d'exécuter un calcul flottant en parallèle d'un accès mémoire. Sur les CPU 32 bits, il est possible de faire les multiplications dans la FPU. Pour rappel, la FPU contient un multiplieur entier 53-54 bits, pour multiplier les mantisses de deux flottants 64 bits, qu'on peut utiliser pour faire les multiplications entières 32 bits. Cela permet d'émettre une multiplication en même temps qu'une opération entière dans l'ALU. Ainsi, le CPU pouvait émettre deux instructions : une opération entière de base, avec soit une multiplication, soit une opération flottante. En clair, une émission de type INT + (MUL /FLOAT). Par contre, on perd la possibilité d'émettre une multiplication entière avec une opération flottante, mais c'était un compromis qui en valait la peine. Le CPU PA-RISC 7100 implémentait cette optimisation. Il s'agissait d'un CPU double émission entière-flottante, qui utilisait donc un partitionnement assez simple. Le combo partitionnement + reconditionnement permettait ici de gagner en performance, pour un cout en matériel très limité. D’autant plus limité que le jeu d'instruction prévoyait le reconditionnement de la FPU. Les multiplications ne lisaient pas leurs opérandes dans les registres entiers, mais dans les registres flottants. ===La double émission entière=== Une autre possibilité ajoute un second pipeline, capable d'exécuter des opérations entières simples, appelé le pipeline entier. Le processeur supporte alors la '''double émission entière''', à savoir qu'ils peuvent émettre une opération entière en plus d'une autre instruction. L'opération entière en question est une opération simple, comme une addition, une soustraction, une opération bit à bit, une comparaison, etc. Les exemples classiques sont les processeurs Intel i960 et Pentium. L'implémentation était différente entre l'i960 et le Pentium : Le Pentium avait une seconde ALU entière, alors que le i960 rusait. Le Pentium dupliquait l'ALU entière, pour créer un second pipeline entier. Sur le Pentium originel, les contraintes d'appariement étaient assez strictes. Le Pentium avait une FPU, mais ne pouvait pas l'utiliser en double émission. Il lui était impossible d'exécuter une opération flottante en même temps qu'une opération entière (branchements inclus). Le Cyrix 6x86 était une sorte de Pentium produit par l'entreprise Cyrix, avec une microarchitecture différente. Il avait des contraintes d’appariement réduites. Par exemple, il pouvait émettre une opération flottante en parallèle d'une opération entière. Nous détaillerons ces processeurs dans le prochain chapitre, qui porte justement sur les CPU superscalaires x86. [[File:CPU simple et double émission avec un second pipeline entier.png|centre|vignette|upright=2.5|CPU simple et double émission avec un second pipeline entier.]] L'Intel i960 n'avait pas de FPU, juste une ALU entière et une unité mémoire. Il utilisait l'unité mémoire comme une seconde ALU entière limitée. Pour rappel, une unité mémoire contient une AGU, à savoir une ALU spécialisée dans les calculs d'adresse. Elle est capable de faire des additions, soustractions, et quelques décalages limités (des décalages par 2, 4, 8, pas plus). L'Intel i960 ajoutait des connexions entre AGU et banc de registre, afin que celle-ci serve de seconde unité de calcul. L'AGU est déjà reliée aux deux ports de lecture, pour lire les opérandes du calcul d'adresse, il suffit de la connecter sur le port d'écriture. Le processeur peut alors émettre deux instructions/µops entières, sous certaines conditions. [[File:Emission multiple des opérations entières, double émission.png|centre|vignette|upright=2|Émission multiple des opérations entières, double émission.]] ==Les processeurs superscalaires dynamiques== Les processeurs précédents, avec 2 pipelines, avaient une unité d'émission assez simple. Elle avait deux ports de décodage, et deux ports d'émission. Le nombre de ports de décodage et d'émission étaient identiques. Vous vous dites que c'est naturel, et intuitif, que c'est normal pour un processeur superscalaire. Mais en réalité, la majorité des processeurs superscalaires a plus de ports d'émission que de décodage. Expliquer pourquoi va cependant nous demander de parler de comment la superscalarité exploite les unités de calcul. Posons-nous cette question : de combien d'unités un processeur superscalaire a besoin ? Les unités en question ne sont nécessairement des unité de calcul, l'unité mémoire et l'unité de branchement comptent aussi. La réponse dépend du nombre de voies. Si le ''front-end'' charge et décode un paquet de N instructions, exécuter ces N instructions simultanément demandera là aussi au moins N unités de calcul. Notez le terme : ''au moins'', car c'est là tout l'enjeu de cette section. La réponse dépend aussi des contraintes d’appariement. Pour un CPU superscalaire "parfait", sans contraintes d’appariement, toutes les unités doivent être dupliquées, y compris l'unité mémoire. Un processeur à double émission parfaite devrait dupliquer l'ALU entière, le ''barrel shifter'', le circuit multiplieur, la FPU, l'unité mémoire, et l'unité de branchement, ce qui ferait passer de 6 unités à 12. Le cout en circuit est énorme, même pour de la double émission ! Et pour un CPU à N pipelines, le cout en circuit encore plus prohibitif ! En pratique, les processeurs superscalaires qui font ça sont très rares. La majeure partie des processeurs superscalaires utilisent d'autres techniques : le partitionnement, la duplication partielle des ALUs, la duplication des autres unités. ===Le partitionnement des unités fonctionnelles=== Les CPU superscalaires les plus simples ne dupliquent pas leurs unités de calcul, ils se contentent d'exploiter les unités existantes. Et pour expliquer comment, nous allons partir de l'exemple d'un processeur non-superscalaire contient une ALU entière, une FPU, une unité mémoire et une unité de branchement. Les quatre unités peuvent fonctionner en parallèle, à savoir qu'une unité peut exécuter une instruction à elle toute seule, sans interagir avec les autres. Cela suffit pour créer un processeur quadruple émission, qui peut émettre en même temps : une opération entière, une opération flottante, un branchement, un accès mémoire. Le principe marche aussi sur un processeur avec moins de 4 unités, par exemple sans FPU et/ou sans unité de branchement, ou avec au contraire des unités en plus. L'idée générale est d’émettre une µops séparée dans chaque unité fonctionnelle. Utiliser ainsi les unités existantes, pour rendre un CPU superscalaire, s'appelle le '''partitionnement superscalaire'''. Le terme n'est pas beaucoup utilisé en-dehors de quelques vieux articles académiques. Le partitionnement est fortement dépendant du jeu d'instruction, car il demande de bien séparer instructions entières, flottantes, branchements et instructions mémoire. Et autant c'est bien le cas sur les CPU RISC, autant les CPU CISC ne sont pas dans ce cas. Les CPU CISC ont des instructions ''load-op'', qui effectuent une instruction arithmétique et une µop mémoire. Et ces instructions sont très compliquées à implémenter avec le partitionnement. Et au-delà de ça, les CPU CISC ont beaucoup d'instructions qui sont décodées en plusieurs µops, à exécuter dans un ordre bien précis. On peut pas émettre les µops en question simultanément. Le partitionnement a un cout en circuit très limité, pour un gain en performance lui aussi limité. Pour reprendre le CPU de l'exemple précédent, il est rare que l'on ait à exécuter ces quatre instructions en même temps. En pratique, les combinaisons fréquentes sont les combinaisons calcul + accès mémoire, calcul + branchement, calcul entier + calcul flottant. Utiliser une quadruple émission de ce type n'est donc pas une bonne idée, alors que la double émission parait plus adaptée. Et c'est là que la différence entre ports d'émission et de décodage devient intéressante. L'idée est d'avoir une unité d'émission avec deux ports de décodage, et 4 port d'émission (un par unité). Les contraintes d’appariement varient alors suivant le processeur, mais la règle générale est que si deux micro-opérations tombent dans deux unités différentes, on peut les émettre en même temps. En clair, on peut émettre une opération entière avec une opération flottante, une opération entière avec un branchement, un accès mémoire avec un branchement, etc. Et cela rend le partitionnement bien plus intéressant que prévu. Les tout premiers CPU superscalaires étaient des CPU double émission, qui utilisaient le partitionnement avec : une ALU entière, une unité mémoire et une FPU. Nous parlerons de '''partitionnement INT-FLOAT-MEM'''. L'avantage sur la double émission flottante est que les combinaisons INT + MEM et FLOAT + MEM étaient autorisées. L'intérêt était d'émettre une opération en parallèle d'un accès mémoire, ce qui est un doublet d'instruction assez fréquent. Les exemples classiques sont l'HyperSPARC, de l'alpha 21064 et du PowerPC 603. Les contraintes d’appariement variaient grandement suivant le processeur. Le PowerPC 603 implémentait une double émission "parfaite". C'est à dire que toutes les combinaisons possibles à deux instructions étaient possibles, que ce soit INT + FLOAT, INT + MEM, FLOAT + MEM. En plus de cette double émission "parfaite", le CPU utilisait la technique dite de ''branch folding'', qui permettait d'exécuter un branchement sans utiliser d'unité de calcul, ce qui fait qu'il était qualifié de ''CPU 2-way + Branch''. A l'opposé, le processeur alpha 21064 avait pas mal de contraintes d’appariement, à savoir que certaines combinaisons de deux instructions étaient interdites, bien que compatibles avec les unités disponibles. Une des raisons est que le banc de registre n'avait pas assez de ports de lectures, ce qui fait que certaines combinaisons avec une écriture mémoire n'étaient pas permises. Les concepteurs avaient volontairement inséré ces contraintes afin de simplifier le design du processeur. Avant de poursuivre, précisons que la FPU regroupe un additionneur flottant et un multiplieur flottant. Et ce fait peut être exploité pour approfondir le partitionnement. La '''double émission FADD/FMUL''' permet d'émettre une addition flottante en même temps qu'une multiplication flottante. Elle a été utilisée sur les processeurs x86, Alpha et SPARC. Les autres circuits de calcul flottant sont souvent regroupés avec l'additionneur. La division est parfois e même port que le multiplieur flottant, parfois sur celui de l'additionneur (quand elle est microcodée et exécutée en enchainant les soustractions). ===La duplication des ALU entières=== Le partitionnement est une technique élégante, simple, facile à implémenter et au cout en circuits modeste. Mais il faut avouer que cela ne donne pas des CPU superscalaires très efficaces. La raison est que le partitionnement permet d'émettre des paires, triplets, quadruplets de micro-opérations qui sont rares en pratique. Les combinaisons les plus fréquentes en pratique sont des paires/triplets d'opérations entières, souvent des paires/triplets d'additions ou d'opérations entières simples. Il est donc primordial d'émettre plusieurs opérations entières simultanément. Le fait d'émettre et d'exécuter plusieurs opérations entières en même temps s'appelle l''''émission entière multiple'''. Pour exécuter la seconde/troisième opération entière, il faut dupliquer les ALU entières (ou réutiliser l'AGU comme ALU entière comme le fait l'Intel i960). Le processeur doit avoir deux ALU entières pour de la double émission entière, trois pour de triple émission entière, etc. De plus, il faut ajouter des ports au banc de registre, pour lire deux fois plus d'opérandes et décrire deux résultats. Et enfin, il faut rajouter un port d'émission pour pouvoir émettre une micro-opération entière en plus. [[File:Processeur non-superscalaire basique 03.png|centre|vignette|upright=2|Processeur non-superscalaire basique]] La tendance est de multiplier les ALU entières, mais pas le circuit multiplieur. Le cout en transistors est alors grandement réduit, au prix de l'apparition de dépendances structurelles. Le CPU peut émettre deux additions en même temps, ou une addition et une multiplication, mais pas deux multiplications. Il en est de même avec le ''barrel shifter'', qui n'est pas dupliqué. Il est donc possible d'émettre un décalage avec une opération de base, mais pas deux décalages en parallèle. Mais ces contraintes d’appariement ne sont pas un problème, car il est rare de devoir émettre deux multiplications/décalages en même temps. La plupart des programmes sont majoritairement remplis d'additions, avec des multiplications assez rares et des décalages qui le sont encore plus. La moyenne est proche d'une multiplication pour 4/5 additions. Vu que des multiplications consécutives sont très rares, dupliquer le multiplieur est presque inutile. Disposer de plusieurs circuits multiplieurs ou de plusieurs ''barrel shifters'' serait donc un cout en circuits qui ne servirait que rarement et n'en vaut pas la chandelle. Il faut noter que sur les CPU 32 bits, les multiplications peuvent être exécutées dans la FPU ou dans un multiplieur séparé, tout dépend de si le CPU exécute les multiplications dans la FPU ou pas. {|class="wikitable" |- ! Voie d'émission n°1 !! Voie d'émission n°2 !! Voie d'émission n°3 |- | ALU entière || ALU entière || FPU |} Reste à connecter les unités de calcul à l'unité d'émission (indirectement, car il y a des étages de pipeline entre les deux). Une implémentation basique utilisée un port d'émission par unité. Prenons l'exemple d'un CPU superscalaire avec 4 ALU entières, une FPU, et une unité mémoire. Vu qu'il y a 6 unités, cela fait donc 6 ports d'émission. L'exemple historique le plus impressionnant est celui du Motorola 88110, un CPU double émission qui possède 10 unités. Il contient deux ALU entières, un circuit multiplieur, un circuit diviseur, une unité de manipulation de bits, une unité mémoire, un additionneur flottant, et deux unités graphiques pour des calculs impliquant des pixels. Le multiplieur est utilisé à la fois pour les multiplications entières, flottantes et le produit de deux pixels. Idem pour le diviseur, qui sert pour les divisions entières et flottantes. Et chaque unité a son propre port d'émission. La conséquence est que les contraintes d'appariement du Motorola 88110 sont simples : tant que deux µops atterrissent dans des unités séparées, la paire est permise. Il est par exemple possible d'émettre simultanément deux opérations entières simples, vu qu'il y a deux ALU. Par contre, impossible d'émettre simultanément deux multiplications, deux divisions, deux opérations flottantes, deux manipulations de bit, deux accès mémoire, etc. De plus, le partage du multiplieur fait qu'on ne peut pas émettre une multiplication entière avec une multiplication flottante. Idem avec les divisions, vu que le diviseur est aussi partagé. Ce sont les seules contraintes. ===Le partage des ports d'émission=== La présence d'un circuit multiplieur et d'un ''barrel shifter'' pose des problèmes pour le partitionnement. Il est possible d'avoir un port d'émission dédié au multiplieur, et un autre au ''barrel shifter'', qui sont séparés de ceux pour l'ALU entière. Il est alors possible d'émettre une opération entière, une multiplication et un décalage, simultanément. Nous parlerons de '''partitionnement entier''' pour désigner cette possibilité. [[File:Partitionnement superscalaire entier.png|centre|vignette|upright=2|Partitionnement superscalaire entier.]] Le partitionnement entier est cependant très rare, car le gain en performance serait trop faible au regard des couts en circuit. Quelques processeurs historiques l'utilisaient, mais ce n'est plus le cas de nos jours. La raison est que les multiplications et les décalages sont assez rares dans le code, ce qui fait que le port d'émission associés sont sous-utilisés. Et un port d'émission a un cout en circuit assez important. Et c'est sans compter qu'ajouter des ports sur le banc de registres juste pour un multiplier sous-utilisé n'en vaut pas la peine. L'idéal serait de trouver un moyen de réduire le nombre de ports d'émissions, sans réduire le nombre d'unités de calcul. [[File:Emission multiple des opérations entières, implémentation naive.png|vignette|Émission multiple des opérations entières, implémentation naive]] La solution consiste à '''partager les ports d'émission''', à savoir connecter un port d'émission à plusieurs unités de calcul. L'exemple classique est justement lié aux circuits multiplieur et ''barrel shifters''. L'idée est que le multiplieur et le ''barrel shifter'' sont mis sur le même port d'émission qu'une ALU entière. Prenons par exemple le processeur à double émission entière illustré ci-contre. Un port d'émission est relié à une ALU entière seule, et l'autre port d'émission alimente la seconde ALU entière et le multiplieur. La conséquence est que le processeur peut émettre deux opérations entières, dont une multiplication. Si on avait utilisé un port d'émission dédié au multiplieur, il aurait été possible d'émettre deux opérations entières et une multiplication. On perd donc une voie, mais on gagne en flexibilité et on économise des circuits. Notons que ce partage signifie aussi que le multiplieur partage les ports sur le banc de registre, ce qui fait une double économie. [[File:Emission multiple des opérations entières, implémentation courante.png|centre|vignette|upright=1.5|Émission multiple des opérations entières, implémentation courante]] En général, le ''barrel shifter'' et le multiplieur sont placés sur deux voies d'émission séparés, ce qui permet d'émettre un décalage et une multiplication en même temps. Les mettre sur le même port ne le permettrait pas. {|class="wikitable" |- ! Voie d'émission n°1 !! Voie d'émission n°2 !! Voie d'émission n°3 |- | * ALU entière * Multiplieur | * ALU entière * Barrel shifter | FPU |- | * Additions, soustractions, opérations bit à bit, etc. * Multiplication | * Additions, soustractions, opérations bit à bit, etc. * Décalages et rotations | Opération flottante |} Terminons concernant les multiplieurs avec une dernière subtilité. Pour rappel, les processeurs modernes intégrent en réalité deux multiplieurs différents. Le résultat d'une multiplication est très large et prend deux registres. Par exemple, une multiplication de deux opérandes 64 bits donne un résultat sur 128 bits, ce qui ne tient pas dans un registre, mais en prend deux. L'instruction de multiplication classique ne calcule que les 64 bits de poids faible. mais elle est complétée par d'autres instructions de multiplication qui peuvent faire le calcul complet. Pour résoudre le problème, les processeurs modernes intègrent deux instructions de multiplications : une qui calcule les bits de poids faible du résultat, une autre qui calcule les bits de poids fort. Et ces deux instructions sont associées à deux multiplieurs séparés, aux circuits différent. Le multiplieur qui calcule les bits de poids faible du résultat est appelé le ''low multiplier'', l'autre est appelé le ''high multiplier''. Le second multiplieur est souvent placé sur un second port d'émission, différent du premier multiplieur, partagé avec une ALU. L’avantage de mettre les deux multiplieurs sur deux ports d'émission différents est qu'une multiplication complète peut être réalisée en utilisant les deux multiplieurs en parallèle. Les deux sous-multiplications sont émises en même temps, exécutées en même temps. pas besoin d'exécuter l'une puis la seconde, d'où un gain performance appréciable. Nous venons de voir comment partager un port d'émission entre une ALU et un multiplieur. Mais au-delà de cet exemple, le partage des ports d'émission peut appliquer à n'importe quelle unité. Prenons l'exemple d'un CPU superscalaire avec 4 ALU entières, une FPU, et une unité mémoire. Vu qu'il y a 6 unités, cela fait donc 6 ports d'émission. Cependant, il est rare qu'un bloc de 6 instructions contienne exactement 4 opérations entières, une opération flottante, et un accès mémoire. Beaucoup de ports d'émission seraient sous-utilisés. La solution est de partager des ports d'émission, pour passer à la quadruple émission. Le CPU peut alors répartir 4 instructions sur les ports d'émission adéquats, à chaque cycle. Le CPU a donc 4 ports de décodage et 6 ports d'émission. Une implémentation classique permet n'importe quelle combinaison de 4 instructions compatible avec les 6 unités. Par exemple, il devient possible d'émettre simultanément 4 additions, la combinaison 2 * INT + FLOAT + MEM, 3 * INT + MEM, et bien d'autres. L'exemple relie une ALU entière, la FPU et l'unité mémoire sur le même port. Le CPU a alors quatre ports d'émission, qui ne sont pas "identiques". Trois d'entre eux sont reliés à une ALU entière chacun, rien d'autre. Le quatrième est lui relié à une ALU entière, la FPU et l'unité mémoire. On économise alors deux ports d'émission, mais cela entraine l'apparition de contraintes d’appariement. Le CPU peut émettre 3 opérations entières + n'importe quelle autre opération. Mais les autres combinaisons sont interdites. Le CPU peut émettre 6 opérations entières simultanément, grâce à 6 ALU entières. Les accès mémoire ou opérations flottantes ne viennent pas en plus, mais en remplacement des opérations entières. Regrouper plusieurs ALU sur un même port d'émission est donc à l'origine de dépendances structurelles, de nouvelles contraintes d’appariement. Dans certaines situations de '''''port contention''''', on a assez d'ALU pour exécuter N micro-opérations, mais la répartition des ALUs sur les ports l'empêche. Impossible d'émettre deux micro-opérations sur deux ALU si elles sont sur le même port d'émission. On peut réduire les cas de ''port contention'' en répartissant correctement les ALU sur les ports d'émission, mais sans jamais les supprimer complétement. Un exemple est celui du PowerPC 604. Il implémentait la quadruple émission, alors qu'il avait 5 unités de calcul. Mais deux unités partageaient un même port d'émission. Dans le détail, il avait deux ALU entières, un circuit multiplieur/diviseur, une FPU, une unité mémoire. La FPU et le multiplieur étaient sur le même port d'émission. En conséquence, le CPU pouvait émettre seulement les combinaisons INT + INT + MEM + (MUL/FLOAT). : Il est intéressant de voir l'exemple d'un processeur superscalaire parfait, sans contraintes d'appariement, à N voies. Pour cela, on part d'un processeur non-superscalaire, avec M unités de calcul. Un tel processeur peut s'implémenter avec N ports d'émission, chacun relié à M unités de calcul possibles, ce qui fait que les M unités de calcul sont dupliquées en N exemplaires. Si on prend par exemple un CPU non-superscalaire avec une ALU, une FPU, une unité mémoire et une unité de branchement, un port d'émission sera relié à une ALU, une FPU, une unité mémoire et une unité de branchement. ===La duplication des autres unités fonctionnelles=== Dupliquer les ALU entière est une première étape, mais il est aussi possible de dupliquer les autres unités fonctionnelles. Par exemple, il est possible de dupliquer l'unité mémoire ou l'unité de branchement. Reste à voir quelles unités dupliquer, et pourquoi. Précisons que dans ce qui va suivre, nous allons parler de la duplication des unités en général, pas seulement des unités mémoire/branchement. Nous allons continuer de parler de la duplication des ALU entières dans ce qui suit, mais de manière plus générale. Pour un processeur à N voies, il est théoriquement possible de dupliquer toutes les unités en N exemplaires. Mais ce n'est jamais fait en pratique, car le cout en circuits serait trop important et le gain en performance trop faible. Mieux vaut dupliquer certaines unités bien précises, quitte à avoir des contraintes d'appariement. Et à ce petit jeu, toutes les duplications ne se valent pas, certaines sont plus rentables en matière de performance, le cout en circuit n'est pas le même selon l'unité, etc. La rentabilité en performance dépend surtout des contraintes d'appariement. Les contraintes d'appariement entrainent une baisse de performance significatives si elles interdisent des paires d'instructions fréquentes. Aussi, les opérations très fréquentes, souvent appairées, gagnent à dupliquer l'unité associée. Et au contraire, les unités rarement utilisées ne doivent pas être dupliquées. Il se trouve que les unités les plus utilisées sont les ALU entières, suivies par les unités mémoire et l'unité de branchement. Le cout en circuit n'est aussi pas le même. Dupliquer les ALU entière est trivial, car elles ont un budget en transistors assez faible. Les circuits multiplieurs, diviseurs, et les ''barrel shifter'' ont eux un cout en transistor plus élevés. Si on devait faire un classement, on aurait : ALU entière < ''barrel shifter'' < multiplieur. Pour les unités mémoire, le cout en transistor est là aussi conséquent. Le résultat final est que dupliquer les ALU entières est privilégié sur le reste, comme l'a vu dans la section précédente. Les unités mémoire arrivent en seconde place, suivie par les multiplieurs/''barrel shifter'' à la troisième place, et les unités de branchement à la quatrième place. Les CPU superscalaires larges ont donc tendance à multiplier les unités mémoire en second. Les multiplieurs et ''barrel shifters'' sont eux aussi dupliqués sur les CPU superscalaires larges, mais cela vient souvent après avoir dupliqué les unités mémoire. La raison est que les accès mémoire sont critiques pour la performance des CPU à exécution dans le désordre, pas les multiplications. Pour les unités de branchement, une subtilité complique le fait d'en installer plusieurs. Que faire quand deux branchements sont pris ? La solution la plus simple est de ne pas se trouver dans cette situation : on n'utilise qu'une seule unité de branchement et on n’exécute qu'un seul branchement par cycle. La majorité des processeurs superscalaires étroits font ainsi. Les processeurs superscalaires larges ont cependant deux unités de branchements, mais ils n'acceptent qu'un seul branchement pris à la fois. Si les deux branchements pris sont exécutés en même temps, le processeur n’exécute que le plus récent, dans l'ordre du programme. ===Les CPU superscalaires mélangent les trois techniques=== Les CPU superscalaires utilisent toutes les techniques à la fois : partitionnement, duplication de l'ALU entière, duplication des autre unités fonctionnelles. Chaque processeur utilise ces trois stratégies à sa sauce, en fonction de son budget en transistor. Les quatre techniques ont cependant un cout en circuit différent, et donnent des gains de performances eux aussi forts différents. * Le '''partitionnement superscalaire''' a un cout en circuit modéré, car on n'a pas besoin de dupliquer d'ALU. * La '''duplication des ALU entières''' est la technique la plus importante : elle a un cout en circuit modéré, et donne des gains en performance impressionnants. * La '''duplication des autres unités''' a un cout en circuit variable, pour des gains en performance eux aussi variables. * Le '''partage des ports d'émission''' réduit le cout en circuit du CPU, pour des pertes de performances mineures si bien fait. L'usage du partitionnement seul, sans duplication, était surtout le fait des processeurs commercialisés entre les années 1989 et 1993. Le partage des ports d'émission a lui aussi mis un peu de temps pour s'imposer. Globalement, les processeurs superscalaires ont évolués progressivement, pour se rapprocher d'une sorte de standard. Mais pour comprendre ce qu'est ce standard, et en quoi les CPU historiques s'en sont progressivement rapprochés, il faut étudier l'histoire des CPU superscalaires. L'histoire des CPU superscalaires a commencé dès 1960, mais est resté un projet de recherche pendant plusieurs décennies. De nombreux designs ont été conçus, mais abandonnés avant la production, comme l'ACS-1 d'IBM. Les années 1980 ont vu l'arrivée de prototypes de processeurs VLIW, mais qui n'étaient pas superscalaires. Par exemple, l'Apollo DN10000 et l'Intel i860 pouvaient émettre deux instructions à la fois, sous conditions, mais demandaient que le compilateur fasse une bonne partie du travail. Les premiers CPU superscalaires commercialisés sont sortis en 1989. Deux CPUs superscalaires sont sortis cette année là : le RS/6000 d'IBM et l'i960CA d'Intel. Puis, la compétition s'est aussi lancée dans la bataille. Les CPU commercialisés avant l'année 1993 étaient à double émission, à l'exception du SuperSPARC qui utilisait la triple émission. Les modèles après 1993 hésitaient entre double et quadruple émission. Dans le tableau ci-dessous, les processeurs quadruple émission sont en bleu, les triple émission sont en rouge, les autres ne sont pas en couleur. {|class="wikitable" |- ! !! IBM !! HP PA-RISC !! SPARC !! Intel!! Alpha !! Autres |- ! 1989 | RS/6000 || || || i960CA || || |- ! 1990 | || || || || || |- ! 1991 | || || || || || Motorola 88110 |- ! 1992 | RSC || PA 7100 || class="f_rouge | SuperSPARC || || 21064 || |- ! 1993 | PPC 601 || || HyperSPARC || Pentium || || |- ! 1994 | class="f_bleu | POWER 2 || PA 7200 || || || class="f_bleu | 21164 || |- ! 1995 | 603/604 || class="f_bleu | PA 8000 || class="f_bleu | UltraSPARC 1 || Microarchitecture P6 (+ concurrence AMD) || || class="f_bleu | MIPS R1000 |- ! 1996 | class="f_bleu | 620 || || || || class="f_bleu | 21264 || |- ! ... || ... || ... || ... || ... || ... || ... |} Les premiers CPU à double émission sont assez représentatifs des CPU à double émission modernes. Il faut dire que se limiter à deux voies ne permet pas de faire beaucoup de choses. Voici le tableau chronologique disant quel CPU utilisait quelle technique. * Les CPU en vert utilisaient la double émission entière-flottante. * Les CPU en rouge utilisaient la double émission entière "pure". * Les CPU en jaune utilisaient un ''partitionnement complet'' entre ALU, FPU et unité mémoire. * Les CPU sans couleur utilisaient un grand nombre d'unités, avec beaucoup de ports d'émission. * Les CPU barrés utilisent la triple ou quadruple émission et seront vu dans la section suivante. {|class="wikitable" |- ! !! IBM !! HP PA-RISC !! SPARC !! Intel!! Alpha !! Autres |- ! 1989 | class="f_vert | RS/6000 || || || class="f_rouge | i960CA || || |- ! 1990 | || || || || || |- ! 1991 | || || || || || Motorola 88110 |- ! 1992 | class="f_vert | RSC || class="f_vert | PA 7100 || <s>SuperSPARC</s> || || class="f_jaune | 21064 || |- ! 1993 | class="f_vert | PPC 601 || || class="f_jaune | HyperSPARC || class="f_rouge | Pentium || || |- ! 1994 | <s>POWER 2</s> || PA 7200 || || || <s>21164</s> || |} C'est en 1994, que la quadruple émission est arrivée et que les CPU ont essayé divers implémentations. Il y avait alors trois stratégies pour la double/triple/quadruple émission, qui partageaient des problèmes similaires. La première implémentation dupliquait les ALUs et les FPUs, ce qui permettait d'émettre deux opérations flottantes avec deux opérations entières. Le POWER 2 dupliquait ses FPUs à la perfection, alors que le 21264 séparait l'additionneur et le multiplieur flottant. Les accès mémoire étaient traités comme des opérations entières et le processeur pouvait souvent en émettre deux à la fois. Mais une telle organisation n'est plus utilisée de nos jours, car, sans instructions flottantes à exécuter, elle est équivalente à de la double émission. La seconde implémentation utilisait deux ALU entières (dont un multiplieur), une unité mémoire et une FPU.Cette organisation est intéressante, mais encore trop stricte pour donner de bons résultats, les quadruplets avec exactement deux opérations entières, un accès mémoire et une opération flottante étant trop rares. L'usage de ces 4 unités en double ou triple émission a été utilisé sur le PA 7200 et le SuperSPARC. Malheureusement, en plus de problèmes au niveau de son cache, le SuperSPARC avait de nombreuses contraintes d’appariement, car le banc de registre n'avait pas assez de ports pour alimenter certaines combinaisons d'instructions. De plus, s'il émettait une multiplication, il ne pouvait pas émettre de seconde µop. Enfin, une troisième implémentation utilisait un grand nombre d'unités fort différentes, bien plus que quatre, avec au minimum deux ALU entières. Prenons l'exemple de l'UltraSPARC, qui avait : deux ALU entières, une unité mémoire, une unité de branchement, un additionneur flottant, un multiplieur flottant, un diviseur flottant (aussi utilisé pour le calcul des racines carrées), et 2 unités graphiques pour les calculs sur des pixels. En tout, cela fait 9 unités différentes, pour de la quadruple émission. Dans le même genre, les processeurs MIPS R8000 et R10000 avaient une implémentation plus moderne, dans le sens où toutes les unités étaient dupliquées. Le CPU avait deux ALU, deux FPU et deux unités mémoire. Il pouvait donc émettre quatre instructions à la fois, tant que le paquet collait avec ces six unités. Moitié opérations entières, moitié opérations mémoire, avec de quoi remplacer les opérations entières par des opérations flottantes. Le PA 8000, lui, dupliquait toutes ses unités en deux exemplaires, ce qui n'est pas l'idéal, aucun processeur moderne ne fait cela aujourd'hui. Le tout est résumé dans le tableau ci-dessous, avec : * en vert les CPU utilisant la première stratégie ; * en rouge les CPU utilisant la seconde stratégie ; * en jaune les CPU utilisant la troisième stratégie. {|class="wikitable" |+ Processeurs quadruple émission historiques |- ! Année !! Processeur !! Unités |- ! 1991 | class="f_jaune | Motorola 88110 || class="f_jaune | 2 ALU + MUL + DIV + BIT + MEM + FADD + 2 unités graphiques |- |- ! rowspan="2" | 1994 | class="f_vert | POWER 2 || class="f_vert | 2 ALU/MEM + 2 FPU (+ 2 Branchements via ''branch folding'') |- | class="f_rouge | 21164 || class="f_rouge | 2 ALU + FPU + MEM |- ! rowspan="3" | 1995 | PA 8000 || 2 ALU + 2 ''barrel shifters'' + 2 MEM + 2 FPU (FMA) + 2 FPU (DIV et SQRT) + 2 SIMD |- | class="f_jaune | UltraSPARC 1 || class="f_jaune | 2 ALU + MEM + BRANCH + FADD + FMULFDIV + 2 unités graphiques |- | MIPS R8000 et R10000 || 2 ALU + 2 FPU + 2 MEM |- ! rowspan="2" | 1996 | class="f_rouge | 620 || class="f_rouge | 2 ALU + FPU + MEM |- | class="f_vert | 21264 || class="f_vert | 2 ALU/MEM + 2 FPU (FADD + FMUL) |} Malheureusement, ces CPUs historiques n'avaient ni assez d'unités de calcul entières, ni d'unités mémoire, pour remplir la quadruple émission. Environ la moitié des instructions d'un programme correspond à des instructions entières. Pour en profiter, un processeur à N voies doit disposer d'au minimum N/2 ALU entières, l'idéal étant d'aller au-delà. Les CPU superscalaires historiques avaient 2 ALU pour de la quadruple émission, ce qui était très limite. En comparaison, les CPU superscalaires modernes mettent le paquet niveau ALU entière. La plupart des CPU x86 modernes descendent rarement sous les 2/3, la plupart remplit presque la totalité de la largeur du CPU. Pour donner un exemple, la microarchitecture Golden Cove d'Intel est un processeur à 6 voies, avec 5 ALU entières. Pour être précis, un programme informatique exécute environ 40% de son code dans des instructions arithmétiques, un autre 40% dans les accès mémoire, et un le reste pour... le reste. La conséquence est que les processeurs modernes dupliquent leurs unités mémoire. Par exemple, la microarchitecture ''Golden Cove'' d'Intel dispose de trois unités mémoire : deux spécialisées dans les écritures, trois dans les lectures. La microarchitecture ''Gracemont'' utilise la pentuple émission et peut émettre 4 µops entières et 4 µops mémoire. Notez que le ratio est équilibré entre opérations entières et mémoire, avec soit égalité, soit un avantage pour les ALU entières. Une autre régularité est que la largeur totale du processeur peut être occupée par des opérations entières/mémoire. Pour le dire autrement, sur un processeur quadruple émission, il pourra émettre un mix de 4 instructions entière/mémoire, avec zéro opération flottante. Idem avec des processeurs triples ou pentuple émission, voire plus. Si le processeur émet une opération flottante, elle remplace une opération entière. Prenons l'exemple des processeurs AMD K6, sortis en 1997, juste avant les AMD Athlon. Ils avaient 10 unités de calcul, 6 ports d'émission, 4 ports de décodage. Voici exactement comment étaient répartie les unités de calcul sur les ports d'émission. C'était des processeurs quadruple émission, ce qui fait que la moitié de la largeur du processeur sert pour des opérations entières, et l'autre moitié pour les accès mémoire. {|class="wikitable" |- ! Port d'émission n°1 !! Port d'émission n°2 !! Port d'émission n°3 !! Port d'émission n°4 !! Port d'émission n°5 !! Port d'émission n°6 ! |- | ALU entière || ALU entière || FPU || Unité de branchement || Unité LOAD || Unité STORE |- | || Multiplieur || || || || Unité de calcul d'adresse (instruction LEA) |- | || ''Barrel shifter'' || || || || Unité pour les instructions PUSH |} Les microarchitectures K7, K8 et K10, utilisées sur les anciens CPU AMD Athlon, sont un exemple moins représentatif. Ces microarchitectures utilisent le partage des ports d'émission au maximum. C'était des microarchitectures à triple émission, avec six ports d’émission. Il y avait trois ports d'émission pour les opérations flottantes, et trois ports d'émission pour les micro-opérations entières/mémoire. Il y avait trois ALU entières et trois unités mémoire, chaque ALU partageait un port d'émission avec une unité mémoire. Elle pouvait donc émettre soit trois opérations entières, soit trois µops mémoire, soit un mix des deux. En plus des mix avec les opérations flottantes et branchements. {|class="wikitable" |- ! Port d'émission n°1 !! Port d'émission n°2 !! Port d'émission n°3 !! Port d'émission n°4 !! Port d'émission n°5 !! Port d'émission n°6 ! |- | ALU entière || ALU entière || ALU entière || FADD || FMUL || FPU (autres opérations) |- | Multiplieur || || || || || |- | LOAD/STORE || LOAD/STORE || LOAD/STORE || || || |} Les CPU superscalaires larges dupliquent les multiplieurs et/ou les ''barrel shifters'', et même les unités de branchement. La raison est que quand la largeur du CPU augmente, le processeur traite des paquets d'instructions de plus en plus gros. Par exemple, pour un CPU à 10 voies, cela veut dire émettre 10 instructions en même temps. Il est alors plus fréquent d'avoir deux multiplications, deux décalages, deux accès mémoire, deux branchements. Par exemple, la moyenne est d'une multiplication tous les 5 instructions. Les CPU superscalaires à 10 voies ont donc tendance à avoir deux multiplications par paquet d'instruction, en moyenne. Avoir deux multiplieurs est alors un gain en performance clair. Par exemple, la microarchitecture ''Golden Cove'' a deux ''barrel shifters''. C'est une architecture à 6 voies. {|class="wikitable" |- ! Port d'émission n°1 !! Port d'émission n°2 !! Port d'émission n°3 !! Port d'émission n°4 !! Port d'émission n°5 !! Port d'émission n°6 !! Port d'émission n°7 !! Port d'émission n°8 !! Port d'émission n°9 !! Port d'émission n°10 |- | ALU entière || ALU entière || ALU entière || ALU entière || ALU entière || LOAD || LOAD || LOAD || STORE || STORE |- | ''Barrel shifter'' || Multiplieur || Multiplieur || ''Barrel shifter'' || || || || || || |- | Branchements || Diviseur || || Branchements || || || || || || |} ==Les µops mémoire sur les processeurs superscalaires== Plus haut, nous avons volontairement passé sous silence les accès mémoire. La raison à cela est que leur support sur les CPU superscalaire peut se faire de plusieurs manières différentes, qu'il vaut mieux expliquer dans une section dédiée. Les différentes implémentations sont décrites dans la liste suivante, nous allons les voir une par une. * Avec la première méthode, les accès mémoire sont exécutés par le pipeline pour les opérations entières. * Avec la seconde méthode, les accès mémoire ont un pipeline dédié ; c'est l'''émission parallèle des accès mémoire''. * Avec la troisième méthode, il est possible d'émettre plusieurs accès mémoire simultanément : c'est l'''émission multiple des accès mémoire''. Voyons ces trois cas dans le détail. Nous verrons notamment les différentes formes d'émission multiple des accès mémoire. ===Les accès mémoire traités dans le pipeline entier=== Dans le cas le plus simple, les accès mémoire sont traités comme des opérations entières un peu spéciales. L'unité mémoire est sur le même port d'émission que l'ALU entière, ce qui fait que les accès mémoire remplacent des opérations entières. Faire ainsi permet d'utiliser une ALU entière pour les calculs d'adresse, pas besoin de rajouter une unité de calcul d'adresse séparée. Typiquement, un processeur de ce type place l'unité mémoire après l'unité de calcul. Les opérations entières n'utilisent que l'ALU entière, mais pas l'unité mémoire. Les accès mémoire exécutent un calcul d'adresse dans l'ALU entière, puis l'adresse calculée est envoyée à l'unité mémoire. Le tout est illustré ci-dessous, dans le cas d'un processeur historique à double émission entière-flottante. [[File:Processeur non-superscalaire basique 01.png|centre|vignette|upright=1.5|Processeur non-superscalaire basique]] Un exemple de CPU double émission de ce type est celui du Power PC 440, un CPU destiné à l'embarqué. Vu qu'il était destiné à l'embarqué, il n'avait pas de FPU, il n'avait pas besoin de manipuler de nombres flottants. Il n'a donc que des ALU entières, un multiplieur et une unité mémoire. Il dispose de deux ports d'émission. Le premier est connecté à une ALU entière et un circuit multiplieur, le second est relié à l'unité mémoire et une seconde ALU entière. Une organisation simple, mais très efficace ! [[File:PowerPC 440.png|centre|vignette|upright=2|Microarchitecture du PowerPC 440.]] L'implémentation économise une unité de calcul d'adresse, mais n'a pas de cout en performance significatif. Les accès mémoire étant très lents, émettre une µop entière en parallèle d'un accès mémoire ne sert pas à grand-chose. On peut émettre cette µop entière un cycle plus tard, elle sera terminée avant même que l'accès mémoire soit terminé, même si l'accès mémoire se fait dans le cache L1 ou L2. Pour comprendre pourquoi, faisons quelques calculs. Un accès mémoire prend deux-trois cycles quand il tombe dans le cache L1. Et on doit attendre qu'il soit terminé pour en émettre un nouveau. Combien d'instructions arithmétiques peut-on lancer pendant ce temps, sur un CPU triple émission ? Au premier cycle, on peut en émettre 2 (l'instruction mémoire prend une place, donc 3-1), puis 3 au second cycle. Ce qui fait 5 instructions arithmétiques au total. Or, il se trouve qu'il y a une instruction d'accès mémoire pour 5 instructions arithmétiques, environ. Par contre, ce compromis change quand on passe à la quadruple émission, voire au-delà. Dans ce cas, il devient intéressant de pouvoir émettre une nouvelle instruction mémoire à chaque cycle. Ce qui nous amène à la section suivante... ===L'émission parallèle des accès mémoire=== A partir de la quadruple émission, la tendance a été de séparer l'unité mémoire des ALU entières. Cela permet d'émettre des µops mémoire en même temps que des µops entières et/ou flottantes., ce qui porte le nom d''''émission parallèle des µops mémoire''', ou encore ''émission mémoire parallèle''. Par exemple, un processeur quadruple émission peut émettre en même temps deux opérations entières, une opération flottante et un accès mémoire. L'accès mémoire vient en plus des opérations entières, il n'est pas possible de remplacer l'accès mémoire par une opération entière. La technique ne permet pas de faire les calculs d'adresse dans l'ALU entière. Il faut donc utiliser une unité de calcul d'adresse séparée. Elle est intégrée dans l'unité mémoire, qui fait l'interface entre le cache et le banc de registres. Le cout en circuits est très faible, car les unités de calcul d'adresse n'utilisent guère plus qu'un additionneur et un circuit de décalage très simple. L'émission mémoire parallèle est plus facile à implémenter sur les CPU RISC, qui ont des instructions mémoire séparées du reste. Les CPU CISC ne sont pas dans ce cas, ce qui fait que séparer l'unité mémoire du pipeline entier est compliqué. Les CPU superscalaires historiques étaient pour moité des CPU RISC et pour moitié des CPU CISC, ce qui fait qu'ils n'utilisaient pas ou peu l'émission mémoire parallèle. Les premiers processeurs superscalaires se contenaient de l'émission parallèle mémoire, ils ne pouvaient émettre qu'un seul accès mémoire à la fois, l'unité mémoire n'était pas dupliquée. Et ce n'est pas tant un problème que ça, du moins sur les processeurs à double ou triple émission. En effet, il est rare que l'unité mémoire doive faire deux accès simultanés. Notons que le processeur peut exécuter une instruction mémoire en parallèle d'un calcul ou d'un branchement, seuls les accès mémoire simultanés sont impossibles. ===L'émission multiple des accès mémoire avec une LSQ=== Les processeurs superscalaires larges travaillent sur des paquets de 8 à 10 instructions, il est plus fréquent d'avoir plusieurs accès mémoire par paquet. Dans ces conditions, il est utile d'avoir une '''émission multiple des accès mémoire''', à savoir d'émettre plusieurs micro-opérations mémoire en même temps. Les processeurs superscalaires modernes sont capables d'émettre plusieurs lectures/écritures simultanément. Par exemple, ils peuvent émettre une lecture en même temps qu'une écriture, ou plusieurs lectures, ou plusieurs écritures. Il faut noter que selon le processeur, il peut y avoir des restrictions quant aux accès mémoire émis en même temps. Par exemple, certains processeurs peuvent émettre une lecture avec une écriture en même temps, mais pas deux lectures ni deux écritures. Ou encore, ils peuvent émettre deux lectures, une lecture et une écriture, mais pas deux écritures en même temps. Dans la majorité des cas, les processeurs ne permettent pas d'émettre deux écritures en même temps, alors qu'ils supportent plusieurs lectures. Il faut dire que les lectures sont plus fréquentes que les écritures. Les processeurs qui autorisent toutes les combinaisons de lecture/écriture possibles, sont rares. L'émission multiple des accès mémoire s'implémente dans l'unité mémoire. Pour rappel, l'unité mémoire s'interpose entre le cache L1 et le reste du pipeline. Dans le cas le plus simple, elle incorpore une ''load/store queue'' et des unités de calcul d'adresse. L'émission multiple des accès mémoire demande de rendre la ''Load-store queue'' multi-ports, afin de gérer plusieurs micro-opérations mémoire simultanées. Il faut aussi dupliquer les unités de calcul d'adresse reliées à la LSQ, chaque port d'émission mémoire devant avoir sa propre unité de calcul d'adresse. : Dans ce qui suit, nous parlerons d'AGU (''Adress Generation Unit'') pour désigner les unités de calcul d'adresse, et de LSQ pour designer la ''Load-store queue''. [[File:Processeur non-superscalaire basique 02.png|vignette|upright=1|Processeur non-superscalaire basique]] Dupliquer les ports de la LSQ et les AGU est nécessaire. Mais qu'en est-il du cache ? La réponse varie suivant le processeur. Il y a deux grandes méthodes pour implémenter l'émission multiple des accès mémoire. La première méthode ajoute des ports de lecture/écriture au cache de données, pour faire des lectures/écritures simultanées. Il faut alors dupliquer des unités de calcul, rajouter les ports sur le cache, mais aussi rajouter des ports sur la ''load/store queue'', pour qu'elle échange des données/commandes mémoire avec le cache. Le cout en circuits est alors conséquent La seconde duplique les unités de calcul, mais pas les ports d'accès au cache. Les accès mémoire sont alors accumulés dans la ''load/store queue'', qui sont ensuite traités un par un par le cache. Un exemple est celui des processeurs AMD de micro-architecture K7 K8, à savoir les anciens AMD Athlon et AMD Athlon 64, qui pouvaient calculer trois adresses simultanément, mais ne pouvaient faire qu'un seul accès au cache par cycle. Le cout en circuit est modéré : les unités de calcul coutent très peu, les ports de la ''load/store queue'' coutent déjà un peu plus. Quelques processeurs utilisaient des solutions intermédiaires. Un processeur utilisant cette technique est, par exemple, capable d'émettre quatre µops mémoire en même temps, mais avec seulement deux ports sur le cache. Un exemple classique étant les Pentium 1 et 2 d'Intel, dont nous parlerons dans le chapitre suivant. ===L'émission séparée des LOAD et STORE=== De rares processeurs ont des ports d'émission qui peuvent faire indifféremment lecture comme écritures. Mais les processeurs modernes préfèrent séparer ports d'émission pour les lectures et les écritures. Un exemple est celui des processeurs Intel de micro-architecture Nehalem, qui avaient un port de lecture et un port d'écriture tous deux reliés à la ''Load-store queue'', chacun avec leur propre unité de calcul d'adresse. Comme autre exemple, les processeurs skylake ont une LSQ avec deux ports de lecture et un port d'écriture, ce qui permet d'émettre deux lectures en même temps qu'une écriture. Dans cette section, nous allons étudier le cas avec des ports séparés pour les lectures et écritures. En général, les processeurs ont un peu plus de ports de lectures que d'écritures. Une raison est qu'un programme a, en moyenne, un tout petit peu plus de lectures que d'écritures. Mais la différence n'est pas énorme, c'est un léger déséquilibre. Une seconde raison est que l'exécution dans le désordre marche bien mieux quand les lectures ont lieu le plus tôt possible. Donc mieux vaut privilégier les lectures à l'émission, pour qu'elles se fassent un peu en avance. En pratique, la différence n'est pas très marquée. Il est courant d'avoir un port de lecture et un d'écriture, les CPU superscalaires très larges ont souvent deux ports de lecture et deux d'écriture. A la rigueur, quelques CPU ont trois ports de lecture et deux d'écriture. Le cas le plus simple est celui où on peut émettre une lecture et une écriture en même temps. Il s'implémente facilement si la LSQ est en réalité une simple ''Store queue'', à savoir qu'elle met en avance les écritures uniquement. Pour rappel, les écritures sont mises en attente dans la ''Store queue'', mais les lectures sont exécutées immédiatement. Une fois l'adresse à lire connue, la lecture consulte la ''Store queue'' pour détecter les dépendances de données, puis s'exécute. La donnée à lire est lue soit depuis la ''Store queue'', soit depuis le cache. [[File:Emission LOAD - Store séparée.png|vignette|upright=1|Émission LOAD - Store séparée]] L'implémentation de l'émission multiple est alors très simple. La ''Store queue'' a déjà deux ports, avec un pour les lectures et un autre pour les écritures. Idem pour le cache, qui a naturellement un port de lecture et un d'écriture. Émettre une lecture et une écriture simultanément ne demande donc pas de modification digne de ce nom. La ''Store queue'' doit juste supporter une lecture et une écriture simultanée. Ajouter l'émission d'une seconde lecture n'est pas compliquée : il faut juste rajouter un second port de lecture sur le cache et la ''Store queue''. Pour rappel, l'unité mémoire est précédée par une structure qui met en attente les micro-opérations mémoire avant leur émission finale. La structure en question varie suivant l'implémentation, mais un cas particulier se marie bien avec l'émission multiple des µops mémoire. Il s'agit du cas avec une file de µops séparée pour les lectures et une autre pour les écritures, appelées respectivement la ''file de µops LOAD'' et la ''file de µops STORE''. Il est alors possible d'émettre une lecture et une écriture lors du même cycle d'horloge. Le port de lecture alimente une unité de calcul d'adresse dédiée, directement reliée au cache. Le port d'écriture du cache alimente une unité de calcul, qui est suivie par une file d'écriture, elle-même reliée au cache. Les processeurs AMD de micro-architecture K6 utilisaient cette technique. [[File:Double émission avec le Load Ordering, Store Ordering.jpg|centre|vignette|upright=2.5|Double émission avec le Load Ordering, Store Ordering]] ==Les CPU superscalaire à exécution dans le désordre== La superscalarité modifie aussi les circuits dédiés à l'exécution dans le désordre. Elle modifie les unités de renommage de registre, le ROB et les autres structures liées à l'exécution dans le désordre, au sens large. Aucune structure n'est épargnée. Elles ont tous des prots de lecture/écriture en plus, afin d'encaisser l'émission, le ''commit'' ou le renommage simultané de plusieurs µops. Par exemple, le ROB doit être modifié pour émettre et terminer plusieurs instructions en même temps, en ajoutant des ports de lecture/écriture. Pour un CPU superscalaire à 8 voies, on se dit que le ROB peut retirer 8 µops par cycle maximum. Mais certains processeurs récents ont un ROB qui peut retirer le double ! Un exemple est celui des CPU de micro-architecture Skymont, qui peuvent émettre 8 µops par cycle, mais en retirer 16. Quelques CPU de marque AMD étaient aussi dans ce cas. L'avantage est que cela permet de réduire la taille du ROB, du banc de registre et de quelques autres structures matérielles liées à l'exécution dans le désordre. Le gain sur-compense le cout en transistor nécessaire pour retirer 16 µops par cycle. Dans cette section, nous allons voir comment les étages du pipeline dédiés à l'exécution dans le désordre sont modifiées sur un CPU superscalaire. ===L'exemple du PA-RISC PA 8000=== Avant de commencer, nous allons voir un processeur superscalaire assez simple, le PA 8000, de HP, qui implémente le jeu d'instruction PA-RISC. Bien que très ancien, il implémentait l'exécution dans le désordre et le renommage de registre. Le peu d'informations que nous avons sur ce processeurs proviennent des documents "THE HP PA-8000 RISC CPU" par Ashok Kumar, et l'article de microprocessor report "PA-8000 Combines Complexity and Speed". Ils ne donnent malheureusement pas énormémment d'informations et je devrais être amené à faire quelques suppositions dans ce qui suit. Avant de commencer, parlons de détails sans lien avec la superscalairité. Ce processeur, comme beaucoup de processeurs PA-RISC, n'intégrait pas de cache de niveau L2 dans le processeur, qui était déporté en-dehors du CPU, sur la carte mère. Le processeur préférait utiliser ses transistors pour avoir un cache L1 assez large, quitte à ce qu'il soit plus lent. La lenteur du cache était prévue, le processeur compensait celle-ci en utilisant l'exécution dans le désordre, bien que ce ne soit pas parfait. Les CPU PA-RISC avant le PA 8000 utilisaient un pipeline à vagues ''wave pipeline'', ce qui était assez peu commun, mais le PA 8000 repasse à un pipeline synchrone classique. Passons maintenant à la superscalarité. Le PA 8000 est un processeur quadruple émission, qui peut émettre, à chaque cycle, deux opérations et deux accès mémoire. Le renommage de registre utilise des registres de renommage séparés des registres architecturaux, comme c'était la mode à l'époque. Le budget en transistor faisait que c'était soit ça, soit le renommage dans le ROB, faute de mieux. L'exécution dans le désordre, quant à elle, est prise en charge par une structure matérielle unique, qui ressemble à une fusion entre un ROB et une fenêtre d'instruction. Et c'est là que je vais devoir faire des suppositions. Le document "THE HP PA-8000 RISC CPU" nomme cette structure : l''''''Instruction Reorder Buffer'''''. Il utilise pas moins de 850 000 transistors, et prend 20% de la taille du ''die''. L'article "THE HP PA-8000 RISC CPU" laisse fortement sous-entendre qu'il s'agit une structure unique, faite d'un seul tenant, mais l'article de microprocessor report dit le contraire par moment. Il est décrit comme une fenêtre d'instruction, à savoir qu'il détecte les dépendances entre instruction et les émet. Il gère aussi la détection des mauvaises prédictions de branchement et peut annuler les instructions chargées à tord, en les retirant de la fenêtre d'instruction. Il est aussi précisé que les instructions quittent cet ''Instruction Reorder Buffer'' dans l'ordre du programme. Elles ne peuvent en sortir que quand elles ont été exécutées et qu'elles n'ont causé aucune exception. Ce qui fait qu'il se comporte comme un ROB de ce point de vue là. Difficile de dire si l'''Instruction Reorder Buffer'' est un réel mélange entre un ROB et une fenêtre d'instruction, ou si il est réellement conçu avec deux structures séparées. Dans ce qui suit, je pars du principe que les deux structures sont séparées. Le processeur contient deux fenêtres d'instruction : une réservée aux µops mémoire (LOAD et STORE), l'autre pour les opérations entières/flottantes. Elles ont chacune 28 entrées, ce qui permet de mémoriser 56 µops au maximum. Là encore, précisons que les choses ne sont pas claires pour ce qui est de la séparation. L'article de Microprocessor report dit que les deux sont physiquement séparées, et que cette séparation physique permet de simplifications (les opérations mémorisent des noms de registres plus court que les adresses demandées par les µops LOAD/STORE). Mais l'autre document cité laisse penser que l''''Instruction Reorder Buffer'' est une structure unique. A chaque cycle, le processeur peut émettre deux instructions de calcul et deux instructions mémoire. Les deux fenêtres d'instruction ont pour cela chacune deux ports d'émission. Les deux prots d'émission pour les µops mémoire sont identiques, et peuvent faire aussi bien des µops LOAD que STORE. Le cache L1 est un cache double port, ce qui permet de faire deux lectures/écritures apr cycle, ce qui colle avec la double émision de µops mémoire. Pour ce qui est des µops entières/flottantes, le processeur a dupliqué toutes ses unités de calcul : il a deux ALU entières, deux ''barrel shifters'', deux FPU de type FMAC, et deux unités de division flottante. Vraisemblablement, il y a deux ports d'émission, chacun étant connecté à une unité de chaque type. Le partage des ports d'émission est donc parfait. En clair : le processeur aurait une superscalarité presque parfaite s'il était un CPU àç double émission ! A chaque cycle, la fenêtre d'instruction émet les deux µops les plus anciennes qui sont prête à être exécutées. La documentation dit que la fenêtre émet "la plus vielle instruction paire, et la plus vielle instruction impaire", ce qui sous-entend que la fenêtre d'instruction est en réalité composée de deux sous-fenêtres, une fenêtre paire et une impaire. Les µops sont insérées après le décodage dans ces sous-fenêtres : les deux µops sont réparties dans les deux. Et lors de l'émission, une µops vient d'une sous-fenêtre, une autre µops vient de l'autre. La fenêtre d’instruction a donc une structure partitionnée, avec une logique d'éveil segmentée, une partie gérant la moité de la fenêtre d'instruction, l'autre gérant le reste. Le processeur utilise une implémentation ''Read After Issue'', ce qui veut dire que les opérandes des instructions sont lues après l'émission, juste avant l'exécution. La µops est émise, puis ses opérandes sont lues, pas l'inverse. Il n'y a pas de stations de réservation dans le processeur, les µops attendent que toutes leurs opérandes soient prêtes dans la fenêtre d'instruction, puis lisent les registres juste avant l'exécution Chaque fenêtre d'instruction pouvait recevoir 4 µops par cycle de la part des décodeurs, et répartissait ces 4 µops dans les deux fenêtres d'instructions. Les décodeurs, quant à eux, ne pouvaient décoder que 4 instructions/µops par cycle. Le processeur peut aussi ''commit'' deux opérations et deux accès mémoire par cycle, ce qui revient à transférer les résultat des registres de renommage vers les registres architecturaux. ===La superscalarité avec une file/fenêtre d'instruction centralisée=== Plus haut, nous avons montré qu'un processeur pouvait avoir plus de ports d'émission que de ports de décodage. On dit aussi que sa ''largeur de décodage'' était supérieure à sa ''largeur d'émission''. La '''largeur de décodage''' est le nombre de µops fournies par l'unité de décodage par cycle d'horloge, la '''largeur d'émission''' est le nombre maximal de µops émises par cycle d'horloge. Et n'allez pas croire qu'un surplus de ports d'émission est du gâchis. Sur les processeurs avec exécution dans le désordre, ce surplus peut être utilisé. Mais avant toute chose, évacuons un détail. Vous avez sans doute pensé que le surplus peut être exploité par les instructions machines décodées en plusieurs µops . Par exemple, si une instruction est décodée en deux µops, on pourrait avoir un port d'émission en plus pour en profiter. Mais les ports de décodage sont *en sortie du décodeur*, et contiennent des µops, pas des instructions. Le surplus de ports d'émission peut occasionnellement utiliser le surplus de ports de décodage, mais cela implique que des µops ont été mises en attente dans l'unité d'émission, pour être émises par la suite. Et cela implique l'usage d'une fenêtre d'instruction ou d'une file de µops. Le principe est que les µops sont accumulées dans la fenêtre d'instruction, en attendant leurs opérandes ou la résolution d'une dépendance. Et si l'occasion se présente, une µops est émise sur chaque port d'émission. Il y a donc un gain en performances, mais il faut faire quelques précisions sur son origine. La largeur d'émission utilisée ne peut pas dépasser, *en moyenne*, la largeur de décodage. Et c'est intuitif : un CPU qui décode 4 µops par cycle ne peut pas émettre 6 par cycle en moyenne, sur le temps long, il n'y a pas de µops en surplus qui sortent du vide. Par exemple, sur un processeur quadruple émission, si on analyse combien d'instructions sont émises par cycle, il peut y avoir des cycles où la largeur d'émission est totalement utilisée, mais ce sera compensé par des périodes où elle est fortement sous-utilisée. Les µops sont accumulées en cas de sous-utilisation, puis consommées en cas d'utilisation complète. Les deux périodes se compensent. Et c'est là que l'on peut comprendre d'où vient le gain en performance. Les cycles où les ports d'émission sont sous-utilisés existent systématiquement, que le processeur utilise l'exécution dans le désordre ou pas. Ils sont liés à la présence de dépendances de données, aux contraintes d’appariement, etc. Elles tendent à réduire la moyenne du nombre de µops émises par cycle. Par contre, ce sont les cycles de rattrapage, où les ports en surplus sont utilisés, qui font remonter la moyenne. Le gain en performance est donc lié à ces cycles de rattrapage, où les µops accumulées sont émises dans les ports en surplus. Et ils n'existent que sur les processeurs avec une file/fenêtre d'instruction. Réduire le nombre de ports d'émission permet de garder des fenêtres d'instruction et un ROB simples, rapides et économes en énergie. Et mine de rien, c'est là un compromis important : à quoi bon augmenter le nombre de ports d'émission si c'est pour que ce soit compensé par une fréquence plus faible ? Par contre, réduire le nombre de ports augmente la ''port contention'', surtout si on a mal réparti les ALU. Il faut donc trouver un compromis entre réduire le nombre de ports d'émission d'un côté, réduire la ''port contention'' de l'autre. La différence entre largeur de décodage et d'émission a un impact assez fort sur le banc de registre, et précisément sur son nombre de ports de lecture. Le banc de registre a besoin de plus de ports de lecture avec une fenêtre d’instruction qu'avec des stations de réservation. Rappelons la terminologie utilisée dans ce cours. Les fenêtres d'instruction se contentent de mémoriser la micro-opération et quelques bits pour détecter la disponibilité des opérandes. Par contre, les stations de réservations mémorisent aussi les opérandes des instructions. Et cette différence a une influence le nombre de ports de lecture du banc de registre. Supposons que toutes les instructions sont dyadiques, à deux opérandes. Comptons le nombre de ports nécessaires pour alimenter les unités de calcul, sans utiliser d'arbitre de banc de registre. Avec une fenêtre d'instruction, il faut le double du nombre de ports d'émission. Mais avec des stations de réservation, il faut le double des ports de décodage. La raison est que les registres sont lus après émission avec une fenêtre d'instruction, avant avec des stations de réservation (sous-entendu, après le décodage). Or, comme dit plus haut, les processeurs superscalaires larges ont souvent plus de ports d'émission que de décodage. ===La superscalarité à fenêtres d'instruction décentralisées=== Les processeurs précédents utilisaient une unité d'émission simple, qui pouvait utiliser l'émission dans l'ordre ou dans le désordre. Elle peut être remplacée par une fenêtre d'instruction centralisée dans que cela quoi que ce soit aux explications précédentes, idem avec une station de réservation centralisée. En soi, l'exécution dans le désordre est donc totalement compatible avec une implémentation simple de la superscalarité. Par contre, des subtilités surviennent avec les fenêtres d'instruction décentralisées. Pour rappel, sur ces processeurs, les µops sont émises en deux phases. Une première phase de ''dispatch'' qui envoie les µops vers la fenêtre d'instruction adéquate, sans détecter les dépendances de données. La seconde phase de ''schedule'' gère les dépendances de données, elle met en attente les µops en attendant que l'unité soit disponible pour les exécuter, en attendant aussi que les opérandes soient disponibles. Et à ce petit jeu, il y a une différence entre le nombre de µops qui sont ''dispatch par cycle'' et celles qui sont ''schedule''. Dit autrement, la largeur d'émission est scindée en une '''largeur de ''dispatch''''' et une '''largeur de ''schedule''. Par exemple, prenons un processeur triple émission avec deux stations de réservation : une pour les µops entières/mémoire, et une autre pour les µops flottantes. L'unité d'émission peut ''dispatch'' maximum trois µops par cycle : soit trois µops entières/mémoire, soit trois flottantes, soit un mix de trois µops différentes. Les stations de réservation, quant à elles, peuvent chacune ''schedule'' 3 µops par cycle, vers trois ALUs entières pour la station de réservation entière/mémoire, vers trois FPS pour la station de réservation flottante. De quoi ''dispatch'' trois µops, mais d'en ''schedule'' six, à chaque cycle. Et cet exemple ne sort pas de nulle part : les CPU x86 d'Intel et AMD sont globalement dans ce cas, même si les chiffres varient d'une microarchitecture à l'autre. L'exemple précédent colle parfaitement à la microarchitecture K7 d'AMD, utilisée sur les processeurs Athlon dans les années 2000. [[File:AMD K7.png|centre|vignette|upright=2.5|AMD K7, microarchitecture.]] L'exemple précédent avait assez d'unités entières/flottantes pour couvrir toute la largeur de décodage/''Dispatch''. Mais ce n'est pas toujours le cas, comme va le montrer l'exemple suivant. Le MIPS R10000, qui utilisait un mélange de files de µops et de fenêtres d'instructions : une file de µops les accès mémoire, une fenêtre pour les instructions entières et une autre pour les opérations flottantes. Les branchements et NOPs étaient exécutés dans une unité de branchement distincte. Les trois files/fenêtres peuvent mémoriser 16 µops. Le processeur avait deux ALU entières, une AGU de calcul d'adresse, un additionneur flottant et un multiplieur/diviseur flottant. Il y avait un multiplieur entier sur le port d'émission l'ALU 2. Le processeur décodait 4 instructions par cycle et produisait jusqu'à 4µops, qui étaient redistribuées sur les trois fenêtres d'instructions. Chacune pouvait accepter 4 µops par cycle, ce qui fait que processeur pouvait ''dispatch'' 4 µops entières, ou 4 µops flottantes, ou 4 µops mémoire, ou un mélange de deux ou trois types de µops. Pour ce qui est du ''schedule'', la fenêtre d'instruction entière pouvait émettre 2 µops, la fenêtre flottante pouvait émettre une addition en même temps qu'une multiplication/divison flottante et qu'un branchement conditionnel flottant, et la file de µops mémoire ne pouvait émettre qu'une µop mémoire à la fois. En tout, cela fait 6 µops ''schedule'' pour 4 µops au ''dispatch''. [[File:R 10000.png|centre|vignette|upright=2.5|MIPS R10000, microarchitecture.]] ===La superscalarité à fenêtres d'instruction totalement décentralisées=== Prenons un cas extrême de fenêtre d'instruction décentralisée : celui où chaque ALU entière a sa propre station de réservation. En clair : une fenêtre d'instruction par ALU/FPU ! On parle de '''fenêtres d'instruction totalement décentralisées'''. Vous vous dites que ce cas est un peu trop extrême pour être réaliste, mais il n'en est rien. C'est même très courant sur les architectures basse consommation, et sur pas mal de CPU x86 modernes. Une telle organisation entraine une légère perte de performance, comparé à une fenêtre d'instruction centralisée ou partiellement décentralisée. Et cela peut se comprendre par un exemple. Imaginez un processeur avec deux ALU, donc deux stations de réservation. Il arrivera qu'une station de réservation ait plusieurs µops prêtes, alors que l'autre en ait zéro. Dans une telle situation, une seule µop sera émise au cycle suivant, vu que chaque station de réservation a un seul port d'émission vers une seule ALU entière. Par contre, avec une fenêtre d'instruction centralisée double port, on aurait pu émettre les deux µops en même temps sur deux ALUs séparées. La perte de performance est donc liée au fait que les µops '''''prêtes''''' sont mal réparties dans les différentes stations de réservation. Il arrivera que des µops prêtes s'accumulent dans une station de réservation, alors que d'autres seront pleines, ou du moins sous-utilisées. Et ce n'est pas quelque chose qui peut être réglé à l'étape de ''dispatch'', car on ne sait pas encore quand les µops auront leurs opérandes de disponibles. [[File:Comparaison entre une station de réservation totalement décentralisée et une autre qui ne l'est pas.png|centre|vignette|upright=2.5|Comparaison entre une station de réservation totalement décentralisée et une autre qui ne l'est pas.]] Par contre, décentraliser totalement les fenêtres d'instruction entraine aussi un gain considérable en termes de consommation énergétique. Et c'est la raison pour laquelle les fenêtres d'instructions totalement décentralisées sont utilisées sur les architectures basse consommation. La perte de performance ne peut pas s'expliquer clairement à ce stade du cours, car il nous faudrait parler d'émission superscalaire. Le gain en matière d'énergie vient de l'économie de circuits, qui est assez drastique. Le gain en matière d'énergie vient de l'économie de circuits, qui est assez drastique. Je rappelle qu'une station de réservation a besoin, pour N instructions, d'environ N^2 circuits (des comparateurs, notamment). Prenons une station de réservation centralisée de 64 entrées et comparons avec 8 stations de 8 entrées chacune. Les deux donneront 64 entrées, mais la première aura un cout en circuit proportionnel à 64², alors que le second aura un cout en circuit de 8 *(8²). Entre les deux, le choix est clair : la seconde solution est plus économe. D'où l'utilisation de cette solution sur les microarchitectures basse consommation. ===L'unité de renommage superscalaire=== Avec la superscalarité, l'unité de renommage de registre doit gérer le cas où des instructions consécutives ont des dépendances de registre. Par exemple, prenons un processeur à double émission, qui renomme deux instructions consécutives. Si elles ont une dépendance de registre, le renommage de la seconde instruction dépend du renommage de la première. La première doit être renommée et le résultat du renommage est utilisé pour renommer la seconde, ce qui empêche d'utiliser deux unités de renommage séparées. Pour cela, elle renomme les registres sans tenir compte des dépendances, pour ensuite corriger le résultat. [[File:Unité de renommage superscalaire.png|centre|vignette|upright=2|Unité de renommage superscalaire.]] Seules les dépendances lecture-après-écriture doivent être détectées, les autres étant supprimées par le renommage de registres. Repérer ce genre de dépendances se fait assez simplement : il suffit de regarder si un registre de destination d'une instruction est un opérande d'une instruction suivante. [[File:Détection des dépendances sur un processeur superscalaire.png|centre|vignette|upright=2|Détection des dépendances sur un processeur superscalaire.]] Ensuite, il faut corriger le résultat du renommage en fonction des dépendances. Si une instruction n'a pas de dépendance avec une autre, on la laisse telle quelle. Dans le cas contraire, un registre opérande sera identique avec le registre de destination d'une instruction précédente. Dans ce cas, le registre opérande n'est pas le bon après renommage : on doit le remplacer par le registre de destination de l'instruction avec laquelle il y a dépendance. Cela se fait simplement en utilisant un multiplexeur dont les entrées sont reliées à l'unité de détection des dépendances. On doit faire ce replacement pour chaque registre opérande. [[File:Correction des dépendances sur un processeur superscalaire.png|centre|vignette|upright=2|Correction des dépendances sur un processeur superscalaire.]] ==Les optimisations des processeurs superscalaires larges== Les processeurs superscalaires larges ont des optimisations spécifiques, qui n'ont pas de sens sur les processeurs superscalaires étroits. Dans les grandes lignes, elles se classent en deux types. Les premières permettent de charger/décoder plus de 5-10 instructions simultanément. Le problème est alors que les branchements viennent mettre leur grain de sel et qu'il faut en tenir compte. Les secondes corrigent des problèmes qui apparaissent quand un CPU intègre plus de 5 à 10 unités de calcul. ===L'étape de chargement d'un CPU superscalaire large=== Charger plusieurs instructions pose de nombreux problèmes sur les processeurs superscalaires larges, qui émettent de 5 à 10 instructions simultanées. Pour rappel, la stratégie basique pour charger N instructions est de charger un bloc de N instructions consécutives. Les instructions après un branchement ne sont pas décodées ni exécutées, ce qui entraine une petite baisse de performance. Pour un N petit, la perte de performance est mineure. Mais pour un N large, elle devient suffisamment importante pour que la conception du CPU doit alors être repensée de fond en comble. Les analyses statistiques disent qu'il y a environ un branchement tous les 4 à 6 instructions. Un CPU a donc tendance à décoder des paquets de 3 à 5 instructions consécutives, avant qu'un branchement casse la dynamique. Or, cela pose des problèmes pour utiliser plusieurs décodeurs. L'implémentation basique, qui charge N instructions consécutives pour alimenter N décodeurs, fonctionne donc jusqu'à 4/6 décodeurs. Au-delà de 5 instructions, un CPU superscalaire doit être adapté pour gérer les branchements dans les paquets d'instruction qu'il émet. Le nombre de 5 instructions ne sort donc pas de nulle part. La première solution utilise un cache de µops, avec un ''front-end'' capable de charger/décoder 4/5 instructions à la fois, pas plus. L'idée est que la majorité des instructions proviennent du cache de µops (plus de 80%), ce qui fait qu'on peut émettre environ 10 instructions à partir du cache de µops, pas besoin d'avoir beaucoup de décodeurs. Les performances sont cependant dégradées lors d'un défaut de cache de µops. Les instructions doivent alors être chargées depuis le cache d'instruction, par paquets de 4-5, puis sont décodées par 4-5 décodeurs, ce qui ne permet pas d’alimenter les unités de calcul à plein régime. La solution précédente joue sur la distinction entre pots de décodage et d'émission. Elle permet d'émettre un grand nombre de µops sans pour autant charger un grand nombre d'instructions en même temps. En quelque sorte, ce n'est qu'une méthode de contournement, le CPU superscalaire reste de type étroit. Mais il est aussi possible d'utiliser un '''''front-end large''''', capable de charger une bonne dizaine d'instructions en même temps. La seule difficulté est de tenir compte de la présence de branchements. Pour rappel, avec un ''front-end'' étroit, les instructions situées après le premier branchement pris sont annulées, elles ne sont pas décodées ni exécutées. [[File:Fetch sur un processeur superscalaire avec prediction de branchements.png|centre|vignette|upright=2|Fetch sur un processeur superscalaire avec prédiction de branchements.]] Un ''front-end'' large charge les instructions de destination du branchement et les placent à sa suite. Ils chargent deux blocs à la fois et les fusionnent en un seul qui ne contient que les instructions présumées utiles. [[File:Cache d'instructions autoaligné.png|centre|vignette|upright=2|Cache d'instructions auto-aligné.]] Mais cela demande de charger deux blocs de mémoire en une fois, ce qui demande un cache d'instruction multiports. Il faut aussi ajouter un circuit pour assembler plusieurs morceaux de blocs en un seul : le fusionneur (''merger''). En pratique, cette solution demande d'ajouter un second port de lecture au cache, pour un cout en hardware important, avec un impact négatif sur le temps d'accès au cache. Et il faut rajouter le fusionneur, qui prend un étage de pipeline à lui tout seul. Et encore, cette solution ne gère pas le cas où un bloc contient plusieurs branchements ! [[File:Implémentation d'un cache d'instructions autoaligné.png|centre|vignette|upright=2|Implémentation d'un cache d'instructions auto-aligné.]] Les exemples précédents partent du principe qu'il n'y a qu'un seul branchement dans un bloc. Mais quand les blocs deviennent assez longs, il est fréquent d'avoir plusieurs branchements dans un bloc. Et il est même possible d'avoir plusieurs branchements pris. Dans un bloc de 8-10 instructions, ce n'est pas rare, et les CPU superscalaires à 8-10 voies sont la règle dans les CPU des années 2020. Pour gérer ce cas, il faut ajouter des ports supplémentaires au cache d'instruction et adapter le fusionneur, pour qu'il puisse fusionner trois ou quatre blocs. De plus, il faut utiliser une unité de prédiction de branchement capable de ''prédire plusieurs branchements par cycle''. ===Le décodage superscalaire large=== Le décodage des instructions n'est pas censé dépendre de l'implémentation du chargement. En théorie, une fois plusieurs blocs d'instruction fusionnés, on peut décoder les instructions en parallèle. Cependant, certains processeurs effectuent le décodage en tenant compte de la manière dont les branchements découpent les blocs. Les processeurs Atom d'Intel utilisent une solution de ce type, qui couple prédiction de branchement et décodage parallèle. Ils chargent/décodent des paquets de 3 instructions consécutives, chaque paquet étant séparé du précédent par un branchement. Pour cela, en plus d'avoir un fusionneur adapté, ils regroupent les décodeurs en ''clusters'', chacun regroupant 3 décodeurs, et pouvant décoder trois instructions consécutives. Les micro-architectures Tremont et Crestmont avaient deux ''clusters'' (6 décodeurs au total), la micro-architecture Darkmont en intègre trois (9 décodeurs au total). Avec deux ''clusters'', le fonctionnement est le suivant. Si le code est composé d'une suite d'instruction sans branchements, seul le premier ''cluster'' est utilisé, limitant le décodage à trois instructions par cycle. Par contre, si l'une des trois instructions décodée est un branchement, alors le second ''cluster'' décode les trois instructions situées après ce branchement, à partir de l'adresse de destination. Avec un troisième ''cluster'', c'est la même chose, sauf qu'il faut qu'il y ait un branchement dans les trois instructions décodées par le second ''cluster''. Mais comment faire pour savoir quels décodeurs activés, quels ''clusters'' sont actifs ? C'est la prédiction de branchement qui commande. Avec deux ''clusters'', elle détermine si un branchement est présent dans les trois instructions à charger, et quelle est son adresse de destination. Sans branchement, elle prévient les décodeurs et les trois instructions chargées sont décodées dans un ''cluster'' libre. Si elle prédit un branchement, elle charge les instructions adéquates, et active les deux ''clusters''. Avec trois branchements, c'est le même mécanisme, sauf que l'unité de prédiction de branchement doit être capable de prédire deux branchements par cycle. [[File:Front-end découplé de la microarchitecture Tremont.png|centre|vignette|upright=3|Front-end découplé de la microarchitecture Tremont.]] Il faut noter que les décodeurs d'un ''cluster'' sont des décodeurs simples, sans microcode. Sur les processeurs Tremont et Crestmont, le microcode était unique et était partagé entre tous les ''clusters''. Un seul ''cluster'' pouvait décoder une instruction complexe avec le microcode, l'autre devait se limiter à des instructions simples uniquement. Depuis Skymont, le microcode est partiellement dupliqué, avec un microcode par ''cluster''. Le cout en hardware peut paraitre prohibitif, pour un gain en performance faible. Sauf que c'est oublier que ce sont des processeurs Atom, sur lesquels beaucoup d'instructions sont microcodées. Les processeurs Atom ont un budget en transistor limité, ce qui fait qu'il est préférable pour eux d'implémenter des instructions en microcode que d'utiliser des unités de calcul dédiées ou des circuits de décodage complexes. Pour limiter la casse, le microcode n'est que partiellement dupliqué. Seul le microcode pour les instructions fréquente est dupliqué. Il y a un microcode secondaire pour certaines instructions, qui est lui unique et partagé par tous les ''clusters''. ===Le contournement sur les processeurs superscalaires larges=== Pour rappel, la technique du contournement (''register bypass'') permet au résultat d'une instruction d'être immédiatement utilisable en sortie de l'ALU, avant même d'être enregistré dans les registres. Implémenter la technique du contournement demande d'utiliser des multiplexeurs pour relier la sortie de l'unité de calcul sur son entrée si besoin. Il faut aussi des comparateurs pour détecter des dépendances de données. [[File:Pipeline Bypass.png|centre|vignette|upright=1|Pipeline Bypass]] La sortie de chaque ALU doit être reliée aux entrées de toutes les autres, avec les comparateurs qui vont avec. Sur les processeurs ayant plusieurs d'unités de calculs, cela demande beaucoup d’interconnexions et de comparateurs. Pour N unités de calcul, cela demande 2 * N² interconnexions, implémentées avec 2N multiplexeurs de N entrées chacun. Si c'est faisable pour 2 ou 3 ALUs, la solution est impraticable au-delà. Non seulement ce serait un enfer à câbler, mais les fils seraient tellement longs que la fréquence du processeur en prendrait un coup. Notez que cela vaut pour les processeurs superscalaires, mais aussi pour tout processeur avec beaucoup d'unités de calcul. En théorie, un CPU à exécution dans le désordre, non-superscalaire, mais avec beaucoup d'unités de calcul, fait face au même problème. En pratique, avoir une dizaine d'ALU implique processeur superscalaire à exécution dans le désordre. D'où le fait qu'on parle du problème maintenant. La seule solution praticable est de ne pas relier toutes les unités de calcul ensemble. À la place, on préfère regrouper les unités de calcul dans différents '''agglomérats''' ('''cluster'''). Le contournement est alors possible entre les unités d'un même agglomérat, mais pas entre agglomérats différents. Évidemment, certaines possibilités de contournement sont perdues, mais c'est compensé par un gain en fréquence et un cout en circuit/fils réduit. C'est un bon compromis, ce qui explique que presque tous les processeurs modernes l'utilisent. Les rares exceptions sont les processeurs POWER 4 et POWER 5, qui ont préféré se passer de contournement pour garder un processeur très simple et une fréquence élevée. ===Le banc de registre des processeurs superscalaires larges=== Pour émettre deux opérations entières simultanément, il faut lire deux fois plus d'opérandes. Et il faut aussi écrire deux résultats dans les registres, en même temps. Pour cela, on double les ports du banc de registre. En général, il faut au maximum 2 ports de lecture et un port d'écriture par unité de calcul. Le problème, c'est que plus un banc de registres a de ports, plus il utilise de circuits, est compliqué à concevoir, consomme de courant et chauffe. Avec plusieurs dizaines d'unités de calcul différentes, ajouter autant de ports impacterait la fréquence du banc de registres et réduirait les performances, voire est totalement impraticable à cause des contraintes thermiques. Les processeurs superscalaires larges doivent donc trouver des solutions. La première solution utilise un banc de registre unique, mais n'utilise pas autant de ports que le pire des cas le demanderait. Le processeur détecte quand il n'y a pas assez de ports pour servir toutes les micro-opérations. Quand ça arrive, l'unité d'émission émet assez de micro-opérations pour exploiter les ports disponibles, mais met en attente les micro-opérations en trop, le temps que les ports se libèrent. Pour cela, le banc de registre est géré par un circuit d'arbitrage spécialisé, intégré à l'unité d'émission, l’'''arbitre du banc de registres''' (''register file arbiter''). Une autre solution est de dupliquer le banc de registres en plusieurs exemplaires qui contiennent exactement les mêmes données, mais avec moins de ports de lecture/écriture. Un exemple est celui des processeurs POWER, Alpha 21264 et Alpha 21464. Sur ces processeurs, le banc de registre est dupliqué en plusieurs exemplaires, qui contiennent exactement les mêmes données. Les écritures dans les registres sont envoyées à tous les bancs de registres, afin de garantir que leur contenu est identique. Chaque exemplaire a exactement deux ports de lecture. La conception du processeur est simplifiée, que ce soit au niveau du câblage, que de la conception des bancs de registres. Une dernière solution découpe le banc de registres en plusieurs bancs de registres plus petits, avec un réseau d'interconnexions pour échanger des données entre bancs de registres. Dans la plupart des cas, cette séparation est invisible du point de vue de l'assembleur et du langage machine. Le processeur se charge de transférer les données entre bancs de registres suivant les besoins. Sur d'autres processeurs, les transferts de données se font via une instruction spéciale, souvent appelée ''COPY''. [[File:Banc de registres distribué.png|centre|vignette|upright=2|Banc de registres distribué.]] Sur de certains processeurs, un branchement est exécuté par une unité de calcul spécialisée. Or les registres à lire pour déterminer l'adresse de destination du branchement ne sont pas forcément dans le même agglomérat que cette unité de calcul. Pour éviter cela, certains processeurs disposent d'une unité de calcul des branchements dans chaque agglomérat. Dans les cas où plusieurs unités veulent modifier le ''program counter'' en même temps, un système de contrôle général décide quelle unité a la priorité sur les autres. Mais d'autres processeurs fonctionnent autrement : seul un agglomérat possède une unité de branchement, qui peut recevoir des résultats de tests de toutes les autres unités de calcul, quel que soit l’agglomérat. ==La macro-fusion : une optimisation du décodage parallèle== Les processeurs superscalaires supportent la technique dite de '''macro-fusion''', qui permet de fusionner deux-trois instructions consécutives en une seule micro-opération. Par exemple, il est possible fusionner une instruction de test et une instruction de saut en une seule micro-opération de branchement. Il s'agit là de l'utilisation la plus importante de la macro-fusion sur les processeurs x86 modernes. La macro-fusion est utilisée pour fusionner un test et un saut en un branchement unique. L'optimisation est présente sur la plupart des CPU superscalaires modernes. Les CPU x86 l'implémentent, mais aussi quelques CPU ARM et les processeurs Apple de série M (M1 à M5, et potentiellement plus quand ils seront sortis). La fusion des instructions se fait lors du décodage des instructions, grâce à la coopération des décodeurs. Elle marche systématiquement si l'instruction de test et le saut sont consécutives, qu'elles forment bien une paire d'instruction. Par contre, insérer une instruction entre les deux empêche la macro-fusion de faire son travail, sauf si l'instruction insérée est un NOP. Les processeurs ARM64 avaient une forme spécifique de macro-fusion, utilisée pour un cas très précis : charger une constante immédiate de 32 ou 64 bits, dans un registre 64 bits. Les CPU ARM 64 bits utilisent des instructions codées sur 32 bits, qui ne peuvent encoder que des constantes immédiates de 16 bits. Pour charger une constante de 32/64 bits, il faut s'y prendre en plusieurs fois. Une première instruction MOVZ charge les 16 premiers bits, puis 2 à 4 instructions MOVK remplissent le reste. MOVZ met à zéro les 48 bits de poids fort, MOVK permet de sélectionner le doublet à modifier dans le registre (on modifie 16 bits, dont on choisit la place, le reste du registre est laissé tel quel). ARM permet de fusionner cette suite d'instructions en une seule µop MOV avec une constante immédiate. On parle alors de '''''MOVZ + MOVK fusion'''''. Une dernière utilisation, [https://www2.eecs.berkeley.edu/Pubs/TechRpts/2016/EECS-2016-130.pdf proposées pour le jeu d'instruction RISC-V], fusionnait un calcul d'adresse et une instruction LOAD/STORE en une seule instruction d'accès mémoire. Elle a été envisagée à une époque où le jeu d'instruction RISC-V ne gérait pas les modes d'adressage base + indice. L'idée était d'avoir une unité mémoire qui gérait le mode d'adressage base + indice et de fusionner des instructions pour l'exploiter. Mais de nos jours, le jeu d'instruction RISC-V intègre le mode d'adressage base + indice, ce qui fait que la macro-fusion n'a aucun intérêt pour ce cas précis. La macro-fusion a de nombreuses limitations en pratique. En théorie, on pourrait l'utiliser au-delà des deux situations mentionnées plus haut. Par exemple, pour fusionner une addition et une multiplication en une seule instruction MAD. Mais l'intérêt est assez faible. Notons que la macro-fusion ne permet que de fusionner des paires d'instructions. Aller au-delà demanderait un cout en circuit trop important. Déjà que tester deux paires utilise pas mal de comparateurs... ==Le ''stack engine'' : une optimisation de la pile d'appel== Les processeurs modernes intègrent une optimisation liée au pointeur de pile. Pour rappel, sur les architectures modernes, le pointeur de pile est un registre utilisé pour gérer la pile d'appel, précisément pour savoir où se trouve le sommet de la pile. Il est manipulé par les instructions CALL, RET, PUSH et POP, mais aussi par les instructions d'addition/soustraction pour gérer des cadres de pile de taille variable. De plus, il peut servir d'opérande pour des instructions LOAD/STORE, afin de lire/écrire des variables locales, les arguments d'une fonction, et autres. C'est donc un registre général adressable, intégré au banc de registre, altéré par l'unité de calcul entière. L'incrémentation/décrémentation du pointeur de pile passe donc par l'unité de calcul, lors des instructions CALL, RET, PUSH et POP. Mais, l'optimisation que nous allons voir permet d'incrémenter/décrémenter le pointeur de pile sans passer par l'ALU, ou presque. L'idée est de s'inspirer des architectures avec une pile d'adresse de retour, qui intègrent le pointeur de pile dans le séquenceur et l'incrémentent avec un incrémenteur dédié. ===Le ''stack engine''=== L'optimisation que nous allons voir utilise un '''''stack engine''''' intégré à l'unité de contrôle, au séquenceur. Le processeur contient toujours un pointeur de pile dans le banc de registre, cela ne change pas. Par contre, il n'est pas incrémenté/décrémenté à chaque instruction CALL, RET, PUSH, POP. Un compteur intégré au séquenceur est incrémenté à la place, nous l’appellerons le '''compteur delta'''. La vraie valeur du pointeur de pile s'obtient en additionnant le compteur delta avec le registre dans le banc de registre. Précisons que si le compteur delta vaut zéro, la vraie valeur est dans le banc de registre et peut s'utiliser telle quelle. Lorsqu'une instruction ADD/SUB/LOAD/STORE utilise le pointeur de pile comme opérande, elle a besoin de la vraie valeur. Si elle n'est pas dans le banc de registre, le séquenceur déclenche l'addition compteur-registre pour calculer la vraie valeur. Finalement, le banc de registre contient alors la bonne valeur et l'instruction peut s'exécuter sans encombre. L'idée est que le pointeur de pile est généralement altéré par une série d'instruction PUSH/POP consécutives, puis des instructions LOAD/STORE/ADD/SUB utilisent le pointeur de pile final comme opérande. En clair, une bonne partie des incrémentations/décrémentation est accumulée dans le compteur delta, puis la vraie valeur est calculée une fois pour toutes et est utilisée comme opérande. On accumule un delta dans le compteur delta, et ce compteur delta est additionné quand nécessaire. Précisons que le compteur delta est placé juste après le décodeur d'instruction, avant même le cache de micro-opération, l'unité de renommage et l'unité d'émission. Ainsi, les incrémentations/décrémentations du pointeur de pile disparaissent dès l'unité de décodage. Elles ne prennent pas de place dans le cache de micro-opération, ni dans la fenêtre d'instruction, ni dans la suite du pipeline. De nombreuses ressources sont économisées dans le ''front-end''. Mais utiliser un ''stack engine'' a aussi de nombreux avantages au niveau du chemin de données/''back-end''. Déjà, sur les processeurs à exécution dans le désordre, cela libère une unité de calcul qui peut être utilisée pour faire d'autres calculs. Ensuite, le compteur delta mémorise un delta assez court, de 8 bits sur le processeur Pentium M, un peu plus pour les suivants. L'incrémentation se fait donc via un incrémenteur 8 bits, pas une grosse ALU 32/64 bits. Il y a un gain en termes de consommation d'énergie, un incrémenteur 8 bits étant moins gourmand qu'une grosse ALU 32/64 bits. ===Les points de synchronisation du delta=== La technique ne fonctionne que si la vraie valeur du pointeur de pile est calculée au bon moment, avant chaque utilisation pertinente. Il y a donc des '''points de synchronisation''' qui forcent le calcul de la vraie valeur. Plus haut, nous avions dit que c'était à chaque fois qu'une instruction adresse le pointeur de pile explicitement, qui l'utilise comme opérande. Les instructions CALL, RET, PUSH et POP ne sont pas concernées par elles utilisent le pointeur de pile de manière implicite et ne font que l'incrémenter/décrémenter. Mais dans les faits, c'est plus compliqué. D'autres situations peuvent forcer une synchronisation, notamment un débordement du compteur delta. Le compteur delta est généralement un compteur de 8 bits, ce qui fait qu'il peut déborder. En cas de débordement du compteur, le séquenceur déclenche le calcul de la vraie valeur, puis réinitialise le compteur delta. La vraie valeur est donc calculée en avance dans ce cas précis. Précisons qu'un compteur delta de 8 bits permet de gérer environ 30 instructions PUSH/POP consécutives, ce qui rend les débordements de compteur delta assez peu fréquent. À noter que si le compteur delta vaut zéro, il n'y a pas besoin de calculer la vraie valeur, le séquenceur prend cette situation en compte. Un autre point de synchronisation est celui des interruptions et exceptions matérielles. Il faut que le compteur delta soit sauvegardé lors d'une interruption et restauré quand elle se termine. Idem lors d'une commutation de contexte, quand on passe d'un programme à un autre. Pour cela, le processeur peut déclencher le calcul de la vraie valeur lors d'une interruption, avant de sauvegarder les registres. Pour cela, le processeur intègre un mécanisme de sauvegarde automatique, qui mémorise la valeur de ce compteur dans le tampon de réordonnancement, pour forcer le calcul de la vraie valeur en cas de problème. La technique du ''stack engine'' est apparue sur les processeurs Pentium M d'Intel et les processeurs K10 d'AMD, et a été conservée sur tous les modèles ultérieurs. L'implémentation est cependant différente selon les processeurs, bien qu'on n'en connaisse pas les détails et que l'on doive se contenter des résultats de micro-benchmarks et des détails fournit par Intel et AMD. Selon certaines sources, dont les manuels d'optimisation d'Agner Fog, les processeurs AMD auraient moins de points de synchronisation que les processeurs Intel. De plus, leur ''stack engine'' serait placé plus loin que prévu dans le pipeline, après la file de micro-opération. ==La micro-fusion et la délamination== La '''micro-fusion''' est une optimisation qui retarde le décodage réel de certaines instructions assez loin dans le pipeline. Elle concerne surtout les instructions ''load-op'', mais pas que. D'autres instructions mémoire peuvent subir cette optimisation. L'essentiel est que, sans micro-fusion, ces instructions sont décodées en plusieurs micro-opérations. La micro-fusion retarde le décodage final de ces instructions, qui se fait assez tard dans le pipeline. Pour comprendre l'intérêt, nous allons devoir faire quelques explications. L'optimisation en question fait le décodage en deux temps. Prenons l'exemple d'une opération ''load-op'', qui est censée être décodée en deux micro-opérations : une lecture, puis une opération. Le décodage produit une '''macro-opération''' (terme d'Intel), qui est propagée dans le pipeline, pour être scindée en deux micro-opérations un peu avant les ALU et l'unité mémoire. La macro-opération est techniquement une micro-opération comme une autre, sauf que ce n'est pas la micro-opération finale. L'unité d'émission découpe cette macro-opération en deux micro-opérations, qui sont émises l'une après l'autre. Pour résumer, les instructions ''load-op'' ne sont complétement découpées en micro-opération lors de l'émission, pas lors du décodage. L'optimisation impacte ce qui se situe entre le décodeur d'instruction et l'unité d'émission : l'unité de renommage, la file de micro-opérations, le ''Loop Stream Detector'' et/ou le cache de micro-opération. L'intérêt de l'optimisation est que l'on fusionne deux micro-opérations en une seule macro-opération. Le cache de micro-opération et la file de micro-opération peuvent mémoriser plus de micro-opérations, vu que certaines sont fusionnées. Quant à l'unité de renommage, elle renomme une seule macro-opération au lieu de renommer deux micro-opérations, ce qui augmente le débit du renommage de registre. Par contre, cela complique un peu le travail de l'unité d'émission, qui doit découper les instructions ''load-op'' en deux et émettre les micro-opérations l'une après l'autre. Il faut noter qu'il n'y a pas de fusion proprement dite. Le décodeur ne décode pas deux micro-opérations séparées, avant de les fusionner. En réalité, il génère directement une macro-opération, qui correspond à deux micro-opérations, que ce soit plus tard dans le pipeline ou sur une autre architecture. D'ailleurs, la micro-fusion a lieu à l'intérieur d'une instruction, qui est censée être traduite en plusieurs micro-opérations. Et encore : pas toutes. La conséquence est que la technique n'a de sens que sur les processeurs CISC, avec des instructions assez complexes pour être décodées en plusieurs micro-opérations. En pratique, seuls les CPU x86 sont concernés. ===Les domaines de fusion=== La micro-fusion n'est pas spécifique aux processeurs superscalaires. En théorie, on peut l'implémenter sur un processeur non-superscalaire à émission dans l'ordre. Cependant, je ne connais aucun processeur à émission dans l'ordre qui implémente la micro-fusion, même si son implémentation est en théorie possible sur de tels processeurs. La micro-fusion est implémentée différemment selon que l'émission se fasse dans l'ordre, dans le désordre, avec une fenêtre d'instruction, avec des stations de réservation, etc. J'ai dit plus haut que les micro-opérations sont générées lors de l'émission, mais le moment exact varie suivant le processeur. Pour simplifier le tout, nous parlerons de '''scission''' quand le processeur traduit une macro-opération en deux/trois micro-opérations. Le moment où a lieu la scission est théoriquement dans l'unité d'émission, mais celle-ci prend plusieurs formes selon que le processeur utilise l'émission dans l'ordre, dans le désordre, avec une fenêtre d'instruction, avec des stations de réservation, etc. Les processeurs à exécution dans l'ordre sont le cas le plus simple. L'unité d'émission est alors en charge du découpage des macro-opérations en micro-opérations. La file de micro-opération ou le cache de micro-opérations mémorisent des macro-opérations. À l'opposé, le tampon de ré-ordonnancement mémorise lui des micro-opérations. Le reste du processeur n'est pas affecté. Sur les processeurs à exécution dans le désordre, les différences sont nombreuses. Le tampon de ré-ordonnancement peut mémoriser soit les micro-opérations finales, soit des macro-opérations. Il en est de même avec la fenêtre d'instruction et/ou les stations de réservation, qu'elles soient centralisées ou décentralisées. Tout dépend de comment se fait l'implémentation. Une implémentation simple effectue la scission des macro-opérations dans l'unité d'émission, comme sur les processeurs à exécution dans l'ordre. Sur de nombreux processeurs, l'unité d'émission et de renommage sont simplement fusionnées, ce qui fait que la scission a lieu juste après le renommage de registres. En conséquence, le tampon de re-ordonnancement et les fenêtres d'instruction ne voient que des micro-opérations. Les macro-opérations disparaissent juste avant. Cette implémentation est préférée avec une fenêtre d'instruction centralisée, car on voit mal comment scinder une macro-opération juste avant l'ALU. Une autre implémentation fait la scission en sortie de la fenêtre d'instruction ou des stations de réservation, qu'elles soient centralisées ou décentralisées. Dans ce cas, le tampon de re-ordonnancement fait de même. L'avantage est que le tampon de ré-ordonnancement stocke des macro-opérations, ce qui augmente sa taille effective. Par exemple, il utilise une seule entrée pour une instruction ''load-op'', au lieu de deux sans micro-fusion de ce type. ===La délamination=== La scission peut parfois avoir lieu plus tôt, dans des circonstances très précises. Concrètement, cela ne concerne que quelques micro-architectures d'Intel, pour des instructions très précises. La raison est les limitations du format des micro-opérations, pas une histoire d'optimisation. Le processeur aimerait pouvoir faire la micro-fusion, mais ne peut pas à cause de ces limitations. Une telle situation cause alors une '''délamination''' : les micro-opérations sont scindées précocement. Par exemple, sur la micro-architecture SandyBridge d'Intel, les opérations ''load-op'' sont fusionnées, sauf si elles utilisent l'adressage indicé. Les micro-opérations de ce processeur ne peuvent avoir que deux opérandes. Trois opérandes est de trop, et les opérations ''load-op'' en adressage indicé dépassent cette limite. Dans ce cas, les micro-opérations sont fusionnées en sortie du décodeur, mais sont scindés avant d’entrer dans la file de micro-opération. L'avantage n'est pas évident, vu que l'unité de renommage suit de près le décodeur d'instruction. Il est que le cache de micro-opérations mémorise des macro-opérations, pas deux micro-opérations. ===La micro-fusion des processeurs Intel et AMD=== La micro-fusion est apparue sur le Pentium M d'Intel, et a été conservée telle quelle sur les processeurs Intel suivants. Les processeurs AMD supportent la micro-fusion depuis au moins la micro-architecture AMD K8. Mieux que ça, la délamination n'était pas utilisée car les micro-opérations acceptaient plus de 2 opérandes. Que ce soit chez AMD ou Intel, elle concerne deux types d'instructions : les écritures mémoire et les instructions ''load-op''. Sur le Pentium M, il y avait quelques limitations, l'optimisation se limitant par exemple aux registres entiers et flottants, mais pas aux registres MMX, mais pas les registres SSE (nous verrons ces registres dans quelques chapitres). Mais les processeurs modernes n'ont plus cette limitation. La micro-fusion des CPU Intel concerne deux types d'instructions : les écritures mémoire et les instructions ''load-op''. Pour les écritures, la situation est plus complexe que pour les instructions ''load-op''. Sur les processeurs Intel précédents, les écritures étaient réalisées dans deux unités séparées : le calcul d'adresse dans une unité de calcul, l'écriture proprement dite dans l'unité mémoire. Elles prenaient donc deux micro-opérations. Le processeur a changé ses unités mémoire, ce qui fait qu'elle pouvait faire les deux en une seule micro-opération. Il s'agissait alors d'une optimisation du chemin de données, plus que de la micro-fusion proprement dite, mais je la mentionne ici malgré tout. La micro-fusion sur ce processeur avait un avantage en plus des avantages usuels : elle utilisait mieux les décodeurs. Les Pentium M avaient trois décodeurs pour décoder plusieurs instructions en même temps, chose qu'on détaillera dans le chapitre sur les processeurs superscalaires. Un seul décodeur pouvait décoder toutes les instructions, les deux autres ne peuvent décoder que les instructions simples, qui se décodent en une seule micro-opération. Avec la micro-fusion, les trois décodeurs peuvent gérer les écritures mémoire et les opérations ''load-op'', vu qu'elles deviennent des instructions simples. Sans cela, elles auraient été limitées au premier décodeur. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Le parallélisme mémoire | prevText=Le parallélisme mémoire | next=Les microarchitectures pour le x86 : haute performance | nextText=Les microarchitectures pour le x86 : haute performance }} </noinclude> 09ukyirvkxd3g5owmnflvyyrmvnui5w 773579 773578 2026-09-29T16:45:16Z Mewtow 31375 /* L'exemple du PA-RISC PA 8000 */ 773579 wikitext text/x-wiki Les processeurs vus auparavant ne peuvent émettre au maximum qu'une instruction par cycle d'horloge. Ils peuvent avoir plusieurs instructions qui s'exécutent en même temps, dans des unités de calcul séparées. C'est le cas dès qu'une instruction multi-cycles s'exécute. Par contre, ils ne peuvent démarrer qu'une seule instruction par cycle. Et quand on court après la performance, ce n'est pas assez ! Les concepteurs de processeurs ont inventés des processeurs qui émettent plusieurs instructions par cycle : les '''processeurs à émissions multiples'''. Un processeur à émission multiple charge plusieurs instructions en même temps, les décode en parallèle, puis les émet en même temps sur des unités de calculs séparées. Pour cela, il faut gérer les dépendances entre instructions, répartir les instructions sur différentes unités de calcul, et cela n'est pas une mince affaire. En général, pour un processeur à émission multiple capable d'émettre N instructions en parallèle, on parle de '''processeur à N voies''', ou encore un ''processeur à N pipelines''. [[File:Superscalarpipeline.svg|centre|vignette|upright=1.5|Pipeline RISC classique à cinq étages sur un processeur superscalaire. On voit bien que plusieurs instructions sont chargées en même temps.]] Les processeurs à émission multiple sont de deux types : les processeurs VLIW et les '''processeurs superscalaires'''. Nous mettons les processeurs VLIW de côté en attendant le prochain chapitre. La raison est qu'ils ont un jeu d'instruction spécialisé qui expose le parallélisme d'instruction directement au niveau du jeu d'instructions, là où les processeurs superscalaires restent des processeurs au jeu d'instruction normal. La différence principale entre processeur VLIW et superscalaire est qu'un processeur superscalaire répartit les instructions sur les unités de calcul à l’exécution, là où un processeur VLIW délègue cette tâche au compilateur. ==Le nombre de voies d'un processeur superscalaire== Les processeurs superscalaires les plus simples ne permettent que d'émettre deux micro-opérations à la fois, d'où leur nom de processeur ''dual issue'', ce qui se traduit en '''processeur à double émission'''. Les processeurs triple émission permettent eux d’émettre trois instructions à la fois. A l'opposé, les CPU superscalaires les plus puissants peuvent émettre jusqu'à 8-10 instructions simultanément. En 2026, les CPU superscalaires peuvent monter jusqu’à 10 µops émises en même temps, ce qui est énorme ! Et cela nous amène à faire une distinction entre les processeurs superscalaires dits '''étroits''' et ceux dits '''larges'''. Dans ce wikilivre, on part du principe que les processeurs superscalaires étroits émettent jusqu'à 4-5 µops à la fois, alors que les larges peuvent en émettre plus, l'intervalle entre les deux est une zone grise. Le nombre exact n'est pas fixé dans le marbre, la distinction est volontairement vague. Nous parlerons de la '''largeur d'un CPU superscalaire''' pour parler du nombre de voies, du nombre de µops émises en même temps. Plus un CPU superscalaire est large, plus il est performant ''toute chose égale par ailleurs''. Mais dans les faits, vous pouvez oublier la partie en italique. Élargir un CPU superscalaire demande de rajouter beaucoup de circuits. Et ce cout en circuit aura un impact sur la performance. A budget en transistors limité, il y a un compromis entre élargir un CPU et rajouter du cache ou la taille des fenêtres d'instructions/ROB et autres. ===Les contraintes d’appariement=== Prenons un processeur double émission, capable d'émettre deux instructions simultanément. Émettre deux instructions en même temps n'est pas toujours possible. Par exemple, si deux instructions sont dépendantes, on ne peut pas les émettre en même temps. Mais oublions un instant ces histoires de dépendances de données, et partons du principe que le CPU ait affaire à deux instructions indépendantes, une paire idéale. Un CPU double émission "parfait" pourrait exécuter n'importe quelle paire d'instruction. Par exemple, il pourrait émettre deux multiplications consécutives, deux lectures consécutives, une lecture et une écriture en même temps, etc. En pratique, aucun processeur ne permet cela. Implémenter un CPU superscalaire "parfait" aurait un cout en circuit beaucoup trop conséquent. Par exemple, pour émettre deux multiplications en même temps, il faudrait deux multiplieurs séparés. Idem pour exécuter deux accès mémoire simultané : cela demande d'avoir deux unités mémoire et un cache multiport. Mais en pratique, aucun CPU superscalaire ne fait cela. La totalité des CPU double émission se débrouille avec un seul circuit multiplieur et une seule unité mémoire. Et cela entraine l'apparition de dépendances structurelles, qui font que certaines paires d'instructions sont impossibles. Par exemple, impossible d'émettre deux multiplications en même temps avec un seul circuit multiplieur. Mais émettre une multiplication en parallèle d'une addition est parfaitement possible. Il y a donc des paires d'instructions autorisées et des paires interdites. Et la logique est la même sur les CPU à triple ou quadruple émission, et au-delà. : des triplets ou quadruplet d'instructions sont impossibles à émettre simultanément, alors que d'autres le sont. Pour le dire autrement, il y a des '''contraintes d'appariement''' sur les instructions à émettre en même temps. ===L'impact des contraintes d’appariement sur la performance=== Ces contraintes d’appariement ont un impact sur les performance, mais celui-ci peut être grandement mitigé. Les programmes informatiques utilisent en pratique beaucoup plus d'opérations entières de base que de multiplication, branchements et accès mémoire. Il y a environ 5 opérations entières de base pour une multiplication entière. En pratique, il est rare de devoir exécuter deux multiplications à la fois. Idem pour les décalages et rotations, qui sont assez éloignés les uns des autres. Deux branchements consécutifs sont quant à eux plus fréquents. Deux accès mémoire consécutifs est assez rare, mais ils restent assez proches les uns des autres malgré tout. La conséquence est que certaines paires d'instructions sont privilégiées par rapport au reste. Les paires regroupant deux calculs basiques (additions, soustractions, ...) sont systématiquement supportées, car dupliquer des ALU entières est facile. Les paires regroupant un calcul et une autre instruction sont elles aussi systématiquement supportées. Par contre, les paires avec deux branchements, deux accès mémoire, deux décalages/rotations, ou deux multiplications/divisions sont fréquemment interdites. Seuls les CPU superscalaires larges peuvent les permettre, et encore : sous conditions. Le résultat est que le processeur peut se débrouiller avec une seule unité mémoire et une unité de branchement. ===Terminologie pour la suite du chapitre=== Décrire les contraintes d’appariement demande de dire quelles combinaisons d’instructions sont autorisées ou interdites. Et pour cela, nous allons introduire les abréviations suivantes : * INT est un raccourcis pour parler d'une opération entière simple, qu'une ALU entière peut exécuter. * MUL correspond à une opération entière complexe, typiquement une multiplication, éventuellement à une division. * FLOAT désigne une opération flottante, peut importe laquelle. * MEM désigne un accès mémoire, à savoir une instruction ou µop mémoire. * BRANCH désigne une instruction de branchement. Cette terminologie permettra de définir des paires d'instructions, qu'elles soient possibles ou interdites. Par exemple, l'expression INT + FLOAT désigne une paire d'instruction regroupant une instruction entière et une instruction flottante, peu importe l'ordre des deux instructions. Il en sera de même pour les triplets, quadruplets, ou plus. Par exemple, l'expression INT + INT + FLOAT + MUL désigne un quadruplet d'instructions regroupant : deux instructions entières, une instruction flottante, et une multiplication entière. J'utiliserais aussi des parenthèses pour regrouper certaines combinaisons. Par exemple, l'expression INT + (MUL /FLOAT) veut parler d'une paire d'instruction où la première est une opération entière basique, la seconde est : soit une multiplication, soit une opération flottante. ==Le ''front-end'' des processeurs superscalaires== Un processeur superscalaire doit charger, décoder, et exécuter plusieurs instructions par cycle. Par exemple, un processeur triple émission doit charger 3 instructions lors d'un premier cycle, puis les décoder au cycle suivant, et les exécuter au cycle suivant. Il travaille donc pas paquets de 3 instructions, dans cet exemple. Intuitivement, charger, décoder et exécuter plusieurs instructions à la fois demande de dupliquer des circuits. Par exemple, il faut dupliquer les décodeurs pour décoder plusieurs instructions. Les unités de calcul sont aussi dupliquées, sauf sur certaines processeurs qui arrivent à ruser, mais laissons cela de côté pour plus tard. Mais d'autres circuits sont simplement modifiés, comme l'unité de chargement ou l'unité d'émission. Voyons ce qu'il en est dans le détail. {|class="wikitable" |- ! rowspan="2" | Processeur sans émission multiple | rowspan="2" | Chargement | rowspan="2" | Décodage | rowspan="2" | Renommage | rowspan="2" | Émission | Exécution / ALU | rowspan="2" | ''Commit''/ROB |- | Exécution / ALU |- ! rowspan="4" | Processeur superscalaire | rowspan="4" | Chargement | rowspan="2" | Décodage | rowspan="4" | Renommage | rowspan="4" | Émission | Exécution / ALU | rowspan="4" | ''Commit''/ROB |- | Exécution / ALU |- | rowspan="2" | Décodage | Exécution / ALU |- | Exécution / ALU |} Nous allons d'abord voir ce qu'il en est pour le ''front-end'', à savoir la partie du CPU qui s'occupe de charger et décoder les instructions. Elle regroupe l'unité de chargement, les décodeurs, l'unité de prédiction de branchement, la file de µops, la file d'instruction, et divers caches. En soi, les changements portent surtout sur l'unité de chargement et les décodeurs. ===Le chargement de plusieurs instructions consécutives=== Un processeur superscalaire charge plusieurs instructions en même temps, ''en tenant compte de la présence de branchements''. La partie en italique est importante et elle a une conséquence très forte : la manière de faire est fortement différente entre un CPU superscalaire étroit et large. Un CPU superscalaire étroit fait au plus simple : il charge un bloc de 2, 3, 4 instructions consécutives en mémoire RAM. Il faut alors doubler/tripler/quadrupler la taille du bus connecté au cache d'instruction. Par exemple, pour charger quatre instructions de 32 bits chacune, il suffit de lire un bloc de 128 bits dans le cache d'instruction. Un bloc de 8, 16, 32 octets est donc lu depuis le cache et est ensuite découpé en instructions, envoyées chacun à un décodeur. Charger plusieurs instructions consécutives ne marche bien qu'en absence de branchements. La présence de branchements casse cette dynamique, et il faut gérer leur présence. * Sans prédiction de branchement, toutes les instructions d'un bloc sont décodées et exécutées en même temps, même s'il y a un branchement dans le tas. * Avec prédiction de branchement, les instructions situées après le branchement ne sont pas décodées ni exécutées. L'unité de chargement coupe le bloc chargé au niveau du premier branchement pris, remplit les vides avec des NOP, avant d'envoyer le tout à l'unité de décodage. Les instructions à l'adresse de destination seront chargées au cycle suivant, en chargeant un nouveau bloc. [[File:Fetch sur un processeur superscalaire avec prediction de branchements.png|centre|vignette|upright=2|Fetch sur un processeur superscalaire avec prédiction de branchements.]] Un autre défaut est que sur le CPU charge un bloc de 128 bits à la fois, les instructions doivent être alignées sur 128 bits. Et on peut généraliser à n'importe quelle taille de bloc. Si les instructions ne sont pas alignées, il faut gérer la situation. Il arrive qu'une instruction soit à cheval sur deux blocs, avec un morceau dans le premier bloc, un autre dans le second. Dans ce cas, l'instruction est chargée en deux fois, et des circuits doivent gérer la situation pour recoller les morceaux. Sur les CPU avec des instructions de taille fixe, le problème ne survient que rarement. Mais il est fréquent avec des instructions de taille variable. Un autre défaut est lié aux branchements. Imaginez qu'un branchement s'exécute et branche vers une instruction de destination. Rien n'indique que l'instruction de destination sera au tout début d'un bloc. Si ça se trouve, elle sera en troisième position d'un bloc de 4 instructions. Une solution simple charge le bloc en respectant l'alignement, et les deux premières instructions du bloc ne sont pas à exécuter. Il y a donc une petite perte de performance. Certains CPU, comme l'IBM RS/6000, ont la machinerie charger un bloc de N instructions même s'il n'est pas aligné. La machinerie en question se trouve dans le cache d'instruction et est tout sauf simple à expliquer,ce qui fait que je me permets de la passer sous silence. Un détail, cependant : elle ne permet pas de charger des blocs qui sont à cheval sur deux lignes de cache. ===Le décodage parallèle des instructions=== Pour le décodage des instructions, plusieurs instructions sont décodées en même temps. On parle alors de '''décodage parallèle'''. Pour ce faire, un processeur superscalaire contient plusieurs décodeurs, chacun pouvant décoder une instruction en parallèle des autres. Prenons par exemple un processeur superscalaire à 4 voies : le décodage se fera dans quatre décodeurs séparés, qui fonctionneront en parallèle. Cependant, cette implémentation ne marche bien que pour les processeurs RISC, les processeurs CISC devant faire avec un microcode gourmand en circuits. Les processeurs CISC utilisent des décodeurs hybrides, avec un microcode qui complémente un décodeur câblé. Dupliquer le microcode aurait un cout en transistors trop important, ce qui fait que seuls les décodeurs câblés sont dupliqués. Les CPU CISC superscalaires disposent donc de plusieurs décodeurs simples, capables de décoder les instructions les plus courantes, avec un seul microcode. La conséquence est qu'il n'est pas possible de décoder deux instructions microcodées en même temps. Par contre, il reste possible de décoder plusieurs instructions non-microcodées ou une instruction microcodée couplée à une instruction non-microcodée. Vu qu'il est rare que deux instructions microcodées se suivent dans un programme, le cout en performance est extrêmement mineur. Il faut noter qu'une instruction correspond à une ou plusieurs µops. Il est donc possible de charger 5 instructions et de se retrouver avec 8 µops en sortie des décodeurs. Et c'est la source d'une distinction très importante. Plus haut, j'ai parlé de processeurs superscalaires à N voies. La terminologie peut avoir deux interprétations. La première est que le processeur charge/décode N instructions à la fois. Une seconde est qu'il est capable d'exécuter/émettre N µops en même temps. Les deux ne sont pas équivalentes, vu qu'un processeur superscalaire peut, par exemple, charger/décoder N instructions et émettre/exécuter N+2 µops. La distinction est particulièrement importante sur les processeurs superscalaires larges. Certains d'entre eux sont capables de charger 5 instructions et d'en émettre le double ! Un exemple classique était les processeurs Athlon d'AMD, qui pouvaient décoder deux instructions par cycle, mais émettre 4 µops par cycle. Ce n'était pas un problème, car beaucoup d'instructions, même basiques, étaient décodées en 2 µops. ===L'émission parallèle des instructions=== La superscalarité modifie en profondeur l'unité d'émission, notamment au niveau de son interface. Avant, elle recevait une micro-opération sur son entrée, et fournissait la micro-opération émise sur une sortie. Et cela vaut aussi bien pour une unité d'émission simple, un ''scoreboard'', une fenêtre d'instruction ou des stations de réservation. Mais avec l'émission multiple, les sorties et entrées sont dupliquées. Pour la double émission, il y a deux entrées vu qu'elle doit recevoir deux micro-opération décodées/renommées, et deux sorties pour émettre deux micro-opérations. Dans ce qui suit, nous ne parlerons pas d'entrée et de sortie, mais de '''ports de décodage''' et de '''ports d'émission'''. Les ports de décodage reçoivent des micro-opérations provenant de l'unité de décodage, les ports d'émissions sont pour les micro-opérations émises. Les ports d'émission injectent les micro-opérations émises dans le pipeline, elle sont propagée au banc de registre, aux ALUs, etc. Un processeur superscalaire a forcément plusieurs ports d'émission (et de décodage). Si l'interface de l'unité d'émission change, l'intérieur est tout autant modifié. Sur un CPU non-superscalaire, l'unité d'émission reçoit une µop "candidate à l'émission", et détecte les dépendances entre avec les µops en vol, en cours d'exécution dans le pipeline. Et c'est toujours le cas sur les processeurs superscalaires : l'unité d'émission détecte les dépendances entre les µops candidates et les µops en vol. Mais avec la siperscalarité, elle doit en plus tester les dépendances entre les µops candidates. Si l'unité d'émission est un ''scoreboard'', il doit détecter les dépendances entre instructions émises simultanément et les sérialiser si besoin. Avec une fenêtre d'instruction, il n'y a pour ainsi dire rien à faire, vu que les dépendances sont éliminées par le renommage de registre et que les signaux de réveil gèrent les dépendances RAW. C'est la raison pour laquelle les processeurs superscalaires modernes n'utilisent pas de ''scoreboard''. ==Les processeurs implémentés avec plusieurs pipelines== Nous venons de voir comment la superscalarité impacte le ''front-end'', il est maintenant de voir ce qu'il en est de l'unité d'émission et des ''back-ends''. Un processeur superscalaire peut utiliser l'exécution dans le désordre et le renommage de registres, mais ce n'est pas une obligation. Historiquement, les premiers processeurs superscalaires n'utilisaient pas d'exécution dans le désordre. Le meilleur exemple est celui du Pentium 1 et 2 d'Intel. Ils étaient tous deux des processeurs superscalaires, mais n'avaient pas d'exécution dans le désordre, qui est apparue sur le Pentium 3. les explications sont plus simples si on met de côté l'exécution dans le désordre. Vous vous dites que l'implémentation d'un processeur superscalaire n'est pas la même suivant que le CPU utilise l'exécution dans le désordre, ou non. Mais dans les faits, la distinction est plus subtile que ca. Pour l'expliquer, je vais utiliser une classification originale, qui sépare les processeurs superscalaires en trois sous-types. La distinction se fait sur la manière dont la superscalarité est implémentée en matériel.La classification que j'utilise distingue : * Les processeurs avec plusieurs pipelines, sans exécution dans le désordre. * Les processeurs superscalaires avec un pipeline dynamique. * Les processeurs avec des fenêtres d'instruction décentralisées. La distinction n'est pas qu'une question d'implémentation matérielle. Elle impacte aussi le ratio entre instructions chargées/décodées et instructions émises. Vous vous dites que les deux sont égales, mais ce n'est le cas que sur les processeurs avec N pipelines ! Sur les autres processeurs, il est possible de décoder 4 instructions, mais d'en émettre maximum 6 par cycle ! Et sur les CPU avec des fenêtres d'instruction décentralisées, il y a aussi une différence entre le nombre d'instructions qui sont ''dispatch'' et ''schedule''. La catégorie la plus simple est celle des '''processeurs avec plusieurs pipelines'''. Ce sont des processeurs superscalaires sans exécution dans le désordre. Ils partent d'un processeur non-superscalaire, et ajoutent un second pipeline, en sortie de l'unité d'émission. Le second pipeline permet l'émission parallèle d'une seconde instruction. Le second pipeline n'est pas identique au pipeline originel, sur plusieurs points. Premièrement, il n'a pas exactement les mêmes circuits. Le second pipeline est généralement composé d'une unité de calcul, d'une FPU, éventuellement d'un second banc de registres, guère plus. Il permet d'exécuter une seconde opération de calcul, pas plus, ce qui est à l'origine de contraintes d'appariemment assez fortes. De plus, il n'a pas forcément la même longueur, il peut avoir des étages en moins ou en plus. Il s'agit de la forme la plus simple de processeur superscalaire et nous allons leur consacrer cette section. ===La double émission entière-flottante=== L'exemple le plus simple utilise un second pipeline pour les opérations flottantes, séparé du pipeline originel. L'ajout d'un pipeline flottant permet d'émettre une micro-opération entière en même temps qu'une micro-opération flottante, ce qui s'appelle la '''double émission entière-flottante'''. La micro-opération entière s'exécute dans l'ALU entière, la micro-opération flottante dans la FPU. Les exemples les plus notables sont le PA-RISC 7100, le POWER 1 (RIOS .& et .9) et le PowerPC 601. L'Apollo DN10000 et l'Intel i860 utilisaient aussi cette forme de double émission, mais étaient des prototypes de CPU VLIW. [[File:Double émission entière-flottante.png|centre|vignette|upright=2|Double émission entière-flottante]] Pour bien expliquer les choses, prenons le processeur illustré ci-dessous, avec deux ''back-end'' séparés : un pour la FPU, et un autre pour le reste. Les instructions entières et mémoire passent toutes par le ''back-end'' généraliste. [[File:CPU non-superscalaire basique, avec une FPU.png|centre|vignette|upright=1.5|CPU non-superscalaire basique, avec une FPU]] Les deux ''back-end'' sont des pipelines séparés, mais il faut que l'unité d'émission soit spécialement conçue pour en profiter. Un processeur simple émission peut démarrer une seule µop par cycle : soit la µop est envoyée au ''back-end'' flottant, soit elle est envoyée au ''back-end'' général. Avec la double émission entière-flottante, le processeur peut envoyer une µop dans chaque pipeline, à chaque cycle. Vu que la FPU et son banc de registre forment déjà un pipeline séparé, les seules modifications se font au niveau du ''front-end'', unité d'émission inclue. {| |- |[[File:CPU simple émission avec une FPU.png|centre|vignette|upright=1.5|CPU simple émission avec une FPU.]] |[[File:Double émission entière flottante avec un second pipeline.png|centre|vignette|upright=1.5|CPU avec un second pipeline flottant.]] |} Notez que le terme double émission ''entière''-flottante est un peu trompeur. En réalité, la technique permet d'émettre une instruction flottante avec n'importe quelle autre instruction non-flottante, avec des restrictions pour les branchements. Il est par exemple possible d'exécuter un calcul flottant en parallèle d'un accès mémoire. Sur les CPU 32 bits, il est possible de faire les multiplications dans la FPU. Pour rappel, la FPU contient un multiplieur entier 53-54 bits, pour multiplier les mantisses de deux flottants 64 bits, qu'on peut utiliser pour faire les multiplications entières 32 bits. Cela permet d'émettre une multiplication en même temps qu'une opération entière dans l'ALU. Ainsi, le CPU pouvait émettre deux instructions : une opération entière de base, avec soit une multiplication, soit une opération flottante. En clair, une émission de type INT + (MUL /FLOAT). Par contre, on perd la possibilité d'émettre une multiplication entière avec une opération flottante, mais c'était un compromis qui en valait la peine. Le CPU PA-RISC 7100 implémentait cette optimisation. Il s'agissait d'un CPU double émission entière-flottante, qui utilisait donc un partitionnement assez simple. Le combo partitionnement + reconditionnement permettait ici de gagner en performance, pour un cout en matériel très limité. D’autant plus limité que le jeu d'instruction prévoyait le reconditionnement de la FPU. Les multiplications ne lisaient pas leurs opérandes dans les registres entiers, mais dans les registres flottants. ===La double émission entière=== Une autre possibilité ajoute un second pipeline, capable d'exécuter des opérations entières simples, appelé le pipeline entier. Le processeur supporte alors la '''double émission entière''', à savoir qu'ils peuvent émettre une opération entière en plus d'une autre instruction. L'opération entière en question est une opération simple, comme une addition, une soustraction, une opération bit à bit, une comparaison, etc. Les exemples classiques sont les processeurs Intel i960 et Pentium. L'implémentation était différente entre l'i960 et le Pentium : Le Pentium avait une seconde ALU entière, alors que le i960 rusait. Le Pentium dupliquait l'ALU entière, pour créer un second pipeline entier. Sur le Pentium originel, les contraintes d'appariement étaient assez strictes. Le Pentium avait une FPU, mais ne pouvait pas l'utiliser en double émission. Il lui était impossible d'exécuter une opération flottante en même temps qu'une opération entière (branchements inclus). Le Cyrix 6x86 était une sorte de Pentium produit par l'entreprise Cyrix, avec une microarchitecture différente. Il avait des contraintes d’appariement réduites. Par exemple, il pouvait émettre une opération flottante en parallèle d'une opération entière. Nous détaillerons ces processeurs dans le prochain chapitre, qui porte justement sur les CPU superscalaires x86. [[File:CPU simple et double émission avec un second pipeline entier.png|centre|vignette|upright=2.5|CPU simple et double émission avec un second pipeline entier.]] L'Intel i960 n'avait pas de FPU, juste une ALU entière et une unité mémoire. Il utilisait l'unité mémoire comme une seconde ALU entière limitée. Pour rappel, une unité mémoire contient une AGU, à savoir une ALU spécialisée dans les calculs d'adresse. Elle est capable de faire des additions, soustractions, et quelques décalages limités (des décalages par 2, 4, 8, pas plus). L'Intel i960 ajoutait des connexions entre AGU et banc de registre, afin que celle-ci serve de seconde unité de calcul. L'AGU est déjà reliée aux deux ports de lecture, pour lire les opérandes du calcul d'adresse, il suffit de la connecter sur le port d'écriture. Le processeur peut alors émettre deux instructions/µops entières, sous certaines conditions. [[File:Emission multiple des opérations entières, double émission.png|centre|vignette|upright=2|Émission multiple des opérations entières, double émission.]] ==Les processeurs superscalaires dynamiques== Les processeurs précédents, avec 2 pipelines, avaient une unité d'émission assez simple. Elle avait deux ports de décodage, et deux ports d'émission. Le nombre de ports de décodage et d'émission étaient identiques. Vous vous dites que c'est naturel, et intuitif, que c'est normal pour un processeur superscalaire. Mais en réalité, la majorité des processeurs superscalaires a plus de ports d'émission que de décodage. Expliquer pourquoi va cependant nous demander de parler de comment la superscalarité exploite les unités de calcul. Posons-nous cette question : de combien d'unités un processeur superscalaire a besoin ? Les unités en question ne sont nécessairement des unité de calcul, l'unité mémoire et l'unité de branchement comptent aussi. La réponse dépend du nombre de voies. Si le ''front-end'' charge et décode un paquet de N instructions, exécuter ces N instructions simultanément demandera là aussi au moins N unités de calcul. Notez le terme : ''au moins'', car c'est là tout l'enjeu de cette section. La réponse dépend aussi des contraintes d’appariement. Pour un CPU superscalaire "parfait", sans contraintes d’appariement, toutes les unités doivent être dupliquées, y compris l'unité mémoire. Un processeur à double émission parfaite devrait dupliquer l'ALU entière, le ''barrel shifter'', le circuit multiplieur, la FPU, l'unité mémoire, et l'unité de branchement, ce qui ferait passer de 6 unités à 12. Le cout en circuit est énorme, même pour de la double émission ! Et pour un CPU à N pipelines, le cout en circuit encore plus prohibitif ! En pratique, les processeurs superscalaires qui font ça sont très rares. La majeure partie des processeurs superscalaires utilisent d'autres techniques : le partitionnement, la duplication partielle des ALUs, la duplication des autres unités. ===Le partitionnement des unités fonctionnelles=== Les CPU superscalaires les plus simples ne dupliquent pas leurs unités de calcul, ils se contentent d'exploiter les unités existantes. Et pour expliquer comment, nous allons partir de l'exemple d'un processeur non-superscalaire contient une ALU entière, une FPU, une unité mémoire et une unité de branchement. Les quatre unités peuvent fonctionner en parallèle, à savoir qu'une unité peut exécuter une instruction à elle toute seule, sans interagir avec les autres. Cela suffit pour créer un processeur quadruple émission, qui peut émettre en même temps : une opération entière, une opération flottante, un branchement, un accès mémoire. Le principe marche aussi sur un processeur avec moins de 4 unités, par exemple sans FPU et/ou sans unité de branchement, ou avec au contraire des unités en plus. L'idée générale est d’émettre une µops séparée dans chaque unité fonctionnelle. Utiliser ainsi les unités existantes, pour rendre un CPU superscalaire, s'appelle le '''partitionnement superscalaire'''. Le terme n'est pas beaucoup utilisé en-dehors de quelques vieux articles académiques. Le partitionnement est fortement dépendant du jeu d'instruction, car il demande de bien séparer instructions entières, flottantes, branchements et instructions mémoire. Et autant c'est bien le cas sur les CPU RISC, autant les CPU CISC ne sont pas dans ce cas. Les CPU CISC ont des instructions ''load-op'', qui effectuent une instruction arithmétique et une µop mémoire. Et ces instructions sont très compliquées à implémenter avec le partitionnement. Et au-delà de ça, les CPU CISC ont beaucoup d'instructions qui sont décodées en plusieurs µops, à exécuter dans un ordre bien précis. On peut pas émettre les µops en question simultanément. Le partitionnement a un cout en circuit très limité, pour un gain en performance lui aussi limité. Pour reprendre le CPU de l'exemple précédent, il est rare que l'on ait à exécuter ces quatre instructions en même temps. En pratique, les combinaisons fréquentes sont les combinaisons calcul + accès mémoire, calcul + branchement, calcul entier + calcul flottant. Utiliser une quadruple émission de ce type n'est donc pas une bonne idée, alors que la double émission parait plus adaptée. Et c'est là que la différence entre ports d'émission et de décodage devient intéressante. L'idée est d'avoir une unité d'émission avec deux ports de décodage, et 4 port d'émission (un par unité). Les contraintes d’appariement varient alors suivant le processeur, mais la règle générale est que si deux micro-opérations tombent dans deux unités différentes, on peut les émettre en même temps. En clair, on peut émettre une opération entière avec une opération flottante, une opération entière avec un branchement, un accès mémoire avec un branchement, etc. Et cela rend le partitionnement bien plus intéressant que prévu. Les tout premiers CPU superscalaires étaient des CPU double émission, qui utilisaient le partitionnement avec : une ALU entière, une unité mémoire et une FPU. Nous parlerons de '''partitionnement INT-FLOAT-MEM'''. L'avantage sur la double émission flottante est que les combinaisons INT + MEM et FLOAT + MEM étaient autorisées. L'intérêt était d'émettre une opération en parallèle d'un accès mémoire, ce qui est un doublet d'instruction assez fréquent. Les exemples classiques sont l'HyperSPARC, de l'alpha 21064 et du PowerPC 603. Les contraintes d’appariement variaient grandement suivant le processeur. Le PowerPC 603 implémentait une double émission "parfaite". C'est à dire que toutes les combinaisons possibles à deux instructions étaient possibles, que ce soit INT + FLOAT, INT + MEM, FLOAT + MEM. En plus de cette double émission "parfaite", le CPU utilisait la technique dite de ''branch folding'', qui permettait d'exécuter un branchement sans utiliser d'unité de calcul, ce qui fait qu'il était qualifié de ''CPU 2-way + Branch''. A l'opposé, le processeur alpha 21064 avait pas mal de contraintes d’appariement, à savoir que certaines combinaisons de deux instructions étaient interdites, bien que compatibles avec les unités disponibles. Une des raisons est que le banc de registre n'avait pas assez de ports de lectures, ce qui fait que certaines combinaisons avec une écriture mémoire n'étaient pas permises. Les concepteurs avaient volontairement inséré ces contraintes afin de simplifier le design du processeur. Avant de poursuivre, précisons que la FPU regroupe un additionneur flottant et un multiplieur flottant. Et ce fait peut être exploité pour approfondir le partitionnement. La '''double émission FADD/FMUL''' permet d'émettre une addition flottante en même temps qu'une multiplication flottante. Elle a été utilisée sur les processeurs x86, Alpha et SPARC. Les autres circuits de calcul flottant sont souvent regroupés avec l'additionneur. La division est parfois e même port que le multiplieur flottant, parfois sur celui de l'additionneur (quand elle est microcodée et exécutée en enchainant les soustractions). ===La duplication des ALU entières=== Le partitionnement est une technique élégante, simple, facile à implémenter et au cout en circuits modeste. Mais il faut avouer que cela ne donne pas des CPU superscalaires très efficaces. La raison est que le partitionnement permet d'émettre des paires, triplets, quadruplets de micro-opérations qui sont rares en pratique. Les combinaisons les plus fréquentes en pratique sont des paires/triplets d'opérations entières, souvent des paires/triplets d'additions ou d'opérations entières simples. Il est donc primordial d'émettre plusieurs opérations entières simultanément. Le fait d'émettre et d'exécuter plusieurs opérations entières en même temps s'appelle l''''émission entière multiple'''. Pour exécuter la seconde/troisième opération entière, il faut dupliquer les ALU entières (ou réutiliser l'AGU comme ALU entière comme le fait l'Intel i960). Le processeur doit avoir deux ALU entières pour de la double émission entière, trois pour de triple émission entière, etc. De plus, il faut ajouter des ports au banc de registre, pour lire deux fois plus d'opérandes et décrire deux résultats. Et enfin, il faut rajouter un port d'émission pour pouvoir émettre une micro-opération entière en plus. [[File:Processeur non-superscalaire basique 03.png|centre|vignette|upright=2|Processeur non-superscalaire basique]] La tendance est de multiplier les ALU entières, mais pas le circuit multiplieur. Le cout en transistors est alors grandement réduit, au prix de l'apparition de dépendances structurelles. Le CPU peut émettre deux additions en même temps, ou une addition et une multiplication, mais pas deux multiplications. Il en est de même avec le ''barrel shifter'', qui n'est pas dupliqué. Il est donc possible d'émettre un décalage avec une opération de base, mais pas deux décalages en parallèle. Mais ces contraintes d’appariement ne sont pas un problème, car il est rare de devoir émettre deux multiplications/décalages en même temps. La plupart des programmes sont majoritairement remplis d'additions, avec des multiplications assez rares et des décalages qui le sont encore plus. La moyenne est proche d'une multiplication pour 4/5 additions. Vu que des multiplications consécutives sont très rares, dupliquer le multiplieur est presque inutile. Disposer de plusieurs circuits multiplieurs ou de plusieurs ''barrel shifters'' serait donc un cout en circuits qui ne servirait que rarement et n'en vaut pas la chandelle. Il faut noter que sur les CPU 32 bits, les multiplications peuvent être exécutées dans la FPU ou dans un multiplieur séparé, tout dépend de si le CPU exécute les multiplications dans la FPU ou pas. {|class="wikitable" |- ! Voie d'émission n°1 !! Voie d'émission n°2 !! Voie d'émission n°3 |- | ALU entière || ALU entière || FPU |} Reste à connecter les unités de calcul à l'unité d'émission (indirectement, car il y a des étages de pipeline entre les deux). Une implémentation basique utilisée un port d'émission par unité. Prenons l'exemple d'un CPU superscalaire avec 4 ALU entières, une FPU, et une unité mémoire. Vu qu'il y a 6 unités, cela fait donc 6 ports d'émission. L'exemple historique le plus impressionnant est celui du Motorola 88110, un CPU double émission qui possède 10 unités. Il contient deux ALU entières, un circuit multiplieur, un circuit diviseur, une unité de manipulation de bits, une unité mémoire, un additionneur flottant, et deux unités graphiques pour des calculs impliquant des pixels. Le multiplieur est utilisé à la fois pour les multiplications entières, flottantes et le produit de deux pixels. Idem pour le diviseur, qui sert pour les divisions entières et flottantes. Et chaque unité a son propre port d'émission. La conséquence est que les contraintes d'appariement du Motorola 88110 sont simples : tant que deux µops atterrissent dans des unités séparées, la paire est permise. Il est par exemple possible d'émettre simultanément deux opérations entières simples, vu qu'il y a deux ALU. Par contre, impossible d'émettre simultanément deux multiplications, deux divisions, deux opérations flottantes, deux manipulations de bit, deux accès mémoire, etc. De plus, le partage du multiplieur fait qu'on ne peut pas émettre une multiplication entière avec une multiplication flottante. Idem avec les divisions, vu que le diviseur est aussi partagé. Ce sont les seules contraintes. ===Le partage des ports d'émission=== La présence d'un circuit multiplieur et d'un ''barrel shifter'' pose des problèmes pour le partitionnement. Il est possible d'avoir un port d'émission dédié au multiplieur, et un autre au ''barrel shifter'', qui sont séparés de ceux pour l'ALU entière. Il est alors possible d'émettre une opération entière, une multiplication et un décalage, simultanément. Nous parlerons de '''partitionnement entier''' pour désigner cette possibilité. [[File:Partitionnement superscalaire entier.png|centre|vignette|upright=2|Partitionnement superscalaire entier.]] Le partitionnement entier est cependant très rare, car le gain en performance serait trop faible au regard des couts en circuit. Quelques processeurs historiques l'utilisaient, mais ce n'est plus le cas de nos jours. La raison est que les multiplications et les décalages sont assez rares dans le code, ce qui fait que le port d'émission associés sont sous-utilisés. Et un port d'émission a un cout en circuit assez important. Et c'est sans compter qu'ajouter des ports sur le banc de registres juste pour un multiplier sous-utilisé n'en vaut pas la peine. L'idéal serait de trouver un moyen de réduire le nombre de ports d'émissions, sans réduire le nombre d'unités de calcul. [[File:Emission multiple des opérations entières, implémentation naive.png|vignette|Émission multiple des opérations entières, implémentation naive]] La solution consiste à '''partager les ports d'émission''', à savoir connecter un port d'émission à plusieurs unités de calcul. L'exemple classique est justement lié aux circuits multiplieur et ''barrel shifters''. L'idée est que le multiplieur et le ''barrel shifter'' sont mis sur le même port d'émission qu'une ALU entière. Prenons par exemple le processeur à double émission entière illustré ci-contre. Un port d'émission est relié à une ALU entière seule, et l'autre port d'émission alimente la seconde ALU entière et le multiplieur. La conséquence est que le processeur peut émettre deux opérations entières, dont une multiplication. Si on avait utilisé un port d'émission dédié au multiplieur, il aurait été possible d'émettre deux opérations entières et une multiplication. On perd donc une voie, mais on gagne en flexibilité et on économise des circuits. Notons que ce partage signifie aussi que le multiplieur partage les ports sur le banc de registre, ce qui fait une double économie. [[File:Emission multiple des opérations entières, implémentation courante.png|centre|vignette|upright=1.5|Émission multiple des opérations entières, implémentation courante]] En général, le ''barrel shifter'' et le multiplieur sont placés sur deux voies d'émission séparés, ce qui permet d'émettre un décalage et une multiplication en même temps. Les mettre sur le même port ne le permettrait pas. {|class="wikitable" |- ! Voie d'émission n°1 !! Voie d'émission n°2 !! Voie d'émission n°3 |- | * ALU entière * Multiplieur | * ALU entière * Barrel shifter | FPU |- | * Additions, soustractions, opérations bit à bit, etc. * Multiplication | * Additions, soustractions, opérations bit à bit, etc. * Décalages et rotations | Opération flottante |} Terminons concernant les multiplieurs avec une dernière subtilité. Pour rappel, les processeurs modernes intégrent en réalité deux multiplieurs différents. Le résultat d'une multiplication est très large et prend deux registres. Par exemple, une multiplication de deux opérandes 64 bits donne un résultat sur 128 bits, ce qui ne tient pas dans un registre, mais en prend deux. L'instruction de multiplication classique ne calcule que les 64 bits de poids faible. mais elle est complétée par d'autres instructions de multiplication qui peuvent faire le calcul complet. Pour résoudre le problème, les processeurs modernes intègrent deux instructions de multiplications : une qui calcule les bits de poids faible du résultat, une autre qui calcule les bits de poids fort. Et ces deux instructions sont associées à deux multiplieurs séparés, aux circuits différent. Le multiplieur qui calcule les bits de poids faible du résultat est appelé le ''low multiplier'', l'autre est appelé le ''high multiplier''. Le second multiplieur est souvent placé sur un second port d'émission, différent du premier multiplieur, partagé avec une ALU. L’avantage de mettre les deux multiplieurs sur deux ports d'émission différents est qu'une multiplication complète peut être réalisée en utilisant les deux multiplieurs en parallèle. Les deux sous-multiplications sont émises en même temps, exécutées en même temps. pas besoin d'exécuter l'une puis la seconde, d'où un gain performance appréciable. Nous venons de voir comment partager un port d'émission entre une ALU et un multiplieur. Mais au-delà de cet exemple, le partage des ports d'émission peut appliquer à n'importe quelle unité. Prenons l'exemple d'un CPU superscalaire avec 4 ALU entières, une FPU, et une unité mémoire. Vu qu'il y a 6 unités, cela fait donc 6 ports d'émission. Cependant, il est rare qu'un bloc de 6 instructions contienne exactement 4 opérations entières, une opération flottante, et un accès mémoire. Beaucoup de ports d'émission seraient sous-utilisés. La solution est de partager des ports d'émission, pour passer à la quadruple émission. Le CPU peut alors répartir 4 instructions sur les ports d'émission adéquats, à chaque cycle. Le CPU a donc 4 ports de décodage et 6 ports d'émission. Une implémentation classique permet n'importe quelle combinaison de 4 instructions compatible avec les 6 unités. Par exemple, il devient possible d'émettre simultanément 4 additions, la combinaison 2 * INT + FLOAT + MEM, 3 * INT + MEM, et bien d'autres. L'exemple relie une ALU entière, la FPU et l'unité mémoire sur le même port. Le CPU a alors quatre ports d'émission, qui ne sont pas "identiques". Trois d'entre eux sont reliés à une ALU entière chacun, rien d'autre. Le quatrième est lui relié à une ALU entière, la FPU et l'unité mémoire. On économise alors deux ports d'émission, mais cela entraine l'apparition de contraintes d’appariement. Le CPU peut émettre 3 opérations entières + n'importe quelle autre opération. Mais les autres combinaisons sont interdites. Le CPU peut émettre 6 opérations entières simultanément, grâce à 6 ALU entières. Les accès mémoire ou opérations flottantes ne viennent pas en plus, mais en remplacement des opérations entières. Regrouper plusieurs ALU sur un même port d'émission est donc à l'origine de dépendances structurelles, de nouvelles contraintes d’appariement. Dans certaines situations de '''''port contention''''', on a assez d'ALU pour exécuter N micro-opérations, mais la répartition des ALUs sur les ports l'empêche. Impossible d'émettre deux micro-opérations sur deux ALU si elles sont sur le même port d'émission. On peut réduire les cas de ''port contention'' en répartissant correctement les ALU sur les ports d'émission, mais sans jamais les supprimer complétement. Un exemple est celui du PowerPC 604. Il implémentait la quadruple émission, alors qu'il avait 5 unités de calcul. Mais deux unités partageaient un même port d'émission. Dans le détail, il avait deux ALU entières, un circuit multiplieur/diviseur, une FPU, une unité mémoire. La FPU et le multiplieur étaient sur le même port d'émission. En conséquence, le CPU pouvait émettre seulement les combinaisons INT + INT + MEM + (MUL/FLOAT). : Il est intéressant de voir l'exemple d'un processeur superscalaire parfait, sans contraintes d'appariement, à N voies. Pour cela, on part d'un processeur non-superscalaire, avec M unités de calcul. Un tel processeur peut s'implémenter avec N ports d'émission, chacun relié à M unités de calcul possibles, ce qui fait que les M unités de calcul sont dupliquées en N exemplaires. Si on prend par exemple un CPU non-superscalaire avec une ALU, une FPU, une unité mémoire et une unité de branchement, un port d'émission sera relié à une ALU, une FPU, une unité mémoire et une unité de branchement. ===La duplication des autres unités fonctionnelles=== Dupliquer les ALU entière est une première étape, mais il est aussi possible de dupliquer les autres unités fonctionnelles. Par exemple, il est possible de dupliquer l'unité mémoire ou l'unité de branchement. Reste à voir quelles unités dupliquer, et pourquoi. Précisons que dans ce qui va suivre, nous allons parler de la duplication des unités en général, pas seulement des unités mémoire/branchement. Nous allons continuer de parler de la duplication des ALU entières dans ce qui suit, mais de manière plus générale. Pour un processeur à N voies, il est théoriquement possible de dupliquer toutes les unités en N exemplaires. Mais ce n'est jamais fait en pratique, car le cout en circuits serait trop important et le gain en performance trop faible. Mieux vaut dupliquer certaines unités bien précises, quitte à avoir des contraintes d'appariement. Et à ce petit jeu, toutes les duplications ne se valent pas, certaines sont plus rentables en matière de performance, le cout en circuit n'est pas le même selon l'unité, etc. La rentabilité en performance dépend surtout des contraintes d'appariement. Les contraintes d'appariement entrainent une baisse de performance significatives si elles interdisent des paires d'instructions fréquentes. Aussi, les opérations très fréquentes, souvent appairées, gagnent à dupliquer l'unité associée. Et au contraire, les unités rarement utilisées ne doivent pas être dupliquées. Il se trouve que les unités les plus utilisées sont les ALU entières, suivies par les unités mémoire et l'unité de branchement. Le cout en circuit n'est aussi pas le même. Dupliquer les ALU entière est trivial, car elles ont un budget en transistors assez faible. Les circuits multiplieurs, diviseurs, et les ''barrel shifter'' ont eux un cout en transistor plus élevés. Si on devait faire un classement, on aurait : ALU entière < ''barrel shifter'' < multiplieur. Pour les unités mémoire, le cout en transistor est là aussi conséquent. Le résultat final est que dupliquer les ALU entières est privilégié sur le reste, comme l'a vu dans la section précédente. Les unités mémoire arrivent en seconde place, suivie par les multiplieurs/''barrel shifter'' à la troisième place, et les unités de branchement à la quatrième place. Les CPU superscalaires larges ont donc tendance à multiplier les unités mémoire en second. Les multiplieurs et ''barrel shifters'' sont eux aussi dupliqués sur les CPU superscalaires larges, mais cela vient souvent après avoir dupliqué les unités mémoire. La raison est que les accès mémoire sont critiques pour la performance des CPU à exécution dans le désordre, pas les multiplications. Pour les unités de branchement, une subtilité complique le fait d'en installer plusieurs. Que faire quand deux branchements sont pris ? La solution la plus simple est de ne pas se trouver dans cette situation : on n'utilise qu'une seule unité de branchement et on n’exécute qu'un seul branchement par cycle. La majorité des processeurs superscalaires étroits font ainsi. Les processeurs superscalaires larges ont cependant deux unités de branchements, mais ils n'acceptent qu'un seul branchement pris à la fois. Si les deux branchements pris sont exécutés en même temps, le processeur n’exécute que le plus récent, dans l'ordre du programme. ===Les CPU superscalaires mélangent les trois techniques=== Les CPU superscalaires utilisent toutes les techniques à la fois : partitionnement, duplication de l'ALU entière, duplication des autre unités fonctionnelles. Chaque processeur utilise ces trois stratégies à sa sauce, en fonction de son budget en transistor. Les quatre techniques ont cependant un cout en circuit différent, et donnent des gains de performances eux aussi forts différents. * Le '''partitionnement superscalaire''' a un cout en circuit modéré, car on n'a pas besoin de dupliquer d'ALU. * La '''duplication des ALU entières''' est la technique la plus importante : elle a un cout en circuit modéré, et donne des gains en performance impressionnants. * La '''duplication des autres unités''' a un cout en circuit variable, pour des gains en performance eux aussi variables. * Le '''partage des ports d'émission''' réduit le cout en circuit du CPU, pour des pertes de performances mineures si bien fait. L'usage du partitionnement seul, sans duplication, était surtout le fait des processeurs commercialisés entre les années 1989 et 1993. Le partage des ports d'émission a lui aussi mis un peu de temps pour s'imposer. Globalement, les processeurs superscalaires ont évolués progressivement, pour se rapprocher d'une sorte de standard. Mais pour comprendre ce qu'est ce standard, et en quoi les CPU historiques s'en sont progressivement rapprochés, il faut étudier l'histoire des CPU superscalaires. L'histoire des CPU superscalaires a commencé dès 1960, mais est resté un projet de recherche pendant plusieurs décennies. De nombreux designs ont été conçus, mais abandonnés avant la production, comme l'ACS-1 d'IBM. Les années 1980 ont vu l'arrivée de prototypes de processeurs VLIW, mais qui n'étaient pas superscalaires. Par exemple, l'Apollo DN10000 et l'Intel i860 pouvaient émettre deux instructions à la fois, sous conditions, mais demandaient que le compilateur fasse une bonne partie du travail. Les premiers CPU superscalaires commercialisés sont sortis en 1989. Deux CPUs superscalaires sont sortis cette année là : le RS/6000 d'IBM et l'i960CA d'Intel. Puis, la compétition s'est aussi lancée dans la bataille. Les CPU commercialisés avant l'année 1993 étaient à double émission, à l'exception du SuperSPARC qui utilisait la triple émission. Les modèles après 1993 hésitaient entre double et quadruple émission. Dans le tableau ci-dessous, les processeurs quadruple émission sont en bleu, les triple émission sont en rouge, les autres ne sont pas en couleur. {|class="wikitable" |- ! !! IBM !! HP PA-RISC !! SPARC !! Intel!! Alpha !! Autres |- ! 1989 | RS/6000 || || || i960CA || || |- ! 1990 | || || || || || |- ! 1991 | || || || || || Motorola 88110 |- ! 1992 | RSC || PA 7100 || class="f_rouge | SuperSPARC || || 21064 || |- ! 1993 | PPC 601 || || HyperSPARC || Pentium || || |- ! 1994 | class="f_bleu | POWER 2 || PA 7200 || || || class="f_bleu | 21164 || |- ! 1995 | 603/604 || class="f_bleu | PA 8000 || class="f_bleu | UltraSPARC 1 || Microarchitecture P6 (+ concurrence AMD) || || class="f_bleu | MIPS R1000 |- ! 1996 | class="f_bleu | 620 || || || || class="f_bleu | 21264 || |- ! ... || ... || ... || ... || ... || ... || ... |} Les premiers CPU à double émission sont assez représentatifs des CPU à double émission modernes. Il faut dire que se limiter à deux voies ne permet pas de faire beaucoup de choses. Voici le tableau chronologique disant quel CPU utilisait quelle technique. * Les CPU en vert utilisaient la double émission entière-flottante. * Les CPU en rouge utilisaient la double émission entière "pure". * Les CPU en jaune utilisaient un ''partitionnement complet'' entre ALU, FPU et unité mémoire. * Les CPU sans couleur utilisaient un grand nombre d'unités, avec beaucoup de ports d'émission. * Les CPU barrés utilisent la triple ou quadruple émission et seront vu dans la section suivante. {|class="wikitable" |- ! !! IBM !! HP PA-RISC !! SPARC !! Intel!! Alpha !! Autres |- ! 1989 | class="f_vert | RS/6000 || || || class="f_rouge | i960CA || || |- ! 1990 | || || || || || |- ! 1991 | || || || || || Motorola 88110 |- ! 1992 | class="f_vert | RSC || class="f_vert | PA 7100 || <s>SuperSPARC</s> || || class="f_jaune | 21064 || |- ! 1993 | class="f_vert | PPC 601 || || class="f_jaune | HyperSPARC || class="f_rouge | Pentium || || |- ! 1994 | <s>POWER 2</s> || PA 7200 || || || <s>21164</s> || |} C'est en 1994, que la quadruple émission est arrivée et que les CPU ont essayé divers implémentations. Il y avait alors trois stratégies pour la double/triple/quadruple émission, qui partageaient des problèmes similaires. La première implémentation dupliquait les ALUs et les FPUs, ce qui permettait d'émettre deux opérations flottantes avec deux opérations entières. Le POWER 2 dupliquait ses FPUs à la perfection, alors que le 21264 séparait l'additionneur et le multiplieur flottant. Les accès mémoire étaient traités comme des opérations entières et le processeur pouvait souvent en émettre deux à la fois. Mais une telle organisation n'est plus utilisée de nos jours, car, sans instructions flottantes à exécuter, elle est équivalente à de la double émission. La seconde implémentation utilisait deux ALU entières (dont un multiplieur), une unité mémoire et une FPU.Cette organisation est intéressante, mais encore trop stricte pour donner de bons résultats, les quadruplets avec exactement deux opérations entières, un accès mémoire et une opération flottante étant trop rares. L'usage de ces 4 unités en double ou triple émission a été utilisé sur le PA 7200 et le SuperSPARC. Malheureusement, en plus de problèmes au niveau de son cache, le SuperSPARC avait de nombreuses contraintes d’appariement, car le banc de registre n'avait pas assez de ports pour alimenter certaines combinaisons d'instructions. De plus, s'il émettait une multiplication, il ne pouvait pas émettre de seconde µop. Enfin, une troisième implémentation utilisait un grand nombre d'unités fort différentes, bien plus que quatre, avec au minimum deux ALU entières. Prenons l'exemple de l'UltraSPARC, qui avait : deux ALU entières, une unité mémoire, une unité de branchement, un additionneur flottant, un multiplieur flottant, un diviseur flottant (aussi utilisé pour le calcul des racines carrées), et 2 unités graphiques pour les calculs sur des pixels. En tout, cela fait 9 unités différentes, pour de la quadruple émission. Dans le même genre, les processeurs MIPS R8000 et R10000 avaient une implémentation plus moderne, dans le sens où toutes les unités étaient dupliquées. Le CPU avait deux ALU, deux FPU et deux unités mémoire. Il pouvait donc émettre quatre instructions à la fois, tant que le paquet collait avec ces six unités. Moitié opérations entières, moitié opérations mémoire, avec de quoi remplacer les opérations entières par des opérations flottantes. Le PA 8000, lui, dupliquait toutes ses unités en deux exemplaires, ce qui n'est pas l'idéal, aucun processeur moderne ne fait cela aujourd'hui. Le tout est résumé dans le tableau ci-dessous, avec : * en vert les CPU utilisant la première stratégie ; * en rouge les CPU utilisant la seconde stratégie ; * en jaune les CPU utilisant la troisième stratégie. {|class="wikitable" |+ Processeurs quadruple émission historiques |- ! Année !! Processeur !! Unités |- ! 1991 | class="f_jaune | Motorola 88110 || class="f_jaune | 2 ALU + MUL + DIV + BIT + MEM + FADD + 2 unités graphiques |- |- ! rowspan="2" | 1994 | class="f_vert | POWER 2 || class="f_vert | 2 ALU/MEM + 2 FPU (+ 2 Branchements via ''branch folding'') |- | class="f_rouge | 21164 || class="f_rouge | 2 ALU + FPU + MEM |- ! rowspan="3" | 1995 | PA 8000 || 2 ALU + 2 ''barrel shifters'' + 2 MEM + 2 FPU (FMA) + 2 FPU (DIV et SQRT) + 2 SIMD |- | class="f_jaune | UltraSPARC 1 || class="f_jaune | 2 ALU + MEM + BRANCH + FADD + FMULFDIV + 2 unités graphiques |- | MIPS R8000 et R10000 || 2 ALU + 2 FPU + 2 MEM |- ! rowspan="2" | 1996 | class="f_rouge | 620 || class="f_rouge | 2 ALU + FPU + MEM |- | class="f_vert | 21264 || class="f_vert | 2 ALU/MEM + 2 FPU (FADD + FMUL) |} Malheureusement, ces CPUs historiques n'avaient ni assez d'unités de calcul entières, ni d'unités mémoire, pour remplir la quadruple émission. Environ la moitié des instructions d'un programme correspond à des instructions entières. Pour en profiter, un processeur à N voies doit disposer d'au minimum N/2 ALU entières, l'idéal étant d'aller au-delà. Les CPU superscalaires historiques avaient 2 ALU pour de la quadruple émission, ce qui était très limite. En comparaison, les CPU superscalaires modernes mettent le paquet niveau ALU entière. La plupart des CPU x86 modernes descendent rarement sous les 2/3, la plupart remplit presque la totalité de la largeur du CPU. Pour donner un exemple, la microarchitecture Golden Cove d'Intel est un processeur à 6 voies, avec 5 ALU entières. Pour être précis, un programme informatique exécute environ 40% de son code dans des instructions arithmétiques, un autre 40% dans les accès mémoire, et un le reste pour... le reste. La conséquence est que les processeurs modernes dupliquent leurs unités mémoire. Par exemple, la microarchitecture ''Golden Cove'' d'Intel dispose de trois unités mémoire : deux spécialisées dans les écritures, trois dans les lectures. La microarchitecture ''Gracemont'' utilise la pentuple émission et peut émettre 4 µops entières et 4 µops mémoire. Notez que le ratio est équilibré entre opérations entières et mémoire, avec soit égalité, soit un avantage pour les ALU entières. Une autre régularité est que la largeur totale du processeur peut être occupée par des opérations entières/mémoire. Pour le dire autrement, sur un processeur quadruple émission, il pourra émettre un mix de 4 instructions entière/mémoire, avec zéro opération flottante. Idem avec des processeurs triples ou pentuple émission, voire plus. Si le processeur émet une opération flottante, elle remplace une opération entière. Prenons l'exemple des processeurs AMD K6, sortis en 1997, juste avant les AMD Athlon. Ils avaient 10 unités de calcul, 6 ports d'émission, 4 ports de décodage. Voici exactement comment étaient répartie les unités de calcul sur les ports d'émission. C'était des processeurs quadruple émission, ce qui fait que la moitié de la largeur du processeur sert pour des opérations entières, et l'autre moitié pour les accès mémoire. {|class="wikitable" |- ! Port d'émission n°1 !! Port d'émission n°2 !! Port d'émission n°3 !! Port d'émission n°4 !! Port d'émission n°5 !! Port d'émission n°6 ! |- | ALU entière || ALU entière || FPU || Unité de branchement || Unité LOAD || Unité STORE |- | || Multiplieur || || || || Unité de calcul d'adresse (instruction LEA) |- | || ''Barrel shifter'' || || || || Unité pour les instructions PUSH |} Les microarchitectures K7, K8 et K10, utilisées sur les anciens CPU AMD Athlon, sont un exemple moins représentatif. Ces microarchitectures utilisent le partage des ports d'émission au maximum. C'était des microarchitectures à triple émission, avec six ports d’émission. Il y avait trois ports d'émission pour les opérations flottantes, et trois ports d'émission pour les micro-opérations entières/mémoire. Il y avait trois ALU entières et trois unités mémoire, chaque ALU partageait un port d'émission avec une unité mémoire. Elle pouvait donc émettre soit trois opérations entières, soit trois µops mémoire, soit un mix des deux. En plus des mix avec les opérations flottantes et branchements. {|class="wikitable" |- ! Port d'émission n°1 !! Port d'émission n°2 !! Port d'émission n°3 !! Port d'émission n°4 !! Port d'émission n°5 !! Port d'émission n°6 ! |- | ALU entière || ALU entière || ALU entière || FADD || FMUL || FPU (autres opérations) |- | Multiplieur || || || || || |- | LOAD/STORE || LOAD/STORE || LOAD/STORE || || || |} Les CPU superscalaires larges dupliquent les multiplieurs et/ou les ''barrel shifters'', et même les unités de branchement. La raison est que quand la largeur du CPU augmente, le processeur traite des paquets d'instructions de plus en plus gros. Par exemple, pour un CPU à 10 voies, cela veut dire émettre 10 instructions en même temps. Il est alors plus fréquent d'avoir deux multiplications, deux décalages, deux accès mémoire, deux branchements. Par exemple, la moyenne est d'une multiplication tous les 5 instructions. Les CPU superscalaires à 10 voies ont donc tendance à avoir deux multiplications par paquet d'instruction, en moyenne. Avoir deux multiplieurs est alors un gain en performance clair. Par exemple, la microarchitecture ''Golden Cove'' a deux ''barrel shifters''. C'est une architecture à 6 voies. {|class="wikitable" |- ! Port d'émission n°1 !! Port d'émission n°2 !! Port d'émission n°3 !! Port d'émission n°4 !! Port d'émission n°5 !! Port d'émission n°6 !! Port d'émission n°7 !! Port d'émission n°8 !! Port d'émission n°9 !! Port d'émission n°10 |- | ALU entière || ALU entière || ALU entière || ALU entière || ALU entière || LOAD || LOAD || LOAD || STORE || STORE |- | ''Barrel shifter'' || Multiplieur || Multiplieur || ''Barrel shifter'' || || || || || || |- | Branchements || Diviseur || || Branchements || || || || || || |} ==Les µops mémoire sur les processeurs superscalaires== Plus haut, nous avons volontairement passé sous silence les accès mémoire. La raison à cela est que leur support sur les CPU superscalaire peut se faire de plusieurs manières différentes, qu'il vaut mieux expliquer dans une section dédiée. Les différentes implémentations sont décrites dans la liste suivante, nous allons les voir une par une. * Avec la première méthode, les accès mémoire sont exécutés par le pipeline pour les opérations entières. * Avec la seconde méthode, les accès mémoire ont un pipeline dédié ; c'est l'''émission parallèle des accès mémoire''. * Avec la troisième méthode, il est possible d'émettre plusieurs accès mémoire simultanément : c'est l'''émission multiple des accès mémoire''. Voyons ces trois cas dans le détail. Nous verrons notamment les différentes formes d'émission multiple des accès mémoire. ===Les accès mémoire traités dans le pipeline entier=== Dans le cas le plus simple, les accès mémoire sont traités comme des opérations entières un peu spéciales. L'unité mémoire est sur le même port d'émission que l'ALU entière, ce qui fait que les accès mémoire remplacent des opérations entières. Faire ainsi permet d'utiliser une ALU entière pour les calculs d'adresse, pas besoin de rajouter une unité de calcul d'adresse séparée. Typiquement, un processeur de ce type place l'unité mémoire après l'unité de calcul. Les opérations entières n'utilisent que l'ALU entière, mais pas l'unité mémoire. Les accès mémoire exécutent un calcul d'adresse dans l'ALU entière, puis l'adresse calculée est envoyée à l'unité mémoire. Le tout est illustré ci-dessous, dans le cas d'un processeur historique à double émission entière-flottante. [[File:Processeur non-superscalaire basique 01.png|centre|vignette|upright=1.5|Processeur non-superscalaire basique]] Un exemple de CPU double émission de ce type est celui du Power PC 440, un CPU destiné à l'embarqué. Vu qu'il était destiné à l'embarqué, il n'avait pas de FPU, il n'avait pas besoin de manipuler de nombres flottants. Il n'a donc que des ALU entières, un multiplieur et une unité mémoire. Il dispose de deux ports d'émission. Le premier est connecté à une ALU entière et un circuit multiplieur, le second est relié à l'unité mémoire et une seconde ALU entière. Une organisation simple, mais très efficace ! [[File:PowerPC 440.png|centre|vignette|upright=2|Microarchitecture du PowerPC 440.]] L'implémentation économise une unité de calcul d'adresse, mais n'a pas de cout en performance significatif. Les accès mémoire étant très lents, émettre une µop entière en parallèle d'un accès mémoire ne sert pas à grand-chose. On peut émettre cette µop entière un cycle plus tard, elle sera terminée avant même que l'accès mémoire soit terminé, même si l'accès mémoire se fait dans le cache L1 ou L2. Pour comprendre pourquoi, faisons quelques calculs. Un accès mémoire prend deux-trois cycles quand il tombe dans le cache L1. Et on doit attendre qu'il soit terminé pour en émettre un nouveau. Combien d'instructions arithmétiques peut-on lancer pendant ce temps, sur un CPU triple émission ? Au premier cycle, on peut en émettre 2 (l'instruction mémoire prend une place, donc 3-1), puis 3 au second cycle. Ce qui fait 5 instructions arithmétiques au total. Or, il se trouve qu'il y a une instruction d'accès mémoire pour 5 instructions arithmétiques, environ. Par contre, ce compromis change quand on passe à la quadruple émission, voire au-delà. Dans ce cas, il devient intéressant de pouvoir émettre une nouvelle instruction mémoire à chaque cycle. Ce qui nous amène à la section suivante... ===L'émission parallèle des accès mémoire=== A partir de la quadruple émission, la tendance a été de séparer l'unité mémoire des ALU entières. Cela permet d'émettre des µops mémoire en même temps que des µops entières et/ou flottantes., ce qui porte le nom d''''émission parallèle des µops mémoire''', ou encore ''émission mémoire parallèle''. Par exemple, un processeur quadruple émission peut émettre en même temps deux opérations entières, une opération flottante et un accès mémoire. L'accès mémoire vient en plus des opérations entières, il n'est pas possible de remplacer l'accès mémoire par une opération entière. La technique ne permet pas de faire les calculs d'adresse dans l'ALU entière. Il faut donc utiliser une unité de calcul d'adresse séparée. Elle est intégrée dans l'unité mémoire, qui fait l'interface entre le cache et le banc de registres. Le cout en circuits est très faible, car les unités de calcul d'adresse n'utilisent guère plus qu'un additionneur et un circuit de décalage très simple. L'émission mémoire parallèle est plus facile à implémenter sur les CPU RISC, qui ont des instructions mémoire séparées du reste. Les CPU CISC ne sont pas dans ce cas, ce qui fait que séparer l'unité mémoire du pipeline entier est compliqué. Les CPU superscalaires historiques étaient pour moité des CPU RISC et pour moitié des CPU CISC, ce qui fait qu'ils n'utilisaient pas ou peu l'émission mémoire parallèle. Les premiers processeurs superscalaires se contenaient de l'émission parallèle mémoire, ils ne pouvaient émettre qu'un seul accès mémoire à la fois, l'unité mémoire n'était pas dupliquée. Et ce n'est pas tant un problème que ça, du moins sur les processeurs à double ou triple émission. En effet, il est rare que l'unité mémoire doive faire deux accès simultanés. Notons que le processeur peut exécuter une instruction mémoire en parallèle d'un calcul ou d'un branchement, seuls les accès mémoire simultanés sont impossibles. ===L'émission multiple des accès mémoire avec une LSQ=== Les processeurs superscalaires larges travaillent sur des paquets de 8 à 10 instructions, il est plus fréquent d'avoir plusieurs accès mémoire par paquet. Dans ces conditions, il est utile d'avoir une '''émission multiple des accès mémoire''', à savoir d'émettre plusieurs micro-opérations mémoire en même temps. Les processeurs superscalaires modernes sont capables d'émettre plusieurs lectures/écritures simultanément. Par exemple, ils peuvent émettre une lecture en même temps qu'une écriture, ou plusieurs lectures, ou plusieurs écritures. Il faut noter que selon le processeur, il peut y avoir des restrictions quant aux accès mémoire émis en même temps. Par exemple, certains processeurs peuvent émettre une lecture avec une écriture en même temps, mais pas deux lectures ni deux écritures. Ou encore, ils peuvent émettre deux lectures, une lecture et une écriture, mais pas deux écritures en même temps. Dans la majorité des cas, les processeurs ne permettent pas d'émettre deux écritures en même temps, alors qu'ils supportent plusieurs lectures. Il faut dire que les lectures sont plus fréquentes que les écritures. Les processeurs qui autorisent toutes les combinaisons de lecture/écriture possibles, sont rares. L'émission multiple des accès mémoire s'implémente dans l'unité mémoire. Pour rappel, l'unité mémoire s'interpose entre le cache L1 et le reste du pipeline. Dans le cas le plus simple, elle incorpore une ''load/store queue'' et des unités de calcul d'adresse. L'émission multiple des accès mémoire demande de rendre la ''Load-store queue'' multi-ports, afin de gérer plusieurs micro-opérations mémoire simultanées. Il faut aussi dupliquer les unités de calcul d'adresse reliées à la LSQ, chaque port d'émission mémoire devant avoir sa propre unité de calcul d'adresse. : Dans ce qui suit, nous parlerons d'AGU (''Adress Generation Unit'') pour désigner les unités de calcul d'adresse, et de LSQ pour designer la ''Load-store queue''. [[File:Processeur non-superscalaire basique 02.png|vignette|upright=1|Processeur non-superscalaire basique]] Dupliquer les ports de la LSQ et les AGU est nécessaire. Mais qu'en est-il du cache ? La réponse varie suivant le processeur. Il y a deux grandes méthodes pour implémenter l'émission multiple des accès mémoire. La première méthode ajoute des ports de lecture/écriture au cache de données, pour faire des lectures/écritures simultanées. Il faut alors dupliquer des unités de calcul, rajouter les ports sur le cache, mais aussi rajouter des ports sur la ''load/store queue'', pour qu'elle échange des données/commandes mémoire avec le cache. Le cout en circuits est alors conséquent La seconde duplique les unités de calcul, mais pas les ports d'accès au cache. Les accès mémoire sont alors accumulés dans la ''load/store queue'', qui sont ensuite traités un par un par le cache. Un exemple est celui des processeurs AMD de micro-architecture K7 K8, à savoir les anciens AMD Athlon et AMD Athlon 64, qui pouvaient calculer trois adresses simultanément, mais ne pouvaient faire qu'un seul accès au cache par cycle. Le cout en circuit est modéré : les unités de calcul coutent très peu, les ports de la ''load/store queue'' coutent déjà un peu plus. Quelques processeurs utilisaient des solutions intermédiaires. Un processeur utilisant cette technique est, par exemple, capable d'émettre quatre µops mémoire en même temps, mais avec seulement deux ports sur le cache. Un exemple classique étant les Pentium 1 et 2 d'Intel, dont nous parlerons dans le chapitre suivant. ===L'émission séparée des LOAD et STORE=== De rares processeurs ont des ports d'émission qui peuvent faire indifféremment lecture comme écritures. Mais les processeurs modernes préfèrent séparer ports d'émission pour les lectures et les écritures. Un exemple est celui des processeurs Intel de micro-architecture Nehalem, qui avaient un port de lecture et un port d'écriture tous deux reliés à la ''Load-store queue'', chacun avec leur propre unité de calcul d'adresse. Comme autre exemple, les processeurs skylake ont une LSQ avec deux ports de lecture et un port d'écriture, ce qui permet d'émettre deux lectures en même temps qu'une écriture. Dans cette section, nous allons étudier le cas avec des ports séparés pour les lectures et écritures. En général, les processeurs ont un peu plus de ports de lectures que d'écritures. Une raison est qu'un programme a, en moyenne, un tout petit peu plus de lectures que d'écritures. Mais la différence n'est pas énorme, c'est un léger déséquilibre. Une seconde raison est que l'exécution dans le désordre marche bien mieux quand les lectures ont lieu le plus tôt possible. Donc mieux vaut privilégier les lectures à l'émission, pour qu'elles se fassent un peu en avance. En pratique, la différence n'est pas très marquée. Il est courant d'avoir un port de lecture et un d'écriture, les CPU superscalaires très larges ont souvent deux ports de lecture et deux d'écriture. A la rigueur, quelques CPU ont trois ports de lecture et deux d'écriture. Le cas le plus simple est celui où on peut émettre une lecture et une écriture en même temps. Il s'implémente facilement si la LSQ est en réalité une simple ''Store queue'', à savoir qu'elle met en avance les écritures uniquement. Pour rappel, les écritures sont mises en attente dans la ''Store queue'', mais les lectures sont exécutées immédiatement. Une fois l'adresse à lire connue, la lecture consulte la ''Store queue'' pour détecter les dépendances de données, puis s'exécute. La donnée à lire est lue soit depuis la ''Store queue'', soit depuis le cache. [[File:Emission LOAD - Store séparée.png|vignette|upright=1|Émission LOAD - Store séparée]] L'implémentation de l'émission multiple est alors très simple. La ''Store queue'' a déjà deux ports, avec un pour les lectures et un autre pour les écritures. Idem pour le cache, qui a naturellement un port de lecture et un d'écriture. Émettre une lecture et une écriture simultanément ne demande donc pas de modification digne de ce nom. La ''Store queue'' doit juste supporter une lecture et une écriture simultanée. Ajouter l'émission d'une seconde lecture n'est pas compliquée : il faut juste rajouter un second port de lecture sur le cache et la ''Store queue''. Pour rappel, l'unité mémoire est précédée par une structure qui met en attente les micro-opérations mémoire avant leur émission finale. La structure en question varie suivant l'implémentation, mais un cas particulier se marie bien avec l'émission multiple des µops mémoire. Il s'agit du cas avec une file de µops séparée pour les lectures et une autre pour les écritures, appelées respectivement la ''file de µops LOAD'' et la ''file de µops STORE''. Il est alors possible d'émettre une lecture et une écriture lors du même cycle d'horloge. Le port de lecture alimente une unité de calcul d'adresse dédiée, directement reliée au cache. Le port d'écriture du cache alimente une unité de calcul, qui est suivie par une file d'écriture, elle-même reliée au cache. Les processeurs AMD de micro-architecture K6 utilisaient cette technique. [[File:Double émission avec le Load Ordering, Store Ordering.jpg|centre|vignette|upright=2.5|Double émission avec le Load Ordering, Store Ordering]] ==Les CPU superscalaire à exécution dans le désordre== La superscalarité modifie aussi les circuits dédiés à l'exécution dans le désordre. Elle modifie les unités de renommage de registre, le ROB et les autres structures liées à l'exécution dans le désordre, au sens large. Aucune structure n'est épargnée. Elles ont tous des prots de lecture/écriture en plus, afin d'encaisser l'émission, le ''commit'' ou le renommage simultané de plusieurs µops. Par exemple, le ROB doit être modifié pour émettre et terminer plusieurs instructions en même temps, en ajoutant des ports de lecture/écriture. Pour un CPU superscalaire à 8 voies, on se dit que le ROB peut retirer 8 µops par cycle maximum. Mais certains processeurs récents ont un ROB qui peut retirer le double ! Un exemple est celui des CPU de micro-architecture Skymont, qui peuvent émettre 8 µops par cycle, mais en retirer 16. Quelques CPU de marque AMD étaient aussi dans ce cas. L'avantage est que cela permet de réduire la taille du ROB, du banc de registre et de quelques autres structures matérielles liées à l'exécution dans le désordre. Le gain sur-compense le cout en transistor nécessaire pour retirer 16 µops par cycle. Dans cette section, nous allons voir comment les étages du pipeline dédiés à l'exécution dans le désordre sont modifiées sur un CPU superscalaire. ===L'exemple du PA-RISC PA 8000=== Avant de commencer, nous allons voir un processeur superscalaire assez simple, le PA 8000, de HP, qui implémente le jeu d'instruction PA-RISC. Bien que très ancien, il implémentait l'exécution dans le désordre et le renommage de registre. Le peu d'informations que nous avons sur ce processeurs proviennent des documents "THE HP PA-8000 RISC CPU" par Ashok Kumar, et l'article de microprocessor report "PA-8000 Combines Complexity and Speed". Ils ne donnent malheureusement pas énormémment d'informations et je devrais être amené à faire quelques suppositions dans ce qui suit. Avant de commencer, parlons de détails sans lien avec la superscalairité. Ce processeur, comme beaucoup de processeurs PA-RISC, n'intégrait pas de cache de niveau L2 dans le processeur, qui était déporté en-dehors du CPU, sur la carte mère. Le processeur préférait utiliser ses transistors pour avoir un cache L1 assez large, quitte à ce qu'il soit plus lent. La lenteur du cache était prévue, le processeur compensait celle-ci en utilisant l'exécution dans le désordre, bien que ce ne soit pas parfait. Les CPU PA-RISC avant le PA 8000 utilisaient un pipeline à vagues ''wave pipeline'', ce qui était assez peu commun, mais le PA 8000 repasse à un pipeline synchrone classique. Passons maintenant à la superscalarité. Le PA 8000 est un processeur quadruple émission, qui peut émettre, à chaque cycle, deux opérations et deux accès mémoire. Le renommage de registre utilise des registres de renommage séparés des registres architecturaux, comme c'était la mode à l'époque. Le budget en transistor faisait que c'était soit ça, soit le renommage dans le ROB, faute de mieux. L'exécution dans le désordre, quant à elle, est prise en charge par une structure matérielle unique, qui ressemble à une fusion entre un ROB et une fenêtre d'instruction. Et c'est là que je vais devoir faire des suppositions. Le document "THE HP PA-8000 RISC CPU" nomme cette structure : l''''''Instruction Reorder Buffer'''''. Il utilise pas moins de 850 000 transistors, et prend 20% de la taille du ''die''. L'article "THE HP PA-8000 RISC CPU" laisse fortement sous-entendre qu'il s'agit une structure unique, faite d'un seul tenant, mais l'article de microprocessor report dit le contraire par moment. Il est décrit comme une fenêtre d'instruction, à savoir qu'il détecte les dépendances entre instruction et les émet. Il gère aussi la détection des mauvaises prédictions de branchement et peut annuler les instructions chargées à tord, en les retirant de la fenêtre d'instruction. Il est aussi précisé que les instructions quittent cet ''Instruction Reorder Buffer'' dans l'ordre du programme. Elles ne peuvent en sortir que quand elles ont été exécutées et qu'elles n'ont causé aucune exception. Ce qui fait qu'il se comporte comme un ROB de ce point de vue là. Difficile de dire si l'''Instruction Reorder Buffer'' est un réel mélange entre un ROB et une fenêtre d'instruction, ou si il est réellement conçu avec deux structures séparées. Dans ce qui suit, je pars du principe que les deux structures sont séparées. Le processeur contient deux fenêtres d'instruction : une réservée aux µops mémoire (LOAD et STORE), l'autre pour les opérations entières/flottantes. Elles ont chacune 28 entrées, ce qui permet de mémoriser 56 µops au maximum. Là encore, précisons que les choses ne sont pas claires pour ce qui est de la séparation. L'article de Microprocessor report dit que les deux sont physiquement séparées, et que cette séparation physique permet de simplifications (les opérations mémorisent des noms de registres plus court que les adresses demandées par les µops LOAD/STORE). Mais l'autre document cité laisse penser que l''''Instruction Reorder Buffer'' est une structure unique. A chaque cycle, le processeur peut émettre deux instructions de calcul et deux instructions mémoire. Les deux fenêtres d'instruction ont pour cela chacune deux ports d'émission. Les deux prots d'émission pour les µops mémoire sont identiques, et peuvent faire aussi bien des µops LOAD que STORE. Le cache L1 est un cache double port, ce qui permet de faire deux lectures/écritures apr cycle, ce qui colle avec la double émision de µops mémoire. Pour ce qui est des µops entières/flottantes, le processeur a dupliqué toutes ses unités de calcul : il a deux ALU entières, deux ''barrel shifters'', deux FPU de type FMAC, et deux unités de division flottante. Vraisemblablement, il y a deux ports d'émission, chacun étant connecté à une unité de chaque type. Le partage des ports d'émission est donc parfait. En clair : le processeur aurait une superscalarité presque parfaite s'il était un CPU àç double émission ! A chaque cycle, la fenêtre d'instruction émet les deux µops les plus anciennes qui sont prête à être exécutées. La documentation dit que la fenêtre émet "la plus vielle instruction paire, et la plus vielle instruction impaire", ce qui sous-entend que la fenêtre d'instruction est en réalité composée de deux sous-fenêtres, une fenêtre paire et une impaire. Les µops sont insérées après le décodage dans ces sous-fenêtres : les deux µops sont réparties dans les deux. Et lors de l'émission, une µops vient d'une sous-fenêtre, une autre µops vient de l'autre. La fenêtre d’instruction a donc une structure partitionnée, avec une logique d'éveil segmentée, une partie gérant la moité de la fenêtre d'instruction, l'autre gérant le reste. [[File:PA 8000 - microarchitecture.png|centre|vignette|upright=2|PA 8000 - microarchitecture]] Le processeur utilise une implémentation ''Read After Issue'', ce qui veut dire que les opérandes des instructions sont lues après l'émission, juste avant l'exécution. La µops est émise, puis ses opérandes sont lues, pas l'inverse. Il n'y a pas de stations de réservation dans le processeur, les µops attendent que toutes leurs opérandes soient prêtes dans la fenêtre d'instruction, puis lisent les registres juste avant l'exécution Chaque fenêtre d'instruction pouvait recevoir 4 µops par cycle de la part des décodeurs, et répartissait ces 4 µops dans les deux fenêtres d'instructions. Les décodeurs, quant à eux, ne pouvaient décoder que 4 instructions/µops par cycle. Le processeur peut aussi ''commit'' deux opérations et deux accès mémoire par cycle, ce qui revient à transférer les résultat des registres de renommage vers les registres architecturaux. ===La superscalarité avec une file/fenêtre d'instruction centralisée=== Plus haut, nous avons montré qu'un processeur pouvait avoir plus de ports d'émission que de ports de décodage. On dit aussi que sa ''largeur de décodage'' était supérieure à sa ''largeur d'émission''. La '''largeur de décodage''' est le nombre de µops fournies par l'unité de décodage par cycle d'horloge, la '''largeur d'émission''' est le nombre maximal de µops émises par cycle d'horloge. Et n'allez pas croire qu'un surplus de ports d'émission est du gâchis. Sur les processeurs avec exécution dans le désordre, ce surplus peut être utilisé. Mais avant toute chose, évacuons un détail. Vous avez sans doute pensé que le surplus peut être exploité par les instructions machines décodées en plusieurs µops . Par exemple, si une instruction est décodée en deux µops, on pourrait avoir un port d'émission en plus pour en profiter. Mais les ports de décodage sont *en sortie du décodeur*, et contiennent des µops, pas des instructions. Le surplus de ports d'émission peut occasionnellement utiliser le surplus de ports de décodage, mais cela implique que des µops ont été mises en attente dans l'unité d'émission, pour être émises par la suite. Et cela implique l'usage d'une fenêtre d'instruction ou d'une file de µops. Le principe est que les µops sont accumulées dans la fenêtre d'instruction, en attendant leurs opérandes ou la résolution d'une dépendance. Et si l'occasion se présente, une µops est émise sur chaque port d'émission. Il y a donc un gain en performances, mais il faut faire quelques précisions sur son origine. La largeur d'émission utilisée ne peut pas dépasser, *en moyenne*, la largeur de décodage. Et c'est intuitif : un CPU qui décode 4 µops par cycle ne peut pas émettre 6 par cycle en moyenne, sur le temps long, il n'y a pas de µops en surplus qui sortent du vide. Par exemple, sur un processeur quadruple émission, si on analyse combien d'instructions sont émises par cycle, il peut y avoir des cycles où la largeur d'émission est totalement utilisée, mais ce sera compensé par des périodes où elle est fortement sous-utilisée. Les µops sont accumulées en cas de sous-utilisation, puis consommées en cas d'utilisation complète. Les deux périodes se compensent. Et c'est là que l'on peut comprendre d'où vient le gain en performance. Les cycles où les ports d'émission sont sous-utilisés existent systématiquement, que le processeur utilise l'exécution dans le désordre ou pas. Ils sont liés à la présence de dépendances de données, aux contraintes d’appariement, etc. Elles tendent à réduire la moyenne du nombre de µops émises par cycle. Par contre, ce sont les cycles de rattrapage, où les ports en surplus sont utilisés, qui font remonter la moyenne. Le gain en performance est donc lié à ces cycles de rattrapage, où les µops accumulées sont émises dans les ports en surplus. Et ils n'existent que sur les processeurs avec une file/fenêtre d'instruction. Réduire le nombre de ports d'émission permet de garder des fenêtres d'instruction et un ROB simples, rapides et économes en énergie. Et mine de rien, c'est là un compromis important : à quoi bon augmenter le nombre de ports d'émission si c'est pour que ce soit compensé par une fréquence plus faible ? Par contre, réduire le nombre de ports augmente la ''port contention'', surtout si on a mal réparti les ALU. Il faut donc trouver un compromis entre réduire le nombre de ports d'émission d'un côté, réduire la ''port contention'' de l'autre. La différence entre largeur de décodage et d'émission a un impact assez fort sur le banc de registre, et précisément sur son nombre de ports de lecture. Le banc de registre a besoin de plus de ports de lecture avec une fenêtre d’instruction qu'avec des stations de réservation. Rappelons la terminologie utilisée dans ce cours. Les fenêtres d'instruction se contentent de mémoriser la micro-opération et quelques bits pour détecter la disponibilité des opérandes. Par contre, les stations de réservations mémorisent aussi les opérandes des instructions. Et cette différence a une influence le nombre de ports de lecture du banc de registre. Supposons que toutes les instructions sont dyadiques, à deux opérandes. Comptons le nombre de ports nécessaires pour alimenter les unités de calcul, sans utiliser d'arbitre de banc de registre. Avec une fenêtre d'instruction, il faut le double du nombre de ports d'émission. Mais avec des stations de réservation, il faut le double des ports de décodage. La raison est que les registres sont lus après émission avec une fenêtre d'instruction, avant avec des stations de réservation (sous-entendu, après le décodage). Or, comme dit plus haut, les processeurs superscalaires larges ont souvent plus de ports d'émission que de décodage. ===La superscalarité à fenêtres d'instruction décentralisées=== Les processeurs précédents utilisaient une unité d'émission simple, qui pouvait utiliser l'émission dans l'ordre ou dans le désordre. Elle peut être remplacée par une fenêtre d'instruction centralisée dans que cela quoi que ce soit aux explications précédentes, idem avec une station de réservation centralisée. En soi, l'exécution dans le désordre est donc totalement compatible avec une implémentation simple de la superscalarité. Par contre, des subtilités surviennent avec les fenêtres d'instruction décentralisées. Pour rappel, sur ces processeurs, les µops sont émises en deux phases. Une première phase de ''dispatch'' qui envoie les µops vers la fenêtre d'instruction adéquate, sans détecter les dépendances de données. La seconde phase de ''schedule'' gère les dépendances de données, elle met en attente les µops en attendant que l'unité soit disponible pour les exécuter, en attendant aussi que les opérandes soient disponibles. Et à ce petit jeu, il y a une différence entre le nombre de µops qui sont ''dispatch par cycle'' et celles qui sont ''schedule''. Dit autrement, la largeur d'émission est scindée en une '''largeur de ''dispatch''''' et une '''largeur de ''schedule''. Par exemple, prenons un processeur triple émission avec deux stations de réservation : une pour les µops entières/mémoire, et une autre pour les µops flottantes. L'unité d'émission peut ''dispatch'' maximum trois µops par cycle : soit trois µops entières/mémoire, soit trois flottantes, soit un mix de trois µops différentes. Les stations de réservation, quant à elles, peuvent chacune ''schedule'' 3 µops par cycle, vers trois ALUs entières pour la station de réservation entière/mémoire, vers trois FPS pour la station de réservation flottante. De quoi ''dispatch'' trois µops, mais d'en ''schedule'' six, à chaque cycle. Et cet exemple ne sort pas de nulle part : les CPU x86 d'Intel et AMD sont globalement dans ce cas, même si les chiffres varient d'une microarchitecture à l'autre. L'exemple précédent colle parfaitement à la microarchitecture K7 d'AMD, utilisée sur les processeurs Athlon dans les années 2000. [[File:AMD K7.png|centre|vignette|upright=2.5|AMD K7, microarchitecture.]] L'exemple précédent avait assez d'unités entières/flottantes pour couvrir toute la largeur de décodage/''Dispatch''. Mais ce n'est pas toujours le cas, comme va le montrer l'exemple suivant. Le MIPS R10000, qui utilisait un mélange de files de µops et de fenêtres d'instructions : une file de µops les accès mémoire, une fenêtre pour les instructions entières et une autre pour les opérations flottantes. Les branchements et NOPs étaient exécutés dans une unité de branchement distincte. Les trois files/fenêtres peuvent mémoriser 16 µops. Le processeur avait deux ALU entières, une AGU de calcul d'adresse, un additionneur flottant et un multiplieur/diviseur flottant. Il y avait un multiplieur entier sur le port d'émission l'ALU 2. Le processeur décodait 4 instructions par cycle et produisait jusqu'à 4µops, qui étaient redistribuées sur les trois fenêtres d'instructions. Chacune pouvait accepter 4 µops par cycle, ce qui fait que processeur pouvait ''dispatch'' 4 µops entières, ou 4 µops flottantes, ou 4 µops mémoire, ou un mélange de deux ou trois types de µops. Pour ce qui est du ''schedule'', la fenêtre d'instruction entière pouvait émettre 2 µops, la fenêtre flottante pouvait émettre une addition en même temps qu'une multiplication/divison flottante et qu'un branchement conditionnel flottant, et la file de µops mémoire ne pouvait émettre qu'une µop mémoire à la fois. En tout, cela fait 6 µops ''schedule'' pour 4 µops au ''dispatch''. [[File:R 10000.png|centre|vignette|upright=2.5|MIPS R10000, microarchitecture.]] ===La superscalarité à fenêtres d'instruction totalement décentralisées=== Prenons un cas extrême de fenêtre d'instruction décentralisée : celui où chaque ALU entière a sa propre station de réservation. En clair : une fenêtre d'instruction par ALU/FPU ! On parle de '''fenêtres d'instruction totalement décentralisées'''. Vous vous dites que ce cas est un peu trop extrême pour être réaliste, mais il n'en est rien. C'est même très courant sur les architectures basse consommation, et sur pas mal de CPU x86 modernes. Une telle organisation entraine une légère perte de performance, comparé à une fenêtre d'instruction centralisée ou partiellement décentralisée. Et cela peut se comprendre par un exemple. Imaginez un processeur avec deux ALU, donc deux stations de réservation. Il arrivera qu'une station de réservation ait plusieurs µops prêtes, alors que l'autre en ait zéro. Dans une telle situation, une seule µop sera émise au cycle suivant, vu que chaque station de réservation a un seul port d'émission vers une seule ALU entière. Par contre, avec une fenêtre d'instruction centralisée double port, on aurait pu émettre les deux µops en même temps sur deux ALUs séparées. La perte de performance est donc liée au fait que les µops '''''prêtes''''' sont mal réparties dans les différentes stations de réservation. Il arrivera que des µops prêtes s'accumulent dans une station de réservation, alors que d'autres seront pleines, ou du moins sous-utilisées. Et ce n'est pas quelque chose qui peut être réglé à l'étape de ''dispatch'', car on ne sait pas encore quand les µops auront leurs opérandes de disponibles. [[File:Comparaison entre une station de réservation totalement décentralisée et une autre qui ne l'est pas.png|centre|vignette|upright=2.5|Comparaison entre une station de réservation totalement décentralisée et une autre qui ne l'est pas.]] Par contre, décentraliser totalement les fenêtres d'instruction entraine aussi un gain considérable en termes de consommation énergétique. Et c'est la raison pour laquelle les fenêtres d'instructions totalement décentralisées sont utilisées sur les architectures basse consommation. La perte de performance ne peut pas s'expliquer clairement à ce stade du cours, car il nous faudrait parler d'émission superscalaire. Le gain en matière d'énergie vient de l'économie de circuits, qui est assez drastique. Le gain en matière d'énergie vient de l'économie de circuits, qui est assez drastique. Je rappelle qu'une station de réservation a besoin, pour N instructions, d'environ N^2 circuits (des comparateurs, notamment). Prenons une station de réservation centralisée de 64 entrées et comparons avec 8 stations de 8 entrées chacune. Les deux donneront 64 entrées, mais la première aura un cout en circuit proportionnel à 64², alors que le second aura un cout en circuit de 8 *(8²). Entre les deux, le choix est clair : la seconde solution est plus économe. D'où l'utilisation de cette solution sur les microarchitectures basse consommation. ===L'unité de renommage superscalaire=== Avec la superscalarité, l'unité de renommage de registre doit gérer le cas où des instructions consécutives ont des dépendances de registre. Par exemple, prenons un processeur à double émission, qui renomme deux instructions consécutives. Si elles ont une dépendance de registre, le renommage de la seconde instruction dépend du renommage de la première. La première doit être renommée et le résultat du renommage est utilisé pour renommer la seconde, ce qui empêche d'utiliser deux unités de renommage séparées. Pour cela, elle renomme les registres sans tenir compte des dépendances, pour ensuite corriger le résultat. [[File:Unité de renommage superscalaire.png|centre|vignette|upright=2|Unité de renommage superscalaire.]] Seules les dépendances lecture-après-écriture doivent être détectées, les autres étant supprimées par le renommage de registres. Repérer ce genre de dépendances se fait assez simplement : il suffit de regarder si un registre de destination d'une instruction est un opérande d'une instruction suivante. [[File:Détection des dépendances sur un processeur superscalaire.png|centre|vignette|upright=2|Détection des dépendances sur un processeur superscalaire.]] Ensuite, il faut corriger le résultat du renommage en fonction des dépendances. Si une instruction n'a pas de dépendance avec une autre, on la laisse telle quelle. Dans le cas contraire, un registre opérande sera identique avec le registre de destination d'une instruction précédente. Dans ce cas, le registre opérande n'est pas le bon après renommage : on doit le remplacer par le registre de destination de l'instruction avec laquelle il y a dépendance. Cela se fait simplement en utilisant un multiplexeur dont les entrées sont reliées à l'unité de détection des dépendances. On doit faire ce replacement pour chaque registre opérande. [[File:Correction des dépendances sur un processeur superscalaire.png|centre|vignette|upright=2|Correction des dépendances sur un processeur superscalaire.]] ==Les optimisations des processeurs superscalaires larges== Les processeurs superscalaires larges ont des optimisations spécifiques, qui n'ont pas de sens sur les processeurs superscalaires étroits. Dans les grandes lignes, elles se classent en deux types. Les premières permettent de charger/décoder plus de 5-10 instructions simultanément. Le problème est alors que les branchements viennent mettre leur grain de sel et qu'il faut en tenir compte. Les secondes corrigent des problèmes qui apparaissent quand un CPU intègre plus de 5 à 10 unités de calcul. ===L'étape de chargement d'un CPU superscalaire large=== Charger plusieurs instructions pose de nombreux problèmes sur les processeurs superscalaires larges, qui émettent de 5 à 10 instructions simultanées. Pour rappel, la stratégie basique pour charger N instructions est de charger un bloc de N instructions consécutives. Les instructions après un branchement ne sont pas décodées ni exécutées, ce qui entraine une petite baisse de performance. Pour un N petit, la perte de performance est mineure. Mais pour un N large, elle devient suffisamment importante pour que la conception du CPU doit alors être repensée de fond en comble. Les analyses statistiques disent qu'il y a environ un branchement tous les 4 à 6 instructions. Un CPU a donc tendance à décoder des paquets de 3 à 5 instructions consécutives, avant qu'un branchement casse la dynamique. Or, cela pose des problèmes pour utiliser plusieurs décodeurs. L'implémentation basique, qui charge N instructions consécutives pour alimenter N décodeurs, fonctionne donc jusqu'à 4/6 décodeurs. Au-delà de 5 instructions, un CPU superscalaire doit être adapté pour gérer les branchements dans les paquets d'instruction qu'il émet. Le nombre de 5 instructions ne sort donc pas de nulle part. La première solution utilise un cache de µops, avec un ''front-end'' capable de charger/décoder 4/5 instructions à la fois, pas plus. L'idée est que la majorité des instructions proviennent du cache de µops (plus de 80%), ce qui fait qu'on peut émettre environ 10 instructions à partir du cache de µops, pas besoin d'avoir beaucoup de décodeurs. Les performances sont cependant dégradées lors d'un défaut de cache de µops. Les instructions doivent alors être chargées depuis le cache d'instruction, par paquets de 4-5, puis sont décodées par 4-5 décodeurs, ce qui ne permet pas d’alimenter les unités de calcul à plein régime. La solution précédente joue sur la distinction entre pots de décodage et d'émission. Elle permet d'émettre un grand nombre de µops sans pour autant charger un grand nombre d'instructions en même temps. En quelque sorte, ce n'est qu'une méthode de contournement, le CPU superscalaire reste de type étroit. Mais il est aussi possible d'utiliser un '''''front-end large''''', capable de charger une bonne dizaine d'instructions en même temps. La seule difficulté est de tenir compte de la présence de branchements. Pour rappel, avec un ''front-end'' étroit, les instructions situées après le premier branchement pris sont annulées, elles ne sont pas décodées ni exécutées. [[File:Fetch sur un processeur superscalaire avec prediction de branchements.png|centre|vignette|upright=2|Fetch sur un processeur superscalaire avec prédiction de branchements.]] Un ''front-end'' large charge les instructions de destination du branchement et les placent à sa suite. Ils chargent deux blocs à la fois et les fusionnent en un seul qui ne contient que les instructions présumées utiles. [[File:Cache d'instructions autoaligné.png|centre|vignette|upright=2|Cache d'instructions auto-aligné.]] Mais cela demande de charger deux blocs de mémoire en une fois, ce qui demande un cache d'instruction multiports. Il faut aussi ajouter un circuit pour assembler plusieurs morceaux de blocs en un seul : le fusionneur (''merger''). En pratique, cette solution demande d'ajouter un second port de lecture au cache, pour un cout en hardware important, avec un impact négatif sur le temps d'accès au cache. Et il faut rajouter le fusionneur, qui prend un étage de pipeline à lui tout seul. Et encore, cette solution ne gère pas le cas où un bloc contient plusieurs branchements ! [[File:Implémentation d'un cache d'instructions autoaligné.png|centre|vignette|upright=2|Implémentation d'un cache d'instructions auto-aligné.]] Les exemples précédents partent du principe qu'il n'y a qu'un seul branchement dans un bloc. Mais quand les blocs deviennent assez longs, il est fréquent d'avoir plusieurs branchements dans un bloc. Et il est même possible d'avoir plusieurs branchements pris. Dans un bloc de 8-10 instructions, ce n'est pas rare, et les CPU superscalaires à 8-10 voies sont la règle dans les CPU des années 2020. Pour gérer ce cas, il faut ajouter des ports supplémentaires au cache d'instruction et adapter le fusionneur, pour qu'il puisse fusionner trois ou quatre blocs. De plus, il faut utiliser une unité de prédiction de branchement capable de ''prédire plusieurs branchements par cycle''. ===Le décodage superscalaire large=== Le décodage des instructions n'est pas censé dépendre de l'implémentation du chargement. En théorie, une fois plusieurs blocs d'instruction fusionnés, on peut décoder les instructions en parallèle. Cependant, certains processeurs effectuent le décodage en tenant compte de la manière dont les branchements découpent les blocs. Les processeurs Atom d'Intel utilisent une solution de ce type, qui couple prédiction de branchement et décodage parallèle. Ils chargent/décodent des paquets de 3 instructions consécutives, chaque paquet étant séparé du précédent par un branchement. Pour cela, en plus d'avoir un fusionneur adapté, ils regroupent les décodeurs en ''clusters'', chacun regroupant 3 décodeurs, et pouvant décoder trois instructions consécutives. Les micro-architectures Tremont et Crestmont avaient deux ''clusters'' (6 décodeurs au total), la micro-architecture Darkmont en intègre trois (9 décodeurs au total). Avec deux ''clusters'', le fonctionnement est le suivant. Si le code est composé d'une suite d'instruction sans branchements, seul le premier ''cluster'' est utilisé, limitant le décodage à trois instructions par cycle. Par contre, si l'une des trois instructions décodée est un branchement, alors le second ''cluster'' décode les trois instructions situées après ce branchement, à partir de l'adresse de destination. Avec un troisième ''cluster'', c'est la même chose, sauf qu'il faut qu'il y ait un branchement dans les trois instructions décodées par le second ''cluster''. Mais comment faire pour savoir quels décodeurs activés, quels ''clusters'' sont actifs ? C'est la prédiction de branchement qui commande. Avec deux ''clusters'', elle détermine si un branchement est présent dans les trois instructions à charger, et quelle est son adresse de destination. Sans branchement, elle prévient les décodeurs et les trois instructions chargées sont décodées dans un ''cluster'' libre. Si elle prédit un branchement, elle charge les instructions adéquates, et active les deux ''clusters''. Avec trois branchements, c'est le même mécanisme, sauf que l'unité de prédiction de branchement doit être capable de prédire deux branchements par cycle. [[File:Front-end découplé de la microarchitecture Tremont.png|centre|vignette|upright=3|Front-end découplé de la microarchitecture Tremont.]] Il faut noter que les décodeurs d'un ''cluster'' sont des décodeurs simples, sans microcode. Sur les processeurs Tremont et Crestmont, le microcode était unique et était partagé entre tous les ''clusters''. Un seul ''cluster'' pouvait décoder une instruction complexe avec le microcode, l'autre devait se limiter à des instructions simples uniquement. Depuis Skymont, le microcode est partiellement dupliqué, avec un microcode par ''cluster''. Le cout en hardware peut paraitre prohibitif, pour un gain en performance faible. Sauf que c'est oublier que ce sont des processeurs Atom, sur lesquels beaucoup d'instructions sont microcodées. Les processeurs Atom ont un budget en transistor limité, ce qui fait qu'il est préférable pour eux d'implémenter des instructions en microcode que d'utiliser des unités de calcul dédiées ou des circuits de décodage complexes. Pour limiter la casse, le microcode n'est que partiellement dupliqué. Seul le microcode pour les instructions fréquente est dupliqué. Il y a un microcode secondaire pour certaines instructions, qui est lui unique et partagé par tous les ''clusters''. ===Le contournement sur les processeurs superscalaires larges=== Pour rappel, la technique du contournement (''register bypass'') permet au résultat d'une instruction d'être immédiatement utilisable en sortie de l'ALU, avant même d'être enregistré dans les registres. Implémenter la technique du contournement demande d'utiliser des multiplexeurs pour relier la sortie de l'unité de calcul sur son entrée si besoin. Il faut aussi des comparateurs pour détecter des dépendances de données. [[File:Pipeline Bypass.png|centre|vignette|upright=1|Pipeline Bypass]] La sortie de chaque ALU doit être reliée aux entrées de toutes les autres, avec les comparateurs qui vont avec. Sur les processeurs ayant plusieurs d'unités de calculs, cela demande beaucoup d’interconnexions et de comparateurs. Pour N unités de calcul, cela demande 2 * N² interconnexions, implémentées avec 2N multiplexeurs de N entrées chacun. Si c'est faisable pour 2 ou 3 ALUs, la solution est impraticable au-delà. Non seulement ce serait un enfer à câbler, mais les fils seraient tellement longs que la fréquence du processeur en prendrait un coup. Notez que cela vaut pour les processeurs superscalaires, mais aussi pour tout processeur avec beaucoup d'unités de calcul. En théorie, un CPU à exécution dans le désordre, non-superscalaire, mais avec beaucoup d'unités de calcul, fait face au même problème. En pratique, avoir une dizaine d'ALU implique processeur superscalaire à exécution dans le désordre. D'où le fait qu'on parle du problème maintenant. La seule solution praticable est de ne pas relier toutes les unités de calcul ensemble. À la place, on préfère regrouper les unités de calcul dans différents '''agglomérats''' ('''cluster'''). Le contournement est alors possible entre les unités d'un même agglomérat, mais pas entre agglomérats différents. Évidemment, certaines possibilités de contournement sont perdues, mais c'est compensé par un gain en fréquence et un cout en circuit/fils réduit. C'est un bon compromis, ce qui explique que presque tous les processeurs modernes l'utilisent. Les rares exceptions sont les processeurs POWER 4 et POWER 5, qui ont préféré se passer de contournement pour garder un processeur très simple et une fréquence élevée. ===Le banc de registre des processeurs superscalaires larges=== Pour émettre deux opérations entières simultanément, il faut lire deux fois plus d'opérandes. Et il faut aussi écrire deux résultats dans les registres, en même temps. Pour cela, on double les ports du banc de registre. En général, il faut au maximum 2 ports de lecture et un port d'écriture par unité de calcul. Le problème, c'est que plus un banc de registres a de ports, plus il utilise de circuits, est compliqué à concevoir, consomme de courant et chauffe. Avec plusieurs dizaines d'unités de calcul différentes, ajouter autant de ports impacterait la fréquence du banc de registres et réduirait les performances, voire est totalement impraticable à cause des contraintes thermiques. Les processeurs superscalaires larges doivent donc trouver des solutions. La première solution utilise un banc de registre unique, mais n'utilise pas autant de ports que le pire des cas le demanderait. Le processeur détecte quand il n'y a pas assez de ports pour servir toutes les micro-opérations. Quand ça arrive, l'unité d'émission émet assez de micro-opérations pour exploiter les ports disponibles, mais met en attente les micro-opérations en trop, le temps que les ports se libèrent. Pour cela, le banc de registre est géré par un circuit d'arbitrage spécialisé, intégré à l'unité d'émission, l’'''arbitre du banc de registres''' (''register file arbiter''). Une autre solution est de dupliquer le banc de registres en plusieurs exemplaires qui contiennent exactement les mêmes données, mais avec moins de ports de lecture/écriture. Un exemple est celui des processeurs POWER, Alpha 21264 et Alpha 21464. Sur ces processeurs, le banc de registre est dupliqué en plusieurs exemplaires, qui contiennent exactement les mêmes données. Les écritures dans les registres sont envoyées à tous les bancs de registres, afin de garantir que leur contenu est identique. Chaque exemplaire a exactement deux ports de lecture. La conception du processeur est simplifiée, que ce soit au niveau du câblage, que de la conception des bancs de registres. Une dernière solution découpe le banc de registres en plusieurs bancs de registres plus petits, avec un réseau d'interconnexions pour échanger des données entre bancs de registres. Dans la plupart des cas, cette séparation est invisible du point de vue de l'assembleur et du langage machine. Le processeur se charge de transférer les données entre bancs de registres suivant les besoins. Sur d'autres processeurs, les transferts de données se font via une instruction spéciale, souvent appelée ''COPY''. [[File:Banc de registres distribué.png|centre|vignette|upright=2|Banc de registres distribué.]] Sur de certains processeurs, un branchement est exécuté par une unité de calcul spécialisée. Or les registres à lire pour déterminer l'adresse de destination du branchement ne sont pas forcément dans le même agglomérat que cette unité de calcul. Pour éviter cela, certains processeurs disposent d'une unité de calcul des branchements dans chaque agglomérat. Dans les cas où plusieurs unités veulent modifier le ''program counter'' en même temps, un système de contrôle général décide quelle unité a la priorité sur les autres. Mais d'autres processeurs fonctionnent autrement : seul un agglomérat possède une unité de branchement, qui peut recevoir des résultats de tests de toutes les autres unités de calcul, quel que soit l’agglomérat. ==La macro-fusion : une optimisation du décodage parallèle== Les processeurs superscalaires supportent la technique dite de '''macro-fusion''', qui permet de fusionner deux-trois instructions consécutives en une seule micro-opération. Par exemple, il est possible fusionner une instruction de test et une instruction de saut en une seule micro-opération de branchement. Il s'agit là de l'utilisation la plus importante de la macro-fusion sur les processeurs x86 modernes. La macro-fusion est utilisée pour fusionner un test et un saut en un branchement unique. L'optimisation est présente sur la plupart des CPU superscalaires modernes. Les CPU x86 l'implémentent, mais aussi quelques CPU ARM et les processeurs Apple de série M (M1 à M5, et potentiellement plus quand ils seront sortis). La fusion des instructions se fait lors du décodage des instructions, grâce à la coopération des décodeurs. Elle marche systématiquement si l'instruction de test et le saut sont consécutives, qu'elles forment bien une paire d'instruction. Par contre, insérer une instruction entre les deux empêche la macro-fusion de faire son travail, sauf si l'instruction insérée est un NOP. Les processeurs ARM64 avaient une forme spécifique de macro-fusion, utilisée pour un cas très précis : charger une constante immédiate de 32 ou 64 bits, dans un registre 64 bits. Les CPU ARM 64 bits utilisent des instructions codées sur 32 bits, qui ne peuvent encoder que des constantes immédiates de 16 bits. Pour charger une constante de 32/64 bits, il faut s'y prendre en plusieurs fois. Une première instruction MOVZ charge les 16 premiers bits, puis 2 à 4 instructions MOVK remplissent le reste. MOVZ met à zéro les 48 bits de poids fort, MOVK permet de sélectionner le doublet à modifier dans le registre (on modifie 16 bits, dont on choisit la place, le reste du registre est laissé tel quel). ARM permet de fusionner cette suite d'instructions en une seule µop MOV avec une constante immédiate. On parle alors de '''''MOVZ + MOVK fusion'''''. Une dernière utilisation, [https://www2.eecs.berkeley.edu/Pubs/TechRpts/2016/EECS-2016-130.pdf proposées pour le jeu d'instruction RISC-V], fusionnait un calcul d'adresse et une instruction LOAD/STORE en une seule instruction d'accès mémoire. Elle a été envisagée à une époque où le jeu d'instruction RISC-V ne gérait pas les modes d'adressage base + indice. L'idée était d'avoir une unité mémoire qui gérait le mode d'adressage base + indice et de fusionner des instructions pour l'exploiter. Mais de nos jours, le jeu d'instruction RISC-V intègre le mode d'adressage base + indice, ce qui fait que la macro-fusion n'a aucun intérêt pour ce cas précis. La macro-fusion a de nombreuses limitations en pratique. En théorie, on pourrait l'utiliser au-delà des deux situations mentionnées plus haut. Par exemple, pour fusionner une addition et une multiplication en une seule instruction MAD. Mais l'intérêt est assez faible. Notons que la macro-fusion ne permet que de fusionner des paires d'instructions. Aller au-delà demanderait un cout en circuit trop important. Déjà que tester deux paires utilise pas mal de comparateurs... ==Le ''stack engine'' : une optimisation de la pile d'appel== Les processeurs modernes intègrent une optimisation liée au pointeur de pile. Pour rappel, sur les architectures modernes, le pointeur de pile est un registre utilisé pour gérer la pile d'appel, précisément pour savoir où se trouve le sommet de la pile. Il est manipulé par les instructions CALL, RET, PUSH et POP, mais aussi par les instructions d'addition/soustraction pour gérer des cadres de pile de taille variable. De plus, il peut servir d'opérande pour des instructions LOAD/STORE, afin de lire/écrire des variables locales, les arguments d'une fonction, et autres. C'est donc un registre général adressable, intégré au banc de registre, altéré par l'unité de calcul entière. L'incrémentation/décrémentation du pointeur de pile passe donc par l'unité de calcul, lors des instructions CALL, RET, PUSH et POP. Mais, l'optimisation que nous allons voir permet d'incrémenter/décrémenter le pointeur de pile sans passer par l'ALU, ou presque. L'idée est de s'inspirer des architectures avec une pile d'adresse de retour, qui intègrent le pointeur de pile dans le séquenceur et l'incrémentent avec un incrémenteur dédié. ===Le ''stack engine''=== L'optimisation que nous allons voir utilise un '''''stack engine''''' intégré à l'unité de contrôle, au séquenceur. Le processeur contient toujours un pointeur de pile dans le banc de registre, cela ne change pas. Par contre, il n'est pas incrémenté/décrémenté à chaque instruction CALL, RET, PUSH, POP. Un compteur intégré au séquenceur est incrémenté à la place, nous l’appellerons le '''compteur delta'''. La vraie valeur du pointeur de pile s'obtient en additionnant le compteur delta avec le registre dans le banc de registre. Précisons que si le compteur delta vaut zéro, la vraie valeur est dans le banc de registre et peut s'utiliser telle quelle. Lorsqu'une instruction ADD/SUB/LOAD/STORE utilise le pointeur de pile comme opérande, elle a besoin de la vraie valeur. Si elle n'est pas dans le banc de registre, le séquenceur déclenche l'addition compteur-registre pour calculer la vraie valeur. Finalement, le banc de registre contient alors la bonne valeur et l'instruction peut s'exécuter sans encombre. L'idée est que le pointeur de pile est généralement altéré par une série d'instruction PUSH/POP consécutives, puis des instructions LOAD/STORE/ADD/SUB utilisent le pointeur de pile final comme opérande. En clair, une bonne partie des incrémentations/décrémentation est accumulée dans le compteur delta, puis la vraie valeur est calculée une fois pour toutes et est utilisée comme opérande. On accumule un delta dans le compteur delta, et ce compteur delta est additionné quand nécessaire. Précisons que le compteur delta est placé juste après le décodeur d'instruction, avant même le cache de micro-opération, l'unité de renommage et l'unité d'émission. Ainsi, les incrémentations/décrémentations du pointeur de pile disparaissent dès l'unité de décodage. Elles ne prennent pas de place dans le cache de micro-opération, ni dans la fenêtre d'instruction, ni dans la suite du pipeline. De nombreuses ressources sont économisées dans le ''front-end''. Mais utiliser un ''stack engine'' a aussi de nombreux avantages au niveau du chemin de données/''back-end''. Déjà, sur les processeurs à exécution dans le désordre, cela libère une unité de calcul qui peut être utilisée pour faire d'autres calculs. Ensuite, le compteur delta mémorise un delta assez court, de 8 bits sur le processeur Pentium M, un peu plus pour les suivants. L'incrémentation se fait donc via un incrémenteur 8 bits, pas une grosse ALU 32/64 bits. Il y a un gain en termes de consommation d'énergie, un incrémenteur 8 bits étant moins gourmand qu'une grosse ALU 32/64 bits. ===Les points de synchronisation du delta=== La technique ne fonctionne que si la vraie valeur du pointeur de pile est calculée au bon moment, avant chaque utilisation pertinente. Il y a donc des '''points de synchronisation''' qui forcent le calcul de la vraie valeur. Plus haut, nous avions dit que c'était à chaque fois qu'une instruction adresse le pointeur de pile explicitement, qui l'utilise comme opérande. Les instructions CALL, RET, PUSH et POP ne sont pas concernées par elles utilisent le pointeur de pile de manière implicite et ne font que l'incrémenter/décrémenter. Mais dans les faits, c'est plus compliqué. D'autres situations peuvent forcer une synchronisation, notamment un débordement du compteur delta. Le compteur delta est généralement un compteur de 8 bits, ce qui fait qu'il peut déborder. En cas de débordement du compteur, le séquenceur déclenche le calcul de la vraie valeur, puis réinitialise le compteur delta. La vraie valeur est donc calculée en avance dans ce cas précis. Précisons qu'un compteur delta de 8 bits permet de gérer environ 30 instructions PUSH/POP consécutives, ce qui rend les débordements de compteur delta assez peu fréquent. À noter que si le compteur delta vaut zéro, il n'y a pas besoin de calculer la vraie valeur, le séquenceur prend cette situation en compte. Un autre point de synchronisation est celui des interruptions et exceptions matérielles. Il faut que le compteur delta soit sauvegardé lors d'une interruption et restauré quand elle se termine. Idem lors d'une commutation de contexte, quand on passe d'un programme à un autre. Pour cela, le processeur peut déclencher le calcul de la vraie valeur lors d'une interruption, avant de sauvegarder les registres. Pour cela, le processeur intègre un mécanisme de sauvegarde automatique, qui mémorise la valeur de ce compteur dans le tampon de réordonnancement, pour forcer le calcul de la vraie valeur en cas de problème. La technique du ''stack engine'' est apparue sur les processeurs Pentium M d'Intel et les processeurs K10 d'AMD, et a été conservée sur tous les modèles ultérieurs. L'implémentation est cependant différente selon les processeurs, bien qu'on n'en connaisse pas les détails et que l'on doive se contenter des résultats de micro-benchmarks et des détails fournit par Intel et AMD. Selon certaines sources, dont les manuels d'optimisation d'Agner Fog, les processeurs AMD auraient moins de points de synchronisation que les processeurs Intel. De plus, leur ''stack engine'' serait placé plus loin que prévu dans le pipeline, après la file de micro-opération. ==La micro-fusion et la délamination== La '''micro-fusion''' est une optimisation qui retarde le décodage réel de certaines instructions assez loin dans le pipeline. Elle concerne surtout les instructions ''load-op'', mais pas que. D'autres instructions mémoire peuvent subir cette optimisation. L'essentiel est que, sans micro-fusion, ces instructions sont décodées en plusieurs micro-opérations. La micro-fusion retarde le décodage final de ces instructions, qui se fait assez tard dans le pipeline. Pour comprendre l'intérêt, nous allons devoir faire quelques explications. L'optimisation en question fait le décodage en deux temps. Prenons l'exemple d'une opération ''load-op'', qui est censée être décodée en deux micro-opérations : une lecture, puis une opération. Le décodage produit une '''macro-opération''' (terme d'Intel), qui est propagée dans le pipeline, pour être scindée en deux micro-opérations un peu avant les ALU et l'unité mémoire. La macro-opération est techniquement une micro-opération comme une autre, sauf que ce n'est pas la micro-opération finale. L'unité d'émission découpe cette macro-opération en deux micro-opérations, qui sont émises l'une après l'autre. Pour résumer, les instructions ''load-op'' ne sont complétement découpées en micro-opération lors de l'émission, pas lors du décodage. L'optimisation impacte ce qui se situe entre le décodeur d'instruction et l'unité d'émission : l'unité de renommage, la file de micro-opérations, le ''Loop Stream Detector'' et/ou le cache de micro-opération. L'intérêt de l'optimisation est que l'on fusionne deux micro-opérations en une seule macro-opération. Le cache de micro-opération et la file de micro-opération peuvent mémoriser plus de micro-opérations, vu que certaines sont fusionnées. Quant à l'unité de renommage, elle renomme une seule macro-opération au lieu de renommer deux micro-opérations, ce qui augmente le débit du renommage de registre. Par contre, cela complique un peu le travail de l'unité d'émission, qui doit découper les instructions ''load-op'' en deux et émettre les micro-opérations l'une après l'autre. Il faut noter qu'il n'y a pas de fusion proprement dite. Le décodeur ne décode pas deux micro-opérations séparées, avant de les fusionner. En réalité, il génère directement une macro-opération, qui correspond à deux micro-opérations, que ce soit plus tard dans le pipeline ou sur une autre architecture. D'ailleurs, la micro-fusion a lieu à l'intérieur d'une instruction, qui est censée être traduite en plusieurs micro-opérations. Et encore : pas toutes. La conséquence est que la technique n'a de sens que sur les processeurs CISC, avec des instructions assez complexes pour être décodées en plusieurs micro-opérations. En pratique, seuls les CPU x86 sont concernés. ===Les domaines de fusion=== La micro-fusion n'est pas spécifique aux processeurs superscalaires. En théorie, on peut l'implémenter sur un processeur non-superscalaire à émission dans l'ordre. Cependant, je ne connais aucun processeur à émission dans l'ordre qui implémente la micro-fusion, même si son implémentation est en théorie possible sur de tels processeurs. La micro-fusion est implémentée différemment selon que l'émission se fasse dans l'ordre, dans le désordre, avec une fenêtre d'instruction, avec des stations de réservation, etc. J'ai dit plus haut que les micro-opérations sont générées lors de l'émission, mais le moment exact varie suivant le processeur. Pour simplifier le tout, nous parlerons de '''scission''' quand le processeur traduit une macro-opération en deux/trois micro-opérations. Le moment où a lieu la scission est théoriquement dans l'unité d'émission, mais celle-ci prend plusieurs formes selon que le processeur utilise l'émission dans l'ordre, dans le désordre, avec une fenêtre d'instruction, avec des stations de réservation, etc. Les processeurs à exécution dans l'ordre sont le cas le plus simple. L'unité d'émission est alors en charge du découpage des macro-opérations en micro-opérations. La file de micro-opération ou le cache de micro-opérations mémorisent des macro-opérations. À l'opposé, le tampon de ré-ordonnancement mémorise lui des micro-opérations. Le reste du processeur n'est pas affecté. Sur les processeurs à exécution dans le désordre, les différences sont nombreuses. Le tampon de ré-ordonnancement peut mémoriser soit les micro-opérations finales, soit des macro-opérations. Il en est de même avec la fenêtre d'instruction et/ou les stations de réservation, qu'elles soient centralisées ou décentralisées. Tout dépend de comment se fait l'implémentation. Une implémentation simple effectue la scission des macro-opérations dans l'unité d'émission, comme sur les processeurs à exécution dans l'ordre. Sur de nombreux processeurs, l'unité d'émission et de renommage sont simplement fusionnées, ce qui fait que la scission a lieu juste après le renommage de registres. En conséquence, le tampon de re-ordonnancement et les fenêtres d'instruction ne voient que des micro-opérations. Les macro-opérations disparaissent juste avant. Cette implémentation est préférée avec une fenêtre d'instruction centralisée, car on voit mal comment scinder une macro-opération juste avant l'ALU. Une autre implémentation fait la scission en sortie de la fenêtre d'instruction ou des stations de réservation, qu'elles soient centralisées ou décentralisées. Dans ce cas, le tampon de re-ordonnancement fait de même. L'avantage est que le tampon de ré-ordonnancement stocke des macro-opérations, ce qui augmente sa taille effective. Par exemple, il utilise une seule entrée pour une instruction ''load-op'', au lieu de deux sans micro-fusion de ce type. ===La délamination=== La scission peut parfois avoir lieu plus tôt, dans des circonstances très précises. Concrètement, cela ne concerne que quelques micro-architectures d'Intel, pour des instructions très précises. La raison est les limitations du format des micro-opérations, pas une histoire d'optimisation. Le processeur aimerait pouvoir faire la micro-fusion, mais ne peut pas à cause de ces limitations. Une telle situation cause alors une '''délamination''' : les micro-opérations sont scindées précocement. Par exemple, sur la micro-architecture SandyBridge d'Intel, les opérations ''load-op'' sont fusionnées, sauf si elles utilisent l'adressage indicé. Les micro-opérations de ce processeur ne peuvent avoir que deux opérandes. Trois opérandes est de trop, et les opérations ''load-op'' en adressage indicé dépassent cette limite. Dans ce cas, les micro-opérations sont fusionnées en sortie du décodeur, mais sont scindés avant d’entrer dans la file de micro-opération. L'avantage n'est pas évident, vu que l'unité de renommage suit de près le décodeur d'instruction. Il est que le cache de micro-opérations mémorise des macro-opérations, pas deux micro-opérations. ===La micro-fusion des processeurs Intel et AMD=== La micro-fusion est apparue sur le Pentium M d'Intel, et a été conservée telle quelle sur les processeurs Intel suivants. Les processeurs AMD supportent la micro-fusion depuis au moins la micro-architecture AMD K8. Mieux que ça, la délamination n'était pas utilisée car les micro-opérations acceptaient plus de 2 opérandes. Que ce soit chez AMD ou Intel, elle concerne deux types d'instructions : les écritures mémoire et les instructions ''load-op''. Sur le Pentium M, il y avait quelques limitations, l'optimisation se limitant par exemple aux registres entiers et flottants, mais pas aux registres MMX, mais pas les registres SSE (nous verrons ces registres dans quelques chapitres). Mais les processeurs modernes n'ont plus cette limitation. La micro-fusion des CPU Intel concerne deux types d'instructions : les écritures mémoire et les instructions ''load-op''. Pour les écritures, la situation est plus complexe que pour les instructions ''load-op''. Sur les processeurs Intel précédents, les écritures étaient réalisées dans deux unités séparées : le calcul d'adresse dans une unité de calcul, l'écriture proprement dite dans l'unité mémoire. Elles prenaient donc deux micro-opérations. Le processeur a changé ses unités mémoire, ce qui fait qu'elle pouvait faire les deux en une seule micro-opération. Il s'agissait alors d'une optimisation du chemin de données, plus que de la micro-fusion proprement dite, mais je la mentionne ici malgré tout. La micro-fusion sur ce processeur avait un avantage en plus des avantages usuels : elle utilisait mieux les décodeurs. Les Pentium M avaient trois décodeurs pour décoder plusieurs instructions en même temps, chose qu'on détaillera dans le chapitre sur les processeurs superscalaires. Un seul décodeur pouvait décoder toutes les instructions, les deux autres ne peuvent décoder que les instructions simples, qui se décodent en une seule micro-opération. Avec la micro-fusion, les trois décodeurs peuvent gérer les écritures mémoire et les opérations ''load-op'', vu qu'elles deviennent des instructions simples. Sans cela, elles auraient été limitées au premier décodeur. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Le parallélisme mémoire | prevText=Le parallélisme mémoire | next=Les microarchitectures pour le x86 : haute performance | nextText=Les microarchitectures pour le x86 : haute performance }} </noinclude> 0jtxqnpfwxh8z4dq5fh2gthl1g2p7tr 773580 773579 2026-09-29T16:46:35Z Mewtow 31375 /* L'exemple du PA-RISC PA 8000 */ 773580 wikitext text/x-wiki Les processeurs vus auparavant ne peuvent émettre au maximum qu'une instruction par cycle d'horloge. Ils peuvent avoir plusieurs instructions qui s'exécutent en même temps, dans des unités de calcul séparées. C'est le cas dès qu'une instruction multi-cycles s'exécute. Par contre, ils ne peuvent démarrer qu'une seule instruction par cycle. Et quand on court après la performance, ce n'est pas assez ! Les concepteurs de processeurs ont inventés des processeurs qui émettent plusieurs instructions par cycle : les '''processeurs à émissions multiples'''. Un processeur à émission multiple charge plusieurs instructions en même temps, les décode en parallèle, puis les émet en même temps sur des unités de calculs séparées. Pour cela, il faut gérer les dépendances entre instructions, répartir les instructions sur différentes unités de calcul, et cela n'est pas une mince affaire. En général, pour un processeur à émission multiple capable d'émettre N instructions en parallèle, on parle de '''processeur à N voies''', ou encore un ''processeur à N pipelines''. [[File:Superscalarpipeline.svg|centre|vignette|upright=1.5|Pipeline RISC classique à cinq étages sur un processeur superscalaire. On voit bien que plusieurs instructions sont chargées en même temps.]] Les processeurs à émission multiple sont de deux types : les processeurs VLIW et les '''processeurs superscalaires'''. Nous mettons les processeurs VLIW de côté en attendant le prochain chapitre. La raison est qu'ils ont un jeu d'instruction spécialisé qui expose le parallélisme d'instruction directement au niveau du jeu d'instructions, là où les processeurs superscalaires restent des processeurs au jeu d'instruction normal. La différence principale entre processeur VLIW et superscalaire est qu'un processeur superscalaire répartit les instructions sur les unités de calcul à l’exécution, là où un processeur VLIW délègue cette tâche au compilateur. ==Le nombre de voies d'un processeur superscalaire== Les processeurs superscalaires les plus simples ne permettent que d'émettre deux micro-opérations à la fois, d'où leur nom de processeur ''dual issue'', ce qui se traduit en '''processeur à double émission'''. Les processeurs triple émission permettent eux d’émettre trois instructions à la fois. A l'opposé, les CPU superscalaires les plus puissants peuvent émettre jusqu'à 8-10 instructions simultanément. En 2026, les CPU superscalaires peuvent monter jusqu’à 10 µops émises en même temps, ce qui est énorme ! Et cela nous amène à faire une distinction entre les processeurs superscalaires dits '''étroits''' et ceux dits '''larges'''. Dans ce wikilivre, on part du principe que les processeurs superscalaires étroits émettent jusqu'à 4-5 µops à la fois, alors que les larges peuvent en émettre plus, l'intervalle entre les deux est une zone grise. Le nombre exact n'est pas fixé dans le marbre, la distinction est volontairement vague. Nous parlerons de la '''largeur d'un CPU superscalaire''' pour parler du nombre de voies, du nombre de µops émises en même temps. Plus un CPU superscalaire est large, plus il est performant ''toute chose égale par ailleurs''. Mais dans les faits, vous pouvez oublier la partie en italique. Élargir un CPU superscalaire demande de rajouter beaucoup de circuits. Et ce cout en circuit aura un impact sur la performance. A budget en transistors limité, il y a un compromis entre élargir un CPU et rajouter du cache ou la taille des fenêtres d'instructions/ROB et autres. ===Les contraintes d’appariement=== Prenons un processeur double émission, capable d'émettre deux instructions simultanément. Émettre deux instructions en même temps n'est pas toujours possible. Par exemple, si deux instructions sont dépendantes, on ne peut pas les émettre en même temps. Mais oublions un instant ces histoires de dépendances de données, et partons du principe que le CPU ait affaire à deux instructions indépendantes, une paire idéale. Un CPU double émission "parfait" pourrait exécuter n'importe quelle paire d'instruction. Par exemple, il pourrait émettre deux multiplications consécutives, deux lectures consécutives, une lecture et une écriture en même temps, etc. En pratique, aucun processeur ne permet cela. Implémenter un CPU superscalaire "parfait" aurait un cout en circuit beaucoup trop conséquent. Par exemple, pour émettre deux multiplications en même temps, il faudrait deux multiplieurs séparés. Idem pour exécuter deux accès mémoire simultané : cela demande d'avoir deux unités mémoire et un cache multiport. Mais en pratique, aucun CPU superscalaire ne fait cela. La totalité des CPU double émission se débrouille avec un seul circuit multiplieur et une seule unité mémoire. Et cela entraine l'apparition de dépendances structurelles, qui font que certaines paires d'instructions sont impossibles. Par exemple, impossible d'émettre deux multiplications en même temps avec un seul circuit multiplieur. Mais émettre une multiplication en parallèle d'une addition est parfaitement possible. Il y a donc des paires d'instructions autorisées et des paires interdites. Et la logique est la même sur les CPU à triple ou quadruple émission, et au-delà. : des triplets ou quadruplet d'instructions sont impossibles à émettre simultanément, alors que d'autres le sont. Pour le dire autrement, il y a des '''contraintes d'appariement''' sur les instructions à émettre en même temps. ===L'impact des contraintes d’appariement sur la performance=== Ces contraintes d’appariement ont un impact sur les performance, mais celui-ci peut être grandement mitigé. Les programmes informatiques utilisent en pratique beaucoup plus d'opérations entières de base que de multiplication, branchements et accès mémoire. Il y a environ 5 opérations entières de base pour une multiplication entière. En pratique, il est rare de devoir exécuter deux multiplications à la fois. Idem pour les décalages et rotations, qui sont assez éloignés les uns des autres. Deux branchements consécutifs sont quant à eux plus fréquents. Deux accès mémoire consécutifs est assez rare, mais ils restent assez proches les uns des autres malgré tout. La conséquence est que certaines paires d'instructions sont privilégiées par rapport au reste. Les paires regroupant deux calculs basiques (additions, soustractions, ...) sont systématiquement supportées, car dupliquer des ALU entières est facile. Les paires regroupant un calcul et une autre instruction sont elles aussi systématiquement supportées. Par contre, les paires avec deux branchements, deux accès mémoire, deux décalages/rotations, ou deux multiplications/divisions sont fréquemment interdites. Seuls les CPU superscalaires larges peuvent les permettre, et encore : sous conditions. Le résultat est que le processeur peut se débrouiller avec une seule unité mémoire et une unité de branchement. ===Terminologie pour la suite du chapitre=== Décrire les contraintes d’appariement demande de dire quelles combinaisons d’instructions sont autorisées ou interdites. Et pour cela, nous allons introduire les abréviations suivantes : * INT est un raccourcis pour parler d'une opération entière simple, qu'une ALU entière peut exécuter. * MUL correspond à une opération entière complexe, typiquement une multiplication, éventuellement à une division. * FLOAT désigne une opération flottante, peut importe laquelle. * MEM désigne un accès mémoire, à savoir une instruction ou µop mémoire. * BRANCH désigne une instruction de branchement. Cette terminologie permettra de définir des paires d'instructions, qu'elles soient possibles ou interdites. Par exemple, l'expression INT + FLOAT désigne une paire d'instruction regroupant une instruction entière et une instruction flottante, peu importe l'ordre des deux instructions. Il en sera de même pour les triplets, quadruplets, ou plus. Par exemple, l'expression INT + INT + FLOAT + MUL désigne un quadruplet d'instructions regroupant : deux instructions entières, une instruction flottante, et une multiplication entière. J'utiliserais aussi des parenthèses pour regrouper certaines combinaisons. Par exemple, l'expression INT + (MUL /FLOAT) veut parler d'une paire d'instruction où la première est une opération entière basique, la seconde est : soit une multiplication, soit une opération flottante. ==Le ''front-end'' des processeurs superscalaires== Un processeur superscalaire doit charger, décoder, et exécuter plusieurs instructions par cycle. Par exemple, un processeur triple émission doit charger 3 instructions lors d'un premier cycle, puis les décoder au cycle suivant, et les exécuter au cycle suivant. Il travaille donc pas paquets de 3 instructions, dans cet exemple. Intuitivement, charger, décoder et exécuter plusieurs instructions à la fois demande de dupliquer des circuits. Par exemple, il faut dupliquer les décodeurs pour décoder plusieurs instructions. Les unités de calcul sont aussi dupliquées, sauf sur certaines processeurs qui arrivent à ruser, mais laissons cela de côté pour plus tard. Mais d'autres circuits sont simplement modifiés, comme l'unité de chargement ou l'unité d'émission. Voyons ce qu'il en est dans le détail. {|class="wikitable" |- ! rowspan="2" | Processeur sans émission multiple | rowspan="2" | Chargement | rowspan="2" | Décodage | rowspan="2" | Renommage | rowspan="2" | Émission | Exécution / ALU | rowspan="2" | ''Commit''/ROB |- | Exécution / ALU |- ! rowspan="4" | Processeur superscalaire | rowspan="4" | Chargement | rowspan="2" | Décodage | rowspan="4" | Renommage | rowspan="4" | Émission | Exécution / ALU | rowspan="4" | ''Commit''/ROB |- | Exécution / ALU |- | rowspan="2" | Décodage | Exécution / ALU |- | Exécution / ALU |} Nous allons d'abord voir ce qu'il en est pour le ''front-end'', à savoir la partie du CPU qui s'occupe de charger et décoder les instructions. Elle regroupe l'unité de chargement, les décodeurs, l'unité de prédiction de branchement, la file de µops, la file d'instruction, et divers caches. En soi, les changements portent surtout sur l'unité de chargement et les décodeurs. ===Le chargement de plusieurs instructions consécutives=== Un processeur superscalaire charge plusieurs instructions en même temps, ''en tenant compte de la présence de branchements''. La partie en italique est importante et elle a une conséquence très forte : la manière de faire est fortement différente entre un CPU superscalaire étroit et large. Un CPU superscalaire étroit fait au plus simple : il charge un bloc de 2, 3, 4 instructions consécutives en mémoire RAM. Il faut alors doubler/tripler/quadrupler la taille du bus connecté au cache d'instruction. Par exemple, pour charger quatre instructions de 32 bits chacune, il suffit de lire un bloc de 128 bits dans le cache d'instruction. Un bloc de 8, 16, 32 octets est donc lu depuis le cache et est ensuite découpé en instructions, envoyées chacun à un décodeur. Charger plusieurs instructions consécutives ne marche bien qu'en absence de branchements. La présence de branchements casse cette dynamique, et il faut gérer leur présence. * Sans prédiction de branchement, toutes les instructions d'un bloc sont décodées et exécutées en même temps, même s'il y a un branchement dans le tas. * Avec prédiction de branchement, les instructions situées après le branchement ne sont pas décodées ni exécutées. L'unité de chargement coupe le bloc chargé au niveau du premier branchement pris, remplit les vides avec des NOP, avant d'envoyer le tout à l'unité de décodage. Les instructions à l'adresse de destination seront chargées au cycle suivant, en chargeant un nouveau bloc. [[File:Fetch sur un processeur superscalaire avec prediction de branchements.png|centre|vignette|upright=2|Fetch sur un processeur superscalaire avec prédiction de branchements.]] Un autre défaut est que sur le CPU charge un bloc de 128 bits à la fois, les instructions doivent être alignées sur 128 bits. Et on peut généraliser à n'importe quelle taille de bloc. Si les instructions ne sont pas alignées, il faut gérer la situation. Il arrive qu'une instruction soit à cheval sur deux blocs, avec un morceau dans le premier bloc, un autre dans le second. Dans ce cas, l'instruction est chargée en deux fois, et des circuits doivent gérer la situation pour recoller les morceaux. Sur les CPU avec des instructions de taille fixe, le problème ne survient que rarement. Mais il est fréquent avec des instructions de taille variable. Un autre défaut est lié aux branchements. Imaginez qu'un branchement s'exécute et branche vers une instruction de destination. Rien n'indique que l'instruction de destination sera au tout début d'un bloc. Si ça se trouve, elle sera en troisième position d'un bloc de 4 instructions. Une solution simple charge le bloc en respectant l'alignement, et les deux premières instructions du bloc ne sont pas à exécuter. Il y a donc une petite perte de performance. Certains CPU, comme l'IBM RS/6000, ont la machinerie charger un bloc de N instructions même s'il n'est pas aligné. La machinerie en question se trouve dans le cache d'instruction et est tout sauf simple à expliquer,ce qui fait que je me permets de la passer sous silence. Un détail, cependant : elle ne permet pas de charger des blocs qui sont à cheval sur deux lignes de cache. ===Le décodage parallèle des instructions=== Pour le décodage des instructions, plusieurs instructions sont décodées en même temps. On parle alors de '''décodage parallèle'''. Pour ce faire, un processeur superscalaire contient plusieurs décodeurs, chacun pouvant décoder une instruction en parallèle des autres. Prenons par exemple un processeur superscalaire à 4 voies : le décodage se fera dans quatre décodeurs séparés, qui fonctionneront en parallèle. Cependant, cette implémentation ne marche bien que pour les processeurs RISC, les processeurs CISC devant faire avec un microcode gourmand en circuits. Les processeurs CISC utilisent des décodeurs hybrides, avec un microcode qui complémente un décodeur câblé. Dupliquer le microcode aurait un cout en transistors trop important, ce qui fait que seuls les décodeurs câblés sont dupliqués. Les CPU CISC superscalaires disposent donc de plusieurs décodeurs simples, capables de décoder les instructions les plus courantes, avec un seul microcode. La conséquence est qu'il n'est pas possible de décoder deux instructions microcodées en même temps. Par contre, il reste possible de décoder plusieurs instructions non-microcodées ou une instruction microcodée couplée à une instruction non-microcodée. Vu qu'il est rare que deux instructions microcodées se suivent dans un programme, le cout en performance est extrêmement mineur. Il faut noter qu'une instruction correspond à une ou plusieurs µops. Il est donc possible de charger 5 instructions et de se retrouver avec 8 µops en sortie des décodeurs. Et c'est la source d'une distinction très importante. Plus haut, j'ai parlé de processeurs superscalaires à N voies. La terminologie peut avoir deux interprétations. La première est que le processeur charge/décode N instructions à la fois. Une seconde est qu'il est capable d'exécuter/émettre N µops en même temps. Les deux ne sont pas équivalentes, vu qu'un processeur superscalaire peut, par exemple, charger/décoder N instructions et émettre/exécuter N+2 µops. La distinction est particulièrement importante sur les processeurs superscalaires larges. Certains d'entre eux sont capables de charger 5 instructions et d'en émettre le double ! Un exemple classique était les processeurs Athlon d'AMD, qui pouvaient décoder deux instructions par cycle, mais émettre 4 µops par cycle. Ce n'était pas un problème, car beaucoup d'instructions, même basiques, étaient décodées en 2 µops. ===L'émission parallèle des instructions=== La superscalarité modifie en profondeur l'unité d'émission, notamment au niveau de son interface. Avant, elle recevait une micro-opération sur son entrée, et fournissait la micro-opération émise sur une sortie. Et cela vaut aussi bien pour une unité d'émission simple, un ''scoreboard'', une fenêtre d'instruction ou des stations de réservation. Mais avec l'émission multiple, les sorties et entrées sont dupliquées. Pour la double émission, il y a deux entrées vu qu'elle doit recevoir deux micro-opération décodées/renommées, et deux sorties pour émettre deux micro-opérations. Dans ce qui suit, nous ne parlerons pas d'entrée et de sortie, mais de '''ports de décodage''' et de '''ports d'émission'''. Les ports de décodage reçoivent des micro-opérations provenant de l'unité de décodage, les ports d'émissions sont pour les micro-opérations émises. Les ports d'émission injectent les micro-opérations émises dans le pipeline, elle sont propagée au banc de registre, aux ALUs, etc. Un processeur superscalaire a forcément plusieurs ports d'émission (et de décodage). Si l'interface de l'unité d'émission change, l'intérieur est tout autant modifié. Sur un CPU non-superscalaire, l'unité d'émission reçoit une µop "candidate à l'émission", et détecte les dépendances entre avec les µops en vol, en cours d'exécution dans le pipeline. Et c'est toujours le cas sur les processeurs superscalaires : l'unité d'émission détecte les dépendances entre les µops candidates et les µops en vol. Mais avec la siperscalarité, elle doit en plus tester les dépendances entre les µops candidates. Si l'unité d'émission est un ''scoreboard'', il doit détecter les dépendances entre instructions émises simultanément et les sérialiser si besoin. Avec une fenêtre d'instruction, il n'y a pour ainsi dire rien à faire, vu que les dépendances sont éliminées par le renommage de registre et que les signaux de réveil gèrent les dépendances RAW. C'est la raison pour laquelle les processeurs superscalaires modernes n'utilisent pas de ''scoreboard''. ==Les processeurs implémentés avec plusieurs pipelines== Nous venons de voir comment la superscalarité impacte le ''front-end'', il est maintenant de voir ce qu'il en est de l'unité d'émission et des ''back-ends''. Un processeur superscalaire peut utiliser l'exécution dans le désordre et le renommage de registres, mais ce n'est pas une obligation. Historiquement, les premiers processeurs superscalaires n'utilisaient pas d'exécution dans le désordre. Le meilleur exemple est celui du Pentium 1 et 2 d'Intel. Ils étaient tous deux des processeurs superscalaires, mais n'avaient pas d'exécution dans le désordre, qui est apparue sur le Pentium 3. les explications sont plus simples si on met de côté l'exécution dans le désordre. Vous vous dites que l'implémentation d'un processeur superscalaire n'est pas la même suivant que le CPU utilise l'exécution dans le désordre, ou non. Mais dans les faits, la distinction est plus subtile que ca. Pour l'expliquer, je vais utiliser une classification originale, qui sépare les processeurs superscalaires en trois sous-types. La distinction se fait sur la manière dont la superscalarité est implémentée en matériel.La classification que j'utilise distingue : * Les processeurs avec plusieurs pipelines, sans exécution dans le désordre. * Les processeurs superscalaires avec un pipeline dynamique. * Les processeurs avec des fenêtres d'instruction décentralisées. La distinction n'est pas qu'une question d'implémentation matérielle. Elle impacte aussi le ratio entre instructions chargées/décodées et instructions émises. Vous vous dites que les deux sont égales, mais ce n'est le cas que sur les processeurs avec N pipelines ! Sur les autres processeurs, il est possible de décoder 4 instructions, mais d'en émettre maximum 6 par cycle ! Et sur les CPU avec des fenêtres d'instruction décentralisées, il y a aussi une différence entre le nombre d'instructions qui sont ''dispatch'' et ''schedule''. La catégorie la plus simple est celle des '''processeurs avec plusieurs pipelines'''. Ce sont des processeurs superscalaires sans exécution dans le désordre. Ils partent d'un processeur non-superscalaire, et ajoutent un second pipeline, en sortie de l'unité d'émission. Le second pipeline permet l'émission parallèle d'une seconde instruction. Le second pipeline n'est pas identique au pipeline originel, sur plusieurs points. Premièrement, il n'a pas exactement les mêmes circuits. Le second pipeline est généralement composé d'une unité de calcul, d'une FPU, éventuellement d'un second banc de registres, guère plus. Il permet d'exécuter une seconde opération de calcul, pas plus, ce qui est à l'origine de contraintes d'appariemment assez fortes. De plus, il n'a pas forcément la même longueur, il peut avoir des étages en moins ou en plus. Il s'agit de la forme la plus simple de processeur superscalaire et nous allons leur consacrer cette section. ===La double émission entière-flottante=== L'exemple le plus simple utilise un second pipeline pour les opérations flottantes, séparé du pipeline originel. L'ajout d'un pipeline flottant permet d'émettre une micro-opération entière en même temps qu'une micro-opération flottante, ce qui s'appelle la '''double émission entière-flottante'''. La micro-opération entière s'exécute dans l'ALU entière, la micro-opération flottante dans la FPU. Les exemples les plus notables sont le PA-RISC 7100, le POWER 1 (RIOS .& et .9) et le PowerPC 601. L'Apollo DN10000 et l'Intel i860 utilisaient aussi cette forme de double émission, mais étaient des prototypes de CPU VLIW. [[File:Double émission entière-flottante.png|centre|vignette|upright=2|Double émission entière-flottante]] Pour bien expliquer les choses, prenons le processeur illustré ci-dessous, avec deux ''back-end'' séparés : un pour la FPU, et un autre pour le reste. Les instructions entières et mémoire passent toutes par le ''back-end'' généraliste. [[File:CPU non-superscalaire basique, avec une FPU.png|centre|vignette|upright=1.5|CPU non-superscalaire basique, avec une FPU]] Les deux ''back-end'' sont des pipelines séparés, mais il faut que l'unité d'émission soit spécialement conçue pour en profiter. Un processeur simple émission peut démarrer une seule µop par cycle : soit la µop est envoyée au ''back-end'' flottant, soit elle est envoyée au ''back-end'' général. Avec la double émission entière-flottante, le processeur peut envoyer une µop dans chaque pipeline, à chaque cycle. Vu que la FPU et son banc de registre forment déjà un pipeline séparé, les seules modifications se font au niveau du ''front-end'', unité d'émission inclue. {| |- |[[File:CPU simple émission avec une FPU.png|centre|vignette|upright=1.5|CPU simple émission avec une FPU.]] |[[File:Double émission entière flottante avec un second pipeline.png|centre|vignette|upright=1.5|CPU avec un second pipeline flottant.]] |} Notez que le terme double émission ''entière''-flottante est un peu trompeur. En réalité, la technique permet d'émettre une instruction flottante avec n'importe quelle autre instruction non-flottante, avec des restrictions pour les branchements. Il est par exemple possible d'exécuter un calcul flottant en parallèle d'un accès mémoire. Sur les CPU 32 bits, il est possible de faire les multiplications dans la FPU. Pour rappel, la FPU contient un multiplieur entier 53-54 bits, pour multiplier les mantisses de deux flottants 64 bits, qu'on peut utiliser pour faire les multiplications entières 32 bits. Cela permet d'émettre une multiplication en même temps qu'une opération entière dans l'ALU. Ainsi, le CPU pouvait émettre deux instructions : une opération entière de base, avec soit une multiplication, soit une opération flottante. En clair, une émission de type INT + (MUL /FLOAT). Par contre, on perd la possibilité d'émettre une multiplication entière avec une opération flottante, mais c'était un compromis qui en valait la peine. Le CPU PA-RISC 7100 implémentait cette optimisation. Il s'agissait d'un CPU double émission entière-flottante, qui utilisait donc un partitionnement assez simple. Le combo partitionnement + reconditionnement permettait ici de gagner en performance, pour un cout en matériel très limité. D’autant plus limité que le jeu d'instruction prévoyait le reconditionnement de la FPU. Les multiplications ne lisaient pas leurs opérandes dans les registres entiers, mais dans les registres flottants. ===La double émission entière=== Une autre possibilité ajoute un second pipeline, capable d'exécuter des opérations entières simples, appelé le pipeline entier. Le processeur supporte alors la '''double émission entière''', à savoir qu'ils peuvent émettre une opération entière en plus d'une autre instruction. L'opération entière en question est une opération simple, comme une addition, une soustraction, une opération bit à bit, une comparaison, etc. Les exemples classiques sont les processeurs Intel i960 et Pentium. L'implémentation était différente entre l'i960 et le Pentium : Le Pentium avait une seconde ALU entière, alors que le i960 rusait. Le Pentium dupliquait l'ALU entière, pour créer un second pipeline entier. Sur le Pentium originel, les contraintes d'appariement étaient assez strictes. Le Pentium avait une FPU, mais ne pouvait pas l'utiliser en double émission. Il lui était impossible d'exécuter une opération flottante en même temps qu'une opération entière (branchements inclus). Le Cyrix 6x86 était une sorte de Pentium produit par l'entreprise Cyrix, avec une microarchitecture différente. Il avait des contraintes d’appariement réduites. Par exemple, il pouvait émettre une opération flottante en parallèle d'une opération entière. Nous détaillerons ces processeurs dans le prochain chapitre, qui porte justement sur les CPU superscalaires x86. [[File:CPU simple et double émission avec un second pipeline entier.png|centre|vignette|upright=2.5|CPU simple et double émission avec un second pipeline entier.]] L'Intel i960 n'avait pas de FPU, juste une ALU entière et une unité mémoire. Il utilisait l'unité mémoire comme une seconde ALU entière limitée. Pour rappel, une unité mémoire contient une AGU, à savoir une ALU spécialisée dans les calculs d'adresse. Elle est capable de faire des additions, soustractions, et quelques décalages limités (des décalages par 2, 4, 8, pas plus). L'Intel i960 ajoutait des connexions entre AGU et banc de registre, afin que celle-ci serve de seconde unité de calcul. L'AGU est déjà reliée aux deux ports de lecture, pour lire les opérandes du calcul d'adresse, il suffit de la connecter sur le port d'écriture. Le processeur peut alors émettre deux instructions/µops entières, sous certaines conditions. [[File:Emission multiple des opérations entières, double émission.png|centre|vignette|upright=2|Émission multiple des opérations entières, double émission.]] ==Les processeurs superscalaires dynamiques== Les processeurs précédents, avec 2 pipelines, avaient une unité d'émission assez simple. Elle avait deux ports de décodage, et deux ports d'émission. Le nombre de ports de décodage et d'émission étaient identiques. Vous vous dites que c'est naturel, et intuitif, que c'est normal pour un processeur superscalaire. Mais en réalité, la majorité des processeurs superscalaires a plus de ports d'émission que de décodage. Expliquer pourquoi va cependant nous demander de parler de comment la superscalarité exploite les unités de calcul. Posons-nous cette question : de combien d'unités un processeur superscalaire a besoin ? Les unités en question ne sont nécessairement des unité de calcul, l'unité mémoire et l'unité de branchement comptent aussi. La réponse dépend du nombre de voies. Si le ''front-end'' charge et décode un paquet de N instructions, exécuter ces N instructions simultanément demandera là aussi au moins N unités de calcul. Notez le terme : ''au moins'', car c'est là tout l'enjeu de cette section. La réponse dépend aussi des contraintes d’appariement. Pour un CPU superscalaire "parfait", sans contraintes d’appariement, toutes les unités doivent être dupliquées, y compris l'unité mémoire. Un processeur à double émission parfaite devrait dupliquer l'ALU entière, le ''barrel shifter'', le circuit multiplieur, la FPU, l'unité mémoire, et l'unité de branchement, ce qui ferait passer de 6 unités à 12. Le cout en circuit est énorme, même pour de la double émission ! Et pour un CPU à N pipelines, le cout en circuit encore plus prohibitif ! En pratique, les processeurs superscalaires qui font ça sont très rares. La majeure partie des processeurs superscalaires utilisent d'autres techniques : le partitionnement, la duplication partielle des ALUs, la duplication des autres unités. ===Le partitionnement des unités fonctionnelles=== Les CPU superscalaires les plus simples ne dupliquent pas leurs unités de calcul, ils se contentent d'exploiter les unités existantes. Et pour expliquer comment, nous allons partir de l'exemple d'un processeur non-superscalaire contient une ALU entière, une FPU, une unité mémoire et une unité de branchement. Les quatre unités peuvent fonctionner en parallèle, à savoir qu'une unité peut exécuter une instruction à elle toute seule, sans interagir avec les autres. Cela suffit pour créer un processeur quadruple émission, qui peut émettre en même temps : une opération entière, une opération flottante, un branchement, un accès mémoire. Le principe marche aussi sur un processeur avec moins de 4 unités, par exemple sans FPU et/ou sans unité de branchement, ou avec au contraire des unités en plus. L'idée générale est d’émettre une µops séparée dans chaque unité fonctionnelle. Utiliser ainsi les unités existantes, pour rendre un CPU superscalaire, s'appelle le '''partitionnement superscalaire'''. Le terme n'est pas beaucoup utilisé en-dehors de quelques vieux articles académiques. Le partitionnement est fortement dépendant du jeu d'instruction, car il demande de bien séparer instructions entières, flottantes, branchements et instructions mémoire. Et autant c'est bien le cas sur les CPU RISC, autant les CPU CISC ne sont pas dans ce cas. Les CPU CISC ont des instructions ''load-op'', qui effectuent une instruction arithmétique et une µop mémoire. Et ces instructions sont très compliquées à implémenter avec le partitionnement. Et au-delà de ça, les CPU CISC ont beaucoup d'instructions qui sont décodées en plusieurs µops, à exécuter dans un ordre bien précis. On peut pas émettre les µops en question simultanément. Le partitionnement a un cout en circuit très limité, pour un gain en performance lui aussi limité. Pour reprendre le CPU de l'exemple précédent, il est rare que l'on ait à exécuter ces quatre instructions en même temps. En pratique, les combinaisons fréquentes sont les combinaisons calcul + accès mémoire, calcul + branchement, calcul entier + calcul flottant. Utiliser une quadruple émission de ce type n'est donc pas une bonne idée, alors que la double émission parait plus adaptée. Et c'est là que la différence entre ports d'émission et de décodage devient intéressante. L'idée est d'avoir une unité d'émission avec deux ports de décodage, et 4 port d'émission (un par unité). Les contraintes d’appariement varient alors suivant le processeur, mais la règle générale est que si deux micro-opérations tombent dans deux unités différentes, on peut les émettre en même temps. En clair, on peut émettre une opération entière avec une opération flottante, une opération entière avec un branchement, un accès mémoire avec un branchement, etc. Et cela rend le partitionnement bien plus intéressant que prévu. Les tout premiers CPU superscalaires étaient des CPU double émission, qui utilisaient le partitionnement avec : une ALU entière, une unité mémoire et une FPU. Nous parlerons de '''partitionnement INT-FLOAT-MEM'''. L'avantage sur la double émission flottante est que les combinaisons INT + MEM et FLOAT + MEM étaient autorisées. L'intérêt était d'émettre une opération en parallèle d'un accès mémoire, ce qui est un doublet d'instruction assez fréquent. Les exemples classiques sont l'HyperSPARC, de l'alpha 21064 et du PowerPC 603. Les contraintes d’appariement variaient grandement suivant le processeur. Le PowerPC 603 implémentait une double émission "parfaite". C'est à dire que toutes les combinaisons possibles à deux instructions étaient possibles, que ce soit INT + FLOAT, INT + MEM, FLOAT + MEM. En plus de cette double émission "parfaite", le CPU utilisait la technique dite de ''branch folding'', qui permettait d'exécuter un branchement sans utiliser d'unité de calcul, ce qui fait qu'il était qualifié de ''CPU 2-way + Branch''. A l'opposé, le processeur alpha 21064 avait pas mal de contraintes d’appariement, à savoir que certaines combinaisons de deux instructions étaient interdites, bien que compatibles avec les unités disponibles. Une des raisons est que le banc de registre n'avait pas assez de ports de lectures, ce qui fait que certaines combinaisons avec une écriture mémoire n'étaient pas permises. Les concepteurs avaient volontairement inséré ces contraintes afin de simplifier le design du processeur. Avant de poursuivre, précisons que la FPU regroupe un additionneur flottant et un multiplieur flottant. Et ce fait peut être exploité pour approfondir le partitionnement. La '''double émission FADD/FMUL''' permet d'émettre une addition flottante en même temps qu'une multiplication flottante. Elle a été utilisée sur les processeurs x86, Alpha et SPARC. Les autres circuits de calcul flottant sont souvent regroupés avec l'additionneur. La division est parfois e même port que le multiplieur flottant, parfois sur celui de l'additionneur (quand elle est microcodée et exécutée en enchainant les soustractions). ===La duplication des ALU entières=== Le partitionnement est une technique élégante, simple, facile à implémenter et au cout en circuits modeste. Mais il faut avouer que cela ne donne pas des CPU superscalaires très efficaces. La raison est que le partitionnement permet d'émettre des paires, triplets, quadruplets de micro-opérations qui sont rares en pratique. Les combinaisons les plus fréquentes en pratique sont des paires/triplets d'opérations entières, souvent des paires/triplets d'additions ou d'opérations entières simples. Il est donc primordial d'émettre plusieurs opérations entières simultanément. Le fait d'émettre et d'exécuter plusieurs opérations entières en même temps s'appelle l''''émission entière multiple'''. Pour exécuter la seconde/troisième opération entière, il faut dupliquer les ALU entières (ou réutiliser l'AGU comme ALU entière comme le fait l'Intel i960). Le processeur doit avoir deux ALU entières pour de la double émission entière, trois pour de triple émission entière, etc. De plus, il faut ajouter des ports au banc de registre, pour lire deux fois plus d'opérandes et décrire deux résultats. Et enfin, il faut rajouter un port d'émission pour pouvoir émettre une micro-opération entière en plus. [[File:Processeur non-superscalaire basique 03.png|centre|vignette|upright=2|Processeur non-superscalaire basique]] La tendance est de multiplier les ALU entières, mais pas le circuit multiplieur. Le cout en transistors est alors grandement réduit, au prix de l'apparition de dépendances structurelles. Le CPU peut émettre deux additions en même temps, ou une addition et une multiplication, mais pas deux multiplications. Il en est de même avec le ''barrel shifter'', qui n'est pas dupliqué. Il est donc possible d'émettre un décalage avec une opération de base, mais pas deux décalages en parallèle. Mais ces contraintes d’appariement ne sont pas un problème, car il est rare de devoir émettre deux multiplications/décalages en même temps. La plupart des programmes sont majoritairement remplis d'additions, avec des multiplications assez rares et des décalages qui le sont encore plus. La moyenne est proche d'une multiplication pour 4/5 additions. Vu que des multiplications consécutives sont très rares, dupliquer le multiplieur est presque inutile. Disposer de plusieurs circuits multiplieurs ou de plusieurs ''barrel shifters'' serait donc un cout en circuits qui ne servirait que rarement et n'en vaut pas la chandelle. Il faut noter que sur les CPU 32 bits, les multiplications peuvent être exécutées dans la FPU ou dans un multiplieur séparé, tout dépend de si le CPU exécute les multiplications dans la FPU ou pas. {|class="wikitable" |- ! Voie d'émission n°1 !! Voie d'émission n°2 !! Voie d'émission n°3 |- | ALU entière || ALU entière || FPU |} Reste à connecter les unités de calcul à l'unité d'émission (indirectement, car il y a des étages de pipeline entre les deux). Une implémentation basique utilisée un port d'émission par unité. Prenons l'exemple d'un CPU superscalaire avec 4 ALU entières, une FPU, et une unité mémoire. Vu qu'il y a 6 unités, cela fait donc 6 ports d'émission. L'exemple historique le plus impressionnant est celui du Motorola 88110, un CPU double émission qui possède 10 unités. Il contient deux ALU entières, un circuit multiplieur, un circuit diviseur, une unité de manipulation de bits, une unité mémoire, un additionneur flottant, et deux unités graphiques pour des calculs impliquant des pixels. Le multiplieur est utilisé à la fois pour les multiplications entières, flottantes et le produit de deux pixels. Idem pour le diviseur, qui sert pour les divisions entières et flottantes. Et chaque unité a son propre port d'émission. La conséquence est que les contraintes d'appariement du Motorola 88110 sont simples : tant que deux µops atterrissent dans des unités séparées, la paire est permise. Il est par exemple possible d'émettre simultanément deux opérations entières simples, vu qu'il y a deux ALU. Par contre, impossible d'émettre simultanément deux multiplications, deux divisions, deux opérations flottantes, deux manipulations de bit, deux accès mémoire, etc. De plus, le partage du multiplieur fait qu'on ne peut pas émettre une multiplication entière avec une multiplication flottante. Idem avec les divisions, vu que le diviseur est aussi partagé. Ce sont les seules contraintes. ===Le partage des ports d'émission=== La présence d'un circuit multiplieur et d'un ''barrel shifter'' pose des problèmes pour le partitionnement. Il est possible d'avoir un port d'émission dédié au multiplieur, et un autre au ''barrel shifter'', qui sont séparés de ceux pour l'ALU entière. Il est alors possible d'émettre une opération entière, une multiplication et un décalage, simultanément. Nous parlerons de '''partitionnement entier''' pour désigner cette possibilité. [[File:Partitionnement superscalaire entier.png|centre|vignette|upright=2|Partitionnement superscalaire entier.]] Le partitionnement entier est cependant très rare, car le gain en performance serait trop faible au regard des couts en circuit. Quelques processeurs historiques l'utilisaient, mais ce n'est plus le cas de nos jours. La raison est que les multiplications et les décalages sont assez rares dans le code, ce qui fait que le port d'émission associés sont sous-utilisés. Et un port d'émission a un cout en circuit assez important. Et c'est sans compter qu'ajouter des ports sur le banc de registres juste pour un multiplier sous-utilisé n'en vaut pas la peine. L'idéal serait de trouver un moyen de réduire le nombre de ports d'émissions, sans réduire le nombre d'unités de calcul. [[File:Emission multiple des opérations entières, implémentation naive.png|vignette|Émission multiple des opérations entières, implémentation naive]] La solution consiste à '''partager les ports d'émission''', à savoir connecter un port d'émission à plusieurs unités de calcul. L'exemple classique est justement lié aux circuits multiplieur et ''barrel shifters''. L'idée est que le multiplieur et le ''barrel shifter'' sont mis sur le même port d'émission qu'une ALU entière. Prenons par exemple le processeur à double émission entière illustré ci-contre. Un port d'émission est relié à une ALU entière seule, et l'autre port d'émission alimente la seconde ALU entière et le multiplieur. La conséquence est que le processeur peut émettre deux opérations entières, dont une multiplication. Si on avait utilisé un port d'émission dédié au multiplieur, il aurait été possible d'émettre deux opérations entières et une multiplication. On perd donc une voie, mais on gagne en flexibilité et on économise des circuits. Notons que ce partage signifie aussi que le multiplieur partage les ports sur le banc de registre, ce qui fait une double économie. [[File:Emission multiple des opérations entières, implémentation courante.png|centre|vignette|upright=1.5|Émission multiple des opérations entières, implémentation courante]] En général, le ''barrel shifter'' et le multiplieur sont placés sur deux voies d'émission séparés, ce qui permet d'émettre un décalage et une multiplication en même temps. Les mettre sur le même port ne le permettrait pas. {|class="wikitable" |- ! Voie d'émission n°1 !! Voie d'émission n°2 !! Voie d'émission n°3 |- | * ALU entière * Multiplieur | * ALU entière * Barrel shifter | FPU |- | * Additions, soustractions, opérations bit à bit, etc. * Multiplication | * Additions, soustractions, opérations bit à bit, etc. * Décalages et rotations | Opération flottante |} Terminons concernant les multiplieurs avec une dernière subtilité. Pour rappel, les processeurs modernes intégrent en réalité deux multiplieurs différents. Le résultat d'une multiplication est très large et prend deux registres. Par exemple, une multiplication de deux opérandes 64 bits donne un résultat sur 128 bits, ce qui ne tient pas dans un registre, mais en prend deux. L'instruction de multiplication classique ne calcule que les 64 bits de poids faible. mais elle est complétée par d'autres instructions de multiplication qui peuvent faire le calcul complet. Pour résoudre le problème, les processeurs modernes intègrent deux instructions de multiplications : une qui calcule les bits de poids faible du résultat, une autre qui calcule les bits de poids fort. Et ces deux instructions sont associées à deux multiplieurs séparés, aux circuits différent. Le multiplieur qui calcule les bits de poids faible du résultat est appelé le ''low multiplier'', l'autre est appelé le ''high multiplier''. Le second multiplieur est souvent placé sur un second port d'émission, différent du premier multiplieur, partagé avec une ALU. L’avantage de mettre les deux multiplieurs sur deux ports d'émission différents est qu'une multiplication complète peut être réalisée en utilisant les deux multiplieurs en parallèle. Les deux sous-multiplications sont émises en même temps, exécutées en même temps. pas besoin d'exécuter l'une puis la seconde, d'où un gain performance appréciable. Nous venons de voir comment partager un port d'émission entre une ALU et un multiplieur. Mais au-delà de cet exemple, le partage des ports d'émission peut appliquer à n'importe quelle unité. Prenons l'exemple d'un CPU superscalaire avec 4 ALU entières, une FPU, et une unité mémoire. Vu qu'il y a 6 unités, cela fait donc 6 ports d'émission. Cependant, il est rare qu'un bloc de 6 instructions contienne exactement 4 opérations entières, une opération flottante, et un accès mémoire. Beaucoup de ports d'émission seraient sous-utilisés. La solution est de partager des ports d'émission, pour passer à la quadruple émission. Le CPU peut alors répartir 4 instructions sur les ports d'émission adéquats, à chaque cycle. Le CPU a donc 4 ports de décodage et 6 ports d'émission. Une implémentation classique permet n'importe quelle combinaison de 4 instructions compatible avec les 6 unités. Par exemple, il devient possible d'émettre simultanément 4 additions, la combinaison 2 * INT + FLOAT + MEM, 3 * INT + MEM, et bien d'autres. L'exemple relie une ALU entière, la FPU et l'unité mémoire sur le même port. Le CPU a alors quatre ports d'émission, qui ne sont pas "identiques". Trois d'entre eux sont reliés à une ALU entière chacun, rien d'autre. Le quatrième est lui relié à une ALU entière, la FPU et l'unité mémoire. On économise alors deux ports d'émission, mais cela entraine l'apparition de contraintes d’appariement. Le CPU peut émettre 3 opérations entières + n'importe quelle autre opération. Mais les autres combinaisons sont interdites. Le CPU peut émettre 6 opérations entières simultanément, grâce à 6 ALU entières. Les accès mémoire ou opérations flottantes ne viennent pas en plus, mais en remplacement des opérations entières. Regrouper plusieurs ALU sur un même port d'émission est donc à l'origine de dépendances structurelles, de nouvelles contraintes d’appariement. Dans certaines situations de '''''port contention''''', on a assez d'ALU pour exécuter N micro-opérations, mais la répartition des ALUs sur les ports l'empêche. Impossible d'émettre deux micro-opérations sur deux ALU si elles sont sur le même port d'émission. On peut réduire les cas de ''port contention'' en répartissant correctement les ALU sur les ports d'émission, mais sans jamais les supprimer complétement. Un exemple est celui du PowerPC 604. Il implémentait la quadruple émission, alors qu'il avait 5 unités de calcul. Mais deux unités partageaient un même port d'émission. Dans le détail, il avait deux ALU entières, un circuit multiplieur/diviseur, une FPU, une unité mémoire. La FPU et le multiplieur étaient sur le même port d'émission. En conséquence, le CPU pouvait émettre seulement les combinaisons INT + INT + MEM + (MUL/FLOAT). : Il est intéressant de voir l'exemple d'un processeur superscalaire parfait, sans contraintes d'appariement, à N voies. Pour cela, on part d'un processeur non-superscalaire, avec M unités de calcul. Un tel processeur peut s'implémenter avec N ports d'émission, chacun relié à M unités de calcul possibles, ce qui fait que les M unités de calcul sont dupliquées en N exemplaires. Si on prend par exemple un CPU non-superscalaire avec une ALU, une FPU, une unité mémoire et une unité de branchement, un port d'émission sera relié à une ALU, une FPU, une unité mémoire et une unité de branchement. ===La duplication des autres unités fonctionnelles=== Dupliquer les ALU entière est une première étape, mais il est aussi possible de dupliquer les autres unités fonctionnelles. Par exemple, il est possible de dupliquer l'unité mémoire ou l'unité de branchement. Reste à voir quelles unités dupliquer, et pourquoi. Précisons que dans ce qui va suivre, nous allons parler de la duplication des unités en général, pas seulement des unités mémoire/branchement. Nous allons continuer de parler de la duplication des ALU entières dans ce qui suit, mais de manière plus générale. Pour un processeur à N voies, il est théoriquement possible de dupliquer toutes les unités en N exemplaires. Mais ce n'est jamais fait en pratique, car le cout en circuits serait trop important et le gain en performance trop faible. Mieux vaut dupliquer certaines unités bien précises, quitte à avoir des contraintes d'appariement. Et à ce petit jeu, toutes les duplications ne se valent pas, certaines sont plus rentables en matière de performance, le cout en circuit n'est pas le même selon l'unité, etc. La rentabilité en performance dépend surtout des contraintes d'appariement. Les contraintes d'appariement entrainent une baisse de performance significatives si elles interdisent des paires d'instructions fréquentes. Aussi, les opérations très fréquentes, souvent appairées, gagnent à dupliquer l'unité associée. Et au contraire, les unités rarement utilisées ne doivent pas être dupliquées. Il se trouve que les unités les plus utilisées sont les ALU entières, suivies par les unités mémoire et l'unité de branchement. Le cout en circuit n'est aussi pas le même. Dupliquer les ALU entière est trivial, car elles ont un budget en transistors assez faible. Les circuits multiplieurs, diviseurs, et les ''barrel shifter'' ont eux un cout en transistor plus élevés. Si on devait faire un classement, on aurait : ALU entière < ''barrel shifter'' < multiplieur. Pour les unités mémoire, le cout en transistor est là aussi conséquent. Le résultat final est que dupliquer les ALU entières est privilégié sur le reste, comme l'a vu dans la section précédente. Les unités mémoire arrivent en seconde place, suivie par les multiplieurs/''barrel shifter'' à la troisième place, et les unités de branchement à la quatrième place. Les CPU superscalaires larges ont donc tendance à multiplier les unités mémoire en second. Les multiplieurs et ''barrel shifters'' sont eux aussi dupliqués sur les CPU superscalaires larges, mais cela vient souvent après avoir dupliqué les unités mémoire. La raison est que les accès mémoire sont critiques pour la performance des CPU à exécution dans le désordre, pas les multiplications. Pour les unités de branchement, une subtilité complique le fait d'en installer plusieurs. Que faire quand deux branchements sont pris ? La solution la plus simple est de ne pas se trouver dans cette situation : on n'utilise qu'une seule unité de branchement et on n’exécute qu'un seul branchement par cycle. La majorité des processeurs superscalaires étroits font ainsi. Les processeurs superscalaires larges ont cependant deux unités de branchements, mais ils n'acceptent qu'un seul branchement pris à la fois. Si les deux branchements pris sont exécutés en même temps, le processeur n’exécute que le plus récent, dans l'ordre du programme. ===Les CPU superscalaires mélangent les trois techniques=== Les CPU superscalaires utilisent toutes les techniques à la fois : partitionnement, duplication de l'ALU entière, duplication des autre unités fonctionnelles. Chaque processeur utilise ces trois stratégies à sa sauce, en fonction de son budget en transistor. Les quatre techniques ont cependant un cout en circuit différent, et donnent des gains de performances eux aussi forts différents. * Le '''partitionnement superscalaire''' a un cout en circuit modéré, car on n'a pas besoin de dupliquer d'ALU. * La '''duplication des ALU entières''' est la technique la plus importante : elle a un cout en circuit modéré, et donne des gains en performance impressionnants. * La '''duplication des autres unités''' a un cout en circuit variable, pour des gains en performance eux aussi variables. * Le '''partage des ports d'émission''' réduit le cout en circuit du CPU, pour des pertes de performances mineures si bien fait. L'usage du partitionnement seul, sans duplication, était surtout le fait des processeurs commercialisés entre les années 1989 et 1993. Le partage des ports d'émission a lui aussi mis un peu de temps pour s'imposer. Globalement, les processeurs superscalaires ont évolués progressivement, pour se rapprocher d'une sorte de standard. Mais pour comprendre ce qu'est ce standard, et en quoi les CPU historiques s'en sont progressivement rapprochés, il faut étudier l'histoire des CPU superscalaires. L'histoire des CPU superscalaires a commencé dès 1960, mais est resté un projet de recherche pendant plusieurs décennies. De nombreux designs ont été conçus, mais abandonnés avant la production, comme l'ACS-1 d'IBM. Les années 1980 ont vu l'arrivée de prototypes de processeurs VLIW, mais qui n'étaient pas superscalaires. Par exemple, l'Apollo DN10000 et l'Intel i860 pouvaient émettre deux instructions à la fois, sous conditions, mais demandaient que le compilateur fasse une bonne partie du travail. Les premiers CPU superscalaires commercialisés sont sortis en 1989. Deux CPUs superscalaires sont sortis cette année là : le RS/6000 d'IBM et l'i960CA d'Intel. Puis, la compétition s'est aussi lancée dans la bataille. Les CPU commercialisés avant l'année 1993 étaient à double émission, à l'exception du SuperSPARC qui utilisait la triple émission. Les modèles après 1993 hésitaient entre double et quadruple émission. Dans le tableau ci-dessous, les processeurs quadruple émission sont en bleu, les triple émission sont en rouge, les autres ne sont pas en couleur. {|class="wikitable" |- ! !! IBM !! HP PA-RISC !! SPARC !! Intel!! Alpha !! Autres |- ! 1989 | RS/6000 || || || i960CA || || |- ! 1990 | || || || || || |- ! 1991 | || || || || || Motorola 88110 |- ! 1992 | RSC || PA 7100 || class="f_rouge | SuperSPARC || || 21064 || |- ! 1993 | PPC 601 || || HyperSPARC || Pentium || || |- ! 1994 | class="f_bleu | POWER 2 || PA 7200 || || || class="f_bleu | 21164 || |- ! 1995 | 603/604 || class="f_bleu | PA 8000 || class="f_bleu | UltraSPARC 1 || Microarchitecture P6 (+ concurrence AMD) || || class="f_bleu | MIPS R1000 |- ! 1996 | class="f_bleu | 620 || || || || class="f_bleu | 21264 || |- ! ... || ... || ... || ... || ... || ... || ... |} Les premiers CPU à double émission sont assez représentatifs des CPU à double émission modernes. Il faut dire que se limiter à deux voies ne permet pas de faire beaucoup de choses. Voici le tableau chronologique disant quel CPU utilisait quelle technique. * Les CPU en vert utilisaient la double émission entière-flottante. * Les CPU en rouge utilisaient la double émission entière "pure". * Les CPU en jaune utilisaient un ''partitionnement complet'' entre ALU, FPU et unité mémoire. * Les CPU sans couleur utilisaient un grand nombre d'unités, avec beaucoup de ports d'émission. * Les CPU barrés utilisent la triple ou quadruple émission et seront vu dans la section suivante. {|class="wikitable" |- ! !! IBM !! HP PA-RISC !! SPARC !! Intel!! Alpha !! Autres |- ! 1989 | class="f_vert | RS/6000 || || || class="f_rouge | i960CA || || |- ! 1990 | || || || || || |- ! 1991 | || || || || || Motorola 88110 |- ! 1992 | class="f_vert | RSC || class="f_vert | PA 7100 || <s>SuperSPARC</s> || || class="f_jaune | 21064 || |- ! 1993 | class="f_vert | PPC 601 || || class="f_jaune | HyperSPARC || class="f_rouge | Pentium || || |- ! 1994 | <s>POWER 2</s> || PA 7200 || || || <s>21164</s> || |} C'est en 1994, que la quadruple émission est arrivée et que les CPU ont essayé divers implémentations. Il y avait alors trois stratégies pour la double/triple/quadruple émission, qui partageaient des problèmes similaires. La première implémentation dupliquait les ALUs et les FPUs, ce qui permettait d'émettre deux opérations flottantes avec deux opérations entières. Le POWER 2 dupliquait ses FPUs à la perfection, alors que le 21264 séparait l'additionneur et le multiplieur flottant. Les accès mémoire étaient traités comme des opérations entières et le processeur pouvait souvent en émettre deux à la fois. Mais une telle organisation n'est plus utilisée de nos jours, car, sans instructions flottantes à exécuter, elle est équivalente à de la double émission. La seconde implémentation utilisait deux ALU entières (dont un multiplieur), une unité mémoire et une FPU.Cette organisation est intéressante, mais encore trop stricte pour donner de bons résultats, les quadruplets avec exactement deux opérations entières, un accès mémoire et une opération flottante étant trop rares. L'usage de ces 4 unités en double ou triple émission a été utilisé sur le PA 7200 et le SuperSPARC. Malheureusement, en plus de problèmes au niveau de son cache, le SuperSPARC avait de nombreuses contraintes d’appariement, car le banc de registre n'avait pas assez de ports pour alimenter certaines combinaisons d'instructions. De plus, s'il émettait une multiplication, il ne pouvait pas émettre de seconde µop. Enfin, une troisième implémentation utilisait un grand nombre d'unités fort différentes, bien plus que quatre, avec au minimum deux ALU entières. Prenons l'exemple de l'UltraSPARC, qui avait : deux ALU entières, une unité mémoire, une unité de branchement, un additionneur flottant, un multiplieur flottant, un diviseur flottant (aussi utilisé pour le calcul des racines carrées), et 2 unités graphiques pour les calculs sur des pixels. En tout, cela fait 9 unités différentes, pour de la quadruple émission. Dans le même genre, les processeurs MIPS R8000 et R10000 avaient une implémentation plus moderne, dans le sens où toutes les unités étaient dupliquées. Le CPU avait deux ALU, deux FPU et deux unités mémoire. Il pouvait donc émettre quatre instructions à la fois, tant que le paquet collait avec ces six unités. Moitié opérations entières, moitié opérations mémoire, avec de quoi remplacer les opérations entières par des opérations flottantes. Le PA 8000, lui, dupliquait toutes ses unités en deux exemplaires, ce qui n'est pas l'idéal, aucun processeur moderne ne fait cela aujourd'hui. Le tout est résumé dans le tableau ci-dessous, avec : * en vert les CPU utilisant la première stratégie ; * en rouge les CPU utilisant la seconde stratégie ; * en jaune les CPU utilisant la troisième stratégie. {|class="wikitable" |+ Processeurs quadruple émission historiques |- ! Année !! Processeur !! Unités |- ! 1991 | class="f_jaune | Motorola 88110 || class="f_jaune | 2 ALU + MUL + DIV + BIT + MEM + FADD + 2 unités graphiques |- |- ! rowspan="2" | 1994 | class="f_vert | POWER 2 || class="f_vert | 2 ALU/MEM + 2 FPU (+ 2 Branchements via ''branch folding'') |- | class="f_rouge | 21164 || class="f_rouge | 2 ALU + FPU + MEM |- ! rowspan="3" | 1995 | PA 8000 || 2 ALU + 2 ''barrel shifters'' + 2 MEM + 2 FPU (FMA) + 2 FPU (DIV et SQRT) + 2 SIMD |- | class="f_jaune | UltraSPARC 1 || class="f_jaune | 2 ALU + MEM + BRANCH + FADD + FMULFDIV + 2 unités graphiques |- | MIPS R8000 et R10000 || 2 ALU + 2 FPU + 2 MEM |- ! rowspan="2" | 1996 | class="f_rouge | 620 || class="f_rouge | 2 ALU + FPU + MEM |- | class="f_vert | 21264 || class="f_vert | 2 ALU/MEM + 2 FPU (FADD + FMUL) |} Malheureusement, ces CPUs historiques n'avaient ni assez d'unités de calcul entières, ni d'unités mémoire, pour remplir la quadruple émission. Environ la moitié des instructions d'un programme correspond à des instructions entières. Pour en profiter, un processeur à N voies doit disposer d'au minimum N/2 ALU entières, l'idéal étant d'aller au-delà. Les CPU superscalaires historiques avaient 2 ALU pour de la quadruple émission, ce qui était très limite. En comparaison, les CPU superscalaires modernes mettent le paquet niveau ALU entière. La plupart des CPU x86 modernes descendent rarement sous les 2/3, la plupart remplit presque la totalité de la largeur du CPU. Pour donner un exemple, la microarchitecture Golden Cove d'Intel est un processeur à 6 voies, avec 5 ALU entières. Pour être précis, un programme informatique exécute environ 40% de son code dans des instructions arithmétiques, un autre 40% dans les accès mémoire, et un le reste pour... le reste. La conséquence est que les processeurs modernes dupliquent leurs unités mémoire. Par exemple, la microarchitecture ''Golden Cove'' d'Intel dispose de trois unités mémoire : deux spécialisées dans les écritures, trois dans les lectures. La microarchitecture ''Gracemont'' utilise la pentuple émission et peut émettre 4 µops entières et 4 µops mémoire. Notez que le ratio est équilibré entre opérations entières et mémoire, avec soit égalité, soit un avantage pour les ALU entières. Une autre régularité est que la largeur totale du processeur peut être occupée par des opérations entières/mémoire. Pour le dire autrement, sur un processeur quadruple émission, il pourra émettre un mix de 4 instructions entière/mémoire, avec zéro opération flottante. Idem avec des processeurs triples ou pentuple émission, voire plus. Si le processeur émet une opération flottante, elle remplace une opération entière. Prenons l'exemple des processeurs AMD K6, sortis en 1997, juste avant les AMD Athlon. Ils avaient 10 unités de calcul, 6 ports d'émission, 4 ports de décodage. Voici exactement comment étaient répartie les unités de calcul sur les ports d'émission. C'était des processeurs quadruple émission, ce qui fait que la moitié de la largeur du processeur sert pour des opérations entières, et l'autre moitié pour les accès mémoire. {|class="wikitable" |- ! Port d'émission n°1 !! Port d'émission n°2 !! Port d'émission n°3 !! Port d'émission n°4 !! Port d'émission n°5 !! Port d'émission n°6 ! |- | ALU entière || ALU entière || FPU || Unité de branchement || Unité LOAD || Unité STORE |- | || Multiplieur || || || || Unité de calcul d'adresse (instruction LEA) |- | || ''Barrel shifter'' || || || || Unité pour les instructions PUSH |} Les microarchitectures K7, K8 et K10, utilisées sur les anciens CPU AMD Athlon, sont un exemple moins représentatif. Ces microarchitectures utilisent le partage des ports d'émission au maximum. C'était des microarchitectures à triple émission, avec six ports d’émission. Il y avait trois ports d'émission pour les opérations flottantes, et trois ports d'émission pour les micro-opérations entières/mémoire. Il y avait trois ALU entières et trois unités mémoire, chaque ALU partageait un port d'émission avec une unité mémoire. Elle pouvait donc émettre soit trois opérations entières, soit trois µops mémoire, soit un mix des deux. En plus des mix avec les opérations flottantes et branchements. {|class="wikitable" |- ! Port d'émission n°1 !! Port d'émission n°2 !! Port d'émission n°3 !! Port d'émission n°4 !! Port d'émission n°5 !! Port d'émission n°6 ! |- | ALU entière || ALU entière || ALU entière || FADD || FMUL || FPU (autres opérations) |- | Multiplieur || || || || || |- | LOAD/STORE || LOAD/STORE || LOAD/STORE || || || |} Les CPU superscalaires larges dupliquent les multiplieurs et/ou les ''barrel shifters'', et même les unités de branchement. La raison est que quand la largeur du CPU augmente, le processeur traite des paquets d'instructions de plus en plus gros. Par exemple, pour un CPU à 10 voies, cela veut dire émettre 10 instructions en même temps. Il est alors plus fréquent d'avoir deux multiplications, deux décalages, deux accès mémoire, deux branchements. Par exemple, la moyenne est d'une multiplication tous les 5 instructions. Les CPU superscalaires à 10 voies ont donc tendance à avoir deux multiplications par paquet d'instruction, en moyenne. Avoir deux multiplieurs est alors un gain en performance clair. Par exemple, la microarchitecture ''Golden Cove'' a deux ''barrel shifters''. C'est une architecture à 6 voies. {|class="wikitable" |- ! Port d'émission n°1 !! Port d'émission n°2 !! Port d'émission n°3 !! Port d'émission n°4 !! Port d'émission n°5 !! Port d'émission n°6 !! Port d'émission n°7 !! Port d'émission n°8 !! Port d'émission n°9 !! Port d'émission n°10 |- | ALU entière || ALU entière || ALU entière || ALU entière || ALU entière || LOAD || LOAD || LOAD || STORE || STORE |- | ''Barrel shifter'' || Multiplieur || Multiplieur || ''Barrel shifter'' || || || || || || |- | Branchements || Diviseur || || Branchements || || || || || || |} ==Les µops mémoire sur les processeurs superscalaires== Plus haut, nous avons volontairement passé sous silence les accès mémoire. La raison à cela est que leur support sur les CPU superscalaire peut se faire de plusieurs manières différentes, qu'il vaut mieux expliquer dans une section dédiée. Les différentes implémentations sont décrites dans la liste suivante, nous allons les voir une par une. * Avec la première méthode, les accès mémoire sont exécutés par le pipeline pour les opérations entières. * Avec la seconde méthode, les accès mémoire ont un pipeline dédié ; c'est l'''émission parallèle des accès mémoire''. * Avec la troisième méthode, il est possible d'émettre plusieurs accès mémoire simultanément : c'est l'''émission multiple des accès mémoire''. Voyons ces trois cas dans le détail. Nous verrons notamment les différentes formes d'émission multiple des accès mémoire. ===Les accès mémoire traités dans le pipeline entier=== Dans le cas le plus simple, les accès mémoire sont traités comme des opérations entières un peu spéciales. L'unité mémoire est sur le même port d'émission que l'ALU entière, ce qui fait que les accès mémoire remplacent des opérations entières. Faire ainsi permet d'utiliser une ALU entière pour les calculs d'adresse, pas besoin de rajouter une unité de calcul d'adresse séparée. Typiquement, un processeur de ce type place l'unité mémoire après l'unité de calcul. Les opérations entières n'utilisent que l'ALU entière, mais pas l'unité mémoire. Les accès mémoire exécutent un calcul d'adresse dans l'ALU entière, puis l'adresse calculée est envoyée à l'unité mémoire. Le tout est illustré ci-dessous, dans le cas d'un processeur historique à double émission entière-flottante. [[File:Processeur non-superscalaire basique 01.png|centre|vignette|upright=1.5|Processeur non-superscalaire basique]] Un exemple de CPU double émission de ce type est celui du Power PC 440, un CPU destiné à l'embarqué. Vu qu'il était destiné à l'embarqué, il n'avait pas de FPU, il n'avait pas besoin de manipuler de nombres flottants. Il n'a donc que des ALU entières, un multiplieur et une unité mémoire. Il dispose de deux ports d'émission. Le premier est connecté à une ALU entière et un circuit multiplieur, le second est relié à l'unité mémoire et une seconde ALU entière. Une organisation simple, mais très efficace ! [[File:PowerPC 440.png|centre|vignette|upright=2|Microarchitecture du PowerPC 440.]] L'implémentation économise une unité de calcul d'adresse, mais n'a pas de cout en performance significatif. Les accès mémoire étant très lents, émettre une µop entière en parallèle d'un accès mémoire ne sert pas à grand-chose. On peut émettre cette µop entière un cycle plus tard, elle sera terminée avant même que l'accès mémoire soit terminé, même si l'accès mémoire se fait dans le cache L1 ou L2. Pour comprendre pourquoi, faisons quelques calculs. Un accès mémoire prend deux-trois cycles quand il tombe dans le cache L1. Et on doit attendre qu'il soit terminé pour en émettre un nouveau. Combien d'instructions arithmétiques peut-on lancer pendant ce temps, sur un CPU triple émission ? Au premier cycle, on peut en émettre 2 (l'instruction mémoire prend une place, donc 3-1), puis 3 au second cycle. Ce qui fait 5 instructions arithmétiques au total. Or, il se trouve qu'il y a une instruction d'accès mémoire pour 5 instructions arithmétiques, environ. Par contre, ce compromis change quand on passe à la quadruple émission, voire au-delà. Dans ce cas, il devient intéressant de pouvoir émettre une nouvelle instruction mémoire à chaque cycle. Ce qui nous amène à la section suivante... ===L'émission parallèle des accès mémoire=== A partir de la quadruple émission, la tendance a été de séparer l'unité mémoire des ALU entières. Cela permet d'émettre des µops mémoire en même temps que des µops entières et/ou flottantes., ce qui porte le nom d''''émission parallèle des µops mémoire''', ou encore ''émission mémoire parallèle''. Par exemple, un processeur quadruple émission peut émettre en même temps deux opérations entières, une opération flottante et un accès mémoire. L'accès mémoire vient en plus des opérations entières, il n'est pas possible de remplacer l'accès mémoire par une opération entière. La technique ne permet pas de faire les calculs d'adresse dans l'ALU entière. Il faut donc utiliser une unité de calcul d'adresse séparée. Elle est intégrée dans l'unité mémoire, qui fait l'interface entre le cache et le banc de registres. Le cout en circuits est très faible, car les unités de calcul d'adresse n'utilisent guère plus qu'un additionneur et un circuit de décalage très simple. L'émission mémoire parallèle est plus facile à implémenter sur les CPU RISC, qui ont des instructions mémoire séparées du reste. Les CPU CISC ne sont pas dans ce cas, ce qui fait que séparer l'unité mémoire du pipeline entier est compliqué. Les CPU superscalaires historiques étaient pour moité des CPU RISC et pour moitié des CPU CISC, ce qui fait qu'ils n'utilisaient pas ou peu l'émission mémoire parallèle. Les premiers processeurs superscalaires se contenaient de l'émission parallèle mémoire, ils ne pouvaient émettre qu'un seul accès mémoire à la fois, l'unité mémoire n'était pas dupliquée. Et ce n'est pas tant un problème que ça, du moins sur les processeurs à double ou triple émission. En effet, il est rare que l'unité mémoire doive faire deux accès simultanés. Notons que le processeur peut exécuter une instruction mémoire en parallèle d'un calcul ou d'un branchement, seuls les accès mémoire simultanés sont impossibles. ===L'émission multiple des accès mémoire avec une LSQ=== Les processeurs superscalaires larges travaillent sur des paquets de 8 à 10 instructions, il est plus fréquent d'avoir plusieurs accès mémoire par paquet. Dans ces conditions, il est utile d'avoir une '''émission multiple des accès mémoire''', à savoir d'émettre plusieurs micro-opérations mémoire en même temps. Les processeurs superscalaires modernes sont capables d'émettre plusieurs lectures/écritures simultanément. Par exemple, ils peuvent émettre une lecture en même temps qu'une écriture, ou plusieurs lectures, ou plusieurs écritures. Il faut noter que selon le processeur, il peut y avoir des restrictions quant aux accès mémoire émis en même temps. Par exemple, certains processeurs peuvent émettre une lecture avec une écriture en même temps, mais pas deux lectures ni deux écritures. Ou encore, ils peuvent émettre deux lectures, une lecture et une écriture, mais pas deux écritures en même temps. Dans la majorité des cas, les processeurs ne permettent pas d'émettre deux écritures en même temps, alors qu'ils supportent plusieurs lectures. Il faut dire que les lectures sont plus fréquentes que les écritures. Les processeurs qui autorisent toutes les combinaisons de lecture/écriture possibles, sont rares. L'émission multiple des accès mémoire s'implémente dans l'unité mémoire. Pour rappel, l'unité mémoire s'interpose entre le cache L1 et le reste du pipeline. Dans le cas le plus simple, elle incorpore une ''load/store queue'' et des unités de calcul d'adresse. L'émission multiple des accès mémoire demande de rendre la ''Load-store queue'' multi-ports, afin de gérer plusieurs micro-opérations mémoire simultanées. Il faut aussi dupliquer les unités de calcul d'adresse reliées à la LSQ, chaque port d'émission mémoire devant avoir sa propre unité de calcul d'adresse. : Dans ce qui suit, nous parlerons d'AGU (''Adress Generation Unit'') pour désigner les unités de calcul d'adresse, et de LSQ pour designer la ''Load-store queue''. [[File:Processeur non-superscalaire basique 02.png|vignette|upright=1|Processeur non-superscalaire basique]] Dupliquer les ports de la LSQ et les AGU est nécessaire. Mais qu'en est-il du cache ? La réponse varie suivant le processeur. Il y a deux grandes méthodes pour implémenter l'émission multiple des accès mémoire. La première méthode ajoute des ports de lecture/écriture au cache de données, pour faire des lectures/écritures simultanées. Il faut alors dupliquer des unités de calcul, rajouter les ports sur le cache, mais aussi rajouter des ports sur la ''load/store queue'', pour qu'elle échange des données/commandes mémoire avec le cache. Le cout en circuits est alors conséquent La seconde duplique les unités de calcul, mais pas les ports d'accès au cache. Les accès mémoire sont alors accumulés dans la ''load/store queue'', qui sont ensuite traités un par un par le cache. Un exemple est celui des processeurs AMD de micro-architecture K7 K8, à savoir les anciens AMD Athlon et AMD Athlon 64, qui pouvaient calculer trois adresses simultanément, mais ne pouvaient faire qu'un seul accès au cache par cycle. Le cout en circuit est modéré : les unités de calcul coutent très peu, les ports de la ''load/store queue'' coutent déjà un peu plus. Quelques processeurs utilisaient des solutions intermédiaires. Un processeur utilisant cette technique est, par exemple, capable d'émettre quatre µops mémoire en même temps, mais avec seulement deux ports sur le cache. Un exemple classique étant les Pentium 1 et 2 d'Intel, dont nous parlerons dans le chapitre suivant. ===L'émission séparée des LOAD et STORE=== De rares processeurs ont des ports d'émission qui peuvent faire indifféremment lecture comme écritures. Mais les processeurs modernes préfèrent séparer ports d'émission pour les lectures et les écritures. Un exemple est celui des processeurs Intel de micro-architecture Nehalem, qui avaient un port de lecture et un port d'écriture tous deux reliés à la ''Load-store queue'', chacun avec leur propre unité de calcul d'adresse. Comme autre exemple, les processeurs skylake ont une LSQ avec deux ports de lecture et un port d'écriture, ce qui permet d'émettre deux lectures en même temps qu'une écriture. Dans cette section, nous allons étudier le cas avec des ports séparés pour les lectures et écritures. En général, les processeurs ont un peu plus de ports de lectures que d'écritures. Une raison est qu'un programme a, en moyenne, un tout petit peu plus de lectures que d'écritures. Mais la différence n'est pas énorme, c'est un léger déséquilibre. Une seconde raison est que l'exécution dans le désordre marche bien mieux quand les lectures ont lieu le plus tôt possible. Donc mieux vaut privilégier les lectures à l'émission, pour qu'elles se fassent un peu en avance. En pratique, la différence n'est pas très marquée. Il est courant d'avoir un port de lecture et un d'écriture, les CPU superscalaires très larges ont souvent deux ports de lecture et deux d'écriture. A la rigueur, quelques CPU ont trois ports de lecture et deux d'écriture. Le cas le plus simple est celui où on peut émettre une lecture et une écriture en même temps. Il s'implémente facilement si la LSQ est en réalité une simple ''Store queue'', à savoir qu'elle met en avance les écritures uniquement. Pour rappel, les écritures sont mises en attente dans la ''Store queue'', mais les lectures sont exécutées immédiatement. Une fois l'adresse à lire connue, la lecture consulte la ''Store queue'' pour détecter les dépendances de données, puis s'exécute. La donnée à lire est lue soit depuis la ''Store queue'', soit depuis le cache. [[File:Emission LOAD - Store séparée.png|vignette|upright=1|Émission LOAD - Store séparée]] L'implémentation de l'émission multiple est alors très simple. La ''Store queue'' a déjà deux ports, avec un pour les lectures et un autre pour les écritures. Idem pour le cache, qui a naturellement un port de lecture et un d'écriture. Émettre une lecture et une écriture simultanément ne demande donc pas de modification digne de ce nom. La ''Store queue'' doit juste supporter une lecture et une écriture simultanée. Ajouter l'émission d'une seconde lecture n'est pas compliquée : il faut juste rajouter un second port de lecture sur le cache et la ''Store queue''. Pour rappel, l'unité mémoire est précédée par une structure qui met en attente les micro-opérations mémoire avant leur émission finale. La structure en question varie suivant l'implémentation, mais un cas particulier se marie bien avec l'émission multiple des µops mémoire. Il s'agit du cas avec une file de µops séparée pour les lectures et une autre pour les écritures, appelées respectivement la ''file de µops LOAD'' et la ''file de µops STORE''. Il est alors possible d'émettre une lecture et une écriture lors du même cycle d'horloge. Le port de lecture alimente une unité de calcul d'adresse dédiée, directement reliée au cache. Le port d'écriture du cache alimente une unité de calcul, qui est suivie par une file d'écriture, elle-même reliée au cache. Les processeurs AMD de micro-architecture K6 utilisaient cette technique. [[File:Double émission avec le Load Ordering, Store Ordering.jpg|centre|vignette|upright=2.5|Double émission avec le Load Ordering, Store Ordering]] ==Les CPU superscalaire à exécution dans le désordre== La superscalarité modifie aussi les circuits dédiés à l'exécution dans le désordre. Elle modifie les unités de renommage de registre, le ROB et les autres structures liées à l'exécution dans le désordre, au sens large. Aucune structure n'est épargnée. Elles ont tous des prots de lecture/écriture en plus, afin d'encaisser l'émission, le ''commit'' ou le renommage simultané de plusieurs µops. Par exemple, le ROB doit être modifié pour émettre et terminer plusieurs instructions en même temps, en ajoutant des ports de lecture/écriture. Pour un CPU superscalaire à 8 voies, on se dit que le ROB peut retirer 8 µops par cycle maximum. Mais certains processeurs récents ont un ROB qui peut retirer le double ! Un exemple est celui des CPU de micro-architecture Skymont, qui peuvent émettre 8 µops par cycle, mais en retirer 16. Quelques CPU de marque AMD étaient aussi dans ce cas. L'avantage est que cela permet de réduire la taille du ROB, du banc de registre et de quelques autres structures matérielles liées à l'exécution dans le désordre. Le gain sur-compense le cout en transistor nécessaire pour retirer 16 µops par cycle. Dans cette section, nous allons voir comment les étages du pipeline dédiés à l'exécution dans le désordre sont modifiées sur un CPU superscalaire. ===L'exemple du PA-RISC PA 8000=== Avant de commencer, nous allons voir un processeur superscalaire assez simple, le PA 8000, de HP, qui implémente le jeu d'instruction PA-RISC. Bien que très ancien, il implémentait l'exécution dans le désordre et le renommage de registre. Le peu d'informations que nous avons sur ce processeurs proviennent des documents "THE HP PA-8000 RISC CPU" par Ashok Kumar, et l'article de microprocessor report "PA-8000 Combines Complexity and Speed". Ils ne donnent malheureusement pas énormémment d'informations et je devrais être amené à faire quelques suppositions dans ce qui suit. Avant de commencer, parlons de détails sans lien avec la superscalairité. Ce processeur, comme beaucoup de processeurs PA-RISC, n'intégrait pas de cache de niveau L2 dans le processeur, qui était déporté en-dehors du CPU, sur la carte mère. Le processeur préférait utiliser ses transistors pour avoir un cache L1 assez large, quitte à ce qu'il soit plus lent. La lenteur du cache était prévue, le processeur compensait celle-ci en utilisant l'exécution dans le désordre, bien que ce ne soit pas parfait. Les CPU PA-RISC avant le PA 8000 utilisaient un pipeline à vagues ''wave pipeline'', ce qui était assez peu commun, mais le PA 8000 repasse à un pipeline synchrone classique. Passons maintenant à la superscalarité. Le PA 8000 est un processeur quadruple émission, qui peut émettre, à chaque cycle, deux opérations et deux accès mémoire. L'exécution dans le désordre est prise en charge par une structure matérielle unique, qui ressemble à une fusion entre un ROB et une fenêtre d'instruction. Et c'est là que je vais devoir faire des suppositions. Le document "THE HP PA-8000 RISC CPU" nomme cette structure : l''''''Instruction Reorder Buffer'''''. Il utilise pas moins de 850 000 transistors, et prend 20% de la taille du ''die''. L'article "THE HP PA-8000 RISC CPU" laisse fortement sous-entendre qu'il s'agit une structure unique, faite d'un seul tenant, mais l'article de microprocessor report dit le contraire par moment. Il est décrit comme une fenêtre d'instruction, à savoir qu'il détecte les dépendances entre instruction et les émet. Il gère aussi la détection des mauvaises prédictions de branchement et peut annuler les instructions chargées à tord, en les retirant de la fenêtre d'instruction. Il est aussi précisé que les instructions quittent cet ''Instruction Reorder Buffer'' dans l'ordre du programme. Elles ne peuvent en sortir que quand elles ont été exécutées et qu'elles n'ont causé aucune exception. Ce qui fait qu'il se comporte comme un ROB de ce point de vue là. Difficile de dire si l'''Instruction Reorder Buffer'' est un réel mélange entre un ROB et une fenêtre d'instruction, ou si il est réellement conçu avec deux structures séparées. Dans ce qui suit, je pars du principe que les deux structures sont séparées. Le processeur contient deux fenêtres d'instruction : une réservée aux µops mémoire (LOAD et STORE), l'autre pour les opérations entières/flottantes. Elles ont chacune 28 entrées, ce qui permet de mémoriser 56 µops au maximum. Les deux peuvent recevoir 4 µops par cycle de la part des décodeurs. Là encore, précisons que les choses ne sont pas claires pour ce qui est de la séparation. L'article de Microprocessor report dit que les deux sont physiquement séparées, et que cette séparation physique permet de simplifications (les opérations mémorisent des noms de registres plus court que les adresses demandées par les µops LOAD/STORE). Mais l'autre document cité laisse penser que l''''Instruction Reorder Buffer'' est une structure unique. A chaque cycle, le processeur peut émettre deux instructions de calcul et deux instructions mémoire. Les deux fenêtres d'instruction ont pour cela chacune deux ports d'émission. Les deux prots d'émission pour les µops mémoire sont identiques, et peuvent faire aussi bien des µops LOAD que STORE. Le cache L1 est un cache double port, ce qui permet de faire deux lectures/écritures apr cycle, ce qui colle avec la double émision de µops mémoire. Pour ce qui est des µops entières/flottantes, le processeur a dupliqué toutes ses unités de calcul : il a deux ALU entières, deux ''barrel shifters'', deux FPU de type FMAC, et deux unités de division flottante. Vraisemblablement, il y a deux ports d'émission, chacun étant connecté à une unité de chaque type. Le partage des ports d'émission est donc parfait. En clair : le processeur aurait une superscalarité presque parfaite s'il était un CPU àç double émission ! A chaque cycle, la fenêtre d'instruction émet les deux µops les plus anciennes qui sont prête à être exécutées. La documentation dit que la fenêtre émet "la plus vielle instruction paire, et la plus vielle instruction impaire", ce qui sous-entend que la fenêtre d'instruction est en réalité composée de deux sous-fenêtres, une fenêtre paire et une impaire. Les µops sont insérées après le décodage dans ces sous-fenêtres : les deux µops sont réparties dans les deux. Et lors de l'émission, une µops vient d'une sous-fenêtre, une autre µops vient de l'autre. La fenêtre d’instruction a donc une structure partitionnée, avec une logique d'éveil segmentée, une partie gérant la moité de la fenêtre d'instruction, l'autre gérant le reste. [[File:PA 8000 - microarchitecture.png|centre|vignette|upright=2|PA 8000 - microarchitecture]] Le renommage de registre utilise des registres de renommage séparés des registres architecturaux, comme c'était la mode à l'époque. Le budget en transistor faisait que c'était soit ça, soit le renommage dans le ROB, faute de mieux. Le processeur utilise une implémentation ''Read After Issue'', ce qui veut dire que les opérandes des instructions sont lues après l'émission, juste avant l'exécution. La µops est émise, puis ses opérandes sont lues, pas l'inverse. Il n'y a pas de stations de réservation dans le processeur, les µops attendent que toutes leurs opérandes soient prêtes dans la fenêtre d'instruction, puis lisent les registres juste avant l'exécution. Le processeur peut aussi ''commit'' deux opérations et deux accès mémoire par cycle, ce qui revient à transférer les résultat des registres de renommage vers les registres architecturaux. ===La superscalarité avec une file/fenêtre d'instruction centralisée=== Plus haut, nous avons montré qu'un processeur pouvait avoir plus de ports d'émission que de ports de décodage. On dit aussi que sa ''largeur de décodage'' était supérieure à sa ''largeur d'émission''. La '''largeur de décodage''' est le nombre de µops fournies par l'unité de décodage par cycle d'horloge, la '''largeur d'émission''' est le nombre maximal de µops émises par cycle d'horloge. Et n'allez pas croire qu'un surplus de ports d'émission est du gâchis. Sur les processeurs avec exécution dans le désordre, ce surplus peut être utilisé. Mais avant toute chose, évacuons un détail. Vous avez sans doute pensé que le surplus peut être exploité par les instructions machines décodées en plusieurs µops . Par exemple, si une instruction est décodée en deux µops, on pourrait avoir un port d'émission en plus pour en profiter. Mais les ports de décodage sont *en sortie du décodeur*, et contiennent des µops, pas des instructions. Le surplus de ports d'émission peut occasionnellement utiliser le surplus de ports de décodage, mais cela implique que des µops ont été mises en attente dans l'unité d'émission, pour être émises par la suite. Et cela implique l'usage d'une fenêtre d'instruction ou d'une file de µops. Le principe est que les µops sont accumulées dans la fenêtre d'instruction, en attendant leurs opérandes ou la résolution d'une dépendance. Et si l'occasion se présente, une µops est émise sur chaque port d'émission. Il y a donc un gain en performances, mais il faut faire quelques précisions sur son origine. La largeur d'émission utilisée ne peut pas dépasser, *en moyenne*, la largeur de décodage. Et c'est intuitif : un CPU qui décode 4 µops par cycle ne peut pas émettre 6 par cycle en moyenne, sur le temps long, il n'y a pas de µops en surplus qui sortent du vide. Par exemple, sur un processeur quadruple émission, si on analyse combien d'instructions sont émises par cycle, il peut y avoir des cycles où la largeur d'émission est totalement utilisée, mais ce sera compensé par des périodes où elle est fortement sous-utilisée. Les µops sont accumulées en cas de sous-utilisation, puis consommées en cas d'utilisation complète. Les deux périodes se compensent. Et c'est là que l'on peut comprendre d'où vient le gain en performance. Les cycles où les ports d'émission sont sous-utilisés existent systématiquement, que le processeur utilise l'exécution dans le désordre ou pas. Ils sont liés à la présence de dépendances de données, aux contraintes d’appariement, etc. Elles tendent à réduire la moyenne du nombre de µops émises par cycle. Par contre, ce sont les cycles de rattrapage, où les ports en surplus sont utilisés, qui font remonter la moyenne. Le gain en performance est donc lié à ces cycles de rattrapage, où les µops accumulées sont émises dans les ports en surplus. Et ils n'existent que sur les processeurs avec une file/fenêtre d'instruction. Réduire le nombre de ports d'émission permet de garder des fenêtres d'instruction et un ROB simples, rapides et économes en énergie. Et mine de rien, c'est là un compromis important : à quoi bon augmenter le nombre de ports d'émission si c'est pour que ce soit compensé par une fréquence plus faible ? Par contre, réduire le nombre de ports augmente la ''port contention'', surtout si on a mal réparti les ALU. Il faut donc trouver un compromis entre réduire le nombre de ports d'émission d'un côté, réduire la ''port contention'' de l'autre. La différence entre largeur de décodage et d'émission a un impact assez fort sur le banc de registre, et précisément sur son nombre de ports de lecture. Le banc de registre a besoin de plus de ports de lecture avec une fenêtre d’instruction qu'avec des stations de réservation. Rappelons la terminologie utilisée dans ce cours. Les fenêtres d'instruction se contentent de mémoriser la micro-opération et quelques bits pour détecter la disponibilité des opérandes. Par contre, les stations de réservations mémorisent aussi les opérandes des instructions. Et cette différence a une influence le nombre de ports de lecture du banc de registre. Supposons que toutes les instructions sont dyadiques, à deux opérandes. Comptons le nombre de ports nécessaires pour alimenter les unités de calcul, sans utiliser d'arbitre de banc de registre. Avec une fenêtre d'instruction, il faut le double du nombre de ports d'émission. Mais avec des stations de réservation, il faut le double des ports de décodage. La raison est que les registres sont lus après émission avec une fenêtre d'instruction, avant avec des stations de réservation (sous-entendu, après le décodage). Or, comme dit plus haut, les processeurs superscalaires larges ont souvent plus de ports d'émission que de décodage. ===La superscalarité à fenêtres d'instruction décentralisées=== Les processeurs précédents utilisaient une unité d'émission simple, qui pouvait utiliser l'émission dans l'ordre ou dans le désordre. Elle peut être remplacée par une fenêtre d'instruction centralisée dans que cela quoi que ce soit aux explications précédentes, idem avec une station de réservation centralisée. En soi, l'exécution dans le désordre est donc totalement compatible avec une implémentation simple de la superscalarité. Par contre, des subtilités surviennent avec les fenêtres d'instruction décentralisées. Pour rappel, sur ces processeurs, les µops sont émises en deux phases. Une première phase de ''dispatch'' qui envoie les µops vers la fenêtre d'instruction adéquate, sans détecter les dépendances de données. La seconde phase de ''schedule'' gère les dépendances de données, elle met en attente les µops en attendant que l'unité soit disponible pour les exécuter, en attendant aussi que les opérandes soient disponibles. Et à ce petit jeu, il y a une différence entre le nombre de µops qui sont ''dispatch par cycle'' et celles qui sont ''schedule''. Dit autrement, la largeur d'émission est scindée en une '''largeur de ''dispatch''''' et une '''largeur de ''schedule''. Par exemple, prenons un processeur triple émission avec deux stations de réservation : une pour les µops entières/mémoire, et une autre pour les µops flottantes. L'unité d'émission peut ''dispatch'' maximum trois µops par cycle : soit trois µops entières/mémoire, soit trois flottantes, soit un mix de trois µops différentes. Les stations de réservation, quant à elles, peuvent chacune ''schedule'' 3 µops par cycle, vers trois ALUs entières pour la station de réservation entière/mémoire, vers trois FPS pour la station de réservation flottante. De quoi ''dispatch'' trois µops, mais d'en ''schedule'' six, à chaque cycle. Et cet exemple ne sort pas de nulle part : les CPU x86 d'Intel et AMD sont globalement dans ce cas, même si les chiffres varient d'une microarchitecture à l'autre. L'exemple précédent colle parfaitement à la microarchitecture K7 d'AMD, utilisée sur les processeurs Athlon dans les années 2000. [[File:AMD K7.png|centre|vignette|upright=2.5|AMD K7, microarchitecture.]] L'exemple précédent avait assez d'unités entières/flottantes pour couvrir toute la largeur de décodage/''Dispatch''. Mais ce n'est pas toujours le cas, comme va le montrer l'exemple suivant. Le MIPS R10000, qui utilisait un mélange de files de µops et de fenêtres d'instructions : une file de µops les accès mémoire, une fenêtre pour les instructions entières et une autre pour les opérations flottantes. Les branchements et NOPs étaient exécutés dans une unité de branchement distincte. Les trois files/fenêtres peuvent mémoriser 16 µops. Le processeur avait deux ALU entières, une AGU de calcul d'adresse, un additionneur flottant et un multiplieur/diviseur flottant. Il y avait un multiplieur entier sur le port d'émission l'ALU 2. Le processeur décodait 4 instructions par cycle et produisait jusqu'à 4µops, qui étaient redistribuées sur les trois fenêtres d'instructions. Chacune pouvait accepter 4 µops par cycle, ce qui fait que processeur pouvait ''dispatch'' 4 µops entières, ou 4 µops flottantes, ou 4 µops mémoire, ou un mélange de deux ou trois types de µops. Pour ce qui est du ''schedule'', la fenêtre d'instruction entière pouvait émettre 2 µops, la fenêtre flottante pouvait émettre une addition en même temps qu'une multiplication/divison flottante et qu'un branchement conditionnel flottant, et la file de µops mémoire ne pouvait émettre qu'une µop mémoire à la fois. En tout, cela fait 6 µops ''schedule'' pour 4 µops au ''dispatch''. [[File:R 10000.png|centre|vignette|upright=2.5|MIPS R10000, microarchitecture.]] ===La superscalarité à fenêtres d'instruction totalement décentralisées=== Prenons un cas extrême de fenêtre d'instruction décentralisée : celui où chaque ALU entière a sa propre station de réservation. En clair : une fenêtre d'instruction par ALU/FPU ! On parle de '''fenêtres d'instruction totalement décentralisées'''. Vous vous dites que ce cas est un peu trop extrême pour être réaliste, mais il n'en est rien. C'est même très courant sur les architectures basse consommation, et sur pas mal de CPU x86 modernes. Une telle organisation entraine une légère perte de performance, comparé à une fenêtre d'instruction centralisée ou partiellement décentralisée. Et cela peut se comprendre par un exemple. Imaginez un processeur avec deux ALU, donc deux stations de réservation. Il arrivera qu'une station de réservation ait plusieurs µops prêtes, alors que l'autre en ait zéro. Dans une telle situation, une seule µop sera émise au cycle suivant, vu que chaque station de réservation a un seul port d'émission vers une seule ALU entière. Par contre, avec une fenêtre d'instruction centralisée double port, on aurait pu émettre les deux µops en même temps sur deux ALUs séparées. La perte de performance est donc liée au fait que les µops '''''prêtes''''' sont mal réparties dans les différentes stations de réservation. Il arrivera que des µops prêtes s'accumulent dans une station de réservation, alors que d'autres seront pleines, ou du moins sous-utilisées. Et ce n'est pas quelque chose qui peut être réglé à l'étape de ''dispatch'', car on ne sait pas encore quand les µops auront leurs opérandes de disponibles. [[File:Comparaison entre une station de réservation totalement décentralisée et une autre qui ne l'est pas.png|centre|vignette|upright=2.5|Comparaison entre une station de réservation totalement décentralisée et une autre qui ne l'est pas.]] Par contre, décentraliser totalement les fenêtres d'instruction entraine aussi un gain considérable en termes de consommation énergétique. Et c'est la raison pour laquelle les fenêtres d'instructions totalement décentralisées sont utilisées sur les architectures basse consommation. La perte de performance ne peut pas s'expliquer clairement à ce stade du cours, car il nous faudrait parler d'émission superscalaire. Le gain en matière d'énergie vient de l'économie de circuits, qui est assez drastique. Le gain en matière d'énergie vient de l'économie de circuits, qui est assez drastique. Je rappelle qu'une station de réservation a besoin, pour N instructions, d'environ N^2 circuits (des comparateurs, notamment). Prenons une station de réservation centralisée de 64 entrées et comparons avec 8 stations de 8 entrées chacune. Les deux donneront 64 entrées, mais la première aura un cout en circuit proportionnel à 64², alors que le second aura un cout en circuit de 8 *(8²). Entre les deux, le choix est clair : la seconde solution est plus économe. D'où l'utilisation de cette solution sur les microarchitectures basse consommation. ===L'unité de renommage superscalaire=== Avec la superscalarité, l'unité de renommage de registre doit gérer le cas où des instructions consécutives ont des dépendances de registre. Par exemple, prenons un processeur à double émission, qui renomme deux instructions consécutives. Si elles ont une dépendance de registre, le renommage de la seconde instruction dépend du renommage de la première. La première doit être renommée et le résultat du renommage est utilisé pour renommer la seconde, ce qui empêche d'utiliser deux unités de renommage séparées. Pour cela, elle renomme les registres sans tenir compte des dépendances, pour ensuite corriger le résultat. [[File:Unité de renommage superscalaire.png|centre|vignette|upright=2|Unité de renommage superscalaire.]] Seules les dépendances lecture-après-écriture doivent être détectées, les autres étant supprimées par le renommage de registres. Repérer ce genre de dépendances se fait assez simplement : il suffit de regarder si un registre de destination d'une instruction est un opérande d'une instruction suivante. [[File:Détection des dépendances sur un processeur superscalaire.png|centre|vignette|upright=2|Détection des dépendances sur un processeur superscalaire.]] Ensuite, il faut corriger le résultat du renommage en fonction des dépendances. Si une instruction n'a pas de dépendance avec une autre, on la laisse telle quelle. Dans le cas contraire, un registre opérande sera identique avec le registre de destination d'une instruction précédente. Dans ce cas, le registre opérande n'est pas le bon après renommage : on doit le remplacer par le registre de destination de l'instruction avec laquelle il y a dépendance. Cela se fait simplement en utilisant un multiplexeur dont les entrées sont reliées à l'unité de détection des dépendances. On doit faire ce replacement pour chaque registre opérande. [[File:Correction des dépendances sur un processeur superscalaire.png|centre|vignette|upright=2|Correction des dépendances sur un processeur superscalaire.]] ==Les optimisations des processeurs superscalaires larges== Les processeurs superscalaires larges ont des optimisations spécifiques, qui n'ont pas de sens sur les processeurs superscalaires étroits. Dans les grandes lignes, elles se classent en deux types. Les premières permettent de charger/décoder plus de 5-10 instructions simultanément. Le problème est alors que les branchements viennent mettre leur grain de sel et qu'il faut en tenir compte. Les secondes corrigent des problèmes qui apparaissent quand un CPU intègre plus de 5 à 10 unités de calcul. ===L'étape de chargement d'un CPU superscalaire large=== Charger plusieurs instructions pose de nombreux problèmes sur les processeurs superscalaires larges, qui émettent de 5 à 10 instructions simultanées. Pour rappel, la stratégie basique pour charger N instructions est de charger un bloc de N instructions consécutives. Les instructions après un branchement ne sont pas décodées ni exécutées, ce qui entraine une petite baisse de performance. Pour un N petit, la perte de performance est mineure. Mais pour un N large, elle devient suffisamment importante pour que la conception du CPU doit alors être repensée de fond en comble. Les analyses statistiques disent qu'il y a environ un branchement tous les 4 à 6 instructions. Un CPU a donc tendance à décoder des paquets de 3 à 5 instructions consécutives, avant qu'un branchement casse la dynamique. Or, cela pose des problèmes pour utiliser plusieurs décodeurs. L'implémentation basique, qui charge N instructions consécutives pour alimenter N décodeurs, fonctionne donc jusqu'à 4/6 décodeurs. Au-delà de 5 instructions, un CPU superscalaire doit être adapté pour gérer les branchements dans les paquets d'instruction qu'il émet. Le nombre de 5 instructions ne sort donc pas de nulle part. La première solution utilise un cache de µops, avec un ''front-end'' capable de charger/décoder 4/5 instructions à la fois, pas plus. L'idée est que la majorité des instructions proviennent du cache de µops (plus de 80%), ce qui fait qu'on peut émettre environ 10 instructions à partir du cache de µops, pas besoin d'avoir beaucoup de décodeurs. Les performances sont cependant dégradées lors d'un défaut de cache de µops. Les instructions doivent alors être chargées depuis le cache d'instruction, par paquets de 4-5, puis sont décodées par 4-5 décodeurs, ce qui ne permet pas d’alimenter les unités de calcul à plein régime. La solution précédente joue sur la distinction entre pots de décodage et d'émission. Elle permet d'émettre un grand nombre de µops sans pour autant charger un grand nombre d'instructions en même temps. En quelque sorte, ce n'est qu'une méthode de contournement, le CPU superscalaire reste de type étroit. Mais il est aussi possible d'utiliser un '''''front-end large''''', capable de charger une bonne dizaine d'instructions en même temps. La seule difficulté est de tenir compte de la présence de branchements. Pour rappel, avec un ''front-end'' étroit, les instructions situées après le premier branchement pris sont annulées, elles ne sont pas décodées ni exécutées. [[File:Fetch sur un processeur superscalaire avec prediction de branchements.png|centre|vignette|upright=2|Fetch sur un processeur superscalaire avec prédiction de branchements.]] Un ''front-end'' large charge les instructions de destination du branchement et les placent à sa suite. Ils chargent deux blocs à la fois et les fusionnent en un seul qui ne contient que les instructions présumées utiles. [[File:Cache d'instructions autoaligné.png|centre|vignette|upright=2|Cache d'instructions auto-aligné.]] Mais cela demande de charger deux blocs de mémoire en une fois, ce qui demande un cache d'instruction multiports. Il faut aussi ajouter un circuit pour assembler plusieurs morceaux de blocs en un seul : le fusionneur (''merger''). En pratique, cette solution demande d'ajouter un second port de lecture au cache, pour un cout en hardware important, avec un impact négatif sur le temps d'accès au cache. Et il faut rajouter le fusionneur, qui prend un étage de pipeline à lui tout seul. Et encore, cette solution ne gère pas le cas où un bloc contient plusieurs branchements ! [[File:Implémentation d'un cache d'instructions autoaligné.png|centre|vignette|upright=2|Implémentation d'un cache d'instructions auto-aligné.]] Les exemples précédents partent du principe qu'il n'y a qu'un seul branchement dans un bloc. Mais quand les blocs deviennent assez longs, il est fréquent d'avoir plusieurs branchements dans un bloc. Et il est même possible d'avoir plusieurs branchements pris. Dans un bloc de 8-10 instructions, ce n'est pas rare, et les CPU superscalaires à 8-10 voies sont la règle dans les CPU des années 2020. Pour gérer ce cas, il faut ajouter des ports supplémentaires au cache d'instruction et adapter le fusionneur, pour qu'il puisse fusionner trois ou quatre blocs. De plus, il faut utiliser une unité de prédiction de branchement capable de ''prédire plusieurs branchements par cycle''. ===Le décodage superscalaire large=== Le décodage des instructions n'est pas censé dépendre de l'implémentation du chargement. En théorie, une fois plusieurs blocs d'instruction fusionnés, on peut décoder les instructions en parallèle. Cependant, certains processeurs effectuent le décodage en tenant compte de la manière dont les branchements découpent les blocs. Les processeurs Atom d'Intel utilisent une solution de ce type, qui couple prédiction de branchement et décodage parallèle. Ils chargent/décodent des paquets de 3 instructions consécutives, chaque paquet étant séparé du précédent par un branchement. Pour cela, en plus d'avoir un fusionneur adapté, ils regroupent les décodeurs en ''clusters'', chacun regroupant 3 décodeurs, et pouvant décoder trois instructions consécutives. Les micro-architectures Tremont et Crestmont avaient deux ''clusters'' (6 décodeurs au total), la micro-architecture Darkmont en intègre trois (9 décodeurs au total). Avec deux ''clusters'', le fonctionnement est le suivant. Si le code est composé d'une suite d'instruction sans branchements, seul le premier ''cluster'' est utilisé, limitant le décodage à trois instructions par cycle. Par contre, si l'une des trois instructions décodée est un branchement, alors le second ''cluster'' décode les trois instructions situées après ce branchement, à partir de l'adresse de destination. Avec un troisième ''cluster'', c'est la même chose, sauf qu'il faut qu'il y ait un branchement dans les trois instructions décodées par le second ''cluster''. Mais comment faire pour savoir quels décodeurs activés, quels ''clusters'' sont actifs ? C'est la prédiction de branchement qui commande. Avec deux ''clusters'', elle détermine si un branchement est présent dans les trois instructions à charger, et quelle est son adresse de destination. Sans branchement, elle prévient les décodeurs et les trois instructions chargées sont décodées dans un ''cluster'' libre. Si elle prédit un branchement, elle charge les instructions adéquates, et active les deux ''clusters''. Avec trois branchements, c'est le même mécanisme, sauf que l'unité de prédiction de branchement doit être capable de prédire deux branchements par cycle. [[File:Front-end découplé de la microarchitecture Tremont.png|centre|vignette|upright=3|Front-end découplé de la microarchitecture Tremont.]] Il faut noter que les décodeurs d'un ''cluster'' sont des décodeurs simples, sans microcode. Sur les processeurs Tremont et Crestmont, le microcode était unique et était partagé entre tous les ''clusters''. Un seul ''cluster'' pouvait décoder une instruction complexe avec le microcode, l'autre devait se limiter à des instructions simples uniquement. Depuis Skymont, le microcode est partiellement dupliqué, avec un microcode par ''cluster''. Le cout en hardware peut paraitre prohibitif, pour un gain en performance faible. Sauf que c'est oublier que ce sont des processeurs Atom, sur lesquels beaucoup d'instructions sont microcodées. Les processeurs Atom ont un budget en transistor limité, ce qui fait qu'il est préférable pour eux d'implémenter des instructions en microcode que d'utiliser des unités de calcul dédiées ou des circuits de décodage complexes. Pour limiter la casse, le microcode n'est que partiellement dupliqué. Seul le microcode pour les instructions fréquente est dupliqué. Il y a un microcode secondaire pour certaines instructions, qui est lui unique et partagé par tous les ''clusters''. ===Le contournement sur les processeurs superscalaires larges=== Pour rappel, la technique du contournement (''register bypass'') permet au résultat d'une instruction d'être immédiatement utilisable en sortie de l'ALU, avant même d'être enregistré dans les registres. Implémenter la technique du contournement demande d'utiliser des multiplexeurs pour relier la sortie de l'unité de calcul sur son entrée si besoin. Il faut aussi des comparateurs pour détecter des dépendances de données. [[File:Pipeline Bypass.png|centre|vignette|upright=1|Pipeline Bypass]] La sortie de chaque ALU doit être reliée aux entrées de toutes les autres, avec les comparateurs qui vont avec. Sur les processeurs ayant plusieurs d'unités de calculs, cela demande beaucoup d’interconnexions et de comparateurs. Pour N unités de calcul, cela demande 2 * N² interconnexions, implémentées avec 2N multiplexeurs de N entrées chacun. Si c'est faisable pour 2 ou 3 ALUs, la solution est impraticable au-delà. Non seulement ce serait un enfer à câbler, mais les fils seraient tellement longs que la fréquence du processeur en prendrait un coup. Notez que cela vaut pour les processeurs superscalaires, mais aussi pour tout processeur avec beaucoup d'unités de calcul. En théorie, un CPU à exécution dans le désordre, non-superscalaire, mais avec beaucoup d'unités de calcul, fait face au même problème. En pratique, avoir une dizaine d'ALU implique processeur superscalaire à exécution dans le désordre. D'où le fait qu'on parle du problème maintenant. La seule solution praticable est de ne pas relier toutes les unités de calcul ensemble. À la place, on préfère regrouper les unités de calcul dans différents '''agglomérats''' ('''cluster'''). Le contournement est alors possible entre les unités d'un même agglomérat, mais pas entre agglomérats différents. Évidemment, certaines possibilités de contournement sont perdues, mais c'est compensé par un gain en fréquence et un cout en circuit/fils réduit. C'est un bon compromis, ce qui explique que presque tous les processeurs modernes l'utilisent. Les rares exceptions sont les processeurs POWER 4 et POWER 5, qui ont préféré se passer de contournement pour garder un processeur très simple et une fréquence élevée. ===Le banc de registre des processeurs superscalaires larges=== Pour émettre deux opérations entières simultanément, il faut lire deux fois plus d'opérandes. Et il faut aussi écrire deux résultats dans les registres, en même temps. Pour cela, on double les ports du banc de registre. En général, il faut au maximum 2 ports de lecture et un port d'écriture par unité de calcul. Le problème, c'est que plus un banc de registres a de ports, plus il utilise de circuits, est compliqué à concevoir, consomme de courant et chauffe. Avec plusieurs dizaines d'unités de calcul différentes, ajouter autant de ports impacterait la fréquence du banc de registres et réduirait les performances, voire est totalement impraticable à cause des contraintes thermiques. Les processeurs superscalaires larges doivent donc trouver des solutions. La première solution utilise un banc de registre unique, mais n'utilise pas autant de ports que le pire des cas le demanderait. Le processeur détecte quand il n'y a pas assez de ports pour servir toutes les micro-opérations. Quand ça arrive, l'unité d'émission émet assez de micro-opérations pour exploiter les ports disponibles, mais met en attente les micro-opérations en trop, le temps que les ports se libèrent. Pour cela, le banc de registre est géré par un circuit d'arbitrage spécialisé, intégré à l'unité d'émission, l’'''arbitre du banc de registres''' (''register file arbiter''). Une autre solution est de dupliquer le banc de registres en plusieurs exemplaires qui contiennent exactement les mêmes données, mais avec moins de ports de lecture/écriture. Un exemple est celui des processeurs POWER, Alpha 21264 et Alpha 21464. Sur ces processeurs, le banc de registre est dupliqué en plusieurs exemplaires, qui contiennent exactement les mêmes données. Les écritures dans les registres sont envoyées à tous les bancs de registres, afin de garantir que leur contenu est identique. Chaque exemplaire a exactement deux ports de lecture. La conception du processeur est simplifiée, que ce soit au niveau du câblage, que de la conception des bancs de registres. Une dernière solution découpe le banc de registres en plusieurs bancs de registres plus petits, avec un réseau d'interconnexions pour échanger des données entre bancs de registres. Dans la plupart des cas, cette séparation est invisible du point de vue de l'assembleur et du langage machine. Le processeur se charge de transférer les données entre bancs de registres suivant les besoins. Sur d'autres processeurs, les transferts de données se font via une instruction spéciale, souvent appelée ''COPY''. [[File:Banc de registres distribué.png|centre|vignette|upright=2|Banc de registres distribué.]] Sur de certains processeurs, un branchement est exécuté par une unité de calcul spécialisée. Or les registres à lire pour déterminer l'adresse de destination du branchement ne sont pas forcément dans le même agglomérat que cette unité de calcul. Pour éviter cela, certains processeurs disposent d'une unité de calcul des branchements dans chaque agglomérat. Dans les cas où plusieurs unités veulent modifier le ''program counter'' en même temps, un système de contrôle général décide quelle unité a la priorité sur les autres. Mais d'autres processeurs fonctionnent autrement : seul un agglomérat possède une unité de branchement, qui peut recevoir des résultats de tests de toutes les autres unités de calcul, quel que soit l’agglomérat. ==La macro-fusion : une optimisation du décodage parallèle== Les processeurs superscalaires supportent la technique dite de '''macro-fusion''', qui permet de fusionner deux-trois instructions consécutives en une seule micro-opération. Par exemple, il est possible fusionner une instruction de test et une instruction de saut en une seule micro-opération de branchement. Il s'agit là de l'utilisation la plus importante de la macro-fusion sur les processeurs x86 modernes. La macro-fusion est utilisée pour fusionner un test et un saut en un branchement unique. L'optimisation est présente sur la plupart des CPU superscalaires modernes. Les CPU x86 l'implémentent, mais aussi quelques CPU ARM et les processeurs Apple de série M (M1 à M5, et potentiellement plus quand ils seront sortis). La fusion des instructions se fait lors du décodage des instructions, grâce à la coopération des décodeurs. Elle marche systématiquement si l'instruction de test et le saut sont consécutives, qu'elles forment bien une paire d'instruction. Par contre, insérer une instruction entre les deux empêche la macro-fusion de faire son travail, sauf si l'instruction insérée est un NOP. Les processeurs ARM64 avaient une forme spécifique de macro-fusion, utilisée pour un cas très précis : charger une constante immédiate de 32 ou 64 bits, dans un registre 64 bits. Les CPU ARM 64 bits utilisent des instructions codées sur 32 bits, qui ne peuvent encoder que des constantes immédiates de 16 bits. Pour charger une constante de 32/64 bits, il faut s'y prendre en plusieurs fois. Une première instruction MOVZ charge les 16 premiers bits, puis 2 à 4 instructions MOVK remplissent le reste. MOVZ met à zéro les 48 bits de poids fort, MOVK permet de sélectionner le doublet à modifier dans le registre (on modifie 16 bits, dont on choisit la place, le reste du registre est laissé tel quel). ARM permet de fusionner cette suite d'instructions en une seule µop MOV avec une constante immédiate. On parle alors de '''''MOVZ + MOVK fusion'''''. Une dernière utilisation, [https://www2.eecs.berkeley.edu/Pubs/TechRpts/2016/EECS-2016-130.pdf proposées pour le jeu d'instruction RISC-V], fusionnait un calcul d'adresse et une instruction LOAD/STORE en une seule instruction d'accès mémoire. Elle a été envisagée à une époque où le jeu d'instruction RISC-V ne gérait pas les modes d'adressage base + indice. L'idée était d'avoir une unité mémoire qui gérait le mode d'adressage base + indice et de fusionner des instructions pour l'exploiter. Mais de nos jours, le jeu d'instruction RISC-V intègre le mode d'adressage base + indice, ce qui fait que la macro-fusion n'a aucun intérêt pour ce cas précis. La macro-fusion a de nombreuses limitations en pratique. En théorie, on pourrait l'utiliser au-delà des deux situations mentionnées plus haut. Par exemple, pour fusionner une addition et une multiplication en une seule instruction MAD. Mais l'intérêt est assez faible. Notons que la macro-fusion ne permet que de fusionner des paires d'instructions. Aller au-delà demanderait un cout en circuit trop important. Déjà que tester deux paires utilise pas mal de comparateurs... ==Le ''stack engine'' : une optimisation de la pile d'appel== Les processeurs modernes intègrent une optimisation liée au pointeur de pile. Pour rappel, sur les architectures modernes, le pointeur de pile est un registre utilisé pour gérer la pile d'appel, précisément pour savoir où se trouve le sommet de la pile. Il est manipulé par les instructions CALL, RET, PUSH et POP, mais aussi par les instructions d'addition/soustraction pour gérer des cadres de pile de taille variable. De plus, il peut servir d'opérande pour des instructions LOAD/STORE, afin de lire/écrire des variables locales, les arguments d'une fonction, et autres. C'est donc un registre général adressable, intégré au banc de registre, altéré par l'unité de calcul entière. L'incrémentation/décrémentation du pointeur de pile passe donc par l'unité de calcul, lors des instructions CALL, RET, PUSH et POP. Mais, l'optimisation que nous allons voir permet d'incrémenter/décrémenter le pointeur de pile sans passer par l'ALU, ou presque. L'idée est de s'inspirer des architectures avec une pile d'adresse de retour, qui intègrent le pointeur de pile dans le séquenceur et l'incrémentent avec un incrémenteur dédié. ===Le ''stack engine''=== L'optimisation que nous allons voir utilise un '''''stack engine''''' intégré à l'unité de contrôle, au séquenceur. Le processeur contient toujours un pointeur de pile dans le banc de registre, cela ne change pas. Par contre, il n'est pas incrémenté/décrémenté à chaque instruction CALL, RET, PUSH, POP. Un compteur intégré au séquenceur est incrémenté à la place, nous l’appellerons le '''compteur delta'''. La vraie valeur du pointeur de pile s'obtient en additionnant le compteur delta avec le registre dans le banc de registre. Précisons que si le compteur delta vaut zéro, la vraie valeur est dans le banc de registre et peut s'utiliser telle quelle. Lorsqu'une instruction ADD/SUB/LOAD/STORE utilise le pointeur de pile comme opérande, elle a besoin de la vraie valeur. Si elle n'est pas dans le banc de registre, le séquenceur déclenche l'addition compteur-registre pour calculer la vraie valeur. Finalement, le banc de registre contient alors la bonne valeur et l'instruction peut s'exécuter sans encombre. L'idée est que le pointeur de pile est généralement altéré par une série d'instruction PUSH/POP consécutives, puis des instructions LOAD/STORE/ADD/SUB utilisent le pointeur de pile final comme opérande. En clair, une bonne partie des incrémentations/décrémentation est accumulée dans le compteur delta, puis la vraie valeur est calculée une fois pour toutes et est utilisée comme opérande. On accumule un delta dans le compteur delta, et ce compteur delta est additionné quand nécessaire. Précisons que le compteur delta est placé juste après le décodeur d'instruction, avant même le cache de micro-opération, l'unité de renommage et l'unité d'émission. Ainsi, les incrémentations/décrémentations du pointeur de pile disparaissent dès l'unité de décodage. Elles ne prennent pas de place dans le cache de micro-opération, ni dans la fenêtre d'instruction, ni dans la suite du pipeline. De nombreuses ressources sont économisées dans le ''front-end''. Mais utiliser un ''stack engine'' a aussi de nombreux avantages au niveau du chemin de données/''back-end''. Déjà, sur les processeurs à exécution dans le désordre, cela libère une unité de calcul qui peut être utilisée pour faire d'autres calculs. Ensuite, le compteur delta mémorise un delta assez court, de 8 bits sur le processeur Pentium M, un peu plus pour les suivants. L'incrémentation se fait donc via un incrémenteur 8 bits, pas une grosse ALU 32/64 bits. Il y a un gain en termes de consommation d'énergie, un incrémenteur 8 bits étant moins gourmand qu'une grosse ALU 32/64 bits. ===Les points de synchronisation du delta=== La technique ne fonctionne que si la vraie valeur du pointeur de pile est calculée au bon moment, avant chaque utilisation pertinente. Il y a donc des '''points de synchronisation''' qui forcent le calcul de la vraie valeur. Plus haut, nous avions dit que c'était à chaque fois qu'une instruction adresse le pointeur de pile explicitement, qui l'utilise comme opérande. Les instructions CALL, RET, PUSH et POP ne sont pas concernées par elles utilisent le pointeur de pile de manière implicite et ne font que l'incrémenter/décrémenter. Mais dans les faits, c'est plus compliqué. D'autres situations peuvent forcer une synchronisation, notamment un débordement du compteur delta. Le compteur delta est généralement un compteur de 8 bits, ce qui fait qu'il peut déborder. En cas de débordement du compteur, le séquenceur déclenche le calcul de la vraie valeur, puis réinitialise le compteur delta. La vraie valeur est donc calculée en avance dans ce cas précis. Précisons qu'un compteur delta de 8 bits permet de gérer environ 30 instructions PUSH/POP consécutives, ce qui rend les débordements de compteur delta assez peu fréquent. À noter que si le compteur delta vaut zéro, il n'y a pas besoin de calculer la vraie valeur, le séquenceur prend cette situation en compte. Un autre point de synchronisation est celui des interruptions et exceptions matérielles. Il faut que le compteur delta soit sauvegardé lors d'une interruption et restauré quand elle se termine. Idem lors d'une commutation de contexte, quand on passe d'un programme à un autre. Pour cela, le processeur peut déclencher le calcul de la vraie valeur lors d'une interruption, avant de sauvegarder les registres. Pour cela, le processeur intègre un mécanisme de sauvegarde automatique, qui mémorise la valeur de ce compteur dans le tampon de réordonnancement, pour forcer le calcul de la vraie valeur en cas de problème. La technique du ''stack engine'' est apparue sur les processeurs Pentium M d'Intel et les processeurs K10 d'AMD, et a été conservée sur tous les modèles ultérieurs. L'implémentation est cependant différente selon les processeurs, bien qu'on n'en connaisse pas les détails et que l'on doive se contenter des résultats de micro-benchmarks et des détails fournit par Intel et AMD. Selon certaines sources, dont les manuels d'optimisation d'Agner Fog, les processeurs AMD auraient moins de points de synchronisation que les processeurs Intel. De plus, leur ''stack engine'' serait placé plus loin que prévu dans le pipeline, après la file de micro-opération. ==La micro-fusion et la délamination== La '''micro-fusion''' est une optimisation qui retarde le décodage réel de certaines instructions assez loin dans le pipeline. Elle concerne surtout les instructions ''load-op'', mais pas que. D'autres instructions mémoire peuvent subir cette optimisation. L'essentiel est que, sans micro-fusion, ces instructions sont décodées en plusieurs micro-opérations. La micro-fusion retarde le décodage final de ces instructions, qui se fait assez tard dans le pipeline. Pour comprendre l'intérêt, nous allons devoir faire quelques explications. L'optimisation en question fait le décodage en deux temps. Prenons l'exemple d'une opération ''load-op'', qui est censée être décodée en deux micro-opérations : une lecture, puis une opération. Le décodage produit une '''macro-opération''' (terme d'Intel), qui est propagée dans le pipeline, pour être scindée en deux micro-opérations un peu avant les ALU et l'unité mémoire. La macro-opération est techniquement une micro-opération comme une autre, sauf que ce n'est pas la micro-opération finale. L'unité d'émission découpe cette macro-opération en deux micro-opérations, qui sont émises l'une après l'autre. Pour résumer, les instructions ''load-op'' ne sont complétement découpées en micro-opération lors de l'émission, pas lors du décodage. L'optimisation impacte ce qui se situe entre le décodeur d'instruction et l'unité d'émission : l'unité de renommage, la file de micro-opérations, le ''Loop Stream Detector'' et/ou le cache de micro-opération. L'intérêt de l'optimisation est que l'on fusionne deux micro-opérations en une seule macro-opération. Le cache de micro-opération et la file de micro-opération peuvent mémoriser plus de micro-opérations, vu que certaines sont fusionnées. Quant à l'unité de renommage, elle renomme une seule macro-opération au lieu de renommer deux micro-opérations, ce qui augmente le débit du renommage de registre. Par contre, cela complique un peu le travail de l'unité d'émission, qui doit découper les instructions ''load-op'' en deux et émettre les micro-opérations l'une après l'autre. Il faut noter qu'il n'y a pas de fusion proprement dite. Le décodeur ne décode pas deux micro-opérations séparées, avant de les fusionner. En réalité, il génère directement une macro-opération, qui correspond à deux micro-opérations, que ce soit plus tard dans le pipeline ou sur une autre architecture. D'ailleurs, la micro-fusion a lieu à l'intérieur d'une instruction, qui est censée être traduite en plusieurs micro-opérations. Et encore : pas toutes. La conséquence est que la technique n'a de sens que sur les processeurs CISC, avec des instructions assez complexes pour être décodées en plusieurs micro-opérations. En pratique, seuls les CPU x86 sont concernés. ===Les domaines de fusion=== La micro-fusion n'est pas spécifique aux processeurs superscalaires. En théorie, on peut l'implémenter sur un processeur non-superscalaire à émission dans l'ordre. Cependant, je ne connais aucun processeur à émission dans l'ordre qui implémente la micro-fusion, même si son implémentation est en théorie possible sur de tels processeurs. La micro-fusion est implémentée différemment selon que l'émission se fasse dans l'ordre, dans le désordre, avec une fenêtre d'instruction, avec des stations de réservation, etc. J'ai dit plus haut que les micro-opérations sont générées lors de l'émission, mais le moment exact varie suivant le processeur. Pour simplifier le tout, nous parlerons de '''scission''' quand le processeur traduit une macro-opération en deux/trois micro-opérations. Le moment où a lieu la scission est théoriquement dans l'unité d'émission, mais celle-ci prend plusieurs formes selon que le processeur utilise l'émission dans l'ordre, dans le désordre, avec une fenêtre d'instruction, avec des stations de réservation, etc. Les processeurs à exécution dans l'ordre sont le cas le plus simple. L'unité d'émission est alors en charge du découpage des macro-opérations en micro-opérations. La file de micro-opération ou le cache de micro-opérations mémorisent des macro-opérations. À l'opposé, le tampon de ré-ordonnancement mémorise lui des micro-opérations. Le reste du processeur n'est pas affecté. Sur les processeurs à exécution dans le désordre, les différences sont nombreuses. Le tampon de ré-ordonnancement peut mémoriser soit les micro-opérations finales, soit des macro-opérations. Il en est de même avec la fenêtre d'instruction et/ou les stations de réservation, qu'elles soient centralisées ou décentralisées. Tout dépend de comment se fait l'implémentation. Une implémentation simple effectue la scission des macro-opérations dans l'unité d'émission, comme sur les processeurs à exécution dans l'ordre. Sur de nombreux processeurs, l'unité d'émission et de renommage sont simplement fusionnées, ce qui fait que la scission a lieu juste après le renommage de registres. En conséquence, le tampon de re-ordonnancement et les fenêtres d'instruction ne voient que des micro-opérations. Les macro-opérations disparaissent juste avant. Cette implémentation est préférée avec une fenêtre d'instruction centralisée, car on voit mal comment scinder une macro-opération juste avant l'ALU. Une autre implémentation fait la scission en sortie de la fenêtre d'instruction ou des stations de réservation, qu'elles soient centralisées ou décentralisées. Dans ce cas, le tampon de re-ordonnancement fait de même. L'avantage est que le tampon de ré-ordonnancement stocke des macro-opérations, ce qui augmente sa taille effective. Par exemple, il utilise une seule entrée pour une instruction ''load-op'', au lieu de deux sans micro-fusion de ce type. ===La délamination=== La scission peut parfois avoir lieu plus tôt, dans des circonstances très précises. Concrètement, cela ne concerne que quelques micro-architectures d'Intel, pour des instructions très précises. La raison est les limitations du format des micro-opérations, pas une histoire d'optimisation. Le processeur aimerait pouvoir faire la micro-fusion, mais ne peut pas à cause de ces limitations. Une telle situation cause alors une '''délamination''' : les micro-opérations sont scindées précocement. Par exemple, sur la micro-architecture SandyBridge d'Intel, les opérations ''load-op'' sont fusionnées, sauf si elles utilisent l'adressage indicé. Les micro-opérations de ce processeur ne peuvent avoir que deux opérandes. Trois opérandes est de trop, et les opérations ''load-op'' en adressage indicé dépassent cette limite. Dans ce cas, les micro-opérations sont fusionnées en sortie du décodeur, mais sont scindés avant d’entrer dans la file de micro-opération. L'avantage n'est pas évident, vu que l'unité de renommage suit de près le décodeur d'instruction. Il est que le cache de micro-opérations mémorise des macro-opérations, pas deux micro-opérations. ===La micro-fusion des processeurs Intel et AMD=== La micro-fusion est apparue sur le Pentium M d'Intel, et a été conservée telle quelle sur les processeurs Intel suivants. Les processeurs AMD supportent la micro-fusion depuis au moins la micro-architecture AMD K8. Mieux que ça, la délamination n'était pas utilisée car les micro-opérations acceptaient plus de 2 opérandes. Que ce soit chez AMD ou Intel, elle concerne deux types d'instructions : les écritures mémoire et les instructions ''load-op''. Sur le Pentium M, il y avait quelques limitations, l'optimisation se limitant par exemple aux registres entiers et flottants, mais pas aux registres MMX, mais pas les registres SSE (nous verrons ces registres dans quelques chapitres). Mais les processeurs modernes n'ont plus cette limitation. La micro-fusion des CPU Intel concerne deux types d'instructions : les écritures mémoire et les instructions ''load-op''. Pour les écritures, la situation est plus complexe que pour les instructions ''load-op''. Sur les processeurs Intel précédents, les écritures étaient réalisées dans deux unités séparées : le calcul d'adresse dans une unité de calcul, l'écriture proprement dite dans l'unité mémoire. Elles prenaient donc deux micro-opérations. Le processeur a changé ses unités mémoire, ce qui fait qu'elle pouvait faire les deux en une seule micro-opération. Il s'agissait alors d'une optimisation du chemin de données, plus que de la micro-fusion proprement dite, mais je la mentionne ici malgré tout. La micro-fusion sur ce processeur avait un avantage en plus des avantages usuels : elle utilisait mieux les décodeurs. Les Pentium M avaient trois décodeurs pour décoder plusieurs instructions en même temps, chose qu'on détaillera dans le chapitre sur les processeurs superscalaires. Un seul décodeur pouvait décoder toutes les instructions, les deux autres ne peuvent décoder que les instructions simples, qui se décodent en une seule micro-opération. Avec la micro-fusion, les trois décodeurs peuvent gérer les écritures mémoire et les opérations ''load-op'', vu qu'elles deviennent des instructions simples. Sans cela, elles auraient été limitées au premier décodeur. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Le parallélisme mémoire | prevText=Le parallélisme mémoire | next=Les microarchitectures pour le x86 : haute performance | nextText=Les microarchitectures pour le x86 : haute performance }} </noinclude> pshfxxw6x987d1ii0oqcf7jvc9k1b0m 773581 773580 2026-09-29T16:48:49Z Mewtow 31375 /* L'exemple du PA-RISC PA 8000 */ 773581 wikitext text/x-wiki Les processeurs vus auparavant ne peuvent émettre au maximum qu'une instruction par cycle d'horloge. Ils peuvent avoir plusieurs instructions qui s'exécutent en même temps, dans des unités de calcul séparées. C'est le cas dès qu'une instruction multi-cycles s'exécute. Par contre, ils ne peuvent démarrer qu'une seule instruction par cycle. Et quand on court après la performance, ce n'est pas assez ! Les concepteurs de processeurs ont inventés des processeurs qui émettent plusieurs instructions par cycle : les '''processeurs à émissions multiples'''. Un processeur à émission multiple charge plusieurs instructions en même temps, les décode en parallèle, puis les émet en même temps sur des unités de calculs séparées. Pour cela, il faut gérer les dépendances entre instructions, répartir les instructions sur différentes unités de calcul, et cela n'est pas une mince affaire. En général, pour un processeur à émission multiple capable d'émettre N instructions en parallèle, on parle de '''processeur à N voies''', ou encore un ''processeur à N pipelines''. [[File:Superscalarpipeline.svg|centre|vignette|upright=1.5|Pipeline RISC classique à cinq étages sur un processeur superscalaire. On voit bien que plusieurs instructions sont chargées en même temps.]] Les processeurs à émission multiple sont de deux types : les processeurs VLIW et les '''processeurs superscalaires'''. Nous mettons les processeurs VLIW de côté en attendant le prochain chapitre. La raison est qu'ils ont un jeu d'instruction spécialisé qui expose le parallélisme d'instruction directement au niveau du jeu d'instructions, là où les processeurs superscalaires restent des processeurs au jeu d'instruction normal. La différence principale entre processeur VLIW et superscalaire est qu'un processeur superscalaire répartit les instructions sur les unités de calcul à l’exécution, là où un processeur VLIW délègue cette tâche au compilateur. ==Le nombre de voies d'un processeur superscalaire== Les processeurs superscalaires les plus simples ne permettent que d'émettre deux micro-opérations à la fois, d'où leur nom de processeur ''dual issue'', ce qui se traduit en '''processeur à double émission'''. Les processeurs triple émission permettent eux d’émettre trois instructions à la fois. A l'opposé, les CPU superscalaires les plus puissants peuvent émettre jusqu'à 8-10 instructions simultanément. En 2026, les CPU superscalaires peuvent monter jusqu’à 10 µops émises en même temps, ce qui est énorme ! Et cela nous amène à faire une distinction entre les processeurs superscalaires dits '''étroits''' et ceux dits '''larges'''. Dans ce wikilivre, on part du principe que les processeurs superscalaires étroits émettent jusqu'à 4-5 µops à la fois, alors que les larges peuvent en émettre plus, l'intervalle entre les deux est une zone grise. Le nombre exact n'est pas fixé dans le marbre, la distinction est volontairement vague. Nous parlerons de la '''largeur d'un CPU superscalaire''' pour parler du nombre de voies, du nombre de µops émises en même temps. Plus un CPU superscalaire est large, plus il est performant ''toute chose égale par ailleurs''. Mais dans les faits, vous pouvez oublier la partie en italique. Élargir un CPU superscalaire demande de rajouter beaucoup de circuits. Et ce cout en circuit aura un impact sur la performance. A budget en transistors limité, il y a un compromis entre élargir un CPU et rajouter du cache ou la taille des fenêtres d'instructions/ROB et autres. ===Les contraintes d’appariement=== Prenons un processeur double émission, capable d'émettre deux instructions simultanément. Émettre deux instructions en même temps n'est pas toujours possible. Par exemple, si deux instructions sont dépendantes, on ne peut pas les émettre en même temps. Mais oublions un instant ces histoires de dépendances de données, et partons du principe que le CPU ait affaire à deux instructions indépendantes, une paire idéale. Un CPU double émission "parfait" pourrait exécuter n'importe quelle paire d'instruction. Par exemple, il pourrait émettre deux multiplications consécutives, deux lectures consécutives, une lecture et une écriture en même temps, etc. En pratique, aucun processeur ne permet cela. Implémenter un CPU superscalaire "parfait" aurait un cout en circuit beaucoup trop conséquent. Par exemple, pour émettre deux multiplications en même temps, il faudrait deux multiplieurs séparés. Idem pour exécuter deux accès mémoire simultané : cela demande d'avoir deux unités mémoire et un cache multiport. Mais en pratique, aucun CPU superscalaire ne fait cela. La totalité des CPU double émission se débrouille avec un seul circuit multiplieur et une seule unité mémoire. Et cela entraine l'apparition de dépendances structurelles, qui font que certaines paires d'instructions sont impossibles. Par exemple, impossible d'émettre deux multiplications en même temps avec un seul circuit multiplieur. Mais émettre une multiplication en parallèle d'une addition est parfaitement possible. Il y a donc des paires d'instructions autorisées et des paires interdites. Et la logique est la même sur les CPU à triple ou quadruple émission, et au-delà. : des triplets ou quadruplet d'instructions sont impossibles à émettre simultanément, alors que d'autres le sont. Pour le dire autrement, il y a des '''contraintes d'appariement''' sur les instructions à émettre en même temps. ===L'impact des contraintes d’appariement sur la performance=== Ces contraintes d’appariement ont un impact sur les performance, mais celui-ci peut être grandement mitigé. Les programmes informatiques utilisent en pratique beaucoup plus d'opérations entières de base que de multiplication, branchements et accès mémoire. Il y a environ 5 opérations entières de base pour une multiplication entière. En pratique, il est rare de devoir exécuter deux multiplications à la fois. Idem pour les décalages et rotations, qui sont assez éloignés les uns des autres. Deux branchements consécutifs sont quant à eux plus fréquents. Deux accès mémoire consécutifs est assez rare, mais ils restent assez proches les uns des autres malgré tout. La conséquence est que certaines paires d'instructions sont privilégiées par rapport au reste. Les paires regroupant deux calculs basiques (additions, soustractions, ...) sont systématiquement supportées, car dupliquer des ALU entières est facile. Les paires regroupant un calcul et une autre instruction sont elles aussi systématiquement supportées. Par contre, les paires avec deux branchements, deux accès mémoire, deux décalages/rotations, ou deux multiplications/divisions sont fréquemment interdites. Seuls les CPU superscalaires larges peuvent les permettre, et encore : sous conditions. Le résultat est que le processeur peut se débrouiller avec une seule unité mémoire et une unité de branchement. ===Terminologie pour la suite du chapitre=== Décrire les contraintes d’appariement demande de dire quelles combinaisons d’instructions sont autorisées ou interdites. Et pour cela, nous allons introduire les abréviations suivantes : * INT est un raccourcis pour parler d'une opération entière simple, qu'une ALU entière peut exécuter. * MUL correspond à une opération entière complexe, typiquement une multiplication, éventuellement à une division. * FLOAT désigne une opération flottante, peut importe laquelle. * MEM désigne un accès mémoire, à savoir une instruction ou µop mémoire. * BRANCH désigne une instruction de branchement. Cette terminologie permettra de définir des paires d'instructions, qu'elles soient possibles ou interdites. Par exemple, l'expression INT + FLOAT désigne une paire d'instruction regroupant une instruction entière et une instruction flottante, peu importe l'ordre des deux instructions. Il en sera de même pour les triplets, quadruplets, ou plus. Par exemple, l'expression INT + INT + FLOAT + MUL désigne un quadruplet d'instructions regroupant : deux instructions entières, une instruction flottante, et une multiplication entière. J'utiliserais aussi des parenthèses pour regrouper certaines combinaisons. Par exemple, l'expression INT + (MUL /FLOAT) veut parler d'une paire d'instruction où la première est une opération entière basique, la seconde est : soit une multiplication, soit une opération flottante. ==Le ''front-end'' des processeurs superscalaires== Un processeur superscalaire doit charger, décoder, et exécuter plusieurs instructions par cycle. Par exemple, un processeur triple émission doit charger 3 instructions lors d'un premier cycle, puis les décoder au cycle suivant, et les exécuter au cycle suivant. Il travaille donc pas paquets de 3 instructions, dans cet exemple. Intuitivement, charger, décoder et exécuter plusieurs instructions à la fois demande de dupliquer des circuits. Par exemple, il faut dupliquer les décodeurs pour décoder plusieurs instructions. Les unités de calcul sont aussi dupliquées, sauf sur certaines processeurs qui arrivent à ruser, mais laissons cela de côté pour plus tard. Mais d'autres circuits sont simplement modifiés, comme l'unité de chargement ou l'unité d'émission. Voyons ce qu'il en est dans le détail. {|class="wikitable" |- ! rowspan="2" | Processeur sans émission multiple | rowspan="2" | Chargement | rowspan="2" | Décodage | rowspan="2" | Renommage | rowspan="2" | Émission | Exécution / ALU | rowspan="2" | ''Commit''/ROB |- | Exécution / ALU |- ! rowspan="4" | Processeur superscalaire | rowspan="4" | Chargement | rowspan="2" | Décodage | rowspan="4" | Renommage | rowspan="4" | Émission | Exécution / ALU | rowspan="4" | ''Commit''/ROB |- | Exécution / ALU |- | rowspan="2" | Décodage | Exécution / ALU |- | Exécution / ALU |} Nous allons d'abord voir ce qu'il en est pour le ''front-end'', à savoir la partie du CPU qui s'occupe de charger et décoder les instructions. Elle regroupe l'unité de chargement, les décodeurs, l'unité de prédiction de branchement, la file de µops, la file d'instruction, et divers caches. En soi, les changements portent surtout sur l'unité de chargement et les décodeurs. ===Le chargement de plusieurs instructions consécutives=== Un processeur superscalaire charge plusieurs instructions en même temps, ''en tenant compte de la présence de branchements''. La partie en italique est importante et elle a une conséquence très forte : la manière de faire est fortement différente entre un CPU superscalaire étroit et large. Un CPU superscalaire étroit fait au plus simple : il charge un bloc de 2, 3, 4 instructions consécutives en mémoire RAM. Il faut alors doubler/tripler/quadrupler la taille du bus connecté au cache d'instruction. Par exemple, pour charger quatre instructions de 32 bits chacune, il suffit de lire un bloc de 128 bits dans le cache d'instruction. Un bloc de 8, 16, 32 octets est donc lu depuis le cache et est ensuite découpé en instructions, envoyées chacun à un décodeur. Charger plusieurs instructions consécutives ne marche bien qu'en absence de branchements. La présence de branchements casse cette dynamique, et il faut gérer leur présence. * Sans prédiction de branchement, toutes les instructions d'un bloc sont décodées et exécutées en même temps, même s'il y a un branchement dans le tas. * Avec prédiction de branchement, les instructions situées après le branchement ne sont pas décodées ni exécutées. L'unité de chargement coupe le bloc chargé au niveau du premier branchement pris, remplit les vides avec des NOP, avant d'envoyer le tout à l'unité de décodage. Les instructions à l'adresse de destination seront chargées au cycle suivant, en chargeant un nouveau bloc. [[File:Fetch sur un processeur superscalaire avec prediction de branchements.png|centre|vignette|upright=2|Fetch sur un processeur superscalaire avec prédiction de branchements.]] Un autre défaut est que sur le CPU charge un bloc de 128 bits à la fois, les instructions doivent être alignées sur 128 bits. Et on peut généraliser à n'importe quelle taille de bloc. Si les instructions ne sont pas alignées, il faut gérer la situation. Il arrive qu'une instruction soit à cheval sur deux blocs, avec un morceau dans le premier bloc, un autre dans le second. Dans ce cas, l'instruction est chargée en deux fois, et des circuits doivent gérer la situation pour recoller les morceaux. Sur les CPU avec des instructions de taille fixe, le problème ne survient que rarement. Mais il est fréquent avec des instructions de taille variable. Un autre défaut est lié aux branchements. Imaginez qu'un branchement s'exécute et branche vers une instruction de destination. Rien n'indique que l'instruction de destination sera au tout début d'un bloc. Si ça se trouve, elle sera en troisième position d'un bloc de 4 instructions. Une solution simple charge le bloc en respectant l'alignement, et les deux premières instructions du bloc ne sont pas à exécuter. Il y a donc une petite perte de performance. Certains CPU, comme l'IBM RS/6000, ont la machinerie charger un bloc de N instructions même s'il n'est pas aligné. La machinerie en question se trouve dans le cache d'instruction et est tout sauf simple à expliquer,ce qui fait que je me permets de la passer sous silence. Un détail, cependant : elle ne permet pas de charger des blocs qui sont à cheval sur deux lignes de cache. ===Le décodage parallèle des instructions=== Pour le décodage des instructions, plusieurs instructions sont décodées en même temps. On parle alors de '''décodage parallèle'''. Pour ce faire, un processeur superscalaire contient plusieurs décodeurs, chacun pouvant décoder une instruction en parallèle des autres. Prenons par exemple un processeur superscalaire à 4 voies : le décodage se fera dans quatre décodeurs séparés, qui fonctionneront en parallèle. Cependant, cette implémentation ne marche bien que pour les processeurs RISC, les processeurs CISC devant faire avec un microcode gourmand en circuits. Les processeurs CISC utilisent des décodeurs hybrides, avec un microcode qui complémente un décodeur câblé. Dupliquer le microcode aurait un cout en transistors trop important, ce qui fait que seuls les décodeurs câblés sont dupliqués. Les CPU CISC superscalaires disposent donc de plusieurs décodeurs simples, capables de décoder les instructions les plus courantes, avec un seul microcode. La conséquence est qu'il n'est pas possible de décoder deux instructions microcodées en même temps. Par contre, il reste possible de décoder plusieurs instructions non-microcodées ou une instruction microcodée couplée à une instruction non-microcodée. Vu qu'il est rare que deux instructions microcodées se suivent dans un programme, le cout en performance est extrêmement mineur. Il faut noter qu'une instruction correspond à une ou plusieurs µops. Il est donc possible de charger 5 instructions et de se retrouver avec 8 µops en sortie des décodeurs. Et c'est la source d'une distinction très importante. Plus haut, j'ai parlé de processeurs superscalaires à N voies. La terminologie peut avoir deux interprétations. La première est que le processeur charge/décode N instructions à la fois. Une seconde est qu'il est capable d'exécuter/émettre N µops en même temps. Les deux ne sont pas équivalentes, vu qu'un processeur superscalaire peut, par exemple, charger/décoder N instructions et émettre/exécuter N+2 µops. La distinction est particulièrement importante sur les processeurs superscalaires larges. Certains d'entre eux sont capables de charger 5 instructions et d'en émettre le double ! Un exemple classique était les processeurs Athlon d'AMD, qui pouvaient décoder deux instructions par cycle, mais émettre 4 µops par cycle. Ce n'était pas un problème, car beaucoup d'instructions, même basiques, étaient décodées en 2 µops. ===L'émission parallèle des instructions=== La superscalarité modifie en profondeur l'unité d'émission, notamment au niveau de son interface. Avant, elle recevait une micro-opération sur son entrée, et fournissait la micro-opération émise sur une sortie. Et cela vaut aussi bien pour une unité d'émission simple, un ''scoreboard'', une fenêtre d'instruction ou des stations de réservation. Mais avec l'émission multiple, les sorties et entrées sont dupliquées. Pour la double émission, il y a deux entrées vu qu'elle doit recevoir deux micro-opération décodées/renommées, et deux sorties pour émettre deux micro-opérations. Dans ce qui suit, nous ne parlerons pas d'entrée et de sortie, mais de '''ports de décodage''' et de '''ports d'émission'''. Les ports de décodage reçoivent des micro-opérations provenant de l'unité de décodage, les ports d'émissions sont pour les micro-opérations émises. Les ports d'émission injectent les micro-opérations émises dans le pipeline, elle sont propagée au banc de registre, aux ALUs, etc. Un processeur superscalaire a forcément plusieurs ports d'émission (et de décodage). Si l'interface de l'unité d'émission change, l'intérieur est tout autant modifié. Sur un CPU non-superscalaire, l'unité d'émission reçoit une µop "candidate à l'émission", et détecte les dépendances entre avec les µops en vol, en cours d'exécution dans le pipeline. Et c'est toujours le cas sur les processeurs superscalaires : l'unité d'émission détecte les dépendances entre les µops candidates et les µops en vol. Mais avec la siperscalarité, elle doit en plus tester les dépendances entre les µops candidates. Si l'unité d'émission est un ''scoreboard'', il doit détecter les dépendances entre instructions émises simultanément et les sérialiser si besoin. Avec une fenêtre d'instruction, il n'y a pour ainsi dire rien à faire, vu que les dépendances sont éliminées par le renommage de registre et que les signaux de réveil gèrent les dépendances RAW. C'est la raison pour laquelle les processeurs superscalaires modernes n'utilisent pas de ''scoreboard''. ==Les processeurs implémentés avec plusieurs pipelines== Nous venons de voir comment la superscalarité impacte le ''front-end'', il est maintenant de voir ce qu'il en est de l'unité d'émission et des ''back-ends''. Un processeur superscalaire peut utiliser l'exécution dans le désordre et le renommage de registres, mais ce n'est pas une obligation. Historiquement, les premiers processeurs superscalaires n'utilisaient pas d'exécution dans le désordre. Le meilleur exemple est celui du Pentium 1 et 2 d'Intel. Ils étaient tous deux des processeurs superscalaires, mais n'avaient pas d'exécution dans le désordre, qui est apparue sur le Pentium 3. les explications sont plus simples si on met de côté l'exécution dans le désordre. Vous vous dites que l'implémentation d'un processeur superscalaire n'est pas la même suivant que le CPU utilise l'exécution dans le désordre, ou non. Mais dans les faits, la distinction est plus subtile que ca. Pour l'expliquer, je vais utiliser une classification originale, qui sépare les processeurs superscalaires en trois sous-types. La distinction se fait sur la manière dont la superscalarité est implémentée en matériel.La classification que j'utilise distingue : * Les processeurs avec plusieurs pipelines, sans exécution dans le désordre. * Les processeurs superscalaires avec un pipeline dynamique. * Les processeurs avec des fenêtres d'instruction décentralisées. La distinction n'est pas qu'une question d'implémentation matérielle. Elle impacte aussi le ratio entre instructions chargées/décodées et instructions émises. Vous vous dites que les deux sont égales, mais ce n'est le cas que sur les processeurs avec N pipelines ! Sur les autres processeurs, il est possible de décoder 4 instructions, mais d'en émettre maximum 6 par cycle ! Et sur les CPU avec des fenêtres d'instruction décentralisées, il y a aussi une différence entre le nombre d'instructions qui sont ''dispatch'' et ''schedule''. La catégorie la plus simple est celle des '''processeurs avec plusieurs pipelines'''. Ce sont des processeurs superscalaires sans exécution dans le désordre. Ils partent d'un processeur non-superscalaire, et ajoutent un second pipeline, en sortie de l'unité d'émission. Le second pipeline permet l'émission parallèle d'une seconde instruction. Le second pipeline n'est pas identique au pipeline originel, sur plusieurs points. Premièrement, il n'a pas exactement les mêmes circuits. Le second pipeline est généralement composé d'une unité de calcul, d'une FPU, éventuellement d'un second banc de registres, guère plus. Il permet d'exécuter une seconde opération de calcul, pas plus, ce qui est à l'origine de contraintes d'appariemment assez fortes. De plus, il n'a pas forcément la même longueur, il peut avoir des étages en moins ou en plus. Il s'agit de la forme la plus simple de processeur superscalaire et nous allons leur consacrer cette section. ===La double émission entière-flottante=== L'exemple le plus simple utilise un second pipeline pour les opérations flottantes, séparé du pipeline originel. L'ajout d'un pipeline flottant permet d'émettre une micro-opération entière en même temps qu'une micro-opération flottante, ce qui s'appelle la '''double émission entière-flottante'''. La micro-opération entière s'exécute dans l'ALU entière, la micro-opération flottante dans la FPU. Les exemples les plus notables sont le PA-RISC 7100, le POWER 1 (RIOS .& et .9) et le PowerPC 601. L'Apollo DN10000 et l'Intel i860 utilisaient aussi cette forme de double émission, mais étaient des prototypes de CPU VLIW. [[File:Double émission entière-flottante.png|centre|vignette|upright=2|Double émission entière-flottante]] Pour bien expliquer les choses, prenons le processeur illustré ci-dessous, avec deux ''back-end'' séparés : un pour la FPU, et un autre pour le reste. Les instructions entières et mémoire passent toutes par le ''back-end'' généraliste. [[File:CPU non-superscalaire basique, avec une FPU.png|centre|vignette|upright=1.5|CPU non-superscalaire basique, avec une FPU]] Les deux ''back-end'' sont des pipelines séparés, mais il faut que l'unité d'émission soit spécialement conçue pour en profiter. Un processeur simple émission peut démarrer une seule µop par cycle : soit la µop est envoyée au ''back-end'' flottant, soit elle est envoyée au ''back-end'' général. Avec la double émission entière-flottante, le processeur peut envoyer une µop dans chaque pipeline, à chaque cycle. Vu que la FPU et son banc de registre forment déjà un pipeline séparé, les seules modifications se font au niveau du ''front-end'', unité d'émission inclue. {| |- |[[File:CPU simple émission avec une FPU.png|centre|vignette|upright=1.5|CPU simple émission avec une FPU.]] |[[File:Double émission entière flottante avec un second pipeline.png|centre|vignette|upright=1.5|CPU avec un second pipeline flottant.]] |} Notez que le terme double émission ''entière''-flottante est un peu trompeur. En réalité, la technique permet d'émettre une instruction flottante avec n'importe quelle autre instruction non-flottante, avec des restrictions pour les branchements. Il est par exemple possible d'exécuter un calcul flottant en parallèle d'un accès mémoire. Sur les CPU 32 bits, il est possible de faire les multiplications dans la FPU. Pour rappel, la FPU contient un multiplieur entier 53-54 bits, pour multiplier les mantisses de deux flottants 64 bits, qu'on peut utiliser pour faire les multiplications entières 32 bits. Cela permet d'émettre une multiplication en même temps qu'une opération entière dans l'ALU. Ainsi, le CPU pouvait émettre deux instructions : une opération entière de base, avec soit une multiplication, soit une opération flottante. En clair, une émission de type INT + (MUL /FLOAT). Par contre, on perd la possibilité d'émettre une multiplication entière avec une opération flottante, mais c'était un compromis qui en valait la peine. Le CPU PA-RISC 7100 implémentait cette optimisation. Il s'agissait d'un CPU double émission entière-flottante, qui utilisait donc un partitionnement assez simple. Le combo partitionnement + reconditionnement permettait ici de gagner en performance, pour un cout en matériel très limité. D’autant plus limité que le jeu d'instruction prévoyait le reconditionnement de la FPU. Les multiplications ne lisaient pas leurs opérandes dans les registres entiers, mais dans les registres flottants. ===La double émission entière=== Une autre possibilité ajoute un second pipeline, capable d'exécuter des opérations entières simples, appelé le pipeline entier. Le processeur supporte alors la '''double émission entière''', à savoir qu'ils peuvent émettre une opération entière en plus d'une autre instruction. L'opération entière en question est une opération simple, comme une addition, une soustraction, une opération bit à bit, une comparaison, etc. Les exemples classiques sont les processeurs Intel i960 et Pentium. L'implémentation était différente entre l'i960 et le Pentium : Le Pentium avait une seconde ALU entière, alors que le i960 rusait. Le Pentium dupliquait l'ALU entière, pour créer un second pipeline entier. Sur le Pentium originel, les contraintes d'appariement étaient assez strictes. Le Pentium avait une FPU, mais ne pouvait pas l'utiliser en double émission. Il lui était impossible d'exécuter une opération flottante en même temps qu'une opération entière (branchements inclus). Le Cyrix 6x86 était une sorte de Pentium produit par l'entreprise Cyrix, avec une microarchitecture différente. Il avait des contraintes d’appariement réduites. Par exemple, il pouvait émettre une opération flottante en parallèle d'une opération entière. Nous détaillerons ces processeurs dans le prochain chapitre, qui porte justement sur les CPU superscalaires x86. [[File:CPU simple et double émission avec un second pipeline entier.png|centre|vignette|upright=2.5|CPU simple et double émission avec un second pipeline entier.]] L'Intel i960 n'avait pas de FPU, juste une ALU entière et une unité mémoire. Il utilisait l'unité mémoire comme une seconde ALU entière limitée. Pour rappel, une unité mémoire contient une AGU, à savoir une ALU spécialisée dans les calculs d'adresse. Elle est capable de faire des additions, soustractions, et quelques décalages limités (des décalages par 2, 4, 8, pas plus). L'Intel i960 ajoutait des connexions entre AGU et banc de registre, afin que celle-ci serve de seconde unité de calcul. L'AGU est déjà reliée aux deux ports de lecture, pour lire les opérandes du calcul d'adresse, il suffit de la connecter sur le port d'écriture. Le processeur peut alors émettre deux instructions/µops entières, sous certaines conditions. [[File:Emission multiple des opérations entières, double émission.png|centre|vignette|upright=2|Émission multiple des opérations entières, double émission.]] ==Les processeurs superscalaires dynamiques== Les processeurs précédents, avec 2 pipelines, avaient une unité d'émission assez simple. Elle avait deux ports de décodage, et deux ports d'émission. Le nombre de ports de décodage et d'émission étaient identiques. Vous vous dites que c'est naturel, et intuitif, que c'est normal pour un processeur superscalaire. Mais en réalité, la majorité des processeurs superscalaires a plus de ports d'émission que de décodage. Expliquer pourquoi va cependant nous demander de parler de comment la superscalarité exploite les unités de calcul. Posons-nous cette question : de combien d'unités un processeur superscalaire a besoin ? Les unités en question ne sont nécessairement des unité de calcul, l'unité mémoire et l'unité de branchement comptent aussi. La réponse dépend du nombre de voies. Si le ''front-end'' charge et décode un paquet de N instructions, exécuter ces N instructions simultanément demandera là aussi au moins N unités de calcul. Notez le terme : ''au moins'', car c'est là tout l'enjeu de cette section. La réponse dépend aussi des contraintes d’appariement. Pour un CPU superscalaire "parfait", sans contraintes d’appariement, toutes les unités doivent être dupliquées, y compris l'unité mémoire. Un processeur à double émission parfaite devrait dupliquer l'ALU entière, le ''barrel shifter'', le circuit multiplieur, la FPU, l'unité mémoire, et l'unité de branchement, ce qui ferait passer de 6 unités à 12. Le cout en circuit est énorme, même pour de la double émission ! Et pour un CPU à N pipelines, le cout en circuit encore plus prohibitif ! En pratique, les processeurs superscalaires qui font ça sont très rares. La majeure partie des processeurs superscalaires utilisent d'autres techniques : le partitionnement, la duplication partielle des ALUs, la duplication des autres unités. ===Le partitionnement des unités fonctionnelles=== Les CPU superscalaires les plus simples ne dupliquent pas leurs unités de calcul, ils se contentent d'exploiter les unités existantes. Et pour expliquer comment, nous allons partir de l'exemple d'un processeur non-superscalaire contient une ALU entière, une FPU, une unité mémoire et une unité de branchement. Les quatre unités peuvent fonctionner en parallèle, à savoir qu'une unité peut exécuter une instruction à elle toute seule, sans interagir avec les autres. Cela suffit pour créer un processeur quadruple émission, qui peut émettre en même temps : une opération entière, une opération flottante, un branchement, un accès mémoire. Le principe marche aussi sur un processeur avec moins de 4 unités, par exemple sans FPU et/ou sans unité de branchement, ou avec au contraire des unités en plus. L'idée générale est d’émettre une µops séparée dans chaque unité fonctionnelle. Utiliser ainsi les unités existantes, pour rendre un CPU superscalaire, s'appelle le '''partitionnement superscalaire'''. Le terme n'est pas beaucoup utilisé en-dehors de quelques vieux articles académiques. Le partitionnement est fortement dépendant du jeu d'instruction, car il demande de bien séparer instructions entières, flottantes, branchements et instructions mémoire. Et autant c'est bien le cas sur les CPU RISC, autant les CPU CISC ne sont pas dans ce cas. Les CPU CISC ont des instructions ''load-op'', qui effectuent une instruction arithmétique et une µop mémoire. Et ces instructions sont très compliquées à implémenter avec le partitionnement. Et au-delà de ça, les CPU CISC ont beaucoup d'instructions qui sont décodées en plusieurs µops, à exécuter dans un ordre bien précis. On peut pas émettre les µops en question simultanément. Le partitionnement a un cout en circuit très limité, pour un gain en performance lui aussi limité. Pour reprendre le CPU de l'exemple précédent, il est rare que l'on ait à exécuter ces quatre instructions en même temps. En pratique, les combinaisons fréquentes sont les combinaisons calcul + accès mémoire, calcul + branchement, calcul entier + calcul flottant. Utiliser une quadruple émission de ce type n'est donc pas une bonne idée, alors que la double émission parait plus adaptée. Et c'est là que la différence entre ports d'émission et de décodage devient intéressante. L'idée est d'avoir une unité d'émission avec deux ports de décodage, et 4 port d'émission (un par unité). Les contraintes d’appariement varient alors suivant le processeur, mais la règle générale est que si deux micro-opérations tombent dans deux unités différentes, on peut les émettre en même temps. En clair, on peut émettre une opération entière avec une opération flottante, une opération entière avec un branchement, un accès mémoire avec un branchement, etc. Et cela rend le partitionnement bien plus intéressant que prévu. Les tout premiers CPU superscalaires étaient des CPU double émission, qui utilisaient le partitionnement avec : une ALU entière, une unité mémoire et une FPU. Nous parlerons de '''partitionnement INT-FLOAT-MEM'''. L'avantage sur la double émission flottante est que les combinaisons INT + MEM et FLOAT + MEM étaient autorisées. L'intérêt était d'émettre une opération en parallèle d'un accès mémoire, ce qui est un doublet d'instruction assez fréquent. Les exemples classiques sont l'HyperSPARC, de l'alpha 21064 et du PowerPC 603. Les contraintes d’appariement variaient grandement suivant le processeur. Le PowerPC 603 implémentait une double émission "parfaite". C'est à dire que toutes les combinaisons possibles à deux instructions étaient possibles, que ce soit INT + FLOAT, INT + MEM, FLOAT + MEM. En plus de cette double émission "parfaite", le CPU utilisait la technique dite de ''branch folding'', qui permettait d'exécuter un branchement sans utiliser d'unité de calcul, ce qui fait qu'il était qualifié de ''CPU 2-way + Branch''. A l'opposé, le processeur alpha 21064 avait pas mal de contraintes d’appariement, à savoir que certaines combinaisons de deux instructions étaient interdites, bien que compatibles avec les unités disponibles. Une des raisons est que le banc de registre n'avait pas assez de ports de lectures, ce qui fait que certaines combinaisons avec une écriture mémoire n'étaient pas permises. Les concepteurs avaient volontairement inséré ces contraintes afin de simplifier le design du processeur. Avant de poursuivre, précisons que la FPU regroupe un additionneur flottant et un multiplieur flottant. Et ce fait peut être exploité pour approfondir le partitionnement. La '''double émission FADD/FMUL''' permet d'émettre une addition flottante en même temps qu'une multiplication flottante. Elle a été utilisée sur les processeurs x86, Alpha et SPARC. Les autres circuits de calcul flottant sont souvent regroupés avec l'additionneur. La division est parfois e même port que le multiplieur flottant, parfois sur celui de l'additionneur (quand elle est microcodée et exécutée en enchainant les soustractions). ===La duplication des ALU entières=== Le partitionnement est une technique élégante, simple, facile à implémenter et au cout en circuits modeste. Mais il faut avouer que cela ne donne pas des CPU superscalaires très efficaces. La raison est que le partitionnement permet d'émettre des paires, triplets, quadruplets de micro-opérations qui sont rares en pratique. Les combinaisons les plus fréquentes en pratique sont des paires/triplets d'opérations entières, souvent des paires/triplets d'additions ou d'opérations entières simples. Il est donc primordial d'émettre plusieurs opérations entières simultanément. Le fait d'émettre et d'exécuter plusieurs opérations entières en même temps s'appelle l''''émission entière multiple'''. Pour exécuter la seconde/troisième opération entière, il faut dupliquer les ALU entières (ou réutiliser l'AGU comme ALU entière comme le fait l'Intel i960). Le processeur doit avoir deux ALU entières pour de la double émission entière, trois pour de triple émission entière, etc. De plus, il faut ajouter des ports au banc de registre, pour lire deux fois plus d'opérandes et décrire deux résultats. Et enfin, il faut rajouter un port d'émission pour pouvoir émettre une micro-opération entière en plus. [[File:Processeur non-superscalaire basique 03.png|centre|vignette|upright=2|Processeur non-superscalaire basique]] La tendance est de multiplier les ALU entières, mais pas le circuit multiplieur. Le cout en transistors est alors grandement réduit, au prix de l'apparition de dépendances structurelles. Le CPU peut émettre deux additions en même temps, ou une addition et une multiplication, mais pas deux multiplications. Il en est de même avec le ''barrel shifter'', qui n'est pas dupliqué. Il est donc possible d'émettre un décalage avec une opération de base, mais pas deux décalages en parallèle. Mais ces contraintes d’appariement ne sont pas un problème, car il est rare de devoir émettre deux multiplications/décalages en même temps. La plupart des programmes sont majoritairement remplis d'additions, avec des multiplications assez rares et des décalages qui le sont encore plus. La moyenne est proche d'une multiplication pour 4/5 additions. Vu que des multiplications consécutives sont très rares, dupliquer le multiplieur est presque inutile. Disposer de plusieurs circuits multiplieurs ou de plusieurs ''barrel shifters'' serait donc un cout en circuits qui ne servirait que rarement et n'en vaut pas la chandelle. Il faut noter que sur les CPU 32 bits, les multiplications peuvent être exécutées dans la FPU ou dans un multiplieur séparé, tout dépend de si le CPU exécute les multiplications dans la FPU ou pas. {|class="wikitable" |- ! Voie d'émission n°1 !! Voie d'émission n°2 !! Voie d'émission n°3 |- | ALU entière || ALU entière || FPU |} Reste à connecter les unités de calcul à l'unité d'émission (indirectement, car il y a des étages de pipeline entre les deux). Une implémentation basique utilisée un port d'émission par unité. Prenons l'exemple d'un CPU superscalaire avec 4 ALU entières, une FPU, et une unité mémoire. Vu qu'il y a 6 unités, cela fait donc 6 ports d'émission. L'exemple historique le plus impressionnant est celui du Motorola 88110, un CPU double émission qui possède 10 unités. Il contient deux ALU entières, un circuit multiplieur, un circuit diviseur, une unité de manipulation de bits, une unité mémoire, un additionneur flottant, et deux unités graphiques pour des calculs impliquant des pixels. Le multiplieur est utilisé à la fois pour les multiplications entières, flottantes et le produit de deux pixels. Idem pour le diviseur, qui sert pour les divisions entières et flottantes. Et chaque unité a son propre port d'émission. La conséquence est que les contraintes d'appariement du Motorola 88110 sont simples : tant que deux µops atterrissent dans des unités séparées, la paire est permise. Il est par exemple possible d'émettre simultanément deux opérations entières simples, vu qu'il y a deux ALU. Par contre, impossible d'émettre simultanément deux multiplications, deux divisions, deux opérations flottantes, deux manipulations de bit, deux accès mémoire, etc. De plus, le partage du multiplieur fait qu'on ne peut pas émettre une multiplication entière avec une multiplication flottante. Idem avec les divisions, vu que le diviseur est aussi partagé. Ce sont les seules contraintes. ===Le partage des ports d'émission=== La présence d'un circuit multiplieur et d'un ''barrel shifter'' pose des problèmes pour le partitionnement. Il est possible d'avoir un port d'émission dédié au multiplieur, et un autre au ''barrel shifter'', qui sont séparés de ceux pour l'ALU entière. Il est alors possible d'émettre une opération entière, une multiplication et un décalage, simultanément. Nous parlerons de '''partitionnement entier''' pour désigner cette possibilité. [[File:Partitionnement superscalaire entier.png|centre|vignette|upright=2|Partitionnement superscalaire entier.]] Le partitionnement entier est cependant très rare, car le gain en performance serait trop faible au regard des couts en circuit. Quelques processeurs historiques l'utilisaient, mais ce n'est plus le cas de nos jours. La raison est que les multiplications et les décalages sont assez rares dans le code, ce qui fait que le port d'émission associés sont sous-utilisés. Et un port d'émission a un cout en circuit assez important. Et c'est sans compter qu'ajouter des ports sur le banc de registres juste pour un multiplier sous-utilisé n'en vaut pas la peine. L'idéal serait de trouver un moyen de réduire le nombre de ports d'émissions, sans réduire le nombre d'unités de calcul. [[File:Emission multiple des opérations entières, implémentation naive.png|vignette|Émission multiple des opérations entières, implémentation naive]] La solution consiste à '''partager les ports d'émission''', à savoir connecter un port d'émission à plusieurs unités de calcul. L'exemple classique est justement lié aux circuits multiplieur et ''barrel shifters''. L'idée est que le multiplieur et le ''barrel shifter'' sont mis sur le même port d'émission qu'une ALU entière. Prenons par exemple le processeur à double émission entière illustré ci-contre. Un port d'émission est relié à une ALU entière seule, et l'autre port d'émission alimente la seconde ALU entière et le multiplieur. La conséquence est que le processeur peut émettre deux opérations entières, dont une multiplication. Si on avait utilisé un port d'émission dédié au multiplieur, il aurait été possible d'émettre deux opérations entières et une multiplication. On perd donc une voie, mais on gagne en flexibilité et on économise des circuits. Notons que ce partage signifie aussi que le multiplieur partage les ports sur le banc de registre, ce qui fait une double économie. [[File:Emission multiple des opérations entières, implémentation courante.png|centre|vignette|upright=1.5|Émission multiple des opérations entières, implémentation courante]] En général, le ''barrel shifter'' et le multiplieur sont placés sur deux voies d'émission séparés, ce qui permet d'émettre un décalage et une multiplication en même temps. Les mettre sur le même port ne le permettrait pas. {|class="wikitable" |- ! Voie d'émission n°1 !! Voie d'émission n°2 !! Voie d'émission n°3 |- | * ALU entière * Multiplieur | * ALU entière * Barrel shifter | FPU |- | * Additions, soustractions, opérations bit à bit, etc. * Multiplication | * Additions, soustractions, opérations bit à bit, etc. * Décalages et rotations | Opération flottante |} Terminons concernant les multiplieurs avec une dernière subtilité. Pour rappel, les processeurs modernes intégrent en réalité deux multiplieurs différents. Le résultat d'une multiplication est très large et prend deux registres. Par exemple, une multiplication de deux opérandes 64 bits donne un résultat sur 128 bits, ce qui ne tient pas dans un registre, mais en prend deux. L'instruction de multiplication classique ne calcule que les 64 bits de poids faible. mais elle est complétée par d'autres instructions de multiplication qui peuvent faire le calcul complet. Pour résoudre le problème, les processeurs modernes intègrent deux instructions de multiplications : une qui calcule les bits de poids faible du résultat, une autre qui calcule les bits de poids fort. Et ces deux instructions sont associées à deux multiplieurs séparés, aux circuits différent. Le multiplieur qui calcule les bits de poids faible du résultat est appelé le ''low multiplier'', l'autre est appelé le ''high multiplier''. Le second multiplieur est souvent placé sur un second port d'émission, différent du premier multiplieur, partagé avec une ALU. L’avantage de mettre les deux multiplieurs sur deux ports d'émission différents est qu'une multiplication complète peut être réalisée en utilisant les deux multiplieurs en parallèle. Les deux sous-multiplications sont émises en même temps, exécutées en même temps. pas besoin d'exécuter l'une puis la seconde, d'où un gain performance appréciable. Nous venons de voir comment partager un port d'émission entre une ALU et un multiplieur. Mais au-delà de cet exemple, le partage des ports d'émission peut appliquer à n'importe quelle unité. Prenons l'exemple d'un CPU superscalaire avec 4 ALU entières, une FPU, et une unité mémoire. Vu qu'il y a 6 unités, cela fait donc 6 ports d'émission. Cependant, il est rare qu'un bloc de 6 instructions contienne exactement 4 opérations entières, une opération flottante, et un accès mémoire. Beaucoup de ports d'émission seraient sous-utilisés. La solution est de partager des ports d'émission, pour passer à la quadruple émission. Le CPU peut alors répartir 4 instructions sur les ports d'émission adéquats, à chaque cycle. Le CPU a donc 4 ports de décodage et 6 ports d'émission. Une implémentation classique permet n'importe quelle combinaison de 4 instructions compatible avec les 6 unités. Par exemple, il devient possible d'émettre simultanément 4 additions, la combinaison 2 * INT + FLOAT + MEM, 3 * INT + MEM, et bien d'autres. L'exemple relie une ALU entière, la FPU et l'unité mémoire sur le même port. Le CPU a alors quatre ports d'émission, qui ne sont pas "identiques". Trois d'entre eux sont reliés à une ALU entière chacun, rien d'autre. Le quatrième est lui relié à une ALU entière, la FPU et l'unité mémoire. On économise alors deux ports d'émission, mais cela entraine l'apparition de contraintes d’appariement. Le CPU peut émettre 3 opérations entières + n'importe quelle autre opération. Mais les autres combinaisons sont interdites. Le CPU peut émettre 6 opérations entières simultanément, grâce à 6 ALU entières. Les accès mémoire ou opérations flottantes ne viennent pas en plus, mais en remplacement des opérations entières. Regrouper plusieurs ALU sur un même port d'émission est donc à l'origine de dépendances structurelles, de nouvelles contraintes d’appariement. Dans certaines situations de '''''port contention''''', on a assez d'ALU pour exécuter N micro-opérations, mais la répartition des ALUs sur les ports l'empêche. Impossible d'émettre deux micro-opérations sur deux ALU si elles sont sur le même port d'émission. On peut réduire les cas de ''port contention'' en répartissant correctement les ALU sur les ports d'émission, mais sans jamais les supprimer complétement. Un exemple est celui du PowerPC 604. Il implémentait la quadruple émission, alors qu'il avait 5 unités de calcul. Mais deux unités partageaient un même port d'émission. Dans le détail, il avait deux ALU entières, un circuit multiplieur/diviseur, une FPU, une unité mémoire. La FPU et le multiplieur étaient sur le même port d'émission. En conséquence, le CPU pouvait émettre seulement les combinaisons INT + INT + MEM + (MUL/FLOAT). : Il est intéressant de voir l'exemple d'un processeur superscalaire parfait, sans contraintes d'appariement, à N voies. Pour cela, on part d'un processeur non-superscalaire, avec M unités de calcul. Un tel processeur peut s'implémenter avec N ports d'émission, chacun relié à M unités de calcul possibles, ce qui fait que les M unités de calcul sont dupliquées en N exemplaires. Si on prend par exemple un CPU non-superscalaire avec une ALU, une FPU, une unité mémoire et une unité de branchement, un port d'émission sera relié à une ALU, une FPU, une unité mémoire et une unité de branchement. ===La duplication des autres unités fonctionnelles=== Dupliquer les ALU entière est une première étape, mais il est aussi possible de dupliquer les autres unités fonctionnelles. Par exemple, il est possible de dupliquer l'unité mémoire ou l'unité de branchement. Reste à voir quelles unités dupliquer, et pourquoi. Précisons que dans ce qui va suivre, nous allons parler de la duplication des unités en général, pas seulement des unités mémoire/branchement. Nous allons continuer de parler de la duplication des ALU entières dans ce qui suit, mais de manière plus générale. Pour un processeur à N voies, il est théoriquement possible de dupliquer toutes les unités en N exemplaires. Mais ce n'est jamais fait en pratique, car le cout en circuits serait trop important et le gain en performance trop faible. Mieux vaut dupliquer certaines unités bien précises, quitte à avoir des contraintes d'appariement. Et à ce petit jeu, toutes les duplications ne se valent pas, certaines sont plus rentables en matière de performance, le cout en circuit n'est pas le même selon l'unité, etc. La rentabilité en performance dépend surtout des contraintes d'appariement. Les contraintes d'appariement entrainent une baisse de performance significatives si elles interdisent des paires d'instructions fréquentes. Aussi, les opérations très fréquentes, souvent appairées, gagnent à dupliquer l'unité associée. Et au contraire, les unités rarement utilisées ne doivent pas être dupliquées. Il se trouve que les unités les plus utilisées sont les ALU entières, suivies par les unités mémoire et l'unité de branchement. Le cout en circuit n'est aussi pas le même. Dupliquer les ALU entière est trivial, car elles ont un budget en transistors assez faible. Les circuits multiplieurs, diviseurs, et les ''barrel shifter'' ont eux un cout en transistor plus élevés. Si on devait faire un classement, on aurait : ALU entière < ''barrel shifter'' < multiplieur. Pour les unités mémoire, le cout en transistor est là aussi conséquent. Le résultat final est que dupliquer les ALU entières est privilégié sur le reste, comme l'a vu dans la section précédente. Les unités mémoire arrivent en seconde place, suivie par les multiplieurs/''barrel shifter'' à la troisième place, et les unités de branchement à la quatrième place. Les CPU superscalaires larges ont donc tendance à multiplier les unités mémoire en second. Les multiplieurs et ''barrel shifters'' sont eux aussi dupliqués sur les CPU superscalaires larges, mais cela vient souvent après avoir dupliqué les unités mémoire. La raison est que les accès mémoire sont critiques pour la performance des CPU à exécution dans le désordre, pas les multiplications. Pour les unités de branchement, une subtilité complique le fait d'en installer plusieurs. Que faire quand deux branchements sont pris ? La solution la plus simple est de ne pas se trouver dans cette situation : on n'utilise qu'une seule unité de branchement et on n’exécute qu'un seul branchement par cycle. La majorité des processeurs superscalaires étroits font ainsi. Les processeurs superscalaires larges ont cependant deux unités de branchements, mais ils n'acceptent qu'un seul branchement pris à la fois. Si les deux branchements pris sont exécutés en même temps, le processeur n’exécute que le plus récent, dans l'ordre du programme. ===Les CPU superscalaires mélangent les trois techniques=== Les CPU superscalaires utilisent toutes les techniques à la fois : partitionnement, duplication de l'ALU entière, duplication des autre unités fonctionnelles. Chaque processeur utilise ces trois stratégies à sa sauce, en fonction de son budget en transistor. Les quatre techniques ont cependant un cout en circuit différent, et donnent des gains de performances eux aussi forts différents. * Le '''partitionnement superscalaire''' a un cout en circuit modéré, car on n'a pas besoin de dupliquer d'ALU. * La '''duplication des ALU entières''' est la technique la plus importante : elle a un cout en circuit modéré, et donne des gains en performance impressionnants. * La '''duplication des autres unités''' a un cout en circuit variable, pour des gains en performance eux aussi variables. * Le '''partage des ports d'émission''' réduit le cout en circuit du CPU, pour des pertes de performances mineures si bien fait. L'usage du partitionnement seul, sans duplication, était surtout le fait des processeurs commercialisés entre les années 1989 et 1993. Le partage des ports d'émission a lui aussi mis un peu de temps pour s'imposer. Globalement, les processeurs superscalaires ont évolués progressivement, pour se rapprocher d'une sorte de standard. Mais pour comprendre ce qu'est ce standard, et en quoi les CPU historiques s'en sont progressivement rapprochés, il faut étudier l'histoire des CPU superscalaires. L'histoire des CPU superscalaires a commencé dès 1960, mais est resté un projet de recherche pendant plusieurs décennies. De nombreux designs ont été conçus, mais abandonnés avant la production, comme l'ACS-1 d'IBM. Les années 1980 ont vu l'arrivée de prototypes de processeurs VLIW, mais qui n'étaient pas superscalaires. Par exemple, l'Apollo DN10000 et l'Intel i860 pouvaient émettre deux instructions à la fois, sous conditions, mais demandaient que le compilateur fasse une bonne partie du travail. Les premiers CPU superscalaires commercialisés sont sortis en 1989. Deux CPUs superscalaires sont sortis cette année là : le RS/6000 d'IBM et l'i960CA d'Intel. Puis, la compétition s'est aussi lancée dans la bataille. Les CPU commercialisés avant l'année 1993 étaient à double émission, à l'exception du SuperSPARC qui utilisait la triple émission. Les modèles après 1993 hésitaient entre double et quadruple émission. Dans le tableau ci-dessous, les processeurs quadruple émission sont en bleu, les triple émission sont en rouge, les autres ne sont pas en couleur. {|class="wikitable" |- ! !! IBM !! HP PA-RISC !! SPARC !! Intel!! Alpha !! Autres |- ! 1989 | RS/6000 || || || i960CA || || |- ! 1990 | || || || || || |- ! 1991 | || || || || || Motorola 88110 |- ! 1992 | RSC || PA 7100 || class="f_rouge | SuperSPARC || || 21064 || |- ! 1993 | PPC 601 || || HyperSPARC || Pentium || || |- ! 1994 | class="f_bleu | POWER 2 || PA 7200 || || || class="f_bleu | 21164 || |- ! 1995 | 603/604 || class="f_bleu | PA 8000 || class="f_bleu | UltraSPARC 1 || Microarchitecture P6 (+ concurrence AMD) || || class="f_bleu | MIPS R1000 |- ! 1996 | class="f_bleu | 620 || || || || class="f_bleu | 21264 || |- ! ... || ... || ... || ... || ... || ... || ... |} Les premiers CPU à double émission sont assez représentatifs des CPU à double émission modernes. Il faut dire que se limiter à deux voies ne permet pas de faire beaucoup de choses. Voici le tableau chronologique disant quel CPU utilisait quelle technique. * Les CPU en vert utilisaient la double émission entière-flottante. * Les CPU en rouge utilisaient la double émission entière "pure". * Les CPU en jaune utilisaient un ''partitionnement complet'' entre ALU, FPU et unité mémoire. * Les CPU sans couleur utilisaient un grand nombre d'unités, avec beaucoup de ports d'émission. * Les CPU barrés utilisent la triple ou quadruple émission et seront vu dans la section suivante. {|class="wikitable" |- ! !! IBM !! HP PA-RISC !! SPARC !! Intel!! Alpha !! Autres |- ! 1989 | class="f_vert | RS/6000 || || || class="f_rouge | i960CA || || |- ! 1990 | || || || || || |- ! 1991 | || || || || || Motorola 88110 |- ! 1992 | class="f_vert | RSC || class="f_vert | PA 7100 || <s>SuperSPARC</s> || || class="f_jaune | 21064 || |- ! 1993 | class="f_vert | PPC 601 || || class="f_jaune | HyperSPARC || class="f_rouge | Pentium || || |- ! 1994 | <s>POWER 2</s> || PA 7200 || || || <s>21164</s> || |} C'est en 1994, que la quadruple émission est arrivée et que les CPU ont essayé divers implémentations. Il y avait alors trois stratégies pour la double/triple/quadruple émission, qui partageaient des problèmes similaires. La première implémentation dupliquait les ALUs et les FPUs, ce qui permettait d'émettre deux opérations flottantes avec deux opérations entières. Le POWER 2 dupliquait ses FPUs à la perfection, alors que le 21264 séparait l'additionneur et le multiplieur flottant. Les accès mémoire étaient traités comme des opérations entières et le processeur pouvait souvent en émettre deux à la fois. Mais une telle organisation n'est plus utilisée de nos jours, car, sans instructions flottantes à exécuter, elle est équivalente à de la double émission. La seconde implémentation utilisait deux ALU entières (dont un multiplieur), une unité mémoire et une FPU.Cette organisation est intéressante, mais encore trop stricte pour donner de bons résultats, les quadruplets avec exactement deux opérations entières, un accès mémoire et une opération flottante étant trop rares. L'usage de ces 4 unités en double ou triple émission a été utilisé sur le PA 7200 et le SuperSPARC. Malheureusement, en plus de problèmes au niveau de son cache, le SuperSPARC avait de nombreuses contraintes d’appariement, car le banc de registre n'avait pas assez de ports pour alimenter certaines combinaisons d'instructions. De plus, s'il émettait une multiplication, il ne pouvait pas émettre de seconde µop. Enfin, une troisième implémentation utilisait un grand nombre d'unités fort différentes, bien plus que quatre, avec au minimum deux ALU entières. Prenons l'exemple de l'UltraSPARC, qui avait : deux ALU entières, une unité mémoire, une unité de branchement, un additionneur flottant, un multiplieur flottant, un diviseur flottant (aussi utilisé pour le calcul des racines carrées), et 2 unités graphiques pour les calculs sur des pixels. En tout, cela fait 9 unités différentes, pour de la quadruple émission. Dans le même genre, les processeurs MIPS R8000 et R10000 avaient une implémentation plus moderne, dans le sens où toutes les unités étaient dupliquées. Le CPU avait deux ALU, deux FPU et deux unités mémoire. Il pouvait donc émettre quatre instructions à la fois, tant que le paquet collait avec ces six unités. Moitié opérations entières, moitié opérations mémoire, avec de quoi remplacer les opérations entières par des opérations flottantes. Le PA 8000, lui, dupliquait toutes ses unités en deux exemplaires, ce qui n'est pas l'idéal, aucun processeur moderne ne fait cela aujourd'hui. Le tout est résumé dans le tableau ci-dessous, avec : * en vert les CPU utilisant la première stratégie ; * en rouge les CPU utilisant la seconde stratégie ; * en jaune les CPU utilisant la troisième stratégie. {|class="wikitable" |+ Processeurs quadruple émission historiques |- ! Année !! Processeur !! Unités |- ! 1991 | class="f_jaune | Motorola 88110 || class="f_jaune | 2 ALU + MUL + DIV + BIT + MEM + FADD + 2 unités graphiques |- |- ! rowspan="2" | 1994 | class="f_vert | POWER 2 || class="f_vert | 2 ALU/MEM + 2 FPU (+ 2 Branchements via ''branch folding'') |- | class="f_rouge | 21164 || class="f_rouge | 2 ALU + FPU + MEM |- ! rowspan="3" | 1995 | PA 8000 || 2 ALU + 2 ''barrel shifters'' + 2 MEM + 2 FPU (FMA) + 2 FPU (DIV et SQRT) + 2 SIMD |- | class="f_jaune | UltraSPARC 1 || class="f_jaune | 2 ALU + MEM + BRANCH + FADD + FMULFDIV + 2 unités graphiques |- | MIPS R8000 et R10000 || 2 ALU + 2 FPU + 2 MEM |- ! rowspan="2" | 1996 | class="f_rouge | 620 || class="f_rouge | 2 ALU + FPU + MEM |- | class="f_vert | 21264 || class="f_vert | 2 ALU/MEM + 2 FPU (FADD + FMUL) |} Malheureusement, ces CPUs historiques n'avaient ni assez d'unités de calcul entières, ni d'unités mémoire, pour remplir la quadruple émission. Environ la moitié des instructions d'un programme correspond à des instructions entières. Pour en profiter, un processeur à N voies doit disposer d'au minimum N/2 ALU entières, l'idéal étant d'aller au-delà. Les CPU superscalaires historiques avaient 2 ALU pour de la quadruple émission, ce qui était très limite. En comparaison, les CPU superscalaires modernes mettent le paquet niveau ALU entière. La plupart des CPU x86 modernes descendent rarement sous les 2/3, la plupart remplit presque la totalité de la largeur du CPU. Pour donner un exemple, la microarchitecture Golden Cove d'Intel est un processeur à 6 voies, avec 5 ALU entières. Pour être précis, un programme informatique exécute environ 40% de son code dans des instructions arithmétiques, un autre 40% dans les accès mémoire, et un le reste pour... le reste. La conséquence est que les processeurs modernes dupliquent leurs unités mémoire. Par exemple, la microarchitecture ''Golden Cove'' d'Intel dispose de trois unités mémoire : deux spécialisées dans les écritures, trois dans les lectures. La microarchitecture ''Gracemont'' utilise la pentuple émission et peut émettre 4 µops entières et 4 µops mémoire. Notez que le ratio est équilibré entre opérations entières et mémoire, avec soit égalité, soit un avantage pour les ALU entières. Une autre régularité est que la largeur totale du processeur peut être occupée par des opérations entières/mémoire. Pour le dire autrement, sur un processeur quadruple émission, il pourra émettre un mix de 4 instructions entière/mémoire, avec zéro opération flottante. Idem avec des processeurs triples ou pentuple émission, voire plus. Si le processeur émet une opération flottante, elle remplace une opération entière. Prenons l'exemple des processeurs AMD K6, sortis en 1997, juste avant les AMD Athlon. Ils avaient 10 unités de calcul, 6 ports d'émission, 4 ports de décodage. Voici exactement comment étaient répartie les unités de calcul sur les ports d'émission. C'était des processeurs quadruple émission, ce qui fait que la moitié de la largeur du processeur sert pour des opérations entières, et l'autre moitié pour les accès mémoire. {|class="wikitable" |- ! Port d'émission n°1 !! Port d'émission n°2 !! Port d'émission n°3 !! Port d'émission n°4 !! Port d'émission n°5 !! Port d'émission n°6 ! |- | ALU entière || ALU entière || FPU || Unité de branchement || Unité LOAD || Unité STORE |- | || Multiplieur || || || || Unité de calcul d'adresse (instruction LEA) |- | || ''Barrel shifter'' || || || || Unité pour les instructions PUSH |} Les microarchitectures K7, K8 et K10, utilisées sur les anciens CPU AMD Athlon, sont un exemple moins représentatif. Ces microarchitectures utilisent le partage des ports d'émission au maximum. C'était des microarchitectures à triple émission, avec six ports d’émission. Il y avait trois ports d'émission pour les opérations flottantes, et trois ports d'émission pour les micro-opérations entières/mémoire. Il y avait trois ALU entières et trois unités mémoire, chaque ALU partageait un port d'émission avec une unité mémoire. Elle pouvait donc émettre soit trois opérations entières, soit trois µops mémoire, soit un mix des deux. En plus des mix avec les opérations flottantes et branchements. {|class="wikitable" |- ! Port d'émission n°1 !! Port d'émission n°2 !! Port d'émission n°3 !! Port d'émission n°4 !! Port d'émission n°5 !! Port d'émission n°6 ! |- | ALU entière || ALU entière || ALU entière || FADD || FMUL || FPU (autres opérations) |- | Multiplieur || || || || || |- | LOAD/STORE || LOAD/STORE || LOAD/STORE || || || |} Les CPU superscalaires larges dupliquent les multiplieurs et/ou les ''barrel shifters'', et même les unités de branchement. La raison est que quand la largeur du CPU augmente, le processeur traite des paquets d'instructions de plus en plus gros. Par exemple, pour un CPU à 10 voies, cela veut dire émettre 10 instructions en même temps. Il est alors plus fréquent d'avoir deux multiplications, deux décalages, deux accès mémoire, deux branchements. Par exemple, la moyenne est d'une multiplication tous les 5 instructions. Les CPU superscalaires à 10 voies ont donc tendance à avoir deux multiplications par paquet d'instruction, en moyenne. Avoir deux multiplieurs est alors un gain en performance clair. Par exemple, la microarchitecture ''Golden Cove'' a deux ''barrel shifters''. C'est une architecture à 6 voies. {|class="wikitable" |- ! Port d'émission n°1 !! Port d'émission n°2 !! Port d'émission n°3 !! Port d'émission n°4 !! Port d'émission n°5 !! Port d'émission n°6 !! Port d'émission n°7 !! Port d'émission n°8 !! Port d'émission n°9 !! Port d'émission n°10 |- | ALU entière || ALU entière || ALU entière || ALU entière || ALU entière || LOAD || LOAD || LOAD || STORE || STORE |- | ''Barrel shifter'' || Multiplieur || Multiplieur || ''Barrel shifter'' || || || || || || |- | Branchements || Diviseur || || Branchements || || || || || || |} ==Les µops mémoire sur les processeurs superscalaires== Plus haut, nous avons volontairement passé sous silence les accès mémoire. La raison à cela est que leur support sur les CPU superscalaire peut se faire de plusieurs manières différentes, qu'il vaut mieux expliquer dans une section dédiée. Les différentes implémentations sont décrites dans la liste suivante, nous allons les voir une par une. * Avec la première méthode, les accès mémoire sont exécutés par le pipeline pour les opérations entières. * Avec la seconde méthode, les accès mémoire ont un pipeline dédié ; c'est l'''émission parallèle des accès mémoire''. * Avec la troisième méthode, il est possible d'émettre plusieurs accès mémoire simultanément : c'est l'''émission multiple des accès mémoire''. Voyons ces trois cas dans le détail. Nous verrons notamment les différentes formes d'émission multiple des accès mémoire. ===Les accès mémoire traités dans le pipeline entier=== Dans le cas le plus simple, les accès mémoire sont traités comme des opérations entières un peu spéciales. L'unité mémoire est sur le même port d'émission que l'ALU entière, ce qui fait que les accès mémoire remplacent des opérations entières. Faire ainsi permet d'utiliser une ALU entière pour les calculs d'adresse, pas besoin de rajouter une unité de calcul d'adresse séparée. Typiquement, un processeur de ce type place l'unité mémoire après l'unité de calcul. Les opérations entières n'utilisent que l'ALU entière, mais pas l'unité mémoire. Les accès mémoire exécutent un calcul d'adresse dans l'ALU entière, puis l'adresse calculée est envoyée à l'unité mémoire. Le tout est illustré ci-dessous, dans le cas d'un processeur historique à double émission entière-flottante. [[File:Processeur non-superscalaire basique 01.png|centre|vignette|upright=1.5|Processeur non-superscalaire basique]] Un exemple de CPU double émission de ce type est celui du Power PC 440, un CPU destiné à l'embarqué. Vu qu'il était destiné à l'embarqué, il n'avait pas de FPU, il n'avait pas besoin de manipuler de nombres flottants. Il n'a donc que des ALU entières, un multiplieur et une unité mémoire. Il dispose de deux ports d'émission. Le premier est connecté à une ALU entière et un circuit multiplieur, le second est relié à l'unité mémoire et une seconde ALU entière. Une organisation simple, mais très efficace ! [[File:PowerPC 440.png|centre|vignette|upright=2|Microarchitecture du PowerPC 440.]] L'implémentation économise une unité de calcul d'adresse, mais n'a pas de cout en performance significatif. Les accès mémoire étant très lents, émettre une µop entière en parallèle d'un accès mémoire ne sert pas à grand-chose. On peut émettre cette µop entière un cycle plus tard, elle sera terminée avant même que l'accès mémoire soit terminé, même si l'accès mémoire se fait dans le cache L1 ou L2. Pour comprendre pourquoi, faisons quelques calculs. Un accès mémoire prend deux-trois cycles quand il tombe dans le cache L1. Et on doit attendre qu'il soit terminé pour en émettre un nouveau. Combien d'instructions arithmétiques peut-on lancer pendant ce temps, sur un CPU triple émission ? Au premier cycle, on peut en émettre 2 (l'instruction mémoire prend une place, donc 3-1), puis 3 au second cycle. Ce qui fait 5 instructions arithmétiques au total. Or, il se trouve qu'il y a une instruction d'accès mémoire pour 5 instructions arithmétiques, environ. Par contre, ce compromis change quand on passe à la quadruple émission, voire au-delà. Dans ce cas, il devient intéressant de pouvoir émettre une nouvelle instruction mémoire à chaque cycle. Ce qui nous amène à la section suivante... ===L'émission parallèle des accès mémoire=== A partir de la quadruple émission, la tendance a été de séparer l'unité mémoire des ALU entières. Cela permet d'émettre des µops mémoire en même temps que des µops entières et/ou flottantes., ce qui porte le nom d''''émission parallèle des µops mémoire''', ou encore ''émission mémoire parallèle''. Par exemple, un processeur quadruple émission peut émettre en même temps deux opérations entières, une opération flottante et un accès mémoire. L'accès mémoire vient en plus des opérations entières, il n'est pas possible de remplacer l'accès mémoire par une opération entière. La technique ne permet pas de faire les calculs d'adresse dans l'ALU entière. Il faut donc utiliser une unité de calcul d'adresse séparée. Elle est intégrée dans l'unité mémoire, qui fait l'interface entre le cache et le banc de registres. Le cout en circuits est très faible, car les unités de calcul d'adresse n'utilisent guère plus qu'un additionneur et un circuit de décalage très simple. L'émission mémoire parallèle est plus facile à implémenter sur les CPU RISC, qui ont des instructions mémoire séparées du reste. Les CPU CISC ne sont pas dans ce cas, ce qui fait que séparer l'unité mémoire du pipeline entier est compliqué. Les CPU superscalaires historiques étaient pour moité des CPU RISC et pour moitié des CPU CISC, ce qui fait qu'ils n'utilisaient pas ou peu l'émission mémoire parallèle. Les premiers processeurs superscalaires se contenaient de l'émission parallèle mémoire, ils ne pouvaient émettre qu'un seul accès mémoire à la fois, l'unité mémoire n'était pas dupliquée. Et ce n'est pas tant un problème que ça, du moins sur les processeurs à double ou triple émission. En effet, il est rare que l'unité mémoire doive faire deux accès simultanés. Notons que le processeur peut exécuter une instruction mémoire en parallèle d'un calcul ou d'un branchement, seuls les accès mémoire simultanés sont impossibles. ===L'émission multiple des accès mémoire avec une LSQ=== Les processeurs superscalaires larges travaillent sur des paquets de 8 à 10 instructions, il est plus fréquent d'avoir plusieurs accès mémoire par paquet. Dans ces conditions, il est utile d'avoir une '''émission multiple des accès mémoire''', à savoir d'émettre plusieurs micro-opérations mémoire en même temps. Les processeurs superscalaires modernes sont capables d'émettre plusieurs lectures/écritures simultanément. Par exemple, ils peuvent émettre une lecture en même temps qu'une écriture, ou plusieurs lectures, ou plusieurs écritures. Il faut noter que selon le processeur, il peut y avoir des restrictions quant aux accès mémoire émis en même temps. Par exemple, certains processeurs peuvent émettre une lecture avec une écriture en même temps, mais pas deux lectures ni deux écritures. Ou encore, ils peuvent émettre deux lectures, une lecture et une écriture, mais pas deux écritures en même temps. Dans la majorité des cas, les processeurs ne permettent pas d'émettre deux écritures en même temps, alors qu'ils supportent plusieurs lectures. Il faut dire que les lectures sont plus fréquentes que les écritures. Les processeurs qui autorisent toutes les combinaisons de lecture/écriture possibles, sont rares. L'émission multiple des accès mémoire s'implémente dans l'unité mémoire. Pour rappel, l'unité mémoire s'interpose entre le cache L1 et le reste du pipeline. Dans le cas le plus simple, elle incorpore une ''load/store queue'' et des unités de calcul d'adresse. L'émission multiple des accès mémoire demande de rendre la ''Load-store queue'' multi-ports, afin de gérer plusieurs micro-opérations mémoire simultanées. Il faut aussi dupliquer les unités de calcul d'adresse reliées à la LSQ, chaque port d'émission mémoire devant avoir sa propre unité de calcul d'adresse. : Dans ce qui suit, nous parlerons d'AGU (''Adress Generation Unit'') pour désigner les unités de calcul d'adresse, et de LSQ pour designer la ''Load-store queue''. [[File:Processeur non-superscalaire basique 02.png|vignette|upright=1|Processeur non-superscalaire basique]] Dupliquer les ports de la LSQ et les AGU est nécessaire. Mais qu'en est-il du cache ? La réponse varie suivant le processeur. Il y a deux grandes méthodes pour implémenter l'émission multiple des accès mémoire. La première méthode ajoute des ports de lecture/écriture au cache de données, pour faire des lectures/écritures simultanées. Il faut alors dupliquer des unités de calcul, rajouter les ports sur le cache, mais aussi rajouter des ports sur la ''load/store queue'', pour qu'elle échange des données/commandes mémoire avec le cache. Le cout en circuits est alors conséquent La seconde duplique les unités de calcul, mais pas les ports d'accès au cache. Les accès mémoire sont alors accumulés dans la ''load/store queue'', qui sont ensuite traités un par un par le cache. Un exemple est celui des processeurs AMD de micro-architecture K7 K8, à savoir les anciens AMD Athlon et AMD Athlon 64, qui pouvaient calculer trois adresses simultanément, mais ne pouvaient faire qu'un seul accès au cache par cycle. Le cout en circuit est modéré : les unités de calcul coutent très peu, les ports de la ''load/store queue'' coutent déjà un peu plus. Quelques processeurs utilisaient des solutions intermédiaires. Un processeur utilisant cette technique est, par exemple, capable d'émettre quatre µops mémoire en même temps, mais avec seulement deux ports sur le cache. Un exemple classique étant les Pentium 1 et 2 d'Intel, dont nous parlerons dans le chapitre suivant. ===L'émission séparée des LOAD et STORE=== De rares processeurs ont des ports d'émission qui peuvent faire indifféremment lecture comme écritures. Mais les processeurs modernes préfèrent séparer ports d'émission pour les lectures et les écritures. Un exemple est celui des processeurs Intel de micro-architecture Nehalem, qui avaient un port de lecture et un port d'écriture tous deux reliés à la ''Load-store queue'', chacun avec leur propre unité de calcul d'adresse. Comme autre exemple, les processeurs skylake ont une LSQ avec deux ports de lecture et un port d'écriture, ce qui permet d'émettre deux lectures en même temps qu'une écriture. Dans cette section, nous allons étudier le cas avec des ports séparés pour les lectures et écritures. En général, les processeurs ont un peu plus de ports de lectures que d'écritures. Une raison est qu'un programme a, en moyenne, un tout petit peu plus de lectures que d'écritures. Mais la différence n'est pas énorme, c'est un léger déséquilibre. Une seconde raison est que l'exécution dans le désordre marche bien mieux quand les lectures ont lieu le plus tôt possible. Donc mieux vaut privilégier les lectures à l'émission, pour qu'elles se fassent un peu en avance. En pratique, la différence n'est pas très marquée. Il est courant d'avoir un port de lecture et un d'écriture, les CPU superscalaires très larges ont souvent deux ports de lecture et deux d'écriture. A la rigueur, quelques CPU ont trois ports de lecture et deux d'écriture. Le cas le plus simple est celui où on peut émettre une lecture et une écriture en même temps. Il s'implémente facilement si la LSQ est en réalité une simple ''Store queue'', à savoir qu'elle met en avance les écritures uniquement. Pour rappel, les écritures sont mises en attente dans la ''Store queue'', mais les lectures sont exécutées immédiatement. Une fois l'adresse à lire connue, la lecture consulte la ''Store queue'' pour détecter les dépendances de données, puis s'exécute. La donnée à lire est lue soit depuis la ''Store queue'', soit depuis le cache. [[File:Emission LOAD - Store séparée.png|vignette|upright=1|Émission LOAD - Store séparée]] L'implémentation de l'émission multiple est alors très simple. La ''Store queue'' a déjà deux ports, avec un pour les lectures et un autre pour les écritures. Idem pour le cache, qui a naturellement un port de lecture et un d'écriture. Émettre une lecture et une écriture simultanément ne demande donc pas de modification digne de ce nom. La ''Store queue'' doit juste supporter une lecture et une écriture simultanée. Ajouter l'émission d'une seconde lecture n'est pas compliquée : il faut juste rajouter un second port de lecture sur le cache et la ''Store queue''. Pour rappel, l'unité mémoire est précédée par une structure qui met en attente les micro-opérations mémoire avant leur émission finale. La structure en question varie suivant l'implémentation, mais un cas particulier se marie bien avec l'émission multiple des µops mémoire. Il s'agit du cas avec une file de µops séparée pour les lectures et une autre pour les écritures, appelées respectivement la ''file de µops LOAD'' et la ''file de µops STORE''. Il est alors possible d'émettre une lecture et une écriture lors du même cycle d'horloge. Le port de lecture alimente une unité de calcul d'adresse dédiée, directement reliée au cache. Le port d'écriture du cache alimente une unité de calcul, qui est suivie par une file d'écriture, elle-même reliée au cache. Les processeurs AMD de micro-architecture K6 utilisaient cette technique. [[File:Double émission avec le Load Ordering, Store Ordering.jpg|centre|vignette|upright=2.5|Double émission avec le Load Ordering, Store Ordering]] ==Les CPU superscalaire à exécution dans le désordre== La superscalarité modifie aussi les circuits dédiés à l'exécution dans le désordre. Elle modifie les unités de renommage de registre, le ROB et les autres structures liées à l'exécution dans le désordre, au sens large. Aucune structure n'est épargnée. Elles ont tous des prots de lecture/écriture en plus, afin d'encaisser l'émission, le ''commit'' ou le renommage simultané de plusieurs µops. Par exemple, le ROB doit être modifié pour émettre et terminer plusieurs instructions en même temps, en ajoutant des ports de lecture/écriture. Pour un CPU superscalaire à 8 voies, on se dit que le ROB peut retirer 8 µops par cycle maximum. Mais certains processeurs récents ont un ROB qui peut retirer le double ! Un exemple est celui des CPU de micro-architecture Skymont, qui peuvent émettre 8 µops par cycle, mais en retirer 16. Quelques CPU de marque AMD étaient aussi dans ce cas. L'avantage est que cela permet de réduire la taille du ROB, du banc de registre et de quelques autres structures matérielles liées à l'exécution dans le désordre. Le gain sur-compense le cout en transistor nécessaire pour retirer 16 µops par cycle. Dans cette section, nous allons voir comment les étages du pipeline dédiés à l'exécution dans le désordre sont modifiées sur un CPU superscalaire. ===L'exemple du PA-RISC PA 8000=== Avant de commencer, nous allons voir un processeur superscalaire assez simple, le PA 8000, de HP, qui implémente le jeu d'instruction PA-RISC. Bien que très ancien, il implémentait l'exécution dans le désordre et le renommage de registre. Le peu d'informations que nous avons sur ce processeurs proviennent des documents "THE HP PA-8000 RISC CPU" par Ashok Kumar, et l'article de microprocessor report "PA-8000 Combines Complexity and Speed". Ils ne donnent malheureusement pas énormémment d'informations et je devrais être amené à faire quelques suppositions dans ce qui suit. Avant de commencer, parlons de détails sans lien avec la superscalarité. Ce processeur, comme beaucoup de processeurs PA-RISC, n'intégrait pas de cache de niveau L2 dans le processeur, qui était déporté en-dehors du CPU, sur la carte mère. Le processeur préférait utiliser ses transistors pour avoir un cache L1 assez large, quitte à ce qu'il soit plus lent. La lenteur du cache était prévue, le processeur compensait celle-ci en utilisant l'exécution dans le désordre, bien que ce ne soit pas parfait. Les CPU PA-RISC avant le PA 8000 utilisaient un pipeline à vagues ''wave pipeline'', ce qui était assez peu commun, mais le PA 8000 repasse à un pipeline synchrone classique. Passons maintenant à la superscalarité. Le PA 8000 est un processeur quadruple émission, qui peut émettre, à chaque cycle, deux opérations et deux accès mémoire. Le renommage de registre utilise des registres de renommage séparés des registres architecturaux, comme c'était la mode à l'époque. Le budget en transistor faisait que c'était soit ça, soit le renommage dans le ROB, faute de mieux. Le processeur utilise une implémentation ''Read After Issue'', ce qui veut dire que les opérandes des instructions sont lues après l'émission, juste avant l'exécution. Le processeur peut aussi ''commit'' deux opérations et deux accès mémoire par cycle, ce qui revient à transférer les résultats des registres de renommage vers les registres architecturaux. L'exécution dans le désordre est prise en charge par une structure matérielle unique, qui ressemble à une fusion entre un ROB et une fenêtre d'instruction. Et c'est là que je vais devoir faire des suppositions. Le document "THE HP PA-8000 RISC CPU" nomme cette structure : l''''''Instruction Reorder Buffer'''''. Il utilise pas moins de 850 000 transistors, et prend 20% de la taille du ''die''. L'article "THE HP PA-8000 RISC CPU" laisse fortement sous-entendre qu'il s'agit une structure unique, faite d'un seul tenant, mais l'article de microprocessor report dit le contraire par moment. Il est décrit comme une fenêtre d'instruction, à savoir qu'il détecte les dépendances entre instruction et les émet. Il gère aussi la détection des mauvaises prédictions de branchement et peut annuler les instructions chargées à tord, en les retirant de la fenêtre d'instruction. Il est aussi précisé que les instructions quittent cet ''Instruction Reorder Buffer'' dans l'ordre du programme. Elles ne peuvent en sortir que quand elles ont été exécutées et qu'elles n'ont causé aucune exception. Ce qui fait qu'il se comporte comme un ROB de ce point de vue là. Difficile de dire si l'''Instruction Reorder Buffer'' est un réel mélange entre un ROB et une fenêtre d'instruction, ou si il est réellement conçu avec deux structures séparées. Dans ce qui suit, je pars du principe que les deux structures sont séparées. Le processeur contient deux fenêtres d'instruction : une réservée aux µops mémoire (LOAD et STORE), l'autre pour les opérations entières/flottantes. Elles ont chacune 28 entrées, ce qui permet de mémoriser 56 µops au maximum. Les deux peuvent recevoir 4 µops par cycle de la part des décodeurs. Là encore, précisons que les choses ne sont pas claires pour ce qui est de la séparation. L'article de Microprocessor report dit que les deux sont physiquement séparées, et que cette séparation physique permet de simplifications (les opérations mémorisent des noms de registres plus court que les adresses demandées par les µops LOAD/STORE). Mais l'autre document cité laisse penser que l''''Instruction Reorder Buffer'' est une structure unique. A chaque cycle, le processeur peut émettre deux instructions de calcul et deux instructions mémoire. Les deux fenêtres d'instruction ont pour cela chacune deux ports d'émission. Les deux prots d'émission pour les µops mémoire sont identiques, et peuvent faire aussi bien des µops LOAD que STORE. Le cache L1 est un cache double port, ce qui permet de faire deux lectures/écritures apr cycle, ce qui colle avec la double émision de µops mémoire. Pour ce qui est des µops entières/flottantes, le processeur a dupliqué toutes ses unités de calcul : il a deux ALU entières, deux ''barrel shifters'', deux FPU de type FMAC, et deux unités de division flottante. Vraisemblablement, il y a deux ports d'émission, chacun étant connecté à une unité de chaque type. Le partage des ports d'émission est donc parfait. En clair : le processeur aurait une superscalarité presque parfaite s'il était un CPU àç double émission ! A chaque cycle, la fenêtre d'instruction émet les deux µops les plus anciennes qui sont prête à être exécutées. La documentation dit que la fenêtre émet "la plus vielle instruction paire, et la plus vielle instruction impaire", ce qui sous-entend que la fenêtre d'instruction est en réalité composée de deux sous-fenêtres, une fenêtre paire et une impaire. Les µops sont insérées après le décodage dans ces sous-fenêtres : les deux µops sont réparties dans les deux. Et lors de l'émission, une µops vient d'une sous-fenêtre, une autre µops vient de l'autre. La fenêtre d’instruction a donc une structure partitionnée, avec une logique d'éveil segmentée, une partie gérant la moité de la fenêtre d'instruction, l'autre gérant le reste. [[File:PA 8000 - microarchitecture.png|centre|vignette|upright=2|PA 8000 - microarchitecture]] ===La superscalarité avec une file/fenêtre d'instruction centralisée=== Plus haut, nous avons montré qu'un processeur pouvait avoir plus de ports d'émission que de ports de décodage. On dit aussi que sa ''largeur de décodage'' était supérieure à sa ''largeur d'émission''. La '''largeur de décodage''' est le nombre de µops fournies par l'unité de décodage par cycle d'horloge, la '''largeur d'émission''' est le nombre maximal de µops émises par cycle d'horloge. Et n'allez pas croire qu'un surplus de ports d'émission est du gâchis. Sur les processeurs avec exécution dans le désordre, ce surplus peut être utilisé. Mais avant toute chose, évacuons un détail. Vous avez sans doute pensé que le surplus peut être exploité par les instructions machines décodées en plusieurs µops . Par exemple, si une instruction est décodée en deux µops, on pourrait avoir un port d'émission en plus pour en profiter. Mais les ports de décodage sont *en sortie du décodeur*, et contiennent des µops, pas des instructions. Le surplus de ports d'émission peut occasionnellement utiliser le surplus de ports de décodage, mais cela implique que des µops ont été mises en attente dans l'unité d'émission, pour être émises par la suite. Et cela implique l'usage d'une fenêtre d'instruction ou d'une file de µops. Le principe est que les µops sont accumulées dans la fenêtre d'instruction, en attendant leurs opérandes ou la résolution d'une dépendance. Et si l'occasion se présente, une µops est émise sur chaque port d'émission. Il y a donc un gain en performances, mais il faut faire quelques précisions sur son origine. La largeur d'émission utilisée ne peut pas dépasser, *en moyenne*, la largeur de décodage. Et c'est intuitif : un CPU qui décode 4 µops par cycle ne peut pas émettre 6 par cycle en moyenne, sur le temps long, il n'y a pas de µops en surplus qui sortent du vide. Par exemple, sur un processeur quadruple émission, si on analyse combien d'instructions sont émises par cycle, il peut y avoir des cycles où la largeur d'émission est totalement utilisée, mais ce sera compensé par des périodes où elle est fortement sous-utilisée. Les µops sont accumulées en cas de sous-utilisation, puis consommées en cas d'utilisation complète. Les deux périodes se compensent. Et c'est là que l'on peut comprendre d'où vient le gain en performance. Les cycles où les ports d'émission sont sous-utilisés existent systématiquement, que le processeur utilise l'exécution dans le désordre ou pas. Ils sont liés à la présence de dépendances de données, aux contraintes d’appariement, etc. Elles tendent à réduire la moyenne du nombre de µops émises par cycle. Par contre, ce sont les cycles de rattrapage, où les ports en surplus sont utilisés, qui font remonter la moyenne. Le gain en performance est donc lié à ces cycles de rattrapage, où les µops accumulées sont émises dans les ports en surplus. Et ils n'existent que sur les processeurs avec une file/fenêtre d'instruction. Réduire le nombre de ports d'émission permet de garder des fenêtres d'instruction et un ROB simples, rapides et économes en énergie. Et mine de rien, c'est là un compromis important : à quoi bon augmenter le nombre de ports d'émission si c'est pour que ce soit compensé par une fréquence plus faible ? Par contre, réduire le nombre de ports augmente la ''port contention'', surtout si on a mal réparti les ALU. Il faut donc trouver un compromis entre réduire le nombre de ports d'émission d'un côté, réduire la ''port contention'' de l'autre. La différence entre largeur de décodage et d'émission a un impact assez fort sur le banc de registre, et précisément sur son nombre de ports de lecture. Le banc de registre a besoin de plus de ports de lecture avec une fenêtre d’instruction qu'avec des stations de réservation. Rappelons la terminologie utilisée dans ce cours. Les fenêtres d'instruction se contentent de mémoriser la micro-opération et quelques bits pour détecter la disponibilité des opérandes. Par contre, les stations de réservations mémorisent aussi les opérandes des instructions. Et cette différence a une influence le nombre de ports de lecture du banc de registre. Supposons que toutes les instructions sont dyadiques, à deux opérandes. Comptons le nombre de ports nécessaires pour alimenter les unités de calcul, sans utiliser d'arbitre de banc de registre. Avec une fenêtre d'instruction, il faut le double du nombre de ports d'émission. Mais avec des stations de réservation, il faut le double des ports de décodage. La raison est que les registres sont lus après émission avec une fenêtre d'instruction, avant avec des stations de réservation (sous-entendu, après le décodage). Or, comme dit plus haut, les processeurs superscalaires larges ont souvent plus de ports d'émission que de décodage. ===La superscalarité à fenêtres d'instruction décentralisées=== Les processeurs précédents utilisaient une unité d'émission simple, qui pouvait utiliser l'émission dans l'ordre ou dans le désordre. Elle peut être remplacée par une fenêtre d'instruction centralisée dans que cela quoi que ce soit aux explications précédentes, idem avec une station de réservation centralisée. En soi, l'exécution dans le désordre est donc totalement compatible avec une implémentation simple de la superscalarité. Par contre, des subtilités surviennent avec les fenêtres d'instruction décentralisées. Pour rappel, sur ces processeurs, les µops sont émises en deux phases. Une première phase de ''dispatch'' qui envoie les µops vers la fenêtre d'instruction adéquate, sans détecter les dépendances de données. La seconde phase de ''schedule'' gère les dépendances de données, elle met en attente les µops en attendant que l'unité soit disponible pour les exécuter, en attendant aussi que les opérandes soient disponibles. Et à ce petit jeu, il y a une différence entre le nombre de µops qui sont ''dispatch par cycle'' et celles qui sont ''schedule''. Dit autrement, la largeur d'émission est scindée en une '''largeur de ''dispatch''''' et une '''largeur de ''schedule''. Par exemple, prenons un processeur triple émission avec deux stations de réservation : une pour les µops entières/mémoire, et une autre pour les µops flottantes. L'unité d'émission peut ''dispatch'' maximum trois µops par cycle : soit trois µops entières/mémoire, soit trois flottantes, soit un mix de trois µops différentes. Les stations de réservation, quant à elles, peuvent chacune ''schedule'' 3 µops par cycle, vers trois ALUs entières pour la station de réservation entière/mémoire, vers trois FPS pour la station de réservation flottante. De quoi ''dispatch'' trois µops, mais d'en ''schedule'' six, à chaque cycle. Et cet exemple ne sort pas de nulle part : les CPU x86 d'Intel et AMD sont globalement dans ce cas, même si les chiffres varient d'une microarchitecture à l'autre. L'exemple précédent colle parfaitement à la microarchitecture K7 d'AMD, utilisée sur les processeurs Athlon dans les années 2000. [[File:AMD K7.png|centre|vignette|upright=2.5|AMD K7, microarchitecture.]] L'exemple précédent avait assez d'unités entières/flottantes pour couvrir toute la largeur de décodage/''Dispatch''. Mais ce n'est pas toujours le cas, comme va le montrer l'exemple suivant. Le MIPS R10000, qui utilisait un mélange de files de µops et de fenêtres d'instructions : une file de µops les accès mémoire, une fenêtre pour les instructions entières et une autre pour les opérations flottantes. Les branchements et NOPs étaient exécutés dans une unité de branchement distincte. Les trois files/fenêtres peuvent mémoriser 16 µops. Le processeur avait deux ALU entières, une AGU de calcul d'adresse, un additionneur flottant et un multiplieur/diviseur flottant. Il y avait un multiplieur entier sur le port d'émission l'ALU 2. Le processeur décodait 4 instructions par cycle et produisait jusqu'à 4µops, qui étaient redistribuées sur les trois fenêtres d'instructions. Chacune pouvait accepter 4 µops par cycle, ce qui fait que processeur pouvait ''dispatch'' 4 µops entières, ou 4 µops flottantes, ou 4 µops mémoire, ou un mélange de deux ou trois types de µops. Pour ce qui est du ''schedule'', la fenêtre d'instruction entière pouvait émettre 2 µops, la fenêtre flottante pouvait émettre une addition en même temps qu'une multiplication/divison flottante et qu'un branchement conditionnel flottant, et la file de µops mémoire ne pouvait émettre qu'une µop mémoire à la fois. En tout, cela fait 6 µops ''schedule'' pour 4 µops au ''dispatch''. [[File:R 10000.png|centre|vignette|upright=2.5|MIPS R10000, microarchitecture.]] ===La superscalarité à fenêtres d'instruction totalement décentralisées=== Prenons un cas extrême de fenêtre d'instruction décentralisée : celui où chaque ALU entière a sa propre station de réservation. En clair : une fenêtre d'instruction par ALU/FPU ! On parle de '''fenêtres d'instruction totalement décentralisées'''. Vous vous dites que ce cas est un peu trop extrême pour être réaliste, mais il n'en est rien. C'est même très courant sur les architectures basse consommation, et sur pas mal de CPU x86 modernes. Une telle organisation entraine une légère perte de performance, comparé à une fenêtre d'instruction centralisée ou partiellement décentralisée. Et cela peut se comprendre par un exemple. Imaginez un processeur avec deux ALU, donc deux stations de réservation. Il arrivera qu'une station de réservation ait plusieurs µops prêtes, alors que l'autre en ait zéro. Dans une telle situation, une seule µop sera émise au cycle suivant, vu que chaque station de réservation a un seul port d'émission vers une seule ALU entière. Par contre, avec une fenêtre d'instruction centralisée double port, on aurait pu émettre les deux µops en même temps sur deux ALUs séparées. La perte de performance est donc liée au fait que les µops '''''prêtes''''' sont mal réparties dans les différentes stations de réservation. Il arrivera que des µops prêtes s'accumulent dans une station de réservation, alors que d'autres seront pleines, ou du moins sous-utilisées. Et ce n'est pas quelque chose qui peut être réglé à l'étape de ''dispatch'', car on ne sait pas encore quand les µops auront leurs opérandes de disponibles. [[File:Comparaison entre une station de réservation totalement décentralisée et une autre qui ne l'est pas.png|centre|vignette|upright=2.5|Comparaison entre une station de réservation totalement décentralisée et une autre qui ne l'est pas.]] Par contre, décentraliser totalement les fenêtres d'instruction entraine aussi un gain considérable en termes de consommation énergétique. Et c'est la raison pour laquelle les fenêtres d'instructions totalement décentralisées sont utilisées sur les architectures basse consommation. La perte de performance ne peut pas s'expliquer clairement à ce stade du cours, car il nous faudrait parler d'émission superscalaire. Le gain en matière d'énergie vient de l'économie de circuits, qui est assez drastique. Le gain en matière d'énergie vient de l'économie de circuits, qui est assez drastique. Je rappelle qu'une station de réservation a besoin, pour N instructions, d'environ N^2 circuits (des comparateurs, notamment). Prenons une station de réservation centralisée de 64 entrées et comparons avec 8 stations de 8 entrées chacune. Les deux donneront 64 entrées, mais la première aura un cout en circuit proportionnel à 64², alors que le second aura un cout en circuit de 8 *(8²). Entre les deux, le choix est clair : la seconde solution est plus économe. D'où l'utilisation de cette solution sur les microarchitectures basse consommation. ===L'unité de renommage superscalaire=== Avec la superscalarité, l'unité de renommage de registre doit gérer le cas où des instructions consécutives ont des dépendances de registre. Par exemple, prenons un processeur à double émission, qui renomme deux instructions consécutives. Si elles ont une dépendance de registre, le renommage de la seconde instruction dépend du renommage de la première. La première doit être renommée et le résultat du renommage est utilisé pour renommer la seconde, ce qui empêche d'utiliser deux unités de renommage séparées. Pour cela, elle renomme les registres sans tenir compte des dépendances, pour ensuite corriger le résultat. [[File:Unité de renommage superscalaire.png|centre|vignette|upright=2|Unité de renommage superscalaire.]] Seules les dépendances lecture-après-écriture doivent être détectées, les autres étant supprimées par le renommage de registres. Repérer ce genre de dépendances se fait assez simplement : il suffit de regarder si un registre de destination d'une instruction est un opérande d'une instruction suivante. [[File:Détection des dépendances sur un processeur superscalaire.png|centre|vignette|upright=2|Détection des dépendances sur un processeur superscalaire.]] Ensuite, il faut corriger le résultat du renommage en fonction des dépendances. Si une instruction n'a pas de dépendance avec une autre, on la laisse telle quelle. Dans le cas contraire, un registre opérande sera identique avec le registre de destination d'une instruction précédente. Dans ce cas, le registre opérande n'est pas le bon après renommage : on doit le remplacer par le registre de destination de l'instruction avec laquelle il y a dépendance. Cela se fait simplement en utilisant un multiplexeur dont les entrées sont reliées à l'unité de détection des dépendances. On doit faire ce replacement pour chaque registre opérande. [[File:Correction des dépendances sur un processeur superscalaire.png|centre|vignette|upright=2|Correction des dépendances sur un processeur superscalaire.]] ==Les optimisations des processeurs superscalaires larges== Les processeurs superscalaires larges ont des optimisations spécifiques, qui n'ont pas de sens sur les processeurs superscalaires étroits. Dans les grandes lignes, elles se classent en deux types. Les premières permettent de charger/décoder plus de 5-10 instructions simultanément. Le problème est alors que les branchements viennent mettre leur grain de sel et qu'il faut en tenir compte. Les secondes corrigent des problèmes qui apparaissent quand un CPU intègre plus de 5 à 10 unités de calcul. ===L'étape de chargement d'un CPU superscalaire large=== Charger plusieurs instructions pose de nombreux problèmes sur les processeurs superscalaires larges, qui émettent de 5 à 10 instructions simultanées. Pour rappel, la stratégie basique pour charger N instructions est de charger un bloc de N instructions consécutives. Les instructions après un branchement ne sont pas décodées ni exécutées, ce qui entraine une petite baisse de performance. Pour un N petit, la perte de performance est mineure. Mais pour un N large, elle devient suffisamment importante pour que la conception du CPU doit alors être repensée de fond en comble. Les analyses statistiques disent qu'il y a environ un branchement tous les 4 à 6 instructions. Un CPU a donc tendance à décoder des paquets de 3 à 5 instructions consécutives, avant qu'un branchement casse la dynamique. Or, cela pose des problèmes pour utiliser plusieurs décodeurs. L'implémentation basique, qui charge N instructions consécutives pour alimenter N décodeurs, fonctionne donc jusqu'à 4/6 décodeurs. Au-delà de 5 instructions, un CPU superscalaire doit être adapté pour gérer les branchements dans les paquets d'instruction qu'il émet. Le nombre de 5 instructions ne sort donc pas de nulle part. La première solution utilise un cache de µops, avec un ''front-end'' capable de charger/décoder 4/5 instructions à la fois, pas plus. L'idée est que la majorité des instructions proviennent du cache de µops (plus de 80%), ce qui fait qu'on peut émettre environ 10 instructions à partir du cache de µops, pas besoin d'avoir beaucoup de décodeurs. Les performances sont cependant dégradées lors d'un défaut de cache de µops. Les instructions doivent alors être chargées depuis le cache d'instruction, par paquets de 4-5, puis sont décodées par 4-5 décodeurs, ce qui ne permet pas d’alimenter les unités de calcul à plein régime. La solution précédente joue sur la distinction entre pots de décodage et d'émission. Elle permet d'émettre un grand nombre de µops sans pour autant charger un grand nombre d'instructions en même temps. En quelque sorte, ce n'est qu'une méthode de contournement, le CPU superscalaire reste de type étroit. Mais il est aussi possible d'utiliser un '''''front-end large''''', capable de charger une bonne dizaine d'instructions en même temps. La seule difficulté est de tenir compte de la présence de branchements. Pour rappel, avec un ''front-end'' étroit, les instructions situées après le premier branchement pris sont annulées, elles ne sont pas décodées ni exécutées. [[File:Fetch sur un processeur superscalaire avec prediction de branchements.png|centre|vignette|upright=2|Fetch sur un processeur superscalaire avec prédiction de branchements.]] Un ''front-end'' large charge les instructions de destination du branchement et les placent à sa suite. Ils chargent deux blocs à la fois et les fusionnent en un seul qui ne contient que les instructions présumées utiles. [[File:Cache d'instructions autoaligné.png|centre|vignette|upright=2|Cache d'instructions auto-aligné.]] Mais cela demande de charger deux blocs de mémoire en une fois, ce qui demande un cache d'instruction multiports. Il faut aussi ajouter un circuit pour assembler plusieurs morceaux de blocs en un seul : le fusionneur (''merger''). En pratique, cette solution demande d'ajouter un second port de lecture au cache, pour un cout en hardware important, avec un impact négatif sur le temps d'accès au cache. Et il faut rajouter le fusionneur, qui prend un étage de pipeline à lui tout seul. Et encore, cette solution ne gère pas le cas où un bloc contient plusieurs branchements ! [[File:Implémentation d'un cache d'instructions autoaligné.png|centre|vignette|upright=2|Implémentation d'un cache d'instructions auto-aligné.]] Les exemples précédents partent du principe qu'il n'y a qu'un seul branchement dans un bloc. Mais quand les blocs deviennent assez longs, il est fréquent d'avoir plusieurs branchements dans un bloc. Et il est même possible d'avoir plusieurs branchements pris. Dans un bloc de 8-10 instructions, ce n'est pas rare, et les CPU superscalaires à 8-10 voies sont la règle dans les CPU des années 2020. Pour gérer ce cas, il faut ajouter des ports supplémentaires au cache d'instruction et adapter le fusionneur, pour qu'il puisse fusionner trois ou quatre blocs. De plus, il faut utiliser une unité de prédiction de branchement capable de ''prédire plusieurs branchements par cycle''. ===Le décodage superscalaire large=== Le décodage des instructions n'est pas censé dépendre de l'implémentation du chargement. En théorie, une fois plusieurs blocs d'instruction fusionnés, on peut décoder les instructions en parallèle. Cependant, certains processeurs effectuent le décodage en tenant compte de la manière dont les branchements découpent les blocs. Les processeurs Atom d'Intel utilisent une solution de ce type, qui couple prédiction de branchement et décodage parallèle. Ils chargent/décodent des paquets de 3 instructions consécutives, chaque paquet étant séparé du précédent par un branchement. Pour cela, en plus d'avoir un fusionneur adapté, ils regroupent les décodeurs en ''clusters'', chacun regroupant 3 décodeurs, et pouvant décoder trois instructions consécutives. Les micro-architectures Tremont et Crestmont avaient deux ''clusters'' (6 décodeurs au total), la micro-architecture Darkmont en intègre trois (9 décodeurs au total). Avec deux ''clusters'', le fonctionnement est le suivant. Si le code est composé d'une suite d'instruction sans branchements, seul le premier ''cluster'' est utilisé, limitant le décodage à trois instructions par cycle. Par contre, si l'une des trois instructions décodée est un branchement, alors le second ''cluster'' décode les trois instructions situées après ce branchement, à partir de l'adresse de destination. Avec un troisième ''cluster'', c'est la même chose, sauf qu'il faut qu'il y ait un branchement dans les trois instructions décodées par le second ''cluster''. Mais comment faire pour savoir quels décodeurs activés, quels ''clusters'' sont actifs ? C'est la prédiction de branchement qui commande. Avec deux ''clusters'', elle détermine si un branchement est présent dans les trois instructions à charger, et quelle est son adresse de destination. Sans branchement, elle prévient les décodeurs et les trois instructions chargées sont décodées dans un ''cluster'' libre. Si elle prédit un branchement, elle charge les instructions adéquates, et active les deux ''clusters''. Avec trois branchements, c'est le même mécanisme, sauf que l'unité de prédiction de branchement doit être capable de prédire deux branchements par cycle. [[File:Front-end découplé de la microarchitecture Tremont.png|centre|vignette|upright=3|Front-end découplé de la microarchitecture Tremont.]] Il faut noter que les décodeurs d'un ''cluster'' sont des décodeurs simples, sans microcode. Sur les processeurs Tremont et Crestmont, le microcode était unique et était partagé entre tous les ''clusters''. Un seul ''cluster'' pouvait décoder une instruction complexe avec le microcode, l'autre devait se limiter à des instructions simples uniquement. Depuis Skymont, le microcode est partiellement dupliqué, avec un microcode par ''cluster''. Le cout en hardware peut paraitre prohibitif, pour un gain en performance faible. Sauf que c'est oublier que ce sont des processeurs Atom, sur lesquels beaucoup d'instructions sont microcodées. Les processeurs Atom ont un budget en transistor limité, ce qui fait qu'il est préférable pour eux d'implémenter des instructions en microcode que d'utiliser des unités de calcul dédiées ou des circuits de décodage complexes. Pour limiter la casse, le microcode n'est que partiellement dupliqué. Seul le microcode pour les instructions fréquente est dupliqué. Il y a un microcode secondaire pour certaines instructions, qui est lui unique et partagé par tous les ''clusters''. ===Le contournement sur les processeurs superscalaires larges=== Pour rappel, la technique du contournement (''register bypass'') permet au résultat d'une instruction d'être immédiatement utilisable en sortie de l'ALU, avant même d'être enregistré dans les registres. Implémenter la technique du contournement demande d'utiliser des multiplexeurs pour relier la sortie de l'unité de calcul sur son entrée si besoin. Il faut aussi des comparateurs pour détecter des dépendances de données. [[File:Pipeline Bypass.png|centre|vignette|upright=1|Pipeline Bypass]] La sortie de chaque ALU doit être reliée aux entrées de toutes les autres, avec les comparateurs qui vont avec. Sur les processeurs ayant plusieurs d'unités de calculs, cela demande beaucoup d’interconnexions et de comparateurs. Pour N unités de calcul, cela demande 2 * N² interconnexions, implémentées avec 2N multiplexeurs de N entrées chacun. Si c'est faisable pour 2 ou 3 ALUs, la solution est impraticable au-delà. Non seulement ce serait un enfer à câbler, mais les fils seraient tellement longs que la fréquence du processeur en prendrait un coup. Notez que cela vaut pour les processeurs superscalaires, mais aussi pour tout processeur avec beaucoup d'unités de calcul. En théorie, un CPU à exécution dans le désordre, non-superscalaire, mais avec beaucoup d'unités de calcul, fait face au même problème. En pratique, avoir une dizaine d'ALU implique processeur superscalaire à exécution dans le désordre. D'où le fait qu'on parle du problème maintenant. La seule solution praticable est de ne pas relier toutes les unités de calcul ensemble. À la place, on préfère regrouper les unités de calcul dans différents '''agglomérats''' ('''cluster'''). Le contournement est alors possible entre les unités d'un même agglomérat, mais pas entre agglomérats différents. Évidemment, certaines possibilités de contournement sont perdues, mais c'est compensé par un gain en fréquence et un cout en circuit/fils réduit. C'est un bon compromis, ce qui explique que presque tous les processeurs modernes l'utilisent. Les rares exceptions sont les processeurs POWER 4 et POWER 5, qui ont préféré se passer de contournement pour garder un processeur très simple et une fréquence élevée. ===Le banc de registre des processeurs superscalaires larges=== Pour émettre deux opérations entières simultanément, il faut lire deux fois plus d'opérandes. Et il faut aussi écrire deux résultats dans les registres, en même temps. Pour cela, on double les ports du banc de registre. En général, il faut au maximum 2 ports de lecture et un port d'écriture par unité de calcul. Le problème, c'est que plus un banc de registres a de ports, plus il utilise de circuits, est compliqué à concevoir, consomme de courant et chauffe. Avec plusieurs dizaines d'unités de calcul différentes, ajouter autant de ports impacterait la fréquence du banc de registres et réduirait les performances, voire est totalement impraticable à cause des contraintes thermiques. Les processeurs superscalaires larges doivent donc trouver des solutions. La première solution utilise un banc de registre unique, mais n'utilise pas autant de ports que le pire des cas le demanderait. Le processeur détecte quand il n'y a pas assez de ports pour servir toutes les micro-opérations. Quand ça arrive, l'unité d'émission émet assez de micro-opérations pour exploiter les ports disponibles, mais met en attente les micro-opérations en trop, le temps que les ports se libèrent. Pour cela, le banc de registre est géré par un circuit d'arbitrage spécialisé, intégré à l'unité d'émission, l’'''arbitre du banc de registres''' (''register file arbiter''). Une autre solution est de dupliquer le banc de registres en plusieurs exemplaires qui contiennent exactement les mêmes données, mais avec moins de ports de lecture/écriture. Un exemple est celui des processeurs POWER, Alpha 21264 et Alpha 21464. Sur ces processeurs, le banc de registre est dupliqué en plusieurs exemplaires, qui contiennent exactement les mêmes données. Les écritures dans les registres sont envoyées à tous les bancs de registres, afin de garantir que leur contenu est identique. Chaque exemplaire a exactement deux ports de lecture. La conception du processeur est simplifiée, que ce soit au niveau du câblage, que de la conception des bancs de registres. Une dernière solution découpe le banc de registres en plusieurs bancs de registres plus petits, avec un réseau d'interconnexions pour échanger des données entre bancs de registres. Dans la plupart des cas, cette séparation est invisible du point de vue de l'assembleur et du langage machine. Le processeur se charge de transférer les données entre bancs de registres suivant les besoins. Sur d'autres processeurs, les transferts de données se font via une instruction spéciale, souvent appelée ''COPY''. [[File:Banc de registres distribué.png|centre|vignette|upright=2|Banc de registres distribué.]] Sur de certains processeurs, un branchement est exécuté par une unité de calcul spécialisée. Or les registres à lire pour déterminer l'adresse de destination du branchement ne sont pas forcément dans le même agglomérat que cette unité de calcul. Pour éviter cela, certains processeurs disposent d'une unité de calcul des branchements dans chaque agglomérat. Dans les cas où plusieurs unités veulent modifier le ''program counter'' en même temps, un système de contrôle général décide quelle unité a la priorité sur les autres. Mais d'autres processeurs fonctionnent autrement : seul un agglomérat possède une unité de branchement, qui peut recevoir des résultats de tests de toutes les autres unités de calcul, quel que soit l’agglomérat. ==La macro-fusion : une optimisation du décodage parallèle== Les processeurs superscalaires supportent la technique dite de '''macro-fusion''', qui permet de fusionner deux-trois instructions consécutives en une seule micro-opération. Par exemple, il est possible fusionner une instruction de test et une instruction de saut en une seule micro-opération de branchement. Il s'agit là de l'utilisation la plus importante de la macro-fusion sur les processeurs x86 modernes. La macro-fusion est utilisée pour fusionner un test et un saut en un branchement unique. L'optimisation est présente sur la plupart des CPU superscalaires modernes. Les CPU x86 l'implémentent, mais aussi quelques CPU ARM et les processeurs Apple de série M (M1 à M5, et potentiellement plus quand ils seront sortis). La fusion des instructions se fait lors du décodage des instructions, grâce à la coopération des décodeurs. Elle marche systématiquement si l'instruction de test et le saut sont consécutives, qu'elles forment bien une paire d'instruction. Par contre, insérer une instruction entre les deux empêche la macro-fusion de faire son travail, sauf si l'instruction insérée est un NOP. Les processeurs ARM64 avaient une forme spécifique de macro-fusion, utilisée pour un cas très précis : charger une constante immédiate de 32 ou 64 bits, dans un registre 64 bits. Les CPU ARM 64 bits utilisent des instructions codées sur 32 bits, qui ne peuvent encoder que des constantes immédiates de 16 bits. Pour charger une constante de 32/64 bits, il faut s'y prendre en plusieurs fois. Une première instruction MOVZ charge les 16 premiers bits, puis 2 à 4 instructions MOVK remplissent le reste. MOVZ met à zéro les 48 bits de poids fort, MOVK permet de sélectionner le doublet à modifier dans le registre (on modifie 16 bits, dont on choisit la place, le reste du registre est laissé tel quel). ARM permet de fusionner cette suite d'instructions en une seule µop MOV avec une constante immédiate. On parle alors de '''''MOVZ + MOVK fusion'''''. Une dernière utilisation, [https://www2.eecs.berkeley.edu/Pubs/TechRpts/2016/EECS-2016-130.pdf proposées pour le jeu d'instruction RISC-V], fusionnait un calcul d'adresse et une instruction LOAD/STORE en une seule instruction d'accès mémoire. Elle a été envisagée à une époque où le jeu d'instruction RISC-V ne gérait pas les modes d'adressage base + indice. L'idée était d'avoir une unité mémoire qui gérait le mode d'adressage base + indice et de fusionner des instructions pour l'exploiter. Mais de nos jours, le jeu d'instruction RISC-V intègre le mode d'adressage base + indice, ce qui fait que la macro-fusion n'a aucun intérêt pour ce cas précis. La macro-fusion a de nombreuses limitations en pratique. En théorie, on pourrait l'utiliser au-delà des deux situations mentionnées plus haut. Par exemple, pour fusionner une addition et une multiplication en une seule instruction MAD. Mais l'intérêt est assez faible. Notons que la macro-fusion ne permet que de fusionner des paires d'instructions. Aller au-delà demanderait un cout en circuit trop important. Déjà que tester deux paires utilise pas mal de comparateurs... ==Le ''stack engine'' : une optimisation de la pile d'appel== Les processeurs modernes intègrent une optimisation liée au pointeur de pile. Pour rappel, sur les architectures modernes, le pointeur de pile est un registre utilisé pour gérer la pile d'appel, précisément pour savoir où se trouve le sommet de la pile. Il est manipulé par les instructions CALL, RET, PUSH et POP, mais aussi par les instructions d'addition/soustraction pour gérer des cadres de pile de taille variable. De plus, il peut servir d'opérande pour des instructions LOAD/STORE, afin de lire/écrire des variables locales, les arguments d'une fonction, et autres. C'est donc un registre général adressable, intégré au banc de registre, altéré par l'unité de calcul entière. L'incrémentation/décrémentation du pointeur de pile passe donc par l'unité de calcul, lors des instructions CALL, RET, PUSH et POP. Mais, l'optimisation que nous allons voir permet d'incrémenter/décrémenter le pointeur de pile sans passer par l'ALU, ou presque. L'idée est de s'inspirer des architectures avec une pile d'adresse de retour, qui intègrent le pointeur de pile dans le séquenceur et l'incrémentent avec un incrémenteur dédié. ===Le ''stack engine''=== L'optimisation que nous allons voir utilise un '''''stack engine''''' intégré à l'unité de contrôle, au séquenceur. Le processeur contient toujours un pointeur de pile dans le banc de registre, cela ne change pas. Par contre, il n'est pas incrémenté/décrémenté à chaque instruction CALL, RET, PUSH, POP. Un compteur intégré au séquenceur est incrémenté à la place, nous l’appellerons le '''compteur delta'''. La vraie valeur du pointeur de pile s'obtient en additionnant le compteur delta avec le registre dans le banc de registre. Précisons que si le compteur delta vaut zéro, la vraie valeur est dans le banc de registre et peut s'utiliser telle quelle. Lorsqu'une instruction ADD/SUB/LOAD/STORE utilise le pointeur de pile comme opérande, elle a besoin de la vraie valeur. Si elle n'est pas dans le banc de registre, le séquenceur déclenche l'addition compteur-registre pour calculer la vraie valeur. Finalement, le banc de registre contient alors la bonne valeur et l'instruction peut s'exécuter sans encombre. L'idée est que le pointeur de pile est généralement altéré par une série d'instruction PUSH/POP consécutives, puis des instructions LOAD/STORE/ADD/SUB utilisent le pointeur de pile final comme opérande. En clair, une bonne partie des incrémentations/décrémentation est accumulée dans le compteur delta, puis la vraie valeur est calculée une fois pour toutes et est utilisée comme opérande. On accumule un delta dans le compteur delta, et ce compteur delta est additionné quand nécessaire. Précisons que le compteur delta est placé juste après le décodeur d'instruction, avant même le cache de micro-opération, l'unité de renommage et l'unité d'émission. Ainsi, les incrémentations/décrémentations du pointeur de pile disparaissent dès l'unité de décodage. Elles ne prennent pas de place dans le cache de micro-opération, ni dans la fenêtre d'instruction, ni dans la suite du pipeline. De nombreuses ressources sont économisées dans le ''front-end''. Mais utiliser un ''stack engine'' a aussi de nombreux avantages au niveau du chemin de données/''back-end''. Déjà, sur les processeurs à exécution dans le désordre, cela libère une unité de calcul qui peut être utilisée pour faire d'autres calculs. Ensuite, le compteur delta mémorise un delta assez court, de 8 bits sur le processeur Pentium M, un peu plus pour les suivants. L'incrémentation se fait donc via un incrémenteur 8 bits, pas une grosse ALU 32/64 bits. Il y a un gain en termes de consommation d'énergie, un incrémenteur 8 bits étant moins gourmand qu'une grosse ALU 32/64 bits. ===Les points de synchronisation du delta=== La technique ne fonctionne que si la vraie valeur du pointeur de pile est calculée au bon moment, avant chaque utilisation pertinente. Il y a donc des '''points de synchronisation''' qui forcent le calcul de la vraie valeur. Plus haut, nous avions dit que c'était à chaque fois qu'une instruction adresse le pointeur de pile explicitement, qui l'utilise comme opérande. Les instructions CALL, RET, PUSH et POP ne sont pas concernées par elles utilisent le pointeur de pile de manière implicite et ne font que l'incrémenter/décrémenter. Mais dans les faits, c'est plus compliqué. D'autres situations peuvent forcer une synchronisation, notamment un débordement du compteur delta. Le compteur delta est généralement un compteur de 8 bits, ce qui fait qu'il peut déborder. En cas de débordement du compteur, le séquenceur déclenche le calcul de la vraie valeur, puis réinitialise le compteur delta. La vraie valeur est donc calculée en avance dans ce cas précis. Précisons qu'un compteur delta de 8 bits permet de gérer environ 30 instructions PUSH/POP consécutives, ce qui rend les débordements de compteur delta assez peu fréquent. À noter que si le compteur delta vaut zéro, il n'y a pas besoin de calculer la vraie valeur, le séquenceur prend cette situation en compte. Un autre point de synchronisation est celui des interruptions et exceptions matérielles. Il faut que le compteur delta soit sauvegardé lors d'une interruption et restauré quand elle se termine. Idem lors d'une commutation de contexte, quand on passe d'un programme à un autre. Pour cela, le processeur peut déclencher le calcul de la vraie valeur lors d'une interruption, avant de sauvegarder les registres. Pour cela, le processeur intègre un mécanisme de sauvegarde automatique, qui mémorise la valeur de ce compteur dans le tampon de réordonnancement, pour forcer le calcul de la vraie valeur en cas de problème. La technique du ''stack engine'' est apparue sur les processeurs Pentium M d'Intel et les processeurs K10 d'AMD, et a été conservée sur tous les modèles ultérieurs. L'implémentation est cependant différente selon les processeurs, bien qu'on n'en connaisse pas les détails et que l'on doive se contenter des résultats de micro-benchmarks et des détails fournit par Intel et AMD. Selon certaines sources, dont les manuels d'optimisation d'Agner Fog, les processeurs AMD auraient moins de points de synchronisation que les processeurs Intel. De plus, leur ''stack engine'' serait placé plus loin que prévu dans le pipeline, après la file de micro-opération. ==La micro-fusion et la délamination== La '''micro-fusion''' est une optimisation qui retarde le décodage réel de certaines instructions assez loin dans le pipeline. Elle concerne surtout les instructions ''load-op'', mais pas que. D'autres instructions mémoire peuvent subir cette optimisation. L'essentiel est que, sans micro-fusion, ces instructions sont décodées en plusieurs micro-opérations. La micro-fusion retarde le décodage final de ces instructions, qui se fait assez tard dans le pipeline. Pour comprendre l'intérêt, nous allons devoir faire quelques explications. L'optimisation en question fait le décodage en deux temps. Prenons l'exemple d'une opération ''load-op'', qui est censée être décodée en deux micro-opérations : une lecture, puis une opération. Le décodage produit une '''macro-opération''' (terme d'Intel), qui est propagée dans le pipeline, pour être scindée en deux micro-opérations un peu avant les ALU et l'unité mémoire. La macro-opération est techniquement une micro-opération comme une autre, sauf que ce n'est pas la micro-opération finale. L'unité d'émission découpe cette macro-opération en deux micro-opérations, qui sont émises l'une après l'autre. Pour résumer, les instructions ''load-op'' ne sont complétement découpées en micro-opération lors de l'émission, pas lors du décodage. L'optimisation impacte ce qui se situe entre le décodeur d'instruction et l'unité d'émission : l'unité de renommage, la file de micro-opérations, le ''Loop Stream Detector'' et/ou le cache de micro-opération. L'intérêt de l'optimisation est que l'on fusionne deux micro-opérations en une seule macro-opération. Le cache de micro-opération et la file de micro-opération peuvent mémoriser plus de micro-opérations, vu que certaines sont fusionnées. Quant à l'unité de renommage, elle renomme une seule macro-opération au lieu de renommer deux micro-opérations, ce qui augmente le débit du renommage de registre. Par contre, cela complique un peu le travail de l'unité d'émission, qui doit découper les instructions ''load-op'' en deux et émettre les micro-opérations l'une après l'autre. Il faut noter qu'il n'y a pas de fusion proprement dite. Le décodeur ne décode pas deux micro-opérations séparées, avant de les fusionner. En réalité, il génère directement une macro-opération, qui correspond à deux micro-opérations, que ce soit plus tard dans le pipeline ou sur une autre architecture. D'ailleurs, la micro-fusion a lieu à l'intérieur d'une instruction, qui est censée être traduite en plusieurs micro-opérations. Et encore : pas toutes. La conséquence est que la technique n'a de sens que sur les processeurs CISC, avec des instructions assez complexes pour être décodées en plusieurs micro-opérations. En pratique, seuls les CPU x86 sont concernés. ===Les domaines de fusion=== La micro-fusion n'est pas spécifique aux processeurs superscalaires. En théorie, on peut l'implémenter sur un processeur non-superscalaire à émission dans l'ordre. Cependant, je ne connais aucun processeur à émission dans l'ordre qui implémente la micro-fusion, même si son implémentation est en théorie possible sur de tels processeurs. La micro-fusion est implémentée différemment selon que l'émission se fasse dans l'ordre, dans le désordre, avec une fenêtre d'instruction, avec des stations de réservation, etc. J'ai dit plus haut que les micro-opérations sont générées lors de l'émission, mais le moment exact varie suivant le processeur. Pour simplifier le tout, nous parlerons de '''scission''' quand le processeur traduit une macro-opération en deux/trois micro-opérations. Le moment où a lieu la scission est théoriquement dans l'unité d'émission, mais celle-ci prend plusieurs formes selon que le processeur utilise l'émission dans l'ordre, dans le désordre, avec une fenêtre d'instruction, avec des stations de réservation, etc. Les processeurs à exécution dans l'ordre sont le cas le plus simple. L'unité d'émission est alors en charge du découpage des macro-opérations en micro-opérations. La file de micro-opération ou le cache de micro-opérations mémorisent des macro-opérations. À l'opposé, le tampon de ré-ordonnancement mémorise lui des micro-opérations. Le reste du processeur n'est pas affecté. Sur les processeurs à exécution dans le désordre, les différences sont nombreuses. Le tampon de ré-ordonnancement peut mémoriser soit les micro-opérations finales, soit des macro-opérations. Il en est de même avec la fenêtre d'instruction et/ou les stations de réservation, qu'elles soient centralisées ou décentralisées. Tout dépend de comment se fait l'implémentation. Une implémentation simple effectue la scission des macro-opérations dans l'unité d'émission, comme sur les processeurs à exécution dans l'ordre. Sur de nombreux processeurs, l'unité d'émission et de renommage sont simplement fusionnées, ce qui fait que la scission a lieu juste après le renommage de registres. En conséquence, le tampon de re-ordonnancement et les fenêtres d'instruction ne voient que des micro-opérations. Les macro-opérations disparaissent juste avant. Cette implémentation est préférée avec une fenêtre d'instruction centralisée, car on voit mal comment scinder une macro-opération juste avant l'ALU. Une autre implémentation fait la scission en sortie de la fenêtre d'instruction ou des stations de réservation, qu'elles soient centralisées ou décentralisées. Dans ce cas, le tampon de re-ordonnancement fait de même. L'avantage est que le tampon de ré-ordonnancement stocke des macro-opérations, ce qui augmente sa taille effective. Par exemple, il utilise une seule entrée pour une instruction ''load-op'', au lieu de deux sans micro-fusion de ce type. ===La délamination=== La scission peut parfois avoir lieu plus tôt, dans des circonstances très précises. Concrètement, cela ne concerne que quelques micro-architectures d'Intel, pour des instructions très précises. La raison est les limitations du format des micro-opérations, pas une histoire d'optimisation. Le processeur aimerait pouvoir faire la micro-fusion, mais ne peut pas à cause de ces limitations. Une telle situation cause alors une '''délamination''' : les micro-opérations sont scindées précocement. Par exemple, sur la micro-architecture SandyBridge d'Intel, les opérations ''load-op'' sont fusionnées, sauf si elles utilisent l'adressage indicé. Les micro-opérations de ce processeur ne peuvent avoir que deux opérandes. Trois opérandes est de trop, et les opérations ''load-op'' en adressage indicé dépassent cette limite. Dans ce cas, les micro-opérations sont fusionnées en sortie du décodeur, mais sont scindés avant d’entrer dans la file de micro-opération. L'avantage n'est pas évident, vu que l'unité de renommage suit de près le décodeur d'instruction. Il est que le cache de micro-opérations mémorise des macro-opérations, pas deux micro-opérations. ===La micro-fusion des processeurs Intel et AMD=== La micro-fusion est apparue sur le Pentium M d'Intel, et a été conservée telle quelle sur les processeurs Intel suivants. Les processeurs AMD supportent la micro-fusion depuis au moins la micro-architecture AMD K8. Mieux que ça, la délamination n'était pas utilisée car les micro-opérations acceptaient plus de 2 opérandes. Que ce soit chez AMD ou Intel, elle concerne deux types d'instructions : les écritures mémoire et les instructions ''load-op''. Sur le Pentium M, il y avait quelques limitations, l'optimisation se limitant par exemple aux registres entiers et flottants, mais pas aux registres MMX, mais pas les registres SSE (nous verrons ces registres dans quelques chapitres). Mais les processeurs modernes n'ont plus cette limitation. La micro-fusion des CPU Intel concerne deux types d'instructions : les écritures mémoire et les instructions ''load-op''. Pour les écritures, la situation est plus complexe que pour les instructions ''load-op''. Sur les processeurs Intel précédents, les écritures étaient réalisées dans deux unités séparées : le calcul d'adresse dans une unité de calcul, l'écriture proprement dite dans l'unité mémoire. Elles prenaient donc deux micro-opérations. Le processeur a changé ses unités mémoire, ce qui fait qu'elle pouvait faire les deux en une seule micro-opération. Il s'agissait alors d'une optimisation du chemin de données, plus que de la micro-fusion proprement dite, mais je la mentionne ici malgré tout. La micro-fusion sur ce processeur avait un avantage en plus des avantages usuels : elle utilisait mieux les décodeurs. Les Pentium M avaient trois décodeurs pour décoder plusieurs instructions en même temps, chose qu'on détaillera dans le chapitre sur les processeurs superscalaires. Un seul décodeur pouvait décoder toutes les instructions, les deux autres ne peuvent décoder que les instructions simples, qui se décodent en une seule micro-opération. Avec la micro-fusion, les trois décodeurs peuvent gérer les écritures mémoire et les opérations ''load-op'', vu qu'elles deviennent des instructions simples. Sans cela, elles auraient été limitées au premier décodeur. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Le parallélisme mémoire | prevText=Le parallélisme mémoire | next=Les microarchitectures pour le x86 : haute performance | nextText=Les microarchitectures pour le x86 : haute performance }} </noinclude> dk2ngu78suyubl57d0aqm4aolxa8nql 773582 773581 2026-09-29T16:51:10Z Mewtow 31375 /* L'exemple du PA-RISC PA 8000 */ 773582 wikitext text/x-wiki Les processeurs vus auparavant ne peuvent émettre au maximum qu'une instruction par cycle d'horloge. Ils peuvent avoir plusieurs instructions qui s'exécutent en même temps, dans des unités de calcul séparées. C'est le cas dès qu'une instruction multi-cycles s'exécute. Par contre, ils ne peuvent démarrer qu'une seule instruction par cycle. Et quand on court après la performance, ce n'est pas assez ! Les concepteurs de processeurs ont inventés des processeurs qui émettent plusieurs instructions par cycle : les '''processeurs à émissions multiples'''. Un processeur à émission multiple charge plusieurs instructions en même temps, les décode en parallèle, puis les émet en même temps sur des unités de calculs séparées. Pour cela, il faut gérer les dépendances entre instructions, répartir les instructions sur différentes unités de calcul, et cela n'est pas une mince affaire. En général, pour un processeur à émission multiple capable d'émettre N instructions en parallèle, on parle de '''processeur à N voies''', ou encore un ''processeur à N pipelines''. [[File:Superscalarpipeline.svg|centre|vignette|upright=1.5|Pipeline RISC classique à cinq étages sur un processeur superscalaire. On voit bien que plusieurs instructions sont chargées en même temps.]] Les processeurs à émission multiple sont de deux types : les processeurs VLIW et les '''processeurs superscalaires'''. Nous mettons les processeurs VLIW de côté en attendant le prochain chapitre. La raison est qu'ils ont un jeu d'instruction spécialisé qui expose le parallélisme d'instruction directement au niveau du jeu d'instructions, là où les processeurs superscalaires restent des processeurs au jeu d'instruction normal. La différence principale entre processeur VLIW et superscalaire est qu'un processeur superscalaire répartit les instructions sur les unités de calcul à l’exécution, là où un processeur VLIW délègue cette tâche au compilateur. ==Le nombre de voies d'un processeur superscalaire== Les processeurs superscalaires les plus simples ne permettent que d'émettre deux micro-opérations à la fois, d'où leur nom de processeur ''dual issue'', ce qui se traduit en '''processeur à double émission'''. Les processeurs triple émission permettent eux d’émettre trois instructions à la fois. A l'opposé, les CPU superscalaires les plus puissants peuvent émettre jusqu'à 8-10 instructions simultanément. En 2026, les CPU superscalaires peuvent monter jusqu’à 10 µops émises en même temps, ce qui est énorme ! Et cela nous amène à faire une distinction entre les processeurs superscalaires dits '''étroits''' et ceux dits '''larges'''. Dans ce wikilivre, on part du principe que les processeurs superscalaires étroits émettent jusqu'à 4-5 µops à la fois, alors que les larges peuvent en émettre plus, l'intervalle entre les deux est une zone grise. Le nombre exact n'est pas fixé dans le marbre, la distinction est volontairement vague. Nous parlerons de la '''largeur d'un CPU superscalaire''' pour parler du nombre de voies, du nombre de µops émises en même temps. Plus un CPU superscalaire est large, plus il est performant ''toute chose égale par ailleurs''. Mais dans les faits, vous pouvez oublier la partie en italique. Élargir un CPU superscalaire demande de rajouter beaucoup de circuits. Et ce cout en circuit aura un impact sur la performance. A budget en transistors limité, il y a un compromis entre élargir un CPU et rajouter du cache ou la taille des fenêtres d'instructions/ROB et autres. ===Les contraintes d’appariement=== Prenons un processeur double émission, capable d'émettre deux instructions simultanément. Émettre deux instructions en même temps n'est pas toujours possible. Par exemple, si deux instructions sont dépendantes, on ne peut pas les émettre en même temps. Mais oublions un instant ces histoires de dépendances de données, et partons du principe que le CPU ait affaire à deux instructions indépendantes, une paire idéale. Un CPU double émission "parfait" pourrait exécuter n'importe quelle paire d'instruction. Par exemple, il pourrait émettre deux multiplications consécutives, deux lectures consécutives, une lecture et une écriture en même temps, etc. En pratique, aucun processeur ne permet cela. Implémenter un CPU superscalaire "parfait" aurait un cout en circuit beaucoup trop conséquent. Par exemple, pour émettre deux multiplications en même temps, il faudrait deux multiplieurs séparés. Idem pour exécuter deux accès mémoire simultané : cela demande d'avoir deux unités mémoire et un cache multiport. Mais en pratique, aucun CPU superscalaire ne fait cela. La totalité des CPU double émission se débrouille avec un seul circuit multiplieur et une seule unité mémoire. Et cela entraine l'apparition de dépendances structurelles, qui font que certaines paires d'instructions sont impossibles. Par exemple, impossible d'émettre deux multiplications en même temps avec un seul circuit multiplieur. Mais émettre une multiplication en parallèle d'une addition est parfaitement possible. Il y a donc des paires d'instructions autorisées et des paires interdites. Et la logique est la même sur les CPU à triple ou quadruple émission, et au-delà. : des triplets ou quadruplet d'instructions sont impossibles à émettre simultanément, alors que d'autres le sont. Pour le dire autrement, il y a des '''contraintes d'appariement''' sur les instructions à émettre en même temps. ===L'impact des contraintes d’appariement sur la performance=== Ces contraintes d’appariement ont un impact sur les performance, mais celui-ci peut être grandement mitigé. Les programmes informatiques utilisent en pratique beaucoup plus d'opérations entières de base que de multiplication, branchements et accès mémoire. Il y a environ 5 opérations entières de base pour une multiplication entière. En pratique, il est rare de devoir exécuter deux multiplications à la fois. Idem pour les décalages et rotations, qui sont assez éloignés les uns des autres. Deux branchements consécutifs sont quant à eux plus fréquents. Deux accès mémoire consécutifs est assez rare, mais ils restent assez proches les uns des autres malgré tout. La conséquence est que certaines paires d'instructions sont privilégiées par rapport au reste. Les paires regroupant deux calculs basiques (additions, soustractions, ...) sont systématiquement supportées, car dupliquer des ALU entières est facile. Les paires regroupant un calcul et une autre instruction sont elles aussi systématiquement supportées. Par contre, les paires avec deux branchements, deux accès mémoire, deux décalages/rotations, ou deux multiplications/divisions sont fréquemment interdites. Seuls les CPU superscalaires larges peuvent les permettre, et encore : sous conditions. Le résultat est que le processeur peut se débrouiller avec une seule unité mémoire et une unité de branchement. ===Terminologie pour la suite du chapitre=== Décrire les contraintes d’appariement demande de dire quelles combinaisons d’instructions sont autorisées ou interdites. Et pour cela, nous allons introduire les abréviations suivantes : * INT est un raccourcis pour parler d'une opération entière simple, qu'une ALU entière peut exécuter. * MUL correspond à une opération entière complexe, typiquement une multiplication, éventuellement à une division. * FLOAT désigne une opération flottante, peut importe laquelle. * MEM désigne un accès mémoire, à savoir une instruction ou µop mémoire. * BRANCH désigne une instruction de branchement. Cette terminologie permettra de définir des paires d'instructions, qu'elles soient possibles ou interdites. Par exemple, l'expression INT + FLOAT désigne une paire d'instruction regroupant une instruction entière et une instruction flottante, peu importe l'ordre des deux instructions. Il en sera de même pour les triplets, quadruplets, ou plus. Par exemple, l'expression INT + INT + FLOAT + MUL désigne un quadruplet d'instructions regroupant : deux instructions entières, une instruction flottante, et une multiplication entière. J'utiliserais aussi des parenthèses pour regrouper certaines combinaisons. Par exemple, l'expression INT + (MUL /FLOAT) veut parler d'une paire d'instruction où la première est une opération entière basique, la seconde est : soit une multiplication, soit une opération flottante. ==Le ''front-end'' des processeurs superscalaires== Un processeur superscalaire doit charger, décoder, et exécuter plusieurs instructions par cycle. Par exemple, un processeur triple émission doit charger 3 instructions lors d'un premier cycle, puis les décoder au cycle suivant, et les exécuter au cycle suivant. Il travaille donc pas paquets de 3 instructions, dans cet exemple. Intuitivement, charger, décoder et exécuter plusieurs instructions à la fois demande de dupliquer des circuits. Par exemple, il faut dupliquer les décodeurs pour décoder plusieurs instructions. Les unités de calcul sont aussi dupliquées, sauf sur certaines processeurs qui arrivent à ruser, mais laissons cela de côté pour plus tard. Mais d'autres circuits sont simplement modifiés, comme l'unité de chargement ou l'unité d'émission. Voyons ce qu'il en est dans le détail. {|class="wikitable" |- ! rowspan="2" | Processeur sans émission multiple | rowspan="2" | Chargement | rowspan="2" | Décodage | rowspan="2" | Renommage | rowspan="2" | Émission | Exécution / ALU | rowspan="2" | ''Commit''/ROB |- | Exécution / ALU |- ! rowspan="4" | Processeur superscalaire | rowspan="4" | Chargement | rowspan="2" | Décodage | rowspan="4" | Renommage | rowspan="4" | Émission | Exécution / ALU | rowspan="4" | ''Commit''/ROB |- | Exécution / ALU |- | rowspan="2" | Décodage | Exécution / ALU |- | Exécution / ALU |} Nous allons d'abord voir ce qu'il en est pour le ''front-end'', à savoir la partie du CPU qui s'occupe de charger et décoder les instructions. Elle regroupe l'unité de chargement, les décodeurs, l'unité de prédiction de branchement, la file de µops, la file d'instruction, et divers caches. En soi, les changements portent surtout sur l'unité de chargement et les décodeurs. ===Le chargement de plusieurs instructions consécutives=== Un processeur superscalaire charge plusieurs instructions en même temps, ''en tenant compte de la présence de branchements''. La partie en italique est importante et elle a une conséquence très forte : la manière de faire est fortement différente entre un CPU superscalaire étroit et large. Un CPU superscalaire étroit fait au plus simple : il charge un bloc de 2, 3, 4 instructions consécutives en mémoire RAM. Il faut alors doubler/tripler/quadrupler la taille du bus connecté au cache d'instruction. Par exemple, pour charger quatre instructions de 32 bits chacune, il suffit de lire un bloc de 128 bits dans le cache d'instruction. Un bloc de 8, 16, 32 octets est donc lu depuis le cache et est ensuite découpé en instructions, envoyées chacun à un décodeur. Charger plusieurs instructions consécutives ne marche bien qu'en absence de branchements. La présence de branchements casse cette dynamique, et il faut gérer leur présence. * Sans prédiction de branchement, toutes les instructions d'un bloc sont décodées et exécutées en même temps, même s'il y a un branchement dans le tas. * Avec prédiction de branchement, les instructions situées après le branchement ne sont pas décodées ni exécutées. L'unité de chargement coupe le bloc chargé au niveau du premier branchement pris, remplit les vides avec des NOP, avant d'envoyer le tout à l'unité de décodage. Les instructions à l'adresse de destination seront chargées au cycle suivant, en chargeant un nouveau bloc. [[File:Fetch sur un processeur superscalaire avec prediction de branchements.png|centre|vignette|upright=2|Fetch sur un processeur superscalaire avec prédiction de branchements.]] Un autre défaut est que sur le CPU charge un bloc de 128 bits à la fois, les instructions doivent être alignées sur 128 bits. Et on peut généraliser à n'importe quelle taille de bloc. Si les instructions ne sont pas alignées, il faut gérer la situation. Il arrive qu'une instruction soit à cheval sur deux blocs, avec un morceau dans le premier bloc, un autre dans le second. Dans ce cas, l'instruction est chargée en deux fois, et des circuits doivent gérer la situation pour recoller les morceaux. Sur les CPU avec des instructions de taille fixe, le problème ne survient que rarement. Mais il est fréquent avec des instructions de taille variable. Un autre défaut est lié aux branchements. Imaginez qu'un branchement s'exécute et branche vers une instruction de destination. Rien n'indique que l'instruction de destination sera au tout début d'un bloc. Si ça se trouve, elle sera en troisième position d'un bloc de 4 instructions. Une solution simple charge le bloc en respectant l'alignement, et les deux premières instructions du bloc ne sont pas à exécuter. Il y a donc une petite perte de performance. Certains CPU, comme l'IBM RS/6000, ont la machinerie charger un bloc de N instructions même s'il n'est pas aligné. La machinerie en question se trouve dans le cache d'instruction et est tout sauf simple à expliquer,ce qui fait que je me permets de la passer sous silence. Un détail, cependant : elle ne permet pas de charger des blocs qui sont à cheval sur deux lignes de cache. ===Le décodage parallèle des instructions=== Pour le décodage des instructions, plusieurs instructions sont décodées en même temps. On parle alors de '''décodage parallèle'''. Pour ce faire, un processeur superscalaire contient plusieurs décodeurs, chacun pouvant décoder une instruction en parallèle des autres. Prenons par exemple un processeur superscalaire à 4 voies : le décodage se fera dans quatre décodeurs séparés, qui fonctionneront en parallèle. Cependant, cette implémentation ne marche bien que pour les processeurs RISC, les processeurs CISC devant faire avec un microcode gourmand en circuits. Les processeurs CISC utilisent des décodeurs hybrides, avec un microcode qui complémente un décodeur câblé. Dupliquer le microcode aurait un cout en transistors trop important, ce qui fait que seuls les décodeurs câblés sont dupliqués. Les CPU CISC superscalaires disposent donc de plusieurs décodeurs simples, capables de décoder les instructions les plus courantes, avec un seul microcode. La conséquence est qu'il n'est pas possible de décoder deux instructions microcodées en même temps. Par contre, il reste possible de décoder plusieurs instructions non-microcodées ou une instruction microcodée couplée à une instruction non-microcodée. Vu qu'il est rare que deux instructions microcodées se suivent dans un programme, le cout en performance est extrêmement mineur. Il faut noter qu'une instruction correspond à une ou plusieurs µops. Il est donc possible de charger 5 instructions et de se retrouver avec 8 µops en sortie des décodeurs. Et c'est la source d'une distinction très importante. Plus haut, j'ai parlé de processeurs superscalaires à N voies. La terminologie peut avoir deux interprétations. La première est que le processeur charge/décode N instructions à la fois. Une seconde est qu'il est capable d'exécuter/émettre N µops en même temps. Les deux ne sont pas équivalentes, vu qu'un processeur superscalaire peut, par exemple, charger/décoder N instructions et émettre/exécuter N+2 µops. La distinction est particulièrement importante sur les processeurs superscalaires larges. Certains d'entre eux sont capables de charger 5 instructions et d'en émettre le double ! Un exemple classique était les processeurs Athlon d'AMD, qui pouvaient décoder deux instructions par cycle, mais émettre 4 µops par cycle. Ce n'était pas un problème, car beaucoup d'instructions, même basiques, étaient décodées en 2 µops. ===L'émission parallèle des instructions=== La superscalarité modifie en profondeur l'unité d'émission, notamment au niveau de son interface. Avant, elle recevait une micro-opération sur son entrée, et fournissait la micro-opération émise sur une sortie. Et cela vaut aussi bien pour une unité d'émission simple, un ''scoreboard'', une fenêtre d'instruction ou des stations de réservation. Mais avec l'émission multiple, les sorties et entrées sont dupliquées. Pour la double émission, il y a deux entrées vu qu'elle doit recevoir deux micro-opération décodées/renommées, et deux sorties pour émettre deux micro-opérations. Dans ce qui suit, nous ne parlerons pas d'entrée et de sortie, mais de '''ports de décodage''' et de '''ports d'émission'''. Les ports de décodage reçoivent des micro-opérations provenant de l'unité de décodage, les ports d'émissions sont pour les micro-opérations émises. Les ports d'émission injectent les micro-opérations émises dans le pipeline, elle sont propagée au banc de registre, aux ALUs, etc. Un processeur superscalaire a forcément plusieurs ports d'émission (et de décodage). Si l'interface de l'unité d'émission change, l'intérieur est tout autant modifié. Sur un CPU non-superscalaire, l'unité d'émission reçoit une µop "candidate à l'émission", et détecte les dépendances entre avec les µops en vol, en cours d'exécution dans le pipeline. Et c'est toujours le cas sur les processeurs superscalaires : l'unité d'émission détecte les dépendances entre les µops candidates et les µops en vol. Mais avec la siperscalarité, elle doit en plus tester les dépendances entre les µops candidates. Si l'unité d'émission est un ''scoreboard'', il doit détecter les dépendances entre instructions émises simultanément et les sérialiser si besoin. Avec une fenêtre d'instruction, il n'y a pour ainsi dire rien à faire, vu que les dépendances sont éliminées par le renommage de registre et que les signaux de réveil gèrent les dépendances RAW. C'est la raison pour laquelle les processeurs superscalaires modernes n'utilisent pas de ''scoreboard''. ==Les processeurs implémentés avec plusieurs pipelines== Nous venons de voir comment la superscalarité impacte le ''front-end'', il est maintenant de voir ce qu'il en est de l'unité d'émission et des ''back-ends''. Un processeur superscalaire peut utiliser l'exécution dans le désordre et le renommage de registres, mais ce n'est pas une obligation. Historiquement, les premiers processeurs superscalaires n'utilisaient pas d'exécution dans le désordre. Le meilleur exemple est celui du Pentium 1 et 2 d'Intel. Ils étaient tous deux des processeurs superscalaires, mais n'avaient pas d'exécution dans le désordre, qui est apparue sur le Pentium 3. les explications sont plus simples si on met de côté l'exécution dans le désordre. Vous vous dites que l'implémentation d'un processeur superscalaire n'est pas la même suivant que le CPU utilise l'exécution dans le désordre, ou non. Mais dans les faits, la distinction est plus subtile que ca. Pour l'expliquer, je vais utiliser une classification originale, qui sépare les processeurs superscalaires en trois sous-types. La distinction se fait sur la manière dont la superscalarité est implémentée en matériel.La classification que j'utilise distingue : * Les processeurs avec plusieurs pipelines, sans exécution dans le désordre. * Les processeurs superscalaires avec un pipeline dynamique. * Les processeurs avec des fenêtres d'instruction décentralisées. La distinction n'est pas qu'une question d'implémentation matérielle. Elle impacte aussi le ratio entre instructions chargées/décodées et instructions émises. Vous vous dites que les deux sont égales, mais ce n'est le cas que sur les processeurs avec N pipelines ! Sur les autres processeurs, il est possible de décoder 4 instructions, mais d'en émettre maximum 6 par cycle ! Et sur les CPU avec des fenêtres d'instruction décentralisées, il y a aussi une différence entre le nombre d'instructions qui sont ''dispatch'' et ''schedule''. La catégorie la plus simple est celle des '''processeurs avec plusieurs pipelines'''. Ce sont des processeurs superscalaires sans exécution dans le désordre. Ils partent d'un processeur non-superscalaire, et ajoutent un second pipeline, en sortie de l'unité d'émission. Le second pipeline permet l'émission parallèle d'une seconde instruction. Le second pipeline n'est pas identique au pipeline originel, sur plusieurs points. Premièrement, il n'a pas exactement les mêmes circuits. Le second pipeline est généralement composé d'une unité de calcul, d'une FPU, éventuellement d'un second banc de registres, guère plus. Il permet d'exécuter une seconde opération de calcul, pas plus, ce qui est à l'origine de contraintes d'appariemment assez fortes. De plus, il n'a pas forcément la même longueur, il peut avoir des étages en moins ou en plus. Il s'agit de la forme la plus simple de processeur superscalaire et nous allons leur consacrer cette section. ===La double émission entière-flottante=== L'exemple le plus simple utilise un second pipeline pour les opérations flottantes, séparé du pipeline originel. L'ajout d'un pipeline flottant permet d'émettre une micro-opération entière en même temps qu'une micro-opération flottante, ce qui s'appelle la '''double émission entière-flottante'''. La micro-opération entière s'exécute dans l'ALU entière, la micro-opération flottante dans la FPU. Les exemples les plus notables sont le PA-RISC 7100, le POWER 1 (RIOS .& et .9) et le PowerPC 601. L'Apollo DN10000 et l'Intel i860 utilisaient aussi cette forme de double émission, mais étaient des prototypes de CPU VLIW. [[File:Double émission entière-flottante.png|centre|vignette|upright=2|Double émission entière-flottante]] Pour bien expliquer les choses, prenons le processeur illustré ci-dessous, avec deux ''back-end'' séparés : un pour la FPU, et un autre pour le reste. Les instructions entières et mémoire passent toutes par le ''back-end'' généraliste. [[File:CPU non-superscalaire basique, avec une FPU.png|centre|vignette|upright=1.5|CPU non-superscalaire basique, avec une FPU]] Les deux ''back-end'' sont des pipelines séparés, mais il faut que l'unité d'émission soit spécialement conçue pour en profiter. Un processeur simple émission peut démarrer une seule µop par cycle : soit la µop est envoyée au ''back-end'' flottant, soit elle est envoyée au ''back-end'' général. Avec la double émission entière-flottante, le processeur peut envoyer une µop dans chaque pipeline, à chaque cycle. Vu que la FPU et son banc de registre forment déjà un pipeline séparé, les seules modifications se font au niveau du ''front-end'', unité d'émission inclue. {| |- |[[File:CPU simple émission avec une FPU.png|centre|vignette|upright=1.5|CPU simple émission avec une FPU.]] |[[File:Double émission entière flottante avec un second pipeline.png|centre|vignette|upright=1.5|CPU avec un second pipeline flottant.]] |} Notez que le terme double émission ''entière''-flottante est un peu trompeur. En réalité, la technique permet d'émettre une instruction flottante avec n'importe quelle autre instruction non-flottante, avec des restrictions pour les branchements. Il est par exemple possible d'exécuter un calcul flottant en parallèle d'un accès mémoire. Sur les CPU 32 bits, il est possible de faire les multiplications dans la FPU. Pour rappel, la FPU contient un multiplieur entier 53-54 bits, pour multiplier les mantisses de deux flottants 64 bits, qu'on peut utiliser pour faire les multiplications entières 32 bits. Cela permet d'émettre une multiplication en même temps qu'une opération entière dans l'ALU. Ainsi, le CPU pouvait émettre deux instructions : une opération entière de base, avec soit une multiplication, soit une opération flottante. En clair, une émission de type INT + (MUL /FLOAT). Par contre, on perd la possibilité d'émettre une multiplication entière avec une opération flottante, mais c'était un compromis qui en valait la peine. Le CPU PA-RISC 7100 implémentait cette optimisation. Il s'agissait d'un CPU double émission entière-flottante, qui utilisait donc un partitionnement assez simple. Le combo partitionnement + reconditionnement permettait ici de gagner en performance, pour un cout en matériel très limité. D’autant plus limité que le jeu d'instruction prévoyait le reconditionnement de la FPU. Les multiplications ne lisaient pas leurs opérandes dans les registres entiers, mais dans les registres flottants. ===La double émission entière=== Une autre possibilité ajoute un second pipeline, capable d'exécuter des opérations entières simples, appelé le pipeline entier. Le processeur supporte alors la '''double émission entière''', à savoir qu'ils peuvent émettre une opération entière en plus d'une autre instruction. L'opération entière en question est une opération simple, comme une addition, une soustraction, une opération bit à bit, une comparaison, etc. Les exemples classiques sont les processeurs Intel i960 et Pentium. L'implémentation était différente entre l'i960 et le Pentium : Le Pentium avait une seconde ALU entière, alors que le i960 rusait. Le Pentium dupliquait l'ALU entière, pour créer un second pipeline entier. Sur le Pentium originel, les contraintes d'appariement étaient assez strictes. Le Pentium avait une FPU, mais ne pouvait pas l'utiliser en double émission. Il lui était impossible d'exécuter une opération flottante en même temps qu'une opération entière (branchements inclus). Le Cyrix 6x86 était une sorte de Pentium produit par l'entreprise Cyrix, avec une microarchitecture différente. Il avait des contraintes d’appariement réduites. Par exemple, il pouvait émettre une opération flottante en parallèle d'une opération entière. Nous détaillerons ces processeurs dans le prochain chapitre, qui porte justement sur les CPU superscalaires x86. [[File:CPU simple et double émission avec un second pipeline entier.png|centre|vignette|upright=2.5|CPU simple et double émission avec un second pipeline entier.]] L'Intel i960 n'avait pas de FPU, juste une ALU entière et une unité mémoire. Il utilisait l'unité mémoire comme une seconde ALU entière limitée. Pour rappel, une unité mémoire contient une AGU, à savoir une ALU spécialisée dans les calculs d'adresse. Elle est capable de faire des additions, soustractions, et quelques décalages limités (des décalages par 2, 4, 8, pas plus). L'Intel i960 ajoutait des connexions entre AGU et banc de registre, afin que celle-ci serve de seconde unité de calcul. L'AGU est déjà reliée aux deux ports de lecture, pour lire les opérandes du calcul d'adresse, il suffit de la connecter sur le port d'écriture. Le processeur peut alors émettre deux instructions/µops entières, sous certaines conditions. [[File:Emission multiple des opérations entières, double émission.png|centre|vignette|upright=2|Émission multiple des opérations entières, double émission.]] ==Les processeurs superscalaires dynamiques== Les processeurs précédents, avec 2 pipelines, avaient une unité d'émission assez simple. Elle avait deux ports de décodage, et deux ports d'émission. Le nombre de ports de décodage et d'émission étaient identiques. Vous vous dites que c'est naturel, et intuitif, que c'est normal pour un processeur superscalaire. Mais en réalité, la majorité des processeurs superscalaires a plus de ports d'émission que de décodage. Expliquer pourquoi va cependant nous demander de parler de comment la superscalarité exploite les unités de calcul. Posons-nous cette question : de combien d'unités un processeur superscalaire a besoin ? Les unités en question ne sont nécessairement des unité de calcul, l'unité mémoire et l'unité de branchement comptent aussi. La réponse dépend du nombre de voies. Si le ''front-end'' charge et décode un paquet de N instructions, exécuter ces N instructions simultanément demandera là aussi au moins N unités de calcul. Notez le terme : ''au moins'', car c'est là tout l'enjeu de cette section. La réponse dépend aussi des contraintes d’appariement. Pour un CPU superscalaire "parfait", sans contraintes d’appariement, toutes les unités doivent être dupliquées, y compris l'unité mémoire. Un processeur à double émission parfaite devrait dupliquer l'ALU entière, le ''barrel shifter'', le circuit multiplieur, la FPU, l'unité mémoire, et l'unité de branchement, ce qui ferait passer de 6 unités à 12. Le cout en circuit est énorme, même pour de la double émission ! Et pour un CPU à N pipelines, le cout en circuit encore plus prohibitif ! En pratique, les processeurs superscalaires qui font ça sont très rares. La majeure partie des processeurs superscalaires utilisent d'autres techniques : le partitionnement, la duplication partielle des ALUs, la duplication des autres unités. ===Le partitionnement des unités fonctionnelles=== Les CPU superscalaires les plus simples ne dupliquent pas leurs unités de calcul, ils se contentent d'exploiter les unités existantes. Et pour expliquer comment, nous allons partir de l'exemple d'un processeur non-superscalaire contient une ALU entière, une FPU, une unité mémoire et une unité de branchement. Les quatre unités peuvent fonctionner en parallèle, à savoir qu'une unité peut exécuter une instruction à elle toute seule, sans interagir avec les autres. Cela suffit pour créer un processeur quadruple émission, qui peut émettre en même temps : une opération entière, une opération flottante, un branchement, un accès mémoire. Le principe marche aussi sur un processeur avec moins de 4 unités, par exemple sans FPU et/ou sans unité de branchement, ou avec au contraire des unités en plus. L'idée générale est d’émettre une µops séparée dans chaque unité fonctionnelle. Utiliser ainsi les unités existantes, pour rendre un CPU superscalaire, s'appelle le '''partitionnement superscalaire'''. Le terme n'est pas beaucoup utilisé en-dehors de quelques vieux articles académiques. Le partitionnement est fortement dépendant du jeu d'instruction, car il demande de bien séparer instructions entières, flottantes, branchements et instructions mémoire. Et autant c'est bien le cas sur les CPU RISC, autant les CPU CISC ne sont pas dans ce cas. Les CPU CISC ont des instructions ''load-op'', qui effectuent une instruction arithmétique et une µop mémoire. Et ces instructions sont très compliquées à implémenter avec le partitionnement. Et au-delà de ça, les CPU CISC ont beaucoup d'instructions qui sont décodées en plusieurs µops, à exécuter dans un ordre bien précis. On peut pas émettre les µops en question simultanément. Le partitionnement a un cout en circuit très limité, pour un gain en performance lui aussi limité. Pour reprendre le CPU de l'exemple précédent, il est rare que l'on ait à exécuter ces quatre instructions en même temps. En pratique, les combinaisons fréquentes sont les combinaisons calcul + accès mémoire, calcul + branchement, calcul entier + calcul flottant. Utiliser une quadruple émission de ce type n'est donc pas une bonne idée, alors que la double émission parait plus adaptée. Et c'est là que la différence entre ports d'émission et de décodage devient intéressante. L'idée est d'avoir une unité d'émission avec deux ports de décodage, et 4 port d'émission (un par unité). Les contraintes d’appariement varient alors suivant le processeur, mais la règle générale est que si deux micro-opérations tombent dans deux unités différentes, on peut les émettre en même temps. En clair, on peut émettre une opération entière avec une opération flottante, une opération entière avec un branchement, un accès mémoire avec un branchement, etc. Et cela rend le partitionnement bien plus intéressant que prévu. Les tout premiers CPU superscalaires étaient des CPU double émission, qui utilisaient le partitionnement avec : une ALU entière, une unité mémoire et une FPU. Nous parlerons de '''partitionnement INT-FLOAT-MEM'''. L'avantage sur la double émission flottante est que les combinaisons INT + MEM et FLOAT + MEM étaient autorisées. L'intérêt était d'émettre une opération en parallèle d'un accès mémoire, ce qui est un doublet d'instruction assez fréquent. Les exemples classiques sont l'HyperSPARC, de l'alpha 21064 et du PowerPC 603. Les contraintes d’appariement variaient grandement suivant le processeur. Le PowerPC 603 implémentait une double émission "parfaite". C'est à dire que toutes les combinaisons possibles à deux instructions étaient possibles, que ce soit INT + FLOAT, INT + MEM, FLOAT + MEM. En plus de cette double émission "parfaite", le CPU utilisait la technique dite de ''branch folding'', qui permettait d'exécuter un branchement sans utiliser d'unité de calcul, ce qui fait qu'il était qualifié de ''CPU 2-way + Branch''. A l'opposé, le processeur alpha 21064 avait pas mal de contraintes d’appariement, à savoir que certaines combinaisons de deux instructions étaient interdites, bien que compatibles avec les unités disponibles. Une des raisons est que le banc de registre n'avait pas assez de ports de lectures, ce qui fait que certaines combinaisons avec une écriture mémoire n'étaient pas permises. Les concepteurs avaient volontairement inséré ces contraintes afin de simplifier le design du processeur. Avant de poursuivre, précisons que la FPU regroupe un additionneur flottant et un multiplieur flottant. Et ce fait peut être exploité pour approfondir le partitionnement. La '''double émission FADD/FMUL''' permet d'émettre une addition flottante en même temps qu'une multiplication flottante. Elle a été utilisée sur les processeurs x86, Alpha et SPARC. Les autres circuits de calcul flottant sont souvent regroupés avec l'additionneur. La division est parfois e même port que le multiplieur flottant, parfois sur celui de l'additionneur (quand elle est microcodée et exécutée en enchainant les soustractions). ===La duplication des ALU entières=== Le partitionnement est une technique élégante, simple, facile à implémenter et au cout en circuits modeste. Mais il faut avouer que cela ne donne pas des CPU superscalaires très efficaces. La raison est que le partitionnement permet d'émettre des paires, triplets, quadruplets de micro-opérations qui sont rares en pratique. Les combinaisons les plus fréquentes en pratique sont des paires/triplets d'opérations entières, souvent des paires/triplets d'additions ou d'opérations entières simples. Il est donc primordial d'émettre plusieurs opérations entières simultanément. Le fait d'émettre et d'exécuter plusieurs opérations entières en même temps s'appelle l''''émission entière multiple'''. Pour exécuter la seconde/troisième opération entière, il faut dupliquer les ALU entières (ou réutiliser l'AGU comme ALU entière comme le fait l'Intel i960). Le processeur doit avoir deux ALU entières pour de la double émission entière, trois pour de triple émission entière, etc. De plus, il faut ajouter des ports au banc de registre, pour lire deux fois plus d'opérandes et décrire deux résultats. Et enfin, il faut rajouter un port d'émission pour pouvoir émettre une micro-opération entière en plus. [[File:Processeur non-superscalaire basique 03.png|centre|vignette|upright=2|Processeur non-superscalaire basique]] La tendance est de multiplier les ALU entières, mais pas le circuit multiplieur. Le cout en transistors est alors grandement réduit, au prix de l'apparition de dépendances structurelles. Le CPU peut émettre deux additions en même temps, ou une addition et une multiplication, mais pas deux multiplications. Il en est de même avec le ''barrel shifter'', qui n'est pas dupliqué. Il est donc possible d'émettre un décalage avec une opération de base, mais pas deux décalages en parallèle. Mais ces contraintes d’appariement ne sont pas un problème, car il est rare de devoir émettre deux multiplications/décalages en même temps. La plupart des programmes sont majoritairement remplis d'additions, avec des multiplications assez rares et des décalages qui le sont encore plus. La moyenne est proche d'une multiplication pour 4/5 additions. Vu que des multiplications consécutives sont très rares, dupliquer le multiplieur est presque inutile. Disposer de plusieurs circuits multiplieurs ou de plusieurs ''barrel shifters'' serait donc un cout en circuits qui ne servirait que rarement et n'en vaut pas la chandelle. Il faut noter que sur les CPU 32 bits, les multiplications peuvent être exécutées dans la FPU ou dans un multiplieur séparé, tout dépend de si le CPU exécute les multiplications dans la FPU ou pas. {|class="wikitable" |- ! Voie d'émission n°1 !! Voie d'émission n°2 !! Voie d'émission n°3 |- | ALU entière || ALU entière || FPU |} Reste à connecter les unités de calcul à l'unité d'émission (indirectement, car il y a des étages de pipeline entre les deux). Une implémentation basique utilisée un port d'émission par unité. Prenons l'exemple d'un CPU superscalaire avec 4 ALU entières, une FPU, et une unité mémoire. Vu qu'il y a 6 unités, cela fait donc 6 ports d'émission. L'exemple historique le plus impressionnant est celui du Motorola 88110, un CPU double émission qui possède 10 unités. Il contient deux ALU entières, un circuit multiplieur, un circuit diviseur, une unité de manipulation de bits, une unité mémoire, un additionneur flottant, et deux unités graphiques pour des calculs impliquant des pixels. Le multiplieur est utilisé à la fois pour les multiplications entières, flottantes et le produit de deux pixels. Idem pour le diviseur, qui sert pour les divisions entières et flottantes. Et chaque unité a son propre port d'émission. La conséquence est que les contraintes d'appariement du Motorola 88110 sont simples : tant que deux µops atterrissent dans des unités séparées, la paire est permise. Il est par exemple possible d'émettre simultanément deux opérations entières simples, vu qu'il y a deux ALU. Par contre, impossible d'émettre simultanément deux multiplications, deux divisions, deux opérations flottantes, deux manipulations de bit, deux accès mémoire, etc. De plus, le partage du multiplieur fait qu'on ne peut pas émettre une multiplication entière avec une multiplication flottante. Idem avec les divisions, vu que le diviseur est aussi partagé. Ce sont les seules contraintes. ===Le partage des ports d'émission=== La présence d'un circuit multiplieur et d'un ''barrel shifter'' pose des problèmes pour le partitionnement. Il est possible d'avoir un port d'émission dédié au multiplieur, et un autre au ''barrel shifter'', qui sont séparés de ceux pour l'ALU entière. Il est alors possible d'émettre une opération entière, une multiplication et un décalage, simultanément. Nous parlerons de '''partitionnement entier''' pour désigner cette possibilité. [[File:Partitionnement superscalaire entier.png|centre|vignette|upright=2|Partitionnement superscalaire entier.]] Le partitionnement entier est cependant très rare, car le gain en performance serait trop faible au regard des couts en circuit. Quelques processeurs historiques l'utilisaient, mais ce n'est plus le cas de nos jours. La raison est que les multiplications et les décalages sont assez rares dans le code, ce qui fait que le port d'émission associés sont sous-utilisés. Et un port d'émission a un cout en circuit assez important. Et c'est sans compter qu'ajouter des ports sur le banc de registres juste pour un multiplier sous-utilisé n'en vaut pas la peine. L'idéal serait de trouver un moyen de réduire le nombre de ports d'émissions, sans réduire le nombre d'unités de calcul. [[File:Emission multiple des opérations entières, implémentation naive.png|vignette|Émission multiple des opérations entières, implémentation naive]] La solution consiste à '''partager les ports d'émission''', à savoir connecter un port d'émission à plusieurs unités de calcul. L'exemple classique est justement lié aux circuits multiplieur et ''barrel shifters''. L'idée est que le multiplieur et le ''barrel shifter'' sont mis sur le même port d'émission qu'une ALU entière. Prenons par exemple le processeur à double émission entière illustré ci-contre. Un port d'émission est relié à une ALU entière seule, et l'autre port d'émission alimente la seconde ALU entière et le multiplieur. La conséquence est que le processeur peut émettre deux opérations entières, dont une multiplication. Si on avait utilisé un port d'émission dédié au multiplieur, il aurait été possible d'émettre deux opérations entières et une multiplication. On perd donc une voie, mais on gagne en flexibilité et on économise des circuits. Notons que ce partage signifie aussi que le multiplieur partage les ports sur le banc de registre, ce qui fait une double économie. [[File:Emission multiple des opérations entières, implémentation courante.png|centre|vignette|upright=1.5|Émission multiple des opérations entières, implémentation courante]] En général, le ''barrel shifter'' et le multiplieur sont placés sur deux voies d'émission séparés, ce qui permet d'émettre un décalage et une multiplication en même temps. Les mettre sur le même port ne le permettrait pas. {|class="wikitable" |- ! Voie d'émission n°1 !! Voie d'émission n°2 !! Voie d'émission n°3 |- | * ALU entière * Multiplieur | * ALU entière * Barrel shifter | FPU |- | * Additions, soustractions, opérations bit à bit, etc. * Multiplication | * Additions, soustractions, opérations bit à bit, etc. * Décalages et rotations | Opération flottante |} Terminons concernant les multiplieurs avec une dernière subtilité. Pour rappel, les processeurs modernes intégrent en réalité deux multiplieurs différents. Le résultat d'une multiplication est très large et prend deux registres. Par exemple, une multiplication de deux opérandes 64 bits donne un résultat sur 128 bits, ce qui ne tient pas dans un registre, mais en prend deux. L'instruction de multiplication classique ne calcule que les 64 bits de poids faible. mais elle est complétée par d'autres instructions de multiplication qui peuvent faire le calcul complet. Pour résoudre le problème, les processeurs modernes intègrent deux instructions de multiplications : une qui calcule les bits de poids faible du résultat, une autre qui calcule les bits de poids fort. Et ces deux instructions sont associées à deux multiplieurs séparés, aux circuits différent. Le multiplieur qui calcule les bits de poids faible du résultat est appelé le ''low multiplier'', l'autre est appelé le ''high multiplier''. Le second multiplieur est souvent placé sur un second port d'émission, différent du premier multiplieur, partagé avec une ALU. L’avantage de mettre les deux multiplieurs sur deux ports d'émission différents est qu'une multiplication complète peut être réalisée en utilisant les deux multiplieurs en parallèle. Les deux sous-multiplications sont émises en même temps, exécutées en même temps. pas besoin d'exécuter l'une puis la seconde, d'où un gain performance appréciable. Nous venons de voir comment partager un port d'émission entre une ALU et un multiplieur. Mais au-delà de cet exemple, le partage des ports d'émission peut appliquer à n'importe quelle unité. Prenons l'exemple d'un CPU superscalaire avec 4 ALU entières, une FPU, et une unité mémoire. Vu qu'il y a 6 unités, cela fait donc 6 ports d'émission. Cependant, il est rare qu'un bloc de 6 instructions contienne exactement 4 opérations entières, une opération flottante, et un accès mémoire. Beaucoup de ports d'émission seraient sous-utilisés. La solution est de partager des ports d'émission, pour passer à la quadruple émission. Le CPU peut alors répartir 4 instructions sur les ports d'émission adéquats, à chaque cycle. Le CPU a donc 4 ports de décodage et 6 ports d'émission. Une implémentation classique permet n'importe quelle combinaison de 4 instructions compatible avec les 6 unités. Par exemple, il devient possible d'émettre simultanément 4 additions, la combinaison 2 * INT + FLOAT + MEM, 3 * INT + MEM, et bien d'autres. L'exemple relie une ALU entière, la FPU et l'unité mémoire sur le même port. Le CPU a alors quatre ports d'émission, qui ne sont pas "identiques". Trois d'entre eux sont reliés à une ALU entière chacun, rien d'autre. Le quatrième est lui relié à une ALU entière, la FPU et l'unité mémoire. On économise alors deux ports d'émission, mais cela entraine l'apparition de contraintes d’appariement. Le CPU peut émettre 3 opérations entières + n'importe quelle autre opération. Mais les autres combinaisons sont interdites. Le CPU peut émettre 6 opérations entières simultanément, grâce à 6 ALU entières. Les accès mémoire ou opérations flottantes ne viennent pas en plus, mais en remplacement des opérations entières. Regrouper plusieurs ALU sur un même port d'émission est donc à l'origine de dépendances structurelles, de nouvelles contraintes d’appariement. Dans certaines situations de '''''port contention''''', on a assez d'ALU pour exécuter N micro-opérations, mais la répartition des ALUs sur les ports l'empêche. Impossible d'émettre deux micro-opérations sur deux ALU si elles sont sur le même port d'émission. On peut réduire les cas de ''port contention'' en répartissant correctement les ALU sur les ports d'émission, mais sans jamais les supprimer complétement. Un exemple est celui du PowerPC 604. Il implémentait la quadruple émission, alors qu'il avait 5 unités de calcul. Mais deux unités partageaient un même port d'émission. Dans le détail, il avait deux ALU entières, un circuit multiplieur/diviseur, une FPU, une unité mémoire. La FPU et le multiplieur étaient sur le même port d'émission. En conséquence, le CPU pouvait émettre seulement les combinaisons INT + INT + MEM + (MUL/FLOAT). : Il est intéressant de voir l'exemple d'un processeur superscalaire parfait, sans contraintes d'appariement, à N voies. Pour cela, on part d'un processeur non-superscalaire, avec M unités de calcul. Un tel processeur peut s'implémenter avec N ports d'émission, chacun relié à M unités de calcul possibles, ce qui fait que les M unités de calcul sont dupliquées en N exemplaires. Si on prend par exemple un CPU non-superscalaire avec une ALU, une FPU, une unité mémoire et une unité de branchement, un port d'émission sera relié à une ALU, une FPU, une unité mémoire et une unité de branchement. ===La duplication des autres unités fonctionnelles=== Dupliquer les ALU entière est une première étape, mais il est aussi possible de dupliquer les autres unités fonctionnelles. Par exemple, il est possible de dupliquer l'unité mémoire ou l'unité de branchement. Reste à voir quelles unités dupliquer, et pourquoi. Précisons que dans ce qui va suivre, nous allons parler de la duplication des unités en général, pas seulement des unités mémoire/branchement. Nous allons continuer de parler de la duplication des ALU entières dans ce qui suit, mais de manière plus générale. Pour un processeur à N voies, il est théoriquement possible de dupliquer toutes les unités en N exemplaires. Mais ce n'est jamais fait en pratique, car le cout en circuits serait trop important et le gain en performance trop faible. Mieux vaut dupliquer certaines unités bien précises, quitte à avoir des contraintes d'appariement. Et à ce petit jeu, toutes les duplications ne se valent pas, certaines sont plus rentables en matière de performance, le cout en circuit n'est pas le même selon l'unité, etc. La rentabilité en performance dépend surtout des contraintes d'appariement. Les contraintes d'appariement entrainent une baisse de performance significatives si elles interdisent des paires d'instructions fréquentes. Aussi, les opérations très fréquentes, souvent appairées, gagnent à dupliquer l'unité associée. Et au contraire, les unités rarement utilisées ne doivent pas être dupliquées. Il se trouve que les unités les plus utilisées sont les ALU entières, suivies par les unités mémoire et l'unité de branchement. Le cout en circuit n'est aussi pas le même. Dupliquer les ALU entière est trivial, car elles ont un budget en transistors assez faible. Les circuits multiplieurs, diviseurs, et les ''barrel shifter'' ont eux un cout en transistor plus élevés. Si on devait faire un classement, on aurait : ALU entière < ''barrel shifter'' < multiplieur. Pour les unités mémoire, le cout en transistor est là aussi conséquent. Le résultat final est que dupliquer les ALU entières est privilégié sur le reste, comme l'a vu dans la section précédente. Les unités mémoire arrivent en seconde place, suivie par les multiplieurs/''barrel shifter'' à la troisième place, et les unités de branchement à la quatrième place. Les CPU superscalaires larges ont donc tendance à multiplier les unités mémoire en second. Les multiplieurs et ''barrel shifters'' sont eux aussi dupliqués sur les CPU superscalaires larges, mais cela vient souvent après avoir dupliqué les unités mémoire. La raison est que les accès mémoire sont critiques pour la performance des CPU à exécution dans le désordre, pas les multiplications. Pour les unités de branchement, une subtilité complique le fait d'en installer plusieurs. Que faire quand deux branchements sont pris ? La solution la plus simple est de ne pas se trouver dans cette situation : on n'utilise qu'une seule unité de branchement et on n’exécute qu'un seul branchement par cycle. La majorité des processeurs superscalaires étroits font ainsi. Les processeurs superscalaires larges ont cependant deux unités de branchements, mais ils n'acceptent qu'un seul branchement pris à la fois. Si les deux branchements pris sont exécutés en même temps, le processeur n’exécute que le plus récent, dans l'ordre du programme. ===Les CPU superscalaires mélangent les trois techniques=== Les CPU superscalaires utilisent toutes les techniques à la fois : partitionnement, duplication de l'ALU entière, duplication des autre unités fonctionnelles. Chaque processeur utilise ces trois stratégies à sa sauce, en fonction de son budget en transistor. Les quatre techniques ont cependant un cout en circuit différent, et donnent des gains de performances eux aussi forts différents. * Le '''partitionnement superscalaire''' a un cout en circuit modéré, car on n'a pas besoin de dupliquer d'ALU. * La '''duplication des ALU entières''' est la technique la plus importante : elle a un cout en circuit modéré, et donne des gains en performance impressionnants. * La '''duplication des autres unités''' a un cout en circuit variable, pour des gains en performance eux aussi variables. * Le '''partage des ports d'émission''' réduit le cout en circuit du CPU, pour des pertes de performances mineures si bien fait. L'usage du partitionnement seul, sans duplication, était surtout le fait des processeurs commercialisés entre les années 1989 et 1993. Le partage des ports d'émission a lui aussi mis un peu de temps pour s'imposer. Globalement, les processeurs superscalaires ont évolués progressivement, pour se rapprocher d'une sorte de standard. Mais pour comprendre ce qu'est ce standard, et en quoi les CPU historiques s'en sont progressivement rapprochés, il faut étudier l'histoire des CPU superscalaires. L'histoire des CPU superscalaires a commencé dès 1960, mais est resté un projet de recherche pendant plusieurs décennies. De nombreux designs ont été conçus, mais abandonnés avant la production, comme l'ACS-1 d'IBM. Les années 1980 ont vu l'arrivée de prototypes de processeurs VLIW, mais qui n'étaient pas superscalaires. Par exemple, l'Apollo DN10000 et l'Intel i860 pouvaient émettre deux instructions à la fois, sous conditions, mais demandaient que le compilateur fasse une bonne partie du travail. Les premiers CPU superscalaires commercialisés sont sortis en 1989. Deux CPUs superscalaires sont sortis cette année là : le RS/6000 d'IBM et l'i960CA d'Intel. Puis, la compétition s'est aussi lancée dans la bataille. Les CPU commercialisés avant l'année 1993 étaient à double émission, à l'exception du SuperSPARC qui utilisait la triple émission. Les modèles après 1993 hésitaient entre double et quadruple émission. Dans le tableau ci-dessous, les processeurs quadruple émission sont en bleu, les triple émission sont en rouge, les autres ne sont pas en couleur. {|class="wikitable" |- ! !! IBM !! HP PA-RISC !! SPARC !! Intel!! Alpha !! Autres |- ! 1989 | RS/6000 || || || i960CA || || |- ! 1990 | || || || || || |- ! 1991 | || || || || || Motorola 88110 |- ! 1992 | RSC || PA 7100 || class="f_rouge | SuperSPARC || || 21064 || |- ! 1993 | PPC 601 || || HyperSPARC || Pentium || || |- ! 1994 | class="f_bleu | POWER 2 || PA 7200 || || || class="f_bleu | 21164 || |- ! 1995 | 603/604 || class="f_bleu | PA 8000 || class="f_bleu | UltraSPARC 1 || Microarchitecture P6 (+ concurrence AMD) || || class="f_bleu | MIPS R1000 |- ! 1996 | class="f_bleu | 620 || || || || class="f_bleu | 21264 || |- ! ... || ... || ... || ... || ... || ... || ... |} Les premiers CPU à double émission sont assez représentatifs des CPU à double émission modernes. Il faut dire que se limiter à deux voies ne permet pas de faire beaucoup de choses. Voici le tableau chronologique disant quel CPU utilisait quelle technique. * Les CPU en vert utilisaient la double émission entière-flottante. * Les CPU en rouge utilisaient la double émission entière "pure". * Les CPU en jaune utilisaient un ''partitionnement complet'' entre ALU, FPU et unité mémoire. * Les CPU sans couleur utilisaient un grand nombre d'unités, avec beaucoup de ports d'émission. * Les CPU barrés utilisent la triple ou quadruple émission et seront vu dans la section suivante. {|class="wikitable" |- ! !! IBM !! HP PA-RISC !! SPARC !! Intel!! Alpha !! Autres |- ! 1989 | class="f_vert | RS/6000 || || || class="f_rouge | i960CA || || |- ! 1990 | || || || || || |- ! 1991 | || || || || || Motorola 88110 |- ! 1992 | class="f_vert | RSC || class="f_vert | PA 7100 || <s>SuperSPARC</s> || || class="f_jaune | 21064 || |- ! 1993 | class="f_vert | PPC 601 || || class="f_jaune | HyperSPARC || class="f_rouge | Pentium || || |- ! 1994 | <s>POWER 2</s> || PA 7200 || || || <s>21164</s> || |} C'est en 1994, que la quadruple émission est arrivée et que les CPU ont essayé divers implémentations. Il y avait alors trois stratégies pour la double/triple/quadruple émission, qui partageaient des problèmes similaires. La première implémentation dupliquait les ALUs et les FPUs, ce qui permettait d'émettre deux opérations flottantes avec deux opérations entières. Le POWER 2 dupliquait ses FPUs à la perfection, alors que le 21264 séparait l'additionneur et le multiplieur flottant. Les accès mémoire étaient traités comme des opérations entières et le processeur pouvait souvent en émettre deux à la fois. Mais une telle organisation n'est plus utilisée de nos jours, car, sans instructions flottantes à exécuter, elle est équivalente à de la double émission. La seconde implémentation utilisait deux ALU entières (dont un multiplieur), une unité mémoire et une FPU.Cette organisation est intéressante, mais encore trop stricte pour donner de bons résultats, les quadruplets avec exactement deux opérations entières, un accès mémoire et une opération flottante étant trop rares. L'usage de ces 4 unités en double ou triple émission a été utilisé sur le PA 7200 et le SuperSPARC. Malheureusement, en plus de problèmes au niveau de son cache, le SuperSPARC avait de nombreuses contraintes d’appariement, car le banc de registre n'avait pas assez de ports pour alimenter certaines combinaisons d'instructions. De plus, s'il émettait une multiplication, il ne pouvait pas émettre de seconde µop. Enfin, une troisième implémentation utilisait un grand nombre d'unités fort différentes, bien plus que quatre, avec au minimum deux ALU entières. Prenons l'exemple de l'UltraSPARC, qui avait : deux ALU entières, une unité mémoire, une unité de branchement, un additionneur flottant, un multiplieur flottant, un diviseur flottant (aussi utilisé pour le calcul des racines carrées), et 2 unités graphiques pour les calculs sur des pixels. En tout, cela fait 9 unités différentes, pour de la quadruple émission. Dans le même genre, les processeurs MIPS R8000 et R10000 avaient une implémentation plus moderne, dans le sens où toutes les unités étaient dupliquées. Le CPU avait deux ALU, deux FPU et deux unités mémoire. Il pouvait donc émettre quatre instructions à la fois, tant que le paquet collait avec ces six unités. Moitié opérations entières, moitié opérations mémoire, avec de quoi remplacer les opérations entières par des opérations flottantes. Le PA 8000, lui, dupliquait toutes ses unités en deux exemplaires, ce qui n'est pas l'idéal, aucun processeur moderne ne fait cela aujourd'hui. Le tout est résumé dans le tableau ci-dessous, avec : * en vert les CPU utilisant la première stratégie ; * en rouge les CPU utilisant la seconde stratégie ; * en jaune les CPU utilisant la troisième stratégie. {|class="wikitable" |+ Processeurs quadruple émission historiques |- ! Année !! Processeur !! Unités |- ! 1991 | class="f_jaune | Motorola 88110 || class="f_jaune | 2 ALU + MUL + DIV + BIT + MEM + FADD + 2 unités graphiques |- |- ! rowspan="2" | 1994 | class="f_vert | POWER 2 || class="f_vert | 2 ALU/MEM + 2 FPU (+ 2 Branchements via ''branch folding'') |- | class="f_rouge | 21164 || class="f_rouge | 2 ALU + FPU + MEM |- ! rowspan="3" | 1995 | PA 8000 || 2 ALU + 2 ''barrel shifters'' + 2 MEM + 2 FPU (FMA) + 2 FPU (DIV et SQRT) + 2 SIMD |- | class="f_jaune | UltraSPARC 1 || class="f_jaune | 2 ALU + MEM + BRANCH + FADD + FMULFDIV + 2 unités graphiques |- | MIPS R8000 et R10000 || 2 ALU + 2 FPU + 2 MEM |- ! rowspan="2" | 1996 | class="f_rouge | 620 || class="f_rouge | 2 ALU + FPU + MEM |- | class="f_vert | 21264 || class="f_vert | 2 ALU/MEM + 2 FPU (FADD + FMUL) |} Malheureusement, ces CPUs historiques n'avaient ni assez d'unités de calcul entières, ni d'unités mémoire, pour remplir la quadruple émission. Environ la moitié des instructions d'un programme correspond à des instructions entières. Pour en profiter, un processeur à N voies doit disposer d'au minimum N/2 ALU entières, l'idéal étant d'aller au-delà. Les CPU superscalaires historiques avaient 2 ALU pour de la quadruple émission, ce qui était très limite. En comparaison, les CPU superscalaires modernes mettent le paquet niveau ALU entière. La plupart des CPU x86 modernes descendent rarement sous les 2/3, la plupart remplit presque la totalité de la largeur du CPU. Pour donner un exemple, la microarchitecture Golden Cove d'Intel est un processeur à 6 voies, avec 5 ALU entières. Pour être précis, un programme informatique exécute environ 40% de son code dans des instructions arithmétiques, un autre 40% dans les accès mémoire, et un le reste pour... le reste. La conséquence est que les processeurs modernes dupliquent leurs unités mémoire. Par exemple, la microarchitecture ''Golden Cove'' d'Intel dispose de trois unités mémoire : deux spécialisées dans les écritures, trois dans les lectures. La microarchitecture ''Gracemont'' utilise la pentuple émission et peut émettre 4 µops entières et 4 µops mémoire. Notez que le ratio est équilibré entre opérations entières et mémoire, avec soit égalité, soit un avantage pour les ALU entières. Une autre régularité est que la largeur totale du processeur peut être occupée par des opérations entières/mémoire. Pour le dire autrement, sur un processeur quadruple émission, il pourra émettre un mix de 4 instructions entière/mémoire, avec zéro opération flottante. Idem avec des processeurs triples ou pentuple émission, voire plus. Si le processeur émet une opération flottante, elle remplace une opération entière. Prenons l'exemple des processeurs AMD K6, sortis en 1997, juste avant les AMD Athlon. Ils avaient 10 unités de calcul, 6 ports d'émission, 4 ports de décodage. Voici exactement comment étaient répartie les unités de calcul sur les ports d'émission. C'était des processeurs quadruple émission, ce qui fait que la moitié de la largeur du processeur sert pour des opérations entières, et l'autre moitié pour les accès mémoire. {|class="wikitable" |- ! Port d'émission n°1 !! Port d'émission n°2 !! Port d'émission n°3 !! Port d'émission n°4 !! Port d'émission n°5 !! Port d'émission n°6 ! |- | ALU entière || ALU entière || FPU || Unité de branchement || Unité LOAD || Unité STORE |- | || Multiplieur || || || || Unité de calcul d'adresse (instruction LEA) |- | || ''Barrel shifter'' || || || || Unité pour les instructions PUSH |} Les microarchitectures K7, K8 et K10, utilisées sur les anciens CPU AMD Athlon, sont un exemple moins représentatif. Ces microarchitectures utilisent le partage des ports d'émission au maximum. C'était des microarchitectures à triple émission, avec six ports d’émission. Il y avait trois ports d'émission pour les opérations flottantes, et trois ports d'émission pour les micro-opérations entières/mémoire. Il y avait trois ALU entières et trois unités mémoire, chaque ALU partageait un port d'émission avec une unité mémoire. Elle pouvait donc émettre soit trois opérations entières, soit trois µops mémoire, soit un mix des deux. En plus des mix avec les opérations flottantes et branchements. {|class="wikitable" |- ! Port d'émission n°1 !! Port d'émission n°2 !! Port d'émission n°3 !! Port d'émission n°4 !! Port d'émission n°5 !! Port d'émission n°6 ! |- | ALU entière || ALU entière || ALU entière || FADD || FMUL || FPU (autres opérations) |- | Multiplieur || || || || || |- | LOAD/STORE || LOAD/STORE || LOAD/STORE || || || |} Les CPU superscalaires larges dupliquent les multiplieurs et/ou les ''barrel shifters'', et même les unités de branchement. La raison est que quand la largeur du CPU augmente, le processeur traite des paquets d'instructions de plus en plus gros. Par exemple, pour un CPU à 10 voies, cela veut dire émettre 10 instructions en même temps. Il est alors plus fréquent d'avoir deux multiplications, deux décalages, deux accès mémoire, deux branchements. Par exemple, la moyenne est d'une multiplication tous les 5 instructions. Les CPU superscalaires à 10 voies ont donc tendance à avoir deux multiplications par paquet d'instruction, en moyenne. Avoir deux multiplieurs est alors un gain en performance clair. Par exemple, la microarchitecture ''Golden Cove'' a deux ''barrel shifters''. C'est une architecture à 6 voies. {|class="wikitable" |- ! Port d'émission n°1 !! Port d'émission n°2 !! Port d'émission n°3 !! Port d'émission n°4 !! Port d'émission n°5 !! Port d'émission n°6 !! Port d'émission n°7 !! Port d'émission n°8 !! Port d'émission n°9 !! Port d'émission n°10 |- | ALU entière || ALU entière || ALU entière || ALU entière || ALU entière || LOAD || LOAD || LOAD || STORE || STORE |- | ''Barrel shifter'' || Multiplieur || Multiplieur || ''Barrel shifter'' || || || || || || |- | Branchements || Diviseur || || Branchements || || || || || || |} ==Les µops mémoire sur les processeurs superscalaires== Plus haut, nous avons volontairement passé sous silence les accès mémoire. La raison à cela est que leur support sur les CPU superscalaire peut se faire de plusieurs manières différentes, qu'il vaut mieux expliquer dans une section dédiée. Les différentes implémentations sont décrites dans la liste suivante, nous allons les voir une par une. * Avec la première méthode, les accès mémoire sont exécutés par le pipeline pour les opérations entières. * Avec la seconde méthode, les accès mémoire ont un pipeline dédié ; c'est l'''émission parallèle des accès mémoire''. * Avec la troisième méthode, il est possible d'émettre plusieurs accès mémoire simultanément : c'est l'''émission multiple des accès mémoire''. Voyons ces trois cas dans le détail. Nous verrons notamment les différentes formes d'émission multiple des accès mémoire. ===Les accès mémoire traités dans le pipeline entier=== Dans le cas le plus simple, les accès mémoire sont traités comme des opérations entières un peu spéciales. L'unité mémoire est sur le même port d'émission que l'ALU entière, ce qui fait que les accès mémoire remplacent des opérations entières. Faire ainsi permet d'utiliser une ALU entière pour les calculs d'adresse, pas besoin de rajouter une unité de calcul d'adresse séparée. Typiquement, un processeur de ce type place l'unité mémoire après l'unité de calcul. Les opérations entières n'utilisent que l'ALU entière, mais pas l'unité mémoire. Les accès mémoire exécutent un calcul d'adresse dans l'ALU entière, puis l'adresse calculée est envoyée à l'unité mémoire. Le tout est illustré ci-dessous, dans le cas d'un processeur historique à double émission entière-flottante. [[File:Processeur non-superscalaire basique 01.png|centre|vignette|upright=1.5|Processeur non-superscalaire basique]] Un exemple de CPU double émission de ce type est celui du Power PC 440, un CPU destiné à l'embarqué. Vu qu'il était destiné à l'embarqué, il n'avait pas de FPU, il n'avait pas besoin de manipuler de nombres flottants. Il n'a donc que des ALU entières, un multiplieur et une unité mémoire. Il dispose de deux ports d'émission. Le premier est connecté à une ALU entière et un circuit multiplieur, le second est relié à l'unité mémoire et une seconde ALU entière. Une organisation simple, mais très efficace ! [[File:PowerPC 440.png|centre|vignette|upright=2|Microarchitecture du PowerPC 440.]] L'implémentation économise une unité de calcul d'adresse, mais n'a pas de cout en performance significatif. Les accès mémoire étant très lents, émettre une µop entière en parallèle d'un accès mémoire ne sert pas à grand-chose. On peut émettre cette µop entière un cycle plus tard, elle sera terminée avant même que l'accès mémoire soit terminé, même si l'accès mémoire se fait dans le cache L1 ou L2. Pour comprendre pourquoi, faisons quelques calculs. Un accès mémoire prend deux-trois cycles quand il tombe dans le cache L1. Et on doit attendre qu'il soit terminé pour en émettre un nouveau. Combien d'instructions arithmétiques peut-on lancer pendant ce temps, sur un CPU triple émission ? Au premier cycle, on peut en émettre 2 (l'instruction mémoire prend une place, donc 3-1), puis 3 au second cycle. Ce qui fait 5 instructions arithmétiques au total. Or, il se trouve qu'il y a une instruction d'accès mémoire pour 5 instructions arithmétiques, environ. Par contre, ce compromis change quand on passe à la quadruple émission, voire au-delà. Dans ce cas, il devient intéressant de pouvoir émettre une nouvelle instruction mémoire à chaque cycle. Ce qui nous amène à la section suivante... ===L'émission parallèle des accès mémoire=== A partir de la quadruple émission, la tendance a été de séparer l'unité mémoire des ALU entières. Cela permet d'émettre des µops mémoire en même temps que des µops entières et/ou flottantes., ce qui porte le nom d''''émission parallèle des µops mémoire''', ou encore ''émission mémoire parallèle''. Par exemple, un processeur quadruple émission peut émettre en même temps deux opérations entières, une opération flottante et un accès mémoire. L'accès mémoire vient en plus des opérations entières, il n'est pas possible de remplacer l'accès mémoire par une opération entière. La technique ne permet pas de faire les calculs d'adresse dans l'ALU entière. Il faut donc utiliser une unité de calcul d'adresse séparée. Elle est intégrée dans l'unité mémoire, qui fait l'interface entre le cache et le banc de registres. Le cout en circuits est très faible, car les unités de calcul d'adresse n'utilisent guère plus qu'un additionneur et un circuit de décalage très simple. L'émission mémoire parallèle est plus facile à implémenter sur les CPU RISC, qui ont des instructions mémoire séparées du reste. Les CPU CISC ne sont pas dans ce cas, ce qui fait que séparer l'unité mémoire du pipeline entier est compliqué. Les CPU superscalaires historiques étaient pour moité des CPU RISC et pour moitié des CPU CISC, ce qui fait qu'ils n'utilisaient pas ou peu l'émission mémoire parallèle. Les premiers processeurs superscalaires se contenaient de l'émission parallèle mémoire, ils ne pouvaient émettre qu'un seul accès mémoire à la fois, l'unité mémoire n'était pas dupliquée. Et ce n'est pas tant un problème que ça, du moins sur les processeurs à double ou triple émission. En effet, il est rare que l'unité mémoire doive faire deux accès simultanés. Notons que le processeur peut exécuter une instruction mémoire en parallèle d'un calcul ou d'un branchement, seuls les accès mémoire simultanés sont impossibles. ===L'émission multiple des accès mémoire avec une LSQ=== Les processeurs superscalaires larges travaillent sur des paquets de 8 à 10 instructions, il est plus fréquent d'avoir plusieurs accès mémoire par paquet. Dans ces conditions, il est utile d'avoir une '''émission multiple des accès mémoire''', à savoir d'émettre plusieurs micro-opérations mémoire en même temps. Les processeurs superscalaires modernes sont capables d'émettre plusieurs lectures/écritures simultanément. Par exemple, ils peuvent émettre une lecture en même temps qu'une écriture, ou plusieurs lectures, ou plusieurs écritures. Il faut noter que selon le processeur, il peut y avoir des restrictions quant aux accès mémoire émis en même temps. Par exemple, certains processeurs peuvent émettre une lecture avec une écriture en même temps, mais pas deux lectures ni deux écritures. Ou encore, ils peuvent émettre deux lectures, une lecture et une écriture, mais pas deux écritures en même temps. Dans la majorité des cas, les processeurs ne permettent pas d'émettre deux écritures en même temps, alors qu'ils supportent plusieurs lectures. Il faut dire que les lectures sont plus fréquentes que les écritures. Les processeurs qui autorisent toutes les combinaisons de lecture/écriture possibles, sont rares. L'émission multiple des accès mémoire s'implémente dans l'unité mémoire. Pour rappel, l'unité mémoire s'interpose entre le cache L1 et le reste du pipeline. Dans le cas le plus simple, elle incorpore une ''load/store queue'' et des unités de calcul d'adresse. L'émission multiple des accès mémoire demande de rendre la ''Load-store queue'' multi-ports, afin de gérer plusieurs micro-opérations mémoire simultanées. Il faut aussi dupliquer les unités de calcul d'adresse reliées à la LSQ, chaque port d'émission mémoire devant avoir sa propre unité de calcul d'adresse. : Dans ce qui suit, nous parlerons d'AGU (''Adress Generation Unit'') pour désigner les unités de calcul d'adresse, et de LSQ pour designer la ''Load-store queue''. [[File:Processeur non-superscalaire basique 02.png|vignette|upright=1|Processeur non-superscalaire basique]] Dupliquer les ports de la LSQ et les AGU est nécessaire. Mais qu'en est-il du cache ? La réponse varie suivant le processeur. Il y a deux grandes méthodes pour implémenter l'émission multiple des accès mémoire. La première méthode ajoute des ports de lecture/écriture au cache de données, pour faire des lectures/écritures simultanées. Il faut alors dupliquer des unités de calcul, rajouter les ports sur le cache, mais aussi rajouter des ports sur la ''load/store queue'', pour qu'elle échange des données/commandes mémoire avec le cache. Le cout en circuits est alors conséquent La seconde duplique les unités de calcul, mais pas les ports d'accès au cache. Les accès mémoire sont alors accumulés dans la ''load/store queue'', qui sont ensuite traités un par un par le cache. Un exemple est celui des processeurs AMD de micro-architecture K7 K8, à savoir les anciens AMD Athlon et AMD Athlon 64, qui pouvaient calculer trois adresses simultanément, mais ne pouvaient faire qu'un seul accès au cache par cycle. Le cout en circuit est modéré : les unités de calcul coutent très peu, les ports de la ''load/store queue'' coutent déjà un peu plus. Quelques processeurs utilisaient des solutions intermédiaires. Un processeur utilisant cette technique est, par exemple, capable d'émettre quatre µops mémoire en même temps, mais avec seulement deux ports sur le cache. Un exemple classique étant les Pentium 1 et 2 d'Intel, dont nous parlerons dans le chapitre suivant. ===L'émission séparée des LOAD et STORE=== De rares processeurs ont des ports d'émission qui peuvent faire indifféremment lecture comme écritures. Mais les processeurs modernes préfèrent séparer ports d'émission pour les lectures et les écritures. Un exemple est celui des processeurs Intel de micro-architecture Nehalem, qui avaient un port de lecture et un port d'écriture tous deux reliés à la ''Load-store queue'', chacun avec leur propre unité de calcul d'adresse. Comme autre exemple, les processeurs skylake ont une LSQ avec deux ports de lecture et un port d'écriture, ce qui permet d'émettre deux lectures en même temps qu'une écriture. Dans cette section, nous allons étudier le cas avec des ports séparés pour les lectures et écritures. En général, les processeurs ont un peu plus de ports de lectures que d'écritures. Une raison est qu'un programme a, en moyenne, un tout petit peu plus de lectures que d'écritures. Mais la différence n'est pas énorme, c'est un léger déséquilibre. Une seconde raison est que l'exécution dans le désordre marche bien mieux quand les lectures ont lieu le plus tôt possible. Donc mieux vaut privilégier les lectures à l'émission, pour qu'elles se fassent un peu en avance. En pratique, la différence n'est pas très marquée. Il est courant d'avoir un port de lecture et un d'écriture, les CPU superscalaires très larges ont souvent deux ports de lecture et deux d'écriture. A la rigueur, quelques CPU ont trois ports de lecture et deux d'écriture. Le cas le plus simple est celui où on peut émettre une lecture et une écriture en même temps. Il s'implémente facilement si la LSQ est en réalité une simple ''Store queue'', à savoir qu'elle met en avance les écritures uniquement. Pour rappel, les écritures sont mises en attente dans la ''Store queue'', mais les lectures sont exécutées immédiatement. Une fois l'adresse à lire connue, la lecture consulte la ''Store queue'' pour détecter les dépendances de données, puis s'exécute. La donnée à lire est lue soit depuis la ''Store queue'', soit depuis le cache. [[File:Emission LOAD - Store séparée.png|vignette|upright=1|Émission LOAD - Store séparée]] L'implémentation de l'émission multiple est alors très simple. La ''Store queue'' a déjà deux ports, avec un pour les lectures et un autre pour les écritures. Idem pour le cache, qui a naturellement un port de lecture et un d'écriture. Émettre une lecture et une écriture simultanément ne demande donc pas de modification digne de ce nom. La ''Store queue'' doit juste supporter une lecture et une écriture simultanée. Ajouter l'émission d'une seconde lecture n'est pas compliquée : il faut juste rajouter un second port de lecture sur le cache et la ''Store queue''. Pour rappel, l'unité mémoire est précédée par une structure qui met en attente les micro-opérations mémoire avant leur émission finale. La structure en question varie suivant l'implémentation, mais un cas particulier se marie bien avec l'émission multiple des µops mémoire. Il s'agit du cas avec une file de µops séparée pour les lectures et une autre pour les écritures, appelées respectivement la ''file de µops LOAD'' et la ''file de µops STORE''. Il est alors possible d'émettre une lecture et une écriture lors du même cycle d'horloge. Le port de lecture alimente une unité de calcul d'adresse dédiée, directement reliée au cache. Le port d'écriture du cache alimente une unité de calcul, qui est suivie par une file d'écriture, elle-même reliée au cache. Les processeurs AMD de micro-architecture K6 utilisaient cette technique. [[File:Double émission avec le Load Ordering, Store Ordering.jpg|centre|vignette|upright=2.5|Double émission avec le Load Ordering, Store Ordering]] ==Les CPU superscalaire à exécution dans le désordre== La superscalarité modifie aussi les circuits dédiés à l'exécution dans le désordre. Elle modifie les unités de renommage de registre, le ROB et les autres structures liées à l'exécution dans le désordre, au sens large. Aucune structure n'est épargnée. Elles ont tous des prots de lecture/écriture en plus, afin d'encaisser l'émission, le ''commit'' ou le renommage simultané de plusieurs µops. Par exemple, le ROB doit être modifié pour émettre et terminer plusieurs instructions en même temps, en ajoutant des ports de lecture/écriture. Pour un CPU superscalaire à 8 voies, on se dit que le ROB peut retirer 8 µops par cycle maximum. Mais certains processeurs récents ont un ROB qui peut retirer le double ! Un exemple est celui des CPU de micro-architecture Skymont, qui peuvent émettre 8 µops par cycle, mais en retirer 16. Quelques CPU de marque AMD étaient aussi dans ce cas. L'avantage est que cela permet de réduire la taille du ROB, du banc de registre et de quelques autres structures matérielles liées à l'exécution dans le désordre. Le gain sur-compense le cout en transistor nécessaire pour retirer 16 µops par cycle. Dans cette section, nous allons voir comment les étages du pipeline dédiés à l'exécution dans le désordre sont modifiées sur un CPU superscalaire. ===L'exemple du PA-RISC PA 8000=== Avant de commencer, nous allons voir un processeur superscalaire assez simple, le PA 8000, de HP, qui implémente le jeu d'instruction PA-RISC. Bien que très ancien, il implémentait l'exécution dans le désordre et le renommage de registre. Le peu d'informations que nous avons sur ce processeurs proviennent des documents "THE HP PA-8000 RISC CPU" par Ashok Kumar, et l'article de microprocessor report "PA-8000 Combines Complexity and Speed". Ils ne donnent malheureusement pas énormémment d'informations et je devrais être amené à faire quelques suppositions dans ce qui suit. Avant de commencer, parlons de détails sans lien avec la superscalarité. Ce processeur, comme beaucoup de processeurs PA-RISC, n'intégrait pas de cache de niveau L2 dans le processeur, qui était déporté en-dehors du CPU, sur la carte mère. Le processeur préférait utiliser ses transistors pour avoir un cache L1 assez large, quitte à ce qu'il soit plus lent. La lenteur du cache était prévue, le processeur compensait celle-ci en utilisant l'exécution dans le désordre, bien que ce ne soit pas parfait. Les CPU PA-RISC avant le PA 8000 utilisaient un pipeline à vagues ''wave pipeline'', ce qui était assez peu commun, mais le PA 8000 repasse à un pipeline synchrone classique. Passons maintenant à la superscalarité. Le PA 8000 est un processeur quadruple émission, qui peut émettre, à chaque cycle, deux opérations et deux accès mémoire. Le renommage de registre utilise des registres de renommage séparés des registres architecturaux, comme c'était la mode à l'époque. Le budget en transistor faisait que c'était soit ça, soit le renommage dans le ROB, faute de mieux. Le processeur utilise une implémentation ''Read After Issue'', ce qui veut dire que les opérandes des instructions sont lues après l'émission, juste avant l'exécution. Le processeur peut aussi ''commit'' deux opérations et deux accès mémoire par cycle, ce qui revient à transférer les résultats des registres de renommage vers les registres architecturaux. L'exécution dans le désordre est prise en charge par une structure matérielle unique, qui ressemble à une fusion entre un ROB et une fenêtre d'instruction. Et c'est là que je vais devoir faire des suppositions. Le document "THE HP PA-8000 RISC CPU" nomme cette structure : l''''''Instruction Reorder Buffer'''''. Il utilise pas moins de 850 000 transistors, et prend 20% de la taille du ''die''. L'article "THE HP PA-8000 RISC CPU" laisse fortement sous-entendre qu'il s'agit une structure unique, faite d'un seul tenant, mais l'article de microprocessor report dit le contraire par moment. Il est décrit comme une fenêtre d'instruction, à savoir qu'il détecte les dépendances entre instruction et les émet. Il gère aussi la détection des mauvaises prédictions de branchement et peut annuler les instructions chargées à tord, en les retirant de la fenêtre d'instruction. Il est aussi précisé que les instructions quittent cet ''Instruction Reorder Buffer'' dans l'ordre du programme. Elles ne peuvent en sortir que quand elles ont été exécutées et qu'elles n'ont causé aucune exception. Ce qui fait qu'il se comporte comme un ROB de ce point de vue là. Difficile de dire si l'''Instruction Reorder Buffer'' est un réel mélange entre un ROB et une fenêtre d'instruction, ou si il est réellement conçu avec deux structures séparées. Dans ce qui suit, je pars du principe que les deux structures sont séparées. Le processeur contient deux fenêtres d'instruction : une réservée aux µops mémoire (LOAD et STORE), l'autre pour les opérations entières/flottantes. Elles ont chacune 28 entrées, ce qui permet de mémoriser 56 µops au maximum. Les deux peuvent recevoir 4 µops par cycle de la part des décodeurs. Là encore, précisons que les choses ne sont pas claires pour ce qui est de la séparation. L'article de Microprocessor report dit que les deux sont physiquement séparées, et que cette séparation physique permet de simplifications (les opérations mémorisent des noms de registres plus court que les adresses demandées par les µops LOAD/STORE). Mais l'autre document cité laisse penser que l''''Instruction Reorder Buffer'' est une structure unique. A chaque cycle, le processeur peut émettre deux instructions de calcul et deux instructions mémoire. Les deux fenêtres d'instruction ont pour cela chacune deux ports d'émission. Les deux ports d'émission pour les µops mémoire sont identiques, et le cache L1 est un cache double port, ce qui permet d'exécuter deux lectures/écritures par cycle. Pour ce qui est des µops entières/flottantes, le processeur a dupliqué toutes ses unités de calcul : il a deux ALU entières, deux ''barrel shifters'', deux FPU de type FMAC, et deux unités de division flottante. Vraisemblablement, il y a deux ports d'émission, chacun étant connecté à une unité de chaque type. : S'il n'utilisait pas l'exécution dans le désordre, ce processeur aurait donc quatre pipelines : deux pipeline entiers identiques et deux pipelines mémoire. Et il aurait une superscalarité presque parfaite s'il était un CPU à double émission ! A chaque cycle, la fenêtre d'instruction émet les deux µops les plus anciennes qui sont prête à être exécutées. La documentation dit que la fenêtre émet "la plus vielle instruction paire, et la plus vielle instruction impaire", ce qui sous-entend que la fenêtre d'instruction est en réalité composée de deux sous-fenêtres, une fenêtre paire et une impaire. Les µops sont insérées après le décodage dans ces sous-fenêtres : les deux µops sont réparties dans les deux. Et lors de l'émission, une µops vient d'une sous-fenêtre, une autre µops vient de l'autre. La fenêtre d’instruction a donc une structure partitionnée, avec une logique d'éveil segmentée, une partie gérant la moité de la fenêtre d'instruction, l'autre gérant le reste. [[File:PA 8000 - microarchitecture.png|centre|vignette|upright=2|PA 8000 - microarchitecture]] ===La superscalarité avec une file/fenêtre d'instruction centralisée=== Plus haut, nous avons montré qu'un processeur pouvait avoir plus de ports d'émission que de ports de décodage. On dit aussi que sa ''largeur de décodage'' était supérieure à sa ''largeur d'émission''. La '''largeur de décodage''' est le nombre de µops fournies par l'unité de décodage par cycle d'horloge, la '''largeur d'émission''' est le nombre maximal de µops émises par cycle d'horloge. Et n'allez pas croire qu'un surplus de ports d'émission est du gâchis. Sur les processeurs avec exécution dans le désordre, ce surplus peut être utilisé. Mais avant toute chose, évacuons un détail. Vous avez sans doute pensé que le surplus peut être exploité par les instructions machines décodées en plusieurs µops . Par exemple, si une instruction est décodée en deux µops, on pourrait avoir un port d'émission en plus pour en profiter. Mais les ports de décodage sont *en sortie du décodeur*, et contiennent des µops, pas des instructions. Le surplus de ports d'émission peut occasionnellement utiliser le surplus de ports de décodage, mais cela implique que des µops ont été mises en attente dans l'unité d'émission, pour être émises par la suite. Et cela implique l'usage d'une fenêtre d'instruction ou d'une file de µops. Le principe est que les µops sont accumulées dans la fenêtre d'instruction, en attendant leurs opérandes ou la résolution d'une dépendance. Et si l'occasion se présente, une µops est émise sur chaque port d'émission. Il y a donc un gain en performances, mais il faut faire quelques précisions sur son origine. La largeur d'émission utilisée ne peut pas dépasser, *en moyenne*, la largeur de décodage. Et c'est intuitif : un CPU qui décode 4 µops par cycle ne peut pas émettre 6 par cycle en moyenne, sur le temps long, il n'y a pas de µops en surplus qui sortent du vide. Par exemple, sur un processeur quadruple émission, si on analyse combien d'instructions sont émises par cycle, il peut y avoir des cycles où la largeur d'émission est totalement utilisée, mais ce sera compensé par des périodes où elle est fortement sous-utilisée. Les µops sont accumulées en cas de sous-utilisation, puis consommées en cas d'utilisation complète. Les deux périodes se compensent. Et c'est là que l'on peut comprendre d'où vient le gain en performance. Les cycles où les ports d'émission sont sous-utilisés existent systématiquement, que le processeur utilise l'exécution dans le désordre ou pas. Ils sont liés à la présence de dépendances de données, aux contraintes d’appariement, etc. Elles tendent à réduire la moyenne du nombre de µops émises par cycle. Par contre, ce sont les cycles de rattrapage, où les ports en surplus sont utilisés, qui font remonter la moyenne. Le gain en performance est donc lié à ces cycles de rattrapage, où les µops accumulées sont émises dans les ports en surplus. Et ils n'existent que sur les processeurs avec une file/fenêtre d'instruction. Réduire le nombre de ports d'émission permet de garder des fenêtres d'instruction et un ROB simples, rapides et économes en énergie. Et mine de rien, c'est là un compromis important : à quoi bon augmenter le nombre de ports d'émission si c'est pour que ce soit compensé par une fréquence plus faible ? Par contre, réduire le nombre de ports augmente la ''port contention'', surtout si on a mal réparti les ALU. Il faut donc trouver un compromis entre réduire le nombre de ports d'émission d'un côté, réduire la ''port contention'' de l'autre. La différence entre largeur de décodage et d'émission a un impact assez fort sur le banc de registre, et précisément sur son nombre de ports de lecture. Le banc de registre a besoin de plus de ports de lecture avec une fenêtre d’instruction qu'avec des stations de réservation. Rappelons la terminologie utilisée dans ce cours. Les fenêtres d'instruction se contentent de mémoriser la micro-opération et quelques bits pour détecter la disponibilité des opérandes. Par contre, les stations de réservations mémorisent aussi les opérandes des instructions. Et cette différence a une influence le nombre de ports de lecture du banc de registre. Supposons que toutes les instructions sont dyadiques, à deux opérandes. Comptons le nombre de ports nécessaires pour alimenter les unités de calcul, sans utiliser d'arbitre de banc de registre. Avec une fenêtre d'instruction, il faut le double du nombre de ports d'émission. Mais avec des stations de réservation, il faut le double des ports de décodage. La raison est que les registres sont lus après émission avec une fenêtre d'instruction, avant avec des stations de réservation (sous-entendu, après le décodage). Or, comme dit plus haut, les processeurs superscalaires larges ont souvent plus de ports d'émission que de décodage. ===La superscalarité à fenêtres d'instruction décentralisées=== Les processeurs précédents utilisaient une unité d'émission simple, qui pouvait utiliser l'émission dans l'ordre ou dans le désordre. Elle peut être remplacée par une fenêtre d'instruction centralisée dans que cela quoi que ce soit aux explications précédentes, idem avec une station de réservation centralisée. En soi, l'exécution dans le désordre est donc totalement compatible avec une implémentation simple de la superscalarité. Par contre, des subtilités surviennent avec les fenêtres d'instruction décentralisées. Pour rappel, sur ces processeurs, les µops sont émises en deux phases. Une première phase de ''dispatch'' qui envoie les µops vers la fenêtre d'instruction adéquate, sans détecter les dépendances de données. La seconde phase de ''schedule'' gère les dépendances de données, elle met en attente les µops en attendant que l'unité soit disponible pour les exécuter, en attendant aussi que les opérandes soient disponibles. Et à ce petit jeu, il y a une différence entre le nombre de µops qui sont ''dispatch par cycle'' et celles qui sont ''schedule''. Dit autrement, la largeur d'émission est scindée en une '''largeur de ''dispatch''''' et une '''largeur de ''schedule''. Par exemple, prenons un processeur triple émission avec deux stations de réservation : une pour les µops entières/mémoire, et une autre pour les µops flottantes. L'unité d'émission peut ''dispatch'' maximum trois µops par cycle : soit trois µops entières/mémoire, soit trois flottantes, soit un mix de trois µops différentes. Les stations de réservation, quant à elles, peuvent chacune ''schedule'' 3 µops par cycle, vers trois ALUs entières pour la station de réservation entière/mémoire, vers trois FPS pour la station de réservation flottante. De quoi ''dispatch'' trois µops, mais d'en ''schedule'' six, à chaque cycle. Et cet exemple ne sort pas de nulle part : les CPU x86 d'Intel et AMD sont globalement dans ce cas, même si les chiffres varient d'une microarchitecture à l'autre. L'exemple précédent colle parfaitement à la microarchitecture K7 d'AMD, utilisée sur les processeurs Athlon dans les années 2000. [[File:AMD K7.png|centre|vignette|upright=2.5|AMD K7, microarchitecture.]] L'exemple précédent avait assez d'unités entières/flottantes pour couvrir toute la largeur de décodage/''Dispatch''. Mais ce n'est pas toujours le cas, comme va le montrer l'exemple suivant. Le MIPS R10000, qui utilisait un mélange de files de µops et de fenêtres d'instructions : une file de µops les accès mémoire, une fenêtre pour les instructions entières et une autre pour les opérations flottantes. Les branchements et NOPs étaient exécutés dans une unité de branchement distincte. Les trois files/fenêtres peuvent mémoriser 16 µops. Le processeur avait deux ALU entières, une AGU de calcul d'adresse, un additionneur flottant et un multiplieur/diviseur flottant. Il y avait un multiplieur entier sur le port d'émission l'ALU 2. Le processeur décodait 4 instructions par cycle et produisait jusqu'à 4µops, qui étaient redistribuées sur les trois fenêtres d'instructions. Chacune pouvait accepter 4 µops par cycle, ce qui fait que processeur pouvait ''dispatch'' 4 µops entières, ou 4 µops flottantes, ou 4 µops mémoire, ou un mélange de deux ou trois types de µops. Pour ce qui est du ''schedule'', la fenêtre d'instruction entière pouvait émettre 2 µops, la fenêtre flottante pouvait émettre une addition en même temps qu'une multiplication/divison flottante et qu'un branchement conditionnel flottant, et la file de µops mémoire ne pouvait émettre qu'une µop mémoire à la fois. En tout, cela fait 6 µops ''schedule'' pour 4 µops au ''dispatch''. [[File:R 10000.png|centre|vignette|upright=2.5|MIPS R10000, microarchitecture.]] ===La superscalarité à fenêtres d'instruction totalement décentralisées=== Prenons un cas extrême de fenêtre d'instruction décentralisée : celui où chaque ALU entière a sa propre station de réservation. En clair : une fenêtre d'instruction par ALU/FPU ! On parle de '''fenêtres d'instruction totalement décentralisées'''. Vous vous dites que ce cas est un peu trop extrême pour être réaliste, mais il n'en est rien. C'est même très courant sur les architectures basse consommation, et sur pas mal de CPU x86 modernes. Une telle organisation entraine une légère perte de performance, comparé à une fenêtre d'instruction centralisée ou partiellement décentralisée. Et cela peut se comprendre par un exemple. Imaginez un processeur avec deux ALU, donc deux stations de réservation. Il arrivera qu'une station de réservation ait plusieurs µops prêtes, alors que l'autre en ait zéro. Dans une telle situation, une seule µop sera émise au cycle suivant, vu que chaque station de réservation a un seul port d'émission vers une seule ALU entière. Par contre, avec une fenêtre d'instruction centralisée double port, on aurait pu émettre les deux µops en même temps sur deux ALUs séparées. La perte de performance est donc liée au fait que les µops '''''prêtes''''' sont mal réparties dans les différentes stations de réservation. Il arrivera que des µops prêtes s'accumulent dans une station de réservation, alors que d'autres seront pleines, ou du moins sous-utilisées. Et ce n'est pas quelque chose qui peut être réglé à l'étape de ''dispatch'', car on ne sait pas encore quand les µops auront leurs opérandes de disponibles. [[File:Comparaison entre une station de réservation totalement décentralisée et une autre qui ne l'est pas.png|centre|vignette|upright=2.5|Comparaison entre une station de réservation totalement décentralisée et une autre qui ne l'est pas.]] Par contre, décentraliser totalement les fenêtres d'instruction entraine aussi un gain considérable en termes de consommation énergétique. Et c'est la raison pour laquelle les fenêtres d'instructions totalement décentralisées sont utilisées sur les architectures basse consommation. La perte de performance ne peut pas s'expliquer clairement à ce stade du cours, car il nous faudrait parler d'émission superscalaire. Le gain en matière d'énergie vient de l'économie de circuits, qui est assez drastique. Le gain en matière d'énergie vient de l'économie de circuits, qui est assez drastique. Je rappelle qu'une station de réservation a besoin, pour N instructions, d'environ N^2 circuits (des comparateurs, notamment). Prenons une station de réservation centralisée de 64 entrées et comparons avec 8 stations de 8 entrées chacune. Les deux donneront 64 entrées, mais la première aura un cout en circuit proportionnel à 64², alors que le second aura un cout en circuit de 8 *(8²). Entre les deux, le choix est clair : la seconde solution est plus économe. D'où l'utilisation de cette solution sur les microarchitectures basse consommation. ===L'unité de renommage superscalaire=== Avec la superscalarité, l'unité de renommage de registre doit gérer le cas où des instructions consécutives ont des dépendances de registre. Par exemple, prenons un processeur à double émission, qui renomme deux instructions consécutives. Si elles ont une dépendance de registre, le renommage de la seconde instruction dépend du renommage de la première. La première doit être renommée et le résultat du renommage est utilisé pour renommer la seconde, ce qui empêche d'utiliser deux unités de renommage séparées. Pour cela, elle renomme les registres sans tenir compte des dépendances, pour ensuite corriger le résultat. [[File:Unité de renommage superscalaire.png|centre|vignette|upright=2|Unité de renommage superscalaire.]] Seules les dépendances lecture-après-écriture doivent être détectées, les autres étant supprimées par le renommage de registres. Repérer ce genre de dépendances se fait assez simplement : il suffit de regarder si un registre de destination d'une instruction est un opérande d'une instruction suivante. [[File:Détection des dépendances sur un processeur superscalaire.png|centre|vignette|upright=2|Détection des dépendances sur un processeur superscalaire.]] Ensuite, il faut corriger le résultat du renommage en fonction des dépendances. Si une instruction n'a pas de dépendance avec une autre, on la laisse telle quelle. Dans le cas contraire, un registre opérande sera identique avec le registre de destination d'une instruction précédente. Dans ce cas, le registre opérande n'est pas le bon après renommage : on doit le remplacer par le registre de destination de l'instruction avec laquelle il y a dépendance. Cela se fait simplement en utilisant un multiplexeur dont les entrées sont reliées à l'unité de détection des dépendances. On doit faire ce replacement pour chaque registre opérande. [[File:Correction des dépendances sur un processeur superscalaire.png|centre|vignette|upright=2|Correction des dépendances sur un processeur superscalaire.]] ==Les optimisations des processeurs superscalaires larges== Les processeurs superscalaires larges ont des optimisations spécifiques, qui n'ont pas de sens sur les processeurs superscalaires étroits. Dans les grandes lignes, elles se classent en deux types. Les premières permettent de charger/décoder plus de 5-10 instructions simultanément. Le problème est alors que les branchements viennent mettre leur grain de sel et qu'il faut en tenir compte. Les secondes corrigent des problèmes qui apparaissent quand un CPU intègre plus de 5 à 10 unités de calcul. ===L'étape de chargement d'un CPU superscalaire large=== Charger plusieurs instructions pose de nombreux problèmes sur les processeurs superscalaires larges, qui émettent de 5 à 10 instructions simultanées. Pour rappel, la stratégie basique pour charger N instructions est de charger un bloc de N instructions consécutives. Les instructions après un branchement ne sont pas décodées ni exécutées, ce qui entraine une petite baisse de performance. Pour un N petit, la perte de performance est mineure. Mais pour un N large, elle devient suffisamment importante pour que la conception du CPU doit alors être repensée de fond en comble. Les analyses statistiques disent qu'il y a environ un branchement tous les 4 à 6 instructions. Un CPU a donc tendance à décoder des paquets de 3 à 5 instructions consécutives, avant qu'un branchement casse la dynamique. Or, cela pose des problèmes pour utiliser plusieurs décodeurs. L'implémentation basique, qui charge N instructions consécutives pour alimenter N décodeurs, fonctionne donc jusqu'à 4/6 décodeurs. Au-delà de 5 instructions, un CPU superscalaire doit être adapté pour gérer les branchements dans les paquets d'instruction qu'il émet. Le nombre de 5 instructions ne sort donc pas de nulle part. La première solution utilise un cache de µops, avec un ''front-end'' capable de charger/décoder 4/5 instructions à la fois, pas plus. L'idée est que la majorité des instructions proviennent du cache de µops (plus de 80%), ce qui fait qu'on peut émettre environ 10 instructions à partir du cache de µops, pas besoin d'avoir beaucoup de décodeurs. Les performances sont cependant dégradées lors d'un défaut de cache de µops. Les instructions doivent alors être chargées depuis le cache d'instruction, par paquets de 4-5, puis sont décodées par 4-5 décodeurs, ce qui ne permet pas d’alimenter les unités de calcul à plein régime. La solution précédente joue sur la distinction entre pots de décodage et d'émission. Elle permet d'émettre un grand nombre de µops sans pour autant charger un grand nombre d'instructions en même temps. En quelque sorte, ce n'est qu'une méthode de contournement, le CPU superscalaire reste de type étroit. Mais il est aussi possible d'utiliser un '''''front-end large''''', capable de charger une bonne dizaine d'instructions en même temps. La seule difficulté est de tenir compte de la présence de branchements. Pour rappel, avec un ''front-end'' étroit, les instructions situées après le premier branchement pris sont annulées, elles ne sont pas décodées ni exécutées. [[File:Fetch sur un processeur superscalaire avec prediction de branchements.png|centre|vignette|upright=2|Fetch sur un processeur superscalaire avec prédiction de branchements.]] Un ''front-end'' large charge les instructions de destination du branchement et les placent à sa suite. Ils chargent deux blocs à la fois et les fusionnent en un seul qui ne contient que les instructions présumées utiles. [[File:Cache d'instructions autoaligné.png|centre|vignette|upright=2|Cache d'instructions auto-aligné.]] Mais cela demande de charger deux blocs de mémoire en une fois, ce qui demande un cache d'instruction multiports. Il faut aussi ajouter un circuit pour assembler plusieurs morceaux de blocs en un seul : le fusionneur (''merger''). En pratique, cette solution demande d'ajouter un second port de lecture au cache, pour un cout en hardware important, avec un impact négatif sur le temps d'accès au cache. Et il faut rajouter le fusionneur, qui prend un étage de pipeline à lui tout seul. Et encore, cette solution ne gère pas le cas où un bloc contient plusieurs branchements ! [[File:Implémentation d'un cache d'instructions autoaligné.png|centre|vignette|upright=2|Implémentation d'un cache d'instructions auto-aligné.]] Les exemples précédents partent du principe qu'il n'y a qu'un seul branchement dans un bloc. Mais quand les blocs deviennent assez longs, il est fréquent d'avoir plusieurs branchements dans un bloc. Et il est même possible d'avoir plusieurs branchements pris. Dans un bloc de 8-10 instructions, ce n'est pas rare, et les CPU superscalaires à 8-10 voies sont la règle dans les CPU des années 2020. Pour gérer ce cas, il faut ajouter des ports supplémentaires au cache d'instruction et adapter le fusionneur, pour qu'il puisse fusionner trois ou quatre blocs. De plus, il faut utiliser une unité de prédiction de branchement capable de ''prédire plusieurs branchements par cycle''. ===Le décodage superscalaire large=== Le décodage des instructions n'est pas censé dépendre de l'implémentation du chargement. En théorie, une fois plusieurs blocs d'instruction fusionnés, on peut décoder les instructions en parallèle. Cependant, certains processeurs effectuent le décodage en tenant compte de la manière dont les branchements découpent les blocs. Les processeurs Atom d'Intel utilisent une solution de ce type, qui couple prédiction de branchement et décodage parallèle. Ils chargent/décodent des paquets de 3 instructions consécutives, chaque paquet étant séparé du précédent par un branchement. Pour cela, en plus d'avoir un fusionneur adapté, ils regroupent les décodeurs en ''clusters'', chacun regroupant 3 décodeurs, et pouvant décoder trois instructions consécutives. Les micro-architectures Tremont et Crestmont avaient deux ''clusters'' (6 décodeurs au total), la micro-architecture Darkmont en intègre trois (9 décodeurs au total). Avec deux ''clusters'', le fonctionnement est le suivant. Si le code est composé d'une suite d'instruction sans branchements, seul le premier ''cluster'' est utilisé, limitant le décodage à trois instructions par cycle. Par contre, si l'une des trois instructions décodée est un branchement, alors le second ''cluster'' décode les trois instructions situées après ce branchement, à partir de l'adresse de destination. Avec un troisième ''cluster'', c'est la même chose, sauf qu'il faut qu'il y ait un branchement dans les trois instructions décodées par le second ''cluster''. Mais comment faire pour savoir quels décodeurs activés, quels ''clusters'' sont actifs ? C'est la prédiction de branchement qui commande. Avec deux ''clusters'', elle détermine si un branchement est présent dans les trois instructions à charger, et quelle est son adresse de destination. Sans branchement, elle prévient les décodeurs et les trois instructions chargées sont décodées dans un ''cluster'' libre. Si elle prédit un branchement, elle charge les instructions adéquates, et active les deux ''clusters''. Avec trois branchements, c'est le même mécanisme, sauf que l'unité de prédiction de branchement doit être capable de prédire deux branchements par cycle. [[File:Front-end découplé de la microarchitecture Tremont.png|centre|vignette|upright=3|Front-end découplé de la microarchitecture Tremont.]] Il faut noter que les décodeurs d'un ''cluster'' sont des décodeurs simples, sans microcode. Sur les processeurs Tremont et Crestmont, le microcode était unique et était partagé entre tous les ''clusters''. Un seul ''cluster'' pouvait décoder une instruction complexe avec le microcode, l'autre devait se limiter à des instructions simples uniquement. Depuis Skymont, le microcode est partiellement dupliqué, avec un microcode par ''cluster''. Le cout en hardware peut paraitre prohibitif, pour un gain en performance faible. Sauf que c'est oublier que ce sont des processeurs Atom, sur lesquels beaucoup d'instructions sont microcodées. Les processeurs Atom ont un budget en transistor limité, ce qui fait qu'il est préférable pour eux d'implémenter des instructions en microcode que d'utiliser des unités de calcul dédiées ou des circuits de décodage complexes. Pour limiter la casse, le microcode n'est que partiellement dupliqué. Seul le microcode pour les instructions fréquente est dupliqué. Il y a un microcode secondaire pour certaines instructions, qui est lui unique et partagé par tous les ''clusters''. ===Le contournement sur les processeurs superscalaires larges=== Pour rappel, la technique du contournement (''register bypass'') permet au résultat d'une instruction d'être immédiatement utilisable en sortie de l'ALU, avant même d'être enregistré dans les registres. Implémenter la technique du contournement demande d'utiliser des multiplexeurs pour relier la sortie de l'unité de calcul sur son entrée si besoin. Il faut aussi des comparateurs pour détecter des dépendances de données. [[File:Pipeline Bypass.png|centre|vignette|upright=1|Pipeline Bypass]] La sortie de chaque ALU doit être reliée aux entrées de toutes les autres, avec les comparateurs qui vont avec. Sur les processeurs ayant plusieurs d'unités de calculs, cela demande beaucoup d’interconnexions et de comparateurs. Pour N unités de calcul, cela demande 2 * N² interconnexions, implémentées avec 2N multiplexeurs de N entrées chacun. Si c'est faisable pour 2 ou 3 ALUs, la solution est impraticable au-delà. Non seulement ce serait un enfer à câbler, mais les fils seraient tellement longs que la fréquence du processeur en prendrait un coup. Notez que cela vaut pour les processeurs superscalaires, mais aussi pour tout processeur avec beaucoup d'unités de calcul. En théorie, un CPU à exécution dans le désordre, non-superscalaire, mais avec beaucoup d'unités de calcul, fait face au même problème. En pratique, avoir une dizaine d'ALU implique processeur superscalaire à exécution dans le désordre. D'où le fait qu'on parle du problème maintenant. La seule solution praticable est de ne pas relier toutes les unités de calcul ensemble. À la place, on préfère regrouper les unités de calcul dans différents '''agglomérats''' ('''cluster'''). Le contournement est alors possible entre les unités d'un même agglomérat, mais pas entre agglomérats différents. Évidemment, certaines possibilités de contournement sont perdues, mais c'est compensé par un gain en fréquence et un cout en circuit/fils réduit. C'est un bon compromis, ce qui explique que presque tous les processeurs modernes l'utilisent. Les rares exceptions sont les processeurs POWER 4 et POWER 5, qui ont préféré se passer de contournement pour garder un processeur très simple et une fréquence élevée. ===Le banc de registre des processeurs superscalaires larges=== Pour émettre deux opérations entières simultanément, il faut lire deux fois plus d'opérandes. Et il faut aussi écrire deux résultats dans les registres, en même temps. Pour cela, on double les ports du banc de registre. En général, il faut au maximum 2 ports de lecture et un port d'écriture par unité de calcul. Le problème, c'est que plus un banc de registres a de ports, plus il utilise de circuits, est compliqué à concevoir, consomme de courant et chauffe. Avec plusieurs dizaines d'unités de calcul différentes, ajouter autant de ports impacterait la fréquence du banc de registres et réduirait les performances, voire est totalement impraticable à cause des contraintes thermiques. Les processeurs superscalaires larges doivent donc trouver des solutions. La première solution utilise un banc de registre unique, mais n'utilise pas autant de ports que le pire des cas le demanderait. Le processeur détecte quand il n'y a pas assez de ports pour servir toutes les micro-opérations. Quand ça arrive, l'unité d'émission émet assez de micro-opérations pour exploiter les ports disponibles, mais met en attente les micro-opérations en trop, le temps que les ports se libèrent. Pour cela, le banc de registre est géré par un circuit d'arbitrage spécialisé, intégré à l'unité d'émission, l’'''arbitre du banc de registres''' (''register file arbiter''). Une autre solution est de dupliquer le banc de registres en plusieurs exemplaires qui contiennent exactement les mêmes données, mais avec moins de ports de lecture/écriture. Un exemple est celui des processeurs POWER, Alpha 21264 et Alpha 21464. Sur ces processeurs, le banc de registre est dupliqué en plusieurs exemplaires, qui contiennent exactement les mêmes données. Les écritures dans les registres sont envoyées à tous les bancs de registres, afin de garantir que leur contenu est identique. Chaque exemplaire a exactement deux ports de lecture. La conception du processeur est simplifiée, que ce soit au niveau du câblage, que de la conception des bancs de registres. Une dernière solution découpe le banc de registres en plusieurs bancs de registres plus petits, avec un réseau d'interconnexions pour échanger des données entre bancs de registres. Dans la plupart des cas, cette séparation est invisible du point de vue de l'assembleur et du langage machine. Le processeur se charge de transférer les données entre bancs de registres suivant les besoins. Sur d'autres processeurs, les transferts de données se font via une instruction spéciale, souvent appelée ''COPY''. [[File:Banc de registres distribué.png|centre|vignette|upright=2|Banc de registres distribué.]] Sur de certains processeurs, un branchement est exécuté par une unité de calcul spécialisée. Or les registres à lire pour déterminer l'adresse de destination du branchement ne sont pas forcément dans le même agglomérat que cette unité de calcul. Pour éviter cela, certains processeurs disposent d'une unité de calcul des branchements dans chaque agglomérat. Dans les cas où plusieurs unités veulent modifier le ''program counter'' en même temps, un système de contrôle général décide quelle unité a la priorité sur les autres. Mais d'autres processeurs fonctionnent autrement : seul un agglomérat possède une unité de branchement, qui peut recevoir des résultats de tests de toutes les autres unités de calcul, quel que soit l’agglomérat. ==La macro-fusion : une optimisation du décodage parallèle== Les processeurs superscalaires supportent la technique dite de '''macro-fusion''', qui permet de fusionner deux-trois instructions consécutives en une seule micro-opération. Par exemple, il est possible fusionner une instruction de test et une instruction de saut en une seule micro-opération de branchement. Il s'agit là de l'utilisation la plus importante de la macro-fusion sur les processeurs x86 modernes. La macro-fusion est utilisée pour fusionner un test et un saut en un branchement unique. L'optimisation est présente sur la plupart des CPU superscalaires modernes. Les CPU x86 l'implémentent, mais aussi quelques CPU ARM et les processeurs Apple de série M (M1 à M5, et potentiellement plus quand ils seront sortis). La fusion des instructions se fait lors du décodage des instructions, grâce à la coopération des décodeurs. Elle marche systématiquement si l'instruction de test et le saut sont consécutives, qu'elles forment bien une paire d'instruction. Par contre, insérer une instruction entre les deux empêche la macro-fusion de faire son travail, sauf si l'instruction insérée est un NOP. Les processeurs ARM64 avaient une forme spécifique de macro-fusion, utilisée pour un cas très précis : charger une constante immédiate de 32 ou 64 bits, dans un registre 64 bits. Les CPU ARM 64 bits utilisent des instructions codées sur 32 bits, qui ne peuvent encoder que des constantes immédiates de 16 bits. Pour charger une constante de 32/64 bits, il faut s'y prendre en plusieurs fois. Une première instruction MOVZ charge les 16 premiers bits, puis 2 à 4 instructions MOVK remplissent le reste. MOVZ met à zéro les 48 bits de poids fort, MOVK permet de sélectionner le doublet à modifier dans le registre (on modifie 16 bits, dont on choisit la place, le reste du registre est laissé tel quel). ARM permet de fusionner cette suite d'instructions en une seule µop MOV avec une constante immédiate. On parle alors de '''''MOVZ + MOVK fusion'''''. Une dernière utilisation, [https://www2.eecs.berkeley.edu/Pubs/TechRpts/2016/EECS-2016-130.pdf proposées pour le jeu d'instruction RISC-V], fusionnait un calcul d'adresse et une instruction LOAD/STORE en une seule instruction d'accès mémoire. Elle a été envisagée à une époque où le jeu d'instruction RISC-V ne gérait pas les modes d'adressage base + indice. L'idée était d'avoir une unité mémoire qui gérait le mode d'adressage base + indice et de fusionner des instructions pour l'exploiter. Mais de nos jours, le jeu d'instruction RISC-V intègre le mode d'adressage base + indice, ce qui fait que la macro-fusion n'a aucun intérêt pour ce cas précis. La macro-fusion a de nombreuses limitations en pratique. En théorie, on pourrait l'utiliser au-delà des deux situations mentionnées plus haut. Par exemple, pour fusionner une addition et une multiplication en une seule instruction MAD. Mais l'intérêt est assez faible. Notons que la macro-fusion ne permet que de fusionner des paires d'instructions. Aller au-delà demanderait un cout en circuit trop important. Déjà que tester deux paires utilise pas mal de comparateurs... ==Le ''stack engine'' : une optimisation de la pile d'appel== Les processeurs modernes intègrent une optimisation liée au pointeur de pile. Pour rappel, sur les architectures modernes, le pointeur de pile est un registre utilisé pour gérer la pile d'appel, précisément pour savoir où se trouve le sommet de la pile. Il est manipulé par les instructions CALL, RET, PUSH et POP, mais aussi par les instructions d'addition/soustraction pour gérer des cadres de pile de taille variable. De plus, il peut servir d'opérande pour des instructions LOAD/STORE, afin de lire/écrire des variables locales, les arguments d'une fonction, et autres. C'est donc un registre général adressable, intégré au banc de registre, altéré par l'unité de calcul entière. L'incrémentation/décrémentation du pointeur de pile passe donc par l'unité de calcul, lors des instructions CALL, RET, PUSH et POP. Mais, l'optimisation que nous allons voir permet d'incrémenter/décrémenter le pointeur de pile sans passer par l'ALU, ou presque. L'idée est de s'inspirer des architectures avec une pile d'adresse de retour, qui intègrent le pointeur de pile dans le séquenceur et l'incrémentent avec un incrémenteur dédié. ===Le ''stack engine''=== L'optimisation que nous allons voir utilise un '''''stack engine''''' intégré à l'unité de contrôle, au séquenceur. Le processeur contient toujours un pointeur de pile dans le banc de registre, cela ne change pas. Par contre, il n'est pas incrémenté/décrémenté à chaque instruction CALL, RET, PUSH, POP. Un compteur intégré au séquenceur est incrémenté à la place, nous l’appellerons le '''compteur delta'''. La vraie valeur du pointeur de pile s'obtient en additionnant le compteur delta avec le registre dans le banc de registre. Précisons que si le compteur delta vaut zéro, la vraie valeur est dans le banc de registre et peut s'utiliser telle quelle. Lorsqu'une instruction ADD/SUB/LOAD/STORE utilise le pointeur de pile comme opérande, elle a besoin de la vraie valeur. Si elle n'est pas dans le banc de registre, le séquenceur déclenche l'addition compteur-registre pour calculer la vraie valeur. Finalement, le banc de registre contient alors la bonne valeur et l'instruction peut s'exécuter sans encombre. L'idée est que le pointeur de pile est généralement altéré par une série d'instruction PUSH/POP consécutives, puis des instructions LOAD/STORE/ADD/SUB utilisent le pointeur de pile final comme opérande. En clair, une bonne partie des incrémentations/décrémentation est accumulée dans le compteur delta, puis la vraie valeur est calculée une fois pour toutes et est utilisée comme opérande. On accumule un delta dans le compteur delta, et ce compteur delta est additionné quand nécessaire. Précisons que le compteur delta est placé juste après le décodeur d'instruction, avant même le cache de micro-opération, l'unité de renommage et l'unité d'émission. Ainsi, les incrémentations/décrémentations du pointeur de pile disparaissent dès l'unité de décodage. Elles ne prennent pas de place dans le cache de micro-opération, ni dans la fenêtre d'instruction, ni dans la suite du pipeline. De nombreuses ressources sont économisées dans le ''front-end''. Mais utiliser un ''stack engine'' a aussi de nombreux avantages au niveau du chemin de données/''back-end''. Déjà, sur les processeurs à exécution dans le désordre, cela libère une unité de calcul qui peut être utilisée pour faire d'autres calculs. Ensuite, le compteur delta mémorise un delta assez court, de 8 bits sur le processeur Pentium M, un peu plus pour les suivants. L'incrémentation se fait donc via un incrémenteur 8 bits, pas une grosse ALU 32/64 bits. Il y a un gain en termes de consommation d'énergie, un incrémenteur 8 bits étant moins gourmand qu'une grosse ALU 32/64 bits. ===Les points de synchronisation du delta=== La technique ne fonctionne que si la vraie valeur du pointeur de pile est calculée au bon moment, avant chaque utilisation pertinente. Il y a donc des '''points de synchronisation''' qui forcent le calcul de la vraie valeur. Plus haut, nous avions dit que c'était à chaque fois qu'une instruction adresse le pointeur de pile explicitement, qui l'utilise comme opérande. Les instructions CALL, RET, PUSH et POP ne sont pas concernées par elles utilisent le pointeur de pile de manière implicite et ne font que l'incrémenter/décrémenter. Mais dans les faits, c'est plus compliqué. D'autres situations peuvent forcer une synchronisation, notamment un débordement du compteur delta. Le compteur delta est généralement un compteur de 8 bits, ce qui fait qu'il peut déborder. En cas de débordement du compteur, le séquenceur déclenche le calcul de la vraie valeur, puis réinitialise le compteur delta. La vraie valeur est donc calculée en avance dans ce cas précis. Précisons qu'un compteur delta de 8 bits permet de gérer environ 30 instructions PUSH/POP consécutives, ce qui rend les débordements de compteur delta assez peu fréquent. À noter que si le compteur delta vaut zéro, il n'y a pas besoin de calculer la vraie valeur, le séquenceur prend cette situation en compte. Un autre point de synchronisation est celui des interruptions et exceptions matérielles. Il faut que le compteur delta soit sauvegardé lors d'une interruption et restauré quand elle se termine. Idem lors d'une commutation de contexte, quand on passe d'un programme à un autre. Pour cela, le processeur peut déclencher le calcul de la vraie valeur lors d'une interruption, avant de sauvegarder les registres. Pour cela, le processeur intègre un mécanisme de sauvegarde automatique, qui mémorise la valeur de ce compteur dans le tampon de réordonnancement, pour forcer le calcul de la vraie valeur en cas de problème. La technique du ''stack engine'' est apparue sur les processeurs Pentium M d'Intel et les processeurs K10 d'AMD, et a été conservée sur tous les modèles ultérieurs. L'implémentation est cependant différente selon les processeurs, bien qu'on n'en connaisse pas les détails et que l'on doive se contenter des résultats de micro-benchmarks et des détails fournit par Intel et AMD. Selon certaines sources, dont les manuels d'optimisation d'Agner Fog, les processeurs AMD auraient moins de points de synchronisation que les processeurs Intel. De plus, leur ''stack engine'' serait placé plus loin que prévu dans le pipeline, après la file de micro-opération. ==La micro-fusion et la délamination== La '''micro-fusion''' est une optimisation qui retarde le décodage réel de certaines instructions assez loin dans le pipeline. Elle concerne surtout les instructions ''load-op'', mais pas que. D'autres instructions mémoire peuvent subir cette optimisation. L'essentiel est que, sans micro-fusion, ces instructions sont décodées en plusieurs micro-opérations. La micro-fusion retarde le décodage final de ces instructions, qui se fait assez tard dans le pipeline. Pour comprendre l'intérêt, nous allons devoir faire quelques explications. L'optimisation en question fait le décodage en deux temps. Prenons l'exemple d'une opération ''load-op'', qui est censée être décodée en deux micro-opérations : une lecture, puis une opération. Le décodage produit une '''macro-opération''' (terme d'Intel), qui est propagée dans le pipeline, pour être scindée en deux micro-opérations un peu avant les ALU et l'unité mémoire. La macro-opération est techniquement une micro-opération comme une autre, sauf que ce n'est pas la micro-opération finale. L'unité d'émission découpe cette macro-opération en deux micro-opérations, qui sont émises l'une après l'autre. Pour résumer, les instructions ''load-op'' ne sont complétement découpées en micro-opération lors de l'émission, pas lors du décodage. L'optimisation impacte ce qui se situe entre le décodeur d'instruction et l'unité d'émission : l'unité de renommage, la file de micro-opérations, le ''Loop Stream Detector'' et/ou le cache de micro-opération. L'intérêt de l'optimisation est que l'on fusionne deux micro-opérations en une seule macro-opération. Le cache de micro-opération et la file de micro-opération peuvent mémoriser plus de micro-opérations, vu que certaines sont fusionnées. Quant à l'unité de renommage, elle renomme une seule macro-opération au lieu de renommer deux micro-opérations, ce qui augmente le débit du renommage de registre. Par contre, cela complique un peu le travail de l'unité d'émission, qui doit découper les instructions ''load-op'' en deux et émettre les micro-opérations l'une après l'autre. Il faut noter qu'il n'y a pas de fusion proprement dite. Le décodeur ne décode pas deux micro-opérations séparées, avant de les fusionner. En réalité, il génère directement une macro-opération, qui correspond à deux micro-opérations, que ce soit plus tard dans le pipeline ou sur une autre architecture. D'ailleurs, la micro-fusion a lieu à l'intérieur d'une instruction, qui est censée être traduite en plusieurs micro-opérations. Et encore : pas toutes. La conséquence est que la technique n'a de sens que sur les processeurs CISC, avec des instructions assez complexes pour être décodées en plusieurs micro-opérations. En pratique, seuls les CPU x86 sont concernés. ===Les domaines de fusion=== La micro-fusion n'est pas spécifique aux processeurs superscalaires. En théorie, on peut l'implémenter sur un processeur non-superscalaire à émission dans l'ordre. Cependant, je ne connais aucun processeur à émission dans l'ordre qui implémente la micro-fusion, même si son implémentation est en théorie possible sur de tels processeurs. La micro-fusion est implémentée différemment selon que l'émission se fasse dans l'ordre, dans le désordre, avec une fenêtre d'instruction, avec des stations de réservation, etc. J'ai dit plus haut que les micro-opérations sont générées lors de l'émission, mais le moment exact varie suivant le processeur. Pour simplifier le tout, nous parlerons de '''scission''' quand le processeur traduit une macro-opération en deux/trois micro-opérations. Le moment où a lieu la scission est théoriquement dans l'unité d'émission, mais celle-ci prend plusieurs formes selon que le processeur utilise l'émission dans l'ordre, dans le désordre, avec une fenêtre d'instruction, avec des stations de réservation, etc. Les processeurs à exécution dans l'ordre sont le cas le plus simple. L'unité d'émission est alors en charge du découpage des macro-opérations en micro-opérations. La file de micro-opération ou le cache de micro-opérations mémorisent des macro-opérations. À l'opposé, le tampon de ré-ordonnancement mémorise lui des micro-opérations. Le reste du processeur n'est pas affecté. Sur les processeurs à exécution dans le désordre, les différences sont nombreuses. Le tampon de ré-ordonnancement peut mémoriser soit les micro-opérations finales, soit des macro-opérations. Il en est de même avec la fenêtre d'instruction et/ou les stations de réservation, qu'elles soient centralisées ou décentralisées. Tout dépend de comment se fait l'implémentation. Une implémentation simple effectue la scission des macro-opérations dans l'unité d'émission, comme sur les processeurs à exécution dans l'ordre. Sur de nombreux processeurs, l'unité d'émission et de renommage sont simplement fusionnées, ce qui fait que la scission a lieu juste après le renommage de registres. En conséquence, le tampon de re-ordonnancement et les fenêtres d'instruction ne voient que des micro-opérations. Les macro-opérations disparaissent juste avant. Cette implémentation est préférée avec une fenêtre d'instruction centralisée, car on voit mal comment scinder une macro-opération juste avant l'ALU. Une autre implémentation fait la scission en sortie de la fenêtre d'instruction ou des stations de réservation, qu'elles soient centralisées ou décentralisées. Dans ce cas, le tampon de re-ordonnancement fait de même. L'avantage est que le tampon de ré-ordonnancement stocke des macro-opérations, ce qui augmente sa taille effective. Par exemple, il utilise une seule entrée pour une instruction ''load-op'', au lieu de deux sans micro-fusion de ce type. ===La délamination=== La scission peut parfois avoir lieu plus tôt, dans des circonstances très précises. Concrètement, cela ne concerne que quelques micro-architectures d'Intel, pour des instructions très précises. La raison est les limitations du format des micro-opérations, pas une histoire d'optimisation. Le processeur aimerait pouvoir faire la micro-fusion, mais ne peut pas à cause de ces limitations. Une telle situation cause alors une '''délamination''' : les micro-opérations sont scindées précocement. Par exemple, sur la micro-architecture SandyBridge d'Intel, les opérations ''load-op'' sont fusionnées, sauf si elles utilisent l'adressage indicé. Les micro-opérations de ce processeur ne peuvent avoir que deux opérandes. Trois opérandes est de trop, et les opérations ''load-op'' en adressage indicé dépassent cette limite. Dans ce cas, les micro-opérations sont fusionnées en sortie du décodeur, mais sont scindés avant d’entrer dans la file de micro-opération. L'avantage n'est pas évident, vu que l'unité de renommage suit de près le décodeur d'instruction. Il est que le cache de micro-opérations mémorise des macro-opérations, pas deux micro-opérations. ===La micro-fusion des processeurs Intel et AMD=== La micro-fusion est apparue sur le Pentium M d'Intel, et a été conservée telle quelle sur les processeurs Intel suivants. Les processeurs AMD supportent la micro-fusion depuis au moins la micro-architecture AMD K8. Mieux que ça, la délamination n'était pas utilisée car les micro-opérations acceptaient plus de 2 opérandes. Que ce soit chez AMD ou Intel, elle concerne deux types d'instructions : les écritures mémoire et les instructions ''load-op''. Sur le Pentium M, il y avait quelques limitations, l'optimisation se limitant par exemple aux registres entiers et flottants, mais pas aux registres MMX, mais pas les registres SSE (nous verrons ces registres dans quelques chapitres). Mais les processeurs modernes n'ont plus cette limitation. La micro-fusion des CPU Intel concerne deux types d'instructions : les écritures mémoire et les instructions ''load-op''. Pour les écritures, la situation est plus complexe que pour les instructions ''load-op''. Sur les processeurs Intel précédents, les écritures étaient réalisées dans deux unités séparées : le calcul d'adresse dans une unité de calcul, l'écriture proprement dite dans l'unité mémoire. Elles prenaient donc deux micro-opérations. Le processeur a changé ses unités mémoire, ce qui fait qu'elle pouvait faire les deux en une seule micro-opération. Il s'agissait alors d'une optimisation du chemin de données, plus que de la micro-fusion proprement dite, mais je la mentionne ici malgré tout. La micro-fusion sur ce processeur avait un avantage en plus des avantages usuels : elle utilisait mieux les décodeurs. Les Pentium M avaient trois décodeurs pour décoder plusieurs instructions en même temps, chose qu'on détaillera dans le chapitre sur les processeurs superscalaires. Un seul décodeur pouvait décoder toutes les instructions, les deux autres ne peuvent décoder que les instructions simples, qui se décodent en une seule micro-opération. Avec la micro-fusion, les trois décodeurs peuvent gérer les écritures mémoire et les opérations ''load-op'', vu qu'elles deviennent des instructions simples. Sans cela, elles auraient été limitées au premier décodeur. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Le parallélisme mémoire | prevText=Le parallélisme mémoire | next=Les microarchitectures pour le x86 : haute performance | nextText=Les microarchitectures pour le x86 : haute performance }} </noinclude> 319cm9blyuqodrxju71ipu00qyngh6p 773583 773582 2026-09-29T16:52:32Z Mewtow 31375 /* L'exemple du PA-RISC PA 8000 */ 773583 wikitext text/x-wiki Les processeurs vus auparavant ne peuvent émettre au maximum qu'une instruction par cycle d'horloge. Ils peuvent avoir plusieurs instructions qui s'exécutent en même temps, dans des unités de calcul séparées. C'est le cas dès qu'une instruction multi-cycles s'exécute. Par contre, ils ne peuvent démarrer qu'une seule instruction par cycle. Et quand on court après la performance, ce n'est pas assez ! Les concepteurs de processeurs ont inventés des processeurs qui émettent plusieurs instructions par cycle : les '''processeurs à émissions multiples'''. Un processeur à émission multiple charge plusieurs instructions en même temps, les décode en parallèle, puis les émet en même temps sur des unités de calculs séparées. Pour cela, il faut gérer les dépendances entre instructions, répartir les instructions sur différentes unités de calcul, et cela n'est pas une mince affaire. En général, pour un processeur à émission multiple capable d'émettre N instructions en parallèle, on parle de '''processeur à N voies''', ou encore un ''processeur à N pipelines''. [[File:Superscalarpipeline.svg|centre|vignette|upright=1.5|Pipeline RISC classique à cinq étages sur un processeur superscalaire. On voit bien que plusieurs instructions sont chargées en même temps.]] Les processeurs à émission multiple sont de deux types : les processeurs VLIW et les '''processeurs superscalaires'''. Nous mettons les processeurs VLIW de côté en attendant le prochain chapitre. La raison est qu'ils ont un jeu d'instruction spécialisé qui expose le parallélisme d'instruction directement au niveau du jeu d'instructions, là où les processeurs superscalaires restent des processeurs au jeu d'instruction normal. La différence principale entre processeur VLIW et superscalaire est qu'un processeur superscalaire répartit les instructions sur les unités de calcul à l’exécution, là où un processeur VLIW délègue cette tâche au compilateur. ==Le nombre de voies d'un processeur superscalaire== Les processeurs superscalaires les plus simples ne permettent que d'émettre deux micro-opérations à la fois, d'où leur nom de processeur ''dual issue'', ce qui se traduit en '''processeur à double émission'''. Les processeurs triple émission permettent eux d’émettre trois instructions à la fois. A l'opposé, les CPU superscalaires les plus puissants peuvent émettre jusqu'à 8-10 instructions simultanément. En 2026, les CPU superscalaires peuvent monter jusqu’à 10 µops émises en même temps, ce qui est énorme ! Et cela nous amène à faire une distinction entre les processeurs superscalaires dits '''étroits''' et ceux dits '''larges'''. Dans ce wikilivre, on part du principe que les processeurs superscalaires étroits émettent jusqu'à 4-5 µops à la fois, alors que les larges peuvent en émettre plus, l'intervalle entre les deux est une zone grise. Le nombre exact n'est pas fixé dans le marbre, la distinction est volontairement vague. Nous parlerons de la '''largeur d'un CPU superscalaire''' pour parler du nombre de voies, du nombre de µops émises en même temps. Plus un CPU superscalaire est large, plus il est performant ''toute chose égale par ailleurs''. Mais dans les faits, vous pouvez oublier la partie en italique. Élargir un CPU superscalaire demande de rajouter beaucoup de circuits. Et ce cout en circuit aura un impact sur la performance. A budget en transistors limité, il y a un compromis entre élargir un CPU et rajouter du cache ou la taille des fenêtres d'instructions/ROB et autres. ===Les contraintes d’appariement=== Prenons un processeur double émission, capable d'émettre deux instructions simultanément. Émettre deux instructions en même temps n'est pas toujours possible. Par exemple, si deux instructions sont dépendantes, on ne peut pas les émettre en même temps. Mais oublions un instant ces histoires de dépendances de données, et partons du principe que le CPU ait affaire à deux instructions indépendantes, une paire idéale. Un CPU double émission "parfait" pourrait exécuter n'importe quelle paire d'instruction. Par exemple, il pourrait émettre deux multiplications consécutives, deux lectures consécutives, une lecture et une écriture en même temps, etc. En pratique, aucun processeur ne permet cela. Implémenter un CPU superscalaire "parfait" aurait un cout en circuit beaucoup trop conséquent. Par exemple, pour émettre deux multiplications en même temps, il faudrait deux multiplieurs séparés. Idem pour exécuter deux accès mémoire simultané : cela demande d'avoir deux unités mémoire et un cache multiport. Mais en pratique, aucun CPU superscalaire ne fait cela. La totalité des CPU double émission se débrouille avec un seul circuit multiplieur et une seule unité mémoire. Et cela entraine l'apparition de dépendances structurelles, qui font que certaines paires d'instructions sont impossibles. Par exemple, impossible d'émettre deux multiplications en même temps avec un seul circuit multiplieur. Mais émettre une multiplication en parallèle d'une addition est parfaitement possible. Il y a donc des paires d'instructions autorisées et des paires interdites. Et la logique est la même sur les CPU à triple ou quadruple émission, et au-delà. : des triplets ou quadruplet d'instructions sont impossibles à émettre simultanément, alors que d'autres le sont. Pour le dire autrement, il y a des '''contraintes d'appariement''' sur les instructions à émettre en même temps. ===L'impact des contraintes d’appariement sur la performance=== Ces contraintes d’appariement ont un impact sur les performance, mais celui-ci peut être grandement mitigé. Les programmes informatiques utilisent en pratique beaucoup plus d'opérations entières de base que de multiplication, branchements et accès mémoire. Il y a environ 5 opérations entières de base pour une multiplication entière. En pratique, il est rare de devoir exécuter deux multiplications à la fois. Idem pour les décalages et rotations, qui sont assez éloignés les uns des autres. Deux branchements consécutifs sont quant à eux plus fréquents. Deux accès mémoire consécutifs est assez rare, mais ils restent assez proches les uns des autres malgré tout. La conséquence est que certaines paires d'instructions sont privilégiées par rapport au reste. Les paires regroupant deux calculs basiques (additions, soustractions, ...) sont systématiquement supportées, car dupliquer des ALU entières est facile. Les paires regroupant un calcul et une autre instruction sont elles aussi systématiquement supportées. Par contre, les paires avec deux branchements, deux accès mémoire, deux décalages/rotations, ou deux multiplications/divisions sont fréquemment interdites. Seuls les CPU superscalaires larges peuvent les permettre, et encore : sous conditions. Le résultat est que le processeur peut se débrouiller avec une seule unité mémoire et une unité de branchement. ===Terminologie pour la suite du chapitre=== Décrire les contraintes d’appariement demande de dire quelles combinaisons d’instructions sont autorisées ou interdites. Et pour cela, nous allons introduire les abréviations suivantes : * INT est un raccourcis pour parler d'une opération entière simple, qu'une ALU entière peut exécuter. * MUL correspond à une opération entière complexe, typiquement une multiplication, éventuellement à une division. * FLOAT désigne une opération flottante, peut importe laquelle. * MEM désigne un accès mémoire, à savoir une instruction ou µop mémoire. * BRANCH désigne une instruction de branchement. Cette terminologie permettra de définir des paires d'instructions, qu'elles soient possibles ou interdites. Par exemple, l'expression INT + FLOAT désigne une paire d'instruction regroupant une instruction entière et une instruction flottante, peu importe l'ordre des deux instructions. Il en sera de même pour les triplets, quadruplets, ou plus. Par exemple, l'expression INT + INT + FLOAT + MUL désigne un quadruplet d'instructions regroupant : deux instructions entières, une instruction flottante, et une multiplication entière. J'utiliserais aussi des parenthèses pour regrouper certaines combinaisons. Par exemple, l'expression INT + (MUL /FLOAT) veut parler d'une paire d'instruction où la première est une opération entière basique, la seconde est : soit une multiplication, soit une opération flottante. ==Le ''front-end'' des processeurs superscalaires== Un processeur superscalaire doit charger, décoder, et exécuter plusieurs instructions par cycle. Par exemple, un processeur triple émission doit charger 3 instructions lors d'un premier cycle, puis les décoder au cycle suivant, et les exécuter au cycle suivant. Il travaille donc pas paquets de 3 instructions, dans cet exemple. Intuitivement, charger, décoder et exécuter plusieurs instructions à la fois demande de dupliquer des circuits. Par exemple, il faut dupliquer les décodeurs pour décoder plusieurs instructions. Les unités de calcul sont aussi dupliquées, sauf sur certaines processeurs qui arrivent à ruser, mais laissons cela de côté pour plus tard. Mais d'autres circuits sont simplement modifiés, comme l'unité de chargement ou l'unité d'émission. Voyons ce qu'il en est dans le détail. {|class="wikitable" |- ! rowspan="2" | Processeur sans émission multiple | rowspan="2" | Chargement | rowspan="2" | Décodage | rowspan="2" | Renommage | rowspan="2" | Émission | Exécution / ALU | rowspan="2" | ''Commit''/ROB |- | Exécution / ALU |- ! rowspan="4" | Processeur superscalaire | rowspan="4" | Chargement | rowspan="2" | Décodage | rowspan="4" | Renommage | rowspan="4" | Émission | Exécution / ALU | rowspan="4" | ''Commit''/ROB |- | Exécution / ALU |- | rowspan="2" | Décodage | Exécution / ALU |- | Exécution / ALU |} Nous allons d'abord voir ce qu'il en est pour le ''front-end'', à savoir la partie du CPU qui s'occupe de charger et décoder les instructions. Elle regroupe l'unité de chargement, les décodeurs, l'unité de prédiction de branchement, la file de µops, la file d'instruction, et divers caches. En soi, les changements portent surtout sur l'unité de chargement et les décodeurs. ===Le chargement de plusieurs instructions consécutives=== Un processeur superscalaire charge plusieurs instructions en même temps, ''en tenant compte de la présence de branchements''. La partie en italique est importante et elle a une conséquence très forte : la manière de faire est fortement différente entre un CPU superscalaire étroit et large. Un CPU superscalaire étroit fait au plus simple : il charge un bloc de 2, 3, 4 instructions consécutives en mémoire RAM. Il faut alors doubler/tripler/quadrupler la taille du bus connecté au cache d'instruction. Par exemple, pour charger quatre instructions de 32 bits chacune, il suffit de lire un bloc de 128 bits dans le cache d'instruction. Un bloc de 8, 16, 32 octets est donc lu depuis le cache et est ensuite découpé en instructions, envoyées chacun à un décodeur. Charger plusieurs instructions consécutives ne marche bien qu'en absence de branchements. La présence de branchements casse cette dynamique, et il faut gérer leur présence. * Sans prédiction de branchement, toutes les instructions d'un bloc sont décodées et exécutées en même temps, même s'il y a un branchement dans le tas. * Avec prédiction de branchement, les instructions situées après le branchement ne sont pas décodées ni exécutées. L'unité de chargement coupe le bloc chargé au niveau du premier branchement pris, remplit les vides avec des NOP, avant d'envoyer le tout à l'unité de décodage. Les instructions à l'adresse de destination seront chargées au cycle suivant, en chargeant un nouveau bloc. [[File:Fetch sur un processeur superscalaire avec prediction de branchements.png|centre|vignette|upright=2|Fetch sur un processeur superscalaire avec prédiction de branchements.]] Un autre défaut est que sur le CPU charge un bloc de 128 bits à la fois, les instructions doivent être alignées sur 128 bits. Et on peut généraliser à n'importe quelle taille de bloc. Si les instructions ne sont pas alignées, il faut gérer la situation. Il arrive qu'une instruction soit à cheval sur deux blocs, avec un morceau dans le premier bloc, un autre dans le second. Dans ce cas, l'instruction est chargée en deux fois, et des circuits doivent gérer la situation pour recoller les morceaux. Sur les CPU avec des instructions de taille fixe, le problème ne survient que rarement. Mais il est fréquent avec des instructions de taille variable. Un autre défaut est lié aux branchements. Imaginez qu'un branchement s'exécute et branche vers une instruction de destination. Rien n'indique que l'instruction de destination sera au tout début d'un bloc. Si ça se trouve, elle sera en troisième position d'un bloc de 4 instructions. Une solution simple charge le bloc en respectant l'alignement, et les deux premières instructions du bloc ne sont pas à exécuter. Il y a donc une petite perte de performance. Certains CPU, comme l'IBM RS/6000, ont la machinerie charger un bloc de N instructions même s'il n'est pas aligné. La machinerie en question se trouve dans le cache d'instruction et est tout sauf simple à expliquer,ce qui fait que je me permets de la passer sous silence. Un détail, cependant : elle ne permet pas de charger des blocs qui sont à cheval sur deux lignes de cache. ===Le décodage parallèle des instructions=== Pour le décodage des instructions, plusieurs instructions sont décodées en même temps. On parle alors de '''décodage parallèle'''. Pour ce faire, un processeur superscalaire contient plusieurs décodeurs, chacun pouvant décoder une instruction en parallèle des autres. Prenons par exemple un processeur superscalaire à 4 voies : le décodage se fera dans quatre décodeurs séparés, qui fonctionneront en parallèle. Cependant, cette implémentation ne marche bien que pour les processeurs RISC, les processeurs CISC devant faire avec un microcode gourmand en circuits. Les processeurs CISC utilisent des décodeurs hybrides, avec un microcode qui complémente un décodeur câblé. Dupliquer le microcode aurait un cout en transistors trop important, ce qui fait que seuls les décodeurs câblés sont dupliqués. Les CPU CISC superscalaires disposent donc de plusieurs décodeurs simples, capables de décoder les instructions les plus courantes, avec un seul microcode. La conséquence est qu'il n'est pas possible de décoder deux instructions microcodées en même temps. Par contre, il reste possible de décoder plusieurs instructions non-microcodées ou une instruction microcodée couplée à une instruction non-microcodée. Vu qu'il est rare que deux instructions microcodées se suivent dans un programme, le cout en performance est extrêmement mineur. Il faut noter qu'une instruction correspond à une ou plusieurs µops. Il est donc possible de charger 5 instructions et de se retrouver avec 8 µops en sortie des décodeurs. Et c'est la source d'une distinction très importante. Plus haut, j'ai parlé de processeurs superscalaires à N voies. La terminologie peut avoir deux interprétations. La première est que le processeur charge/décode N instructions à la fois. Une seconde est qu'il est capable d'exécuter/émettre N µops en même temps. Les deux ne sont pas équivalentes, vu qu'un processeur superscalaire peut, par exemple, charger/décoder N instructions et émettre/exécuter N+2 µops. La distinction est particulièrement importante sur les processeurs superscalaires larges. Certains d'entre eux sont capables de charger 5 instructions et d'en émettre le double ! Un exemple classique était les processeurs Athlon d'AMD, qui pouvaient décoder deux instructions par cycle, mais émettre 4 µops par cycle. Ce n'était pas un problème, car beaucoup d'instructions, même basiques, étaient décodées en 2 µops. ===L'émission parallèle des instructions=== La superscalarité modifie en profondeur l'unité d'émission, notamment au niveau de son interface. Avant, elle recevait une micro-opération sur son entrée, et fournissait la micro-opération émise sur une sortie. Et cela vaut aussi bien pour une unité d'émission simple, un ''scoreboard'', une fenêtre d'instruction ou des stations de réservation. Mais avec l'émission multiple, les sorties et entrées sont dupliquées. Pour la double émission, il y a deux entrées vu qu'elle doit recevoir deux micro-opération décodées/renommées, et deux sorties pour émettre deux micro-opérations. Dans ce qui suit, nous ne parlerons pas d'entrée et de sortie, mais de '''ports de décodage''' et de '''ports d'émission'''. Les ports de décodage reçoivent des micro-opérations provenant de l'unité de décodage, les ports d'émissions sont pour les micro-opérations émises. Les ports d'émission injectent les micro-opérations émises dans le pipeline, elle sont propagée au banc de registre, aux ALUs, etc. Un processeur superscalaire a forcément plusieurs ports d'émission (et de décodage). Si l'interface de l'unité d'émission change, l'intérieur est tout autant modifié. Sur un CPU non-superscalaire, l'unité d'émission reçoit une µop "candidate à l'émission", et détecte les dépendances entre avec les µops en vol, en cours d'exécution dans le pipeline. Et c'est toujours le cas sur les processeurs superscalaires : l'unité d'émission détecte les dépendances entre les µops candidates et les µops en vol. Mais avec la siperscalarité, elle doit en plus tester les dépendances entre les µops candidates. Si l'unité d'émission est un ''scoreboard'', il doit détecter les dépendances entre instructions émises simultanément et les sérialiser si besoin. Avec une fenêtre d'instruction, il n'y a pour ainsi dire rien à faire, vu que les dépendances sont éliminées par le renommage de registre et que les signaux de réveil gèrent les dépendances RAW. C'est la raison pour laquelle les processeurs superscalaires modernes n'utilisent pas de ''scoreboard''. ==Les processeurs implémentés avec plusieurs pipelines== Nous venons de voir comment la superscalarité impacte le ''front-end'', il est maintenant de voir ce qu'il en est de l'unité d'émission et des ''back-ends''. Un processeur superscalaire peut utiliser l'exécution dans le désordre et le renommage de registres, mais ce n'est pas une obligation. Historiquement, les premiers processeurs superscalaires n'utilisaient pas d'exécution dans le désordre. Le meilleur exemple est celui du Pentium 1 et 2 d'Intel. Ils étaient tous deux des processeurs superscalaires, mais n'avaient pas d'exécution dans le désordre, qui est apparue sur le Pentium 3. les explications sont plus simples si on met de côté l'exécution dans le désordre. Vous vous dites que l'implémentation d'un processeur superscalaire n'est pas la même suivant que le CPU utilise l'exécution dans le désordre, ou non. Mais dans les faits, la distinction est plus subtile que ca. Pour l'expliquer, je vais utiliser une classification originale, qui sépare les processeurs superscalaires en trois sous-types. La distinction se fait sur la manière dont la superscalarité est implémentée en matériel.La classification que j'utilise distingue : * Les processeurs avec plusieurs pipelines, sans exécution dans le désordre. * Les processeurs superscalaires avec un pipeline dynamique. * Les processeurs avec des fenêtres d'instruction décentralisées. La distinction n'est pas qu'une question d'implémentation matérielle. Elle impacte aussi le ratio entre instructions chargées/décodées et instructions émises. Vous vous dites que les deux sont égales, mais ce n'est le cas que sur les processeurs avec N pipelines ! Sur les autres processeurs, il est possible de décoder 4 instructions, mais d'en émettre maximum 6 par cycle ! Et sur les CPU avec des fenêtres d'instruction décentralisées, il y a aussi une différence entre le nombre d'instructions qui sont ''dispatch'' et ''schedule''. La catégorie la plus simple est celle des '''processeurs avec plusieurs pipelines'''. Ce sont des processeurs superscalaires sans exécution dans le désordre. Ils partent d'un processeur non-superscalaire, et ajoutent un second pipeline, en sortie de l'unité d'émission. Le second pipeline permet l'émission parallèle d'une seconde instruction. Le second pipeline n'est pas identique au pipeline originel, sur plusieurs points. Premièrement, il n'a pas exactement les mêmes circuits. Le second pipeline est généralement composé d'une unité de calcul, d'une FPU, éventuellement d'un second banc de registres, guère plus. Il permet d'exécuter une seconde opération de calcul, pas plus, ce qui est à l'origine de contraintes d'appariemment assez fortes. De plus, il n'a pas forcément la même longueur, il peut avoir des étages en moins ou en plus. Il s'agit de la forme la plus simple de processeur superscalaire et nous allons leur consacrer cette section. ===La double émission entière-flottante=== L'exemple le plus simple utilise un second pipeline pour les opérations flottantes, séparé du pipeline originel. L'ajout d'un pipeline flottant permet d'émettre une micro-opération entière en même temps qu'une micro-opération flottante, ce qui s'appelle la '''double émission entière-flottante'''. La micro-opération entière s'exécute dans l'ALU entière, la micro-opération flottante dans la FPU. Les exemples les plus notables sont le PA-RISC 7100, le POWER 1 (RIOS .& et .9) et le PowerPC 601. L'Apollo DN10000 et l'Intel i860 utilisaient aussi cette forme de double émission, mais étaient des prototypes de CPU VLIW. [[File:Double émission entière-flottante.png|centre|vignette|upright=2|Double émission entière-flottante]] Pour bien expliquer les choses, prenons le processeur illustré ci-dessous, avec deux ''back-end'' séparés : un pour la FPU, et un autre pour le reste. Les instructions entières et mémoire passent toutes par le ''back-end'' généraliste. [[File:CPU non-superscalaire basique, avec une FPU.png|centre|vignette|upright=1.5|CPU non-superscalaire basique, avec une FPU]] Les deux ''back-end'' sont des pipelines séparés, mais il faut que l'unité d'émission soit spécialement conçue pour en profiter. Un processeur simple émission peut démarrer une seule µop par cycle : soit la µop est envoyée au ''back-end'' flottant, soit elle est envoyée au ''back-end'' général. Avec la double émission entière-flottante, le processeur peut envoyer une µop dans chaque pipeline, à chaque cycle. Vu que la FPU et son banc de registre forment déjà un pipeline séparé, les seules modifications se font au niveau du ''front-end'', unité d'émission inclue. {| |- |[[File:CPU simple émission avec une FPU.png|centre|vignette|upright=1.5|CPU simple émission avec une FPU.]] |[[File:Double émission entière flottante avec un second pipeline.png|centre|vignette|upright=1.5|CPU avec un second pipeline flottant.]] |} Notez que le terme double émission ''entière''-flottante est un peu trompeur. En réalité, la technique permet d'émettre une instruction flottante avec n'importe quelle autre instruction non-flottante, avec des restrictions pour les branchements. Il est par exemple possible d'exécuter un calcul flottant en parallèle d'un accès mémoire. Sur les CPU 32 bits, il est possible de faire les multiplications dans la FPU. Pour rappel, la FPU contient un multiplieur entier 53-54 bits, pour multiplier les mantisses de deux flottants 64 bits, qu'on peut utiliser pour faire les multiplications entières 32 bits. Cela permet d'émettre une multiplication en même temps qu'une opération entière dans l'ALU. Ainsi, le CPU pouvait émettre deux instructions : une opération entière de base, avec soit une multiplication, soit une opération flottante. En clair, une émission de type INT + (MUL /FLOAT). Par contre, on perd la possibilité d'émettre une multiplication entière avec une opération flottante, mais c'était un compromis qui en valait la peine. Le CPU PA-RISC 7100 implémentait cette optimisation. Il s'agissait d'un CPU double émission entière-flottante, qui utilisait donc un partitionnement assez simple. Le combo partitionnement + reconditionnement permettait ici de gagner en performance, pour un cout en matériel très limité. D’autant plus limité que le jeu d'instruction prévoyait le reconditionnement de la FPU. Les multiplications ne lisaient pas leurs opérandes dans les registres entiers, mais dans les registres flottants. ===La double émission entière=== Une autre possibilité ajoute un second pipeline, capable d'exécuter des opérations entières simples, appelé le pipeline entier. Le processeur supporte alors la '''double émission entière''', à savoir qu'ils peuvent émettre une opération entière en plus d'une autre instruction. L'opération entière en question est une opération simple, comme une addition, une soustraction, une opération bit à bit, une comparaison, etc. Les exemples classiques sont les processeurs Intel i960 et Pentium. L'implémentation était différente entre l'i960 et le Pentium : Le Pentium avait une seconde ALU entière, alors que le i960 rusait. Le Pentium dupliquait l'ALU entière, pour créer un second pipeline entier. Sur le Pentium originel, les contraintes d'appariement étaient assez strictes. Le Pentium avait une FPU, mais ne pouvait pas l'utiliser en double émission. Il lui était impossible d'exécuter une opération flottante en même temps qu'une opération entière (branchements inclus). Le Cyrix 6x86 était une sorte de Pentium produit par l'entreprise Cyrix, avec une microarchitecture différente. Il avait des contraintes d’appariement réduites. Par exemple, il pouvait émettre une opération flottante en parallèle d'une opération entière. Nous détaillerons ces processeurs dans le prochain chapitre, qui porte justement sur les CPU superscalaires x86. [[File:CPU simple et double émission avec un second pipeline entier.png|centre|vignette|upright=2.5|CPU simple et double émission avec un second pipeline entier.]] L'Intel i960 n'avait pas de FPU, juste une ALU entière et une unité mémoire. Il utilisait l'unité mémoire comme une seconde ALU entière limitée. Pour rappel, une unité mémoire contient une AGU, à savoir une ALU spécialisée dans les calculs d'adresse. Elle est capable de faire des additions, soustractions, et quelques décalages limités (des décalages par 2, 4, 8, pas plus). L'Intel i960 ajoutait des connexions entre AGU et banc de registre, afin que celle-ci serve de seconde unité de calcul. L'AGU est déjà reliée aux deux ports de lecture, pour lire les opérandes du calcul d'adresse, il suffit de la connecter sur le port d'écriture. Le processeur peut alors émettre deux instructions/µops entières, sous certaines conditions. [[File:Emission multiple des opérations entières, double émission.png|centre|vignette|upright=2|Émission multiple des opérations entières, double émission.]] ==Les processeurs superscalaires dynamiques== Les processeurs précédents, avec 2 pipelines, avaient une unité d'émission assez simple. Elle avait deux ports de décodage, et deux ports d'émission. Le nombre de ports de décodage et d'émission étaient identiques. Vous vous dites que c'est naturel, et intuitif, que c'est normal pour un processeur superscalaire. Mais en réalité, la majorité des processeurs superscalaires a plus de ports d'émission que de décodage. Expliquer pourquoi va cependant nous demander de parler de comment la superscalarité exploite les unités de calcul. Posons-nous cette question : de combien d'unités un processeur superscalaire a besoin ? Les unités en question ne sont nécessairement des unité de calcul, l'unité mémoire et l'unité de branchement comptent aussi. La réponse dépend du nombre de voies. Si le ''front-end'' charge et décode un paquet de N instructions, exécuter ces N instructions simultanément demandera là aussi au moins N unités de calcul. Notez le terme : ''au moins'', car c'est là tout l'enjeu de cette section. La réponse dépend aussi des contraintes d’appariement. Pour un CPU superscalaire "parfait", sans contraintes d’appariement, toutes les unités doivent être dupliquées, y compris l'unité mémoire. Un processeur à double émission parfaite devrait dupliquer l'ALU entière, le ''barrel shifter'', le circuit multiplieur, la FPU, l'unité mémoire, et l'unité de branchement, ce qui ferait passer de 6 unités à 12. Le cout en circuit est énorme, même pour de la double émission ! Et pour un CPU à N pipelines, le cout en circuit encore plus prohibitif ! En pratique, les processeurs superscalaires qui font ça sont très rares. La majeure partie des processeurs superscalaires utilisent d'autres techniques : le partitionnement, la duplication partielle des ALUs, la duplication des autres unités. ===Le partitionnement des unités fonctionnelles=== Les CPU superscalaires les plus simples ne dupliquent pas leurs unités de calcul, ils se contentent d'exploiter les unités existantes. Et pour expliquer comment, nous allons partir de l'exemple d'un processeur non-superscalaire contient une ALU entière, une FPU, une unité mémoire et une unité de branchement. Les quatre unités peuvent fonctionner en parallèle, à savoir qu'une unité peut exécuter une instruction à elle toute seule, sans interagir avec les autres. Cela suffit pour créer un processeur quadruple émission, qui peut émettre en même temps : une opération entière, une opération flottante, un branchement, un accès mémoire. Le principe marche aussi sur un processeur avec moins de 4 unités, par exemple sans FPU et/ou sans unité de branchement, ou avec au contraire des unités en plus. L'idée générale est d’émettre une µops séparée dans chaque unité fonctionnelle. Utiliser ainsi les unités existantes, pour rendre un CPU superscalaire, s'appelle le '''partitionnement superscalaire'''. Le terme n'est pas beaucoup utilisé en-dehors de quelques vieux articles académiques. Le partitionnement est fortement dépendant du jeu d'instruction, car il demande de bien séparer instructions entières, flottantes, branchements et instructions mémoire. Et autant c'est bien le cas sur les CPU RISC, autant les CPU CISC ne sont pas dans ce cas. Les CPU CISC ont des instructions ''load-op'', qui effectuent une instruction arithmétique et une µop mémoire. Et ces instructions sont très compliquées à implémenter avec le partitionnement. Et au-delà de ça, les CPU CISC ont beaucoup d'instructions qui sont décodées en plusieurs µops, à exécuter dans un ordre bien précis. On peut pas émettre les µops en question simultanément. Le partitionnement a un cout en circuit très limité, pour un gain en performance lui aussi limité. Pour reprendre le CPU de l'exemple précédent, il est rare que l'on ait à exécuter ces quatre instructions en même temps. En pratique, les combinaisons fréquentes sont les combinaisons calcul + accès mémoire, calcul + branchement, calcul entier + calcul flottant. Utiliser une quadruple émission de ce type n'est donc pas une bonne idée, alors que la double émission parait plus adaptée. Et c'est là que la différence entre ports d'émission et de décodage devient intéressante. L'idée est d'avoir une unité d'émission avec deux ports de décodage, et 4 port d'émission (un par unité). Les contraintes d’appariement varient alors suivant le processeur, mais la règle générale est que si deux micro-opérations tombent dans deux unités différentes, on peut les émettre en même temps. En clair, on peut émettre une opération entière avec une opération flottante, une opération entière avec un branchement, un accès mémoire avec un branchement, etc. Et cela rend le partitionnement bien plus intéressant que prévu. Les tout premiers CPU superscalaires étaient des CPU double émission, qui utilisaient le partitionnement avec : une ALU entière, une unité mémoire et une FPU. Nous parlerons de '''partitionnement INT-FLOAT-MEM'''. L'avantage sur la double émission flottante est que les combinaisons INT + MEM et FLOAT + MEM étaient autorisées. L'intérêt était d'émettre une opération en parallèle d'un accès mémoire, ce qui est un doublet d'instruction assez fréquent. Les exemples classiques sont l'HyperSPARC, de l'alpha 21064 et du PowerPC 603. Les contraintes d’appariement variaient grandement suivant le processeur. Le PowerPC 603 implémentait une double émission "parfaite". C'est à dire que toutes les combinaisons possibles à deux instructions étaient possibles, que ce soit INT + FLOAT, INT + MEM, FLOAT + MEM. En plus de cette double émission "parfaite", le CPU utilisait la technique dite de ''branch folding'', qui permettait d'exécuter un branchement sans utiliser d'unité de calcul, ce qui fait qu'il était qualifié de ''CPU 2-way + Branch''. A l'opposé, le processeur alpha 21064 avait pas mal de contraintes d’appariement, à savoir que certaines combinaisons de deux instructions étaient interdites, bien que compatibles avec les unités disponibles. Une des raisons est que le banc de registre n'avait pas assez de ports de lectures, ce qui fait que certaines combinaisons avec une écriture mémoire n'étaient pas permises. Les concepteurs avaient volontairement inséré ces contraintes afin de simplifier le design du processeur. Avant de poursuivre, précisons que la FPU regroupe un additionneur flottant et un multiplieur flottant. Et ce fait peut être exploité pour approfondir le partitionnement. La '''double émission FADD/FMUL''' permet d'émettre une addition flottante en même temps qu'une multiplication flottante. Elle a été utilisée sur les processeurs x86, Alpha et SPARC. Les autres circuits de calcul flottant sont souvent regroupés avec l'additionneur. La division est parfois e même port que le multiplieur flottant, parfois sur celui de l'additionneur (quand elle est microcodée et exécutée en enchainant les soustractions). ===La duplication des ALU entières=== Le partitionnement est une technique élégante, simple, facile à implémenter et au cout en circuits modeste. Mais il faut avouer que cela ne donne pas des CPU superscalaires très efficaces. La raison est que le partitionnement permet d'émettre des paires, triplets, quadruplets de micro-opérations qui sont rares en pratique. Les combinaisons les plus fréquentes en pratique sont des paires/triplets d'opérations entières, souvent des paires/triplets d'additions ou d'opérations entières simples. Il est donc primordial d'émettre plusieurs opérations entières simultanément. Le fait d'émettre et d'exécuter plusieurs opérations entières en même temps s'appelle l''''émission entière multiple'''. Pour exécuter la seconde/troisième opération entière, il faut dupliquer les ALU entières (ou réutiliser l'AGU comme ALU entière comme le fait l'Intel i960). Le processeur doit avoir deux ALU entières pour de la double émission entière, trois pour de triple émission entière, etc. De plus, il faut ajouter des ports au banc de registre, pour lire deux fois plus d'opérandes et décrire deux résultats. Et enfin, il faut rajouter un port d'émission pour pouvoir émettre une micro-opération entière en plus. [[File:Processeur non-superscalaire basique 03.png|centre|vignette|upright=2|Processeur non-superscalaire basique]] La tendance est de multiplier les ALU entières, mais pas le circuit multiplieur. Le cout en transistors est alors grandement réduit, au prix de l'apparition de dépendances structurelles. Le CPU peut émettre deux additions en même temps, ou une addition et une multiplication, mais pas deux multiplications. Il en est de même avec le ''barrel shifter'', qui n'est pas dupliqué. Il est donc possible d'émettre un décalage avec une opération de base, mais pas deux décalages en parallèle. Mais ces contraintes d’appariement ne sont pas un problème, car il est rare de devoir émettre deux multiplications/décalages en même temps. La plupart des programmes sont majoritairement remplis d'additions, avec des multiplications assez rares et des décalages qui le sont encore plus. La moyenne est proche d'une multiplication pour 4/5 additions. Vu que des multiplications consécutives sont très rares, dupliquer le multiplieur est presque inutile. Disposer de plusieurs circuits multiplieurs ou de plusieurs ''barrel shifters'' serait donc un cout en circuits qui ne servirait que rarement et n'en vaut pas la chandelle. Il faut noter que sur les CPU 32 bits, les multiplications peuvent être exécutées dans la FPU ou dans un multiplieur séparé, tout dépend de si le CPU exécute les multiplications dans la FPU ou pas. {|class="wikitable" |- ! Voie d'émission n°1 !! Voie d'émission n°2 !! Voie d'émission n°3 |- | ALU entière || ALU entière || FPU |} Reste à connecter les unités de calcul à l'unité d'émission (indirectement, car il y a des étages de pipeline entre les deux). Une implémentation basique utilisée un port d'émission par unité. Prenons l'exemple d'un CPU superscalaire avec 4 ALU entières, une FPU, et une unité mémoire. Vu qu'il y a 6 unités, cela fait donc 6 ports d'émission. L'exemple historique le plus impressionnant est celui du Motorola 88110, un CPU double émission qui possède 10 unités. Il contient deux ALU entières, un circuit multiplieur, un circuit diviseur, une unité de manipulation de bits, une unité mémoire, un additionneur flottant, et deux unités graphiques pour des calculs impliquant des pixels. Le multiplieur est utilisé à la fois pour les multiplications entières, flottantes et le produit de deux pixels. Idem pour le diviseur, qui sert pour les divisions entières et flottantes. Et chaque unité a son propre port d'émission. La conséquence est que les contraintes d'appariement du Motorola 88110 sont simples : tant que deux µops atterrissent dans des unités séparées, la paire est permise. Il est par exemple possible d'émettre simultanément deux opérations entières simples, vu qu'il y a deux ALU. Par contre, impossible d'émettre simultanément deux multiplications, deux divisions, deux opérations flottantes, deux manipulations de bit, deux accès mémoire, etc. De plus, le partage du multiplieur fait qu'on ne peut pas émettre une multiplication entière avec une multiplication flottante. Idem avec les divisions, vu que le diviseur est aussi partagé. Ce sont les seules contraintes. ===Le partage des ports d'émission=== La présence d'un circuit multiplieur et d'un ''barrel shifter'' pose des problèmes pour le partitionnement. Il est possible d'avoir un port d'émission dédié au multiplieur, et un autre au ''barrel shifter'', qui sont séparés de ceux pour l'ALU entière. Il est alors possible d'émettre une opération entière, une multiplication et un décalage, simultanément. Nous parlerons de '''partitionnement entier''' pour désigner cette possibilité. [[File:Partitionnement superscalaire entier.png|centre|vignette|upright=2|Partitionnement superscalaire entier.]] Le partitionnement entier est cependant très rare, car le gain en performance serait trop faible au regard des couts en circuit. Quelques processeurs historiques l'utilisaient, mais ce n'est plus le cas de nos jours. La raison est que les multiplications et les décalages sont assez rares dans le code, ce qui fait que le port d'émission associés sont sous-utilisés. Et un port d'émission a un cout en circuit assez important. Et c'est sans compter qu'ajouter des ports sur le banc de registres juste pour un multiplier sous-utilisé n'en vaut pas la peine. L'idéal serait de trouver un moyen de réduire le nombre de ports d'émissions, sans réduire le nombre d'unités de calcul. [[File:Emission multiple des opérations entières, implémentation naive.png|vignette|Émission multiple des opérations entières, implémentation naive]] La solution consiste à '''partager les ports d'émission''', à savoir connecter un port d'émission à plusieurs unités de calcul. L'exemple classique est justement lié aux circuits multiplieur et ''barrel shifters''. L'idée est que le multiplieur et le ''barrel shifter'' sont mis sur le même port d'émission qu'une ALU entière. Prenons par exemple le processeur à double émission entière illustré ci-contre. Un port d'émission est relié à une ALU entière seule, et l'autre port d'émission alimente la seconde ALU entière et le multiplieur. La conséquence est que le processeur peut émettre deux opérations entières, dont une multiplication. Si on avait utilisé un port d'émission dédié au multiplieur, il aurait été possible d'émettre deux opérations entières et une multiplication. On perd donc une voie, mais on gagne en flexibilité et on économise des circuits. Notons que ce partage signifie aussi que le multiplieur partage les ports sur le banc de registre, ce qui fait une double économie. [[File:Emission multiple des opérations entières, implémentation courante.png|centre|vignette|upright=1.5|Émission multiple des opérations entières, implémentation courante]] En général, le ''barrel shifter'' et le multiplieur sont placés sur deux voies d'émission séparés, ce qui permet d'émettre un décalage et une multiplication en même temps. Les mettre sur le même port ne le permettrait pas. {|class="wikitable" |- ! Voie d'émission n°1 !! Voie d'émission n°2 !! Voie d'émission n°3 |- | * ALU entière * Multiplieur | * ALU entière * Barrel shifter | FPU |- | * Additions, soustractions, opérations bit à bit, etc. * Multiplication | * Additions, soustractions, opérations bit à bit, etc. * Décalages et rotations | Opération flottante |} Terminons concernant les multiplieurs avec une dernière subtilité. Pour rappel, les processeurs modernes intégrent en réalité deux multiplieurs différents. Le résultat d'une multiplication est très large et prend deux registres. Par exemple, une multiplication de deux opérandes 64 bits donne un résultat sur 128 bits, ce qui ne tient pas dans un registre, mais en prend deux. L'instruction de multiplication classique ne calcule que les 64 bits de poids faible. mais elle est complétée par d'autres instructions de multiplication qui peuvent faire le calcul complet. Pour résoudre le problème, les processeurs modernes intègrent deux instructions de multiplications : une qui calcule les bits de poids faible du résultat, une autre qui calcule les bits de poids fort. Et ces deux instructions sont associées à deux multiplieurs séparés, aux circuits différent. Le multiplieur qui calcule les bits de poids faible du résultat est appelé le ''low multiplier'', l'autre est appelé le ''high multiplier''. Le second multiplieur est souvent placé sur un second port d'émission, différent du premier multiplieur, partagé avec une ALU. L’avantage de mettre les deux multiplieurs sur deux ports d'émission différents est qu'une multiplication complète peut être réalisée en utilisant les deux multiplieurs en parallèle. Les deux sous-multiplications sont émises en même temps, exécutées en même temps. pas besoin d'exécuter l'une puis la seconde, d'où un gain performance appréciable. Nous venons de voir comment partager un port d'émission entre une ALU et un multiplieur. Mais au-delà de cet exemple, le partage des ports d'émission peut appliquer à n'importe quelle unité. Prenons l'exemple d'un CPU superscalaire avec 4 ALU entières, une FPU, et une unité mémoire. Vu qu'il y a 6 unités, cela fait donc 6 ports d'émission. Cependant, il est rare qu'un bloc de 6 instructions contienne exactement 4 opérations entières, une opération flottante, et un accès mémoire. Beaucoup de ports d'émission seraient sous-utilisés. La solution est de partager des ports d'émission, pour passer à la quadruple émission. Le CPU peut alors répartir 4 instructions sur les ports d'émission adéquats, à chaque cycle. Le CPU a donc 4 ports de décodage et 6 ports d'émission. Une implémentation classique permet n'importe quelle combinaison de 4 instructions compatible avec les 6 unités. Par exemple, il devient possible d'émettre simultanément 4 additions, la combinaison 2 * INT + FLOAT + MEM, 3 * INT + MEM, et bien d'autres. L'exemple relie une ALU entière, la FPU et l'unité mémoire sur le même port. Le CPU a alors quatre ports d'émission, qui ne sont pas "identiques". Trois d'entre eux sont reliés à une ALU entière chacun, rien d'autre. Le quatrième est lui relié à une ALU entière, la FPU et l'unité mémoire. On économise alors deux ports d'émission, mais cela entraine l'apparition de contraintes d’appariement. Le CPU peut émettre 3 opérations entières + n'importe quelle autre opération. Mais les autres combinaisons sont interdites. Le CPU peut émettre 6 opérations entières simultanément, grâce à 6 ALU entières. Les accès mémoire ou opérations flottantes ne viennent pas en plus, mais en remplacement des opérations entières. Regrouper plusieurs ALU sur un même port d'émission est donc à l'origine de dépendances structurelles, de nouvelles contraintes d’appariement. Dans certaines situations de '''''port contention''''', on a assez d'ALU pour exécuter N micro-opérations, mais la répartition des ALUs sur les ports l'empêche. Impossible d'émettre deux micro-opérations sur deux ALU si elles sont sur le même port d'émission. On peut réduire les cas de ''port contention'' en répartissant correctement les ALU sur les ports d'émission, mais sans jamais les supprimer complétement. Un exemple est celui du PowerPC 604. Il implémentait la quadruple émission, alors qu'il avait 5 unités de calcul. Mais deux unités partageaient un même port d'émission. Dans le détail, il avait deux ALU entières, un circuit multiplieur/diviseur, une FPU, une unité mémoire. La FPU et le multiplieur étaient sur le même port d'émission. En conséquence, le CPU pouvait émettre seulement les combinaisons INT + INT + MEM + (MUL/FLOAT). : Il est intéressant de voir l'exemple d'un processeur superscalaire parfait, sans contraintes d'appariement, à N voies. Pour cela, on part d'un processeur non-superscalaire, avec M unités de calcul. Un tel processeur peut s'implémenter avec N ports d'émission, chacun relié à M unités de calcul possibles, ce qui fait que les M unités de calcul sont dupliquées en N exemplaires. Si on prend par exemple un CPU non-superscalaire avec une ALU, une FPU, une unité mémoire et une unité de branchement, un port d'émission sera relié à une ALU, une FPU, une unité mémoire et une unité de branchement. ===La duplication des autres unités fonctionnelles=== Dupliquer les ALU entière est une première étape, mais il est aussi possible de dupliquer les autres unités fonctionnelles. Par exemple, il est possible de dupliquer l'unité mémoire ou l'unité de branchement. Reste à voir quelles unités dupliquer, et pourquoi. Précisons que dans ce qui va suivre, nous allons parler de la duplication des unités en général, pas seulement des unités mémoire/branchement. Nous allons continuer de parler de la duplication des ALU entières dans ce qui suit, mais de manière plus générale. Pour un processeur à N voies, il est théoriquement possible de dupliquer toutes les unités en N exemplaires. Mais ce n'est jamais fait en pratique, car le cout en circuits serait trop important et le gain en performance trop faible. Mieux vaut dupliquer certaines unités bien précises, quitte à avoir des contraintes d'appariement. Et à ce petit jeu, toutes les duplications ne se valent pas, certaines sont plus rentables en matière de performance, le cout en circuit n'est pas le même selon l'unité, etc. La rentabilité en performance dépend surtout des contraintes d'appariement. Les contraintes d'appariement entrainent une baisse de performance significatives si elles interdisent des paires d'instructions fréquentes. Aussi, les opérations très fréquentes, souvent appairées, gagnent à dupliquer l'unité associée. Et au contraire, les unités rarement utilisées ne doivent pas être dupliquées. Il se trouve que les unités les plus utilisées sont les ALU entières, suivies par les unités mémoire et l'unité de branchement. Le cout en circuit n'est aussi pas le même. Dupliquer les ALU entière est trivial, car elles ont un budget en transistors assez faible. Les circuits multiplieurs, diviseurs, et les ''barrel shifter'' ont eux un cout en transistor plus élevés. Si on devait faire un classement, on aurait : ALU entière < ''barrel shifter'' < multiplieur. Pour les unités mémoire, le cout en transistor est là aussi conséquent. Le résultat final est que dupliquer les ALU entières est privilégié sur le reste, comme l'a vu dans la section précédente. Les unités mémoire arrivent en seconde place, suivie par les multiplieurs/''barrel shifter'' à la troisième place, et les unités de branchement à la quatrième place. Les CPU superscalaires larges ont donc tendance à multiplier les unités mémoire en second. Les multiplieurs et ''barrel shifters'' sont eux aussi dupliqués sur les CPU superscalaires larges, mais cela vient souvent après avoir dupliqué les unités mémoire. La raison est que les accès mémoire sont critiques pour la performance des CPU à exécution dans le désordre, pas les multiplications. Pour les unités de branchement, une subtilité complique le fait d'en installer plusieurs. Que faire quand deux branchements sont pris ? La solution la plus simple est de ne pas se trouver dans cette situation : on n'utilise qu'une seule unité de branchement et on n’exécute qu'un seul branchement par cycle. La majorité des processeurs superscalaires étroits font ainsi. Les processeurs superscalaires larges ont cependant deux unités de branchements, mais ils n'acceptent qu'un seul branchement pris à la fois. Si les deux branchements pris sont exécutés en même temps, le processeur n’exécute que le plus récent, dans l'ordre du programme. ===Les CPU superscalaires mélangent les trois techniques=== Les CPU superscalaires utilisent toutes les techniques à la fois : partitionnement, duplication de l'ALU entière, duplication des autre unités fonctionnelles. Chaque processeur utilise ces trois stratégies à sa sauce, en fonction de son budget en transistor. Les quatre techniques ont cependant un cout en circuit différent, et donnent des gains de performances eux aussi forts différents. * Le '''partitionnement superscalaire''' a un cout en circuit modéré, car on n'a pas besoin de dupliquer d'ALU. * La '''duplication des ALU entières''' est la technique la plus importante : elle a un cout en circuit modéré, et donne des gains en performance impressionnants. * La '''duplication des autres unités''' a un cout en circuit variable, pour des gains en performance eux aussi variables. * Le '''partage des ports d'émission''' réduit le cout en circuit du CPU, pour des pertes de performances mineures si bien fait. L'usage du partitionnement seul, sans duplication, était surtout le fait des processeurs commercialisés entre les années 1989 et 1993. Le partage des ports d'émission a lui aussi mis un peu de temps pour s'imposer. Globalement, les processeurs superscalaires ont évolués progressivement, pour se rapprocher d'une sorte de standard. Mais pour comprendre ce qu'est ce standard, et en quoi les CPU historiques s'en sont progressivement rapprochés, il faut étudier l'histoire des CPU superscalaires. L'histoire des CPU superscalaires a commencé dès 1960, mais est resté un projet de recherche pendant plusieurs décennies. De nombreux designs ont été conçus, mais abandonnés avant la production, comme l'ACS-1 d'IBM. Les années 1980 ont vu l'arrivée de prototypes de processeurs VLIW, mais qui n'étaient pas superscalaires. Par exemple, l'Apollo DN10000 et l'Intel i860 pouvaient émettre deux instructions à la fois, sous conditions, mais demandaient que le compilateur fasse une bonne partie du travail. Les premiers CPU superscalaires commercialisés sont sortis en 1989. Deux CPUs superscalaires sont sortis cette année là : le RS/6000 d'IBM et l'i960CA d'Intel. Puis, la compétition s'est aussi lancée dans la bataille. Les CPU commercialisés avant l'année 1993 étaient à double émission, à l'exception du SuperSPARC qui utilisait la triple émission. Les modèles après 1993 hésitaient entre double et quadruple émission. Dans le tableau ci-dessous, les processeurs quadruple émission sont en bleu, les triple émission sont en rouge, les autres ne sont pas en couleur. {|class="wikitable" |- ! !! IBM !! HP PA-RISC !! SPARC !! Intel!! Alpha !! Autres |- ! 1989 | RS/6000 || || || i960CA || || |- ! 1990 | || || || || || |- ! 1991 | || || || || || Motorola 88110 |- ! 1992 | RSC || PA 7100 || class="f_rouge | SuperSPARC || || 21064 || |- ! 1993 | PPC 601 || || HyperSPARC || Pentium || || |- ! 1994 | class="f_bleu | POWER 2 || PA 7200 || || || class="f_bleu | 21164 || |- ! 1995 | 603/604 || class="f_bleu | PA 8000 || class="f_bleu | UltraSPARC 1 || Microarchitecture P6 (+ concurrence AMD) || || class="f_bleu | MIPS R1000 |- ! 1996 | class="f_bleu | 620 || || || || class="f_bleu | 21264 || |- ! ... || ... || ... || ... || ... || ... || ... |} Les premiers CPU à double émission sont assez représentatifs des CPU à double émission modernes. Il faut dire que se limiter à deux voies ne permet pas de faire beaucoup de choses. Voici le tableau chronologique disant quel CPU utilisait quelle technique. * Les CPU en vert utilisaient la double émission entière-flottante. * Les CPU en rouge utilisaient la double émission entière "pure". * Les CPU en jaune utilisaient un ''partitionnement complet'' entre ALU, FPU et unité mémoire. * Les CPU sans couleur utilisaient un grand nombre d'unités, avec beaucoup de ports d'émission. * Les CPU barrés utilisent la triple ou quadruple émission et seront vu dans la section suivante. {|class="wikitable" |- ! !! IBM !! HP PA-RISC !! SPARC !! Intel!! Alpha !! Autres |- ! 1989 | class="f_vert | RS/6000 || || || class="f_rouge | i960CA || || |- ! 1990 | || || || || || |- ! 1991 | || || || || || Motorola 88110 |- ! 1992 | class="f_vert | RSC || class="f_vert | PA 7100 || <s>SuperSPARC</s> || || class="f_jaune | 21064 || |- ! 1993 | class="f_vert | PPC 601 || || class="f_jaune | HyperSPARC || class="f_rouge | Pentium || || |- ! 1994 | <s>POWER 2</s> || PA 7200 || || || <s>21164</s> || |} C'est en 1994, que la quadruple émission est arrivée et que les CPU ont essayé divers implémentations. Il y avait alors trois stratégies pour la double/triple/quadruple émission, qui partageaient des problèmes similaires. La première implémentation dupliquait les ALUs et les FPUs, ce qui permettait d'émettre deux opérations flottantes avec deux opérations entières. Le POWER 2 dupliquait ses FPUs à la perfection, alors que le 21264 séparait l'additionneur et le multiplieur flottant. Les accès mémoire étaient traités comme des opérations entières et le processeur pouvait souvent en émettre deux à la fois. Mais une telle organisation n'est plus utilisée de nos jours, car, sans instructions flottantes à exécuter, elle est équivalente à de la double émission. La seconde implémentation utilisait deux ALU entières (dont un multiplieur), une unité mémoire et une FPU.Cette organisation est intéressante, mais encore trop stricte pour donner de bons résultats, les quadruplets avec exactement deux opérations entières, un accès mémoire et une opération flottante étant trop rares. L'usage de ces 4 unités en double ou triple émission a été utilisé sur le PA 7200 et le SuperSPARC. Malheureusement, en plus de problèmes au niveau de son cache, le SuperSPARC avait de nombreuses contraintes d’appariement, car le banc de registre n'avait pas assez de ports pour alimenter certaines combinaisons d'instructions. De plus, s'il émettait une multiplication, il ne pouvait pas émettre de seconde µop. Enfin, une troisième implémentation utilisait un grand nombre d'unités fort différentes, bien plus que quatre, avec au minimum deux ALU entières. Prenons l'exemple de l'UltraSPARC, qui avait : deux ALU entières, une unité mémoire, une unité de branchement, un additionneur flottant, un multiplieur flottant, un diviseur flottant (aussi utilisé pour le calcul des racines carrées), et 2 unités graphiques pour les calculs sur des pixels. En tout, cela fait 9 unités différentes, pour de la quadruple émission. Dans le même genre, les processeurs MIPS R8000 et R10000 avaient une implémentation plus moderne, dans le sens où toutes les unités étaient dupliquées. Le CPU avait deux ALU, deux FPU et deux unités mémoire. Il pouvait donc émettre quatre instructions à la fois, tant que le paquet collait avec ces six unités. Moitié opérations entières, moitié opérations mémoire, avec de quoi remplacer les opérations entières par des opérations flottantes. Le PA 8000, lui, dupliquait toutes ses unités en deux exemplaires, ce qui n'est pas l'idéal, aucun processeur moderne ne fait cela aujourd'hui. Le tout est résumé dans le tableau ci-dessous, avec : * en vert les CPU utilisant la première stratégie ; * en rouge les CPU utilisant la seconde stratégie ; * en jaune les CPU utilisant la troisième stratégie. {|class="wikitable" |+ Processeurs quadruple émission historiques |- ! Année !! Processeur !! Unités |- ! 1991 | class="f_jaune | Motorola 88110 || class="f_jaune | 2 ALU + MUL + DIV + BIT + MEM + FADD + 2 unités graphiques |- |- ! rowspan="2" | 1994 | class="f_vert | POWER 2 || class="f_vert | 2 ALU/MEM + 2 FPU (+ 2 Branchements via ''branch folding'') |- | class="f_rouge | 21164 || class="f_rouge | 2 ALU + FPU + MEM |- ! rowspan="3" | 1995 | PA 8000 || 2 ALU + 2 ''barrel shifters'' + 2 MEM + 2 FPU (FMA) + 2 FPU (DIV et SQRT) + 2 SIMD |- | class="f_jaune | UltraSPARC 1 || class="f_jaune | 2 ALU + MEM + BRANCH + FADD + FMULFDIV + 2 unités graphiques |- | MIPS R8000 et R10000 || 2 ALU + 2 FPU + 2 MEM |- ! rowspan="2" | 1996 | class="f_rouge | 620 || class="f_rouge | 2 ALU + FPU + MEM |- | class="f_vert | 21264 || class="f_vert | 2 ALU/MEM + 2 FPU (FADD + FMUL) |} Malheureusement, ces CPUs historiques n'avaient ni assez d'unités de calcul entières, ni d'unités mémoire, pour remplir la quadruple émission. Environ la moitié des instructions d'un programme correspond à des instructions entières. Pour en profiter, un processeur à N voies doit disposer d'au minimum N/2 ALU entières, l'idéal étant d'aller au-delà. Les CPU superscalaires historiques avaient 2 ALU pour de la quadruple émission, ce qui était très limite. En comparaison, les CPU superscalaires modernes mettent le paquet niveau ALU entière. La plupart des CPU x86 modernes descendent rarement sous les 2/3, la plupart remplit presque la totalité de la largeur du CPU. Pour donner un exemple, la microarchitecture Golden Cove d'Intel est un processeur à 6 voies, avec 5 ALU entières. Pour être précis, un programme informatique exécute environ 40% de son code dans des instructions arithmétiques, un autre 40% dans les accès mémoire, et un le reste pour... le reste. La conséquence est que les processeurs modernes dupliquent leurs unités mémoire. Par exemple, la microarchitecture ''Golden Cove'' d'Intel dispose de trois unités mémoire : deux spécialisées dans les écritures, trois dans les lectures. La microarchitecture ''Gracemont'' utilise la pentuple émission et peut émettre 4 µops entières et 4 µops mémoire. Notez que le ratio est équilibré entre opérations entières et mémoire, avec soit égalité, soit un avantage pour les ALU entières. Une autre régularité est que la largeur totale du processeur peut être occupée par des opérations entières/mémoire. Pour le dire autrement, sur un processeur quadruple émission, il pourra émettre un mix de 4 instructions entière/mémoire, avec zéro opération flottante. Idem avec des processeurs triples ou pentuple émission, voire plus. Si le processeur émet une opération flottante, elle remplace une opération entière. Prenons l'exemple des processeurs AMD K6, sortis en 1997, juste avant les AMD Athlon. Ils avaient 10 unités de calcul, 6 ports d'émission, 4 ports de décodage. Voici exactement comment étaient répartie les unités de calcul sur les ports d'émission. C'était des processeurs quadruple émission, ce qui fait que la moitié de la largeur du processeur sert pour des opérations entières, et l'autre moitié pour les accès mémoire. {|class="wikitable" |- ! Port d'émission n°1 !! Port d'émission n°2 !! Port d'émission n°3 !! Port d'émission n°4 !! Port d'émission n°5 !! Port d'émission n°6 ! |- | ALU entière || ALU entière || FPU || Unité de branchement || Unité LOAD || Unité STORE |- | || Multiplieur || || || || Unité de calcul d'adresse (instruction LEA) |- | || ''Barrel shifter'' || || || || Unité pour les instructions PUSH |} Les microarchitectures K7, K8 et K10, utilisées sur les anciens CPU AMD Athlon, sont un exemple moins représentatif. Ces microarchitectures utilisent le partage des ports d'émission au maximum. C'était des microarchitectures à triple émission, avec six ports d’émission. Il y avait trois ports d'émission pour les opérations flottantes, et trois ports d'émission pour les micro-opérations entières/mémoire. Il y avait trois ALU entières et trois unités mémoire, chaque ALU partageait un port d'émission avec une unité mémoire. Elle pouvait donc émettre soit trois opérations entières, soit trois µops mémoire, soit un mix des deux. En plus des mix avec les opérations flottantes et branchements. {|class="wikitable" |- ! Port d'émission n°1 !! Port d'émission n°2 !! Port d'émission n°3 !! Port d'émission n°4 !! Port d'émission n°5 !! Port d'émission n°6 ! |- | ALU entière || ALU entière || ALU entière || FADD || FMUL || FPU (autres opérations) |- | Multiplieur || || || || || |- | LOAD/STORE || LOAD/STORE || LOAD/STORE || || || |} Les CPU superscalaires larges dupliquent les multiplieurs et/ou les ''barrel shifters'', et même les unités de branchement. La raison est que quand la largeur du CPU augmente, le processeur traite des paquets d'instructions de plus en plus gros. Par exemple, pour un CPU à 10 voies, cela veut dire émettre 10 instructions en même temps. Il est alors plus fréquent d'avoir deux multiplications, deux décalages, deux accès mémoire, deux branchements. Par exemple, la moyenne est d'une multiplication tous les 5 instructions. Les CPU superscalaires à 10 voies ont donc tendance à avoir deux multiplications par paquet d'instruction, en moyenne. Avoir deux multiplieurs est alors un gain en performance clair. Par exemple, la microarchitecture ''Golden Cove'' a deux ''barrel shifters''. C'est une architecture à 6 voies. {|class="wikitable" |- ! Port d'émission n°1 !! Port d'émission n°2 !! Port d'émission n°3 !! Port d'émission n°4 !! Port d'émission n°5 !! Port d'émission n°6 !! Port d'émission n°7 !! Port d'émission n°8 !! Port d'émission n°9 !! Port d'émission n°10 |- | ALU entière || ALU entière || ALU entière || ALU entière || ALU entière || LOAD || LOAD || LOAD || STORE || STORE |- | ''Barrel shifter'' || Multiplieur || Multiplieur || ''Barrel shifter'' || || || || || || |- | Branchements || Diviseur || || Branchements || || || || || || |} ==Les µops mémoire sur les processeurs superscalaires== Plus haut, nous avons volontairement passé sous silence les accès mémoire. La raison à cela est que leur support sur les CPU superscalaire peut se faire de plusieurs manières différentes, qu'il vaut mieux expliquer dans une section dédiée. Les différentes implémentations sont décrites dans la liste suivante, nous allons les voir une par une. * Avec la première méthode, les accès mémoire sont exécutés par le pipeline pour les opérations entières. * Avec la seconde méthode, les accès mémoire ont un pipeline dédié ; c'est l'''émission parallèle des accès mémoire''. * Avec la troisième méthode, il est possible d'émettre plusieurs accès mémoire simultanément : c'est l'''émission multiple des accès mémoire''. Voyons ces trois cas dans le détail. Nous verrons notamment les différentes formes d'émission multiple des accès mémoire. ===Les accès mémoire traités dans le pipeline entier=== Dans le cas le plus simple, les accès mémoire sont traités comme des opérations entières un peu spéciales. L'unité mémoire est sur le même port d'émission que l'ALU entière, ce qui fait que les accès mémoire remplacent des opérations entières. Faire ainsi permet d'utiliser une ALU entière pour les calculs d'adresse, pas besoin de rajouter une unité de calcul d'adresse séparée. Typiquement, un processeur de ce type place l'unité mémoire après l'unité de calcul. Les opérations entières n'utilisent que l'ALU entière, mais pas l'unité mémoire. Les accès mémoire exécutent un calcul d'adresse dans l'ALU entière, puis l'adresse calculée est envoyée à l'unité mémoire. Le tout est illustré ci-dessous, dans le cas d'un processeur historique à double émission entière-flottante. [[File:Processeur non-superscalaire basique 01.png|centre|vignette|upright=1.5|Processeur non-superscalaire basique]] Un exemple de CPU double émission de ce type est celui du Power PC 440, un CPU destiné à l'embarqué. Vu qu'il était destiné à l'embarqué, il n'avait pas de FPU, il n'avait pas besoin de manipuler de nombres flottants. Il n'a donc que des ALU entières, un multiplieur et une unité mémoire. Il dispose de deux ports d'émission. Le premier est connecté à une ALU entière et un circuit multiplieur, le second est relié à l'unité mémoire et une seconde ALU entière. Une organisation simple, mais très efficace ! [[File:PowerPC 440.png|centre|vignette|upright=2|Microarchitecture du PowerPC 440.]] L'implémentation économise une unité de calcul d'adresse, mais n'a pas de cout en performance significatif. Les accès mémoire étant très lents, émettre une µop entière en parallèle d'un accès mémoire ne sert pas à grand-chose. On peut émettre cette µop entière un cycle plus tard, elle sera terminée avant même que l'accès mémoire soit terminé, même si l'accès mémoire se fait dans le cache L1 ou L2. Pour comprendre pourquoi, faisons quelques calculs. Un accès mémoire prend deux-trois cycles quand il tombe dans le cache L1. Et on doit attendre qu'il soit terminé pour en émettre un nouveau. Combien d'instructions arithmétiques peut-on lancer pendant ce temps, sur un CPU triple émission ? Au premier cycle, on peut en émettre 2 (l'instruction mémoire prend une place, donc 3-1), puis 3 au second cycle. Ce qui fait 5 instructions arithmétiques au total. Or, il se trouve qu'il y a une instruction d'accès mémoire pour 5 instructions arithmétiques, environ. Par contre, ce compromis change quand on passe à la quadruple émission, voire au-delà. Dans ce cas, il devient intéressant de pouvoir émettre une nouvelle instruction mémoire à chaque cycle. Ce qui nous amène à la section suivante... ===L'émission parallèle des accès mémoire=== A partir de la quadruple émission, la tendance a été de séparer l'unité mémoire des ALU entières. Cela permet d'émettre des µops mémoire en même temps que des µops entières et/ou flottantes., ce qui porte le nom d''''émission parallèle des µops mémoire''', ou encore ''émission mémoire parallèle''. Par exemple, un processeur quadruple émission peut émettre en même temps deux opérations entières, une opération flottante et un accès mémoire. L'accès mémoire vient en plus des opérations entières, il n'est pas possible de remplacer l'accès mémoire par une opération entière. La technique ne permet pas de faire les calculs d'adresse dans l'ALU entière. Il faut donc utiliser une unité de calcul d'adresse séparée. Elle est intégrée dans l'unité mémoire, qui fait l'interface entre le cache et le banc de registres. Le cout en circuits est très faible, car les unités de calcul d'adresse n'utilisent guère plus qu'un additionneur et un circuit de décalage très simple. L'émission mémoire parallèle est plus facile à implémenter sur les CPU RISC, qui ont des instructions mémoire séparées du reste. Les CPU CISC ne sont pas dans ce cas, ce qui fait que séparer l'unité mémoire du pipeline entier est compliqué. Les CPU superscalaires historiques étaient pour moité des CPU RISC et pour moitié des CPU CISC, ce qui fait qu'ils n'utilisaient pas ou peu l'émission mémoire parallèle. Les premiers processeurs superscalaires se contenaient de l'émission parallèle mémoire, ils ne pouvaient émettre qu'un seul accès mémoire à la fois, l'unité mémoire n'était pas dupliquée. Et ce n'est pas tant un problème que ça, du moins sur les processeurs à double ou triple émission. En effet, il est rare que l'unité mémoire doive faire deux accès simultanés. Notons que le processeur peut exécuter une instruction mémoire en parallèle d'un calcul ou d'un branchement, seuls les accès mémoire simultanés sont impossibles. ===L'émission multiple des accès mémoire avec une LSQ=== Les processeurs superscalaires larges travaillent sur des paquets de 8 à 10 instructions, il est plus fréquent d'avoir plusieurs accès mémoire par paquet. Dans ces conditions, il est utile d'avoir une '''émission multiple des accès mémoire''', à savoir d'émettre plusieurs micro-opérations mémoire en même temps. Les processeurs superscalaires modernes sont capables d'émettre plusieurs lectures/écritures simultanément. Par exemple, ils peuvent émettre une lecture en même temps qu'une écriture, ou plusieurs lectures, ou plusieurs écritures. Il faut noter que selon le processeur, il peut y avoir des restrictions quant aux accès mémoire émis en même temps. Par exemple, certains processeurs peuvent émettre une lecture avec une écriture en même temps, mais pas deux lectures ni deux écritures. Ou encore, ils peuvent émettre deux lectures, une lecture et une écriture, mais pas deux écritures en même temps. Dans la majorité des cas, les processeurs ne permettent pas d'émettre deux écritures en même temps, alors qu'ils supportent plusieurs lectures. Il faut dire que les lectures sont plus fréquentes que les écritures. Les processeurs qui autorisent toutes les combinaisons de lecture/écriture possibles, sont rares. L'émission multiple des accès mémoire s'implémente dans l'unité mémoire. Pour rappel, l'unité mémoire s'interpose entre le cache L1 et le reste du pipeline. Dans le cas le plus simple, elle incorpore une ''load/store queue'' et des unités de calcul d'adresse. L'émission multiple des accès mémoire demande de rendre la ''Load-store queue'' multi-ports, afin de gérer plusieurs micro-opérations mémoire simultanées. Il faut aussi dupliquer les unités de calcul d'adresse reliées à la LSQ, chaque port d'émission mémoire devant avoir sa propre unité de calcul d'adresse. : Dans ce qui suit, nous parlerons d'AGU (''Adress Generation Unit'') pour désigner les unités de calcul d'adresse, et de LSQ pour designer la ''Load-store queue''. [[File:Processeur non-superscalaire basique 02.png|vignette|upright=1|Processeur non-superscalaire basique]] Dupliquer les ports de la LSQ et les AGU est nécessaire. Mais qu'en est-il du cache ? La réponse varie suivant le processeur. Il y a deux grandes méthodes pour implémenter l'émission multiple des accès mémoire. La première méthode ajoute des ports de lecture/écriture au cache de données, pour faire des lectures/écritures simultanées. Il faut alors dupliquer des unités de calcul, rajouter les ports sur le cache, mais aussi rajouter des ports sur la ''load/store queue'', pour qu'elle échange des données/commandes mémoire avec le cache. Le cout en circuits est alors conséquent La seconde duplique les unités de calcul, mais pas les ports d'accès au cache. Les accès mémoire sont alors accumulés dans la ''load/store queue'', qui sont ensuite traités un par un par le cache. Un exemple est celui des processeurs AMD de micro-architecture K7 K8, à savoir les anciens AMD Athlon et AMD Athlon 64, qui pouvaient calculer trois adresses simultanément, mais ne pouvaient faire qu'un seul accès au cache par cycle. Le cout en circuit est modéré : les unités de calcul coutent très peu, les ports de la ''load/store queue'' coutent déjà un peu plus. Quelques processeurs utilisaient des solutions intermédiaires. Un processeur utilisant cette technique est, par exemple, capable d'émettre quatre µops mémoire en même temps, mais avec seulement deux ports sur le cache. Un exemple classique étant les Pentium 1 et 2 d'Intel, dont nous parlerons dans le chapitre suivant. ===L'émission séparée des LOAD et STORE=== De rares processeurs ont des ports d'émission qui peuvent faire indifféremment lecture comme écritures. Mais les processeurs modernes préfèrent séparer ports d'émission pour les lectures et les écritures. Un exemple est celui des processeurs Intel de micro-architecture Nehalem, qui avaient un port de lecture et un port d'écriture tous deux reliés à la ''Load-store queue'', chacun avec leur propre unité de calcul d'adresse. Comme autre exemple, les processeurs skylake ont une LSQ avec deux ports de lecture et un port d'écriture, ce qui permet d'émettre deux lectures en même temps qu'une écriture. Dans cette section, nous allons étudier le cas avec des ports séparés pour les lectures et écritures. En général, les processeurs ont un peu plus de ports de lectures que d'écritures. Une raison est qu'un programme a, en moyenne, un tout petit peu plus de lectures que d'écritures. Mais la différence n'est pas énorme, c'est un léger déséquilibre. Une seconde raison est que l'exécution dans le désordre marche bien mieux quand les lectures ont lieu le plus tôt possible. Donc mieux vaut privilégier les lectures à l'émission, pour qu'elles se fassent un peu en avance. En pratique, la différence n'est pas très marquée. Il est courant d'avoir un port de lecture et un d'écriture, les CPU superscalaires très larges ont souvent deux ports de lecture et deux d'écriture. A la rigueur, quelques CPU ont trois ports de lecture et deux d'écriture. Le cas le plus simple est celui où on peut émettre une lecture et une écriture en même temps. Il s'implémente facilement si la LSQ est en réalité une simple ''Store queue'', à savoir qu'elle met en avance les écritures uniquement. Pour rappel, les écritures sont mises en attente dans la ''Store queue'', mais les lectures sont exécutées immédiatement. Une fois l'adresse à lire connue, la lecture consulte la ''Store queue'' pour détecter les dépendances de données, puis s'exécute. La donnée à lire est lue soit depuis la ''Store queue'', soit depuis le cache. [[File:Emission LOAD - Store séparée.png|vignette|upright=1|Émission LOAD - Store séparée]] L'implémentation de l'émission multiple est alors très simple. La ''Store queue'' a déjà deux ports, avec un pour les lectures et un autre pour les écritures. Idem pour le cache, qui a naturellement un port de lecture et un d'écriture. Émettre une lecture et une écriture simultanément ne demande donc pas de modification digne de ce nom. La ''Store queue'' doit juste supporter une lecture et une écriture simultanée. Ajouter l'émission d'une seconde lecture n'est pas compliquée : il faut juste rajouter un second port de lecture sur le cache et la ''Store queue''. Pour rappel, l'unité mémoire est précédée par une structure qui met en attente les micro-opérations mémoire avant leur émission finale. La structure en question varie suivant l'implémentation, mais un cas particulier se marie bien avec l'émission multiple des µops mémoire. Il s'agit du cas avec une file de µops séparée pour les lectures et une autre pour les écritures, appelées respectivement la ''file de µops LOAD'' et la ''file de µops STORE''. Il est alors possible d'émettre une lecture et une écriture lors du même cycle d'horloge. Le port de lecture alimente une unité de calcul d'adresse dédiée, directement reliée au cache. Le port d'écriture du cache alimente une unité de calcul, qui est suivie par une file d'écriture, elle-même reliée au cache. Les processeurs AMD de micro-architecture K6 utilisaient cette technique. [[File:Double émission avec le Load Ordering, Store Ordering.jpg|centre|vignette|upright=2.5|Double émission avec le Load Ordering, Store Ordering]] ==Les CPU superscalaire à exécution dans le désordre== La superscalarité modifie aussi les circuits dédiés à l'exécution dans le désordre. Elle modifie les unités de renommage de registre, le ROB et les autres structures liées à l'exécution dans le désordre, au sens large. Aucune structure n'est épargnée. Elles ont tous des prots de lecture/écriture en plus, afin d'encaisser l'émission, le ''commit'' ou le renommage simultané de plusieurs µops. Par exemple, le ROB doit être modifié pour émettre et terminer plusieurs instructions en même temps, en ajoutant des ports de lecture/écriture. Pour un CPU superscalaire à 8 voies, on se dit que le ROB peut retirer 8 µops par cycle maximum. Mais certains processeurs récents ont un ROB qui peut retirer le double ! Un exemple est celui des CPU de micro-architecture Skymont, qui peuvent émettre 8 µops par cycle, mais en retirer 16. Quelques CPU de marque AMD étaient aussi dans ce cas. L'avantage est que cela permet de réduire la taille du ROB, du banc de registre et de quelques autres structures matérielles liées à l'exécution dans le désordre. Le gain sur-compense le cout en transistor nécessaire pour retirer 16 µops par cycle. Dans cette section, nous allons voir comment les étages du pipeline dédiés à l'exécution dans le désordre sont modifiées sur un CPU superscalaire. ===L'exemple du PA-RISC PA 8000=== Avant de commencer, nous allons voir un processeur superscalaire assez simple, le PA 8000, de HP, qui implémente le jeu d'instruction PA-RISC. Bien que très ancien, il implémentait l'exécution dans le désordre et le renommage de registre. Le peu d'informations que nous avons sur ce processeurs proviennent des documents "THE HP PA-8000 RISC CPU" par Ashok Kumar, et l'article de microprocessor report "PA-8000 Combines Complexity and Speed". Ils ne donnent malheureusement pas énormémment d'informations et je devrais être amené à faire quelques suppositions dans ce qui suit. Avant de commencer, parlons de détails sans lien avec la superscalarité. Ce processeur, comme beaucoup de processeurs PA-RISC, n'intégrait pas de cache de niveau L2 dans le processeur, qui était déporté en-dehors du CPU, sur la carte mère. Le processeur préférait utiliser ses transistors pour avoir un cache L1 assez large, quitte à ce qu'il soit plus lent. La lenteur du cache était prévue, le processeur compensait celle-ci en utilisant l'exécution dans le désordre, bien que ce ne soit pas parfait. Les CPU PA-RISC avant le PA 8000 utilisaient un pipeline à vagues ''wave pipeline'', ce qui était assez peu commun, mais le PA 8000 repasse à un pipeline synchrone classique. Passons maintenant à la superscalarité. Le PA 8000 est un processeur quadruple émission, qui peut émettre, à chaque cycle, deux opérations et deux accès mémoire. Le renommage de registre utilise des registres de renommage séparés des registres architecturaux, comme c'était la mode à l'époque. Le budget en transistor faisait que c'était soit ça, soit le renommage dans le ROB, faute de mieux. Le processeur utilise une implémentation ''Read After Issue'', ce qui veut dire que les opérandes des instructions sont lues après l'émission, juste avant l'exécution. Le processeur peut aussi ''commit'' deux opérations et deux accès mémoire par cycle, ce qui revient à transférer les résultats des registres de renommage vers les registres architecturaux. L'exécution dans le désordre est prise en charge par une structure matérielle unique, qui ressemble à une fusion entre un ROB et une fenêtre d'instruction. Et c'est là que je vais devoir faire des suppositions. Le document "THE HP PA-8000 RISC CPU" nomme cette structure : l''''''Instruction Reorder Buffer'''''. Il utilise pas moins de 850 000 transistors, et prend 20% de la taille du ''die''. L'article "THE HP PA-8000 RISC CPU" laisse fortement sous-entendre qu'il s'agit une structure unique, faite d'un seul tenant, mais l'article de microprocessor report dit le contraire par moment. Il est décrit comme une fenêtre d'instruction, à savoir qu'il détecte les dépendances entre instruction et les émet. Il gère aussi la détection des mauvaises prédictions de branchement et peut annuler les instructions chargées à tord, en les retirant de la fenêtre d'instruction. Il est aussi précisé que les instructions quittent cet ''Instruction Reorder Buffer'' dans l'ordre du programme. Elles ne peuvent en sortir que quand elles ont été exécutées et qu'elles n'ont causé aucune exception. Ce qui fait qu'il se comporte comme un ROB de ce point de vue là. Difficile de dire si l'''Instruction Reorder Buffer'' est un réel mélange entre un ROB et une fenêtre d'instruction, ou si il est réellement conçu avec deux structures séparées. Dans ce qui suit, je pars du principe que les deux structures sont séparées. Le processeur contient deux fenêtres d'instruction : une réservée aux µops mémoire (LOAD et STORE), l'autre pour les opérations entières/flottantes. Elles ont chacune 28 entrées, ce qui permet de mémoriser 56 µops au maximum. Les deux peuvent recevoir 4 µops par cycle de la part des décodeurs. Là encore, précisons que les choses ne sont pas claires pour ce qui est de la séparation. L'article de Microprocessor report dit que les deux sont physiquement séparées, et que cette séparation physique permet de simplifications (les opérations mémorisent des noms de registres plus court que les adresses demandées par les µops LOAD/STORE). Mais l'autre document cité laisse penser que l''''Instruction Reorder Buffer'' est une structure unique. A chaque cycle, le processeur peut émettre deux instructions de calcul et deux instructions mémoire. Les deux fenêtres d'instruction ont pour cela chacune deux ports d'émission. Les deux ports d'émission pour les µops mémoire sont identiques, et le cache L1 est un cache double port, ce qui permet d'exécuter deux lectures/écritures par cycle. Pour ce qui est des µops entières/flottantes, le processeur a dupliqué toutes ses unités de calcul : il a deux ALU entières, deux ''barrel shifters'', deux FPU de type FMAC, et deux unités de division flottante. Vraisemblablement, il y a deux ports d'émission, chacun étant connecté à une unité de chaque type. : S'il n'utilisait pas l'exécution dans le désordre, ce processeur aurait donc quatre pipelines : deux pipeline entiers identiques et deux pipelines mémoire. Et il aurait une superscalarité presque parfaite s'il était un CPU à double émission ! A chaque cycle, la fenêtre d'instruction émet les deux µops les plus anciennes qui sont prête à être exécutées. La documentation dit que la fenêtre émet "la plus vielle instruction paire, et la plus vielle instruction impaire", ce qui sous-entend que la fenêtre d'instruction est segmentée en deux. C'est précisémment la logique d'éveil et d'émission qui est segmentée, une partie gérant la moité de la fenêtre d'instruction, une seconde logique d'éveil/''schedule'' gérant le reste. [[File:PA 8000 - microarchitecture.png|centre|vignette|upright=2|PA 8000 - microarchitecture]] ===La superscalarité avec une file/fenêtre d'instruction centralisée=== Plus haut, nous avons montré qu'un processeur pouvait avoir plus de ports d'émission que de ports de décodage. On dit aussi que sa ''largeur de décodage'' était supérieure à sa ''largeur d'émission''. La '''largeur de décodage''' est le nombre de µops fournies par l'unité de décodage par cycle d'horloge, la '''largeur d'émission''' est le nombre maximal de µops émises par cycle d'horloge. Et n'allez pas croire qu'un surplus de ports d'émission est du gâchis. Sur les processeurs avec exécution dans le désordre, ce surplus peut être utilisé. Mais avant toute chose, évacuons un détail. Vous avez sans doute pensé que le surplus peut être exploité par les instructions machines décodées en plusieurs µops . Par exemple, si une instruction est décodée en deux µops, on pourrait avoir un port d'émission en plus pour en profiter. Mais les ports de décodage sont *en sortie du décodeur*, et contiennent des µops, pas des instructions. Le surplus de ports d'émission peut occasionnellement utiliser le surplus de ports de décodage, mais cela implique que des µops ont été mises en attente dans l'unité d'émission, pour être émises par la suite. Et cela implique l'usage d'une fenêtre d'instruction ou d'une file de µops. Le principe est que les µops sont accumulées dans la fenêtre d'instruction, en attendant leurs opérandes ou la résolution d'une dépendance. Et si l'occasion se présente, une µops est émise sur chaque port d'émission. Il y a donc un gain en performances, mais il faut faire quelques précisions sur son origine. La largeur d'émission utilisée ne peut pas dépasser, *en moyenne*, la largeur de décodage. Et c'est intuitif : un CPU qui décode 4 µops par cycle ne peut pas émettre 6 par cycle en moyenne, sur le temps long, il n'y a pas de µops en surplus qui sortent du vide. Par exemple, sur un processeur quadruple émission, si on analyse combien d'instructions sont émises par cycle, il peut y avoir des cycles où la largeur d'émission est totalement utilisée, mais ce sera compensé par des périodes où elle est fortement sous-utilisée. Les µops sont accumulées en cas de sous-utilisation, puis consommées en cas d'utilisation complète. Les deux périodes se compensent. Et c'est là que l'on peut comprendre d'où vient le gain en performance. Les cycles où les ports d'émission sont sous-utilisés existent systématiquement, que le processeur utilise l'exécution dans le désordre ou pas. Ils sont liés à la présence de dépendances de données, aux contraintes d’appariement, etc. Elles tendent à réduire la moyenne du nombre de µops émises par cycle. Par contre, ce sont les cycles de rattrapage, où les ports en surplus sont utilisés, qui font remonter la moyenne. Le gain en performance est donc lié à ces cycles de rattrapage, où les µops accumulées sont émises dans les ports en surplus. Et ils n'existent que sur les processeurs avec une file/fenêtre d'instruction. Réduire le nombre de ports d'émission permet de garder des fenêtres d'instruction et un ROB simples, rapides et économes en énergie. Et mine de rien, c'est là un compromis important : à quoi bon augmenter le nombre de ports d'émission si c'est pour que ce soit compensé par une fréquence plus faible ? Par contre, réduire le nombre de ports augmente la ''port contention'', surtout si on a mal réparti les ALU. Il faut donc trouver un compromis entre réduire le nombre de ports d'émission d'un côté, réduire la ''port contention'' de l'autre. La différence entre largeur de décodage et d'émission a un impact assez fort sur le banc de registre, et précisément sur son nombre de ports de lecture. Le banc de registre a besoin de plus de ports de lecture avec une fenêtre d’instruction qu'avec des stations de réservation. Rappelons la terminologie utilisée dans ce cours. Les fenêtres d'instruction se contentent de mémoriser la micro-opération et quelques bits pour détecter la disponibilité des opérandes. Par contre, les stations de réservations mémorisent aussi les opérandes des instructions. Et cette différence a une influence le nombre de ports de lecture du banc de registre. Supposons que toutes les instructions sont dyadiques, à deux opérandes. Comptons le nombre de ports nécessaires pour alimenter les unités de calcul, sans utiliser d'arbitre de banc de registre. Avec une fenêtre d'instruction, il faut le double du nombre de ports d'émission. Mais avec des stations de réservation, il faut le double des ports de décodage. La raison est que les registres sont lus après émission avec une fenêtre d'instruction, avant avec des stations de réservation (sous-entendu, après le décodage). Or, comme dit plus haut, les processeurs superscalaires larges ont souvent plus de ports d'émission que de décodage. ===La superscalarité à fenêtres d'instruction décentralisées=== Les processeurs précédents utilisaient une unité d'émission simple, qui pouvait utiliser l'émission dans l'ordre ou dans le désordre. Elle peut être remplacée par une fenêtre d'instruction centralisée dans que cela quoi que ce soit aux explications précédentes, idem avec une station de réservation centralisée. En soi, l'exécution dans le désordre est donc totalement compatible avec une implémentation simple de la superscalarité. Par contre, des subtilités surviennent avec les fenêtres d'instruction décentralisées. Pour rappel, sur ces processeurs, les µops sont émises en deux phases. Une première phase de ''dispatch'' qui envoie les µops vers la fenêtre d'instruction adéquate, sans détecter les dépendances de données. La seconde phase de ''schedule'' gère les dépendances de données, elle met en attente les µops en attendant que l'unité soit disponible pour les exécuter, en attendant aussi que les opérandes soient disponibles. Et à ce petit jeu, il y a une différence entre le nombre de µops qui sont ''dispatch par cycle'' et celles qui sont ''schedule''. Dit autrement, la largeur d'émission est scindée en une '''largeur de ''dispatch''''' et une '''largeur de ''schedule''. Par exemple, prenons un processeur triple émission avec deux stations de réservation : une pour les µops entières/mémoire, et une autre pour les µops flottantes. L'unité d'émission peut ''dispatch'' maximum trois µops par cycle : soit trois µops entières/mémoire, soit trois flottantes, soit un mix de trois µops différentes. Les stations de réservation, quant à elles, peuvent chacune ''schedule'' 3 µops par cycle, vers trois ALUs entières pour la station de réservation entière/mémoire, vers trois FPS pour la station de réservation flottante. De quoi ''dispatch'' trois µops, mais d'en ''schedule'' six, à chaque cycle. Et cet exemple ne sort pas de nulle part : les CPU x86 d'Intel et AMD sont globalement dans ce cas, même si les chiffres varient d'une microarchitecture à l'autre. L'exemple précédent colle parfaitement à la microarchitecture K7 d'AMD, utilisée sur les processeurs Athlon dans les années 2000. [[File:AMD K7.png|centre|vignette|upright=2.5|AMD K7, microarchitecture.]] L'exemple précédent avait assez d'unités entières/flottantes pour couvrir toute la largeur de décodage/''Dispatch''. Mais ce n'est pas toujours le cas, comme va le montrer l'exemple suivant. Le MIPS R10000, qui utilisait un mélange de files de µops et de fenêtres d'instructions : une file de µops les accès mémoire, une fenêtre pour les instructions entières et une autre pour les opérations flottantes. Les branchements et NOPs étaient exécutés dans une unité de branchement distincte. Les trois files/fenêtres peuvent mémoriser 16 µops. Le processeur avait deux ALU entières, une AGU de calcul d'adresse, un additionneur flottant et un multiplieur/diviseur flottant. Il y avait un multiplieur entier sur le port d'émission l'ALU 2. Le processeur décodait 4 instructions par cycle et produisait jusqu'à 4µops, qui étaient redistribuées sur les trois fenêtres d'instructions. Chacune pouvait accepter 4 µops par cycle, ce qui fait que processeur pouvait ''dispatch'' 4 µops entières, ou 4 µops flottantes, ou 4 µops mémoire, ou un mélange de deux ou trois types de µops. Pour ce qui est du ''schedule'', la fenêtre d'instruction entière pouvait émettre 2 µops, la fenêtre flottante pouvait émettre une addition en même temps qu'une multiplication/divison flottante et qu'un branchement conditionnel flottant, et la file de µops mémoire ne pouvait émettre qu'une µop mémoire à la fois. En tout, cela fait 6 µops ''schedule'' pour 4 µops au ''dispatch''. [[File:R 10000.png|centre|vignette|upright=2.5|MIPS R10000, microarchitecture.]] ===La superscalarité à fenêtres d'instruction totalement décentralisées=== Prenons un cas extrême de fenêtre d'instruction décentralisée : celui où chaque ALU entière a sa propre station de réservation. En clair : une fenêtre d'instruction par ALU/FPU ! On parle de '''fenêtres d'instruction totalement décentralisées'''. Vous vous dites que ce cas est un peu trop extrême pour être réaliste, mais il n'en est rien. C'est même très courant sur les architectures basse consommation, et sur pas mal de CPU x86 modernes. Une telle organisation entraine une légère perte de performance, comparé à une fenêtre d'instruction centralisée ou partiellement décentralisée. Et cela peut se comprendre par un exemple. Imaginez un processeur avec deux ALU, donc deux stations de réservation. Il arrivera qu'une station de réservation ait plusieurs µops prêtes, alors que l'autre en ait zéro. Dans une telle situation, une seule µop sera émise au cycle suivant, vu que chaque station de réservation a un seul port d'émission vers une seule ALU entière. Par contre, avec une fenêtre d'instruction centralisée double port, on aurait pu émettre les deux µops en même temps sur deux ALUs séparées. La perte de performance est donc liée au fait que les µops '''''prêtes''''' sont mal réparties dans les différentes stations de réservation. Il arrivera que des µops prêtes s'accumulent dans une station de réservation, alors que d'autres seront pleines, ou du moins sous-utilisées. Et ce n'est pas quelque chose qui peut être réglé à l'étape de ''dispatch'', car on ne sait pas encore quand les µops auront leurs opérandes de disponibles. [[File:Comparaison entre une station de réservation totalement décentralisée et une autre qui ne l'est pas.png|centre|vignette|upright=2.5|Comparaison entre une station de réservation totalement décentralisée et une autre qui ne l'est pas.]] Par contre, décentraliser totalement les fenêtres d'instruction entraine aussi un gain considérable en termes de consommation énergétique. Et c'est la raison pour laquelle les fenêtres d'instructions totalement décentralisées sont utilisées sur les architectures basse consommation. La perte de performance ne peut pas s'expliquer clairement à ce stade du cours, car il nous faudrait parler d'émission superscalaire. Le gain en matière d'énergie vient de l'économie de circuits, qui est assez drastique. Le gain en matière d'énergie vient de l'économie de circuits, qui est assez drastique. Je rappelle qu'une station de réservation a besoin, pour N instructions, d'environ N^2 circuits (des comparateurs, notamment). Prenons une station de réservation centralisée de 64 entrées et comparons avec 8 stations de 8 entrées chacune. Les deux donneront 64 entrées, mais la première aura un cout en circuit proportionnel à 64², alors que le second aura un cout en circuit de 8 *(8²). Entre les deux, le choix est clair : la seconde solution est plus économe. D'où l'utilisation de cette solution sur les microarchitectures basse consommation. ===L'unité de renommage superscalaire=== Avec la superscalarité, l'unité de renommage de registre doit gérer le cas où des instructions consécutives ont des dépendances de registre. Par exemple, prenons un processeur à double émission, qui renomme deux instructions consécutives. Si elles ont une dépendance de registre, le renommage de la seconde instruction dépend du renommage de la première. La première doit être renommée et le résultat du renommage est utilisé pour renommer la seconde, ce qui empêche d'utiliser deux unités de renommage séparées. Pour cela, elle renomme les registres sans tenir compte des dépendances, pour ensuite corriger le résultat. [[File:Unité de renommage superscalaire.png|centre|vignette|upright=2|Unité de renommage superscalaire.]] Seules les dépendances lecture-après-écriture doivent être détectées, les autres étant supprimées par le renommage de registres. Repérer ce genre de dépendances se fait assez simplement : il suffit de regarder si un registre de destination d'une instruction est un opérande d'une instruction suivante. [[File:Détection des dépendances sur un processeur superscalaire.png|centre|vignette|upright=2|Détection des dépendances sur un processeur superscalaire.]] Ensuite, il faut corriger le résultat du renommage en fonction des dépendances. Si une instruction n'a pas de dépendance avec une autre, on la laisse telle quelle. Dans le cas contraire, un registre opérande sera identique avec le registre de destination d'une instruction précédente. Dans ce cas, le registre opérande n'est pas le bon après renommage : on doit le remplacer par le registre de destination de l'instruction avec laquelle il y a dépendance. Cela se fait simplement en utilisant un multiplexeur dont les entrées sont reliées à l'unité de détection des dépendances. On doit faire ce replacement pour chaque registre opérande. [[File:Correction des dépendances sur un processeur superscalaire.png|centre|vignette|upright=2|Correction des dépendances sur un processeur superscalaire.]] ==Les optimisations des processeurs superscalaires larges== Les processeurs superscalaires larges ont des optimisations spécifiques, qui n'ont pas de sens sur les processeurs superscalaires étroits. Dans les grandes lignes, elles se classent en deux types. Les premières permettent de charger/décoder plus de 5-10 instructions simultanément. Le problème est alors que les branchements viennent mettre leur grain de sel et qu'il faut en tenir compte. Les secondes corrigent des problèmes qui apparaissent quand un CPU intègre plus de 5 à 10 unités de calcul. ===L'étape de chargement d'un CPU superscalaire large=== Charger plusieurs instructions pose de nombreux problèmes sur les processeurs superscalaires larges, qui émettent de 5 à 10 instructions simultanées. Pour rappel, la stratégie basique pour charger N instructions est de charger un bloc de N instructions consécutives. Les instructions après un branchement ne sont pas décodées ni exécutées, ce qui entraine une petite baisse de performance. Pour un N petit, la perte de performance est mineure. Mais pour un N large, elle devient suffisamment importante pour que la conception du CPU doit alors être repensée de fond en comble. Les analyses statistiques disent qu'il y a environ un branchement tous les 4 à 6 instructions. Un CPU a donc tendance à décoder des paquets de 3 à 5 instructions consécutives, avant qu'un branchement casse la dynamique. Or, cela pose des problèmes pour utiliser plusieurs décodeurs. L'implémentation basique, qui charge N instructions consécutives pour alimenter N décodeurs, fonctionne donc jusqu'à 4/6 décodeurs. Au-delà de 5 instructions, un CPU superscalaire doit être adapté pour gérer les branchements dans les paquets d'instruction qu'il émet. Le nombre de 5 instructions ne sort donc pas de nulle part. La première solution utilise un cache de µops, avec un ''front-end'' capable de charger/décoder 4/5 instructions à la fois, pas plus. L'idée est que la majorité des instructions proviennent du cache de µops (plus de 80%), ce qui fait qu'on peut émettre environ 10 instructions à partir du cache de µops, pas besoin d'avoir beaucoup de décodeurs. Les performances sont cependant dégradées lors d'un défaut de cache de µops. Les instructions doivent alors être chargées depuis le cache d'instruction, par paquets de 4-5, puis sont décodées par 4-5 décodeurs, ce qui ne permet pas d’alimenter les unités de calcul à plein régime. La solution précédente joue sur la distinction entre pots de décodage et d'émission. Elle permet d'émettre un grand nombre de µops sans pour autant charger un grand nombre d'instructions en même temps. En quelque sorte, ce n'est qu'une méthode de contournement, le CPU superscalaire reste de type étroit. Mais il est aussi possible d'utiliser un '''''front-end large''''', capable de charger une bonne dizaine d'instructions en même temps. La seule difficulté est de tenir compte de la présence de branchements. Pour rappel, avec un ''front-end'' étroit, les instructions situées après le premier branchement pris sont annulées, elles ne sont pas décodées ni exécutées. [[File:Fetch sur un processeur superscalaire avec prediction de branchements.png|centre|vignette|upright=2|Fetch sur un processeur superscalaire avec prédiction de branchements.]] Un ''front-end'' large charge les instructions de destination du branchement et les placent à sa suite. Ils chargent deux blocs à la fois et les fusionnent en un seul qui ne contient que les instructions présumées utiles. [[File:Cache d'instructions autoaligné.png|centre|vignette|upright=2|Cache d'instructions auto-aligné.]] Mais cela demande de charger deux blocs de mémoire en une fois, ce qui demande un cache d'instruction multiports. Il faut aussi ajouter un circuit pour assembler plusieurs morceaux de blocs en un seul : le fusionneur (''merger''). En pratique, cette solution demande d'ajouter un second port de lecture au cache, pour un cout en hardware important, avec un impact négatif sur le temps d'accès au cache. Et il faut rajouter le fusionneur, qui prend un étage de pipeline à lui tout seul. Et encore, cette solution ne gère pas le cas où un bloc contient plusieurs branchements ! [[File:Implémentation d'un cache d'instructions autoaligné.png|centre|vignette|upright=2|Implémentation d'un cache d'instructions auto-aligné.]] Les exemples précédents partent du principe qu'il n'y a qu'un seul branchement dans un bloc. Mais quand les blocs deviennent assez longs, il est fréquent d'avoir plusieurs branchements dans un bloc. Et il est même possible d'avoir plusieurs branchements pris. Dans un bloc de 8-10 instructions, ce n'est pas rare, et les CPU superscalaires à 8-10 voies sont la règle dans les CPU des années 2020. Pour gérer ce cas, il faut ajouter des ports supplémentaires au cache d'instruction et adapter le fusionneur, pour qu'il puisse fusionner trois ou quatre blocs. De plus, il faut utiliser une unité de prédiction de branchement capable de ''prédire plusieurs branchements par cycle''. ===Le décodage superscalaire large=== Le décodage des instructions n'est pas censé dépendre de l'implémentation du chargement. En théorie, une fois plusieurs blocs d'instruction fusionnés, on peut décoder les instructions en parallèle. Cependant, certains processeurs effectuent le décodage en tenant compte de la manière dont les branchements découpent les blocs. Les processeurs Atom d'Intel utilisent une solution de ce type, qui couple prédiction de branchement et décodage parallèle. Ils chargent/décodent des paquets de 3 instructions consécutives, chaque paquet étant séparé du précédent par un branchement. Pour cela, en plus d'avoir un fusionneur adapté, ils regroupent les décodeurs en ''clusters'', chacun regroupant 3 décodeurs, et pouvant décoder trois instructions consécutives. Les micro-architectures Tremont et Crestmont avaient deux ''clusters'' (6 décodeurs au total), la micro-architecture Darkmont en intègre trois (9 décodeurs au total). Avec deux ''clusters'', le fonctionnement est le suivant. Si le code est composé d'une suite d'instruction sans branchements, seul le premier ''cluster'' est utilisé, limitant le décodage à trois instructions par cycle. Par contre, si l'une des trois instructions décodée est un branchement, alors le second ''cluster'' décode les trois instructions situées après ce branchement, à partir de l'adresse de destination. Avec un troisième ''cluster'', c'est la même chose, sauf qu'il faut qu'il y ait un branchement dans les trois instructions décodées par le second ''cluster''. Mais comment faire pour savoir quels décodeurs activés, quels ''clusters'' sont actifs ? C'est la prédiction de branchement qui commande. Avec deux ''clusters'', elle détermine si un branchement est présent dans les trois instructions à charger, et quelle est son adresse de destination. Sans branchement, elle prévient les décodeurs et les trois instructions chargées sont décodées dans un ''cluster'' libre. Si elle prédit un branchement, elle charge les instructions adéquates, et active les deux ''clusters''. Avec trois branchements, c'est le même mécanisme, sauf que l'unité de prédiction de branchement doit être capable de prédire deux branchements par cycle. [[File:Front-end découplé de la microarchitecture Tremont.png|centre|vignette|upright=3|Front-end découplé de la microarchitecture Tremont.]] Il faut noter que les décodeurs d'un ''cluster'' sont des décodeurs simples, sans microcode. Sur les processeurs Tremont et Crestmont, le microcode était unique et était partagé entre tous les ''clusters''. Un seul ''cluster'' pouvait décoder une instruction complexe avec le microcode, l'autre devait se limiter à des instructions simples uniquement. Depuis Skymont, le microcode est partiellement dupliqué, avec un microcode par ''cluster''. Le cout en hardware peut paraitre prohibitif, pour un gain en performance faible. Sauf que c'est oublier que ce sont des processeurs Atom, sur lesquels beaucoup d'instructions sont microcodées. Les processeurs Atom ont un budget en transistor limité, ce qui fait qu'il est préférable pour eux d'implémenter des instructions en microcode que d'utiliser des unités de calcul dédiées ou des circuits de décodage complexes. Pour limiter la casse, le microcode n'est que partiellement dupliqué. Seul le microcode pour les instructions fréquente est dupliqué. Il y a un microcode secondaire pour certaines instructions, qui est lui unique et partagé par tous les ''clusters''. ===Le contournement sur les processeurs superscalaires larges=== Pour rappel, la technique du contournement (''register bypass'') permet au résultat d'une instruction d'être immédiatement utilisable en sortie de l'ALU, avant même d'être enregistré dans les registres. Implémenter la technique du contournement demande d'utiliser des multiplexeurs pour relier la sortie de l'unité de calcul sur son entrée si besoin. Il faut aussi des comparateurs pour détecter des dépendances de données. [[File:Pipeline Bypass.png|centre|vignette|upright=1|Pipeline Bypass]] La sortie de chaque ALU doit être reliée aux entrées de toutes les autres, avec les comparateurs qui vont avec. Sur les processeurs ayant plusieurs d'unités de calculs, cela demande beaucoup d’interconnexions et de comparateurs. Pour N unités de calcul, cela demande 2 * N² interconnexions, implémentées avec 2N multiplexeurs de N entrées chacun. Si c'est faisable pour 2 ou 3 ALUs, la solution est impraticable au-delà. Non seulement ce serait un enfer à câbler, mais les fils seraient tellement longs que la fréquence du processeur en prendrait un coup. Notez que cela vaut pour les processeurs superscalaires, mais aussi pour tout processeur avec beaucoup d'unités de calcul. En théorie, un CPU à exécution dans le désordre, non-superscalaire, mais avec beaucoup d'unités de calcul, fait face au même problème. En pratique, avoir une dizaine d'ALU implique processeur superscalaire à exécution dans le désordre. D'où le fait qu'on parle du problème maintenant. La seule solution praticable est de ne pas relier toutes les unités de calcul ensemble. À la place, on préfère regrouper les unités de calcul dans différents '''agglomérats''' ('''cluster'''). Le contournement est alors possible entre les unités d'un même agglomérat, mais pas entre agglomérats différents. Évidemment, certaines possibilités de contournement sont perdues, mais c'est compensé par un gain en fréquence et un cout en circuit/fils réduit. C'est un bon compromis, ce qui explique que presque tous les processeurs modernes l'utilisent. Les rares exceptions sont les processeurs POWER 4 et POWER 5, qui ont préféré se passer de contournement pour garder un processeur très simple et une fréquence élevée. ===Le banc de registre des processeurs superscalaires larges=== Pour émettre deux opérations entières simultanément, il faut lire deux fois plus d'opérandes. Et il faut aussi écrire deux résultats dans les registres, en même temps. Pour cela, on double les ports du banc de registre. En général, il faut au maximum 2 ports de lecture et un port d'écriture par unité de calcul. Le problème, c'est que plus un banc de registres a de ports, plus il utilise de circuits, est compliqué à concevoir, consomme de courant et chauffe. Avec plusieurs dizaines d'unités de calcul différentes, ajouter autant de ports impacterait la fréquence du banc de registres et réduirait les performances, voire est totalement impraticable à cause des contraintes thermiques. Les processeurs superscalaires larges doivent donc trouver des solutions. La première solution utilise un banc de registre unique, mais n'utilise pas autant de ports que le pire des cas le demanderait. Le processeur détecte quand il n'y a pas assez de ports pour servir toutes les micro-opérations. Quand ça arrive, l'unité d'émission émet assez de micro-opérations pour exploiter les ports disponibles, mais met en attente les micro-opérations en trop, le temps que les ports se libèrent. Pour cela, le banc de registre est géré par un circuit d'arbitrage spécialisé, intégré à l'unité d'émission, l’'''arbitre du banc de registres''' (''register file arbiter''). Une autre solution est de dupliquer le banc de registres en plusieurs exemplaires qui contiennent exactement les mêmes données, mais avec moins de ports de lecture/écriture. Un exemple est celui des processeurs POWER, Alpha 21264 et Alpha 21464. Sur ces processeurs, le banc de registre est dupliqué en plusieurs exemplaires, qui contiennent exactement les mêmes données. Les écritures dans les registres sont envoyées à tous les bancs de registres, afin de garantir que leur contenu est identique. Chaque exemplaire a exactement deux ports de lecture. La conception du processeur est simplifiée, que ce soit au niveau du câblage, que de la conception des bancs de registres. Une dernière solution découpe le banc de registres en plusieurs bancs de registres plus petits, avec un réseau d'interconnexions pour échanger des données entre bancs de registres. Dans la plupart des cas, cette séparation est invisible du point de vue de l'assembleur et du langage machine. Le processeur se charge de transférer les données entre bancs de registres suivant les besoins. Sur d'autres processeurs, les transferts de données se font via une instruction spéciale, souvent appelée ''COPY''. [[File:Banc de registres distribué.png|centre|vignette|upright=2|Banc de registres distribué.]] Sur de certains processeurs, un branchement est exécuté par une unité de calcul spécialisée. Or les registres à lire pour déterminer l'adresse de destination du branchement ne sont pas forcément dans le même agglomérat que cette unité de calcul. Pour éviter cela, certains processeurs disposent d'une unité de calcul des branchements dans chaque agglomérat. Dans les cas où plusieurs unités veulent modifier le ''program counter'' en même temps, un système de contrôle général décide quelle unité a la priorité sur les autres. Mais d'autres processeurs fonctionnent autrement : seul un agglomérat possède une unité de branchement, qui peut recevoir des résultats de tests de toutes les autres unités de calcul, quel que soit l’agglomérat. ==La macro-fusion : une optimisation du décodage parallèle== Les processeurs superscalaires supportent la technique dite de '''macro-fusion''', qui permet de fusionner deux-trois instructions consécutives en une seule micro-opération. Par exemple, il est possible fusionner une instruction de test et une instruction de saut en une seule micro-opération de branchement. Il s'agit là de l'utilisation la plus importante de la macro-fusion sur les processeurs x86 modernes. La macro-fusion est utilisée pour fusionner un test et un saut en un branchement unique. L'optimisation est présente sur la plupart des CPU superscalaires modernes. Les CPU x86 l'implémentent, mais aussi quelques CPU ARM et les processeurs Apple de série M (M1 à M5, et potentiellement plus quand ils seront sortis). La fusion des instructions se fait lors du décodage des instructions, grâce à la coopération des décodeurs. Elle marche systématiquement si l'instruction de test et le saut sont consécutives, qu'elles forment bien une paire d'instruction. Par contre, insérer une instruction entre les deux empêche la macro-fusion de faire son travail, sauf si l'instruction insérée est un NOP. Les processeurs ARM64 avaient une forme spécifique de macro-fusion, utilisée pour un cas très précis : charger une constante immédiate de 32 ou 64 bits, dans un registre 64 bits. Les CPU ARM 64 bits utilisent des instructions codées sur 32 bits, qui ne peuvent encoder que des constantes immédiates de 16 bits. Pour charger une constante de 32/64 bits, il faut s'y prendre en plusieurs fois. Une première instruction MOVZ charge les 16 premiers bits, puis 2 à 4 instructions MOVK remplissent le reste. MOVZ met à zéro les 48 bits de poids fort, MOVK permet de sélectionner le doublet à modifier dans le registre (on modifie 16 bits, dont on choisit la place, le reste du registre est laissé tel quel). ARM permet de fusionner cette suite d'instructions en une seule µop MOV avec une constante immédiate. On parle alors de '''''MOVZ + MOVK fusion'''''. Une dernière utilisation, [https://www2.eecs.berkeley.edu/Pubs/TechRpts/2016/EECS-2016-130.pdf proposées pour le jeu d'instruction RISC-V], fusionnait un calcul d'adresse et une instruction LOAD/STORE en une seule instruction d'accès mémoire. Elle a été envisagée à une époque où le jeu d'instruction RISC-V ne gérait pas les modes d'adressage base + indice. L'idée était d'avoir une unité mémoire qui gérait le mode d'adressage base + indice et de fusionner des instructions pour l'exploiter. Mais de nos jours, le jeu d'instruction RISC-V intègre le mode d'adressage base + indice, ce qui fait que la macro-fusion n'a aucun intérêt pour ce cas précis. La macro-fusion a de nombreuses limitations en pratique. En théorie, on pourrait l'utiliser au-delà des deux situations mentionnées plus haut. Par exemple, pour fusionner une addition et une multiplication en une seule instruction MAD. Mais l'intérêt est assez faible. Notons que la macro-fusion ne permet que de fusionner des paires d'instructions. Aller au-delà demanderait un cout en circuit trop important. Déjà que tester deux paires utilise pas mal de comparateurs... ==Le ''stack engine'' : une optimisation de la pile d'appel== Les processeurs modernes intègrent une optimisation liée au pointeur de pile. Pour rappel, sur les architectures modernes, le pointeur de pile est un registre utilisé pour gérer la pile d'appel, précisément pour savoir où se trouve le sommet de la pile. Il est manipulé par les instructions CALL, RET, PUSH et POP, mais aussi par les instructions d'addition/soustraction pour gérer des cadres de pile de taille variable. De plus, il peut servir d'opérande pour des instructions LOAD/STORE, afin de lire/écrire des variables locales, les arguments d'une fonction, et autres. C'est donc un registre général adressable, intégré au banc de registre, altéré par l'unité de calcul entière. L'incrémentation/décrémentation du pointeur de pile passe donc par l'unité de calcul, lors des instructions CALL, RET, PUSH et POP. Mais, l'optimisation que nous allons voir permet d'incrémenter/décrémenter le pointeur de pile sans passer par l'ALU, ou presque. L'idée est de s'inspirer des architectures avec une pile d'adresse de retour, qui intègrent le pointeur de pile dans le séquenceur et l'incrémentent avec un incrémenteur dédié. ===Le ''stack engine''=== L'optimisation que nous allons voir utilise un '''''stack engine''''' intégré à l'unité de contrôle, au séquenceur. Le processeur contient toujours un pointeur de pile dans le banc de registre, cela ne change pas. Par contre, il n'est pas incrémenté/décrémenté à chaque instruction CALL, RET, PUSH, POP. Un compteur intégré au séquenceur est incrémenté à la place, nous l’appellerons le '''compteur delta'''. La vraie valeur du pointeur de pile s'obtient en additionnant le compteur delta avec le registre dans le banc de registre. Précisons que si le compteur delta vaut zéro, la vraie valeur est dans le banc de registre et peut s'utiliser telle quelle. Lorsqu'une instruction ADD/SUB/LOAD/STORE utilise le pointeur de pile comme opérande, elle a besoin de la vraie valeur. Si elle n'est pas dans le banc de registre, le séquenceur déclenche l'addition compteur-registre pour calculer la vraie valeur. Finalement, le banc de registre contient alors la bonne valeur et l'instruction peut s'exécuter sans encombre. L'idée est que le pointeur de pile est généralement altéré par une série d'instruction PUSH/POP consécutives, puis des instructions LOAD/STORE/ADD/SUB utilisent le pointeur de pile final comme opérande. En clair, une bonne partie des incrémentations/décrémentation est accumulée dans le compteur delta, puis la vraie valeur est calculée une fois pour toutes et est utilisée comme opérande. On accumule un delta dans le compteur delta, et ce compteur delta est additionné quand nécessaire. Précisons que le compteur delta est placé juste après le décodeur d'instruction, avant même le cache de micro-opération, l'unité de renommage et l'unité d'émission. Ainsi, les incrémentations/décrémentations du pointeur de pile disparaissent dès l'unité de décodage. Elles ne prennent pas de place dans le cache de micro-opération, ni dans la fenêtre d'instruction, ni dans la suite du pipeline. De nombreuses ressources sont économisées dans le ''front-end''. Mais utiliser un ''stack engine'' a aussi de nombreux avantages au niveau du chemin de données/''back-end''. Déjà, sur les processeurs à exécution dans le désordre, cela libère une unité de calcul qui peut être utilisée pour faire d'autres calculs. Ensuite, le compteur delta mémorise un delta assez court, de 8 bits sur le processeur Pentium M, un peu plus pour les suivants. L'incrémentation se fait donc via un incrémenteur 8 bits, pas une grosse ALU 32/64 bits. Il y a un gain en termes de consommation d'énergie, un incrémenteur 8 bits étant moins gourmand qu'une grosse ALU 32/64 bits. ===Les points de synchronisation du delta=== La technique ne fonctionne que si la vraie valeur du pointeur de pile est calculée au bon moment, avant chaque utilisation pertinente. Il y a donc des '''points de synchronisation''' qui forcent le calcul de la vraie valeur. Plus haut, nous avions dit que c'était à chaque fois qu'une instruction adresse le pointeur de pile explicitement, qui l'utilise comme opérande. Les instructions CALL, RET, PUSH et POP ne sont pas concernées par elles utilisent le pointeur de pile de manière implicite et ne font que l'incrémenter/décrémenter. Mais dans les faits, c'est plus compliqué. D'autres situations peuvent forcer une synchronisation, notamment un débordement du compteur delta. Le compteur delta est généralement un compteur de 8 bits, ce qui fait qu'il peut déborder. En cas de débordement du compteur, le séquenceur déclenche le calcul de la vraie valeur, puis réinitialise le compteur delta. La vraie valeur est donc calculée en avance dans ce cas précis. Précisons qu'un compteur delta de 8 bits permet de gérer environ 30 instructions PUSH/POP consécutives, ce qui rend les débordements de compteur delta assez peu fréquent. À noter que si le compteur delta vaut zéro, il n'y a pas besoin de calculer la vraie valeur, le séquenceur prend cette situation en compte. Un autre point de synchronisation est celui des interruptions et exceptions matérielles. Il faut que le compteur delta soit sauvegardé lors d'une interruption et restauré quand elle se termine. Idem lors d'une commutation de contexte, quand on passe d'un programme à un autre. Pour cela, le processeur peut déclencher le calcul de la vraie valeur lors d'une interruption, avant de sauvegarder les registres. Pour cela, le processeur intègre un mécanisme de sauvegarde automatique, qui mémorise la valeur de ce compteur dans le tampon de réordonnancement, pour forcer le calcul de la vraie valeur en cas de problème. La technique du ''stack engine'' est apparue sur les processeurs Pentium M d'Intel et les processeurs K10 d'AMD, et a été conservée sur tous les modèles ultérieurs. L'implémentation est cependant différente selon les processeurs, bien qu'on n'en connaisse pas les détails et que l'on doive se contenter des résultats de micro-benchmarks et des détails fournit par Intel et AMD. Selon certaines sources, dont les manuels d'optimisation d'Agner Fog, les processeurs AMD auraient moins de points de synchronisation que les processeurs Intel. De plus, leur ''stack engine'' serait placé plus loin que prévu dans le pipeline, après la file de micro-opération. ==La micro-fusion et la délamination== La '''micro-fusion''' est une optimisation qui retarde le décodage réel de certaines instructions assez loin dans le pipeline. Elle concerne surtout les instructions ''load-op'', mais pas que. D'autres instructions mémoire peuvent subir cette optimisation. L'essentiel est que, sans micro-fusion, ces instructions sont décodées en plusieurs micro-opérations. La micro-fusion retarde le décodage final de ces instructions, qui se fait assez tard dans le pipeline. Pour comprendre l'intérêt, nous allons devoir faire quelques explications. L'optimisation en question fait le décodage en deux temps. Prenons l'exemple d'une opération ''load-op'', qui est censée être décodée en deux micro-opérations : une lecture, puis une opération. Le décodage produit une '''macro-opération''' (terme d'Intel), qui est propagée dans le pipeline, pour être scindée en deux micro-opérations un peu avant les ALU et l'unité mémoire. La macro-opération est techniquement une micro-opération comme une autre, sauf que ce n'est pas la micro-opération finale. L'unité d'émission découpe cette macro-opération en deux micro-opérations, qui sont émises l'une après l'autre. Pour résumer, les instructions ''load-op'' ne sont complétement découpées en micro-opération lors de l'émission, pas lors du décodage. L'optimisation impacte ce qui se situe entre le décodeur d'instruction et l'unité d'émission : l'unité de renommage, la file de micro-opérations, le ''Loop Stream Detector'' et/ou le cache de micro-opération. L'intérêt de l'optimisation est que l'on fusionne deux micro-opérations en une seule macro-opération. Le cache de micro-opération et la file de micro-opération peuvent mémoriser plus de micro-opérations, vu que certaines sont fusionnées. Quant à l'unité de renommage, elle renomme une seule macro-opération au lieu de renommer deux micro-opérations, ce qui augmente le débit du renommage de registre. Par contre, cela complique un peu le travail de l'unité d'émission, qui doit découper les instructions ''load-op'' en deux et émettre les micro-opérations l'une après l'autre. Il faut noter qu'il n'y a pas de fusion proprement dite. Le décodeur ne décode pas deux micro-opérations séparées, avant de les fusionner. En réalité, il génère directement une macro-opération, qui correspond à deux micro-opérations, que ce soit plus tard dans le pipeline ou sur une autre architecture. D'ailleurs, la micro-fusion a lieu à l'intérieur d'une instruction, qui est censée être traduite en plusieurs micro-opérations. Et encore : pas toutes. La conséquence est que la technique n'a de sens que sur les processeurs CISC, avec des instructions assez complexes pour être décodées en plusieurs micro-opérations. En pratique, seuls les CPU x86 sont concernés. ===Les domaines de fusion=== La micro-fusion n'est pas spécifique aux processeurs superscalaires. En théorie, on peut l'implémenter sur un processeur non-superscalaire à émission dans l'ordre. Cependant, je ne connais aucun processeur à émission dans l'ordre qui implémente la micro-fusion, même si son implémentation est en théorie possible sur de tels processeurs. La micro-fusion est implémentée différemment selon que l'émission se fasse dans l'ordre, dans le désordre, avec une fenêtre d'instruction, avec des stations de réservation, etc. J'ai dit plus haut que les micro-opérations sont générées lors de l'émission, mais le moment exact varie suivant le processeur. Pour simplifier le tout, nous parlerons de '''scission''' quand le processeur traduit une macro-opération en deux/trois micro-opérations. Le moment où a lieu la scission est théoriquement dans l'unité d'émission, mais celle-ci prend plusieurs formes selon que le processeur utilise l'émission dans l'ordre, dans le désordre, avec une fenêtre d'instruction, avec des stations de réservation, etc. Les processeurs à exécution dans l'ordre sont le cas le plus simple. L'unité d'émission est alors en charge du découpage des macro-opérations en micro-opérations. La file de micro-opération ou le cache de micro-opérations mémorisent des macro-opérations. À l'opposé, le tampon de ré-ordonnancement mémorise lui des micro-opérations. Le reste du processeur n'est pas affecté. Sur les processeurs à exécution dans le désordre, les différences sont nombreuses. Le tampon de ré-ordonnancement peut mémoriser soit les micro-opérations finales, soit des macro-opérations. Il en est de même avec la fenêtre d'instruction et/ou les stations de réservation, qu'elles soient centralisées ou décentralisées. Tout dépend de comment se fait l'implémentation. Une implémentation simple effectue la scission des macro-opérations dans l'unité d'émission, comme sur les processeurs à exécution dans l'ordre. Sur de nombreux processeurs, l'unité d'émission et de renommage sont simplement fusionnées, ce qui fait que la scission a lieu juste après le renommage de registres. En conséquence, le tampon de re-ordonnancement et les fenêtres d'instruction ne voient que des micro-opérations. Les macro-opérations disparaissent juste avant. Cette implémentation est préférée avec une fenêtre d'instruction centralisée, car on voit mal comment scinder une macro-opération juste avant l'ALU. Une autre implémentation fait la scission en sortie de la fenêtre d'instruction ou des stations de réservation, qu'elles soient centralisées ou décentralisées. Dans ce cas, le tampon de re-ordonnancement fait de même. L'avantage est que le tampon de ré-ordonnancement stocke des macro-opérations, ce qui augmente sa taille effective. Par exemple, il utilise une seule entrée pour une instruction ''load-op'', au lieu de deux sans micro-fusion de ce type. ===La délamination=== La scission peut parfois avoir lieu plus tôt, dans des circonstances très précises. Concrètement, cela ne concerne que quelques micro-architectures d'Intel, pour des instructions très précises. La raison est les limitations du format des micro-opérations, pas une histoire d'optimisation. Le processeur aimerait pouvoir faire la micro-fusion, mais ne peut pas à cause de ces limitations. Une telle situation cause alors une '''délamination''' : les micro-opérations sont scindées précocement. Par exemple, sur la micro-architecture SandyBridge d'Intel, les opérations ''load-op'' sont fusionnées, sauf si elles utilisent l'adressage indicé. Les micro-opérations de ce processeur ne peuvent avoir que deux opérandes. Trois opérandes est de trop, et les opérations ''load-op'' en adressage indicé dépassent cette limite. Dans ce cas, les micro-opérations sont fusionnées en sortie du décodeur, mais sont scindés avant d’entrer dans la file de micro-opération. L'avantage n'est pas évident, vu que l'unité de renommage suit de près le décodeur d'instruction. Il est que le cache de micro-opérations mémorise des macro-opérations, pas deux micro-opérations. ===La micro-fusion des processeurs Intel et AMD=== La micro-fusion est apparue sur le Pentium M d'Intel, et a été conservée telle quelle sur les processeurs Intel suivants. Les processeurs AMD supportent la micro-fusion depuis au moins la micro-architecture AMD K8. Mieux que ça, la délamination n'était pas utilisée car les micro-opérations acceptaient plus de 2 opérandes. Que ce soit chez AMD ou Intel, elle concerne deux types d'instructions : les écritures mémoire et les instructions ''load-op''. Sur le Pentium M, il y avait quelques limitations, l'optimisation se limitant par exemple aux registres entiers et flottants, mais pas aux registres MMX, mais pas les registres SSE (nous verrons ces registres dans quelques chapitres). Mais les processeurs modernes n'ont plus cette limitation. La micro-fusion des CPU Intel concerne deux types d'instructions : les écritures mémoire et les instructions ''load-op''. Pour les écritures, la situation est plus complexe que pour les instructions ''load-op''. Sur les processeurs Intel précédents, les écritures étaient réalisées dans deux unités séparées : le calcul d'adresse dans une unité de calcul, l'écriture proprement dite dans l'unité mémoire. Elles prenaient donc deux micro-opérations. Le processeur a changé ses unités mémoire, ce qui fait qu'elle pouvait faire les deux en une seule micro-opération. Il s'agissait alors d'une optimisation du chemin de données, plus que de la micro-fusion proprement dite, mais je la mentionne ici malgré tout. La micro-fusion sur ce processeur avait un avantage en plus des avantages usuels : elle utilisait mieux les décodeurs. Les Pentium M avaient trois décodeurs pour décoder plusieurs instructions en même temps, chose qu'on détaillera dans le chapitre sur les processeurs superscalaires. Un seul décodeur pouvait décoder toutes les instructions, les deux autres ne peuvent décoder que les instructions simples, qui se décodent en une seule micro-opération. Avec la micro-fusion, les trois décodeurs peuvent gérer les écritures mémoire et les opérations ''load-op'', vu qu'elles deviennent des instructions simples. Sans cela, elles auraient été limitées au premier décodeur. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Le parallélisme mémoire | prevText=Le parallélisme mémoire | next=Les microarchitectures pour le x86 : haute performance | nextText=Les microarchitectures pour le x86 : haute performance }} </noinclude> 2i9olmxo4xj799vuxxp8c1kw5ilazek 773584 773583 2026-09-29T16:54:08Z Mewtow 31375 /* L'exemple du PA-RISC PA 8000 */ 773584 wikitext text/x-wiki Les processeurs vus auparavant ne peuvent émettre au maximum qu'une instruction par cycle d'horloge. Ils peuvent avoir plusieurs instructions qui s'exécutent en même temps, dans des unités de calcul séparées. C'est le cas dès qu'une instruction multi-cycles s'exécute. Par contre, ils ne peuvent démarrer qu'une seule instruction par cycle. Et quand on court après la performance, ce n'est pas assez ! Les concepteurs de processeurs ont inventés des processeurs qui émettent plusieurs instructions par cycle : les '''processeurs à émissions multiples'''. Un processeur à émission multiple charge plusieurs instructions en même temps, les décode en parallèle, puis les émet en même temps sur des unités de calculs séparées. Pour cela, il faut gérer les dépendances entre instructions, répartir les instructions sur différentes unités de calcul, et cela n'est pas une mince affaire. En général, pour un processeur à émission multiple capable d'émettre N instructions en parallèle, on parle de '''processeur à N voies''', ou encore un ''processeur à N pipelines''. [[File:Superscalarpipeline.svg|centre|vignette|upright=1.5|Pipeline RISC classique à cinq étages sur un processeur superscalaire. On voit bien que plusieurs instructions sont chargées en même temps.]] Les processeurs à émission multiple sont de deux types : les processeurs VLIW et les '''processeurs superscalaires'''. Nous mettons les processeurs VLIW de côté en attendant le prochain chapitre. La raison est qu'ils ont un jeu d'instruction spécialisé qui expose le parallélisme d'instruction directement au niveau du jeu d'instructions, là où les processeurs superscalaires restent des processeurs au jeu d'instruction normal. La différence principale entre processeur VLIW et superscalaire est qu'un processeur superscalaire répartit les instructions sur les unités de calcul à l’exécution, là où un processeur VLIW délègue cette tâche au compilateur. ==Le nombre de voies d'un processeur superscalaire== Les processeurs superscalaires les plus simples ne permettent que d'émettre deux micro-opérations à la fois, d'où leur nom de processeur ''dual issue'', ce qui se traduit en '''processeur à double émission'''. Les processeurs triple émission permettent eux d’émettre trois instructions à la fois. A l'opposé, les CPU superscalaires les plus puissants peuvent émettre jusqu'à 8-10 instructions simultanément. En 2026, les CPU superscalaires peuvent monter jusqu’à 10 µops émises en même temps, ce qui est énorme ! Et cela nous amène à faire une distinction entre les processeurs superscalaires dits '''étroits''' et ceux dits '''larges'''. Dans ce wikilivre, on part du principe que les processeurs superscalaires étroits émettent jusqu'à 4-5 µops à la fois, alors que les larges peuvent en émettre plus, l'intervalle entre les deux est une zone grise. Le nombre exact n'est pas fixé dans le marbre, la distinction est volontairement vague. Nous parlerons de la '''largeur d'un CPU superscalaire''' pour parler du nombre de voies, du nombre de µops émises en même temps. Plus un CPU superscalaire est large, plus il est performant ''toute chose égale par ailleurs''. Mais dans les faits, vous pouvez oublier la partie en italique. Élargir un CPU superscalaire demande de rajouter beaucoup de circuits. Et ce cout en circuit aura un impact sur la performance. A budget en transistors limité, il y a un compromis entre élargir un CPU et rajouter du cache ou la taille des fenêtres d'instructions/ROB et autres. ===Les contraintes d’appariement=== Prenons un processeur double émission, capable d'émettre deux instructions simultanément. Émettre deux instructions en même temps n'est pas toujours possible. Par exemple, si deux instructions sont dépendantes, on ne peut pas les émettre en même temps. Mais oublions un instant ces histoires de dépendances de données, et partons du principe que le CPU ait affaire à deux instructions indépendantes, une paire idéale. Un CPU double émission "parfait" pourrait exécuter n'importe quelle paire d'instruction. Par exemple, il pourrait émettre deux multiplications consécutives, deux lectures consécutives, une lecture et une écriture en même temps, etc. En pratique, aucun processeur ne permet cela. Implémenter un CPU superscalaire "parfait" aurait un cout en circuit beaucoup trop conséquent. Par exemple, pour émettre deux multiplications en même temps, il faudrait deux multiplieurs séparés. Idem pour exécuter deux accès mémoire simultané : cela demande d'avoir deux unités mémoire et un cache multiport. Mais en pratique, aucun CPU superscalaire ne fait cela. La totalité des CPU double émission se débrouille avec un seul circuit multiplieur et une seule unité mémoire. Et cela entraine l'apparition de dépendances structurelles, qui font que certaines paires d'instructions sont impossibles. Par exemple, impossible d'émettre deux multiplications en même temps avec un seul circuit multiplieur. Mais émettre une multiplication en parallèle d'une addition est parfaitement possible. Il y a donc des paires d'instructions autorisées et des paires interdites. Et la logique est la même sur les CPU à triple ou quadruple émission, et au-delà. : des triplets ou quadruplet d'instructions sont impossibles à émettre simultanément, alors que d'autres le sont. Pour le dire autrement, il y a des '''contraintes d'appariement''' sur les instructions à émettre en même temps. ===L'impact des contraintes d’appariement sur la performance=== Ces contraintes d’appariement ont un impact sur les performance, mais celui-ci peut être grandement mitigé. Les programmes informatiques utilisent en pratique beaucoup plus d'opérations entières de base que de multiplication, branchements et accès mémoire. Il y a environ 5 opérations entières de base pour une multiplication entière. En pratique, il est rare de devoir exécuter deux multiplications à la fois. Idem pour les décalages et rotations, qui sont assez éloignés les uns des autres. Deux branchements consécutifs sont quant à eux plus fréquents. Deux accès mémoire consécutifs est assez rare, mais ils restent assez proches les uns des autres malgré tout. La conséquence est que certaines paires d'instructions sont privilégiées par rapport au reste. Les paires regroupant deux calculs basiques (additions, soustractions, ...) sont systématiquement supportées, car dupliquer des ALU entières est facile. Les paires regroupant un calcul et une autre instruction sont elles aussi systématiquement supportées. Par contre, les paires avec deux branchements, deux accès mémoire, deux décalages/rotations, ou deux multiplications/divisions sont fréquemment interdites. Seuls les CPU superscalaires larges peuvent les permettre, et encore : sous conditions. Le résultat est que le processeur peut se débrouiller avec une seule unité mémoire et une unité de branchement. ===Terminologie pour la suite du chapitre=== Décrire les contraintes d’appariement demande de dire quelles combinaisons d’instructions sont autorisées ou interdites. Et pour cela, nous allons introduire les abréviations suivantes : * INT est un raccourcis pour parler d'une opération entière simple, qu'une ALU entière peut exécuter. * MUL correspond à une opération entière complexe, typiquement une multiplication, éventuellement à une division. * FLOAT désigne une opération flottante, peut importe laquelle. * MEM désigne un accès mémoire, à savoir une instruction ou µop mémoire. * BRANCH désigne une instruction de branchement. Cette terminologie permettra de définir des paires d'instructions, qu'elles soient possibles ou interdites. Par exemple, l'expression INT + FLOAT désigne une paire d'instruction regroupant une instruction entière et une instruction flottante, peu importe l'ordre des deux instructions. Il en sera de même pour les triplets, quadruplets, ou plus. Par exemple, l'expression INT + INT + FLOAT + MUL désigne un quadruplet d'instructions regroupant : deux instructions entières, une instruction flottante, et une multiplication entière. J'utiliserais aussi des parenthèses pour regrouper certaines combinaisons. Par exemple, l'expression INT + (MUL /FLOAT) veut parler d'une paire d'instruction où la première est une opération entière basique, la seconde est : soit une multiplication, soit une opération flottante. ==Le ''front-end'' des processeurs superscalaires== Un processeur superscalaire doit charger, décoder, et exécuter plusieurs instructions par cycle. Par exemple, un processeur triple émission doit charger 3 instructions lors d'un premier cycle, puis les décoder au cycle suivant, et les exécuter au cycle suivant. Il travaille donc pas paquets de 3 instructions, dans cet exemple. Intuitivement, charger, décoder et exécuter plusieurs instructions à la fois demande de dupliquer des circuits. Par exemple, il faut dupliquer les décodeurs pour décoder plusieurs instructions. Les unités de calcul sont aussi dupliquées, sauf sur certaines processeurs qui arrivent à ruser, mais laissons cela de côté pour plus tard. Mais d'autres circuits sont simplement modifiés, comme l'unité de chargement ou l'unité d'émission. Voyons ce qu'il en est dans le détail. {|class="wikitable" |- ! rowspan="2" | Processeur sans émission multiple | rowspan="2" | Chargement | rowspan="2" | Décodage | rowspan="2" | Renommage | rowspan="2" | Émission | Exécution / ALU | rowspan="2" | ''Commit''/ROB |- | Exécution / ALU |- ! rowspan="4" | Processeur superscalaire | rowspan="4" | Chargement | rowspan="2" | Décodage | rowspan="4" | Renommage | rowspan="4" | Émission | Exécution / ALU | rowspan="4" | ''Commit''/ROB |- | Exécution / ALU |- | rowspan="2" | Décodage | Exécution / ALU |- | Exécution / ALU |} Nous allons d'abord voir ce qu'il en est pour le ''front-end'', à savoir la partie du CPU qui s'occupe de charger et décoder les instructions. Elle regroupe l'unité de chargement, les décodeurs, l'unité de prédiction de branchement, la file de µops, la file d'instruction, et divers caches. En soi, les changements portent surtout sur l'unité de chargement et les décodeurs. ===Le chargement de plusieurs instructions consécutives=== Un processeur superscalaire charge plusieurs instructions en même temps, ''en tenant compte de la présence de branchements''. La partie en italique est importante et elle a une conséquence très forte : la manière de faire est fortement différente entre un CPU superscalaire étroit et large. Un CPU superscalaire étroit fait au plus simple : il charge un bloc de 2, 3, 4 instructions consécutives en mémoire RAM. Il faut alors doubler/tripler/quadrupler la taille du bus connecté au cache d'instruction. Par exemple, pour charger quatre instructions de 32 bits chacune, il suffit de lire un bloc de 128 bits dans le cache d'instruction. Un bloc de 8, 16, 32 octets est donc lu depuis le cache et est ensuite découpé en instructions, envoyées chacun à un décodeur. Charger plusieurs instructions consécutives ne marche bien qu'en absence de branchements. La présence de branchements casse cette dynamique, et il faut gérer leur présence. * Sans prédiction de branchement, toutes les instructions d'un bloc sont décodées et exécutées en même temps, même s'il y a un branchement dans le tas. * Avec prédiction de branchement, les instructions situées après le branchement ne sont pas décodées ni exécutées. L'unité de chargement coupe le bloc chargé au niveau du premier branchement pris, remplit les vides avec des NOP, avant d'envoyer le tout à l'unité de décodage. Les instructions à l'adresse de destination seront chargées au cycle suivant, en chargeant un nouveau bloc. [[File:Fetch sur un processeur superscalaire avec prediction de branchements.png|centre|vignette|upright=2|Fetch sur un processeur superscalaire avec prédiction de branchements.]] Un autre défaut est que sur le CPU charge un bloc de 128 bits à la fois, les instructions doivent être alignées sur 128 bits. Et on peut généraliser à n'importe quelle taille de bloc. Si les instructions ne sont pas alignées, il faut gérer la situation. Il arrive qu'une instruction soit à cheval sur deux blocs, avec un morceau dans le premier bloc, un autre dans le second. Dans ce cas, l'instruction est chargée en deux fois, et des circuits doivent gérer la situation pour recoller les morceaux. Sur les CPU avec des instructions de taille fixe, le problème ne survient que rarement. Mais il est fréquent avec des instructions de taille variable. Un autre défaut est lié aux branchements. Imaginez qu'un branchement s'exécute et branche vers une instruction de destination. Rien n'indique que l'instruction de destination sera au tout début d'un bloc. Si ça se trouve, elle sera en troisième position d'un bloc de 4 instructions. Une solution simple charge le bloc en respectant l'alignement, et les deux premières instructions du bloc ne sont pas à exécuter. Il y a donc une petite perte de performance. Certains CPU, comme l'IBM RS/6000, ont la machinerie charger un bloc de N instructions même s'il n'est pas aligné. La machinerie en question se trouve dans le cache d'instruction et est tout sauf simple à expliquer,ce qui fait que je me permets de la passer sous silence. Un détail, cependant : elle ne permet pas de charger des blocs qui sont à cheval sur deux lignes de cache. ===Le décodage parallèle des instructions=== Pour le décodage des instructions, plusieurs instructions sont décodées en même temps. On parle alors de '''décodage parallèle'''. Pour ce faire, un processeur superscalaire contient plusieurs décodeurs, chacun pouvant décoder une instruction en parallèle des autres. Prenons par exemple un processeur superscalaire à 4 voies : le décodage se fera dans quatre décodeurs séparés, qui fonctionneront en parallèle. Cependant, cette implémentation ne marche bien que pour les processeurs RISC, les processeurs CISC devant faire avec un microcode gourmand en circuits. Les processeurs CISC utilisent des décodeurs hybrides, avec un microcode qui complémente un décodeur câblé. Dupliquer le microcode aurait un cout en transistors trop important, ce qui fait que seuls les décodeurs câblés sont dupliqués. Les CPU CISC superscalaires disposent donc de plusieurs décodeurs simples, capables de décoder les instructions les plus courantes, avec un seul microcode. La conséquence est qu'il n'est pas possible de décoder deux instructions microcodées en même temps. Par contre, il reste possible de décoder plusieurs instructions non-microcodées ou une instruction microcodée couplée à une instruction non-microcodée. Vu qu'il est rare que deux instructions microcodées se suivent dans un programme, le cout en performance est extrêmement mineur. Il faut noter qu'une instruction correspond à une ou plusieurs µops. Il est donc possible de charger 5 instructions et de se retrouver avec 8 µops en sortie des décodeurs. Et c'est la source d'une distinction très importante. Plus haut, j'ai parlé de processeurs superscalaires à N voies. La terminologie peut avoir deux interprétations. La première est que le processeur charge/décode N instructions à la fois. Une seconde est qu'il est capable d'exécuter/émettre N µops en même temps. Les deux ne sont pas équivalentes, vu qu'un processeur superscalaire peut, par exemple, charger/décoder N instructions et émettre/exécuter N+2 µops. La distinction est particulièrement importante sur les processeurs superscalaires larges. Certains d'entre eux sont capables de charger 5 instructions et d'en émettre le double ! Un exemple classique était les processeurs Athlon d'AMD, qui pouvaient décoder deux instructions par cycle, mais émettre 4 µops par cycle. Ce n'était pas un problème, car beaucoup d'instructions, même basiques, étaient décodées en 2 µops. ===L'émission parallèle des instructions=== La superscalarité modifie en profondeur l'unité d'émission, notamment au niveau de son interface. Avant, elle recevait une micro-opération sur son entrée, et fournissait la micro-opération émise sur une sortie. Et cela vaut aussi bien pour une unité d'émission simple, un ''scoreboard'', une fenêtre d'instruction ou des stations de réservation. Mais avec l'émission multiple, les sorties et entrées sont dupliquées. Pour la double émission, il y a deux entrées vu qu'elle doit recevoir deux micro-opération décodées/renommées, et deux sorties pour émettre deux micro-opérations. Dans ce qui suit, nous ne parlerons pas d'entrée et de sortie, mais de '''ports de décodage''' et de '''ports d'émission'''. Les ports de décodage reçoivent des micro-opérations provenant de l'unité de décodage, les ports d'émissions sont pour les micro-opérations émises. Les ports d'émission injectent les micro-opérations émises dans le pipeline, elle sont propagée au banc de registre, aux ALUs, etc. Un processeur superscalaire a forcément plusieurs ports d'émission (et de décodage). Si l'interface de l'unité d'émission change, l'intérieur est tout autant modifié. Sur un CPU non-superscalaire, l'unité d'émission reçoit une µop "candidate à l'émission", et détecte les dépendances entre avec les µops en vol, en cours d'exécution dans le pipeline. Et c'est toujours le cas sur les processeurs superscalaires : l'unité d'émission détecte les dépendances entre les µops candidates et les µops en vol. Mais avec la siperscalarité, elle doit en plus tester les dépendances entre les µops candidates. Si l'unité d'émission est un ''scoreboard'', il doit détecter les dépendances entre instructions émises simultanément et les sérialiser si besoin. Avec une fenêtre d'instruction, il n'y a pour ainsi dire rien à faire, vu que les dépendances sont éliminées par le renommage de registre et que les signaux de réveil gèrent les dépendances RAW. C'est la raison pour laquelle les processeurs superscalaires modernes n'utilisent pas de ''scoreboard''. ==Les processeurs implémentés avec plusieurs pipelines== Nous venons de voir comment la superscalarité impacte le ''front-end'', il est maintenant de voir ce qu'il en est de l'unité d'émission et des ''back-ends''. Un processeur superscalaire peut utiliser l'exécution dans le désordre et le renommage de registres, mais ce n'est pas une obligation. Historiquement, les premiers processeurs superscalaires n'utilisaient pas d'exécution dans le désordre. Le meilleur exemple est celui du Pentium 1 et 2 d'Intel. Ils étaient tous deux des processeurs superscalaires, mais n'avaient pas d'exécution dans le désordre, qui est apparue sur le Pentium 3. les explications sont plus simples si on met de côté l'exécution dans le désordre. Vous vous dites que l'implémentation d'un processeur superscalaire n'est pas la même suivant que le CPU utilise l'exécution dans le désordre, ou non. Mais dans les faits, la distinction est plus subtile que ca. Pour l'expliquer, je vais utiliser une classification originale, qui sépare les processeurs superscalaires en trois sous-types. La distinction se fait sur la manière dont la superscalarité est implémentée en matériel.La classification que j'utilise distingue : * Les processeurs avec plusieurs pipelines, sans exécution dans le désordre. * Les processeurs superscalaires avec un pipeline dynamique. * Les processeurs avec des fenêtres d'instruction décentralisées. La distinction n'est pas qu'une question d'implémentation matérielle. Elle impacte aussi le ratio entre instructions chargées/décodées et instructions émises. Vous vous dites que les deux sont égales, mais ce n'est le cas que sur les processeurs avec N pipelines ! Sur les autres processeurs, il est possible de décoder 4 instructions, mais d'en émettre maximum 6 par cycle ! Et sur les CPU avec des fenêtres d'instruction décentralisées, il y a aussi une différence entre le nombre d'instructions qui sont ''dispatch'' et ''schedule''. La catégorie la plus simple est celle des '''processeurs avec plusieurs pipelines'''. Ce sont des processeurs superscalaires sans exécution dans le désordre. Ils partent d'un processeur non-superscalaire, et ajoutent un second pipeline, en sortie de l'unité d'émission. Le second pipeline permet l'émission parallèle d'une seconde instruction. Le second pipeline n'est pas identique au pipeline originel, sur plusieurs points. Premièrement, il n'a pas exactement les mêmes circuits. Le second pipeline est généralement composé d'une unité de calcul, d'une FPU, éventuellement d'un second banc de registres, guère plus. Il permet d'exécuter une seconde opération de calcul, pas plus, ce qui est à l'origine de contraintes d'appariemment assez fortes. De plus, il n'a pas forcément la même longueur, il peut avoir des étages en moins ou en plus. Il s'agit de la forme la plus simple de processeur superscalaire et nous allons leur consacrer cette section. ===La double émission entière-flottante=== L'exemple le plus simple utilise un second pipeline pour les opérations flottantes, séparé du pipeline originel. L'ajout d'un pipeline flottant permet d'émettre une micro-opération entière en même temps qu'une micro-opération flottante, ce qui s'appelle la '''double émission entière-flottante'''. La micro-opération entière s'exécute dans l'ALU entière, la micro-opération flottante dans la FPU. Les exemples les plus notables sont le PA-RISC 7100, le POWER 1 (RIOS .& et .9) et le PowerPC 601. L'Apollo DN10000 et l'Intel i860 utilisaient aussi cette forme de double émission, mais étaient des prototypes de CPU VLIW. [[File:Double émission entière-flottante.png|centre|vignette|upright=2|Double émission entière-flottante]] Pour bien expliquer les choses, prenons le processeur illustré ci-dessous, avec deux ''back-end'' séparés : un pour la FPU, et un autre pour le reste. Les instructions entières et mémoire passent toutes par le ''back-end'' généraliste. [[File:CPU non-superscalaire basique, avec une FPU.png|centre|vignette|upright=1.5|CPU non-superscalaire basique, avec une FPU]] Les deux ''back-end'' sont des pipelines séparés, mais il faut que l'unité d'émission soit spécialement conçue pour en profiter. Un processeur simple émission peut démarrer une seule µop par cycle : soit la µop est envoyée au ''back-end'' flottant, soit elle est envoyée au ''back-end'' général. Avec la double émission entière-flottante, le processeur peut envoyer une µop dans chaque pipeline, à chaque cycle. Vu que la FPU et son banc de registre forment déjà un pipeline séparé, les seules modifications se font au niveau du ''front-end'', unité d'émission inclue. {| |- |[[File:CPU simple émission avec une FPU.png|centre|vignette|upright=1.5|CPU simple émission avec une FPU.]] |[[File:Double émission entière flottante avec un second pipeline.png|centre|vignette|upright=1.5|CPU avec un second pipeline flottant.]] |} Notez que le terme double émission ''entière''-flottante est un peu trompeur. En réalité, la technique permet d'émettre une instruction flottante avec n'importe quelle autre instruction non-flottante, avec des restrictions pour les branchements. Il est par exemple possible d'exécuter un calcul flottant en parallèle d'un accès mémoire. Sur les CPU 32 bits, il est possible de faire les multiplications dans la FPU. Pour rappel, la FPU contient un multiplieur entier 53-54 bits, pour multiplier les mantisses de deux flottants 64 bits, qu'on peut utiliser pour faire les multiplications entières 32 bits. Cela permet d'émettre une multiplication en même temps qu'une opération entière dans l'ALU. Ainsi, le CPU pouvait émettre deux instructions : une opération entière de base, avec soit une multiplication, soit une opération flottante. En clair, une émission de type INT + (MUL /FLOAT). Par contre, on perd la possibilité d'émettre une multiplication entière avec une opération flottante, mais c'était un compromis qui en valait la peine. Le CPU PA-RISC 7100 implémentait cette optimisation. Il s'agissait d'un CPU double émission entière-flottante, qui utilisait donc un partitionnement assez simple. Le combo partitionnement + reconditionnement permettait ici de gagner en performance, pour un cout en matériel très limité. D’autant plus limité que le jeu d'instruction prévoyait le reconditionnement de la FPU. Les multiplications ne lisaient pas leurs opérandes dans les registres entiers, mais dans les registres flottants. ===La double émission entière=== Une autre possibilité ajoute un second pipeline, capable d'exécuter des opérations entières simples, appelé le pipeline entier. Le processeur supporte alors la '''double émission entière''', à savoir qu'ils peuvent émettre une opération entière en plus d'une autre instruction. L'opération entière en question est une opération simple, comme une addition, une soustraction, une opération bit à bit, une comparaison, etc. Les exemples classiques sont les processeurs Intel i960 et Pentium. L'implémentation était différente entre l'i960 et le Pentium : Le Pentium avait une seconde ALU entière, alors que le i960 rusait. Le Pentium dupliquait l'ALU entière, pour créer un second pipeline entier. Sur le Pentium originel, les contraintes d'appariement étaient assez strictes. Le Pentium avait une FPU, mais ne pouvait pas l'utiliser en double émission. Il lui était impossible d'exécuter une opération flottante en même temps qu'une opération entière (branchements inclus). Le Cyrix 6x86 était une sorte de Pentium produit par l'entreprise Cyrix, avec une microarchitecture différente. Il avait des contraintes d’appariement réduites. Par exemple, il pouvait émettre une opération flottante en parallèle d'une opération entière. Nous détaillerons ces processeurs dans le prochain chapitre, qui porte justement sur les CPU superscalaires x86. [[File:CPU simple et double émission avec un second pipeline entier.png|centre|vignette|upright=2.5|CPU simple et double émission avec un second pipeline entier.]] L'Intel i960 n'avait pas de FPU, juste une ALU entière et une unité mémoire. Il utilisait l'unité mémoire comme une seconde ALU entière limitée. Pour rappel, une unité mémoire contient une AGU, à savoir une ALU spécialisée dans les calculs d'adresse. Elle est capable de faire des additions, soustractions, et quelques décalages limités (des décalages par 2, 4, 8, pas plus). L'Intel i960 ajoutait des connexions entre AGU et banc de registre, afin que celle-ci serve de seconde unité de calcul. L'AGU est déjà reliée aux deux ports de lecture, pour lire les opérandes du calcul d'adresse, il suffit de la connecter sur le port d'écriture. Le processeur peut alors émettre deux instructions/µops entières, sous certaines conditions. [[File:Emission multiple des opérations entières, double émission.png|centre|vignette|upright=2|Émission multiple des opérations entières, double émission.]] ==Les processeurs superscalaires dynamiques== Les processeurs précédents, avec 2 pipelines, avaient une unité d'émission assez simple. Elle avait deux ports de décodage, et deux ports d'émission. Le nombre de ports de décodage et d'émission étaient identiques. Vous vous dites que c'est naturel, et intuitif, que c'est normal pour un processeur superscalaire. Mais en réalité, la majorité des processeurs superscalaires a plus de ports d'émission que de décodage. Expliquer pourquoi va cependant nous demander de parler de comment la superscalarité exploite les unités de calcul. Posons-nous cette question : de combien d'unités un processeur superscalaire a besoin ? Les unités en question ne sont nécessairement des unité de calcul, l'unité mémoire et l'unité de branchement comptent aussi. La réponse dépend du nombre de voies. Si le ''front-end'' charge et décode un paquet de N instructions, exécuter ces N instructions simultanément demandera là aussi au moins N unités de calcul. Notez le terme : ''au moins'', car c'est là tout l'enjeu de cette section. La réponse dépend aussi des contraintes d’appariement. Pour un CPU superscalaire "parfait", sans contraintes d’appariement, toutes les unités doivent être dupliquées, y compris l'unité mémoire. Un processeur à double émission parfaite devrait dupliquer l'ALU entière, le ''barrel shifter'', le circuit multiplieur, la FPU, l'unité mémoire, et l'unité de branchement, ce qui ferait passer de 6 unités à 12. Le cout en circuit est énorme, même pour de la double émission ! Et pour un CPU à N pipelines, le cout en circuit encore plus prohibitif ! En pratique, les processeurs superscalaires qui font ça sont très rares. La majeure partie des processeurs superscalaires utilisent d'autres techniques : le partitionnement, la duplication partielle des ALUs, la duplication des autres unités. ===Le partitionnement des unités fonctionnelles=== Les CPU superscalaires les plus simples ne dupliquent pas leurs unités de calcul, ils se contentent d'exploiter les unités existantes. Et pour expliquer comment, nous allons partir de l'exemple d'un processeur non-superscalaire contient une ALU entière, une FPU, une unité mémoire et une unité de branchement. Les quatre unités peuvent fonctionner en parallèle, à savoir qu'une unité peut exécuter une instruction à elle toute seule, sans interagir avec les autres. Cela suffit pour créer un processeur quadruple émission, qui peut émettre en même temps : une opération entière, une opération flottante, un branchement, un accès mémoire. Le principe marche aussi sur un processeur avec moins de 4 unités, par exemple sans FPU et/ou sans unité de branchement, ou avec au contraire des unités en plus. L'idée générale est d’émettre une µops séparée dans chaque unité fonctionnelle. Utiliser ainsi les unités existantes, pour rendre un CPU superscalaire, s'appelle le '''partitionnement superscalaire'''. Le terme n'est pas beaucoup utilisé en-dehors de quelques vieux articles académiques. Le partitionnement est fortement dépendant du jeu d'instruction, car il demande de bien séparer instructions entières, flottantes, branchements et instructions mémoire. Et autant c'est bien le cas sur les CPU RISC, autant les CPU CISC ne sont pas dans ce cas. Les CPU CISC ont des instructions ''load-op'', qui effectuent une instruction arithmétique et une µop mémoire. Et ces instructions sont très compliquées à implémenter avec le partitionnement. Et au-delà de ça, les CPU CISC ont beaucoup d'instructions qui sont décodées en plusieurs µops, à exécuter dans un ordre bien précis. On peut pas émettre les µops en question simultanément. Le partitionnement a un cout en circuit très limité, pour un gain en performance lui aussi limité. Pour reprendre le CPU de l'exemple précédent, il est rare que l'on ait à exécuter ces quatre instructions en même temps. En pratique, les combinaisons fréquentes sont les combinaisons calcul + accès mémoire, calcul + branchement, calcul entier + calcul flottant. Utiliser une quadruple émission de ce type n'est donc pas une bonne idée, alors que la double émission parait plus adaptée. Et c'est là que la différence entre ports d'émission et de décodage devient intéressante. L'idée est d'avoir une unité d'émission avec deux ports de décodage, et 4 port d'émission (un par unité). Les contraintes d’appariement varient alors suivant le processeur, mais la règle générale est que si deux micro-opérations tombent dans deux unités différentes, on peut les émettre en même temps. En clair, on peut émettre une opération entière avec une opération flottante, une opération entière avec un branchement, un accès mémoire avec un branchement, etc. Et cela rend le partitionnement bien plus intéressant que prévu. Les tout premiers CPU superscalaires étaient des CPU double émission, qui utilisaient le partitionnement avec : une ALU entière, une unité mémoire et une FPU. Nous parlerons de '''partitionnement INT-FLOAT-MEM'''. L'avantage sur la double émission flottante est que les combinaisons INT + MEM et FLOAT + MEM étaient autorisées. L'intérêt était d'émettre une opération en parallèle d'un accès mémoire, ce qui est un doublet d'instruction assez fréquent. Les exemples classiques sont l'HyperSPARC, de l'alpha 21064 et du PowerPC 603. Les contraintes d’appariement variaient grandement suivant le processeur. Le PowerPC 603 implémentait une double émission "parfaite". C'est à dire que toutes les combinaisons possibles à deux instructions étaient possibles, que ce soit INT + FLOAT, INT + MEM, FLOAT + MEM. En plus de cette double émission "parfaite", le CPU utilisait la technique dite de ''branch folding'', qui permettait d'exécuter un branchement sans utiliser d'unité de calcul, ce qui fait qu'il était qualifié de ''CPU 2-way + Branch''. A l'opposé, le processeur alpha 21064 avait pas mal de contraintes d’appariement, à savoir que certaines combinaisons de deux instructions étaient interdites, bien que compatibles avec les unités disponibles. Une des raisons est que le banc de registre n'avait pas assez de ports de lectures, ce qui fait que certaines combinaisons avec une écriture mémoire n'étaient pas permises. Les concepteurs avaient volontairement inséré ces contraintes afin de simplifier le design du processeur. Avant de poursuivre, précisons que la FPU regroupe un additionneur flottant et un multiplieur flottant. Et ce fait peut être exploité pour approfondir le partitionnement. La '''double émission FADD/FMUL''' permet d'émettre une addition flottante en même temps qu'une multiplication flottante. Elle a été utilisée sur les processeurs x86, Alpha et SPARC. Les autres circuits de calcul flottant sont souvent regroupés avec l'additionneur. La division est parfois e même port que le multiplieur flottant, parfois sur celui de l'additionneur (quand elle est microcodée et exécutée en enchainant les soustractions). ===La duplication des ALU entières=== Le partitionnement est une technique élégante, simple, facile à implémenter et au cout en circuits modeste. Mais il faut avouer que cela ne donne pas des CPU superscalaires très efficaces. La raison est que le partitionnement permet d'émettre des paires, triplets, quadruplets de micro-opérations qui sont rares en pratique. Les combinaisons les plus fréquentes en pratique sont des paires/triplets d'opérations entières, souvent des paires/triplets d'additions ou d'opérations entières simples. Il est donc primordial d'émettre plusieurs opérations entières simultanément. Le fait d'émettre et d'exécuter plusieurs opérations entières en même temps s'appelle l''''émission entière multiple'''. Pour exécuter la seconde/troisième opération entière, il faut dupliquer les ALU entières (ou réutiliser l'AGU comme ALU entière comme le fait l'Intel i960). Le processeur doit avoir deux ALU entières pour de la double émission entière, trois pour de triple émission entière, etc. De plus, il faut ajouter des ports au banc de registre, pour lire deux fois plus d'opérandes et décrire deux résultats. Et enfin, il faut rajouter un port d'émission pour pouvoir émettre une micro-opération entière en plus. [[File:Processeur non-superscalaire basique 03.png|centre|vignette|upright=2|Processeur non-superscalaire basique]] La tendance est de multiplier les ALU entières, mais pas le circuit multiplieur. Le cout en transistors est alors grandement réduit, au prix de l'apparition de dépendances structurelles. Le CPU peut émettre deux additions en même temps, ou une addition et une multiplication, mais pas deux multiplications. Il en est de même avec le ''barrel shifter'', qui n'est pas dupliqué. Il est donc possible d'émettre un décalage avec une opération de base, mais pas deux décalages en parallèle. Mais ces contraintes d’appariement ne sont pas un problème, car il est rare de devoir émettre deux multiplications/décalages en même temps. La plupart des programmes sont majoritairement remplis d'additions, avec des multiplications assez rares et des décalages qui le sont encore plus. La moyenne est proche d'une multiplication pour 4/5 additions. Vu que des multiplications consécutives sont très rares, dupliquer le multiplieur est presque inutile. Disposer de plusieurs circuits multiplieurs ou de plusieurs ''barrel shifters'' serait donc un cout en circuits qui ne servirait que rarement et n'en vaut pas la chandelle. Il faut noter que sur les CPU 32 bits, les multiplications peuvent être exécutées dans la FPU ou dans un multiplieur séparé, tout dépend de si le CPU exécute les multiplications dans la FPU ou pas. {|class="wikitable" |- ! Voie d'émission n°1 !! Voie d'émission n°2 !! Voie d'émission n°3 |- | ALU entière || ALU entière || FPU |} Reste à connecter les unités de calcul à l'unité d'émission (indirectement, car il y a des étages de pipeline entre les deux). Une implémentation basique utilisée un port d'émission par unité. Prenons l'exemple d'un CPU superscalaire avec 4 ALU entières, une FPU, et une unité mémoire. Vu qu'il y a 6 unités, cela fait donc 6 ports d'émission. L'exemple historique le plus impressionnant est celui du Motorola 88110, un CPU double émission qui possède 10 unités. Il contient deux ALU entières, un circuit multiplieur, un circuit diviseur, une unité de manipulation de bits, une unité mémoire, un additionneur flottant, et deux unités graphiques pour des calculs impliquant des pixels. Le multiplieur est utilisé à la fois pour les multiplications entières, flottantes et le produit de deux pixels. Idem pour le diviseur, qui sert pour les divisions entières et flottantes. Et chaque unité a son propre port d'émission. La conséquence est que les contraintes d'appariement du Motorola 88110 sont simples : tant que deux µops atterrissent dans des unités séparées, la paire est permise. Il est par exemple possible d'émettre simultanément deux opérations entières simples, vu qu'il y a deux ALU. Par contre, impossible d'émettre simultanément deux multiplications, deux divisions, deux opérations flottantes, deux manipulations de bit, deux accès mémoire, etc. De plus, le partage du multiplieur fait qu'on ne peut pas émettre une multiplication entière avec une multiplication flottante. Idem avec les divisions, vu que le diviseur est aussi partagé. Ce sont les seules contraintes. ===Le partage des ports d'émission=== La présence d'un circuit multiplieur et d'un ''barrel shifter'' pose des problèmes pour le partitionnement. Il est possible d'avoir un port d'émission dédié au multiplieur, et un autre au ''barrel shifter'', qui sont séparés de ceux pour l'ALU entière. Il est alors possible d'émettre une opération entière, une multiplication et un décalage, simultanément. Nous parlerons de '''partitionnement entier''' pour désigner cette possibilité. [[File:Partitionnement superscalaire entier.png|centre|vignette|upright=2|Partitionnement superscalaire entier.]] Le partitionnement entier est cependant très rare, car le gain en performance serait trop faible au regard des couts en circuit. Quelques processeurs historiques l'utilisaient, mais ce n'est plus le cas de nos jours. La raison est que les multiplications et les décalages sont assez rares dans le code, ce qui fait que le port d'émission associés sont sous-utilisés. Et un port d'émission a un cout en circuit assez important. Et c'est sans compter qu'ajouter des ports sur le banc de registres juste pour un multiplier sous-utilisé n'en vaut pas la peine. L'idéal serait de trouver un moyen de réduire le nombre de ports d'émissions, sans réduire le nombre d'unités de calcul. [[File:Emission multiple des opérations entières, implémentation naive.png|vignette|Émission multiple des opérations entières, implémentation naive]] La solution consiste à '''partager les ports d'émission''', à savoir connecter un port d'émission à plusieurs unités de calcul. L'exemple classique est justement lié aux circuits multiplieur et ''barrel shifters''. L'idée est que le multiplieur et le ''barrel shifter'' sont mis sur le même port d'émission qu'une ALU entière. Prenons par exemple le processeur à double émission entière illustré ci-contre. Un port d'émission est relié à une ALU entière seule, et l'autre port d'émission alimente la seconde ALU entière et le multiplieur. La conséquence est que le processeur peut émettre deux opérations entières, dont une multiplication. Si on avait utilisé un port d'émission dédié au multiplieur, il aurait été possible d'émettre deux opérations entières et une multiplication. On perd donc une voie, mais on gagne en flexibilité et on économise des circuits. Notons que ce partage signifie aussi que le multiplieur partage les ports sur le banc de registre, ce qui fait une double économie. [[File:Emission multiple des opérations entières, implémentation courante.png|centre|vignette|upright=1.5|Émission multiple des opérations entières, implémentation courante]] En général, le ''barrel shifter'' et le multiplieur sont placés sur deux voies d'émission séparés, ce qui permet d'émettre un décalage et une multiplication en même temps. Les mettre sur le même port ne le permettrait pas. {|class="wikitable" |- ! Voie d'émission n°1 !! Voie d'émission n°2 !! Voie d'émission n°3 |- | * ALU entière * Multiplieur | * ALU entière * Barrel shifter | FPU |- | * Additions, soustractions, opérations bit à bit, etc. * Multiplication | * Additions, soustractions, opérations bit à bit, etc. * Décalages et rotations | Opération flottante |} Terminons concernant les multiplieurs avec une dernière subtilité. Pour rappel, les processeurs modernes intégrent en réalité deux multiplieurs différents. Le résultat d'une multiplication est très large et prend deux registres. Par exemple, une multiplication de deux opérandes 64 bits donne un résultat sur 128 bits, ce qui ne tient pas dans un registre, mais en prend deux. L'instruction de multiplication classique ne calcule que les 64 bits de poids faible. mais elle est complétée par d'autres instructions de multiplication qui peuvent faire le calcul complet. Pour résoudre le problème, les processeurs modernes intègrent deux instructions de multiplications : une qui calcule les bits de poids faible du résultat, une autre qui calcule les bits de poids fort. Et ces deux instructions sont associées à deux multiplieurs séparés, aux circuits différent. Le multiplieur qui calcule les bits de poids faible du résultat est appelé le ''low multiplier'', l'autre est appelé le ''high multiplier''. Le second multiplieur est souvent placé sur un second port d'émission, différent du premier multiplieur, partagé avec une ALU. L’avantage de mettre les deux multiplieurs sur deux ports d'émission différents est qu'une multiplication complète peut être réalisée en utilisant les deux multiplieurs en parallèle. Les deux sous-multiplications sont émises en même temps, exécutées en même temps. pas besoin d'exécuter l'une puis la seconde, d'où un gain performance appréciable. Nous venons de voir comment partager un port d'émission entre une ALU et un multiplieur. Mais au-delà de cet exemple, le partage des ports d'émission peut appliquer à n'importe quelle unité. Prenons l'exemple d'un CPU superscalaire avec 4 ALU entières, une FPU, et une unité mémoire. Vu qu'il y a 6 unités, cela fait donc 6 ports d'émission. Cependant, il est rare qu'un bloc de 6 instructions contienne exactement 4 opérations entières, une opération flottante, et un accès mémoire. Beaucoup de ports d'émission seraient sous-utilisés. La solution est de partager des ports d'émission, pour passer à la quadruple émission. Le CPU peut alors répartir 4 instructions sur les ports d'émission adéquats, à chaque cycle. Le CPU a donc 4 ports de décodage et 6 ports d'émission. Une implémentation classique permet n'importe quelle combinaison de 4 instructions compatible avec les 6 unités. Par exemple, il devient possible d'émettre simultanément 4 additions, la combinaison 2 * INT + FLOAT + MEM, 3 * INT + MEM, et bien d'autres. L'exemple relie une ALU entière, la FPU et l'unité mémoire sur le même port. Le CPU a alors quatre ports d'émission, qui ne sont pas "identiques". Trois d'entre eux sont reliés à une ALU entière chacun, rien d'autre. Le quatrième est lui relié à une ALU entière, la FPU et l'unité mémoire. On économise alors deux ports d'émission, mais cela entraine l'apparition de contraintes d’appariement. Le CPU peut émettre 3 opérations entières + n'importe quelle autre opération. Mais les autres combinaisons sont interdites. Le CPU peut émettre 6 opérations entières simultanément, grâce à 6 ALU entières. Les accès mémoire ou opérations flottantes ne viennent pas en plus, mais en remplacement des opérations entières. Regrouper plusieurs ALU sur un même port d'émission est donc à l'origine de dépendances structurelles, de nouvelles contraintes d’appariement. Dans certaines situations de '''''port contention''''', on a assez d'ALU pour exécuter N micro-opérations, mais la répartition des ALUs sur les ports l'empêche. Impossible d'émettre deux micro-opérations sur deux ALU si elles sont sur le même port d'émission. On peut réduire les cas de ''port contention'' en répartissant correctement les ALU sur les ports d'émission, mais sans jamais les supprimer complétement. Un exemple est celui du PowerPC 604. Il implémentait la quadruple émission, alors qu'il avait 5 unités de calcul. Mais deux unités partageaient un même port d'émission. Dans le détail, il avait deux ALU entières, un circuit multiplieur/diviseur, une FPU, une unité mémoire. La FPU et le multiplieur étaient sur le même port d'émission. En conséquence, le CPU pouvait émettre seulement les combinaisons INT + INT + MEM + (MUL/FLOAT). : Il est intéressant de voir l'exemple d'un processeur superscalaire parfait, sans contraintes d'appariement, à N voies. Pour cela, on part d'un processeur non-superscalaire, avec M unités de calcul. Un tel processeur peut s'implémenter avec N ports d'émission, chacun relié à M unités de calcul possibles, ce qui fait que les M unités de calcul sont dupliquées en N exemplaires. Si on prend par exemple un CPU non-superscalaire avec une ALU, une FPU, une unité mémoire et une unité de branchement, un port d'émission sera relié à une ALU, une FPU, une unité mémoire et une unité de branchement. ===La duplication des autres unités fonctionnelles=== Dupliquer les ALU entière est une première étape, mais il est aussi possible de dupliquer les autres unités fonctionnelles. Par exemple, il est possible de dupliquer l'unité mémoire ou l'unité de branchement. Reste à voir quelles unités dupliquer, et pourquoi. Précisons que dans ce qui va suivre, nous allons parler de la duplication des unités en général, pas seulement des unités mémoire/branchement. Nous allons continuer de parler de la duplication des ALU entières dans ce qui suit, mais de manière plus générale. Pour un processeur à N voies, il est théoriquement possible de dupliquer toutes les unités en N exemplaires. Mais ce n'est jamais fait en pratique, car le cout en circuits serait trop important et le gain en performance trop faible. Mieux vaut dupliquer certaines unités bien précises, quitte à avoir des contraintes d'appariement. Et à ce petit jeu, toutes les duplications ne se valent pas, certaines sont plus rentables en matière de performance, le cout en circuit n'est pas le même selon l'unité, etc. La rentabilité en performance dépend surtout des contraintes d'appariement. Les contraintes d'appariement entrainent une baisse de performance significatives si elles interdisent des paires d'instructions fréquentes. Aussi, les opérations très fréquentes, souvent appairées, gagnent à dupliquer l'unité associée. Et au contraire, les unités rarement utilisées ne doivent pas être dupliquées. Il se trouve que les unités les plus utilisées sont les ALU entières, suivies par les unités mémoire et l'unité de branchement. Le cout en circuit n'est aussi pas le même. Dupliquer les ALU entière est trivial, car elles ont un budget en transistors assez faible. Les circuits multiplieurs, diviseurs, et les ''barrel shifter'' ont eux un cout en transistor plus élevés. Si on devait faire un classement, on aurait : ALU entière < ''barrel shifter'' < multiplieur. Pour les unités mémoire, le cout en transistor est là aussi conséquent. Le résultat final est que dupliquer les ALU entières est privilégié sur le reste, comme l'a vu dans la section précédente. Les unités mémoire arrivent en seconde place, suivie par les multiplieurs/''barrel shifter'' à la troisième place, et les unités de branchement à la quatrième place. Les CPU superscalaires larges ont donc tendance à multiplier les unités mémoire en second. Les multiplieurs et ''barrel shifters'' sont eux aussi dupliqués sur les CPU superscalaires larges, mais cela vient souvent après avoir dupliqué les unités mémoire. La raison est que les accès mémoire sont critiques pour la performance des CPU à exécution dans le désordre, pas les multiplications. Pour les unités de branchement, une subtilité complique le fait d'en installer plusieurs. Que faire quand deux branchements sont pris ? La solution la plus simple est de ne pas se trouver dans cette situation : on n'utilise qu'une seule unité de branchement et on n’exécute qu'un seul branchement par cycle. La majorité des processeurs superscalaires étroits font ainsi. Les processeurs superscalaires larges ont cependant deux unités de branchements, mais ils n'acceptent qu'un seul branchement pris à la fois. Si les deux branchements pris sont exécutés en même temps, le processeur n’exécute que le plus récent, dans l'ordre du programme. ===Les CPU superscalaires mélangent les trois techniques=== Les CPU superscalaires utilisent toutes les techniques à la fois : partitionnement, duplication de l'ALU entière, duplication des autre unités fonctionnelles. Chaque processeur utilise ces trois stratégies à sa sauce, en fonction de son budget en transistor. Les quatre techniques ont cependant un cout en circuit différent, et donnent des gains de performances eux aussi forts différents. * Le '''partitionnement superscalaire''' a un cout en circuit modéré, car on n'a pas besoin de dupliquer d'ALU. * La '''duplication des ALU entières''' est la technique la plus importante : elle a un cout en circuit modéré, et donne des gains en performance impressionnants. * La '''duplication des autres unités''' a un cout en circuit variable, pour des gains en performance eux aussi variables. * Le '''partage des ports d'émission''' réduit le cout en circuit du CPU, pour des pertes de performances mineures si bien fait. L'usage du partitionnement seul, sans duplication, était surtout le fait des processeurs commercialisés entre les années 1989 et 1993. Le partage des ports d'émission a lui aussi mis un peu de temps pour s'imposer. Globalement, les processeurs superscalaires ont évolués progressivement, pour se rapprocher d'une sorte de standard. Mais pour comprendre ce qu'est ce standard, et en quoi les CPU historiques s'en sont progressivement rapprochés, il faut étudier l'histoire des CPU superscalaires. L'histoire des CPU superscalaires a commencé dès 1960, mais est resté un projet de recherche pendant plusieurs décennies. De nombreux designs ont été conçus, mais abandonnés avant la production, comme l'ACS-1 d'IBM. Les années 1980 ont vu l'arrivée de prototypes de processeurs VLIW, mais qui n'étaient pas superscalaires. Par exemple, l'Apollo DN10000 et l'Intel i860 pouvaient émettre deux instructions à la fois, sous conditions, mais demandaient que le compilateur fasse une bonne partie du travail. Les premiers CPU superscalaires commercialisés sont sortis en 1989. Deux CPUs superscalaires sont sortis cette année là : le RS/6000 d'IBM et l'i960CA d'Intel. Puis, la compétition s'est aussi lancée dans la bataille. Les CPU commercialisés avant l'année 1993 étaient à double émission, à l'exception du SuperSPARC qui utilisait la triple émission. Les modèles après 1993 hésitaient entre double et quadruple émission. Dans le tableau ci-dessous, les processeurs quadruple émission sont en bleu, les triple émission sont en rouge, les autres ne sont pas en couleur. {|class="wikitable" |- ! !! IBM !! HP PA-RISC !! SPARC !! Intel!! Alpha !! Autres |- ! 1989 | RS/6000 || || || i960CA || || |- ! 1990 | || || || || || |- ! 1991 | || || || || || Motorola 88110 |- ! 1992 | RSC || PA 7100 || class="f_rouge | SuperSPARC || || 21064 || |- ! 1993 | PPC 601 || || HyperSPARC || Pentium || || |- ! 1994 | class="f_bleu | POWER 2 || PA 7200 || || || class="f_bleu | 21164 || |- ! 1995 | 603/604 || class="f_bleu | PA 8000 || class="f_bleu | UltraSPARC 1 || Microarchitecture P6 (+ concurrence AMD) || || class="f_bleu | MIPS R1000 |- ! 1996 | class="f_bleu | 620 || || || || class="f_bleu | 21264 || |- ! ... || ... || ... || ... || ... || ... || ... |} Les premiers CPU à double émission sont assez représentatifs des CPU à double émission modernes. Il faut dire que se limiter à deux voies ne permet pas de faire beaucoup de choses. Voici le tableau chronologique disant quel CPU utilisait quelle technique. * Les CPU en vert utilisaient la double émission entière-flottante. * Les CPU en rouge utilisaient la double émission entière "pure". * Les CPU en jaune utilisaient un ''partitionnement complet'' entre ALU, FPU et unité mémoire. * Les CPU sans couleur utilisaient un grand nombre d'unités, avec beaucoup de ports d'émission. * Les CPU barrés utilisent la triple ou quadruple émission et seront vu dans la section suivante. {|class="wikitable" |- ! !! IBM !! HP PA-RISC !! SPARC !! Intel!! Alpha !! Autres |- ! 1989 | class="f_vert | RS/6000 || || || class="f_rouge | i960CA || || |- ! 1990 | || || || || || |- ! 1991 | || || || || || Motorola 88110 |- ! 1992 | class="f_vert | RSC || class="f_vert | PA 7100 || <s>SuperSPARC</s> || || class="f_jaune | 21064 || |- ! 1993 | class="f_vert | PPC 601 || || class="f_jaune | HyperSPARC || class="f_rouge | Pentium || || |- ! 1994 | <s>POWER 2</s> || PA 7200 || || || <s>21164</s> || |} C'est en 1994, que la quadruple émission est arrivée et que les CPU ont essayé divers implémentations. Il y avait alors trois stratégies pour la double/triple/quadruple émission, qui partageaient des problèmes similaires. La première implémentation dupliquait les ALUs et les FPUs, ce qui permettait d'émettre deux opérations flottantes avec deux opérations entières. Le POWER 2 dupliquait ses FPUs à la perfection, alors que le 21264 séparait l'additionneur et le multiplieur flottant. Les accès mémoire étaient traités comme des opérations entières et le processeur pouvait souvent en émettre deux à la fois. Mais une telle organisation n'est plus utilisée de nos jours, car, sans instructions flottantes à exécuter, elle est équivalente à de la double émission. La seconde implémentation utilisait deux ALU entières (dont un multiplieur), une unité mémoire et une FPU.Cette organisation est intéressante, mais encore trop stricte pour donner de bons résultats, les quadruplets avec exactement deux opérations entières, un accès mémoire et une opération flottante étant trop rares. L'usage de ces 4 unités en double ou triple émission a été utilisé sur le PA 7200 et le SuperSPARC. Malheureusement, en plus de problèmes au niveau de son cache, le SuperSPARC avait de nombreuses contraintes d’appariement, car le banc de registre n'avait pas assez de ports pour alimenter certaines combinaisons d'instructions. De plus, s'il émettait une multiplication, il ne pouvait pas émettre de seconde µop. Enfin, une troisième implémentation utilisait un grand nombre d'unités fort différentes, bien plus que quatre, avec au minimum deux ALU entières. Prenons l'exemple de l'UltraSPARC, qui avait : deux ALU entières, une unité mémoire, une unité de branchement, un additionneur flottant, un multiplieur flottant, un diviseur flottant (aussi utilisé pour le calcul des racines carrées), et 2 unités graphiques pour les calculs sur des pixels. En tout, cela fait 9 unités différentes, pour de la quadruple émission. Dans le même genre, les processeurs MIPS R8000 et R10000 avaient une implémentation plus moderne, dans le sens où toutes les unités étaient dupliquées. Le CPU avait deux ALU, deux FPU et deux unités mémoire. Il pouvait donc émettre quatre instructions à la fois, tant que le paquet collait avec ces six unités. Moitié opérations entières, moitié opérations mémoire, avec de quoi remplacer les opérations entières par des opérations flottantes. Le PA 8000, lui, dupliquait toutes ses unités en deux exemplaires, ce qui n'est pas l'idéal, aucun processeur moderne ne fait cela aujourd'hui. Le tout est résumé dans le tableau ci-dessous, avec : * en vert les CPU utilisant la première stratégie ; * en rouge les CPU utilisant la seconde stratégie ; * en jaune les CPU utilisant la troisième stratégie. {|class="wikitable" |+ Processeurs quadruple émission historiques |- ! Année !! Processeur !! Unités |- ! 1991 | class="f_jaune | Motorola 88110 || class="f_jaune | 2 ALU + MUL + DIV + BIT + MEM + FADD + 2 unités graphiques |- |- ! rowspan="2" | 1994 | class="f_vert | POWER 2 || class="f_vert | 2 ALU/MEM + 2 FPU (+ 2 Branchements via ''branch folding'') |- | class="f_rouge | 21164 || class="f_rouge | 2 ALU + FPU + MEM |- ! rowspan="3" | 1995 | PA 8000 || 2 ALU + 2 ''barrel shifters'' + 2 MEM + 2 FPU (FMA) + 2 FPU (DIV et SQRT) + 2 SIMD |- | class="f_jaune | UltraSPARC 1 || class="f_jaune | 2 ALU + MEM + BRANCH + FADD + FMULFDIV + 2 unités graphiques |- | MIPS R8000 et R10000 || 2 ALU + 2 FPU + 2 MEM |- ! rowspan="2" | 1996 | class="f_rouge | 620 || class="f_rouge | 2 ALU + FPU + MEM |- | class="f_vert | 21264 || class="f_vert | 2 ALU/MEM + 2 FPU (FADD + FMUL) |} Malheureusement, ces CPUs historiques n'avaient ni assez d'unités de calcul entières, ni d'unités mémoire, pour remplir la quadruple émission. Environ la moitié des instructions d'un programme correspond à des instructions entières. Pour en profiter, un processeur à N voies doit disposer d'au minimum N/2 ALU entières, l'idéal étant d'aller au-delà. Les CPU superscalaires historiques avaient 2 ALU pour de la quadruple émission, ce qui était très limite. En comparaison, les CPU superscalaires modernes mettent le paquet niveau ALU entière. La plupart des CPU x86 modernes descendent rarement sous les 2/3, la plupart remplit presque la totalité de la largeur du CPU. Pour donner un exemple, la microarchitecture Golden Cove d'Intel est un processeur à 6 voies, avec 5 ALU entières. Pour être précis, un programme informatique exécute environ 40% de son code dans des instructions arithmétiques, un autre 40% dans les accès mémoire, et un le reste pour... le reste. La conséquence est que les processeurs modernes dupliquent leurs unités mémoire. Par exemple, la microarchitecture ''Golden Cove'' d'Intel dispose de trois unités mémoire : deux spécialisées dans les écritures, trois dans les lectures. La microarchitecture ''Gracemont'' utilise la pentuple émission et peut émettre 4 µops entières et 4 µops mémoire. Notez que le ratio est équilibré entre opérations entières et mémoire, avec soit égalité, soit un avantage pour les ALU entières. Une autre régularité est que la largeur totale du processeur peut être occupée par des opérations entières/mémoire. Pour le dire autrement, sur un processeur quadruple émission, il pourra émettre un mix de 4 instructions entière/mémoire, avec zéro opération flottante. Idem avec des processeurs triples ou pentuple émission, voire plus. Si le processeur émet une opération flottante, elle remplace une opération entière. Prenons l'exemple des processeurs AMD K6, sortis en 1997, juste avant les AMD Athlon. Ils avaient 10 unités de calcul, 6 ports d'émission, 4 ports de décodage. Voici exactement comment étaient répartie les unités de calcul sur les ports d'émission. C'était des processeurs quadruple émission, ce qui fait que la moitié de la largeur du processeur sert pour des opérations entières, et l'autre moitié pour les accès mémoire. {|class="wikitable" |- ! Port d'émission n°1 !! Port d'émission n°2 !! Port d'émission n°3 !! Port d'émission n°4 !! Port d'émission n°5 !! Port d'émission n°6 ! |- | ALU entière || ALU entière || FPU || Unité de branchement || Unité LOAD || Unité STORE |- | || Multiplieur || || || || Unité de calcul d'adresse (instruction LEA) |- | || ''Barrel shifter'' || || || || Unité pour les instructions PUSH |} Les microarchitectures K7, K8 et K10, utilisées sur les anciens CPU AMD Athlon, sont un exemple moins représentatif. Ces microarchitectures utilisent le partage des ports d'émission au maximum. C'était des microarchitectures à triple émission, avec six ports d’émission. Il y avait trois ports d'émission pour les opérations flottantes, et trois ports d'émission pour les micro-opérations entières/mémoire. Il y avait trois ALU entières et trois unités mémoire, chaque ALU partageait un port d'émission avec une unité mémoire. Elle pouvait donc émettre soit trois opérations entières, soit trois µops mémoire, soit un mix des deux. En plus des mix avec les opérations flottantes et branchements. {|class="wikitable" |- ! Port d'émission n°1 !! Port d'émission n°2 !! Port d'émission n°3 !! Port d'émission n°4 !! Port d'émission n°5 !! Port d'émission n°6 ! |- | ALU entière || ALU entière || ALU entière || FADD || FMUL || FPU (autres opérations) |- | Multiplieur || || || || || |- | LOAD/STORE || LOAD/STORE || LOAD/STORE || || || |} Les CPU superscalaires larges dupliquent les multiplieurs et/ou les ''barrel shifters'', et même les unités de branchement. La raison est que quand la largeur du CPU augmente, le processeur traite des paquets d'instructions de plus en plus gros. Par exemple, pour un CPU à 10 voies, cela veut dire émettre 10 instructions en même temps. Il est alors plus fréquent d'avoir deux multiplications, deux décalages, deux accès mémoire, deux branchements. Par exemple, la moyenne est d'une multiplication tous les 5 instructions. Les CPU superscalaires à 10 voies ont donc tendance à avoir deux multiplications par paquet d'instruction, en moyenne. Avoir deux multiplieurs est alors un gain en performance clair. Par exemple, la microarchitecture ''Golden Cove'' a deux ''barrel shifters''. C'est une architecture à 6 voies. {|class="wikitable" |- ! Port d'émission n°1 !! Port d'émission n°2 !! Port d'émission n°3 !! Port d'émission n°4 !! Port d'émission n°5 !! Port d'émission n°6 !! Port d'émission n°7 !! Port d'émission n°8 !! Port d'émission n°9 !! Port d'émission n°10 |- | ALU entière || ALU entière || ALU entière || ALU entière || ALU entière || LOAD || LOAD || LOAD || STORE || STORE |- | ''Barrel shifter'' || Multiplieur || Multiplieur || ''Barrel shifter'' || || || || || || |- | Branchements || Diviseur || || Branchements || || || || || || |} ==Les µops mémoire sur les processeurs superscalaires== Plus haut, nous avons volontairement passé sous silence les accès mémoire. La raison à cela est que leur support sur les CPU superscalaire peut se faire de plusieurs manières différentes, qu'il vaut mieux expliquer dans une section dédiée. Les différentes implémentations sont décrites dans la liste suivante, nous allons les voir une par une. * Avec la première méthode, les accès mémoire sont exécutés par le pipeline pour les opérations entières. * Avec la seconde méthode, les accès mémoire ont un pipeline dédié ; c'est l'''émission parallèle des accès mémoire''. * Avec la troisième méthode, il est possible d'émettre plusieurs accès mémoire simultanément : c'est l'''émission multiple des accès mémoire''. Voyons ces trois cas dans le détail. Nous verrons notamment les différentes formes d'émission multiple des accès mémoire. ===Les accès mémoire traités dans le pipeline entier=== Dans le cas le plus simple, les accès mémoire sont traités comme des opérations entières un peu spéciales. L'unité mémoire est sur le même port d'émission que l'ALU entière, ce qui fait que les accès mémoire remplacent des opérations entières. Faire ainsi permet d'utiliser une ALU entière pour les calculs d'adresse, pas besoin de rajouter une unité de calcul d'adresse séparée. Typiquement, un processeur de ce type place l'unité mémoire après l'unité de calcul. Les opérations entières n'utilisent que l'ALU entière, mais pas l'unité mémoire. Les accès mémoire exécutent un calcul d'adresse dans l'ALU entière, puis l'adresse calculée est envoyée à l'unité mémoire. Le tout est illustré ci-dessous, dans le cas d'un processeur historique à double émission entière-flottante. [[File:Processeur non-superscalaire basique 01.png|centre|vignette|upright=1.5|Processeur non-superscalaire basique]] Un exemple de CPU double émission de ce type est celui du Power PC 440, un CPU destiné à l'embarqué. Vu qu'il était destiné à l'embarqué, il n'avait pas de FPU, il n'avait pas besoin de manipuler de nombres flottants. Il n'a donc que des ALU entières, un multiplieur et une unité mémoire. Il dispose de deux ports d'émission. Le premier est connecté à une ALU entière et un circuit multiplieur, le second est relié à l'unité mémoire et une seconde ALU entière. Une organisation simple, mais très efficace ! [[File:PowerPC 440.png|centre|vignette|upright=2|Microarchitecture du PowerPC 440.]] L'implémentation économise une unité de calcul d'adresse, mais n'a pas de cout en performance significatif. Les accès mémoire étant très lents, émettre une µop entière en parallèle d'un accès mémoire ne sert pas à grand-chose. On peut émettre cette µop entière un cycle plus tard, elle sera terminée avant même que l'accès mémoire soit terminé, même si l'accès mémoire se fait dans le cache L1 ou L2. Pour comprendre pourquoi, faisons quelques calculs. Un accès mémoire prend deux-trois cycles quand il tombe dans le cache L1. Et on doit attendre qu'il soit terminé pour en émettre un nouveau. Combien d'instructions arithmétiques peut-on lancer pendant ce temps, sur un CPU triple émission ? Au premier cycle, on peut en émettre 2 (l'instruction mémoire prend une place, donc 3-1), puis 3 au second cycle. Ce qui fait 5 instructions arithmétiques au total. Or, il se trouve qu'il y a une instruction d'accès mémoire pour 5 instructions arithmétiques, environ. Par contre, ce compromis change quand on passe à la quadruple émission, voire au-delà. Dans ce cas, il devient intéressant de pouvoir émettre une nouvelle instruction mémoire à chaque cycle. Ce qui nous amène à la section suivante... ===L'émission parallèle des accès mémoire=== A partir de la quadruple émission, la tendance a été de séparer l'unité mémoire des ALU entières. Cela permet d'émettre des µops mémoire en même temps que des µops entières et/ou flottantes., ce qui porte le nom d''''émission parallèle des µops mémoire''', ou encore ''émission mémoire parallèle''. Par exemple, un processeur quadruple émission peut émettre en même temps deux opérations entières, une opération flottante et un accès mémoire. L'accès mémoire vient en plus des opérations entières, il n'est pas possible de remplacer l'accès mémoire par une opération entière. La technique ne permet pas de faire les calculs d'adresse dans l'ALU entière. Il faut donc utiliser une unité de calcul d'adresse séparée. Elle est intégrée dans l'unité mémoire, qui fait l'interface entre le cache et le banc de registres. Le cout en circuits est très faible, car les unités de calcul d'adresse n'utilisent guère plus qu'un additionneur et un circuit de décalage très simple. L'émission mémoire parallèle est plus facile à implémenter sur les CPU RISC, qui ont des instructions mémoire séparées du reste. Les CPU CISC ne sont pas dans ce cas, ce qui fait que séparer l'unité mémoire du pipeline entier est compliqué. Les CPU superscalaires historiques étaient pour moité des CPU RISC et pour moitié des CPU CISC, ce qui fait qu'ils n'utilisaient pas ou peu l'émission mémoire parallèle. Les premiers processeurs superscalaires se contenaient de l'émission parallèle mémoire, ils ne pouvaient émettre qu'un seul accès mémoire à la fois, l'unité mémoire n'était pas dupliquée. Et ce n'est pas tant un problème que ça, du moins sur les processeurs à double ou triple émission. En effet, il est rare que l'unité mémoire doive faire deux accès simultanés. Notons que le processeur peut exécuter une instruction mémoire en parallèle d'un calcul ou d'un branchement, seuls les accès mémoire simultanés sont impossibles. ===L'émission multiple des accès mémoire avec une LSQ=== Les processeurs superscalaires larges travaillent sur des paquets de 8 à 10 instructions, il est plus fréquent d'avoir plusieurs accès mémoire par paquet. Dans ces conditions, il est utile d'avoir une '''émission multiple des accès mémoire''', à savoir d'émettre plusieurs micro-opérations mémoire en même temps. Les processeurs superscalaires modernes sont capables d'émettre plusieurs lectures/écritures simultanément. Par exemple, ils peuvent émettre une lecture en même temps qu'une écriture, ou plusieurs lectures, ou plusieurs écritures. Il faut noter que selon le processeur, il peut y avoir des restrictions quant aux accès mémoire émis en même temps. Par exemple, certains processeurs peuvent émettre une lecture avec une écriture en même temps, mais pas deux lectures ni deux écritures. Ou encore, ils peuvent émettre deux lectures, une lecture et une écriture, mais pas deux écritures en même temps. Dans la majorité des cas, les processeurs ne permettent pas d'émettre deux écritures en même temps, alors qu'ils supportent plusieurs lectures. Il faut dire que les lectures sont plus fréquentes que les écritures. Les processeurs qui autorisent toutes les combinaisons de lecture/écriture possibles, sont rares. L'émission multiple des accès mémoire s'implémente dans l'unité mémoire. Pour rappel, l'unité mémoire s'interpose entre le cache L1 et le reste du pipeline. Dans le cas le plus simple, elle incorpore une ''load/store queue'' et des unités de calcul d'adresse. L'émission multiple des accès mémoire demande de rendre la ''Load-store queue'' multi-ports, afin de gérer plusieurs micro-opérations mémoire simultanées. Il faut aussi dupliquer les unités de calcul d'adresse reliées à la LSQ, chaque port d'émission mémoire devant avoir sa propre unité de calcul d'adresse. : Dans ce qui suit, nous parlerons d'AGU (''Adress Generation Unit'') pour désigner les unités de calcul d'adresse, et de LSQ pour designer la ''Load-store queue''. [[File:Processeur non-superscalaire basique 02.png|vignette|upright=1|Processeur non-superscalaire basique]] Dupliquer les ports de la LSQ et les AGU est nécessaire. Mais qu'en est-il du cache ? La réponse varie suivant le processeur. Il y a deux grandes méthodes pour implémenter l'émission multiple des accès mémoire. La première méthode ajoute des ports de lecture/écriture au cache de données, pour faire des lectures/écritures simultanées. Il faut alors dupliquer des unités de calcul, rajouter les ports sur le cache, mais aussi rajouter des ports sur la ''load/store queue'', pour qu'elle échange des données/commandes mémoire avec le cache. Le cout en circuits est alors conséquent La seconde duplique les unités de calcul, mais pas les ports d'accès au cache. Les accès mémoire sont alors accumulés dans la ''load/store queue'', qui sont ensuite traités un par un par le cache. Un exemple est celui des processeurs AMD de micro-architecture K7 K8, à savoir les anciens AMD Athlon et AMD Athlon 64, qui pouvaient calculer trois adresses simultanément, mais ne pouvaient faire qu'un seul accès au cache par cycle. Le cout en circuit est modéré : les unités de calcul coutent très peu, les ports de la ''load/store queue'' coutent déjà un peu plus. Quelques processeurs utilisaient des solutions intermédiaires. Un processeur utilisant cette technique est, par exemple, capable d'émettre quatre µops mémoire en même temps, mais avec seulement deux ports sur le cache. Un exemple classique étant les Pentium 1 et 2 d'Intel, dont nous parlerons dans le chapitre suivant. ===L'émission séparée des LOAD et STORE=== De rares processeurs ont des ports d'émission qui peuvent faire indifféremment lecture comme écritures. Mais les processeurs modernes préfèrent séparer ports d'émission pour les lectures et les écritures. Un exemple est celui des processeurs Intel de micro-architecture Nehalem, qui avaient un port de lecture et un port d'écriture tous deux reliés à la ''Load-store queue'', chacun avec leur propre unité de calcul d'adresse. Comme autre exemple, les processeurs skylake ont une LSQ avec deux ports de lecture et un port d'écriture, ce qui permet d'émettre deux lectures en même temps qu'une écriture. Dans cette section, nous allons étudier le cas avec des ports séparés pour les lectures et écritures. En général, les processeurs ont un peu plus de ports de lectures que d'écritures. Une raison est qu'un programme a, en moyenne, un tout petit peu plus de lectures que d'écritures. Mais la différence n'est pas énorme, c'est un léger déséquilibre. Une seconde raison est que l'exécution dans le désordre marche bien mieux quand les lectures ont lieu le plus tôt possible. Donc mieux vaut privilégier les lectures à l'émission, pour qu'elles se fassent un peu en avance. En pratique, la différence n'est pas très marquée. Il est courant d'avoir un port de lecture et un d'écriture, les CPU superscalaires très larges ont souvent deux ports de lecture et deux d'écriture. A la rigueur, quelques CPU ont trois ports de lecture et deux d'écriture. Le cas le plus simple est celui où on peut émettre une lecture et une écriture en même temps. Il s'implémente facilement si la LSQ est en réalité une simple ''Store queue'', à savoir qu'elle met en avance les écritures uniquement. Pour rappel, les écritures sont mises en attente dans la ''Store queue'', mais les lectures sont exécutées immédiatement. Une fois l'adresse à lire connue, la lecture consulte la ''Store queue'' pour détecter les dépendances de données, puis s'exécute. La donnée à lire est lue soit depuis la ''Store queue'', soit depuis le cache. [[File:Emission LOAD - Store séparée.png|vignette|upright=1|Émission LOAD - Store séparée]] L'implémentation de l'émission multiple est alors très simple. La ''Store queue'' a déjà deux ports, avec un pour les lectures et un autre pour les écritures. Idem pour le cache, qui a naturellement un port de lecture et un d'écriture. Émettre une lecture et une écriture simultanément ne demande donc pas de modification digne de ce nom. La ''Store queue'' doit juste supporter une lecture et une écriture simultanée. Ajouter l'émission d'une seconde lecture n'est pas compliquée : il faut juste rajouter un second port de lecture sur le cache et la ''Store queue''. Pour rappel, l'unité mémoire est précédée par une structure qui met en attente les micro-opérations mémoire avant leur émission finale. La structure en question varie suivant l'implémentation, mais un cas particulier se marie bien avec l'émission multiple des µops mémoire. Il s'agit du cas avec une file de µops séparée pour les lectures et une autre pour les écritures, appelées respectivement la ''file de µops LOAD'' et la ''file de µops STORE''. Il est alors possible d'émettre une lecture et une écriture lors du même cycle d'horloge. Le port de lecture alimente une unité de calcul d'adresse dédiée, directement reliée au cache. Le port d'écriture du cache alimente une unité de calcul, qui est suivie par une file d'écriture, elle-même reliée au cache. Les processeurs AMD de micro-architecture K6 utilisaient cette technique. [[File:Double émission avec le Load Ordering, Store Ordering.jpg|centre|vignette|upright=2.5|Double émission avec le Load Ordering, Store Ordering]] ==Les CPU superscalaire à exécution dans le désordre== La superscalarité modifie aussi les circuits dédiés à l'exécution dans le désordre. Elle modifie les unités de renommage de registre, le ROB et les autres structures liées à l'exécution dans le désordre, au sens large. Aucune structure n'est épargnée. Elles ont tous des prots de lecture/écriture en plus, afin d'encaisser l'émission, le ''commit'' ou le renommage simultané de plusieurs µops. Par exemple, le ROB doit être modifié pour émettre et terminer plusieurs instructions en même temps, en ajoutant des ports de lecture/écriture. Pour un CPU superscalaire à 8 voies, on se dit que le ROB peut retirer 8 µops par cycle maximum. Mais certains processeurs récents ont un ROB qui peut retirer le double ! Un exemple est celui des CPU de micro-architecture Skymont, qui peuvent émettre 8 µops par cycle, mais en retirer 16. Quelques CPU de marque AMD étaient aussi dans ce cas. L'avantage est que cela permet de réduire la taille du ROB, du banc de registre et de quelques autres structures matérielles liées à l'exécution dans le désordre. Le gain sur-compense le cout en transistor nécessaire pour retirer 16 µops par cycle. Dans cette section, nous allons voir comment les étages du pipeline dédiés à l'exécution dans le désordre sont modifiées sur un CPU superscalaire. ===L'exemple du PA-RISC PA 8000=== Avant de commencer, nous allons voir un processeur superscalaire assez simple, le PA 8000, de HP, qui implémente le jeu d'instruction PA-RISC. Bien que très ancien, il implémentait l'exécution dans le désordre et le renommage de registre. Le peu d'informations que nous avons sur ce processeurs proviennent des documents "THE HP PA-8000 RISC CPU" par Ashok Kumar, et l'article de microprocessor report "PA-8000 Combines Complexity and Speed". Ils ne donnent malheureusement pas énormémment d'informations et je devrais être amené à faire quelques suppositions dans ce qui suit. Avant de commencer, parlons de détails sans lien avec la superscalarité. Ce processeur, comme beaucoup de processeurs PA-RISC, n'intégrait pas de cache de niveau L2 dans le processeur, qui était déporté en-dehors du CPU, sur la carte mère. Le processeur préférait utiliser ses transistors pour avoir un cache L1 assez large, quitte à ce qu'il soit plus lent. La lenteur du cache était prévue, le processeur compensait celle-ci en utilisant l'exécution dans le désordre, bien que ce ne soit pas parfait. Les CPU PA-RISC avant le PA 8000 utilisaient un pipeline à vagues ''wave pipeline'', ce qui était assez peu commun, mais le PA 8000 repasse à un pipeline synchrone classique. Passons maintenant à la superscalarité. Le PA 8000 est un processeur quadruple émission, qui peut émettre, à chaque cycle, deux opérations et deux accès mémoire. Le renommage de registre utilise des registres de renommage séparés des registres architecturaux, comme c'était la mode à l'époque. Le budget en transistor faisait que c'était soit ça, soit le renommage dans le ROB, faute de mieux. Le processeur utilise une implémentation ''Read After Issue'', ce qui veut dire que les opérandes des instructions sont lues après l'émission, juste avant l'exécution. Le processeur peut aussi ''commit'' deux opérations et deux accès mémoire par cycle, ce qui revient à transférer les résultats des registres de renommage vers les registres architecturaux. L'exécution dans le désordre est prise en charge par une structure matérielle unique, qui ressemble à une fusion entre un ROB et une fenêtre d'instruction. Et c'est là que je vais devoir faire des suppositions. Le document "THE HP PA-8000 RISC CPU" nomme cette structure : l''''''Instruction Reorder Buffer'''''. Il utilise pas moins de 850 000 transistors, et prend 20% de la taille du ''die''. L'article "THE HP PA-8000 RISC CPU" laisse fortement sous-entendre qu'il s'agit une structure unique, faite d'un seul tenant, mais l'article de microprocessor report dit le contraire par moment. Il est décrit comme une fenêtre d'instruction, à savoir qu'il détecte les dépendances entre instruction et les émet. Il gère aussi la détection des mauvaises prédictions de branchement et peut annuler les instructions chargées à tord, en les retirant de la fenêtre d'instruction. Il est aussi précisé que les instructions quittent cet ''Instruction Reorder Buffer'' dans l'ordre du programme. Elles ne peuvent en sortir que quand elles ont été exécutées et qu'elles n'ont causé aucune exception. Ce qui fait qu'il se comporte comme un ROB de ce point de vue là. Difficile de dire si l'''Instruction Reorder Buffer'' est un réel mélange entre un ROB et une fenêtre d'instruction, ou si il est réellement conçu avec deux structures séparées. Dans ce qui suit, je pars du principe que les deux structures sont séparées. Le processeur contient deux fenêtres d'instruction : une réservée aux µops mémoire (LOAD et STORE), l'autre pour les opérations entières/flottantes. Elles ont chacune 28 entrées, ce qui permet de mémoriser 56 µops au maximum. Les deux peuvent recevoir 4 µops par cycle de la part des décodeurs. Là encore, précisons que les choses ne sont pas claires pour ce qui est de la séparation. L'article de Microprocessor report dit que les deux sont physiquement séparées, et que cette séparation physique permet de simplifications (les opérations mémorisent des noms de registres plus court que les adresses demandées par les µops LOAD/STORE). Mais l'autre document cité laisse penser que l''''Instruction Reorder Buffer'' est une structure unique. A chaque cycle, le processeur peut émettre deux instructions de calcul et deux instructions mémoire. Les deux fenêtres d'instruction ont pour cela chacune deux ports d'émission. Les deux ports d'émission pour les µops mémoire sont identiques, et le cache L1 est un cache double port, ce qui permet d'exécuter deux lectures/écritures par cycle. Pour ce qui est des µops entières/flottantes, le processeur a dupliqué toutes ses unités de calcul : il a deux ALU entières, deux ''barrel shifters'', deux FPU de type FMAC, et deux unités de division flottante. Vraisemblablement, il y a deux ports d'émission, chacun étant connecté à une unité de chaque type. : S'il n'utilisait pas l'exécution dans le désordre, ce processeur aurait donc quatre pipelines : deux pipeline entiers identiques et deux pipelines mémoire. Et il aurait une superscalarité presque parfaite s'il était un CPU à double émission ! A chaque cycle, la fenêtre d'instruction émet les deux µops les plus anciennes qui sont prête à être exécutées. La documentation dit que la fenêtre émet "la plus vielle instruction paire, et la plus vielle instruction impaire", ce qui sous-entend que la fenêtre d'instruction est segmentée en deux. C'est précisémment la logique d'éveil et d'émission qui est segmentée, une partie gérant la moité de la fenêtre d'instruction, une seconde logique d'éveil/''schedule'' gérant le reste. L'avantage est une économie de transistors manifeste. Un inconvénient est que si les µops prêtes sont toutes dans la même moitié, une seule µops sera émise par cycle. Mais avec 2*14 entrées, le cas est assez rare pour que l'économie de transistors en vaille la peine. [[File:PA 8000 - microarchitecture.png|centre|vignette|upright=2|PA 8000 - microarchitecture]] ===La superscalarité avec une file/fenêtre d'instruction centralisée=== Plus haut, nous avons montré qu'un processeur pouvait avoir plus de ports d'émission que de ports de décodage. On dit aussi que sa ''largeur de décodage'' était supérieure à sa ''largeur d'émission''. La '''largeur de décodage''' est le nombre de µops fournies par l'unité de décodage par cycle d'horloge, la '''largeur d'émission''' est le nombre maximal de µops émises par cycle d'horloge. Et n'allez pas croire qu'un surplus de ports d'émission est du gâchis. Sur les processeurs avec exécution dans le désordre, ce surplus peut être utilisé. Mais avant toute chose, évacuons un détail. Vous avez sans doute pensé que le surplus peut être exploité par les instructions machines décodées en plusieurs µops . Par exemple, si une instruction est décodée en deux µops, on pourrait avoir un port d'émission en plus pour en profiter. Mais les ports de décodage sont *en sortie du décodeur*, et contiennent des µops, pas des instructions. Le surplus de ports d'émission peut occasionnellement utiliser le surplus de ports de décodage, mais cela implique que des µops ont été mises en attente dans l'unité d'émission, pour être émises par la suite. Et cela implique l'usage d'une fenêtre d'instruction ou d'une file de µops. Le principe est que les µops sont accumulées dans la fenêtre d'instruction, en attendant leurs opérandes ou la résolution d'une dépendance. Et si l'occasion se présente, une µops est émise sur chaque port d'émission. Il y a donc un gain en performances, mais il faut faire quelques précisions sur son origine. La largeur d'émission utilisée ne peut pas dépasser, *en moyenne*, la largeur de décodage. Et c'est intuitif : un CPU qui décode 4 µops par cycle ne peut pas émettre 6 par cycle en moyenne, sur le temps long, il n'y a pas de µops en surplus qui sortent du vide. Par exemple, sur un processeur quadruple émission, si on analyse combien d'instructions sont émises par cycle, il peut y avoir des cycles où la largeur d'émission est totalement utilisée, mais ce sera compensé par des périodes où elle est fortement sous-utilisée. Les µops sont accumulées en cas de sous-utilisation, puis consommées en cas d'utilisation complète. Les deux périodes se compensent. Et c'est là que l'on peut comprendre d'où vient le gain en performance. Les cycles où les ports d'émission sont sous-utilisés existent systématiquement, que le processeur utilise l'exécution dans le désordre ou pas. Ils sont liés à la présence de dépendances de données, aux contraintes d’appariement, etc. Elles tendent à réduire la moyenne du nombre de µops émises par cycle. Par contre, ce sont les cycles de rattrapage, où les ports en surplus sont utilisés, qui font remonter la moyenne. Le gain en performance est donc lié à ces cycles de rattrapage, où les µops accumulées sont émises dans les ports en surplus. Et ils n'existent que sur les processeurs avec une file/fenêtre d'instruction. Réduire le nombre de ports d'émission permet de garder des fenêtres d'instruction et un ROB simples, rapides et économes en énergie. Et mine de rien, c'est là un compromis important : à quoi bon augmenter le nombre de ports d'émission si c'est pour que ce soit compensé par une fréquence plus faible ? Par contre, réduire le nombre de ports augmente la ''port contention'', surtout si on a mal réparti les ALU. Il faut donc trouver un compromis entre réduire le nombre de ports d'émission d'un côté, réduire la ''port contention'' de l'autre. La différence entre largeur de décodage et d'émission a un impact assez fort sur le banc de registre, et précisément sur son nombre de ports de lecture. Le banc de registre a besoin de plus de ports de lecture avec une fenêtre d’instruction qu'avec des stations de réservation. Rappelons la terminologie utilisée dans ce cours. Les fenêtres d'instruction se contentent de mémoriser la micro-opération et quelques bits pour détecter la disponibilité des opérandes. Par contre, les stations de réservations mémorisent aussi les opérandes des instructions. Et cette différence a une influence le nombre de ports de lecture du banc de registre. Supposons que toutes les instructions sont dyadiques, à deux opérandes. Comptons le nombre de ports nécessaires pour alimenter les unités de calcul, sans utiliser d'arbitre de banc de registre. Avec une fenêtre d'instruction, il faut le double du nombre de ports d'émission. Mais avec des stations de réservation, il faut le double des ports de décodage. La raison est que les registres sont lus après émission avec une fenêtre d'instruction, avant avec des stations de réservation (sous-entendu, après le décodage). Or, comme dit plus haut, les processeurs superscalaires larges ont souvent plus de ports d'émission que de décodage. ===La superscalarité à fenêtres d'instruction décentralisées=== Les processeurs précédents utilisaient une unité d'émission simple, qui pouvait utiliser l'émission dans l'ordre ou dans le désordre. Elle peut être remplacée par une fenêtre d'instruction centralisée dans que cela quoi que ce soit aux explications précédentes, idem avec une station de réservation centralisée. En soi, l'exécution dans le désordre est donc totalement compatible avec une implémentation simple de la superscalarité. Par contre, des subtilités surviennent avec les fenêtres d'instruction décentralisées. Pour rappel, sur ces processeurs, les µops sont émises en deux phases. Une première phase de ''dispatch'' qui envoie les µops vers la fenêtre d'instruction adéquate, sans détecter les dépendances de données. La seconde phase de ''schedule'' gère les dépendances de données, elle met en attente les µops en attendant que l'unité soit disponible pour les exécuter, en attendant aussi que les opérandes soient disponibles. Et à ce petit jeu, il y a une différence entre le nombre de µops qui sont ''dispatch par cycle'' et celles qui sont ''schedule''. Dit autrement, la largeur d'émission est scindée en une '''largeur de ''dispatch''''' et une '''largeur de ''schedule''. Par exemple, prenons un processeur triple émission avec deux stations de réservation : une pour les µops entières/mémoire, et une autre pour les µops flottantes. L'unité d'émission peut ''dispatch'' maximum trois µops par cycle : soit trois µops entières/mémoire, soit trois flottantes, soit un mix de trois µops différentes. Les stations de réservation, quant à elles, peuvent chacune ''schedule'' 3 µops par cycle, vers trois ALUs entières pour la station de réservation entière/mémoire, vers trois FPS pour la station de réservation flottante. De quoi ''dispatch'' trois µops, mais d'en ''schedule'' six, à chaque cycle. Et cet exemple ne sort pas de nulle part : les CPU x86 d'Intel et AMD sont globalement dans ce cas, même si les chiffres varient d'une microarchitecture à l'autre. L'exemple précédent colle parfaitement à la microarchitecture K7 d'AMD, utilisée sur les processeurs Athlon dans les années 2000. [[File:AMD K7.png|centre|vignette|upright=2.5|AMD K7, microarchitecture.]] L'exemple précédent avait assez d'unités entières/flottantes pour couvrir toute la largeur de décodage/''Dispatch''. Mais ce n'est pas toujours le cas, comme va le montrer l'exemple suivant. Le MIPS R10000, qui utilisait un mélange de files de µops et de fenêtres d'instructions : une file de µops les accès mémoire, une fenêtre pour les instructions entières et une autre pour les opérations flottantes. Les branchements et NOPs étaient exécutés dans une unité de branchement distincte. Les trois files/fenêtres peuvent mémoriser 16 µops. Le processeur avait deux ALU entières, une AGU de calcul d'adresse, un additionneur flottant et un multiplieur/diviseur flottant. Il y avait un multiplieur entier sur le port d'émission l'ALU 2. Le processeur décodait 4 instructions par cycle et produisait jusqu'à 4µops, qui étaient redistribuées sur les trois fenêtres d'instructions. Chacune pouvait accepter 4 µops par cycle, ce qui fait que processeur pouvait ''dispatch'' 4 µops entières, ou 4 µops flottantes, ou 4 µops mémoire, ou un mélange de deux ou trois types de µops. Pour ce qui est du ''schedule'', la fenêtre d'instruction entière pouvait émettre 2 µops, la fenêtre flottante pouvait émettre une addition en même temps qu'une multiplication/divison flottante et qu'un branchement conditionnel flottant, et la file de µops mémoire ne pouvait émettre qu'une µop mémoire à la fois. En tout, cela fait 6 µops ''schedule'' pour 4 µops au ''dispatch''. [[File:R 10000.png|centre|vignette|upright=2.5|MIPS R10000, microarchitecture.]] ===La superscalarité à fenêtres d'instruction totalement décentralisées=== Prenons un cas extrême de fenêtre d'instruction décentralisée : celui où chaque ALU entière a sa propre station de réservation. En clair : une fenêtre d'instruction par ALU/FPU ! On parle de '''fenêtres d'instruction totalement décentralisées'''. Vous vous dites que ce cas est un peu trop extrême pour être réaliste, mais il n'en est rien. C'est même très courant sur les architectures basse consommation, et sur pas mal de CPU x86 modernes. Une telle organisation entraine une légère perte de performance, comparé à une fenêtre d'instruction centralisée ou partiellement décentralisée. Et cela peut se comprendre par un exemple. Imaginez un processeur avec deux ALU, donc deux stations de réservation. Il arrivera qu'une station de réservation ait plusieurs µops prêtes, alors que l'autre en ait zéro. Dans une telle situation, une seule µop sera émise au cycle suivant, vu que chaque station de réservation a un seul port d'émission vers une seule ALU entière. Par contre, avec une fenêtre d'instruction centralisée double port, on aurait pu émettre les deux µops en même temps sur deux ALUs séparées. La perte de performance est donc liée au fait que les µops '''''prêtes''''' sont mal réparties dans les différentes stations de réservation. Il arrivera que des µops prêtes s'accumulent dans une station de réservation, alors que d'autres seront pleines, ou du moins sous-utilisées. Et ce n'est pas quelque chose qui peut être réglé à l'étape de ''dispatch'', car on ne sait pas encore quand les µops auront leurs opérandes de disponibles. [[File:Comparaison entre une station de réservation totalement décentralisée et une autre qui ne l'est pas.png|centre|vignette|upright=2.5|Comparaison entre une station de réservation totalement décentralisée et une autre qui ne l'est pas.]] Par contre, décentraliser totalement les fenêtres d'instruction entraine aussi un gain considérable en termes de consommation énergétique. Et c'est la raison pour laquelle les fenêtres d'instructions totalement décentralisées sont utilisées sur les architectures basse consommation. La perte de performance ne peut pas s'expliquer clairement à ce stade du cours, car il nous faudrait parler d'émission superscalaire. Le gain en matière d'énergie vient de l'économie de circuits, qui est assez drastique. Le gain en matière d'énergie vient de l'économie de circuits, qui est assez drastique. Je rappelle qu'une station de réservation a besoin, pour N instructions, d'environ N^2 circuits (des comparateurs, notamment). Prenons une station de réservation centralisée de 64 entrées et comparons avec 8 stations de 8 entrées chacune. Les deux donneront 64 entrées, mais la première aura un cout en circuit proportionnel à 64², alors que le second aura un cout en circuit de 8 *(8²). Entre les deux, le choix est clair : la seconde solution est plus économe. D'où l'utilisation de cette solution sur les microarchitectures basse consommation. ===L'unité de renommage superscalaire=== Avec la superscalarité, l'unité de renommage de registre doit gérer le cas où des instructions consécutives ont des dépendances de registre. Par exemple, prenons un processeur à double émission, qui renomme deux instructions consécutives. Si elles ont une dépendance de registre, le renommage de la seconde instruction dépend du renommage de la première. La première doit être renommée et le résultat du renommage est utilisé pour renommer la seconde, ce qui empêche d'utiliser deux unités de renommage séparées. Pour cela, elle renomme les registres sans tenir compte des dépendances, pour ensuite corriger le résultat. [[File:Unité de renommage superscalaire.png|centre|vignette|upright=2|Unité de renommage superscalaire.]] Seules les dépendances lecture-après-écriture doivent être détectées, les autres étant supprimées par le renommage de registres. Repérer ce genre de dépendances se fait assez simplement : il suffit de regarder si un registre de destination d'une instruction est un opérande d'une instruction suivante. [[File:Détection des dépendances sur un processeur superscalaire.png|centre|vignette|upright=2|Détection des dépendances sur un processeur superscalaire.]] Ensuite, il faut corriger le résultat du renommage en fonction des dépendances. Si une instruction n'a pas de dépendance avec une autre, on la laisse telle quelle. Dans le cas contraire, un registre opérande sera identique avec le registre de destination d'une instruction précédente. Dans ce cas, le registre opérande n'est pas le bon après renommage : on doit le remplacer par le registre de destination de l'instruction avec laquelle il y a dépendance. Cela se fait simplement en utilisant un multiplexeur dont les entrées sont reliées à l'unité de détection des dépendances. On doit faire ce replacement pour chaque registre opérande. [[File:Correction des dépendances sur un processeur superscalaire.png|centre|vignette|upright=2|Correction des dépendances sur un processeur superscalaire.]] ==Les optimisations des processeurs superscalaires larges== Les processeurs superscalaires larges ont des optimisations spécifiques, qui n'ont pas de sens sur les processeurs superscalaires étroits. Dans les grandes lignes, elles se classent en deux types. Les premières permettent de charger/décoder plus de 5-10 instructions simultanément. Le problème est alors que les branchements viennent mettre leur grain de sel et qu'il faut en tenir compte. Les secondes corrigent des problèmes qui apparaissent quand un CPU intègre plus de 5 à 10 unités de calcul. ===L'étape de chargement d'un CPU superscalaire large=== Charger plusieurs instructions pose de nombreux problèmes sur les processeurs superscalaires larges, qui émettent de 5 à 10 instructions simultanées. Pour rappel, la stratégie basique pour charger N instructions est de charger un bloc de N instructions consécutives. Les instructions après un branchement ne sont pas décodées ni exécutées, ce qui entraine une petite baisse de performance. Pour un N petit, la perte de performance est mineure. Mais pour un N large, elle devient suffisamment importante pour que la conception du CPU doit alors être repensée de fond en comble. Les analyses statistiques disent qu'il y a environ un branchement tous les 4 à 6 instructions. Un CPU a donc tendance à décoder des paquets de 3 à 5 instructions consécutives, avant qu'un branchement casse la dynamique. Or, cela pose des problèmes pour utiliser plusieurs décodeurs. L'implémentation basique, qui charge N instructions consécutives pour alimenter N décodeurs, fonctionne donc jusqu'à 4/6 décodeurs. Au-delà de 5 instructions, un CPU superscalaire doit être adapté pour gérer les branchements dans les paquets d'instruction qu'il émet. Le nombre de 5 instructions ne sort donc pas de nulle part. La première solution utilise un cache de µops, avec un ''front-end'' capable de charger/décoder 4/5 instructions à la fois, pas plus. L'idée est que la majorité des instructions proviennent du cache de µops (plus de 80%), ce qui fait qu'on peut émettre environ 10 instructions à partir du cache de µops, pas besoin d'avoir beaucoup de décodeurs. Les performances sont cependant dégradées lors d'un défaut de cache de µops. Les instructions doivent alors être chargées depuis le cache d'instruction, par paquets de 4-5, puis sont décodées par 4-5 décodeurs, ce qui ne permet pas d’alimenter les unités de calcul à plein régime. La solution précédente joue sur la distinction entre pots de décodage et d'émission. Elle permet d'émettre un grand nombre de µops sans pour autant charger un grand nombre d'instructions en même temps. En quelque sorte, ce n'est qu'une méthode de contournement, le CPU superscalaire reste de type étroit. Mais il est aussi possible d'utiliser un '''''front-end large''''', capable de charger une bonne dizaine d'instructions en même temps. La seule difficulté est de tenir compte de la présence de branchements. Pour rappel, avec un ''front-end'' étroit, les instructions situées après le premier branchement pris sont annulées, elles ne sont pas décodées ni exécutées. [[File:Fetch sur un processeur superscalaire avec prediction de branchements.png|centre|vignette|upright=2|Fetch sur un processeur superscalaire avec prédiction de branchements.]] Un ''front-end'' large charge les instructions de destination du branchement et les placent à sa suite. Ils chargent deux blocs à la fois et les fusionnent en un seul qui ne contient que les instructions présumées utiles. [[File:Cache d'instructions autoaligné.png|centre|vignette|upright=2|Cache d'instructions auto-aligné.]] Mais cela demande de charger deux blocs de mémoire en une fois, ce qui demande un cache d'instruction multiports. Il faut aussi ajouter un circuit pour assembler plusieurs morceaux de blocs en un seul : le fusionneur (''merger''). En pratique, cette solution demande d'ajouter un second port de lecture au cache, pour un cout en hardware important, avec un impact négatif sur le temps d'accès au cache. Et il faut rajouter le fusionneur, qui prend un étage de pipeline à lui tout seul. Et encore, cette solution ne gère pas le cas où un bloc contient plusieurs branchements ! [[File:Implémentation d'un cache d'instructions autoaligné.png|centre|vignette|upright=2|Implémentation d'un cache d'instructions auto-aligné.]] Les exemples précédents partent du principe qu'il n'y a qu'un seul branchement dans un bloc. Mais quand les blocs deviennent assez longs, il est fréquent d'avoir plusieurs branchements dans un bloc. Et il est même possible d'avoir plusieurs branchements pris. Dans un bloc de 8-10 instructions, ce n'est pas rare, et les CPU superscalaires à 8-10 voies sont la règle dans les CPU des années 2020. Pour gérer ce cas, il faut ajouter des ports supplémentaires au cache d'instruction et adapter le fusionneur, pour qu'il puisse fusionner trois ou quatre blocs. De plus, il faut utiliser une unité de prédiction de branchement capable de ''prédire plusieurs branchements par cycle''. ===Le décodage superscalaire large=== Le décodage des instructions n'est pas censé dépendre de l'implémentation du chargement. En théorie, une fois plusieurs blocs d'instruction fusionnés, on peut décoder les instructions en parallèle. Cependant, certains processeurs effectuent le décodage en tenant compte de la manière dont les branchements découpent les blocs. Les processeurs Atom d'Intel utilisent une solution de ce type, qui couple prédiction de branchement et décodage parallèle. Ils chargent/décodent des paquets de 3 instructions consécutives, chaque paquet étant séparé du précédent par un branchement. Pour cela, en plus d'avoir un fusionneur adapté, ils regroupent les décodeurs en ''clusters'', chacun regroupant 3 décodeurs, et pouvant décoder trois instructions consécutives. Les micro-architectures Tremont et Crestmont avaient deux ''clusters'' (6 décodeurs au total), la micro-architecture Darkmont en intègre trois (9 décodeurs au total). Avec deux ''clusters'', le fonctionnement est le suivant. Si le code est composé d'une suite d'instruction sans branchements, seul le premier ''cluster'' est utilisé, limitant le décodage à trois instructions par cycle. Par contre, si l'une des trois instructions décodée est un branchement, alors le second ''cluster'' décode les trois instructions situées après ce branchement, à partir de l'adresse de destination. Avec un troisième ''cluster'', c'est la même chose, sauf qu'il faut qu'il y ait un branchement dans les trois instructions décodées par le second ''cluster''. Mais comment faire pour savoir quels décodeurs activés, quels ''clusters'' sont actifs ? C'est la prédiction de branchement qui commande. Avec deux ''clusters'', elle détermine si un branchement est présent dans les trois instructions à charger, et quelle est son adresse de destination. Sans branchement, elle prévient les décodeurs et les trois instructions chargées sont décodées dans un ''cluster'' libre. Si elle prédit un branchement, elle charge les instructions adéquates, et active les deux ''clusters''. Avec trois branchements, c'est le même mécanisme, sauf que l'unité de prédiction de branchement doit être capable de prédire deux branchements par cycle. [[File:Front-end découplé de la microarchitecture Tremont.png|centre|vignette|upright=3|Front-end découplé de la microarchitecture Tremont.]] Il faut noter que les décodeurs d'un ''cluster'' sont des décodeurs simples, sans microcode. Sur les processeurs Tremont et Crestmont, le microcode était unique et était partagé entre tous les ''clusters''. Un seul ''cluster'' pouvait décoder une instruction complexe avec le microcode, l'autre devait se limiter à des instructions simples uniquement. Depuis Skymont, le microcode est partiellement dupliqué, avec un microcode par ''cluster''. Le cout en hardware peut paraitre prohibitif, pour un gain en performance faible. Sauf que c'est oublier que ce sont des processeurs Atom, sur lesquels beaucoup d'instructions sont microcodées. Les processeurs Atom ont un budget en transistor limité, ce qui fait qu'il est préférable pour eux d'implémenter des instructions en microcode que d'utiliser des unités de calcul dédiées ou des circuits de décodage complexes. Pour limiter la casse, le microcode n'est que partiellement dupliqué. Seul le microcode pour les instructions fréquente est dupliqué. Il y a un microcode secondaire pour certaines instructions, qui est lui unique et partagé par tous les ''clusters''. ===Le contournement sur les processeurs superscalaires larges=== Pour rappel, la technique du contournement (''register bypass'') permet au résultat d'une instruction d'être immédiatement utilisable en sortie de l'ALU, avant même d'être enregistré dans les registres. Implémenter la technique du contournement demande d'utiliser des multiplexeurs pour relier la sortie de l'unité de calcul sur son entrée si besoin. Il faut aussi des comparateurs pour détecter des dépendances de données. [[File:Pipeline Bypass.png|centre|vignette|upright=1|Pipeline Bypass]] La sortie de chaque ALU doit être reliée aux entrées de toutes les autres, avec les comparateurs qui vont avec. Sur les processeurs ayant plusieurs d'unités de calculs, cela demande beaucoup d’interconnexions et de comparateurs. Pour N unités de calcul, cela demande 2 * N² interconnexions, implémentées avec 2N multiplexeurs de N entrées chacun. Si c'est faisable pour 2 ou 3 ALUs, la solution est impraticable au-delà. Non seulement ce serait un enfer à câbler, mais les fils seraient tellement longs que la fréquence du processeur en prendrait un coup. Notez que cela vaut pour les processeurs superscalaires, mais aussi pour tout processeur avec beaucoup d'unités de calcul. En théorie, un CPU à exécution dans le désordre, non-superscalaire, mais avec beaucoup d'unités de calcul, fait face au même problème. En pratique, avoir une dizaine d'ALU implique processeur superscalaire à exécution dans le désordre. D'où le fait qu'on parle du problème maintenant. La seule solution praticable est de ne pas relier toutes les unités de calcul ensemble. À la place, on préfère regrouper les unités de calcul dans différents '''agglomérats''' ('''cluster'''). Le contournement est alors possible entre les unités d'un même agglomérat, mais pas entre agglomérats différents. Évidemment, certaines possibilités de contournement sont perdues, mais c'est compensé par un gain en fréquence et un cout en circuit/fils réduit. C'est un bon compromis, ce qui explique que presque tous les processeurs modernes l'utilisent. Les rares exceptions sont les processeurs POWER 4 et POWER 5, qui ont préféré se passer de contournement pour garder un processeur très simple et une fréquence élevée. ===Le banc de registre des processeurs superscalaires larges=== Pour émettre deux opérations entières simultanément, il faut lire deux fois plus d'opérandes. Et il faut aussi écrire deux résultats dans les registres, en même temps. Pour cela, on double les ports du banc de registre. En général, il faut au maximum 2 ports de lecture et un port d'écriture par unité de calcul. Le problème, c'est que plus un banc de registres a de ports, plus il utilise de circuits, est compliqué à concevoir, consomme de courant et chauffe. Avec plusieurs dizaines d'unités de calcul différentes, ajouter autant de ports impacterait la fréquence du banc de registres et réduirait les performances, voire est totalement impraticable à cause des contraintes thermiques. Les processeurs superscalaires larges doivent donc trouver des solutions. La première solution utilise un banc de registre unique, mais n'utilise pas autant de ports que le pire des cas le demanderait. Le processeur détecte quand il n'y a pas assez de ports pour servir toutes les micro-opérations. Quand ça arrive, l'unité d'émission émet assez de micro-opérations pour exploiter les ports disponibles, mais met en attente les micro-opérations en trop, le temps que les ports se libèrent. Pour cela, le banc de registre est géré par un circuit d'arbitrage spécialisé, intégré à l'unité d'émission, l’'''arbitre du banc de registres''' (''register file arbiter''). Une autre solution est de dupliquer le banc de registres en plusieurs exemplaires qui contiennent exactement les mêmes données, mais avec moins de ports de lecture/écriture. Un exemple est celui des processeurs POWER, Alpha 21264 et Alpha 21464. Sur ces processeurs, le banc de registre est dupliqué en plusieurs exemplaires, qui contiennent exactement les mêmes données. Les écritures dans les registres sont envoyées à tous les bancs de registres, afin de garantir que leur contenu est identique. Chaque exemplaire a exactement deux ports de lecture. La conception du processeur est simplifiée, que ce soit au niveau du câblage, que de la conception des bancs de registres. Une dernière solution découpe le banc de registres en plusieurs bancs de registres plus petits, avec un réseau d'interconnexions pour échanger des données entre bancs de registres. Dans la plupart des cas, cette séparation est invisible du point de vue de l'assembleur et du langage machine. Le processeur se charge de transférer les données entre bancs de registres suivant les besoins. Sur d'autres processeurs, les transferts de données se font via une instruction spéciale, souvent appelée ''COPY''. [[File:Banc de registres distribué.png|centre|vignette|upright=2|Banc de registres distribué.]] Sur de certains processeurs, un branchement est exécuté par une unité de calcul spécialisée. Or les registres à lire pour déterminer l'adresse de destination du branchement ne sont pas forcément dans le même agglomérat que cette unité de calcul. Pour éviter cela, certains processeurs disposent d'une unité de calcul des branchements dans chaque agglomérat. Dans les cas où plusieurs unités veulent modifier le ''program counter'' en même temps, un système de contrôle général décide quelle unité a la priorité sur les autres. Mais d'autres processeurs fonctionnent autrement : seul un agglomérat possède une unité de branchement, qui peut recevoir des résultats de tests de toutes les autres unités de calcul, quel que soit l’agglomérat. ==La macro-fusion : une optimisation du décodage parallèle== Les processeurs superscalaires supportent la technique dite de '''macro-fusion''', qui permet de fusionner deux-trois instructions consécutives en une seule micro-opération. Par exemple, il est possible fusionner une instruction de test et une instruction de saut en une seule micro-opération de branchement. Il s'agit là de l'utilisation la plus importante de la macro-fusion sur les processeurs x86 modernes. La macro-fusion est utilisée pour fusionner un test et un saut en un branchement unique. L'optimisation est présente sur la plupart des CPU superscalaires modernes. Les CPU x86 l'implémentent, mais aussi quelques CPU ARM et les processeurs Apple de série M (M1 à M5, et potentiellement plus quand ils seront sortis). La fusion des instructions se fait lors du décodage des instructions, grâce à la coopération des décodeurs. Elle marche systématiquement si l'instruction de test et le saut sont consécutives, qu'elles forment bien une paire d'instruction. Par contre, insérer une instruction entre les deux empêche la macro-fusion de faire son travail, sauf si l'instruction insérée est un NOP. Les processeurs ARM64 avaient une forme spécifique de macro-fusion, utilisée pour un cas très précis : charger une constante immédiate de 32 ou 64 bits, dans un registre 64 bits. Les CPU ARM 64 bits utilisent des instructions codées sur 32 bits, qui ne peuvent encoder que des constantes immédiates de 16 bits. Pour charger une constante de 32/64 bits, il faut s'y prendre en plusieurs fois. Une première instruction MOVZ charge les 16 premiers bits, puis 2 à 4 instructions MOVK remplissent le reste. MOVZ met à zéro les 48 bits de poids fort, MOVK permet de sélectionner le doublet à modifier dans le registre (on modifie 16 bits, dont on choisit la place, le reste du registre est laissé tel quel). ARM permet de fusionner cette suite d'instructions en une seule µop MOV avec une constante immédiate. On parle alors de '''''MOVZ + MOVK fusion'''''. Une dernière utilisation, [https://www2.eecs.berkeley.edu/Pubs/TechRpts/2016/EECS-2016-130.pdf proposées pour le jeu d'instruction RISC-V], fusionnait un calcul d'adresse et une instruction LOAD/STORE en une seule instruction d'accès mémoire. Elle a été envisagée à une époque où le jeu d'instruction RISC-V ne gérait pas les modes d'adressage base + indice. L'idée était d'avoir une unité mémoire qui gérait le mode d'adressage base + indice et de fusionner des instructions pour l'exploiter. Mais de nos jours, le jeu d'instruction RISC-V intègre le mode d'adressage base + indice, ce qui fait que la macro-fusion n'a aucun intérêt pour ce cas précis. La macro-fusion a de nombreuses limitations en pratique. En théorie, on pourrait l'utiliser au-delà des deux situations mentionnées plus haut. Par exemple, pour fusionner une addition et une multiplication en une seule instruction MAD. Mais l'intérêt est assez faible. Notons que la macro-fusion ne permet que de fusionner des paires d'instructions. Aller au-delà demanderait un cout en circuit trop important. Déjà que tester deux paires utilise pas mal de comparateurs... ==Le ''stack engine'' : une optimisation de la pile d'appel== Les processeurs modernes intègrent une optimisation liée au pointeur de pile. Pour rappel, sur les architectures modernes, le pointeur de pile est un registre utilisé pour gérer la pile d'appel, précisément pour savoir où se trouve le sommet de la pile. Il est manipulé par les instructions CALL, RET, PUSH et POP, mais aussi par les instructions d'addition/soustraction pour gérer des cadres de pile de taille variable. De plus, il peut servir d'opérande pour des instructions LOAD/STORE, afin de lire/écrire des variables locales, les arguments d'une fonction, et autres. C'est donc un registre général adressable, intégré au banc de registre, altéré par l'unité de calcul entière. L'incrémentation/décrémentation du pointeur de pile passe donc par l'unité de calcul, lors des instructions CALL, RET, PUSH et POP. Mais, l'optimisation que nous allons voir permet d'incrémenter/décrémenter le pointeur de pile sans passer par l'ALU, ou presque. L'idée est de s'inspirer des architectures avec une pile d'adresse de retour, qui intègrent le pointeur de pile dans le séquenceur et l'incrémentent avec un incrémenteur dédié. ===Le ''stack engine''=== L'optimisation que nous allons voir utilise un '''''stack engine''''' intégré à l'unité de contrôle, au séquenceur. Le processeur contient toujours un pointeur de pile dans le banc de registre, cela ne change pas. Par contre, il n'est pas incrémenté/décrémenté à chaque instruction CALL, RET, PUSH, POP. Un compteur intégré au séquenceur est incrémenté à la place, nous l’appellerons le '''compteur delta'''. La vraie valeur du pointeur de pile s'obtient en additionnant le compteur delta avec le registre dans le banc de registre. Précisons que si le compteur delta vaut zéro, la vraie valeur est dans le banc de registre et peut s'utiliser telle quelle. Lorsqu'une instruction ADD/SUB/LOAD/STORE utilise le pointeur de pile comme opérande, elle a besoin de la vraie valeur. Si elle n'est pas dans le banc de registre, le séquenceur déclenche l'addition compteur-registre pour calculer la vraie valeur. Finalement, le banc de registre contient alors la bonne valeur et l'instruction peut s'exécuter sans encombre. L'idée est que le pointeur de pile est généralement altéré par une série d'instruction PUSH/POP consécutives, puis des instructions LOAD/STORE/ADD/SUB utilisent le pointeur de pile final comme opérande. En clair, une bonne partie des incrémentations/décrémentation est accumulée dans le compteur delta, puis la vraie valeur est calculée une fois pour toutes et est utilisée comme opérande. On accumule un delta dans le compteur delta, et ce compteur delta est additionné quand nécessaire. Précisons que le compteur delta est placé juste après le décodeur d'instruction, avant même le cache de micro-opération, l'unité de renommage et l'unité d'émission. Ainsi, les incrémentations/décrémentations du pointeur de pile disparaissent dès l'unité de décodage. Elles ne prennent pas de place dans le cache de micro-opération, ni dans la fenêtre d'instruction, ni dans la suite du pipeline. De nombreuses ressources sont économisées dans le ''front-end''. Mais utiliser un ''stack engine'' a aussi de nombreux avantages au niveau du chemin de données/''back-end''. Déjà, sur les processeurs à exécution dans le désordre, cela libère une unité de calcul qui peut être utilisée pour faire d'autres calculs. Ensuite, le compteur delta mémorise un delta assez court, de 8 bits sur le processeur Pentium M, un peu plus pour les suivants. L'incrémentation se fait donc via un incrémenteur 8 bits, pas une grosse ALU 32/64 bits. Il y a un gain en termes de consommation d'énergie, un incrémenteur 8 bits étant moins gourmand qu'une grosse ALU 32/64 bits. ===Les points de synchronisation du delta=== La technique ne fonctionne que si la vraie valeur du pointeur de pile est calculée au bon moment, avant chaque utilisation pertinente. Il y a donc des '''points de synchronisation''' qui forcent le calcul de la vraie valeur. Plus haut, nous avions dit que c'était à chaque fois qu'une instruction adresse le pointeur de pile explicitement, qui l'utilise comme opérande. Les instructions CALL, RET, PUSH et POP ne sont pas concernées par elles utilisent le pointeur de pile de manière implicite et ne font que l'incrémenter/décrémenter. Mais dans les faits, c'est plus compliqué. D'autres situations peuvent forcer une synchronisation, notamment un débordement du compteur delta. Le compteur delta est généralement un compteur de 8 bits, ce qui fait qu'il peut déborder. En cas de débordement du compteur, le séquenceur déclenche le calcul de la vraie valeur, puis réinitialise le compteur delta. La vraie valeur est donc calculée en avance dans ce cas précis. Précisons qu'un compteur delta de 8 bits permet de gérer environ 30 instructions PUSH/POP consécutives, ce qui rend les débordements de compteur delta assez peu fréquent. À noter que si le compteur delta vaut zéro, il n'y a pas besoin de calculer la vraie valeur, le séquenceur prend cette situation en compte. Un autre point de synchronisation est celui des interruptions et exceptions matérielles. Il faut que le compteur delta soit sauvegardé lors d'une interruption et restauré quand elle se termine. Idem lors d'une commutation de contexte, quand on passe d'un programme à un autre. Pour cela, le processeur peut déclencher le calcul de la vraie valeur lors d'une interruption, avant de sauvegarder les registres. Pour cela, le processeur intègre un mécanisme de sauvegarde automatique, qui mémorise la valeur de ce compteur dans le tampon de réordonnancement, pour forcer le calcul de la vraie valeur en cas de problème. La technique du ''stack engine'' est apparue sur les processeurs Pentium M d'Intel et les processeurs K10 d'AMD, et a été conservée sur tous les modèles ultérieurs. L'implémentation est cependant différente selon les processeurs, bien qu'on n'en connaisse pas les détails et que l'on doive se contenter des résultats de micro-benchmarks et des détails fournit par Intel et AMD. Selon certaines sources, dont les manuels d'optimisation d'Agner Fog, les processeurs AMD auraient moins de points de synchronisation que les processeurs Intel. De plus, leur ''stack engine'' serait placé plus loin que prévu dans le pipeline, après la file de micro-opération. ==La micro-fusion et la délamination== La '''micro-fusion''' est une optimisation qui retarde le décodage réel de certaines instructions assez loin dans le pipeline. Elle concerne surtout les instructions ''load-op'', mais pas que. D'autres instructions mémoire peuvent subir cette optimisation. L'essentiel est que, sans micro-fusion, ces instructions sont décodées en plusieurs micro-opérations. La micro-fusion retarde le décodage final de ces instructions, qui se fait assez tard dans le pipeline. Pour comprendre l'intérêt, nous allons devoir faire quelques explications. L'optimisation en question fait le décodage en deux temps. Prenons l'exemple d'une opération ''load-op'', qui est censée être décodée en deux micro-opérations : une lecture, puis une opération. Le décodage produit une '''macro-opération''' (terme d'Intel), qui est propagée dans le pipeline, pour être scindée en deux micro-opérations un peu avant les ALU et l'unité mémoire. La macro-opération est techniquement une micro-opération comme une autre, sauf que ce n'est pas la micro-opération finale. L'unité d'émission découpe cette macro-opération en deux micro-opérations, qui sont émises l'une après l'autre. Pour résumer, les instructions ''load-op'' ne sont complétement découpées en micro-opération lors de l'émission, pas lors du décodage. L'optimisation impacte ce qui se situe entre le décodeur d'instruction et l'unité d'émission : l'unité de renommage, la file de micro-opérations, le ''Loop Stream Detector'' et/ou le cache de micro-opération. L'intérêt de l'optimisation est que l'on fusionne deux micro-opérations en une seule macro-opération. Le cache de micro-opération et la file de micro-opération peuvent mémoriser plus de micro-opérations, vu que certaines sont fusionnées. Quant à l'unité de renommage, elle renomme une seule macro-opération au lieu de renommer deux micro-opérations, ce qui augmente le débit du renommage de registre. Par contre, cela complique un peu le travail de l'unité d'émission, qui doit découper les instructions ''load-op'' en deux et émettre les micro-opérations l'une après l'autre. Il faut noter qu'il n'y a pas de fusion proprement dite. Le décodeur ne décode pas deux micro-opérations séparées, avant de les fusionner. En réalité, il génère directement une macro-opération, qui correspond à deux micro-opérations, que ce soit plus tard dans le pipeline ou sur une autre architecture. D'ailleurs, la micro-fusion a lieu à l'intérieur d'une instruction, qui est censée être traduite en plusieurs micro-opérations. Et encore : pas toutes. La conséquence est que la technique n'a de sens que sur les processeurs CISC, avec des instructions assez complexes pour être décodées en plusieurs micro-opérations. En pratique, seuls les CPU x86 sont concernés. ===Les domaines de fusion=== La micro-fusion n'est pas spécifique aux processeurs superscalaires. En théorie, on peut l'implémenter sur un processeur non-superscalaire à émission dans l'ordre. Cependant, je ne connais aucun processeur à émission dans l'ordre qui implémente la micro-fusion, même si son implémentation est en théorie possible sur de tels processeurs. La micro-fusion est implémentée différemment selon que l'émission se fasse dans l'ordre, dans le désordre, avec une fenêtre d'instruction, avec des stations de réservation, etc. J'ai dit plus haut que les micro-opérations sont générées lors de l'émission, mais le moment exact varie suivant le processeur. Pour simplifier le tout, nous parlerons de '''scission''' quand le processeur traduit une macro-opération en deux/trois micro-opérations. Le moment où a lieu la scission est théoriquement dans l'unité d'émission, mais celle-ci prend plusieurs formes selon que le processeur utilise l'émission dans l'ordre, dans le désordre, avec une fenêtre d'instruction, avec des stations de réservation, etc. Les processeurs à exécution dans l'ordre sont le cas le plus simple. L'unité d'émission est alors en charge du découpage des macro-opérations en micro-opérations. La file de micro-opération ou le cache de micro-opérations mémorisent des macro-opérations. À l'opposé, le tampon de ré-ordonnancement mémorise lui des micro-opérations. Le reste du processeur n'est pas affecté. Sur les processeurs à exécution dans le désordre, les différences sont nombreuses. Le tampon de ré-ordonnancement peut mémoriser soit les micro-opérations finales, soit des macro-opérations. Il en est de même avec la fenêtre d'instruction et/ou les stations de réservation, qu'elles soient centralisées ou décentralisées. Tout dépend de comment se fait l'implémentation. Une implémentation simple effectue la scission des macro-opérations dans l'unité d'émission, comme sur les processeurs à exécution dans l'ordre. Sur de nombreux processeurs, l'unité d'émission et de renommage sont simplement fusionnées, ce qui fait que la scission a lieu juste après le renommage de registres. En conséquence, le tampon de re-ordonnancement et les fenêtres d'instruction ne voient que des micro-opérations. Les macro-opérations disparaissent juste avant. Cette implémentation est préférée avec une fenêtre d'instruction centralisée, car on voit mal comment scinder une macro-opération juste avant l'ALU. Une autre implémentation fait la scission en sortie de la fenêtre d'instruction ou des stations de réservation, qu'elles soient centralisées ou décentralisées. Dans ce cas, le tampon de re-ordonnancement fait de même. L'avantage est que le tampon de ré-ordonnancement stocke des macro-opérations, ce qui augmente sa taille effective. Par exemple, il utilise une seule entrée pour une instruction ''load-op'', au lieu de deux sans micro-fusion de ce type. ===La délamination=== La scission peut parfois avoir lieu plus tôt, dans des circonstances très précises. Concrètement, cela ne concerne que quelques micro-architectures d'Intel, pour des instructions très précises. La raison est les limitations du format des micro-opérations, pas une histoire d'optimisation. Le processeur aimerait pouvoir faire la micro-fusion, mais ne peut pas à cause de ces limitations. Une telle situation cause alors une '''délamination''' : les micro-opérations sont scindées précocement. Par exemple, sur la micro-architecture SandyBridge d'Intel, les opérations ''load-op'' sont fusionnées, sauf si elles utilisent l'adressage indicé. Les micro-opérations de ce processeur ne peuvent avoir que deux opérandes. Trois opérandes est de trop, et les opérations ''load-op'' en adressage indicé dépassent cette limite. Dans ce cas, les micro-opérations sont fusionnées en sortie du décodeur, mais sont scindés avant d’entrer dans la file de micro-opération. L'avantage n'est pas évident, vu que l'unité de renommage suit de près le décodeur d'instruction. Il est que le cache de micro-opérations mémorise des macro-opérations, pas deux micro-opérations. ===La micro-fusion des processeurs Intel et AMD=== La micro-fusion est apparue sur le Pentium M d'Intel, et a été conservée telle quelle sur les processeurs Intel suivants. Les processeurs AMD supportent la micro-fusion depuis au moins la micro-architecture AMD K8. Mieux que ça, la délamination n'était pas utilisée car les micro-opérations acceptaient plus de 2 opérandes. Que ce soit chez AMD ou Intel, elle concerne deux types d'instructions : les écritures mémoire et les instructions ''load-op''. Sur le Pentium M, il y avait quelques limitations, l'optimisation se limitant par exemple aux registres entiers et flottants, mais pas aux registres MMX, mais pas les registres SSE (nous verrons ces registres dans quelques chapitres). Mais les processeurs modernes n'ont plus cette limitation. La micro-fusion des CPU Intel concerne deux types d'instructions : les écritures mémoire et les instructions ''load-op''. Pour les écritures, la situation est plus complexe que pour les instructions ''load-op''. Sur les processeurs Intel précédents, les écritures étaient réalisées dans deux unités séparées : le calcul d'adresse dans une unité de calcul, l'écriture proprement dite dans l'unité mémoire. Elles prenaient donc deux micro-opérations. Le processeur a changé ses unités mémoire, ce qui fait qu'elle pouvait faire les deux en une seule micro-opération. Il s'agissait alors d'une optimisation du chemin de données, plus que de la micro-fusion proprement dite, mais je la mentionne ici malgré tout. La micro-fusion sur ce processeur avait un avantage en plus des avantages usuels : elle utilisait mieux les décodeurs. Les Pentium M avaient trois décodeurs pour décoder plusieurs instructions en même temps, chose qu'on détaillera dans le chapitre sur les processeurs superscalaires. Un seul décodeur pouvait décoder toutes les instructions, les deux autres ne peuvent décoder que les instructions simples, qui se décodent en une seule micro-opération. Avec la micro-fusion, les trois décodeurs peuvent gérer les écritures mémoire et les opérations ''load-op'', vu qu'elles deviennent des instructions simples. Sans cela, elles auraient été limitées au premier décodeur. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Le parallélisme mémoire | prevText=Le parallélisme mémoire | next=Les microarchitectures pour le x86 : haute performance | nextText=Les microarchitectures pour le x86 : haute performance }} </noinclude> qgzn6cz1dk7jvn5wn8v1w19o5rklidq 773585 773584 2026-09-29T16:55:33Z Mewtow 31375 /* L'exemple du PA-RISC PA 8000 */ 773585 wikitext text/x-wiki Les processeurs vus auparavant ne peuvent émettre au maximum qu'une instruction par cycle d'horloge. Ils peuvent avoir plusieurs instructions qui s'exécutent en même temps, dans des unités de calcul séparées. C'est le cas dès qu'une instruction multi-cycles s'exécute. Par contre, ils ne peuvent démarrer qu'une seule instruction par cycle. Et quand on court après la performance, ce n'est pas assez ! Les concepteurs de processeurs ont inventés des processeurs qui émettent plusieurs instructions par cycle : les '''processeurs à émissions multiples'''. Un processeur à émission multiple charge plusieurs instructions en même temps, les décode en parallèle, puis les émet en même temps sur des unités de calculs séparées. Pour cela, il faut gérer les dépendances entre instructions, répartir les instructions sur différentes unités de calcul, et cela n'est pas une mince affaire. En général, pour un processeur à émission multiple capable d'émettre N instructions en parallèle, on parle de '''processeur à N voies''', ou encore un ''processeur à N pipelines''. [[File:Superscalarpipeline.svg|centre|vignette|upright=1.5|Pipeline RISC classique à cinq étages sur un processeur superscalaire. On voit bien que plusieurs instructions sont chargées en même temps.]] Les processeurs à émission multiple sont de deux types : les processeurs VLIW et les '''processeurs superscalaires'''. Nous mettons les processeurs VLIW de côté en attendant le prochain chapitre. La raison est qu'ils ont un jeu d'instruction spécialisé qui expose le parallélisme d'instruction directement au niveau du jeu d'instructions, là où les processeurs superscalaires restent des processeurs au jeu d'instruction normal. La différence principale entre processeur VLIW et superscalaire est qu'un processeur superscalaire répartit les instructions sur les unités de calcul à l’exécution, là où un processeur VLIW délègue cette tâche au compilateur. ==Le nombre de voies d'un processeur superscalaire== Les processeurs superscalaires les plus simples ne permettent que d'émettre deux micro-opérations à la fois, d'où leur nom de processeur ''dual issue'', ce qui se traduit en '''processeur à double émission'''. Les processeurs triple émission permettent eux d’émettre trois instructions à la fois. A l'opposé, les CPU superscalaires les plus puissants peuvent émettre jusqu'à 8-10 instructions simultanément. En 2026, les CPU superscalaires peuvent monter jusqu’à 10 µops émises en même temps, ce qui est énorme ! Et cela nous amène à faire une distinction entre les processeurs superscalaires dits '''étroits''' et ceux dits '''larges'''. Dans ce wikilivre, on part du principe que les processeurs superscalaires étroits émettent jusqu'à 4-5 µops à la fois, alors que les larges peuvent en émettre plus, l'intervalle entre les deux est une zone grise. Le nombre exact n'est pas fixé dans le marbre, la distinction est volontairement vague. Nous parlerons de la '''largeur d'un CPU superscalaire''' pour parler du nombre de voies, du nombre de µops émises en même temps. Plus un CPU superscalaire est large, plus il est performant ''toute chose égale par ailleurs''. Mais dans les faits, vous pouvez oublier la partie en italique. Élargir un CPU superscalaire demande de rajouter beaucoup de circuits. Et ce cout en circuit aura un impact sur la performance. A budget en transistors limité, il y a un compromis entre élargir un CPU et rajouter du cache ou la taille des fenêtres d'instructions/ROB et autres. ===Les contraintes d’appariement=== Prenons un processeur double émission, capable d'émettre deux instructions simultanément. Émettre deux instructions en même temps n'est pas toujours possible. Par exemple, si deux instructions sont dépendantes, on ne peut pas les émettre en même temps. Mais oublions un instant ces histoires de dépendances de données, et partons du principe que le CPU ait affaire à deux instructions indépendantes, une paire idéale. Un CPU double émission "parfait" pourrait exécuter n'importe quelle paire d'instruction. Par exemple, il pourrait émettre deux multiplications consécutives, deux lectures consécutives, une lecture et une écriture en même temps, etc. En pratique, aucun processeur ne permet cela. Implémenter un CPU superscalaire "parfait" aurait un cout en circuit beaucoup trop conséquent. Par exemple, pour émettre deux multiplications en même temps, il faudrait deux multiplieurs séparés. Idem pour exécuter deux accès mémoire simultané : cela demande d'avoir deux unités mémoire et un cache multiport. Mais en pratique, aucun CPU superscalaire ne fait cela. La totalité des CPU double émission se débrouille avec un seul circuit multiplieur et une seule unité mémoire. Et cela entraine l'apparition de dépendances structurelles, qui font que certaines paires d'instructions sont impossibles. Par exemple, impossible d'émettre deux multiplications en même temps avec un seul circuit multiplieur. Mais émettre une multiplication en parallèle d'une addition est parfaitement possible. Il y a donc des paires d'instructions autorisées et des paires interdites. Et la logique est la même sur les CPU à triple ou quadruple émission, et au-delà. : des triplets ou quadruplet d'instructions sont impossibles à émettre simultanément, alors que d'autres le sont. Pour le dire autrement, il y a des '''contraintes d'appariement''' sur les instructions à émettre en même temps. ===L'impact des contraintes d’appariement sur la performance=== Ces contraintes d’appariement ont un impact sur les performance, mais celui-ci peut être grandement mitigé. Les programmes informatiques utilisent en pratique beaucoup plus d'opérations entières de base que de multiplication, branchements et accès mémoire. Il y a environ 5 opérations entières de base pour une multiplication entière. En pratique, il est rare de devoir exécuter deux multiplications à la fois. Idem pour les décalages et rotations, qui sont assez éloignés les uns des autres. Deux branchements consécutifs sont quant à eux plus fréquents. Deux accès mémoire consécutifs est assez rare, mais ils restent assez proches les uns des autres malgré tout. La conséquence est que certaines paires d'instructions sont privilégiées par rapport au reste. Les paires regroupant deux calculs basiques (additions, soustractions, ...) sont systématiquement supportées, car dupliquer des ALU entières est facile. Les paires regroupant un calcul et une autre instruction sont elles aussi systématiquement supportées. Par contre, les paires avec deux branchements, deux accès mémoire, deux décalages/rotations, ou deux multiplications/divisions sont fréquemment interdites. Seuls les CPU superscalaires larges peuvent les permettre, et encore : sous conditions. Le résultat est que le processeur peut se débrouiller avec une seule unité mémoire et une unité de branchement. ===Terminologie pour la suite du chapitre=== Décrire les contraintes d’appariement demande de dire quelles combinaisons d’instructions sont autorisées ou interdites. Et pour cela, nous allons introduire les abréviations suivantes : * INT est un raccourcis pour parler d'une opération entière simple, qu'une ALU entière peut exécuter. * MUL correspond à une opération entière complexe, typiquement une multiplication, éventuellement à une division. * FLOAT désigne une opération flottante, peut importe laquelle. * MEM désigne un accès mémoire, à savoir une instruction ou µop mémoire. * BRANCH désigne une instruction de branchement. Cette terminologie permettra de définir des paires d'instructions, qu'elles soient possibles ou interdites. Par exemple, l'expression INT + FLOAT désigne une paire d'instruction regroupant une instruction entière et une instruction flottante, peu importe l'ordre des deux instructions. Il en sera de même pour les triplets, quadruplets, ou plus. Par exemple, l'expression INT + INT + FLOAT + MUL désigne un quadruplet d'instructions regroupant : deux instructions entières, une instruction flottante, et une multiplication entière. J'utiliserais aussi des parenthèses pour regrouper certaines combinaisons. Par exemple, l'expression INT + (MUL /FLOAT) veut parler d'une paire d'instruction où la première est une opération entière basique, la seconde est : soit une multiplication, soit une opération flottante. ==Le ''front-end'' des processeurs superscalaires== Un processeur superscalaire doit charger, décoder, et exécuter plusieurs instructions par cycle. Par exemple, un processeur triple émission doit charger 3 instructions lors d'un premier cycle, puis les décoder au cycle suivant, et les exécuter au cycle suivant. Il travaille donc pas paquets de 3 instructions, dans cet exemple. Intuitivement, charger, décoder et exécuter plusieurs instructions à la fois demande de dupliquer des circuits. Par exemple, il faut dupliquer les décodeurs pour décoder plusieurs instructions. Les unités de calcul sont aussi dupliquées, sauf sur certaines processeurs qui arrivent à ruser, mais laissons cela de côté pour plus tard. Mais d'autres circuits sont simplement modifiés, comme l'unité de chargement ou l'unité d'émission. Voyons ce qu'il en est dans le détail. {|class="wikitable" |- ! rowspan="2" | Processeur sans émission multiple | rowspan="2" | Chargement | rowspan="2" | Décodage | rowspan="2" | Renommage | rowspan="2" | Émission | Exécution / ALU | rowspan="2" | ''Commit''/ROB |- | Exécution / ALU |- ! rowspan="4" | Processeur superscalaire | rowspan="4" | Chargement | rowspan="2" | Décodage | rowspan="4" | Renommage | rowspan="4" | Émission | Exécution / ALU | rowspan="4" | ''Commit''/ROB |- | Exécution / ALU |- | rowspan="2" | Décodage | Exécution / ALU |- | Exécution / ALU |} Nous allons d'abord voir ce qu'il en est pour le ''front-end'', à savoir la partie du CPU qui s'occupe de charger et décoder les instructions. Elle regroupe l'unité de chargement, les décodeurs, l'unité de prédiction de branchement, la file de µops, la file d'instruction, et divers caches. En soi, les changements portent surtout sur l'unité de chargement et les décodeurs. ===Le chargement de plusieurs instructions consécutives=== Un processeur superscalaire charge plusieurs instructions en même temps, ''en tenant compte de la présence de branchements''. La partie en italique est importante et elle a une conséquence très forte : la manière de faire est fortement différente entre un CPU superscalaire étroit et large. Un CPU superscalaire étroit fait au plus simple : il charge un bloc de 2, 3, 4 instructions consécutives en mémoire RAM. Il faut alors doubler/tripler/quadrupler la taille du bus connecté au cache d'instruction. Par exemple, pour charger quatre instructions de 32 bits chacune, il suffit de lire un bloc de 128 bits dans le cache d'instruction. Un bloc de 8, 16, 32 octets est donc lu depuis le cache et est ensuite découpé en instructions, envoyées chacun à un décodeur. Charger plusieurs instructions consécutives ne marche bien qu'en absence de branchements. La présence de branchements casse cette dynamique, et il faut gérer leur présence. * Sans prédiction de branchement, toutes les instructions d'un bloc sont décodées et exécutées en même temps, même s'il y a un branchement dans le tas. * Avec prédiction de branchement, les instructions situées après le branchement ne sont pas décodées ni exécutées. L'unité de chargement coupe le bloc chargé au niveau du premier branchement pris, remplit les vides avec des NOP, avant d'envoyer le tout à l'unité de décodage. Les instructions à l'adresse de destination seront chargées au cycle suivant, en chargeant un nouveau bloc. [[File:Fetch sur un processeur superscalaire avec prediction de branchements.png|centre|vignette|upright=2|Fetch sur un processeur superscalaire avec prédiction de branchements.]] Un autre défaut est que sur le CPU charge un bloc de 128 bits à la fois, les instructions doivent être alignées sur 128 bits. Et on peut généraliser à n'importe quelle taille de bloc. Si les instructions ne sont pas alignées, il faut gérer la situation. Il arrive qu'une instruction soit à cheval sur deux blocs, avec un morceau dans le premier bloc, un autre dans le second. Dans ce cas, l'instruction est chargée en deux fois, et des circuits doivent gérer la situation pour recoller les morceaux. Sur les CPU avec des instructions de taille fixe, le problème ne survient que rarement. Mais il est fréquent avec des instructions de taille variable. Un autre défaut est lié aux branchements. Imaginez qu'un branchement s'exécute et branche vers une instruction de destination. Rien n'indique que l'instruction de destination sera au tout début d'un bloc. Si ça se trouve, elle sera en troisième position d'un bloc de 4 instructions. Une solution simple charge le bloc en respectant l'alignement, et les deux premières instructions du bloc ne sont pas à exécuter. Il y a donc une petite perte de performance. Certains CPU, comme l'IBM RS/6000, ont la machinerie charger un bloc de N instructions même s'il n'est pas aligné. La machinerie en question se trouve dans le cache d'instruction et est tout sauf simple à expliquer,ce qui fait que je me permets de la passer sous silence. Un détail, cependant : elle ne permet pas de charger des blocs qui sont à cheval sur deux lignes de cache. ===Le décodage parallèle des instructions=== Pour le décodage des instructions, plusieurs instructions sont décodées en même temps. On parle alors de '''décodage parallèle'''. Pour ce faire, un processeur superscalaire contient plusieurs décodeurs, chacun pouvant décoder une instruction en parallèle des autres. Prenons par exemple un processeur superscalaire à 4 voies : le décodage se fera dans quatre décodeurs séparés, qui fonctionneront en parallèle. Cependant, cette implémentation ne marche bien que pour les processeurs RISC, les processeurs CISC devant faire avec un microcode gourmand en circuits. Les processeurs CISC utilisent des décodeurs hybrides, avec un microcode qui complémente un décodeur câblé. Dupliquer le microcode aurait un cout en transistors trop important, ce qui fait que seuls les décodeurs câblés sont dupliqués. Les CPU CISC superscalaires disposent donc de plusieurs décodeurs simples, capables de décoder les instructions les plus courantes, avec un seul microcode. La conséquence est qu'il n'est pas possible de décoder deux instructions microcodées en même temps. Par contre, il reste possible de décoder plusieurs instructions non-microcodées ou une instruction microcodée couplée à une instruction non-microcodée. Vu qu'il est rare que deux instructions microcodées se suivent dans un programme, le cout en performance est extrêmement mineur. Il faut noter qu'une instruction correspond à une ou plusieurs µops. Il est donc possible de charger 5 instructions et de se retrouver avec 8 µops en sortie des décodeurs. Et c'est la source d'une distinction très importante. Plus haut, j'ai parlé de processeurs superscalaires à N voies. La terminologie peut avoir deux interprétations. La première est que le processeur charge/décode N instructions à la fois. Une seconde est qu'il est capable d'exécuter/émettre N µops en même temps. Les deux ne sont pas équivalentes, vu qu'un processeur superscalaire peut, par exemple, charger/décoder N instructions et émettre/exécuter N+2 µops. La distinction est particulièrement importante sur les processeurs superscalaires larges. Certains d'entre eux sont capables de charger 5 instructions et d'en émettre le double ! Un exemple classique était les processeurs Athlon d'AMD, qui pouvaient décoder deux instructions par cycle, mais émettre 4 µops par cycle. Ce n'était pas un problème, car beaucoup d'instructions, même basiques, étaient décodées en 2 µops. ===L'émission parallèle des instructions=== La superscalarité modifie en profondeur l'unité d'émission, notamment au niveau de son interface. Avant, elle recevait une micro-opération sur son entrée, et fournissait la micro-opération émise sur une sortie. Et cela vaut aussi bien pour une unité d'émission simple, un ''scoreboard'', une fenêtre d'instruction ou des stations de réservation. Mais avec l'émission multiple, les sorties et entrées sont dupliquées. Pour la double émission, il y a deux entrées vu qu'elle doit recevoir deux micro-opération décodées/renommées, et deux sorties pour émettre deux micro-opérations. Dans ce qui suit, nous ne parlerons pas d'entrée et de sortie, mais de '''ports de décodage''' et de '''ports d'émission'''. Les ports de décodage reçoivent des micro-opérations provenant de l'unité de décodage, les ports d'émissions sont pour les micro-opérations émises. Les ports d'émission injectent les micro-opérations émises dans le pipeline, elle sont propagée au banc de registre, aux ALUs, etc. Un processeur superscalaire a forcément plusieurs ports d'émission (et de décodage). Si l'interface de l'unité d'émission change, l'intérieur est tout autant modifié. Sur un CPU non-superscalaire, l'unité d'émission reçoit une µop "candidate à l'émission", et détecte les dépendances entre avec les µops en vol, en cours d'exécution dans le pipeline. Et c'est toujours le cas sur les processeurs superscalaires : l'unité d'émission détecte les dépendances entre les µops candidates et les µops en vol. Mais avec la siperscalarité, elle doit en plus tester les dépendances entre les µops candidates. Si l'unité d'émission est un ''scoreboard'', il doit détecter les dépendances entre instructions émises simultanément et les sérialiser si besoin. Avec une fenêtre d'instruction, il n'y a pour ainsi dire rien à faire, vu que les dépendances sont éliminées par le renommage de registre et que les signaux de réveil gèrent les dépendances RAW. C'est la raison pour laquelle les processeurs superscalaires modernes n'utilisent pas de ''scoreboard''. ==Les processeurs implémentés avec plusieurs pipelines== Nous venons de voir comment la superscalarité impacte le ''front-end'', il est maintenant de voir ce qu'il en est de l'unité d'émission et des ''back-ends''. Un processeur superscalaire peut utiliser l'exécution dans le désordre et le renommage de registres, mais ce n'est pas une obligation. Historiquement, les premiers processeurs superscalaires n'utilisaient pas d'exécution dans le désordre. Le meilleur exemple est celui du Pentium 1 et 2 d'Intel. Ils étaient tous deux des processeurs superscalaires, mais n'avaient pas d'exécution dans le désordre, qui est apparue sur le Pentium 3. les explications sont plus simples si on met de côté l'exécution dans le désordre. Vous vous dites que l'implémentation d'un processeur superscalaire n'est pas la même suivant que le CPU utilise l'exécution dans le désordre, ou non. Mais dans les faits, la distinction est plus subtile que ca. Pour l'expliquer, je vais utiliser une classification originale, qui sépare les processeurs superscalaires en trois sous-types. La distinction se fait sur la manière dont la superscalarité est implémentée en matériel.La classification que j'utilise distingue : * Les processeurs avec plusieurs pipelines, sans exécution dans le désordre. * Les processeurs superscalaires avec un pipeline dynamique. * Les processeurs avec des fenêtres d'instruction décentralisées. La distinction n'est pas qu'une question d'implémentation matérielle. Elle impacte aussi le ratio entre instructions chargées/décodées et instructions émises. Vous vous dites que les deux sont égales, mais ce n'est le cas que sur les processeurs avec N pipelines ! Sur les autres processeurs, il est possible de décoder 4 instructions, mais d'en émettre maximum 6 par cycle ! Et sur les CPU avec des fenêtres d'instruction décentralisées, il y a aussi une différence entre le nombre d'instructions qui sont ''dispatch'' et ''schedule''. La catégorie la plus simple est celle des '''processeurs avec plusieurs pipelines'''. Ce sont des processeurs superscalaires sans exécution dans le désordre. Ils partent d'un processeur non-superscalaire, et ajoutent un second pipeline, en sortie de l'unité d'émission. Le second pipeline permet l'émission parallèle d'une seconde instruction. Le second pipeline n'est pas identique au pipeline originel, sur plusieurs points. Premièrement, il n'a pas exactement les mêmes circuits. Le second pipeline est généralement composé d'une unité de calcul, d'une FPU, éventuellement d'un second banc de registres, guère plus. Il permet d'exécuter une seconde opération de calcul, pas plus, ce qui est à l'origine de contraintes d'appariemment assez fortes. De plus, il n'a pas forcément la même longueur, il peut avoir des étages en moins ou en plus. Il s'agit de la forme la plus simple de processeur superscalaire et nous allons leur consacrer cette section. ===La double émission entière-flottante=== L'exemple le plus simple utilise un second pipeline pour les opérations flottantes, séparé du pipeline originel. L'ajout d'un pipeline flottant permet d'émettre une micro-opération entière en même temps qu'une micro-opération flottante, ce qui s'appelle la '''double émission entière-flottante'''. La micro-opération entière s'exécute dans l'ALU entière, la micro-opération flottante dans la FPU. Les exemples les plus notables sont le PA-RISC 7100, le POWER 1 (RIOS .& et .9) et le PowerPC 601. L'Apollo DN10000 et l'Intel i860 utilisaient aussi cette forme de double émission, mais étaient des prototypes de CPU VLIW. [[File:Double émission entière-flottante.png|centre|vignette|upright=2|Double émission entière-flottante]] Pour bien expliquer les choses, prenons le processeur illustré ci-dessous, avec deux ''back-end'' séparés : un pour la FPU, et un autre pour le reste. Les instructions entières et mémoire passent toutes par le ''back-end'' généraliste. [[File:CPU non-superscalaire basique, avec une FPU.png|centre|vignette|upright=1.5|CPU non-superscalaire basique, avec une FPU]] Les deux ''back-end'' sont des pipelines séparés, mais il faut que l'unité d'émission soit spécialement conçue pour en profiter. Un processeur simple émission peut démarrer une seule µop par cycle : soit la µop est envoyée au ''back-end'' flottant, soit elle est envoyée au ''back-end'' général. Avec la double émission entière-flottante, le processeur peut envoyer une µop dans chaque pipeline, à chaque cycle. Vu que la FPU et son banc de registre forment déjà un pipeline séparé, les seules modifications se font au niveau du ''front-end'', unité d'émission inclue. {| |- |[[File:CPU simple émission avec une FPU.png|centre|vignette|upright=1.5|CPU simple émission avec une FPU.]] |[[File:Double émission entière flottante avec un second pipeline.png|centre|vignette|upright=1.5|CPU avec un second pipeline flottant.]] |} Notez que le terme double émission ''entière''-flottante est un peu trompeur. En réalité, la technique permet d'émettre une instruction flottante avec n'importe quelle autre instruction non-flottante, avec des restrictions pour les branchements. Il est par exemple possible d'exécuter un calcul flottant en parallèle d'un accès mémoire. Sur les CPU 32 bits, il est possible de faire les multiplications dans la FPU. Pour rappel, la FPU contient un multiplieur entier 53-54 bits, pour multiplier les mantisses de deux flottants 64 bits, qu'on peut utiliser pour faire les multiplications entières 32 bits. Cela permet d'émettre une multiplication en même temps qu'une opération entière dans l'ALU. Ainsi, le CPU pouvait émettre deux instructions : une opération entière de base, avec soit une multiplication, soit une opération flottante. En clair, une émission de type INT + (MUL /FLOAT). Par contre, on perd la possibilité d'émettre une multiplication entière avec une opération flottante, mais c'était un compromis qui en valait la peine. Le CPU PA-RISC 7100 implémentait cette optimisation. Il s'agissait d'un CPU double émission entière-flottante, qui utilisait donc un partitionnement assez simple. Le combo partitionnement + reconditionnement permettait ici de gagner en performance, pour un cout en matériel très limité. D’autant plus limité que le jeu d'instruction prévoyait le reconditionnement de la FPU. Les multiplications ne lisaient pas leurs opérandes dans les registres entiers, mais dans les registres flottants. ===La double émission entière=== Une autre possibilité ajoute un second pipeline, capable d'exécuter des opérations entières simples, appelé le pipeline entier. Le processeur supporte alors la '''double émission entière''', à savoir qu'ils peuvent émettre une opération entière en plus d'une autre instruction. L'opération entière en question est une opération simple, comme une addition, une soustraction, une opération bit à bit, une comparaison, etc. Les exemples classiques sont les processeurs Intel i960 et Pentium. L'implémentation était différente entre l'i960 et le Pentium : Le Pentium avait une seconde ALU entière, alors que le i960 rusait. Le Pentium dupliquait l'ALU entière, pour créer un second pipeline entier. Sur le Pentium originel, les contraintes d'appariement étaient assez strictes. Le Pentium avait une FPU, mais ne pouvait pas l'utiliser en double émission. Il lui était impossible d'exécuter une opération flottante en même temps qu'une opération entière (branchements inclus). Le Cyrix 6x86 était une sorte de Pentium produit par l'entreprise Cyrix, avec une microarchitecture différente. Il avait des contraintes d’appariement réduites. Par exemple, il pouvait émettre une opération flottante en parallèle d'une opération entière. Nous détaillerons ces processeurs dans le prochain chapitre, qui porte justement sur les CPU superscalaires x86. [[File:CPU simple et double émission avec un second pipeline entier.png|centre|vignette|upright=2.5|CPU simple et double émission avec un second pipeline entier.]] L'Intel i960 n'avait pas de FPU, juste une ALU entière et une unité mémoire. Il utilisait l'unité mémoire comme une seconde ALU entière limitée. Pour rappel, une unité mémoire contient une AGU, à savoir une ALU spécialisée dans les calculs d'adresse. Elle est capable de faire des additions, soustractions, et quelques décalages limités (des décalages par 2, 4, 8, pas plus). L'Intel i960 ajoutait des connexions entre AGU et banc de registre, afin que celle-ci serve de seconde unité de calcul. L'AGU est déjà reliée aux deux ports de lecture, pour lire les opérandes du calcul d'adresse, il suffit de la connecter sur le port d'écriture. Le processeur peut alors émettre deux instructions/µops entières, sous certaines conditions. [[File:Emission multiple des opérations entières, double émission.png|centre|vignette|upright=2|Émission multiple des opérations entières, double émission.]] ==Les processeurs superscalaires dynamiques== Les processeurs précédents, avec 2 pipelines, avaient une unité d'émission assez simple. Elle avait deux ports de décodage, et deux ports d'émission. Le nombre de ports de décodage et d'émission étaient identiques. Vous vous dites que c'est naturel, et intuitif, que c'est normal pour un processeur superscalaire. Mais en réalité, la majorité des processeurs superscalaires a plus de ports d'émission que de décodage. Expliquer pourquoi va cependant nous demander de parler de comment la superscalarité exploite les unités de calcul. Posons-nous cette question : de combien d'unités un processeur superscalaire a besoin ? Les unités en question ne sont nécessairement des unité de calcul, l'unité mémoire et l'unité de branchement comptent aussi. La réponse dépend du nombre de voies. Si le ''front-end'' charge et décode un paquet de N instructions, exécuter ces N instructions simultanément demandera là aussi au moins N unités de calcul. Notez le terme : ''au moins'', car c'est là tout l'enjeu de cette section. La réponse dépend aussi des contraintes d’appariement. Pour un CPU superscalaire "parfait", sans contraintes d’appariement, toutes les unités doivent être dupliquées, y compris l'unité mémoire. Un processeur à double émission parfaite devrait dupliquer l'ALU entière, le ''barrel shifter'', le circuit multiplieur, la FPU, l'unité mémoire, et l'unité de branchement, ce qui ferait passer de 6 unités à 12. Le cout en circuit est énorme, même pour de la double émission ! Et pour un CPU à N pipelines, le cout en circuit encore plus prohibitif ! En pratique, les processeurs superscalaires qui font ça sont très rares. La majeure partie des processeurs superscalaires utilisent d'autres techniques : le partitionnement, la duplication partielle des ALUs, la duplication des autres unités. ===Le partitionnement des unités fonctionnelles=== Les CPU superscalaires les plus simples ne dupliquent pas leurs unités de calcul, ils se contentent d'exploiter les unités existantes. Et pour expliquer comment, nous allons partir de l'exemple d'un processeur non-superscalaire contient une ALU entière, une FPU, une unité mémoire et une unité de branchement. Les quatre unités peuvent fonctionner en parallèle, à savoir qu'une unité peut exécuter une instruction à elle toute seule, sans interagir avec les autres. Cela suffit pour créer un processeur quadruple émission, qui peut émettre en même temps : une opération entière, une opération flottante, un branchement, un accès mémoire. Le principe marche aussi sur un processeur avec moins de 4 unités, par exemple sans FPU et/ou sans unité de branchement, ou avec au contraire des unités en plus. L'idée générale est d’émettre une µops séparée dans chaque unité fonctionnelle. Utiliser ainsi les unités existantes, pour rendre un CPU superscalaire, s'appelle le '''partitionnement superscalaire'''. Le terme n'est pas beaucoup utilisé en-dehors de quelques vieux articles académiques. Le partitionnement est fortement dépendant du jeu d'instruction, car il demande de bien séparer instructions entières, flottantes, branchements et instructions mémoire. Et autant c'est bien le cas sur les CPU RISC, autant les CPU CISC ne sont pas dans ce cas. Les CPU CISC ont des instructions ''load-op'', qui effectuent une instruction arithmétique et une µop mémoire. Et ces instructions sont très compliquées à implémenter avec le partitionnement. Et au-delà de ça, les CPU CISC ont beaucoup d'instructions qui sont décodées en plusieurs µops, à exécuter dans un ordre bien précis. On peut pas émettre les µops en question simultanément. Le partitionnement a un cout en circuit très limité, pour un gain en performance lui aussi limité. Pour reprendre le CPU de l'exemple précédent, il est rare que l'on ait à exécuter ces quatre instructions en même temps. En pratique, les combinaisons fréquentes sont les combinaisons calcul + accès mémoire, calcul + branchement, calcul entier + calcul flottant. Utiliser une quadruple émission de ce type n'est donc pas une bonne idée, alors que la double émission parait plus adaptée. Et c'est là que la différence entre ports d'émission et de décodage devient intéressante. L'idée est d'avoir une unité d'émission avec deux ports de décodage, et 4 port d'émission (un par unité). Les contraintes d’appariement varient alors suivant le processeur, mais la règle générale est que si deux micro-opérations tombent dans deux unités différentes, on peut les émettre en même temps. En clair, on peut émettre une opération entière avec une opération flottante, une opération entière avec un branchement, un accès mémoire avec un branchement, etc. Et cela rend le partitionnement bien plus intéressant que prévu. Les tout premiers CPU superscalaires étaient des CPU double émission, qui utilisaient le partitionnement avec : une ALU entière, une unité mémoire et une FPU. Nous parlerons de '''partitionnement INT-FLOAT-MEM'''. L'avantage sur la double émission flottante est que les combinaisons INT + MEM et FLOAT + MEM étaient autorisées. L'intérêt était d'émettre une opération en parallèle d'un accès mémoire, ce qui est un doublet d'instruction assez fréquent. Les exemples classiques sont l'HyperSPARC, de l'alpha 21064 et du PowerPC 603. Les contraintes d’appariement variaient grandement suivant le processeur. Le PowerPC 603 implémentait une double émission "parfaite". C'est à dire que toutes les combinaisons possibles à deux instructions étaient possibles, que ce soit INT + FLOAT, INT + MEM, FLOAT + MEM. En plus de cette double émission "parfaite", le CPU utilisait la technique dite de ''branch folding'', qui permettait d'exécuter un branchement sans utiliser d'unité de calcul, ce qui fait qu'il était qualifié de ''CPU 2-way + Branch''. A l'opposé, le processeur alpha 21064 avait pas mal de contraintes d’appariement, à savoir que certaines combinaisons de deux instructions étaient interdites, bien que compatibles avec les unités disponibles. Une des raisons est que le banc de registre n'avait pas assez de ports de lectures, ce qui fait que certaines combinaisons avec une écriture mémoire n'étaient pas permises. Les concepteurs avaient volontairement inséré ces contraintes afin de simplifier le design du processeur. Avant de poursuivre, précisons que la FPU regroupe un additionneur flottant et un multiplieur flottant. Et ce fait peut être exploité pour approfondir le partitionnement. La '''double émission FADD/FMUL''' permet d'émettre une addition flottante en même temps qu'une multiplication flottante. Elle a été utilisée sur les processeurs x86, Alpha et SPARC. Les autres circuits de calcul flottant sont souvent regroupés avec l'additionneur. La division est parfois e même port que le multiplieur flottant, parfois sur celui de l'additionneur (quand elle est microcodée et exécutée en enchainant les soustractions). ===La duplication des ALU entières=== Le partitionnement est une technique élégante, simple, facile à implémenter et au cout en circuits modeste. Mais il faut avouer que cela ne donne pas des CPU superscalaires très efficaces. La raison est que le partitionnement permet d'émettre des paires, triplets, quadruplets de micro-opérations qui sont rares en pratique. Les combinaisons les plus fréquentes en pratique sont des paires/triplets d'opérations entières, souvent des paires/triplets d'additions ou d'opérations entières simples. Il est donc primordial d'émettre plusieurs opérations entières simultanément. Le fait d'émettre et d'exécuter plusieurs opérations entières en même temps s'appelle l''''émission entière multiple'''. Pour exécuter la seconde/troisième opération entière, il faut dupliquer les ALU entières (ou réutiliser l'AGU comme ALU entière comme le fait l'Intel i960). Le processeur doit avoir deux ALU entières pour de la double émission entière, trois pour de triple émission entière, etc. De plus, il faut ajouter des ports au banc de registre, pour lire deux fois plus d'opérandes et décrire deux résultats. Et enfin, il faut rajouter un port d'émission pour pouvoir émettre une micro-opération entière en plus. [[File:Processeur non-superscalaire basique 03.png|centre|vignette|upright=2|Processeur non-superscalaire basique]] La tendance est de multiplier les ALU entières, mais pas le circuit multiplieur. Le cout en transistors est alors grandement réduit, au prix de l'apparition de dépendances structurelles. Le CPU peut émettre deux additions en même temps, ou une addition et une multiplication, mais pas deux multiplications. Il en est de même avec le ''barrel shifter'', qui n'est pas dupliqué. Il est donc possible d'émettre un décalage avec une opération de base, mais pas deux décalages en parallèle. Mais ces contraintes d’appariement ne sont pas un problème, car il est rare de devoir émettre deux multiplications/décalages en même temps. La plupart des programmes sont majoritairement remplis d'additions, avec des multiplications assez rares et des décalages qui le sont encore plus. La moyenne est proche d'une multiplication pour 4/5 additions. Vu que des multiplications consécutives sont très rares, dupliquer le multiplieur est presque inutile. Disposer de plusieurs circuits multiplieurs ou de plusieurs ''barrel shifters'' serait donc un cout en circuits qui ne servirait que rarement et n'en vaut pas la chandelle. Il faut noter que sur les CPU 32 bits, les multiplications peuvent être exécutées dans la FPU ou dans un multiplieur séparé, tout dépend de si le CPU exécute les multiplications dans la FPU ou pas. {|class="wikitable" |- ! Voie d'émission n°1 !! Voie d'émission n°2 !! Voie d'émission n°3 |- | ALU entière || ALU entière || FPU |} Reste à connecter les unités de calcul à l'unité d'émission (indirectement, car il y a des étages de pipeline entre les deux). Une implémentation basique utilisée un port d'émission par unité. Prenons l'exemple d'un CPU superscalaire avec 4 ALU entières, une FPU, et une unité mémoire. Vu qu'il y a 6 unités, cela fait donc 6 ports d'émission. L'exemple historique le plus impressionnant est celui du Motorola 88110, un CPU double émission qui possède 10 unités. Il contient deux ALU entières, un circuit multiplieur, un circuit diviseur, une unité de manipulation de bits, une unité mémoire, un additionneur flottant, et deux unités graphiques pour des calculs impliquant des pixels. Le multiplieur est utilisé à la fois pour les multiplications entières, flottantes et le produit de deux pixels. Idem pour le diviseur, qui sert pour les divisions entières et flottantes. Et chaque unité a son propre port d'émission. La conséquence est que les contraintes d'appariement du Motorola 88110 sont simples : tant que deux µops atterrissent dans des unités séparées, la paire est permise. Il est par exemple possible d'émettre simultanément deux opérations entières simples, vu qu'il y a deux ALU. Par contre, impossible d'émettre simultanément deux multiplications, deux divisions, deux opérations flottantes, deux manipulations de bit, deux accès mémoire, etc. De plus, le partage du multiplieur fait qu'on ne peut pas émettre une multiplication entière avec une multiplication flottante. Idem avec les divisions, vu que le diviseur est aussi partagé. Ce sont les seules contraintes. ===Le partage des ports d'émission=== La présence d'un circuit multiplieur et d'un ''barrel shifter'' pose des problèmes pour le partitionnement. Il est possible d'avoir un port d'émission dédié au multiplieur, et un autre au ''barrel shifter'', qui sont séparés de ceux pour l'ALU entière. Il est alors possible d'émettre une opération entière, une multiplication et un décalage, simultanément. Nous parlerons de '''partitionnement entier''' pour désigner cette possibilité. [[File:Partitionnement superscalaire entier.png|centre|vignette|upright=2|Partitionnement superscalaire entier.]] Le partitionnement entier est cependant très rare, car le gain en performance serait trop faible au regard des couts en circuit. Quelques processeurs historiques l'utilisaient, mais ce n'est plus le cas de nos jours. La raison est que les multiplications et les décalages sont assez rares dans le code, ce qui fait que le port d'émission associés sont sous-utilisés. Et un port d'émission a un cout en circuit assez important. Et c'est sans compter qu'ajouter des ports sur le banc de registres juste pour un multiplier sous-utilisé n'en vaut pas la peine. L'idéal serait de trouver un moyen de réduire le nombre de ports d'émissions, sans réduire le nombre d'unités de calcul. [[File:Emission multiple des opérations entières, implémentation naive.png|vignette|Émission multiple des opérations entières, implémentation naive]] La solution consiste à '''partager les ports d'émission''', à savoir connecter un port d'émission à plusieurs unités de calcul. L'exemple classique est justement lié aux circuits multiplieur et ''barrel shifters''. L'idée est que le multiplieur et le ''barrel shifter'' sont mis sur le même port d'émission qu'une ALU entière. Prenons par exemple le processeur à double émission entière illustré ci-contre. Un port d'émission est relié à une ALU entière seule, et l'autre port d'émission alimente la seconde ALU entière et le multiplieur. La conséquence est que le processeur peut émettre deux opérations entières, dont une multiplication. Si on avait utilisé un port d'émission dédié au multiplieur, il aurait été possible d'émettre deux opérations entières et une multiplication. On perd donc une voie, mais on gagne en flexibilité et on économise des circuits. Notons que ce partage signifie aussi que le multiplieur partage les ports sur le banc de registre, ce qui fait une double économie. [[File:Emission multiple des opérations entières, implémentation courante.png|centre|vignette|upright=1.5|Émission multiple des opérations entières, implémentation courante]] En général, le ''barrel shifter'' et le multiplieur sont placés sur deux voies d'émission séparés, ce qui permet d'émettre un décalage et une multiplication en même temps. Les mettre sur le même port ne le permettrait pas. {|class="wikitable" |- ! Voie d'émission n°1 !! Voie d'émission n°2 !! Voie d'émission n°3 |- | * ALU entière * Multiplieur | * ALU entière * Barrel shifter | FPU |- | * Additions, soustractions, opérations bit à bit, etc. * Multiplication | * Additions, soustractions, opérations bit à bit, etc. * Décalages et rotations | Opération flottante |} Terminons concernant les multiplieurs avec une dernière subtilité. Pour rappel, les processeurs modernes intégrent en réalité deux multiplieurs différents. Le résultat d'une multiplication est très large et prend deux registres. Par exemple, une multiplication de deux opérandes 64 bits donne un résultat sur 128 bits, ce qui ne tient pas dans un registre, mais en prend deux. L'instruction de multiplication classique ne calcule que les 64 bits de poids faible. mais elle est complétée par d'autres instructions de multiplication qui peuvent faire le calcul complet. Pour résoudre le problème, les processeurs modernes intègrent deux instructions de multiplications : une qui calcule les bits de poids faible du résultat, une autre qui calcule les bits de poids fort. Et ces deux instructions sont associées à deux multiplieurs séparés, aux circuits différent. Le multiplieur qui calcule les bits de poids faible du résultat est appelé le ''low multiplier'', l'autre est appelé le ''high multiplier''. Le second multiplieur est souvent placé sur un second port d'émission, différent du premier multiplieur, partagé avec une ALU. L’avantage de mettre les deux multiplieurs sur deux ports d'émission différents est qu'une multiplication complète peut être réalisée en utilisant les deux multiplieurs en parallèle. Les deux sous-multiplications sont émises en même temps, exécutées en même temps. pas besoin d'exécuter l'une puis la seconde, d'où un gain performance appréciable. Nous venons de voir comment partager un port d'émission entre une ALU et un multiplieur. Mais au-delà de cet exemple, le partage des ports d'émission peut appliquer à n'importe quelle unité. Prenons l'exemple d'un CPU superscalaire avec 4 ALU entières, une FPU, et une unité mémoire. Vu qu'il y a 6 unités, cela fait donc 6 ports d'émission. Cependant, il est rare qu'un bloc de 6 instructions contienne exactement 4 opérations entières, une opération flottante, et un accès mémoire. Beaucoup de ports d'émission seraient sous-utilisés. La solution est de partager des ports d'émission, pour passer à la quadruple émission. Le CPU peut alors répartir 4 instructions sur les ports d'émission adéquats, à chaque cycle. Le CPU a donc 4 ports de décodage et 6 ports d'émission. Une implémentation classique permet n'importe quelle combinaison de 4 instructions compatible avec les 6 unités. Par exemple, il devient possible d'émettre simultanément 4 additions, la combinaison 2 * INT + FLOAT + MEM, 3 * INT + MEM, et bien d'autres. L'exemple relie une ALU entière, la FPU et l'unité mémoire sur le même port. Le CPU a alors quatre ports d'émission, qui ne sont pas "identiques". Trois d'entre eux sont reliés à une ALU entière chacun, rien d'autre. Le quatrième est lui relié à une ALU entière, la FPU et l'unité mémoire. On économise alors deux ports d'émission, mais cela entraine l'apparition de contraintes d’appariement. Le CPU peut émettre 3 opérations entières + n'importe quelle autre opération. Mais les autres combinaisons sont interdites. Le CPU peut émettre 6 opérations entières simultanément, grâce à 6 ALU entières. Les accès mémoire ou opérations flottantes ne viennent pas en plus, mais en remplacement des opérations entières. Regrouper plusieurs ALU sur un même port d'émission est donc à l'origine de dépendances structurelles, de nouvelles contraintes d’appariement. Dans certaines situations de '''''port contention''''', on a assez d'ALU pour exécuter N micro-opérations, mais la répartition des ALUs sur les ports l'empêche. Impossible d'émettre deux micro-opérations sur deux ALU si elles sont sur le même port d'émission. On peut réduire les cas de ''port contention'' en répartissant correctement les ALU sur les ports d'émission, mais sans jamais les supprimer complétement. Un exemple est celui du PowerPC 604. Il implémentait la quadruple émission, alors qu'il avait 5 unités de calcul. Mais deux unités partageaient un même port d'émission. Dans le détail, il avait deux ALU entières, un circuit multiplieur/diviseur, une FPU, une unité mémoire. La FPU et le multiplieur étaient sur le même port d'émission. En conséquence, le CPU pouvait émettre seulement les combinaisons INT + INT + MEM + (MUL/FLOAT). : Il est intéressant de voir l'exemple d'un processeur superscalaire parfait, sans contraintes d'appariement, à N voies. Pour cela, on part d'un processeur non-superscalaire, avec M unités de calcul. Un tel processeur peut s'implémenter avec N ports d'émission, chacun relié à M unités de calcul possibles, ce qui fait que les M unités de calcul sont dupliquées en N exemplaires. Si on prend par exemple un CPU non-superscalaire avec une ALU, une FPU, une unité mémoire et une unité de branchement, un port d'émission sera relié à une ALU, une FPU, une unité mémoire et une unité de branchement. ===La duplication des autres unités fonctionnelles=== Dupliquer les ALU entière est une première étape, mais il est aussi possible de dupliquer les autres unités fonctionnelles. Par exemple, il est possible de dupliquer l'unité mémoire ou l'unité de branchement. Reste à voir quelles unités dupliquer, et pourquoi. Précisons que dans ce qui va suivre, nous allons parler de la duplication des unités en général, pas seulement des unités mémoire/branchement. Nous allons continuer de parler de la duplication des ALU entières dans ce qui suit, mais de manière plus générale. Pour un processeur à N voies, il est théoriquement possible de dupliquer toutes les unités en N exemplaires. Mais ce n'est jamais fait en pratique, car le cout en circuits serait trop important et le gain en performance trop faible. Mieux vaut dupliquer certaines unités bien précises, quitte à avoir des contraintes d'appariement. Et à ce petit jeu, toutes les duplications ne se valent pas, certaines sont plus rentables en matière de performance, le cout en circuit n'est pas le même selon l'unité, etc. La rentabilité en performance dépend surtout des contraintes d'appariement. Les contraintes d'appariement entrainent une baisse de performance significatives si elles interdisent des paires d'instructions fréquentes. Aussi, les opérations très fréquentes, souvent appairées, gagnent à dupliquer l'unité associée. Et au contraire, les unités rarement utilisées ne doivent pas être dupliquées. Il se trouve que les unités les plus utilisées sont les ALU entières, suivies par les unités mémoire et l'unité de branchement. Le cout en circuit n'est aussi pas le même. Dupliquer les ALU entière est trivial, car elles ont un budget en transistors assez faible. Les circuits multiplieurs, diviseurs, et les ''barrel shifter'' ont eux un cout en transistor plus élevés. Si on devait faire un classement, on aurait : ALU entière < ''barrel shifter'' < multiplieur. Pour les unités mémoire, le cout en transistor est là aussi conséquent. Le résultat final est que dupliquer les ALU entières est privilégié sur le reste, comme l'a vu dans la section précédente. Les unités mémoire arrivent en seconde place, suivie par les multiplieurs/''barrel shifter'' à la troisième place, et les unités de branchement à la quatrième place. Les CPU superscalaires larges ont donc tendance à multiplier les unités mémoire en second. Les multiplieurs et ''barrel shifters'' sont eux aussi dupliqués sur les CPU superscalaires larges, mais cela vient souvent après avoir dupliqué les unités mémoire. La raison est que les accès mémoire sont critiques pour la performance des CPU à exécution dans le désordre, pas les multiplications. Pour les unités de branchement, une subtilité complique le fait d'en installer plusieurs. Que faire quand deux branchements sont pris ? La solution la plus simple est de ne pas se trouver dans cette situation : on n'utilise qu'une seule unité de branchement et on n’exécute qu'un seul branchement par cycle. La majorité des processeurs superscalaires étroits font ainsi. Les processeurs superscalaires larges ont cependant deux unités de branchements, mais ils n'acceptent qu'un seul branchement pris à la fois. Si les deux branchements pris sont exécutés en même temps, le processeur n’exécute que le plus récent, dans l'ordre du programme. ===Les CPU superscalaires mélangent les trois techniques=== Les CPU superscalaires utilisent toutes les techniques à la fois : partitionnement, duplication de l'ALU entière, duplication des autre unités fonctionnelles. Chaque processeur utilise ces trois stratégies à sa sauce, en fonction de son budget en transistor. Les quatre techniques ont cependant un cout en circuit différent, et donnent des gains de performances eux aussi forts différents. * Le '''partitionnement superscalaire''' a un cout en circuit modéré, car on n'a pas besoin de dupliquer d'ALU. * La '''duplication des ALU entières''' est la technique la plus importante : elle a un cout en circuit modéré, et donne des gains en performance impressionnants. * La '''duplication des autres unités''' a un cout en circuit variable, pour des gains en performance eux aussi variables. * Le '''partage des ports d'émission''' réduit le cout en circuit du CPU, pour des pertes de performances mineures si bien fait. L'usage du partitionnement seul, sans duplication, était surtout le fait des processeurs commercialisés entre les années 1989 et 1993. Le partage des ports d'émission a lui aussi mis un peu de temps pour s'imposer. Globalement, les processeurs superscalaires ont évolués progressivement, pour se rapprocher d'une sorte de standard. Mais pour comprendre ce qu'est ce standard, et en quoi les CPU historiques s'en sont progressivement rapprochés, il faut étudier l'histoire des CPU superscalaires. L'histoire des CPU superscalaires a commencé dès 1960, mais est resté un projet de recherche pendant plusieurs décennies. De nombreux designs ont été conçus, mais abandonnés avant la production, comme l'ACS-1 d'IBM. Les années 1980 ont vu l'arrivée de prototypes de processeurs VLIW, mais qui n'étaient pas superscalaires. Par exemple, l'Apollo DN10000 et l'Intel i860 pouvaient émettre deux instructions à la fois, sous conditions, mais demandaient que le compilateur fasse une bonne partie du travail. Les premiers CPU superscalaires commercialisés sont sortis en 1989. Deux CPUs superscalaires sont sortis cette année là : le RS/6000 d'IBM et l'i960CA d'Intel. Puis, la compétition s'est aussi lancée dans la bataille. Les CPU commercialisés avant l'année 1993 étaient à double émission, à l'exception du SuperSPARC qui utilisait la triple émission. Les modèles après 1993 hésitaient entre double et quadruple émission. Dans le tableau ci-dessous, les processeurs quadruple émission sont en bleu, les triple émission sont en rouge, les autres ne sont pas en couleur. {|class="wikitable" |- ! !! IBM !! HP PA-RISC !! SPARC !! Intel!! Alpha !! Autres |- ! 1989 | RS/6000 || || || i960CA || || |- ! 1990 | || || || || || |- ! 1991 | || || || || || Motorola 88110 |- ! 1992 | RSC || PA 7100 || class="f_rouge | SuperSPARC || || 21064 || |- ! 1993 | PPC 601 || || HyperSPARC || Pentium || || |- ! 1994 | class="f_bleu | POWER 2 || PA 7200 || || || class="f_bleu | 21164 || |- ! 1995 | 603/604 || class="f_bleu | PA 8000 || class="f_bleu | UltraSPARC 1 || Microarchitecture P6 (+ concurrence AMD) || || class="f_bleu | MIPS R1000 |- ! 1996 | class="f_bleu | 620 || || || || class="f_bleu | 21264 || |- ! ... || ... || ... || ... || ... || ... || ... |} Les premiers CPU à double émission sont assez représentatifs des CPU à double émission modernes. Il faut dire que se limiter à deux voies ne permet pas de faire beaucoup de choses. Voici le tableau chronologique disant quel CPU utilisait quelle technique. * Les CPU en vert utilisaient la double émission entière-flottante. * Les CPU en rouge utilisaient la double émission entière "pure". * Les CPU en jaune utilisaient un ''partitionnement complet'' entre ALU, FPU et unité mémoire. * Les CPU sans couleur utilisaient un grand nombre d'unités, avec beaucoup de ports d'émission. * Les CPU barrés utilisent la triple ou quadruple émission et seront vu dans la section suivante. {|class="wikitable" |- ! !! IBM !! HP PA-RISC !! SPARC !! Intel!! Alpha !! Autres |- ! 1989 | class="f_vert | RS/6000 || || || class="f_rouge | i960CA || || |- ! 1990 | || || || || || |- ! 1991 | || || || || || Motorola 88110 |- ! 1992 | class="f_vert | RSC || class="f_vert | PA 7100 || <s>SuperSPARC</s> || || class="f_jaune | 21064 || |- ! 1993 | class="f_vert | PPC 601 || || class="f_jaune | HyperSPARC || class="f_rouge | Pentium || || |- ! 1994 | <s>POWER 2</s> || PA 7200 || || || <s>21164</s> || |} C'est en 1994, que la quadruple émission est arrivée et que les CPU ont essayé divers implémentations. Il y avait alors trois stratégies pour la double/triple/quadruple émission, qui partageaient des problèmes similaires. La première implémentation dupliquait les ALUs et les FPUs, ce qui permettait d'émettre deux opérations flottantes avec deux opérations entières. Le POWER 2 dupliquait ses FPUs à la perfection, alors que le 21264 séparait l'additionneur et le multiplieur flottant. Les accès mémoire étaient traités comme des opérations entières et le processeur pouvait souvent en émettre deux à la fois. Mais une telle organisation n'est plus utilisée de nos jours, car, sans instructions flottantes à exécuter, elle est équivalente à de la double émission. La seconde implémentation utilisait deux ALU entières (dont un multiplieur), une unité mémoire et une FPU.Cette organisation est intéressante, mais encore trop stricte pour donner de bons résultats, les quadruplets avec exactement deux opérations entières, un accès mémoire et une opération flottante étant trop rares. L'usage de ces 4 unités en double ou triple émission a été utilisé sur le PA 7200 et le SuperSPARC. Malheureusement, en plus de problèmes au niveau de son cache, le SuperSPARC avait de nombreuses contraintes d’appariement, car le banc de registre n'avait pas assez de ports pour alimenter certaines combinaisons d'instructions. De plus, s'il émettait une multiplication, il ne pouvait pas émettre de seconde µop. Enfin, une troisième implémentation utilisait un grand nombre d'unités fort différentes, bien plus que quatre, avec au minimum deux ALU entières. Prenons l'exemple de l'UltraSPARC, qui avait : deux ALU entières, une unité mémoire, une unité de branchement, un additionneur flottant, un multiplieur flottant, un diviseur flottant (aussi utilisé pour le calcul des racines carrées), et 2 unités graphiques pour les calculs sur des pixels. En tout, cela fait 9 unités différentes, pour de la quadruple émission. Dans le même genre, les processeurs MIPS R8000 et R10000 avaient une implémentation plus moderne, dans le sens où toutes les unités étaient dupliquées. Le CPU avait deux ALU, deux FPU et deux unités mémoire. Il pouvait donc émettre quatre instructions à la fois, tant que le paquet collait avec ces six unités. Moitié opérations entières, moitié opérations mémoire, avec de quoi remplacer les opérations entières par des opérations flottantes. Le PA 8000, lui, dupliquait toutes ses unités en deux exemplaires, ce qui n'est pas l'idéal, aucun processeur moderne ne fait cela aujourd'hui. Le tout est résumé dans le tableau ci-dessous, avec : * en vert les CPU utilisant la première stratégie ; * en rouge les CPU utilisant la seconde stratégie ; * en jaune les CPU utilisant la troisième stratégie. {|class="wikitable" |+ Processeurs quadruple émission historiques |- ! Année !! Processeur !! Unités |- ! 1991 | class="f_jaune | Motorola 88110 || class="f_jaune | 2 ALU + MUL + DIV + BIT + MEM + FADD + 2 unités graphiques |- |- ! rowspan="2" | 1994 | class="f_vert | POWER 2 || class="f_vert | 2 ALU/MEM + 2 FPU (+ 2 Branchements via ''branch folding'') |- | class="f_rouge | 21164 || class="f_rouge | 2 ALU + FPU + MEM |- ! rowspan="3" | 1995 | PA 8000 || 2 ALU + 2 ''barrel shifters'' + 2 MEM + 2 FPU (FMA) + 2 FPU (DIV et SQRT) + 2 SIMD |- | class="f_jaune | UltraSPARC 1 || class="f_jaune | 2 ALU + MEM + BRANCH + FADD + FMULFDIV + 2 unités graphiques |- | MIPS R8000 et R10000 || 2 ALU + 2 FPU + 2 MEM |- ! rowspan="2" | 1996 | class="f_rouge | 620 || class="f_rouge | 2 ALU + FPU + MEM |- | class="f_vert | 21264 || class="f_vert | 2 ALU/MEM + 2 FPU (FADD + FMUL) |} Malheureusement, ces CPUs historiques n'avaient ni assez d'unités de calcul entières, ni d'unités mémoire, pour remplir la quadruple émission. Environ la moitié des instructions d'un programme correspond à des instructions entières. Pour en profiter, un processeur à N voies doit disposer d'au minimum N/2 ALU entières, l'idéal étant d'aller au-delà. Les CPU superscalaires historiques avaient 2 ALU pour de la quadruple émission, ce qui était très limite. En comparaison, les CPU superscalaires modernes mettent le paquet niveau ALU entière. La plupart des CPU x86 modernes descendent rarement sous les 2/3, la plupart remplit presque la totalité de la largeur du CPU. Pour donner un exemple, la microarchitecture Golden Cove d'Intel est un processeur à 6 voies, avec 5 ALU entières. Pour être précis, un programme informatique exécute environ 40% de son code dans des instructions arithmétiques, un autre 40% dans les accès mémoire, et un le reste pour... le reste. La conséquence est que les processeurs modernes dupliquent leurs unités mémoire. Par exemple, la microarchitecture ''Golden Cove'' d'Intel dispose de trois unités mémoire : deux spécialisées dans les écritures, trois dans les lectures. La microarchitecture ''Gracemont'' utilise la pentuple émission et peut émettre 4 µops entières et 4 µops mémoire. Notez que le ratio est équilibré entre opérations entières et mémoire, avec soit égalité, soit un avantage pour les ALU entières. Une autre régularité est que la largeur totale du processeur peut être occupée par des opérations entières/mémoire. Pour le dire autrement, sur un processeur quadruple émission, il pourra émettre un mix de 4 instructions entière/mémoire, avec zéro opération flottante. Idem avec des processeurs triples ou pentuple émission, voire plus. Si le processeur émet une opération flottante, elle remplace une opération entière. Prenons l'exemple des processeurs AMD K6, sortis en 1997, juste avant les AMD Athlon. Ils avaient 10 unités de calcul, 6 ports d'émission, 4 ports de décodage. Voici exactement comment étaient répartie les unités de calcul sur les ports d'émission. C'était des processeurs quadruple émission, ce qui fait que la moitié de la largeur du processeur sert pour des opérations entières, et l'autre moitié pour les accès mémoire. {|class="wikitable" |- ! Port d'émission n°1 !! Port d'émission n°2 !! Port d'émission n°3 !! Port d'émission n°4 !! Port d'émission n°5 !! Port d'émission n°6 ! |- | ALU entière || ALU entière || FPU || Unité de branchement || Unité LOAD || Unité STORE |- | || Multiplieur || || || || Unité de calcul d'adresse (instruction LEA) |- | || ''Barrel shifter'' || || || || Unité pour les instructions PUSH |} Les microarchitectures K7, K8 et K10, utilisées sur les anciens CPU AMD Athlon, sont un exemple moins représentatif. Ces microarchitectures utilisent le partage des ports d'émission au maximum. C'était des microarchitectures à triple émission, avec six ports d’émission. Il y avait trois ports d'émission pour les opérations flottantes, et trois ports d'émission pour les micro-opérations entières/mémoire. Il y avait trois ALU entières et trois unités mémoire, chaque ALU partageait un port d'émission avec une unité mémoire. Elle pouvait donc émettre soit trois opérations entières, soit trois µops mémoire, soit un mix des deux. En plus des mix avec les opérations flottantes et branchements. {|class="wikitable" |- ! Port d'émission n°1 !! Port d'émission n°2 !! Port d'émission n°3 !! Port d'émission n°4 !! Port d'émission n°5 !! Port d'émission n°6 ! |- | ALU entière || ALU entière || ALU entière || FADD || FMUL || FPU (autres opérations) |- | Multiplieur || || || || || |- | LOAD/STORE || LOAD/STORE || LOAD/STORE || || || |} Les CPU superscalaires larges dupliquent les multiplieurs et/ou les ''barrel shifters'', et même les unités de branchement. La raison est que quand la largeur du CPU augmente, le processeur traite des paquets d'instructions de plus en plus gros. Par exemple, pour un CPU à 10 voies, cela veut dire émettre 10 instructions en même temps. Il est alors plus fréquent d'avoir deux multiplications, deux décalages, deux accès mémoire, deux branchements. Par exemple, la moyenne est d'une multiplication tous les 5 instructions. Les CPU superscalaires à 10 voies ont donc tendance à avoir deux multiplications par paquet d'instruction, en moyenne. Avoir deux multiplieurs est alors un gain en performance clair. Par exemple, la microarchitecture ''Golden Cove'' a deux ''barrel shifters''. C'est une architecture à 6 voies. {|class="wikitable" |- ! Port d'émission n°1 !! Port d'émission n°2 !! Port d'émission n°3 !! Port d'émission n°4 !! Port d'émission n°5 !! Port d'émission n°6 !! Port d'émission n°7 !! Port d'émission n°8 !! Port d'émission n°9 !! Port d'émission n°10 |- | ALU entière || ALU entière || ALU entière || ALU entière || ALU entière || LOAD || LOAD || LOAD || STORE || STORE |- | ''Barrel shifter'' || Multiplieur || Multiplieur || ''Barrel shifter'' || || || || || || |- | Branchements || Diviseur || || Branchements || || || || || || |} ==Les µops mémoire sur les processeurs superscalaires== Plus haut, nous avons volontairement passé sous silence les accès mémoire. La raison à cela est que leur support sur les CPU superscalaire peut se faire de plusieurs manières différentes, qu'il vaut mieux expliquer dans une section dédiée. Les différentes implémentations sont décrites dans la liste suivante, nous allons les voir une par une. * Avec la première méthode, les accès mémoire sont exécutés par le pipeline pour les opérations entières. * Avec la seconde méthode, les accès mémoire ont un pipeline dédié ; c'est l'''émission parallèle des accès mémoire''. * Avec la troisième méthode, il est possible d'émettre plusieurs accès mémoire simultanément : c'est l'''émission multiple des accès mémoire''. Voyons ces trois cas dans le détail. Nous verrons notamment les différentes formes d'émission multiple des accès mémoire. ===Les accès mémoire traités dans le pipeline entier=== Dans le cas le plus simple, les accès mémoire sont traités comme des opérations entières un peu spéciales. L'unité mémoire est sur le même port d'émission que l'ALU entière, ce qui fait que les accès mémoire remplacent des opérations entières. Faire ainsi permet d'utiliser une ALU entière pour les calculs d'adresse, pas besoin de rajouter une unité de calcul d'adresse séparée. Typiquement, un processeur de ce type place l'unité mémoire après l'unité de calcul. Les opérations entières n'utilisent que l'ALU entière, mais pas l'unité mémoire. Les accès mémoire exécutent un calcul d'adresse dans l'ALU entière, puis l'adresse calculée est envoyée à l'unité mémoire. Le tout est illustré ci-dessous, dans le cas d'un processeur historique à double émission entière-flottante. [[File:Processeur non-superscalaire basique 01.png|centre|vignette|upright=1.5|Processeur non-superscalaire basique]] Un exemple de CPU double émission de ce type est celui du Power PC 440, un CPU destiné à l'embarqué. Vu qu'il était destiné à l'embarqué, il n'avait pas de FPU, il n'avait pas besoin de manipuler de nombres flottants. Il n'a donc que des ALU entières, un multiplieur et une unité mémoire. Il dispose de deux ports d'émission. Le premier est connecté à une ALU entière et un circuit multiplieur, le second est relié à l'unité mémoire et une seconde ALU entière. Une organisation simple, mais très efficace ! [[File:PowerPC 440.png|centre|vignette|upright=2|Microarchitecture du PowerPC 440.]] L'implémentation économise une unité de calcul d'adresse, mais n'a pas de cout en performance significatif. Les accès mémoire étant très lents, émettre une µop entière en parallèle d'un accès mémoire ne sert pas à grand-chose. On peut émettre cette µop entière un cycle plus tard, elle sera terminée avant même que l'accès mémoire soit terminé, même si l'accès mémoire se fait dans le cache L1 ou L2. Pour comprendre pourquoi, faisons quelques calculs. Un accès mémoire prend deux-trois cycles quand il tombe dans le cache L1. Et on doit attendre qu'il soit terminé pour en émettre un nouveau. Combien d'instructions arithmétiques peut-on lancer pendant ce temps, sur un CPU triple émission ? Au premier cycle, on peut en émettre 2 (l'instruction mémoire prend une place, donc 3-1), puis 3 au second cycle. Ce qui fait 5 instructions arithmétiques au total. Or, il se trouve qu'il y a une instruction d'accès mémoire pour 5 instructions arithmétiques, environ. Par contre, ce compromis change quand on passe à la quadruple émission, voire au-delà. Dans ce cas, il devient intéressant de pouvoir émettre une nouvelle instruction mémoire à chaque cycle. Ce qui nous amène à la section suivante... ===L'émission parallèle des accès mémoire=== A partir de la quadruple émission, la tendance a été de séparer l'unité mémoire des ALU entières. Cela permet d'émettre des µops mémoire en même temps que des µops entières et/ou flottantes., ce qui porte le nom d''''émission parallèle des µops mémoire''', ou encore ''émission mémoire parallèle''. Par exemple, un processeur quadruple émission peut émettre en même temps deux opérations entières, une opération flottante et un accès mémoire. L'accès mémoire vient en plus des opérations entières, il n'est pas possible de remplacer l'accès mémoire par une opération entière. La technique ne permet pas de faire les calculs d'adresse dans l'ALU entière. Il faut donc utiliser une unité de calcul d'adresse séparée. Elle est intégrée dans l'unité mémoire, qui fait l'interface entre le cache et le banc de registres. Le cout en circuits est très faible, car les unités de calcul d'adresse n'utilisent guère plus qu'un additionneur et un circuit de décalage très simple. L'émission mémoire parallèle est plus facile à implémenter sur les CPU RISC, qui ont des instructions mémoire séparées du reste. Les CPU CISC ne sont pas dans ce cas, ce qui fait que séparer l'unité mémoire du pipeline entier est compliqué. Les CPU superscalaires historiques étaient pour moité des CPU RISC et pour moitié des CPU CISC, ce qui fait qu'ils n'utilisaient pas ou peu l'émission mémoire parallèle. Les premiers processeurs superscalaires se contenaient de l'émission parallèle mémoire, ils ne pouvaient émettre qu'un seul accès mémoire à la fois, l'unité mémoire n'était pas dupliquée. Et ce n'est pas tant un problème que ça, du moins sur les processeurs à double ou triple émission. En effet, il est rare que l'unité mémoire doive faire deux accès simultanés. Notons que le processeur peut exécuter une instruction mémoire en parallèle d'un calcul ou d'un branchement, seuls les accès mémoire simultanés sont impossibles. ===L'émission multiple des accès mémoire avec une LSQ=== Les processeurs superscalaires larges travaillent sur des paquets de 8 à 10 instructions, il est plus fréquent d'avoir plusieurs accès mémoire par paquet. Dans ces conditions, il est utile d'avoir une '''émission multiple des accès mémoire''', à savoir d'émettre plusieurs micro-opérations mémoire en même temps. Les processeurs superscalaires modernes sont capables d'émettre plusieurs lectures/écritures simultanément. Par exemple, ils peuvent émettre une lecture en même temps qu'une écriture, ou plusieurs lectures, ou plusieurs écritures. Il faut noter que selon le processeur, il peut y avoir des restrictions quant aux accès mémoire émis en même temps. Par exemple, certains processeurs peuvent émettre une lecture avec une écriture en même temps, mais pas deux lectures ni deux écritures. Ou encore, ils peuvent émettre deux lectures, une lecture et une écriture, mais pas deux écritures en même temps. Dans la majorité des cas, les processeurs ne permettent pas d'émettre deux écritures en même temps, alors qu'ils supportent plusieurs lectures. Il faut dire que les lectures sont plus fréquentes que les écritures. Les processeurs qui autorisent toutes les combinaisons de lecture/écriture possibles, sont rares. L'émission multiple des accès mémoire s'implémente dans l'unité mémoire. Pour rappel, l'unité mémoire s'interpose entre le cache L1 et le reste du pipeline. Dans le cas le plus simple, elle incorpore une ''load/store queue'' et des unités de calcul d'adresse. L'émission multiple des accès mémoire demande de rendre la ''Load-store queue'' multi-ports, afin de gérer plusieurs micro-opérations mémoire simultanées. Il faut aussi dupliquer les unités de calcul d'adresse reliées à la LSQ, chaque port d'émission mémoire devant avoir sa propre unité de calcul d'adresse. : Dans ce qui suit, nous parlerons d'AGU (''Adress Generation Unit'') pour désigner les unités de calcul d'adresse, et de LSQ pour designer la ''Load-store queue''. [[File:Processeur non-superscalaire basique 02.png|vignette|upright=1|Processeur non-superscalaire basique]] Dupliquer les ports de la LSQ et les AGU est nécessaire. Mais qu'en est-il du cache ? La réponse varie suivant le processeur. Il y a deux grandes méthodes pour implémenter l'émission multiple des accès mémoire. La première méthode ajoute des ports de lecture/écriture au cache de données, pour faire des lectures/écritures simultanées. Il faut alors dupliquer des unités de calcul, rajouter les ports sur le cache, mais aussi rajouter des ports sur la ''load/store queue'', pour qu'elle échange des données/commandes mémoire avec le cache. Le cout en circuits est alors conséquent La seconde duplique les unités de calcul, mais pas les ports d'accès au cache. Les accès mémoire sont alors accumulés dans la ''load/store queue'', qui sont ensuite traités un par un par le cache. Un exemple est celui des processeurs AMD de micro-architecture K7 K8, à savoir les anciens AMD Athlon et AMD Athlon 64, qui pouvaient calculer trois adresses simultanément, mais ne pouvaient faire qu'un seul accès au cache par cycle. Le cout en circuit est modéré : les unités de calcul coutent très peu, les ports de la ''load/store queue'' coutent déjà un peu plus. Quelques processeurs utilisaient des solutions intermédiaires. Un processeur utilisant cette technique est, par exemple, capable d'émettre quatre µops mémoire en même temps, mais avec seulement deux ports sur le cache. Un exemple classique étant les Pentium 1 et 2 d'Intel, dont nous parlerons dans le chapitre suivant. ===L'émission séparée des LOAD et STORE=== De rares processeurs ont des ports d'émission qui peuvent faire indifféremment lecture comme écritures. Mais les processeurs modernes préfèrent séparer ports d'émission pour les lectures et les écritures. Un exemple est celui des processeurs Intel de micro-architecture Nehalem, qui avaient un port de lecture et un port d'écriture tous deux reliés à la ''Load-store queue'', chacun avec leur propre unité de calcul d'adresse. Comme autre exemple, les processeurs skylake ont une LSQ avec deux ports de lecture et un port d'écriture, ce qui permet d'émettre deux lectures en même temps qu'une écriture. Dans cette section, nous allons étudier le cas avec des ports séparés pour les lectures et écritures. En général, les processeurs ont un peu plus de ports de lectures que d'écritures. Une raison est qu'un programme a, en moyenne, un tout petit peu plus de lectures que d'écritures. Mais la différence n'est pas énorme, c'est un léger déséquilibre. Une seconde raison est que l'exécution dans le désordre marche bien mieux quand les lectures ont lieu le plus tôt possible. Donc mieux vaut privilégier les lectures à l'émission, pour qu'elles se fassent un peu en avance. En pratique, la différence n'est pas très marquée. Il est courant d'avoir un port de lecture et un d'écriture, les CPU superscalaires très larges ont souvent deux ports de lecture et deux d'écriture. A la rigueur, quelques CPU ont trois ports de lecture et deux d'écriture. Le cas le plus simple est celui où on peut émettre une lecture et une écriture en même temps. Il s'implémente facilement si la LSQ est en réalité une simple ''Store queue'', à savoir qu'elle met en avance les écritures uniquement. Pour rappel, les écritures sont mises en attente dans la ''Store queue'', mais les lectures sont exécutées immédiatement. Une fois l'adresse à lire connue, la lecture consulte la ''Store queue'' pour détecter les dépendances de données, puis s'exécute. La donnée à lire est lue soit depuis la ''Store queue'', soit depuis le cache. [[File:Emission LOAD - Store séparée.png|vignette|upright=1|Émission LOAD - Store séparée]] L'implémentation de l'émission multiple est alors très simple. La ''Store queue'' a déjà deux ports, avec un pour les lectures et un autre pour les écritures. Idem pour le cache, qui a naturellement un port de lecture et un d'écriture. Émettre une lecture et une écriture simultanément ne demande donc pas de modification digne de ce nom. La ''Store queue'' doit juste supporter une lecture et une écriture simultanée. Ajouter l'émission d'une seconde lecture n'est pas compliquée : il faut juste rajouter un second port de lecture sur le cache et la ''Store queue''. Pour rappel, l'unité mémoire est précédée par une structure qui met en attente les micro-opérations mémoire avant leur émission finale. La structure en question varie suivant l'implémentation, mais un cas particulier se marie bien avec l'émission multiple des µops mémoire. Il s'agit du cas avec une file de µops séparée pour les lectures et une autre pour les écritures, appelées respectivement la ''file de µops LOAD'' et la ''file de µops STORE''. Il est alors possible d'émettre une lecture et une écriture lors du même cycle d'horloge. Le port de lecture alimente une unité de calcul d'adresse dédiée, directement reliée au cache. Le port d'écriture du cache alimente une unité de calcul, qui est suivie par une file d'écriture, elle-même reliée au cache. Les processeurs AMD de micro-architecture K6 utilisaient cette technique. [[File:Double émission avec le Load Ordering, Store Ordering.jpg|centre|vignette|upright=2.5|Double émission avec le Load Ordering, Store Ordering]] ==Les CPU superscalaire à exécution dans le désordre== La superscalarité modifie aussi les circuits dédiés à l'exécution dans le désordre. Elle modifie les unités de renommage de registre, le ROB et les autres structures liées à l'exécution dans le désordre, au sens large. Aucune structure n'est épargnée. Elles ont tous des prots de lecture/écriture en plus, afin d'encaisser l'émission, le ''commit'' ou le renommage simultané de plusieurs µops. Par exemple, le ROB doit être modifié pour émettre et terminer plusieurs instructions en même temps, en ajoutant des ports de lecture/écriture. Pour un CPU superscalaire à 8 voies, on se dit que le ROB peut retirer 8 µops par cycle maximum. Mais certains processeurs récents ont un ROB qui peut retirer le double ! Un exemple est celui des CPU de micro-architecture Skymont, qui peuvent émettre 8 µops par cycle, mais en retirer 16. Quelques CPU de marque AMD étaient aussi dans ce cas. L'avantage est que cela permet de réduire la taille du ROB, du banc de registre et de quelques autres structures matérielles liées à l'exécution dans le désordre. Le gain sur-compense le cout en transistor nécessaire pour retirer 16 µops par cycle. Dans cette section, nous allons voir comment les étages du pipeline dédiés à l'exécution dans le désordre sont modifiées sur un CPU superscalaire. ===L'exemple du PA-RISC PA 8000=== Avant de commencer, nous allons voir un processeur superscalaire assez simple, le PA 8000, de HP, qui implémente le jeu d'instruction PA-RISC. Bien que très ancien, il implémentait l'exécution dans le désordre et le renommage de registre. Le peu d'informations que nous avons sur ce processeurs proviennent des documents "THE HP PA-8000 RISC CPU" par Ashok Kumar, et l'article de microprocessor report "PA-8000 Combines Complexity and Speed". Ils ne donnent malheureusement pas énormémment d'informations et je devrais être amené à faire quelques suppositions dans ce qui suit. Avant de commencer, parlons de détails sans lien avec la superscalarité. Ce processeur, comme beaucoup de processeurs PA-RISC, n'intégrait pas de cache de niveau L2 dans le processeur, qui était déporté en-dehors du CPU, sur la carte mère. Le processeur préférait utiliser ses transistors pour avoir un cache L1 assez large, quitte à ce qu'il soit plus lent. La lenteur du cache était prévue, le processeur compensait celle-ci en utilisant l'exécution dans le désordre, bien que ce ne soit pas parfait. Les CPU PA-RISC avant le PA 8000 utilisaient un pipeline à vagues ''wave pipeline'', ce qui était assez peu commun, mais le PA 8000 repasse à un pipeline synchrone classique. Passons maintenant à la superscalarité. Le PA 8000 est un processeur quadruple émission, qui peut émettre, à chaque cycle, deux opérations et deux accès mémoire. Le renommage de registre utilise des registres de renommage séparés des registres architecturaux, comme c'était la mode à l'époque. Le budget en transistor faisait que c'était soit ça, soit le renommage dans le ROB, faute de mieux. Le processeur utilise une implémentation ''Read After Issue'', ce qui veut dire que les opérandes des instructions sont lues après l'émission, juste avant l'exécution. Le processeur peut aussi ''commit'' deux opérations et deux accès mémoire par cycle, ce qui revient à transférer les résultats des registres de renommage vers les registres architecturaux. L'exécution dans le désordre est prise en charge par une structure matérielle unique, qui ressemble à une fusion entre un ROB et une fenêtre d'instruction. Et c'est là que je vais devoir faire des suppositions. Le document "THE HP PA-8000 RISC CPU" nomme cette structure : l''''''Instruction Reorder Buffer'''''. Il utilise pas moins de 850 000 transistors, et prend 20% de la taille du ''die''. L'article "THE HP PA-8000 RISC CPU" laisse fortement sous-entendre qu'il s'agit une structure unique, faite d'un seul tenant, mais l'article de microprocessor report dit le contraire par moment. Il est décrit comme une fenêtre d'instruction, à savoir qu'il détecte les dépendances entre instruction et les émet. Il gère aussi la détection des mauvaises prédictions de branchement et peut annuler les instructions chargées à tord, en les retirant de la fenêtre d'instruction. Il est aussi précisé que les instructions quittent cet ''Instruction Reorder Buffer'' dans l'ordre du programme. Elles ne peuvent en sortir que quand elles ont été exécutées et qu'elles n'ont causé aucune exception. Ce qui fait qu'il se comporte comme un ROB de ce point de vue là. Difficile de dire si l'''Instruction Reorder Buffer'' est un réel mélange entre un ROB et une fenêtre d'instruction, ou si il est réellement conçu avec deux structures séparées. Dans ce qui suit, je pars du principe que les deux structures sont séparées. Le processeur contient deux fenêtres d'instruction : une réservée aux µops mémoire (LOAD et STORE), l'autre pour les opérations entières/flottantes. Elles ont chacune 28 entrées, ce qui permet de mémoriser 56 µops au maximum. Les deux peuvent recevoir 4 µops par cycle de la part des décodeurs. Là encore, précisons que les choses ne sont pas claires pour ce qui est de la séparation. L'article de Microprocessor report dit que les deux sont physiquement séparées, et que cette séparation physique permet de simplifications (les opérations mémorisent des noms de registres plus court que les adresses demandées par les µops LOAD/STORE). Mais l'autre document cité laisse penser que l''''Instruction Reorder Buffer'' est une structure unique. A chaque cycle, le processeur peut émettre deux instructions de calcul et deux instructions mémoire. Les deux fenêtres d'instruction ont pour cela chacune deux ports d'émission. Les deux ports d'émission pour les µops mémoire sont identiques, et le cache L1 est un cache double port, ce qui permet d'exécuter deux lectures/écritures par cycle. Pour ce qui est des µops entières/flottantes, le processeur a dupliqué toutes ses unités de calcul : il a deux ALU entières, deux ''barrel shifters'', deux FPU de type FMAC, et deux unités de division flottante. Vraisemblablement, il y a deux ports d'émission, chacun étant connecté à une unité de chaque type. : S'il n'utilisait pas l'exécution dans le désordre, ce processeur aurait donc quatre pipelines : deux pipeline entiers identiques et deux pipelines mémoire. Et il aurait une superscalarité presque parfaite s'il était un CPU à double émission ! A chaque cycle, la fenêtre d'instruction émet les deux µops les plus anciennes qui sont prête à être exécutées. La documentation dit que la fenêtre émet "la plus vielle instruction paire, et la plus vielle instruction impaire", ce qui sous-entend que la fenêtre d'instruction est segmentée en deux. C'est précisément la logique d'éveil et d'émission qui est segmentée, une partie gérant la moité de la fenêtre d'instruction, une seconde logique d'éveil/''schedule'' gérant le reste. La fenêtre d'instructions n'implémente donc pas une vraie double émission, elle est partitionnée pour permettre d'émettre deux µops en même temps. L'avantage est une économie de transistors manifeste. Un inconvénient est que si les µops prêtes sont toutes dans la même moitié, une seule µops sera émise par cycle. Mais avec 2*14 entrées, le cas est assez rare pour que l'économie de transistors en vaille la peine. [[File:PA 8000 - microarchitecture.png|centre|vignette|upright=2|PA 8000 - microarchitecture]] ===La superscalarité avec une file/fenêtre d'instruction centralisée=== Plus haut, nous avons montré qu'un processeur pouvait avoir plus de ports d'émission que de ports de décodage. On dit aussi que sa ''largeur de décodage'' était supérieure à sa ''largeur d'émission''. La '''largeur de décodage''' est le nombre de µops fournies par l'unité de décodage par cycle d'horloge, la '''largeur d'émission''' est le nombre maximal de µops émises par cycle d'horloge. Et n'allez pas croire qu'un surplus de ports d'émission est du gâchis. Sur les processeurs avec exécution dans le désordre, ce surplus peut être utilisé. Mais avant toute chose, évacuons un détail. Vous avez sans doute pensé que le surplus peut être exploité par les instructions machines décodées en plusieurs µops . Par exemple, si une instruction est décodée en deux µops, on pourrait avoir un port d'émission en plus pour en profiter. Mais les ports de décodage sont *en sortie du décodeur*, et contiennent des µops, pas des instructions. Le surplus de ports d'émission peut occasionnellement utiliser le surplus de ports de décodage, mais cela implique que des µops ont été mises en attente dans l'unité d'émission, pour être émises par la suite. Et cela implique l'usage d'une fenêtre d'instruction ou d'une file de µops. Le principe est que les µops sont accumulées dans la fenêtre d'instruction, en attendant leurs opérandes ou la résolution d'une dépendance. Et si l'occasion se présente, une µops est émise sur chaque port d'émission. Il y a donc un gain en performances, mais il faut faire quelques précisions sur son origine. La largeur d'émission utilisée ne peut pas dépasser, *en moyenne*, la largeur de décodage. Et c'est intuitif : un CPU qui décode 4 µops par cycle ne peut pas émettre 6 par cycle en moyenne, sur le temps long, il n'y a pas de µops en surplus qui sortent du vide. Par exemple, sur un processeur quadruple émission, si on analyse combien d'instructions sont émises par cycle, il peut y avoir des cycles où la largeur d'émission est totalement utilisée, mais ce sera compensé par des périodes où elle est fortement sous-utilisée. Les µops sont accumulées en cas de sous-utilisation, puis consommées en cas d'utilisation complète. Les deux périodes se compensent. Et c'est là que l'on peut comprendre d'où vient le gain en performance. Les cycles où les ports d'émission sont sous-utilisés existent systématiquement, que le processeur utilise l'exécution dans le désordre ou pas. Ils sont liés à la présence de dépendances de données, aux contraintes d’appariement, etc. Elles tendent à réduire la moyenne du nombre de µops émises par cycle. Par contre, ce sont les cycles de rattrapage, où les ports en surplus sont utilisés, qui font remonter la moyenne. Le gain en performance est donc lié à ces cycles de rattrapage, où les µops accumulées sont émises dans les ports en surplus. Et ils n'existent que sur les processeurs avec une file/fenêtre d'instruction. Réduire le nombre de ports d'émission permet de garder des fenêtres d'instruction et un ROB simples, rapides et économes en énergie. Et mine de rien, c'est là un compromis important : à quoi bon augmenter le nombre de ports d'émission si c'est pour que ce soit compensé par une fréquence plus faible ? Par contre, réduire le nombre de ports augmente la ''port contention'', surtout si on a mal réparti les ALU. Il faut donc trouver un compromis entre réduire le nombre de ports d'émission d'un côté, réduire la ''port contention'' de l'autre. La différence entre largeur de décodage et d'émission a un impact assez fort sur le banc de registre, et précisément sur son nombre de ports de lecture. Le banc de registre a besoin de plus de ports de lecture avec une fenêtre d’instruction qu'avec des stations de réservation. Rappelons la terminologie utilisée dans ce cours. Les fenêtres d'instruction se contentent de mémoriser la micro-opération et quelques bits pour détecter la disponibilité des opérandes. Par contre, les stations de réservations mémorisent aussi les opérandes des instructions. Et cette différence a une influence le nombre de ports de lecture du banc de registre. Supposons que toutes les instructions sont dyadiques, à deux opérandes. Comptons le nombre de ports nécessaires pour alimenter les unités de calcul, sans utiliser d'arbitre de banc de registre. Avec une fenêtre d'instruction, il faut le double du nombre de ports d'émission. Mais avec des stations de réservation, il faut le double des ports de décodage. La raison est que les registres sont lus après émission avec une fenêtre d'instruction, avant avec des stations de réservation (sous-entendu, après le décodage). Or, comme dit plus haut, les processeurs superscalaires larges ont souvent plus de ports d'émission que de décodage. ===La superscalarité à fenêtres d'instruction décentralisées=== Les processeurs précédents utilisaient une unité d'émission simple, qui pouvait utiliser l'émission dans l'ordre ou dans le désordre. Elle peut être remplacée par une fenêtre d'instruction centralisée dans que cela quoi que ce soit aux explications précédentes, idem avec une station de réservation centralisée. En soi, l'exécution dans le désordre est donc totalement compatible avec une implémentation simple de la superscalarité. Par contre, des subtilités surviennent avec les fenêtres d'instruction décentralisées. Pour rappel, sur ces processeurs, les µops sont émises en deux phases. Une première phase de ''dispatch'' qui envoie les µops vers la fenêtre d'instruction adéquate, sans détecter les dépendances de données. La seconde phase de ''schedule'' gère les dépendances de données, elle met en attente les µops en attendant que l'unité soit disponible pour les exécuter, en attendant aussi que les opérandes soient disponibles. Et à ce petit jeu, il y a une différence entre le nombre de µops qui sont ''dispatch par cycle'' et celles qui sont ''schedule''. Dit autrement, la largeur d'émission est scindée en une '''largeur de ''dispatch''''' et une '''largeur de ''schedule''. Par exemple, prenons un processeur triple émission avec deux stations de réservation : une pour les µops entières/mémoire, et une autre pour les µops flottantes. L'unité d'émission peut ''dispatch'' maximum trois µops par cycle : soit trois µops entières/mémoire, soit trois flottantes, soit un mix de trois µops différentes. Les stations de réservation, quant à elles, peuvent chacune ''schedule'' 3 µops par cycle, vers trois ALUs entières pour la station de réservation entière/mémoire, vers trois FPS pour la station de réservation flottante. De quoi ''dispatch'' trois µops, mais d'en ''schedule'' six, à chaque cycle. Et cet exemple ne sort pas de nulle part : les CPU x86 d'Intel et AMD sont globalement dans ce cas, même si les chiffres varient d'une microarchitecture à l'autre. L'exemple précédent colle parfaitement à la microarchitecture K7 d'AMD, utilisée sur les processeurs Athlon dans les années 2000. [[File:AMD K7.png|centre|vignette|upright=2.5|AMD K7, microarchitecture.]] L'exemple précédent avait assez d'unités entières/flottantes pour couvrir toute la largeur de décodage/''Dispatch''. Mais ce n'est pas toujours le cas, comme va le montrer l'exemple suivant. Le MIPS R10000, qui utilisait un mélange de files de µops et de fenêtres d'instructions : une file de µops les accès mémoire, une fenêtre pour les instructions entières et une autre pour les opérations flottantes. Les branchements et NOPs étaient exécutés dans une unité de branchement distincte. Les trois files/fenêtres peuvent mémoriser 16 µops. Le processeur avait deux ALU entières, une AGU de calcul d'adresse, un additionneur flottant et un multiplieur/diviseur flottant. Il y avait un multiplieur entier sur le port d'émission l'ALU 2. Le processeur décodait 4 instructions par cycle et produisait jusqu'à 4µops, qui étaient redistribuées sur les trois fenêtres d'instructions. Chacune pouvait accepter 4 µops par cycle, ce qui fait que processeur pouvait ''dispatch'' 4 µops entières, ou 4 µops flottantes, ou 4 µops mémoire, ou un mélange de deux ou trois types de µops. Pour ce qui est du ''schedule'', la fenêtre d'instruction entière pouvait émettre 2 µops, la fenêtre flottante pouvait émettre une addition en même temps qu'une multiplication/divison flottante et qu'un branchement conditionnel flottant, et la file de µops mémoire ne pouvait émettre qu'une µop mémoire à la fois. En tout, cela fait 6 µops ''schedule'' pour 4 µops au ''dispatch''. [[File:R 10000.png|centre|vignette|upright=2.5|MIPS R10000, microarchitecture.]] ===La superscalarité à fenêtres d'instruction totalement décentralisées=== Prenons un cas extrême de fenêtre d'instruction décentralisée : celui où chaque ALU entière a sa propre station de réservation. En clair : une fenêtre d'instruction par ALU/FPU ! On parle de '''fenêtres d'instruction totalement décentralisées'''. Vous vous dites que ce cas est un peu trop extrême pour être réaliste, mais il n'en est rien. C'est même très courant sur les architectures basse consommation, et sur pas mal de CPU x86 modernes. Une telle organisation entraine une légère perte de performance, comparé à une fenêtre d'instruction centralisée ou partiellement décentralisée. Et cela peut se comprendre par un exemple. Imaginez un processeur avec deux ALU, donc deux stations de réservation. Il arrivera qu'une station de réservation ait plusieurs µops prêtes, alors que l'autre en ait zéro. Dans une telle situation, une seule µop sera émise au cycle suivant, vu que chaque station de réservation a un seul port d'émission vers une seule ALU entière. Par contre, avec une fenêtre d'instruction centralisée double port, on aurait pu émettre les deux µops en même temps sur deux ALUs séparées. La perte de performance est donc liée au fait que les µops '''''prêtes''''' sont mal réparties dans les différentes stations de réservation. Il arrivera que des µops prêtes s'accumulent dans une station de réservation, alors que d'autres seront pleines, ou du moins sous-utilisées. Et ce n'est pas quelque chose qui peut être réglé à l'étape de ''dispatch'', car on ne sait pas encore quand les µops auront leurs opérandes de disponibles. [[File:Comparaison entre une station de réservation totalement décentralisée et une autre qui ne l'est pas.png|centre|vignette|upright=2.5|Comparaison entre une station de réservation totalement décentralisée et une autre qui ne l'est pas.]] Par contre, décentraliser totalement les fenêtres d'instruction entraine aussi un gain considérable en termes de consommation énergétique. Et c'est la raison pour laquelle les fenêtres d'instructions totalement décentralisées sont utilisées sur les architectures basse consommation. La perte de performance ne peut pas s'expliquer clairement à ce stade du cours, car il nous faudrait parler d'émission superscalaire. Le gain en matière d'énergie vient de l'économie de circuits, qui est assez drastique. Le gain en matière d'énergie vient de l'économie de circuits, qui est assez drastique. Je rappelle qu'une station de réservation a besoin, pour N instructions, d'environ N^2 circuits (des comparateurs, notamment). Prenons une station de réservation centralisée de 64 entrées et comparons avec 8 stations de 8 entrées chacune. Les deux donneront 64 entrées, mais la première aura un cout en circuit proportionnel à 64², alors que le second aura un cout en circuit de 8 *(8²). Entre les deux, le choix est clair : la seconde solution est plus économe. D'où l'utilisation de cette solution sur les microarchitectures basse consommation. ===L'unité de renommage superscalaire=== Avec la superscalarité, l'unité de renommage de registre doit gérer le cas où des instructions consécutives ont des dépendances de registre. Par exemple, prenons un processeur à double émission, qui renomme deux instructions consécutives. Si elles ont une dépendance de registre, le renommage de la seconde instruction dépend du renommage de la première. La première doit être renommée et le résultat du renommage est utilisé pour renommer la seconde, ce qui empêche d'utiliser deux unités de renommage séparées. Pour cela, elle renomme les registres sans tenir compte des dépendances, pour ensuite corriger le résultat. [[File:Unité de renommage superscalaire.png|centre|vignette|upright=2|Unité de renommage superscalaire.]] Seules les dépendances lecture-après-écriture doivent être détectées, les autres étant supprimées par le renommage de registres. Repérer ce genre de dépendances se fait assez simplement : il suffit de regarder si un registre de destination d'une instruction est un opérande d'une instruction suivante. [[File:Détection des dépendances sur un processeur superscalaire.png|centre|vignette|upright=2|Détection des dépendances sur un processeur superscalaire.]] Ensuite, il faut corriger le résultat du renommage en fonction des dépendances. Si une instruction n'a pas de dépendance avec une autre, on la laisse telle quelle. Dans le cas contraire, un registre opérande sera identique avec le registre de destination d'une instruction précédente. Dans ce cas, le registre opérande n'est pas le bon après renommage : on doit le remplacer par le registre de destination de l'instruction avec laquelle il y a dépendance. Cela se fait simplement en utilisant un multiplexeur dont les entrées sont reliées à l'unité de détection des dépendances. On doit faire ce replacement pour chaque registre opérande. [[File:Correction des dépendances sur un processeur superscalaire.png|centre|vignette|upright=2|Correction des dépendances sur un processeur superscalaire.]] ==Les optimisations des processeurs superscalaires larges== Les processeurs superscalaires larges ont des optimisations spécifiques, qui n'ont pas de sens sur les processeurs superscalaires étroits. Dans les grandes lignes, elles se classent en deux types. Les premières permettent de charger/décoder plus de 5-10 instructions simultanément. Le problème est alors que les branchements viennent mettre leur grain de sel et qu'il faut en tenir compte. Les secondes corrigent des problèmes qui apparaissent quand un CPU intègre plus de 5 à 10 unités de calcul. ===L'étape de chargement d'un CPU superscalaire large=== Charger plusieurs instructions pose de nombreux problèmes sur les processeurs superscalaires larges, qui émettent de 5 à 10 instructions simultanées. Pour rappel, la stratégie basique pour charger N instructions est de charger un bloc de N instructions consécutives. Les instructions après un branchement ne sont pas décodées ni exécutées, ce qui entraine une petite baisse de performance. Pour un N petit, la perte de performance est mineure. Mais pour un N large, elle devient suffisamment importante pour que la conception du CPU doit alors être repensée de fond en comble. Les analyses statistiques disent qu'il y a environ un branchement tous les 4 à 6 instructions. Un CPU a donc tendance à décoder des paquets de 3 à 5 instructions consécutives, avant qu'un branchement casse la dynamique. Or, cela pose des problèmes pour utiliser plusieurs décodeurs. L'implémentation basique, qui charge N instructions consécutives pour alimenter N décodeurs, fonctionne donc jusqu'à 4/6 décodeurs. Au-delà de 5 instructions, un CPU superscalaire doit être adapté pour gérer les branchements dans les paquets d'instruction qu'il émet. Le nombre de 5 instructions ne sort donc pas de nulle part. La première solution utilise un cache de µops, avec un ''front-end'' capable de charger/décoder 4/5 instructions à la fois, pas plus. L'idée est que la majorité des instructions proviennent du cache de µops (plus de 80%), ce qui fait qu'on peut émettre environ 10 instructions à partir du cache de µops, pas besoin d'avoir beaucoup de décodeurs. Les performances sont cependant dégradées lors d'un défaut de cache de µops. Les instructions doivent alors être chargées depuis le cache d'instruction, par paquets de 4-5, puis sont décodées par 4-5 décodeurs, ce qui ne permet pas d’alimenter les unités de calcul à plein régime. La solution précédente joue sur la distinction entre pots de décodage et d'émission. Elle permet d'émettre un grand nombre de µops sans pour autant charger un grand nombre d'instructions en même temps. En quelque sorte, ce n'est qu'une méthode de contournement, le CPU superscalaire reste de type étroit. Mais il est aussi possible d'utiliser un '''''front-end large''''', capable de charger une bonne dizaine d'instructions en même temps. La seule difficulté est de tenir compte de la présence de branchements. Pour rappel, avec un ''front-end'' étroit, les instructions situées après le premier branchement pris sont annulées, elles ne sont pas décodées ni exécutées. [[File:Fetch sur un processeur superscalaire avec prediction de branchements.png|centre|vignette|upright=2|Fetch sur un processeur superscalaire avec prédiction de branchements.]] Un ''front-end'' large charge les instructions de destination du branchement et les placent à sa suite. Ils chargent deux blocs à la fois et les fusionnent en un seul qui ne contient que les instructions présumées utiles. [[File:Cache d'instructions autoaligné.png|centre|vignette|upright=2|Cache d'instructions auto-aligné.]] Mais cela demande de charger deux blocs de mémoire en une fois, ce qui demande un cache d'instruction multiports. Il faut aussi ajouter un circuit pour assembler plusieurs morceaux de blocs en un seul : le fusionneur (''merger''). En pratique, cette solution demande d'ajouter un second port de lecture au cache, pour un cout en hardware important, avec un impact négatif sur le temps d'accès au cache. Et il faut rajouter le fusionneur, qui prend un étage de pipeline à lui tout seul. Et encore, cette solution ne gère pas le cas où un bloc contient plusieurs branchements ! [[File:Implémentation d'un cache d'instructions autoaligné.png|centre|vignette|upright=2|Implémentation d'un cache d'instructions auto-aligné.]] Les exemples précédents partent du principe qu'il n'y a qu'un seul branchement dans un bloc. Mais quand les blocs deviennent assez longs, il est fréquent d'avoir plusieurs branchements dans un bloc. Et il est même possible d'avoir plusieurs branchements pris. Dans un bloc de 8-10 instructions, ce n'est pas rare, et les CPU superscalaires à 8-10 voies sont la règle dans les CPU des années 2020. Pour gérer ce cas, il faut ajouter des ports supplémentaires au cache d'instruction et adapter le fusionneur, pour qu'il puisse fusionner trois ou quatre blocs. De plus, il faut utiliser une unité de prédiction de branchement capable de ''prédire plusieurs branchements par cycle''. ===Le décodage superscalaire large=== Le décodage des instructions n'est pas censé dépendre de l'implémentation du chargement. En théorie, une fois plusieurs blocs d'instruction fusionnés, on peut décoder les instructions en parallèle. Cependant, certains processeurs effectuent le décodage en tenant compte de la manière dont les branchements découpent les blocs. Les processeurs Atom d'Intel utilisent une solution de ce type, qui couple prédiction de branchement et décodage parallèle. Ils chargent/décodent des paquets de 3 instructions consécutives, chaque paquet étant séparé du précédent par un branchement. Pour cela, en plus d'avoir un fusionneur adapté, ils regroupent les décodeurs en ''clusters'', chacun regroupant 3 décodeurs, et pouvant décoder trois instructions consécutives. Les micro-architectures Tremont et Crestmont avaient deux ''clusters'' (6 décodeurs au total), la micro-architecture Darkmont en intègre trois (9 décodeurs au total). Avec deux ''clusters'', le fonctionnement est le suivant. Si le code est composé d'une suite d'instruction sans branchements, seul le premier ''cluster'' est utilisé, limitant le décodage à trois instructions par cycle. Par contre, si l'une des trois instructions décodée est un branchement, alors le second ''cluster'' décode les trois instructions situées après ce branchement, à partir de l'adresse de destination. Avec un troisième ''cluster'', c'est la même chose, sauf qu'il faut qu'il y ait un branchement dans les trois instructions décodées par le second ''cluster''. Mais comment faire pour savoir quels décodeurs activés, quels ''clusters'' sont actifs ? C'est la prédiction de branchement qui commande. Avec deux ''clusters'', elle détermine si un branchement est présent dans les trois instructions à charger, et quelle est son adresse de destination. Sans branchement, elle prévient les décodeurs et les trois instructions chargées sont décodées dans un ''cluster'' libre. Si elle prédit un branchement, elle charge les instructions adéquates, et active les deux ''clusters''. Avec trois branchements, c'est le même mécanisme, sauf que l'unité de prédiction de branchement doit être capable de prédire deux branchements par cycle. [[File:Front-end découplé de la microarchitecture Tremont.png|centre|vignette|upright=3|Front-end découplé de la microarchitecture Tremont.]] Il faut noter que les décodeurs d'un ''cluster'' sont des décodeurs simples, sans microcode. Sur les processeurs Tremont et Crestmont, le microcode était unique et était partagé entre tous les ''clusters''. Un seul ''cluster'' pouvait décoder une instruction complexe avec le microcode, l'autre devait se limiter à des instructions simples uniquement. Depuis Skymont, le microcode est partiellement dupliqué, avec un microcode par ''cluster''. Le cout en hardware peut paraitre prohibitif, pour un gain en performance faible. Sauf que c'est oublier que ce sont des processeurs Atom, sur lesquels beaucoup d'instructions sont microcodées. Les processeurs Atom ont un budget en transistor limité, ce qui fait qu'il est préférable pour eux d'implémenter des instructions en microcode que d'utiliser des unités de calcul dédiées ou des circuits de décodage complexes. Pour limiter la casse, le microcode n'est que partiellement dupliqué. Seul le microcode pour les instructions fréquente est dupliqué. Il y a un microcode secondaire pour certaines instructions, qui est lui unique et partagé par tous les ''clusters''. ===Le contournement sur les processeurs superscalaires larges=== Pour rappel, la technique du contournement (''register bypass'') permet au résultat d'une instruction d'être immédiatement utilisable en sortie de l'ALU, avant même d'être enregistré dans les registres. Implémenter la technique du contournement demande d'utiliser des multiplexeurs pour relier la sortie de l'unité de calcul sur son entrée si besoin. Il faut aussi des comparateurs pour détecter des dépendances de données. [[File:Pipeline Bypass.png|centre|vignette|upright=1|Pipeline Bypass]] La sortie de chaque ALU doit être reliée aux entrées de toutes les autres, avec les comparateurs qui vont avec. Sur les processeurs ayant plusieurs d'unités de calculs, cela demande beaucoup d’interconnexions et de comparateurs. Pour N unités de calcul, cela demande 2 * N² interconnexions, implémentées avec 2N multiplexeurs de N entrées chacun. Si c'est faisable pour 2 ou 3 ALUs, la solution est impraticable au-delà. Non seulement ce serait un enfer à câbler, mais les fils seraient tellement longs que la fréquence du processeur en prendrait un coup. Notez que cela vaut pour les processeurs superscalaires, mais aussi pour tout processeur avec beaucoup d'unités de calcul. En théorie, un CPU à exécution dans le désordre, non-superscalaire, mais avec beaucoup d'unités de calcul, fait face au même problème. En pratique, avoir une dizaine d'ALU implique processeur superscalaire à exécution dans le désordre. D'où le fait qu'on parle du problème maintenant. La seule solution praticable est de ne pas relier toutes les unités de calcul ensemble. À la place, on préfère regrouper les unités de calcul dans différents '''agglomérats''' ('''cluster'''). Le contournement est alors possible entre les unités d'un même agglomérat, mais pas entre agglomérats différents. Évidemment, certaines possibilités de contournement sont perdues, mais c'est compensé par un gain en fréquence et un cout en circuit/fils réduit. C'est un bon compromis, ce qui explique que presque tous les processeurs modernes l'utilisent. Les rares exceptions sont les processeurs POWER 4 et POWER 5, qui ont préféré se passer de contournement pour garder un processeur très simple et une fréquence élevée. ===Le banc de registre des processeurs superscalaires larges=== Pour émettre deux opérations entières simultanément, il faut lire deux fois plus d'opérandes. Et il faut aussi écrire deux résultats dans les registres, en même temps. Pour cela, on double les ports du banc de registre. En général, il faut au maximum 2 ports de lecture et un port d'écriture par unité de calcul. Le problème, c'est que plus un banc de registres a de ports, plus il utilise de circuits, est compliqué à concevoir, consomme de courant et chauffe. Avec plusieurs dizaines d'unités de calcul différentes, ajouter autant de ports impacterait la fréquence du banc de registres et réduirait les performances, voire est totalement impraticable à cause des contraintes thermiques. Les processeurs superscalaires larges doivent donc trouver des solutions. La première solution utilise un banc de registre unique, mais n'utilise pas autant de ports que le pire des cas le demanderait. Le processeur détecte quand il n'y a pas assez de ports pour servir toutes les micro-opérations. Quand ça arrive, l'unité d'émission émet assez de micro-opérations pour exploiter les ports disponibles, mais met en attente les micro-opérations en trop, le temps que les ports se libèrent. Pour cela, le banc de registre est géré par un circuit d'arbitrage spécialisé, intégré à l'unité d'émission, l’'''arbitre du banc de registres''' (''register file arbiter''). Une autre solution est de dupliquer le banc de registres en plusieurs exemplaires qui contiennent exactement les mêmes données, mais avec moins de ports de lecture/écriture. Un exemple est celui des processeurs POWER, Alpha 21264 et Alpha 21464. Sur ces processeurs, le banc de registre est dupliqué en plusieurs exemplaires, qui contiennent exactement les mêmes données. Les écritures dans les registres sont envoyées à tous les bancs de registres, afin de garantir que leur contenu est identique. Chaque exemplaire a exactement deux ports de lecture. La conception du processeur est simplifiée, que ce soit au niveau du câblage, que de la conception des bancs de registres. Une dernière solution découpe le banc de registres en plusieurs bancs de registres plus petits, avec un réseau d'interconnexions pour échanger des données entre bancs de registres. Dans la plupart des cas, cette séparation est invisible du point de vue de l'assembleur et du langage machine. Le processeur se charge de transférer les données entre bancs de registres suivant les besoins. Sur d'autres processeurs, les transferts de données se font via une instruction spéciale, souvent appelée ''COPY''. [[File:Banc de registres distribué.png|centre|vignette|upright=2|Banc de registres distribué.]] Sur de certains processeurs, un branchement est exécuté par une unité de calcul spécialisée. Or les registres à lire pour déterminer l'adresse de destination du branchement ne sont pas forcément dans le même agglomérat que cette unité de calcul. Pour éviter cela, certains processeurs disposent d'une unité de calcul des branchements dans chaque agglomérat. Dans les cas où plusieurs unités veulent modifier le ''program counter'' en même temps, un système de contrôle général décide quelle unité a la priorité sur les autres. Mais d'autres processeurs fonctionnent autrement : seul un agglomérat possède une unité de branchement, qui peut recevoir des résultats de tests de toutes les autres unités de calcul, quel que soit l’agglomérat. ==La macro-fusion : une optimisation du décodage parallèle== Les processeurs superscalaires supportent la technique dite de '''macro-fusion''', qui permet de fusionner deux-trois instructions consécutives en une seule micro-opération. Par exemple, il est possible fusionner une instruction de test et une instruction de saut en une seule micro-opération de branchement. Il s'agit là de l'utilisation la plus importante de la macro-fusion sur les processeurs x86 modernes. La macro-fusion est utilisée pour fusionner un test et un saut en un branchement unique. L'optimisation est présente sur la plupart des CPU superscalaires modernes. Les CPU x86 l'implémentent, mais aussi quelques CPU ARM et les processeurs Apple de série M (M1 à M5, et potentiellement plus quand ils seront sortis). La fusion des instructions se fait lors du décodage des instructions, grâce à la coopération des décodeurs. Elle marche systématiquement si l'instruction de test et le saut sont consécutives, qu'elles forment bien une paire d'instruction. Par contre, insérer une instruction entre les deux empêche la macro-fusion de faire son travail, sauf si l'instruction insérée est un NOP. Les processeurs ARM64 avaient une forme spécifique de macro-fusion, utilisée pour un cas très précis : charger une constante immédiate de 32 ou 64 bits, dans un registre 64 bits. Les CPU ARM 64 bits utilisent des instructions codées sur 32 bits, qui ne peuvent encoder que des constantes immédiates de 16 bits. Pour charger une constante de 32/64 bits, il faut s'y prendre en plusieurs fois. Une première instruction MOVZ charge les 16 premiers bits, puis 2 à 4 instructions MOVK remplissent le reste. MOVZ met à zéro les 48 bits de poids fort, MOVK permet de sélectionner le doublet à modifier dans le registre (on modifie 16 bits, dont on choisit la place, le reste du registre est laissé tel quel). ARM permet de fusionner cette suite d'instructions en une seule µop MOV avec une constante immédiate. On parle alors de '''''MOVZ + MOVK fusion'''''. Une dernière utilisation, [https://www2.eecs.berkeley.edu/Pubs/TechRpts/2016/EECS-2016-130.pdf proposées pour le jeu d'instruction RISC-V], fusionnait un calcul d'adresse et une instruction LOAD/STORE en une seule instruction d'accès mémoire. Elle a été envisagée à une époque où le jeu d'instruction RISC-V ne gérait pas les modes d'adressage base + indice. L'idée était d'avoir une unité mémoire qui gérait le mode d'adressage base + indice et de fusionner des instructions pour l'exploiter. Mais de nos jours, le jeu d'instruction RISC-V intègre le mode d'adressage base + indice, ce qui fait que la macro-fusion n'a aucun intérêt pour ce cas précis. La macro-fusion a de nombreuses limitations en pratique. En théorie, on pourrait l'utiliser au-delà des deux situations mentionnées plus haut. Par exemple, pour fusionner une addition et une multiplication en une seule instruction MAD. Mais l'intérêt est assez faible. Notons que la macro-fusion ne permet que de fusionner des paires d'instructions. Aller au-delà demanderait un cout en circuit trop important. Déjà que tester deux paires utilise pas mal de comparateurs... ==Le ''stack engine'' : une optimisation de la pile d'appel== Les processeurs modernes intègrent une optimisation liée au pointeur de pile. Pour rappel, sur les architectures modernes, le pointeur de pile est un registre utilisé pour gérer la pile d'appel, précisément pour savoir où se trouve le sommet de la pile. Il est manipulé par les instructions CALL, RET, PUSH et POP, mais aussi par les instructions d'addition/soustraction pour gérer des cadres de pile de taille variable. De plus, il peut servir d'opérande pour des instructions LOAD/STORE, afin de lire/écrire des variables locales, les arguments d'une fonction, et autres. C'est donc un registre général adressable, intégré au banc de registre, altéré par l'unité de calcul entière. L'incrémentation/décrémentation du pointeur de pile passe donc par l'unité de calcul, lors des instructions CALL, RET, PUSH et POP. Mais, l'optimisation que nous allons voir permet d'incrémenter/décrémenter le pointeur de pile sans passer par l'ALU, ou presque. L'idée est de s'inspirer des architectures avec une pile d'adresse de retour, qui intègrent le pointeur de pile dans le séquenceur et l'incrémentent avec un incrémenteur dédié. ===Le ''stack engine''=== L'optimisation que nous allons voir utilise un '''''stack engine''''' intégré à l'unité de contrôle, au séquenceur. Le processeur contient toujours un pointeur de pile dans le banc de registre, cela ne change pas. Par contre, il n'est pas incrémenté/décrémenté à chaque instruction CALL, RET, PUSH, POP. Un compteur intégré au séquenceur est incrémenté à la place, nous l’appellerons le '''compteur delta'''. La vraie valeur du pointeur de pile s'obtient en additionnant le compteur delta avec le registre dans le banc de registre. Précisons que si le compteur delta vaut zéro, la vraie valeur est dans le banc de registre et peut s'utiliser telle quelle. Lorsqu'une instruction ADD/SUB/LOAD/STORE utilise le pointeur de pile comme opérande, elle a besoin de la vraie valeur. Si elle n'est pas dans le banc de registre, le séquenceur déclenche l'addition compteur-registre pour calculer la vraie valeur. Finalement, le banc de registre contient alors la bonne valeur et l'instruction peut s'exécuter sans encombre. L'idée est que le pointeur de pile est généralement altéré par une série d'instruction PUSH/POP consécutives, puis des instructions LOAD/STORE/ADD/SUB utilisent le pointeur de pile final comme opérande. En clair, une bonne partie des incrémentations/décrémentation est accumulée dans le compteur delta, puis la vraie valeur est calculée une fois pour toutes et est utilisée comme opérande. On accumule un delta dans le compteur delta, et ce compteur delta est additionné quand nécessaire. Précisons que le compteur delta est placé juste après le décodeur d'instruction, avant même le cache de micro-opération, l'unité de renommage et l'unité d'émission. Ainsi, les incrémentations/décrémentations du pointeur de pile disparaissent dès l'unité de décodage. Elles ne prennent pas de place dans le cache de micro-opération, ni dans la fenêtre d'instruction, ni dans la suite du pipeline. De nombreuses ressources sont économisées dans le ''front-end''. Mais utiliser un ''stack engine'' a aussi de nombreux avantages au niveau du chemin de données/''back-end''. Déjà, sur les processeurs à exécution dans le désordre, cela libère une unité de calcul qui peut être utilisée pour faire d'autres calculs. Ensuite, le compteur delta mémorise un delta assez court, de 8 bits sur le processeur Pentium M, un peu plus pour les suivants. L'incrémentation se fait donc via un incrémenteur 8 bits, pas une grosse ALU 32/64 bits. Il y a un gain en termes de consommation d'énergie, un incrémenteur 8 bits étant moins gourmand qu'une grosse ALU 32/64 bits. ===Les points de synchronisation du delta=== La technique ne fonctionne que si la vraie valeur du pointeur de pile est calculée au bon moment, avant chaque utilisation pertinente. Il y a donc des '''points de synchronisation''' qui forcent le calcul de la vraie valeur. Plus haut, nous avions dit que c'était à chaque fois qu'une instruction adresse le pointeur de pile explicitement, qui l'utilise comme opérande. Les instructions CALL, RET, PUSH et POP ne sont pas concernées par elles utilisent le pointeur de pile de manière implicite et ne font que l'incrémenter/décrémenter. Mais dans les faits, c'est plus compliqué. D'autres situations peuvent forcer une synchronisation, notamment un débordement du compteur delta. Le compteur delta est généralement un compteur de 8 bits, ce qui fait qu'il peut déborder. En cas de débordement du compteur, le séquenceur déclenche le calcul de la vraie valeur, puis réinitialise le compteur delta. La vraie valeur est donc calculée en avance dans ce cas précis. Précisons qu'un compteur delta de 8 bits permet de gérer environ 30 instructions PUSH/POP consécutives, ce qui rend les débordements de compteur delta assez peu fréquent. À noter que si le compteur delta vaut zéro, il n'y a pas besoin de calculer la vraie valeur, le séquenceur prend cette situation en compte. Un autre point de synchronisation est celui des interruptions et exceptions matérielles. Il faut que le compteur delta soit sauvegardé lors d'une interruption et restauré quand elle se termine. Idem lors d'une commutation de contexte, quand on passe d'un programme à un autre. Pour cela, le processeur peut déclencher le calcul de la vraie valeur lors d'une interruption, avant de sauvegarder les registres. Pour cela, le processeur intègre un mécanisme de sauvegarde automatique, qui mémorise la valeur de ce compteur dans le tampon de réordonnancement, pour forcer le calcul de la vraie valeur en cas de problème. La technique du ''stack engine'' est apparue sur les processeurs Pentium M d'Intel et les processeurs K10 d'AMD, et a été conservée sur tous les modèles ultérieurs. L'implémentation est cependant différente selon les processeurs, bien qu'on n'en connaisse pas les détails et que l'on doive se contenter des résultats de micro-benchmarks et des détails fournit par Intel et AMD. Selon certaines sources, dont les manuels d'optimisation d'Agner Fog, les processeurs AMD auraient moins de points de synchronisation que les processeurs Intel. De plus, leur ''stack engine'' serait placé plus loin que prévu dans le pipeline, après la file de micro-opération. ==La micro-fusion et la délamination== La '''micro-fusion''' est une optimisation qui retarde le décodage réel de certaines instructions assez loin dans le pipeline. Elle concerne surtout les instructions ''load-op'', mais pas que. D'autres instructions mémoire peuvent subir cette optimisation. L'essentiel est que, sans micro-fusion, ces instructions sont décodées en plusieurs micro-opérations. La micro-fusion retarde le décodage final de ces instructions, qui se fait assez tard dans le pipeline. Pour comprendre l'intérêt, nous allons devoir faire quelques explications. L'optimisation en question fait le décodage en deux temps. Prenons l'exemple d'une opération ''load-op'', qui est censée être décodée en deux micro-opérations : une lecture, puis une opération. Le décodage produit une '''macro-opération''' (terme d'Intel), qui est propagée dans le pipeline, pour être scindée en deux micro-opérations un peu avant les ALU et l'unité mémoire. La macro-opération est techniquement une micro-opération comme une autre, sauf que ce n'est pas la micro-opération finale. L'unité d'émission découpe cette macro-opération en deux micro-opérations, qui sont émises l'une après l'autre. Pour résumer, les instructions ''load-op'' ne sont complétement découpées en micro-opération lors de l'émission, pas lors du décodage. L'optimisation impacte ce qui se situe entre le décodeur d'instruction et l'unité d'émission : l'unité de renommage, la file de micro-opérations, le ''Loop Stream Detector'' et/ou le cache de micro-opération. L'intérêt de l'optimisation est que l'on fusionne deux micro-opérations en une seule macro-opération. Le cache de micro-opération et la file de micro-opération peuvent mémoriser plus de micro-opérations, vu que certaines sont fusionnées. Quant à l'unité de renommage, elle renomme une seule macro-opération au lieu de renommer deux micro-opérations, ce qui augmente le débit du renommage de registre. Par contre, cela complique un peu le travail de l'unité d'émission, qui doit découper les instructions ''load-op'' en deux et émettre les micro-opérations l'une après l'autre. Il faut noter qu'il n'y a pas de fusion proprement dite. Le décodeur ne décode pas deux micro-opérations séparées, avant de les fusionner. En réalité, il génère directement une macro-opération, qui correspond à deux micro-opérations, que ce soit plus tard dans le pipeline ou sur une autre architecture. D'ailleurs, la micro-fusion a lieu à l'intérieur d'une instruction, qui est censée être traduite en plusieurs micro-opérations. Et encore : pas toutes. La conséquence est que la technique n'a de sens que sur les processeurs CISC, avec des instructions assez complexes pour être décodées en plusieurs micro-opérations. En pratique, seuls les CPU x86 sont concernés. ===Les domaines de fusion=== La micro-fusion n'est pas spécifique aux processeurs superscalaires. En théorie, on peut l'implémenter sur un processeur non-superscalaire à émission dans l'ordre. Cependant, je ne connais aucun processeur à émission dans l'ordre qui implémente la micro-fusion, même si son implémentation est en théorie possible sur de tels processeurs. La micro-fusion est implémentée différemment selon que l'émission se fasse dans l'ordre, dans le désordre, avec une fenêtre d'instruction, avec des stations de réservation, etc. J'ai dit plus haut que les micro-opérations sont générées lors de l'émission, mais le moment exact varie suivant le processeur. Pour simplifier le tout, nous parlerons de '''scission''' quand le processeur traduit une macro-opération en deux/trois micro-opérations. Le moment où a lieu la scission est théoriquement dans l'unité d'émission, mais celle-ci prend plusieurs formes selon que le processeur utilise l'émission dans l'ordre, dans le désordre, avec une fenêtre d'instruction, avec des stations de réservation, etc. Les processeurs à exécution dans l'ordre sont le cas le plus simple. L'unité d'émission est alors en charge du découpage des macro-opérations en micro-opérations. La file de micro-opération ou le cache de micro-opérations mémorisent des macro-opérations. À l'opposé, le tampon de ré-ordonnancement mémorise lui des micro-opérations. Le reste du processeur n'est pas affecté. Sur les processeurs à exécution dans le désordre, les différences sont nombreuses. Le tampon de ré-ordonnancement peut mémoriser soit les micro-opérations finales, soit des macro-opérations. Il en est de même avec la fenêtre d'instruction et/ou les stations de réservation, qu'elles soient centralisées ou décentralisées. Tout dépend de comment se fait l'implémentation. Une implémentation simple effectue la scission des macro-opérations dans l'unité d'émission, comme sur les processeurs à exécution dans l'ordre. Sur de nombreux processeurs, l'unité d'émission et de renommage sont simplement fusionnées, ce qui fait que la scission a lieu juste après le renommage de registres. En conséquence, le tampon de re-ordonnancement et les fenêtres d'instruction ne voient que des micro-opérations. Les macro-opérations disparaissent juste avant. Cette implémentation est préférée avec une fenêtre d'instruction centralisée, car on voit mal comment scinder une macro-opération juste avant l'ALU. Une autre implémentation fait la scission en sortie de la fenêtre d'instruction ou des stations de réservation, qu'elles soient centralisées ou décentralisées. Dans ce cas, le tampon de re-ordonnancement fait de même. L'avantage est que le tampon de ré-ordonnancement stocke des macro-opérations, ce qui augmente sa taille effective. Par exemple, il utilise une seule entrée pour une instruction ''load-op'', au lieu de deux sans micro-fusion de ce type. ===La délamination=== La scission peut parfois avoir lieu plus tôt, dans des circonstances très précises. Concrètement, cela ne concerne que quelques micro-architectures d'Intel, pour des instructions très précises. La raison est les limitations du format des micro-opérations, pas une histoire d'optimisation. Le processeur aimerait pouvoir faire la micro-fusion, mais ne peut pas à cause de ces limitations. Une telle situation cause alors une '''délamination''' : les micro-opérations sont scindées précocement. Par exemple, sur la micro-architecture SandyBridge d'Intel, les opérations ''load-op'' sont fusionnées, sauf si elles utilisent l'adressage indicé. Les micro-opérations de ce processeur ne peuvent avoir que deux opérandes. Trois opérandes est de trop, et les opérations ''load-op'' en adressage indicé dépassent cette limite. Dans ce cas, les micro-opérations sont fusionnées en sortie du décodeur, mais sont scindés avant d’entrer dans la file de micro-opération. L'avantage n'est pas évident, vu que l'unité de renommage suit de près le décodeur d'instruction. Il est que le cache de micro-opérations mémorise des macro-opérations, pas deux micro-opérations. ===La micro-fusion des processeurs Intel et AMD=== La micro-fusion est apparue sur le Pentium M d'Intel, et a été conservée telle quelle sur les processeurs Intel suivants. Les processeurs AMD supportent la micro-fusion depuis au moins la micro-architecture AMD K8. Mieux que ça, la délamination n'était pas utilisée car les micro-opérations acceptaient plus de 2 opérandes. Que ce soit chez AMD ou Intel, elle concerne deux types d'instructions : les écritures mémoire et les instructions ''load-op''. Sur le Pentium M, il y avait quelques limitations, l'optimisation se limitant par exemple aux registres entiers et flottants, mais pas aux registres MMX, mais pas les registres SSE (nous verrons ces registres dans quelques chapitres). Mais les processeurs modernes n'ont plus cette limitation. La micro-fusion des CPU Intel concerne deux types d'instructions : les écritures mémoire et les instructions ''load-op''. Pour les écritures, la situation est plus complexe que pour les instructions ''load-op''. Sur les processeurs Intel précédents, les écritures étaient réalisées dans deux unités séparées : le calcul d'adresse dans une unité de calcul, l'écriture proprement dite dans l'unité mémoire. Elles prenaient donc deux micro-opérations. Le processeur a changé ses unités mémoire, ce qui fait qu'elle pouvait faire les deux en une seule micro-opération. Il s'agissait alors d'une optimisation du chemin de données, plus que de la micro-fusion proprement dite, mais je la mentionne ici malgré tout. La micro-fusion sur ce processeur avait un avantage en plus des avantages usuels : elle utilisait mieux les décodeurs. Les Pentium M avaient trois décodeurs pour décoder plusieurs instructions en même temps, chose qu'on détaillera dans le chapitre sur les processeurs superscalaires. Un seul décodeur pouvait décoder toutes les instructions, les deux autres ne peuvent décoder que les instructions simples, qui se décodent en une seule micro-opération. Avec la micro-fusion, les trois décodeurs peuvent gérer les écritures mémoire et les opérations ''load-op'', vu qu'elles deviennent des instructions simples. Sans cela, elles auraient été limitées au premier décodeur. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Le parallélisme mémoire | prevText=Le parallélisme mémoire | next=Les microarchitectures pour le x86 : haute performance | nextText=Les microarchitectures pour le x86 : haute performance }} </noinclude> dba3lz5079dx0dl8b1m616yxdamsr91 773635 773585 2026-09-29T21:17:51Z Mewtow 31375 773635 wikitext text/x-wiki Les processeurs vus auparavant ne peuvent émettre au maximum qu'une instruction par cycle d'horloge. Ils peuvent avoir plusieurs instructions qui s'exécutent en même temps, dans des unités de calcul séparées. C'est le cas dès qu'une instruction multi-cycles s'exécute. Par contre, ils ne peuvent démarrer qu'une seule instruction par cycle. Et quand on court après la performance, ce n'est pas assez ! Les concepteurs de processeurs ont inventés des processeurs qui émettent plusieurs instructions par cycle : les '''processeurs à émissions multiples'''. Un processeur à émission multiple charge plusieurs instructions en même temps, les décode en parallèle, puis les émet en même temps sur des unités de calculs séparées. Pour cela, il faut gérer les dépendances entre instructions, répartir les instructions sur différentes unités de calcul, et cela n'est pas une mince affaire. En général, pour un processeur à émission multiple capable d'émettre N instructions en parallèle, on parle de '''processeur à N voies''', ou encore un ''processeur à N pipelines''. [[File:Superscalarpipeline.svg|centre|vignette|upright=1.5|Pipeline RISC classique à cinq étages sur un processeur superscalaire. On voit bien que plusieurs instructions sont chargées en même temps.]] Les processeurs à émission multiple sont de deux types : les processeurs VLIW et les '''processeurs superscalaires'''. Nous mettons les processeurs VLIW de côté en attendant le prochain chapitre. La raison est qu'ils ont un jeu d'instruction spécialisé qui expose le parallélisme d'instruction directement au niveau du jeu d'instructions, là où les processeurs superscalaires restent des processeurs au jeu d'instruction normal. La différence principale entre processeur VLIW et superscalaire est qu'un processeur superscalaire répartit les instructions sur les unités de calcul à l’exécution, là où un processeur VLIW délègue cette tâche au compilateur. ==Le nombre de voies d'un processeur superscalaire== Les processeurs superscalaires les plus simples ne permettent que d'émettre deux micro-opérations à la fois, d'où leur nom de processeur ''dual issue'', ce qui se traduit en '''processeur à double émission'''. Les processeurs triple émission permettent eux d’émettre trois instructions à la fois. A l'opposé, les CPU superscalaires les plus puissants peuvent émettre jusqu'à 8-10 instructions simultanément. En 2026, les CPU superscalaires peuvent monter jusqu’à 10 µops émises en même temps, ce qui est énorme ! Et cela nous amène à faire une distinction entre les processeurs superscalaires dits '''étroits''' et ceux dits '''larges'''. Dans ce wikilivre, on part du principe que les processeurs superscalaires étroits émettent jusqu'à 4-5 µops à la fois, alors que les larges peuvent en émettre plus, l'intervalle entre les deux est une zone grise. Le nombre exact n'est pas fixé dans le marbre, la distinction est volontairement vague. Nous parlerons de la '''largeur d'un CPU superscalaire''' pour parler du nombre de voies, du nombre de µops émises en même temps. Plus un CPU superscalaire est large, plus il est performant ''toutes choses égales par ailleurs''. Mais dans les faits, vous pouvez oublier la partie en italique. Élargir un CPU superscalaire demande de rajouter beaucoup de circuits. Et ce cout en circuit aura un impact sur la performance. À budget en transistors limité, il y a un compromis entre élargir un CPU et rajouter du cache ou la taille des ''schedulers''/ROB et autres. ===Les contraintes d’appariement=== Prenons un processeur double émission, capable d'émettre deux instructions simultanément. Émettre deux instructions en même temps n'est pas toujours possible. Par exemple, si deux instructions sont dépendantes, on ne peut pas les émettre en même temps. Mais oublions un instant ces histoires de dépendances de données, et partons du principe que le CPU ait affaire à deux instructions indépendantes, une paire idéale. Un CPU double émission "parfait" pourrait exécuter n'importe quelle paire d'instruction. Par exemple, il pourrait émettre deux multiplications consécutives, deux lectures consécutives, une lecture et une écriture en même temps, etc. En pratique, aucun processeur ne permet cela. Implémenter un CPU superscalaire "parfait" aurait un cout en circuit beaucoup trop conséquent. Par exemple, pour émettre deux multiplications en même temps, il faudrait deux multiplieurs séparés. Idem pour exécuter deux accès mémoire simultané : cela demande d'avoir deux unités mémoire et un cache multiport. Mais en pratique, aucun CPU superscalaire ne fait cela. La totalité des CPU double émission se débrouille avec un seul circuit multiplieur et une seule unité mémoire. Et cela entraine l'apparition de dépendances structurelles, qui font que certaines paires d'instructions sont impossibles. Par exemple, impossible d'émettre deux multiplications en même temps avec un seul circuit multiplieur. Mais émettre une multiplication en parallèle d'une addition est parfaitement possible. Il y a donc des paires d'instructions autorisées et des paires interdites. Et la logique est la même sur les CPU à triple ou quadruple émission, et au-delà. : des triplets ou quadruplet d'instructions sont impossibles à émettre simultanément, alors que d'autres le sont. Pour le dire autrement, il y a des '''contraintes d'appariement''' sur les instructions à émettre en même temps. ===L'impact des contraintes d’appariement sur la performance=== Ces contraintes d’appariement ont un impact sur les performances, mais celui-ci peut être grandement mitigé. Les programmes informatiques utilisent en pratique beaucoup plus d'opérations entières de base que de multiplication, branchements et accès mémoire. Il y a environ 5 opérations entières de base pour une multiplication entière. En pratique, il est rare de devoir exécuter deux multiplications à la fois. Idem pour les décalages et rotations, qui sont assez éloignés les uns des autres. Deux branchements consécutifs sont quant à eux plus fréquents. Deux accès mémoire consécutifs est assez rare, mais ils restent assez proches les uns des autres malgré tout. La conséquence est que certaines paires d'instructions sont privilégiées par rapport au reste. Les paires regroupant deux calculs basiques (additions, soustractions, ...) sont systématiquement supportées, car dupliquer des ALU entières est facile. Les paires regroupant un calcul et une autre instruction sont elles aussi systématiquement supportées. Par contre, les paires avec deux branchements, deux accès mémoire, deux décalages/rotations, ou deux multiplications/divisions sont fréquemment interdites. Seuls les CPU superscalaires larges peuvent les permettre, et encore : sous conditions. Le résultat est que le processeur peut se débrouiller avec une seule unité mémoire et une unité de branchement. ===Terminologie pour la suite du chapitre=== Décrire les contraintes d’appariement demande de dire quelles combinaisons d’instructions sont autorisées ou interdites. Et pour cela, nous allons introduire les abréviations suivantes : * INT est un raccourci pour parler d'une opération entière simple, qu'une ALU entière peut exécuter. * MUL correspond à une opération entière complexe, typiquement une multiplication, éventuellement à une division. * FLOAT désigne une opération flottante, peut importe laquelle. * MEM désigne un accès mémoire, à savoir une instruction ou µop mémoire. * BRANCH désigne une instruction de branchement. Cette terminologie permettra de définir des paires d'instructions, qu'elles soient possibles ou interdites. Par exemple, l'expression INT + FLOAT désigne une paire d'instruction regroupant une instruction entière et une instruction flottante, peu importe l'ordre des deux instructions. Il en sera de même pour les triplets, quadruplets, ou plus. Par exemple, l'expression INT + INT + FLOAT + MUL désigne un quadruplet d'instructions regroupant : deux instructions entières, une instruction flottante, et une multiplication entière. J'utiliserais aussi des parenthèses pour regrouper certaines combinaisons. Par exemple, l'expression INT + (MUL /FLOAT) veut parler d'une paire d'instruction où la première est une opération entière basique, la seconde est : soit une multiplication, soit une opération flottante. ==Le ''front-end'' des processeurs superscalaires== Un processeur superscalaire doit charger, décoder, et exécuter plusieurs instructions par cycle. Par exemple, un processeur triple émission doit charger 3 instructions lors d'un premier cycle, puis les décoder au cycle suivant, et les exécuter au cycle suivant. Il travaille donc pas paquets de 3 instructions, dans cet exemple. Intuitivement, charger, décoder et exécuter plusieurs instructions à la fois demande de dupliquer des circuits. Par exemple, il faut dupliquer les décodeurs pour décoder plusieurs instructions. Les unités de calcul sont aussi dupliquées, sauf sur certains processeurs qui arrivent à ruser, mais laissons cela de côté pour plus tard. Mais d'autres circuits sont simplement modifiés, comme l'unité de chargement ou l'unité d'émission. Voyons ce qu'il en est dans le détail. {|class="wikitable" |- ! rowspan="2" | Processeur sans émission multiple | rowspan="2" | Chargement | rowspan="2" | Décodage | rowspan="2" | Renommage | rowspan="2" | Émission | Exécution / ALU | rowspan="2" | ''Commit''/ROB |- | Exécution / ALU |- ! rowspan="4" | Processeur superscalaire | rowspan="4" | Chargement | rowspan="2" | Décodage | rowspan="4" | Renommage | rowspan="4" | Émission | Exécution / ALU | rowspan="4" | ''Commit''/ROB |- | Exécution / ALU |- | rowspan="2" | Décodage | Exécution / ALU |- | Exécution / ALU |} Nous allons d'abord voir ce qu'il en est pour le ''front-end'', à savoir la partie du CPU qui s'occupe de charger et décoder les instructions. Elle regroupe l'unité de chargement, les décodeurs, l'unité de prédiction de branchement, la file de µops, la file d'instruction, et divers caches. En soi, les changements portent surtout sur l'unité de chargement et les décodeurs. ===Le chargement de plusieurs instructions consécutives=== Un processeur superscalaire charge plusieurs instructions en même temps, ''en tenant compte de la présence de branchements''. La partie en italique est importante et elle a une conséquence très forte : la manière de faire est fortement différente entre un CPU superscalaire étroit et large. Un CPU superscalaire étroit fait au plus simple : il charge un bloc de 2, 3, 4 instructions consécutives en mémoire RAM. Il faut alors doubler/tripler/quadrupler la taille du bus connecté au cache d'instruction. Par exemple, pour charger quatre instructions de 32 bits chacune, il suffit de lire un bloc de 128 bits dans le cache d'instruction. Un bloc de 8, 16, 32 octets est donc lu depuis le cache et est ensuite découpé en instructions, envoyées chacun à un décodeur. Charger plusieurs instructions consécutives ne marche bien qu'en absence de branchements. La présence de branchements casse cette dynamique, et il faut gérer leur présence. * Sans prédiction de branchement, toutes les instructions d'un bloc sont décodées et exécutées en même temps, même s'il y a un branchement dans le tas. * Avec prédiction de branchement, les instructions situées après le branchement ne sont pas décodées ni exécutées. L'unité de chargement coupe le bloc chargé au niveau du premier branchement pris, remplit les vides avec des NOP, avant d'envoyer le tout à l'unité de décodage. Les instructions à l'adresse de destination seront chargées au cycle suivant, en chargeant un nouveau bloc. [[File:Fetch sur un processeur superscalaire avec prediction de branchements.png|centre|vignette|upright=2|Fetch sur un processeur superscalaire avec prédiction de branchements.]] Un autre défaut est que sur le CPU charge un bloc de 128 bits à la fois, les instructions doivent être alignées sur 128 bits. Et on peut généraliser à n'importe quelle taille de bloc. Si les instructions ne sont pas alignées, il faut gérer la situation. Il arrive qu'une instruction soit à cheval sur deux blocs, avec un morceau dans le premier bloc, un autre dans le second. Dans ce cas, l'instruction est chargée en deux fois, et des circuits doivent gérer la situation pour recoller les morceaux. Sur les CPU avec des instructions de taille fixe, le problème ne survient que rarement. Mais il est fréquent avec des instructions de taille variable. Un autre défaut est lié aux branchements. Imaginez qu'un branchement s'exécute et branche vers une instruction de destination. Rien n'indique que l'instruction de destination sera au tout début d'un bloc. Si ça se trouve, elle sera en troisième position d'un bloc de 4 instructions. Une solution simple charge le bloc en respectant l'alignement, et les deux premières instructions du bloc ne sont pas à exécuter. Il y a donc une petite perte de performance. Certains CPU, comme l'IBM RS/6000, ont la machinerie charger un bloc de N instructions même s'il n'est pas aligné. La machinerie en question se trouve dans le cache d'instruction et est tout sauf simple à expliquer, ce qui fait que je me permets de la passer sous silence. Un détail, cependant : elle ne permet pas de charger des blocs qui sont à cheval sur deux lignes de cache. ===Le décodage parallèle des instructions=== Pour le décodage des instructions, plusieurs instructions sont décodées en même temps. On parle alors de '''décodage parallèle'''. Pour ce faire, un processeur superscalaire contient plusieurs décodeurs, chacun pouvant décoder une instruction en parallèle des autres. Prenons par exemple un processeur superscalaire à 4 voies : le décodage se fera dans quatre décodeurs séparés, qui fonctionneront en parallèle. Cependant, cette implémentation ne marche bien que pour les processeurs RISC, les processeurs CISC devant faire avec un microcode gourmand en circuits. Les processeurs CISC utilisent des décodeurs hybrides, avec un microcode qui complémente un décodeur câblé. Dupliquer le microcode aurait un cout en transistors trop important, ce qui fait que seuls les décodeurs câblés sont dupliqués. Les CPU CISC superscalaires disposent donc de plusieurs décodeurs simples, capables de décoder les instructions les plus courantes, avec un seul microcode. La conséquence est qu'il n'est pas possible de décoder deux instructions microcodées en même temps. Par contre, il reste possible de décoder plusieurs instructions non-microcodées ou une instruction microcodée couplée à une instruction non-microcodée. Vu qu'il est rare que deux instructions microcodées se suivent dans un programme, le cout en performance est extrêmement mineur. Il faut noter qu'une instruction correspond à une ou plusieurs µops. Il est donc possible de charger 5 instructions et de se retrouver avec 8 µops en sortie des décodeurs. Et c'est la source d'une distinction très importante. Plus haut, j'ai parlé de processeurs superscalaires à N voies. La terminologie peut avoir deux interprétations. La première est que le processeur charge/décode N instructions à la fois. Une seconde est qu'il est capable d'exécuter/émettre N µops en même temps. Les deux ne sont pas équivalentes, vu qu'un processeur superscalaire peut, par exemple, charger/décoder N instructions et émettre/exécuter N+2 µops. La distinction est particulièrement importante sur les processeurs superscalaires larges. Certains d'entre eux sont capables de charger 5 instructions et d'en émettre le double ! Un exemple classique était les processeurs Athlon d'AMD, qui pouvaient décoder deux instructions par cycle, mais émettre 4 µops par cycle. Ce n'était pas un problème, car beaucoup d'instructions, même basiques, étaient décodées en 2 µops. ===L'émission parallèle des instructions=== La superscalarité modifie en profondeur l'unité d'émission, notamment au niveau de son interface. Avant, elle recevait une micro-opération sur son entrée, et fournissait la micro-opération émise sur une sortie. Et cela vaut aussi bien pour une unité d'émission simple, un ''scoreboard'', un ''scheduler'' ou des stations de réservation. Mais avec l'émission multiple, les sorties et entrées sont dupliquées. Pour la double émission, il y a deux entrées vu qu'elle doit recevoir deux micro-opération décodées/renommées, et deux sorties pour émettre deux micro-opérations. Dans ce qui suit, nous ne parlerons pas d'entrée et de sortie, mais de '''ports de décodage''' et de '''ports d'émission'''. Les ports de décodage reçoivent des micro-opérations provenant de l'unité de décodage, les ports d'émissions sont pour les micro-opérations émises. Les ports d'émission injectent les micro-opérations émises dans le pipeline, elles sont propagées au banc de registre, aux ALUs, etc. Un processeur superscalaire a forcément plusieurs ports d'émission (et de décodage). Si l'interface de l'unité d'émission change, l'intérieur est tout autant modifié. Sur un CPU non-superscalaire, l'unité d'émission reçoit une µop "candidate à l'émission", et détecte les dépendances entre avec les µops en vol, en cours d'exécution dans le pipeline. Et c'est toujours le cas sur les processeurs superscalaires : l'unité d'émission détecte les dépendances entre les µops candidates et les µops en vol. Mais avec la siperscalarité, elle doit en plus tester les dépendances entre les µops candidates. Si l'unité d'émission est un ''scoreboard'', il doit détecter les dépendances entre instructions émises simultanément et les sérialiser si besoin. Avec un ''scheduler'', il n'y a pour ainsi dire rien à faire, vu que les dépendances sont éliminées par le renommage de registre et que les signaux de réveil gèrent les dépendances RAW. C'est la raison pour laquelle les processeurs superscalaires modernes n'utilisent pas de ''scoreboard''. ==Les processeurs implémentés avec plusieurs pipelines== Nous venons de voir comment la superscalarité impacte le ''front-end'', il est maintenant de voir ce qu'il en est de l'unité d'émission et des ''back-ends''. Un processeur superscalaire peut utiliser l'exécution dans le désordre et le renommage de registres, mais ce n'est pas une obligation. Historiquement, les premiers processeurs superscalaires n'utilisaient pas d'exécution dans le désordre. Le meilleur exemple est celui du Pentium 1 et 2 d'Intel. Ils étaient tous deux des processeurs superscalaires, mais n'avaient pas d'exécution dans le désordre, qui est apparue sur le Pentium 3. les explications sont plus simples si on met de côté l'exécution dans le désordre. Vous vous dites que l'implémentation d'un processeur superscalaire n'est pas la même suivant que le CPU utilise l'exécution dans le désordre, ou non. Mais dans les faits, la distinction est plus subtile que ca. Pour l'expliquer, je vais utiliser une classification originale, qui sépare les processeurs superscalaires en trois sous-types. La distinction se fait sur la manière dont la superscalarité est implémentée en matériel.La classification que j'utilise distingue : * Les processeurs avec plusieurs pipelines, sans exécution dans le désordre. * Les processeurs superscalaires avec un pipeline dynamique. * Les processeurs avec des ''schedulers'' décentralisées. La distinction n'est pas qu'une question d'implémentation matérielle. Elle impacte aussi le ratio entre instructions chargées/décodées et instructions émises. Vous vous dites que les deux sont égales, mais ce n'est le cas que sur les processeurs avec N pipelines ! Sur les autres processeurs, il est possible de décoder 4 instructions, mais d'en émettre maximum 6 par cycle ! Et sur les CPU avec des ''schedulers'' décentralisées, il y a aussi une différence entre le nombre d'instructions qui sont ''dispatch'' et ''schedule''. La catégorie la plus simple est celle des '''processeurs avec plusieurs pipelines'''. Ce sont des processeurs superscalaires sans exécution dans le désordre. Ils partent d'un processeur non-superscalaire, et ajoutent un second pipeline, en sortie de l'unité d'émission. Le second pipeline permet l'émission parallèle d'une seconde instruction. Le second pipeline n'est pas identique au pipeline originel, sur plusieurs points. Premièrement, il n'a pas exactement les mêmes circuits. Le second pipeline est généralement composé d'une unité de calcul, d'une FPU, éventuellement d'un second banc de registres, guère plus. Il permet d'exécuter une seconde opération de calcul, pas plus, ce qui est à l'origine de contraintes d'appariement assez fortes. De plus, il n'a pas forcément la même longueur, il peut avoir des étages en moins ou en plus. Il s'agit de la forme la plus simple de processeur superscalaire et nous allons leur consacrer cette section. ===La double émission entière-flottante=== L'exemple le plus simple utilise un second pipeline pour les opérations flottantes, séparé du pipeline originel. L'ajout d'un pipeline flottant permet d'émettre une micro-opération entière en même temps qu'une micro-opération flottante, ce qui s'appelle la '''double émission entière-flottante'''. La micro-opération entière s'exécute dans l'ALU entière, la micro-opération flottante dans la FPU. Les exemples les plus notables sont le PA-RISC 7100, le POWER 1 (RIOS .& et .9) et le PowerPC 601. L'Apollo DN10000 et l'Intel i860 utilisaient aussi cette forme de double émission, mais étaient des prototypes de CPU VLIW. [[File:Double émission entière-flottante.png|centre|vignette|upright=2|Double émission entière-flottante]] Pour bien expliquer les choses, prenons le processeur illustré ci-dessous, avec deux ''back-end'' séparés : un pour la FPU, et un autre pour le reste. Les instructions entières et mémoire passent toutes par le ''back-end'' généraliste. [[File:CPU non-superscalaire basique, avec une FPU.png|centre|vignette|upright=1.5|CPU non-superscalaire basique, avec une FPU]] Les deux ''back-end'' sont des pipelines séparés, mais il faut que l'unité d'émission soit spécialement conçue pour en profiter. Un processeur simple émission peut démarrer une seule µop par cycle : soit la µop est envoyée au ''back-end'' flottant, soit elle est envoyée au ''back-end'' général. Avec la double émission entière-flottante, le processeur peut envoyer une µop dans chaque pipeline, à chaque cycle. Vu que la FPU et son banc de registre forment déjà un pipeline séparé, les seules modifications se font au niveau du ''front-end'', unité d'émission inclue. {| |- |[[File:CPU simple émission avec une FPU.png|centre|vignette|upright=1.5|CPU simple émission avec une FPU.]] |[[File:Double émission entière flottante avec un second pipeline.png|centre|vignette|upright=1.5|CPU avec un second pipeline flottant.]] |} Notez que le terme double émission ''entière''-flottante est un peu trompeur. En réalité, la technique permet d'émettre une instruction flottante avec n'importe quelle autre instruction non-flottante, avec des restrictions pour les branchements. Il est par exemple possible d'exécuter un calcul flottant en parallèle d'un accès mémoire. Sur les CPU 32 bits, il est possible de faire les multiplications dans la FPU. Pour rappel, la FPU contient un multiplieur entier 53-54 bits, pour multiplier les mantisses de deux flottants 64 bits, qu'on peut utiliser pour faire les multiplications entières 32 bits. Cela permet d'émettre une multiplication en même temps qu'une opération entière dans l'ALU. Ainsi, le CPU pouvait émettre deux instructions : une opération entière de base, avec soit une multiplication, soit une opération flottante. En clair, une émission de type INT + (MUL /FLOAT). Par contre, on perd la possibilité d'émettre une multiplication entière avec une opération flottante, mais c'était un compromis qui en valait la peine. Le CPU PA-RISC 7100 implémentait cette optimisation. Il s'agissait d'un CPU double émission entière-flottante, qui utilisait donc un partitionnement assez simple. Le combo partitionnement + reconditionnement permettait ici de gagner en performance, pour un cout en matériel très limité. D’autant plus limité que le jeu d'instruction prévoyait le reconditionnement de la FPU. Les multiplications ne lisaient pas leurs opérandes dans les registres entiers, mais dans les registres flottants. ===La double émission entière=== Une autre possibilité ajoute un second pipeline, capable d'exécuter des opérations entières simples, appelé le pipeline entier. Le processeur supporte alors la '''double émission entière''', à savoir qu'ils peuvent émettre une opération entière en plus d'une autre instruction. L'opération entière en question est une opération simple, comme une addition, une soustraction, une opération bit à bit, une comparaison, etc. Les exemples classiques sont les processeurs Intel i960 et Pentium. L'implémentation était différente entre l'i960 et le Pentium : Le Pentium avait une seconde ALU entière, alors que le i960 rusait. Le Pentium dupliquait l'ALU entière, pour créer un second pipeline entier. Sur le Pentium originel, les contraintes d'appariement étaient assez strictes. Le Pentium avait une FPU, mais ne pouvait pas l'utiliser en double émission. Il lui était impossible d'exécuter une opération flottante en même temps qu'une opération entière (branchements inclus). Le Cyrix 6x86 était une sorte de Pentium produit par l'entreprise Cyrix, avec une microarchitecture différente. Il avait des contraintes d’appariement réduites. Par exemple, il pouvait émettre une opération flottante en parallèle d'une opération entière. Nous détaillerons ces processeurs dans le prochain chapitre, qui porte justement sur les CPU superscalaires x86. [[File:CPU simple et double émission avec un second pipeline entier.png|centre|vignette|upright=2.5|CPU simple et double émission avec un second pipeline entier.]] L'Intel i960 n'avait pas de FPU, juste une ALU entière et une unité mémoire. Il utilisait l'unité mémoire comme une seconde ALU entière limitée. Pour rappel, une unité mémoire contient une AGU, à savoir une ALU spécialisée dans les calculs d'adresse. Elle est capable de faire des additions, soustractions, et quelques décalages limités (des décalages par 2, 4, 8, pas plus). L'Intel i960 ajoutait des connexions entre AGU et banc de registre, afin que celle-ci serve de seconde unité de calcul. L'AGU est déjà reliée aux deux ports de lecture, pour lire les opérandes du calcul d'adresse, il suffit de la connecter sur le port d'écriture. Le processeur peut alors émettre deux instructions/µops entières, sous certaines conditions. [[File:Emission multiple des opérations entières, double émission.png|centre|vignette|upright=2|Émission multiple des opérations entières, double émission.]] ==Les processeurs superscalaires dynamiques== Les processeurs précédents, avec 2 pipelines, avaient une unité d'émission assez simple. Elle avait deux ports de décodage, et deux ports d'émission. Le nombre de ports de décodage et d'émission étaient identiques. Vous vous dites que c'est naturel, et intuitif, que c'est normal pour un processeur superscalaire. Mais en réalité, la majorité des processeurs superscalaires a plus de ports d'émission que de décodage. Expliquer pourquoi va cependant nous demander de parler de comment la superscalarité exploite les unités de calcul. Posons-nous cette question : de combien d'unités un processeur superscalaire a besoin ? Les unités en question ne sont nécessairement des unités de calcul, l'unité mémoire et l'unité de branchement comptent aussi. La réponse dépend du nombre de voies. Si le ''front-end'' charge et décode un paquet de N instructions, exécuter ces N instructions simultanément demandera là aussi au moins N unités de calcul. Notez le terme : ''au moins'', car c'est là tout l'enjeu de cette section. La réponse dépend aussi des contraintes d’appariement. Pour un CPU superscalaire "parfait", sans contraintes d’appariement, toutes les unités doivent être dupliquées, y compris l'unité mémoire. Un processeur à double émission parfaite devrait dupliquer l'ALU entière, le ''barrel shifter'', le circuit multiplieur, la FPU, l'unité mémoire, et l'unité de branchement, ce qui ferait passer de 6 unités à 12. Le cout en circuit est énorme, même pour de la double émission ! Et pour un CPU à N pipelines, le cout en circuit encore plus prohibitif ! En pratique, les processeurs superscalaires qui font ça sont très rares. La majeure partie des processeurs superscalaires utilisent d'autres techniques : le partitionnement, la duplication partielle des ALUs, la duplication des autres unités. ===Le partitionnement des unités fonctionnelles=== Les CPU superscalaires les plus simples ne dupliquent pas leurs unités de calcul, ils se contentent d'exploiter les unités existantes. Et pour expliquer comment, nous allons partir de l'exemple d'un processeur non-superscalaire contient une ALU entière, une FPU, une unité mémoire et une unité de branchement. Les quatre unités peuvent fonctionner en parallèle, à savoir qu'une unité peut exécuter une instruction à elle toute seule, sans interagir avec les autres. Cela suffit pour créer un processeur quadruple émission, qui peut émettre en même temps : une opération entière, une opération flottante, un branchement, un accès mémoire. Le principe marche aussi sur un processeur avec moins de 4 unités, par exemple sans FPU et/ou sans unité de branchement, ou avec au contraire des unités en plus. L'idée générale est d’émettre une µops séparée dans chaque unité fonctionnelle. Utiliser ainsi les unités existantes, pour rendre un CPU superscalaire, s'appelle le '''partitionnement superscalaire'''. Le terme n'est pas beaucoup utilisé en dehors de quelques vieux articles académiques. Le partitionnement est fortement dépendant du jeu d'instruction, car il demande de bien séparer instructions entières, flottantes, branchements et instructions mémoire. Et autant c'est bien le cas sur les CPU RISC, autant les CPU CISC ne sont pas dans ce cas. Les CPU CISC ont des instructions ''load-op'', qui effectuent une instruction arithmétique et une µop mémoire. Et ces instructions sont très compliquées à implémenter avec le partitionnement. Et au-delà de ça, les CPU CISC ont beaucoup d'instructions qui sont décodées en plusieurs µops, à exécuter dans un ordre bien précis. On peut pas émettre les µops en question simultanément. Le partitionnement a un cout en circuit très limité, pour un gain en performance lui aussi limité. Pour reprendre le CPU de l'exemple précédent, il est rare que l'on ait à exécuter ces quatre instructions en même temps. En pratique, les combinaisons fréquentes sont les combinaisons calcul + accès mémoire, calcul + branchement, calcul entier + calcul flottant. Utiliser une quadruple émission de ce type n'est donc pas une bonne idée, alors que la double émission parait plus adaptée. Et c'est là que la différence entre ports d'émission et de décodage devient intéressante. L'idée est d'avoir une unité d'émission avec deux ports de décodage, et 4 ports d'émission (un par unité). Les contraintes d’appariement varient alors suivant le processeur, mais la règle générale est que si deux micro-opérations tombent dans deux unités différentes, on peut les émettre en même temps. En clair, on peut émettre une opération entière avec une opération flottante, une opération entière avec un branchement, un accès mémoire avec un branchement, etc. Et cela rend le partitionnement bien plus intéressant que prévu. Les tout premiers CPU superscalaires étaient des CPU double émission, qui utilisaient le partitionnement avec : une ALU entière, une unité mémoire et une FPU. Nous parlerons de '''partitionnement INT-FLOAT-MEM'''. L'avantage sur la double émission flottante est que les combinaisons INT + MEM et FLOAT + MEM étaient autorisées. L'intérêt était d'émettre une opération en parallèle d'un accès mémoire, ce qui est un doublet d'instruction assez fréquent. Les exemples classiques sont l'HyperSPARC, de l'alpha 21064 et du PowerPC 603. Les contraintes d’appariement variaient grandement suivant le processeur. Le PowerPC 603 implémentait une double émission "parfaite". C'est à dire que toutes les combinaisons possibles à deux instructions étaient possibles, que ce soit INT + FLOAT, INT + MEM, FLOAT + MEM. En plus de cette double émission "parfaite", le CPU utilisait la technique dite de ''branch folding'', qui permettait d'exécuter un branchement sans utiliser d'unité de calcul, ce qui fait qu'il était qualifié de ''CPU 2-way + Branch''. A l'opposé, le processeur alpha 21064 avait pas mal de contraintes d’appariement, à savoir que certaines combinaisons de deux instructions étaient interdites, bien que compatibles avec les unités disponibles. Une des raisons est que le banc de registre n'avait pas assez de ports de lectures, ce qui fait que certaines combinaisons avec une écriture mémoire n'étaient pas permises. Les concepteurs avaient volontairement inséré ces contraintes afin de simplifier le design du processeur. Avant de poursuivre, précisons que la FPU regroupe un additionneur flottant et un multiplieur flottant. Et ce fait peut être exploité pour approfondir le partitionnement. La '''double émission FADD/FMUL''' permet d'émettre une addition flottante en même temps qu'une multiplication flottante. Elle a été utilisée sur les processeurs x86, Alpha et SPARC. Les autres circuits de calcul flottant sont souvent regroupés avec l'additionneur. La division est parfois e même port que le multiplieur flottant, parfois sur celui de l'additionneur (quand elle est microcodée et exécutée en enchainant les soustractions). ===La duplication des ALU entières=== Le partitionnement est une technique élégante, simple, facile à implémenter et au cout en circuits modeste. Mais il faut avouer que cela ne donne pas des CPU superscalaires très efficaces. La raison est que le partitionnement permet d'émettre des paires, triplets, quadruplets de micro-opérations qui sont rares en pratique. Les combinaisons les plus fréquentes en pratique sont des paires/triplets d'opérations entières, souvent des paires/triplets d'additions ou d'opérations entières simples. Il est donc primordial d'émettre plusieurs opérations entières simultanément. Le fait d'émettre et d'exécuter plusieurs opérations entières en même temps s'appelle l''''émission entière multiple'''. Pour exécuter la seconde/troisième opération entière, il faut dupliquer les ALU entières (ou réutiliser l'AGU comme ALU entière comme le fait l'Intel i960). Le processeur doit avoir deux ALU entières pour de la double émission entière, trois pour de triple émission entière, etc. De plus, il faut ajouter des ports au banc de registre, pour lire deux fois plus d'opérandes et décrire deux résultats. Et enfin, il faut rajouter un port d'émission pour pouvoir émettre une micro-opération entière en plus. [[File:Processeur non-superscalaire basique 03.png|centre|vignette|upright=2|Processeur non-superscalaire basique]] La tendance est de multiplier les ALU entières, mais pas le circuit multiplieur. Le cout en transistors est alors grandement réduit, au prix de l'apparition de dépendances structurelles. Le CPU peut émettre deux additions en même temps, ou une addition et une multiplication, mais pas deux multiplications. Il en est de même avec le ''barrel shifter'', qui n'est pas dupliqué. Il est donc possible d'émettre un décalage avec une opération de base, mais pas deux décalages en parallèle. Mais ces contraintes d’appariement ne sont pas un problème, car il est rare de devoir émettre deux multiplications/décalages en même temps. La plupart des programmes sont majoritairement remplis d'additions, avec des multiplications assez rares et des décalages qui le sont encore plus. La moyenne est proche d'une multiplication pour 4/5 additions. Vu que des multiplications consécutives sont très rares, dupliquer le multiplieur est presque inutile. Disposer de plusieurs circuits multiplieurs ou de plusieurs ''barrel shifters'' serait donc un cout en circuits qui ne servirait que rarement et n'en vaut pas la chandelle. Il faut noter que sur les CPU 32 bits, les multiplications peuvent être exécutées dans la FPU ou dans un multiplieur séparé, tout dépend de si le CPU exécute les multiplications dans la FPU ou pas. {|class="wikitable" |- ! Voie d'émission n°1 !! Voie d'émission n°2 !! Voie d'émission n°3 |- | ALU entière || ALU entière || FPU |} Reste à connecter les unités de calcul à l'unité d'émission (indirectement, car il y a des étages de pipeline entre les deux). Une implémentation basique utilisée un port d'émission par unité. Prenons l'exemple d'un CPU superscalaire avec 4 ALU entières, une FPU, et une unité mémoire. Vu qu'il y a 6 unités, cela fait donc 6 ports d'émission. L'exemple historique le plus impressionnant est celui du Motorola 88110, un CPU double émission qui possède 10 unités. Il contient deux ALU entières, un circuit multiplieur, un circuit diviseur, une unité de manipulation de bits, une unité mémoire, un additionneur flottant, et deux unités graphiques pour des calculs impliquant des pixels. Le multiplieur est utilisé à la fois pour les multiplications entières, flottantes et le produit de deux pixels. Idem pour le diviseur, qui sert pour les divisions entières et flottantes. Et chaque unité a son propre port d'émission. La conséquence est que les contraintes d'appariement du Motorola 88110 sont simples : tant que deux µops atterrissent dans des unités séparées, la paire est permise. Il est par exemple possible d'émettre simultanément deux opérations entières simples, vu qu'il y a deux ALU. Par contre, impossible d'émettre simultanément deux multiplications, deux divisions, deux opérations flottantes, deux manipulations de bit, deux accès mémoire, etc. De plus, le partage du multiplieur fait qu'on ne peut pas émettre une multiplication entière avec une multiplication flottante. Idem avec les divisions, vu que le diviseur est aussi partagé. Ce sont les seules contraintes. ===Le partage des ports d'émission=== La présence d'un circuit multiplieur et d'un ''barrel shifter'' pose des problèmes pour le partitionnement. Il est possible d'avoir un port d'émission dédié au multiplieur, et un autre au ''barrel shifter'', qui sont séparés de ceux pour l'ALU entière. Il est alors possible d'émettre une opération entière, une multiplication et un décalage, simultanément. Nous parlerons de '''partitionnement entier''' pour désigner cette possibilité. [[File:Partitionnement superscalaire entier.png|centre|vignette|upright=2|Partitionnement superscalaire entier.]] Le partitionnement entier est cependant très rare, car le gain en performance serait trop faible au regard des couts en circuit. Quelques processeurs historiques l'utilisaient, mais ce n'est plus le cas de nos jours. La raison est que les multiplications et les décalages sont assez rares dans le code, ce qui fait que le port d'émission associés sont sous-utilisés. Et un port d'émission a un cout en circuit assez important. Et c'est sans compter qu'ajouter des ports sur le banc de registres juste pour un multiplieur sous-utilisé n'en vaut pas la peine. L'idéal serait de trouver un moyen de réduire le nombre de ports d'émissions, sans réduire le nombre d'unités de calcul. [[File:Emission multiple des opérations entières, implémentation naive.png|vignette|Émission multiple des opérations entières, implémentation naive]] La solution consiste à '''partager les ports d'émission''', à savoir connecter un port d'émission à plusieurs unités de calcul. L'exemple classique est justement lié aux circuits multiplieur et ''barrel shifters''. L'idée est que le multiplieur et le ''barrel shifter'' sont mis sur le même port d'émission qu'une ALU entière. Prenons par exemple le processeur à double émission entière illustré ci-contre. Un port d'émission est relié à une ALU entière seule, et l'autre port d'émission alimente la seconde ALU entière et le multiplieur. La conséquence est que le processeur peut émettre deux opérations entières, dont une multiplication. Si on avait utilisé un port d'émission dédié au multiplieur, il aurait été possible d'émettre deux opérations entières et une multiplication. On perd donc une voie, mais on gagne en flexibilité et on économise des circuits. Notons que ce partage signifie aussi que le multiplieur partage les ports sur le banc de registre, ce qui fait une double économie. [[File:Emission multiple des opérations entières, implémentation courante.png|centre|vignette|upright=1.5|Émission multiple des opérations entières, implémentation courante]] En général, le ''barrel shifter'' et le multiplieur sont placés sur deux voies d'émission séparés, ce qui permet d'émettre un décalage et une multiplication en même temps. Les mettre sur le même port ne le permettrait pas. {|class="wikitable" |- ! Voie d'émission n°1 !! Voie d'émission n°2 !! Voie d'émission n°3 |- | * ALU entière * Multiplieur | * ALU entière * Barrel shifter | FPU |- | * Additions, soustractions, opérations bit à bit, etc. * Multiplication | * Additions, soustractions, opérations bit à bit, etc. * Décalages et rotations | Opération flottante |} Terminons concernant les multiplieurs avec une dernière subtilité. Pour rappel, les processeurs modernes intégrent en réalité deux multiplieurs différents. Le résultat d'une multiplication est très large et prend deux registres. Par exemple, une multiplication de deux opérandes 64 bits donne un résultat sur 128 bits, ce qui ne tient pas dans un registre, mais en prend deux. L'instruction de multiplication classique ne calcule que les 64 bits de poids faible. mais elle est complétée par d'autres instructions de multiplication qui peuvent faire le calcul complet. Pour résoudre le problème, les processeurs modernes intègrent deux instructions de multiplications : une qui calcule les bits de poids faible du résultat, une autre qui calcule les bits de poids fort. Et ces deux instructions sont associées à deux multiplieurs séparés, aux circuits différents. Le multiplieur qui calcule les bits de poids faible du résultat est appelé le ''low multiplier'', l'autre est appelé le ''high multiplier''. Le second multiplieur est souvent placé sur un second port d'émission, différent du premier multiplieur, partagé avec une ALU. L’avantage de mettre les deux multiplieurs sur deux ports d'émission différents est qu'une multiplication complète peut être réalisée en utilisant les deux multiplieurs en parallèle. Les deux sous-multiplications sont émises en même temps, exécutées en même temps. pas besoin d'exécuter l'une puis la seconde, d'où un gain performance appréciable. Nous venons de voir comment partager un port d'émission entre une ALU et un multiplieur. Mais au-delà de cet exemple, le partage des ports d'émission peut appliquer à n'importe quelle unité. Prenons l'exemple d'un CPU superscalaire avec 4 ALU entières, une FPU, et une unité mémoire. Vu qu'il y a 6 unités, cela fait donc 6 ports d'émission. Cependant, il est rare qu'un bloc de 6 instructions contienne exactement 4 opérations entières, une opération flottante, et un accès mémoire. Beaucoup de ports d'émission seraient sous-utilisés. La solution est de partager des ports d'émission, pour passer à la quadruple émission. Le CPU peut alors répartir 4 instructions sur les ports d'émission adéquats, à chaque cycle. Le CPU a donc 4 ports de décodage et 6 ports d'émission. Une implémentation classique permet n'importe quelle combinaison de 4 instructions compatibles avec les 6 unités. Par exemple, il devient possible d'émettre simultanément 4 additions, la combinaison 2 * INT + FLOAT + MEM, 3 * INT + MEM, et bien d'autres. L'exemple relie une ALU entière, la FPU et l'unité mémoire sur le même port. Le CPU a alors quatre ports d'émission, qui ne sont pas "identiques". Trois d'entre eux sont reliés à une ALU entière chacun, rien d'autre. Le quatrième est lui relié à une ALU entière, la FPU et l'unité mémoire. On économise alors deux ports d'émission, mais cela entraine l'apparition de contraintes d’appariement. Le CPU peut émettre 3 opérations entières + n'importe quelle autre opération. Mais les autres combinaisons sont interdites. Le CPU peut émettre 6 opérations entières simultanément, grâce à 6 ALU entières. Les accès mémoire ou opérations flottantes ne viennent pas en plus, mais en remplacement des opérations entières. Regrouper plusieurs ALU sur un même port d'émission est donc à l'origine de dépendances structurelles, de nouvelles contraintes d’appariement. Dans certaines situations de '''''port contention''''', on a assez d'ALU pour exécuter N micro-opérations, mais la répartition des ALUs sur les ports l'empêche. Impossible d'émettre deux micro-opérations sur deux ALU si elles sont sur le même port d'émission. On peut réduire les cas de ''port contention'' en répartissant correctement les ALU sur les ports d'émission, mais sans jamais les supprimer complétement. Un exemple est celui du PowerPC 604. Il implémentait la quadruple émission, alors qu'il avait 5 unités de calcul. Mais deux unités partageaient un même port d'émission. Dans le détail, il avait deux ALU entières, un circuit multiplieur/diviseur, une FPU, une unité mémoire. La FPU et le multiplieur étaient sur le même port d'émission. En conséquence, le CPU pouvait émettre seulement les combinaisons INT + INT + MEM + (MUL/FLOAT). : Il est intéressant de voir l'exemple d'un processeur superscalaire parfait, sans contraintes d'appariement, à N voies. Pour cela, on part d'un processeur non-superscalaire, avec M unités de calcul. Un tel processeur peut s'implémenter avec N ports d'émission, chacun relié à M unités de calcul possibles, ce qui fait que les M unités de calcul sont dupliquées en N exemplaires. Si on prend par exemple un CPU non-superscalaire avec une ALU, une FPU, une unité mémoire et une unité de branchement, un port d'émission sera relié à une ALU, une FPU, une unité mémoire et une unité de branchement. ===La duplication des autres unités fonctionnelles=== Dupliquer les ALU entière est une première étape, mais il est aussi possible de dupliquer les autres unités fonctionnelles. Par exemple, il est possible de dupliquer l'unité mémoire ou l'unité de branchement. Reste à voir quelles unités dupliquer, et pourquoi. Précisons que dans ce qui va suivre, nous allons parler de la duplication des unités en général, pas seulement des unités mémoire/branchement. Nous allons continuer de parler de la duplication des ALU entières dans ce qui suit, mais de manière plus générale. Pour un processeur à N voies, il est théoriquement possible de dupliquer toutes les unités en N exemplaires. Mais ce n'est jamais fait en pratique, car le cout en circuits serait trop important et le gain en performance trop faible. Mieux vaut dupliquer certaines unités bien précises, quitte à avoir des contraintes d'appariement. Et à ce petit jeu, toutes les duplications ne se valent pas, certaines sont plus rentables en matière de performance, le cout en circuit n'est pas le même selon l'unité, etc. La rentabilité en performance dépend surtout des contraintes d'appariement. Les contraintes d'appariement entrainent une baisse de performance significatives si elles interdisent des paires d'instructions fréquentes. Aussi, les opérations très fréquentes, souvent appairées, gagnent à dupliquer l'unité associée. Et au contraire, les unités rarement utilisées ne doivent pas être dupliquées. Il se trouve que les unités les plus utilisées sont les ALU entières, suivies par les unités mémoire et l'unité de branchement. Le cout en circuit n'est aussi pas le même. Dupliquer les ALU entière est trivial, car elles ont un budget en transistors assez faible. Les circuits multiplieurs, diviseurs, et les ''barrel shifter'' ont eux un cout en transistor plus élevés. Si on devait faire un classement, on aurait : ALU entière < ''barrel shifter'' < multiplieur. Pour les unités mémoire, le cout en transistor est là aussi conséquent. Le résultat final est que dupliquer les ALU entières est privilégié sur le reste, comme l'a vu dans la section précédente. Les unités mémoire arrivent en seconde place, suivie par les multiplieurs/''barrel shifter'' à la troisième place, et les unités de branchement à la quatrième place. Les CPU superscalaires larges ont donc tendance à multiplier les unités mémoire en second. Les multiplieurs et ''barrel shifters'' sont eux aussi dupliqués sur les CPU superscalaires larges, mais cela vient souvent après avoir dupliqué les unités mémoire. La raison est que les accès mémoire sont critiques pour la performance des CPU à exécution dans le désordre, pas les multiplications. Pour les unités de branchement, une subtilité complique le fait d'en installer plusieurs. Que faire quand deux branchements sont pris ? La solution la plus simple est de ne pas se trouver dans cette situation : on n'utilise qu'une seule unité de branchement et on n’exécute qu'un seul branchement par cycle. La majorité des processeurs superscalaires étroits font ainsi. Les processeurs superscalaires larges ont cependant deux unités de branchements, mais ils n'acceptent qu'un seul branchement pris à la fois. Si les deux branchements pris sont exécutés en même temps, le processeur n’exécute que le plus récent, dans l'ordre du programme. ===Les CPU superscalaires mélangent les trois techniques=== Les CPU superscalaires utilisent toutes les techniques à la fois : partitionnement, duplication de l'ALU entière, duplication des autres unités fonctionnelles. Chaque processeur utilise ces trois stratégies à sa sauce, en fonction de son budget en transistor. Les quatre techniques ont cependant un cout en circuit différent, et donnent des gains de performances eux aussi forts différents. * Le '''partitionnement superscalaire''' a un cout en circuit modéré, car on n'a pas besoin de dupliquer d'ALU. * La '''duplication des ALU entières''' est la technique la plus importante : elle a un cout en circuit modéré, et donne des gains en performance impressionnants. * La '''duplication des autres unités''' a un cout en circuit variable, pour des gains en performance eux aussi variables. * Le '''partage des ports d'émission''' réduit le cout en circuit du CPU, pour des pertes de performances mineures si bien fait. L'usage du partitionnement seul, sans duplication, était surtout le fait des processeurs commercialisés entre les années 1989 et 1993. Le partage des ports d'émission a lui aussi mis un peu de temps pour s'imposer. Globalement, les processeurs superscalaires ont évolués progressivement, pour se rapprocher d'une sorte de standard. Mais pour comprendre ce qu'est ce standard, et en quoi les CPU historiques s'en sont progressivement rapprochés, il faut étudier l'histoire des CPU superscalaires. L'histoire des CPU superscalaires a commencé dès 1960, mais est resté un projet de recherche pendant plusieurs décennies. De nombreux designs ont été conçus, mais abandonnés avant la production, comme l'ACS-1 d'IBM. Les années 1980 ont vu l'arrivée de prototypes de processeurs VLIW, mais qui n'étaient pas superscalaires. Par exemple, l'Apollo DN10000 et l'Intel i860 pouvaient émettre deux instructions à la fois, sous conditions, mais demandaient que le compilateur fasse une bonne partie du travail. Les premiers CPU superscalaires commercialisés sont sortis en 1989. Deux CPUs superscalaires sont sortis cette année-là : le RS/6000 d'IBM et l'i960CA d'Intel. Puis, la compétition s'est aussi lancée dans la bataille. Les CPU commercialisés avant l'année 1993 étaient à double émission, à l'exception du SuperSPARC qui utilisait la triple émission. Les modèles après 1993 hésitaient entre double et quadruple émission. Dans le tableau ci-dessous, les processeurs quadruple émission sont en bleu, les triple émission sont en rouge, les autres ne sont pas en couleur. {|class="wikitable" |- ! !! IBM !! HP PA-RISC !! SPARC !! Intel!! Alpha !! Autres |- ! 1989 | RS/6000 || || || i960CA || || |- ! 1990 | || || || || || |- ! 1991 | || || || || || Motorola 88110 |- ! 1992 | RSC || PA 7100 || class="f_rouge | SuperSPARC || || 21064 || |- ! 1993 | PPC 601 || || HyperSPARC || Pentium || || |- ! 1994 | class="f_bleu | POWER 2 || PA 7200 || || || class="f_bleu | 21164 || |- ! 1995 | 603/604 || class="f_bleu | PA 8000 || class="f_bleu | UltraSPARC 1 || Microarchitecture P6 (+ concurrence AMD) || || class="f_bleu | MIPS R1000 |- ! 1996 | class="f_bleu | 620 || || || || class="f_bleu | 21264 || |- ! ... || ... || ... || ... || ... || ... || ... |} Les premiers CPU à double émission sont assez représentatifs des CPU à double émission modernes. Il faut dire que se limiter à deux voies ne permet pas de faire beaucoup de choses. Voici le tableau chronologique disant quel CPU utilisait quelle technique. * Les CPU en vert utilisaient la double émission entière-flottante. * Les CPU en rouge utilisaient la double émission entière "pure". * Les CPU en jaune utilisaient un ''partitionnement complet'' entre ALU, FPU et unité mémoire. * Les CPU sans couleur utilisaient un grand nombre d'unités, avec beaucoup de ports d'émission. * Les CPU barrés utilisent la triple ou quadruple émission et seront vu dans la section suivante. {|class="wikitable" |- ! !! IBM !! HP PA-RISC !! SPARC !! Intel!! Alpha !! Autres |- ! 1989 | class="f_vert | RS/6000 || || || class="f_rouge | i960CA || || |- ! 1990 | || || || || || |- ! 1991 | || || || || || Motorola 88110 |- ! 1992 | class="f_vert | RSC || class="f_vert | PA 7100 || <s>SuperSPARC</s> || || class="f_jaune | 21064 || |- ! 1993 | class="f_vert | PPC 601 || || class="f_jaune | HyperSPARC || class="f_rouge | Pentium || || |- ! 1994 | <s>POWER 2</s> || PA 7200 || || || <s>21164</s> || |} C'est en 1994, que la quadruple émission est arrivée et que les CPU ont essayé divers implémentations. Il y avait alors trois stratégies pour la double/triple/quadruple émission, qui partageaient des problèmes similaires. La première implémentation dupliquait les ALUs et les FPUs, ce qui permettait d'émettre deux opérations flottantes avec deux opérations entières. Le POWER 2 dupliquait ses FPUs à la perfection, alors que le 21264 séparait l'additionneur et le multiplieur flottant. Les accès mémoire étaient traités comme des opérations entières et le processeur pouvait souvent en émettre deux à la fois. Mais une telle organisation n'est plus utilisée de nos jours, car, sans instructions flottantes à exécuter, elle est équivalente à de la double émission. La seconde implémentation utilisait deux ALU entières (dont un multiplieur), une unité mémoire et une FPU. Cette organisation est intéressante, mais encore trop stricte pour donner de bons résultats, les quadruplets avec exactement deux opérations entières, un accès mémoire et une opération flottante étant trop rares. L'usage de ces 4 unités en double ou triple émission a été utilisé sur le PA 7200 et le SuperSPARC. Malheureusement, en plus de problèmes au niveau de son cache, le SuperSPARC avait de nombreuses contraintes d’appariement, car le banc de registre n'avait pas assez de ports pour alimenter certaines combinaisons d'instructions. De plus, s'il émettait une multiplication, il ne pouvait pas émettre de seconde µop. Enfin, une troisième implémentation utilisait un grand nombre d'unités fort différentes, bien plus que quatre, avec au minimum deux ALU entières. Prenons l'exemple de l'UltraSPARC, qui avait : deux ALU entières, une unité mémoire, une unité de branchement, un additionneur flottant, un multiplieur flottant, un diviseur flottant (aussi utilisé pour le calcul des racines carrées), et 2 unités graphiques pour les calculs sur des pixels. En tout, cela fait 9 unités différentes, pour de la quadruple émission. Dans le même genre, les processeurs MIPS R8000 et R10000 avaient une implémentation plus moderne, dans le sens où toutes les unités étaient dupliquées. Le CPU avait deux ALU, deux FPU et deux unités mémoire. Il pouvait donc émettre quatre instructions à la fois, tant que le paquet collait avec ces six unités. Moitié opérations entières, moitié opérations mémoire, avec de quoi remplacer les opérations entières par des opérations flottantes. Le PA 8000, lui, dupliquait toutes ses unités en deux exemplaires, ce qui n'est pas l'idéal, aucun processeur moderne ne fait cela aujourd'hui. Le tout est résumé dans le tableau ci-dessous, avec : * en vert les CPU utilisant la première stratégie ; * en rouge les CPU utilisant la seconde stratégie ; * en jaune les CPU utilisant la troisième stratégie. {|class="wikitable" |+ Processeurs quadruple émission historiques |- ! Année !! Processeur !! Unités |- ! 1991 | class="f_jaune | Motorola 88110 || class="f_jaune | 2 ALU + MUL + DIV + BIT + MEM + FADD + 2 unités graphiques |- |- ! rowspan="2" | 1994 | class="f_vert | POWER 2 || class="f_vert | 2 ALU/MEM + 2 FPU (+ 2 Branchements via ''branch folding'') |- | class="f_rouge | 21164 || class="f_rouge | 2 ALU + FPU + MEM |- ! rowspan="3" | 1995 | PA 8000 || 2 ALU + 2 ''barrel shifters'' + 2 MEM + 2 FPU (FMA) + 2 FPU (DIV et SQRT) + 2 SIMD |- | class="f_jaune | UltraSPARC 1 || class="f_jaune | 2 ALU + MEM + BRANCH + FADD + FMULFDIV + 2 unités graphiques |- | MIPS R8000 et R10000 || 2 ALU + 2 FPU + 2 MEM |- ! rowspan="2" | 1996 | class="f_rouge | 620 || class="f_rouge | 2 ALU + FPU + MEM |- | class="f_vert | 21264 || class="f_vert | 2 ALU/MEM + 2 FPU (FADD + FMUL) |} Malheureusement, ces CPUs historiques n'avaient ni assez d'unités de calcul entières, ni d'unités mémoire, pour remplir la quadruple émission. Environ la moitié des instructions d'un programme correspond à des instructions entières. Pour en profiter, un processeur à N voies doit disposer d'au minimum N/2 ALU entières, l'idéal étant d'aller au-delà. Les CPU superscalaires historiques avaient 2 ALU pour de la quadruple émission, ce qui était très limite. En comparaison, les CPU superscalaires modernes mettent le paquet niveau ALU entière. La plupart des CPU x86 modernes descendent rarement sous les 2/3, la plupart remplissent presque la totalité de la largeur du CPU. Pour donner un exemple, la microarchitecture Golden Cove d'Intel est un processeur à 6 voies, avec 5 ALU entières. Pour être précis, un programme informatique exécute environ 40% de son code dans des instructions arithmétiques, un autre 40% dans les accès mémoire, et un le reste pour... le reste. La conséquence est que les processeurs modernes dupliquent leurs unités mémoire. Par exemple, la microarchitecture ''Golden Cove'' d'Intel dispose de trois unités mémoire : deux spécialisées dans les écritures, trois dans les lectures. La microarchitecture ''Gracemont'' utilise la pentuple émission et peut émettre 4 µops entières et 4 µops mémoire. Notez que le ratio est équilibré entre opérations entières et mémoire, avec soit égalité, soit un avantage pour les ALU entières. Une autre régularité est que la largeur totale du processeur peut être occupée par des opérations entières/mémoire. Pour le dire autrement, sur un processeur quadruple émission, il pourra émettre un mix de 4 instructions entière/mémoire, avec zéro opération flottante. Idem avec des processeurs triples ou pentuple émission, voire plus. Si le processeur émet une opération flottante, elle remplace une opération entière. Prenons l'exemple des processeurs AMD K6, sortis en 1997, juste avant les AMD Athlon. Ils avaient 10 unités de calcul, 6 ports d'émission, 4 ports de décodage. Voici exactement comment étaient répartie les unités de calcul sur les ports d'émission. C'était des processeurs quadruple émission, ce qui fait que la moitié de la largeur du processeur sert pour des opérations entières, et l'autre moitié pour les accès mémoire. {|class="wikitable" |- ! Port d'émission n°1 !! Port d'émission n°2 !! Port d'émission n°3 !! Port d'émission n°4 !! Port d'émission n°5 !! Port d'émission n°6 ! |- | ALU entière || ALU entière || FPU || Unité de branchement || Unité LOAD || Unité STORE |- | || Multiplieur || || || || Unité de calcul d'adresse (instruction LEA) |- | || ''Barrel shifter'' || || || || Unité pour les instructions PUSH |} Les microarchitectures K7, K8 et K10, utilisées sur les anciens CPU AMD Athlon, sont un exemple moins représentatif. Ces microarchitectures utilisent le partage des ports d'émission au maximum. C'était des microarchitectures à triple émission, avec six ports d’émission. Il y avait trois ports d'émission pour les opérations flottantes, et trois ports d'émission pour les micro-opérations entières/mémoire. Il y avait trois ALU entières et trois unités mémoire, chaque ALU partageait un port d'émission avec une unité mémoire. Elle pouvait donc émettre soit trois opérations entières, soit trois µops mémoire, soit un mix des deux. En plus des mix avec les opérations flottantes et branchements. {|class="wikitable" |- ! Port d'émission n°1 !! Port d'émission n°2 !! Port d'émission n°3 !! Port d'émission n°4 !! Port d'émission n°5 !! Port d'émission n°6 ! |- | ALU entière || ALU entière || ALU entière || FADD || FMUL || FPU (autres opérations) |- | Multiplieur || || || || || |- | LOAD/STORE || LOAD/STORE || LOAD/STORE || || || |} Les CPU superscalaires larges dupliquent les multiplieurs et/ou les ''barrel shifters'', et même les unités de branchement. La raison est que quand la largeur du CPU augmente, le processeur traite des paquets d'instructions de plus en plus gros. Par exemple, pour un CPU à 10 voies, cela veut dire émettre 10 instructions en même temps. Il est alors plus fréquent d'avoir deux multiplications, deux décalages, deux accès mémoire, deux branchements. Par exemple, la moyenne est d'une multiplication tous les 5 instructions. Les CPU superscalaires à 10 voies ont donc tendance à avoir deux multiplications par paquet d'instruction, en moyenne. Avoir deux multiplieurs est alors un gain en performance clair. Par exemple, la microarchitecture ''Golden Cove'' a deux ''barrel shifters''. C'est une architecture à 6 voies. {|class="wikitable" |- ! Port d'émission n°1 !! Port d'émission n°2 !! Port d'émission n°3 !! Port d'émission n°4 !! Port d'émission n°5 !! Port d'émission n°6 !! Port d'émission n°7 !! Port d'émission n°8 !! Port d'émission n°9 !! Port d'émission n°10 |- | ALU entière || ALU entière || ALU entière || ALU entière || ALU entière || LOAD || LOAD || LOAD || STORE || STORE |- | ''Barrel shifter'' || Multiplieur || Multiplieur || ''Barrel shifter'' || || || || || || |- | Branchements || Diviseur || || Branchements || || || || || || |} ==Les µops mémoire sur les processeurs superscalaires== Plus haut, nous avons volontairement passé sous silence les accès mémoire. La raison à cela est que leur support sur les CPU superscalaire peut se faire de plusieurs manières différentes, qu'il vaut mieux expliquer dans une section dédiée. Les différentes implémentations sont décrites dans la liste suivante, nous allons les voir une par une. * Avec la première méthode, les accès mémoire sont exécutés par le pipeline pour les opérations entières. * Avec la seconde méthode, les accès mémoire ont un pipeline dédié ; c'est l'''émission parallèle des accès mémoire''. * Avec la troisième méthode, il est possible d'émettre plusieurs accès mémoire simultanément : c'est l'''émission multiple des accès mémoire''. Voyons ces trois cas dans le détail. Nous verrons notamment les différentes formes d'émission multiple des accès mémoire. ===Les accès mémoire traités dans le pipeline entier=== Dans le cas le plus simple, les accès mémoire sont traités comme des opérations entières un peu spéciales. L'unité mémoire est sur le même port d'émission que l'ALU entière, ce qui fait que les accès mémoire remplacent des opérations entières. Faire ainsi permet d'utiliser une ALU entière pour les calculs d'adresse, pas besoin de rajouter une unité de calcul d'adresse séparée. Typiquement, un processeur de ce type place l'unité mémoire après l'unité de calcul. Les opérations entières n'utilisent que l'ALU entière, mais pas l'unité mémoire. Les accès mémoire exécutent un calcul d'adresse dans l'ALU entière, puis l'adresse calculée est envoyée à l'unité mémoire. Le tout est illustré ci-dessous, dans le cas d'un processeur historique à double émission entière-flottante. [[File:Processeur non-superscalaire basique 01.png|centre|vignette|upright=1.5|Processeur non-superscalaire basique]] Un exemple de CPU double émission de ce type est celui du Power PC 440, un CPU destiné à l'embarqué. Vu qu'il était destiné à l'embarqué, il n'avait pas de FPU, il n'avait pas besoin de manipuler de nombres flottants. Il n'a donc que des ALU entières, un multiplieur et une unité mémoire. Il dispose de deux ports d'émission. Le premier est connecté à une ALU entière et un circuit multiplieur, le second est relié à l'unité mémoire et une seconde ALU entière. Une organisation simple, mais très efficace ! [[File:PowerPC 440.png|centre|vignette|upright=2|Microarchitecture du PowerPC 440.]] L'implémentation économise une unité de calcul d'adresse, mais n'a pas de cout en performance significatif. Les accès mémoire étant très lents, émettre une µop entière en parallèle d'un accès mémoire ne sert pas à grand-chose. On peut émettre cette µop entière un cycle plus tard, elle sera terminée avant même que l'accès mémoire soit terminé, même si l'accès mémoire se fait dans le cache L1 ou L2. Pour comprendre pourquoi, faisons quelques calculs. Un accès mémoire prend deux-trois cycles quand il tombe dans le cache L1. Et on doit attendre qu'il soit terminé pour en émettre un nouveau. Combien d'instructions arithmétiques peut-on lancer pendant ce temps, sur un CPU triple émission ? Au premier cycle, on peut en émettre 2 (l'instruction mémoire prend une place, donc 3-1), puis 3 au second cycle. Ce qui fait 5 instructions arithmétiques au total. Or, il se trouve qu'il y a une instruction d'accès mémoire pour 5 instructions arithmétiques, environ. Par contre, ce compromis change quand on passe à la quadruple émission, voire au-delà. Dans ce cas, il devient intéressant de pouvoir émettre une nouvelle instruction mémoire à chaque cycle. Ce qui nous amène à la section suivante... ===L'émission parallèle des accès mémoire=== A partir de la quadruple émission, la tendance a été de séparer l'unité mémoire des ALU entières. Cela permet d'émettre des µops mémoire en même temps que des µops entières et/ou flottantes., ce qui porte le nom d''''émission parallèle des µops mémoire''', ou encore ''émission mémoire parallèle''. Par exemple, un processeur quadruple émission peut émettre en même temps deux opérations entières, une opération flottante et un accès mémoire. L'accès mémoire vient en plus des opérations entières, il n'est pas possible de remplacer l'accès mémoire par une opération entière. La technique ne permet pas de faire les calculs d'adresse dans l'ALU entière. Il faut donc utiliser une unité de calcul d'adresse séparée. Elle est intégrée dans l'unité mémoire, qui fait l'interface entre le cache et le banc de registres. Le cout en circuits est très faible, car les unités de calcul d'adresse n'utilisent guère plus qu'un additionneur et un circuit de décalage très simple. L'émission mémoire parallèle est plus facile à implémenter sur les CPU RISC, qui ont des instructions mémoire séparées du reste. Les CPU CISC ne sont pas dans ce cas, ce qui fait que séparer l'unité mémoire du pipeline entier est compliqué. Les CPU superscalaires historiques étaient pour moité des CPU RISC et pour moitié des CPU CISC, ce qui fait qu'ils n'utilisaient pas ou peu l'émission mémoire parallèle. Les premiers processeurs superscalaires se contenaient de l'émission parallèle mémoire, ils ne pouvaient émettre qu'un seul accès mémoire à la fois, l'unité mémoire n'était pas dupliquée. Et ce n'est pas tant un problème que ça, du moins sur les processeurs à double ou triple émission. En effet, il est rare que l'unité mémoire doive faire deux accès simultanés. Notons que le processeur peut exécuter une instruction mémoire en parallèle d'un calcul ou d'un branchement, seuls les accès mémoire simultanés sont impossibles. ===L'émission multiple des accès mémoire avec une LSQ=== Les processeurs superscalaires larges travaillent sur des paquets de 8 à 10 instructions, il est plus fréquent d'avoir plusieurs accès mémoire par paquet. Dans ces conditions, il est utile d'avoir une '''émission multiple des accès mémoire''', à savoir d'émettre plusieurs micro-opérations mémoire en même temps. Les processeurs superscalaires modernes sont capables d'émettre plusieurs lectures/écritures simultanément. Par exemple, ils peuvent émettre une lecture en même temps qu'une écriture, ou plusieurs lectures, ou plusieurs écritures. Il faut noter que selon le processeur, il peut y avoir des restrictions quant aux accès mémoire émis en même temps. Par exemple, certains processeurs peuvent émettre une lecture avec une écriture en même temps, mais pas deux lectures ni deux écritures. Ou encore, ils peuvent émettre deux lectures, une lecture et une écriture, mais pas deux écritures en même temps. Dans la majorité des cas, les processeurs ne permettent pas d'émettre deux écritures en même temps, alors qu'ils supportent plusieurs lectures. Il faut dire que les lectures sont plus fréquentes que les écritures. Les processeurs qui autorisent toutes les combinaisons de lecture/écriture possibles, sont rares. L'émission multiple des accès mémoire s'implémente dans l'unité mémoire. Pour rappel, l'unité mémoire s'interpose entre le cache L1 et le reste du pipeline. Dans le cas le plus simple, elle incorpore une ''load/store queue'' et des unités de calcul d'adresse. L'émission multiple des accès mémoire demande de rendre la ''Load-store queue'' multi-ports, afin de gérer plusieurs micro-opérations mémoire simultanées. Il faut aussi dupliquer les unités de calcul d'adresse reliées à la LSQ, chaque port d'émission mémoire devant avoir sa propre unité de calcul d'adresse. : Dans ce qui suit, nous parlerons d'AGU (''Adress Generation Unit'') pour désigner les unités de calcul d'adresse, et de LSQ pour designer la ''Load-store queue''. [[File:Processeur non-superscalaire basique 02.png|vignette|upright=1|Processeur non-superscalaire basique]] Dupliquer les ports de la LSQ et les AGU est nécessaire. Mais qu'en est-il du cache ? La réponse varie suivant le processeur. Il y a deux grandes méthodes pour implémenter l'émission multiple des accès mémoire. La première méthode ajoute des ports de lecture/écriture au cache de données, pour faire des lectures/écritures simultanées. Il faut alors dupliquer des unités de calcul, rajouter les ports sur le cache, mais aussi rajouter des ports sur la ''load/store queue'', pour qu'elle échange des données/commandes mémoire avec le cache. Le cout en circuits est alors conséquent La seconde duplique les unités de calcul, mais pas les ports d'accès au cache. Les accès mémoire sont alors accumulés dans la ''load/store queue'', qui sont ensuite traités un par un par le cache. Un exemple est celui des processeurs AMD de micro-architecture K7 K8, à savoir les anciens AMD Athlon et AMD Athlon 64, qui pouvaient calculer trois adresses simultanément, mais ne pouvaient faire qu'un seul accès au cache par cycle. Le cout en circuit est modéré : les unités de calcul coutent très peu, les ports de la ''load/store queue'' coutent déjà un peu plus. Quelques processeurs utilisaient des solutions intermédiaires. Un processeur utilisant cette technique est, par exemple, capable d'émettre quatre µops mémoire en même temps, mais avec seulement deux ports sur le cache. Un exemple classique étant les Pentium 1 et 2 d'Intel, dont nous parlerons dans le chapitre suivant. ===L'émission séparée des LOAD et STORE=== De rares processeurs ont des ports d'émission qui peuvent faire indifféremment lecture comme écritures. Mais les processeurs modernes préfèrent séparer ports d'émission pour les lectures et les écritures. Un exemple est celui des processeurs Intel de micro-architecture Nehalem, qui avaient un port de lecture et un port d'écriture tous deux reliés à la ''Load-store queue'', chacun avec leur propre unité de calcul d'adresse. Comme autre exemple, les processeurs skylake ont une LSQ avec deux ports de lecture et un port d'écriture, ce qui permet d'émettre deux lectures en même temps qu'une écriture. Dans cette section, nous allons étudier le cas avec des ports séparés pour les lectures et écritures. En général, les processeurs ont un peu plus de ports de lectures que d'écritures. Une raison est qu'un programme a, en moyenne, un tout petit peu plus de lectures que d'écritures. Mais la différence n'est pas énorme, c'est un léger déséquilibre. Une seconde raison est que l'exécution dans le désordre marche bien mieux quand les lectures ont lieu le plus tôt possible. Donc mieux vaut privilégier les lectures à l'émission, pour qu'elles se fassent un peu en avance. En pratique, la différence n'est pas très marquée. Il est courant d'avoir un port de lecture et un d'écriture, les CPU superscalaires très larges ont souvent deux ports de lecture et deux d'écriture. A la rigueur, quelques CPU ont trois ports de lecture et deux d'écriture. Le cas le plus simple est celui où on peut émettre une lecture et une écriture en même temps. Il s'implémente facilement si la LSQ est en réalité une simple ''Store queue'', à savoir qu'elle met en avance les écritures uniquement. Pour rappel, les écritures sont mises en attente dans la ''Store queue'', mais les lectures sont exécutées immédiatement. Une fois l'adresse à lire connue, la lecture consulte la ''Store queue'' pour détecter les dépendances de données, puis s'exécute. La donnée à lire est lue soit depuis la ''Store queue'', soit depuis le cache. [[File:Emission LOAD - Store séparée.png|vignette|upright=1|Émission LOAD - Store séparée]] L'implémentation de l'émission multiple est alors très simple. La ''Store queue'' a déjà deux ports, avec un pour les lectures et un autre pour les écritures. Idem pour le cache, qui a naturellement un port de lecture et un d'écriture. Émettre une lecture et une écriture simultanément ne demande donc pas de modification digne de ce nom. La ''Store queue'' doit juste supporter une lecture et une écriture simultanée. Ajouter l'émission d'une seconde lecture n'est pas compliquée : il faut juste rajouter un second port de lecture sur le cache et la ''Store queue''. Pour rappel, l'unité mémoire est précédée par une structure qui met en attente les micro-opérations mémoire avant leur émission finale. La structure en question varie suivant l'implémentation, mais un cas particulier se marie bien avec l'émission multiple des µops mémoire. Il s'agit du cas avec une file de µops séparée pour les lectures et une autre pour les écritures, appelées respectivement la ''file de µops LOAD'' et la ''file de µops STORE''. Il est alors possible d'émettre une lecture et une écriture lors du même cycle d'horloge. Le port de lecture alimente une unité de calcul d'adresse dédiée, directement reliée au cache. Le port d'écriture du cache alimente une unité de calcul, qui est suivie par une file d'écriture, elle-même reliée au cache. Les processeurs AMD de micro-architecture K6 utilisaient cette technique. [[File:Double émission avec le Load Ordering, Store Ordering.jpg|centre|vignette|upright=2.5|Double émission avec le Load Ordering, Store Ordering]] ==Les CPU superscalaire à exécution dans le désordre== La superscalarité modifie aussi les circuits dédiés à l'exécution dans le désordre. Elle modifie les unités de renommage de registre, le ROB et les autres structures liées à l'exécution dans le désordre, au sens large. Aucune structure n'est épargnée. Elles ont tous des prots de lecture/écriture en plus, afin d'encaisser l'émission, le ''commit'' ou le renommage simultané de plusieurs µops. Par exemple, le ROB doit être modifié pour émettre et terminer plusieurs instructions en même temps, en ajoutant des ports de lecture/écriture. Pour un CPU superscalaire à 8 voies, on se dit que le ROB peut retirer 8 µops par cycle maximum. Mais certains processeurs récents ont un ROB qui peut retirer le double ! Un exemple est celui des CPU de micro-architecture Skymont, qui peuvent émettre 8 µops par cycle, mais en retirer 16. Quelques CPU de marque AMD étaient aussi dans ce cas. L'avantage est que cela permet de réduire la taille du ROB, du banc de registre et de quelques autres structures matérielles liées à l'exécution dans le désordre. Le gain sur-compense le cout en transistor nécessaire pour retirer 16 µops par cycle. Dans cette section, nous allons voir comment les étages du pipeline dédiés à l'exécution dans le désordre sont modifiées sur un CPU superscalaire. ===L'exemple du PA-RISC PA 8000=== Avant de commencer, nous allons voir un processeur superscalaire assez simple, le PA 8000, de HP, qui implémente le jeu d'instruction PA-RISC. Bien que très ancien, il implémentait l'exécution dans le désordre et le renommage de registre. Le peu d'informations que nous avons sur ce processeurs proviennent des documents "THE HP PA-8000 RISC CPU" par Ashok Kumar, et l'article de microprocessor report "PA-8000 Combines Complexity and Speed". Ils ne donnent malheureusement pas énormémment d'informations et je devrais être amené à faire quelques suppositions dans ce qui suit. Avant de commencer, parlons de détails sans lien avec la superscalarité. Ce processeur, comme beaucoup de processeurs PA-RISC, n'intégrait pas de cache de niveau L2 dans le processeur, qui était déporté en-dehors du CPU, sur la carte mère. Le processeur préférait utiliser ses transistors pour avoir un cache L1 assez large, quitte à ce qu'il soit plus lent. La lenteur du cache était prévue, le processeur compensait celle-ci en utilisant l'exécution dans le désordre, bien que ce ne soit pas parfait. Les CPU PA-RISC avant le PA 8000 utilisaient un pipeline à vagues ''wave pipeline'', ce qui était assez peu commun, mais le PA 8000 repasse à un pipeline synchrone classique. Passons maintenant à la superscalarité. Le PA 8000 est un processeur quadruple émission, qui peut émettre, à chaque cycle, deux opérations et deux accès mémoire. Le renommage de registre utilise des registres de renommage séparés des registres architecturaux, comme c'était la mode à l'époque. Le budget en transistor faisait que c'était soit ça, soit le renommage dans le ROB, faute de mieux. Le processeur utilise une implémentation ''Read After Issue'', ce qui veut dire que les opérandes des instructions sont lues après l'émission, juste avant l'exécution. Le processeur peut aussi ''commit'' deux opérations et deux accès mémoire par cycle, ce qui revient à transférer les résultats des registres de renommage vers les registres architecturaux. L'exécution dans le désordre est prise en charge par une structure matérielle unique, qui ressemble à une fusion entre un ROB et un ''scheduler''. Et c'est là que je vais devoir faire des suppositions. Le document "THE HP PA-8000 RISC CPU" nomme cette structure : l''''''Instruction Reorder Buffer'''''. Il utilise pas moins de 850 000 transistors, et prend 20% de la taille du ''die''. L'article "THE HP PA-8000 RISC CPU" laisse fortement sous-entendre qu'il s'agit une structure unique, faite d'un seul tenant, mais l'article de microprocessor report dit le contraire par moment. Il est décrit comme un ''scheduler'', à savoir qu'il détecte les dépendances entre instruction et les émet. Il gère aussi la détection des mauvaises prédictions de branchement et peut annuler les instructions chargées à tort, en les retirant de le ''scheduler''. Il est aussi précisé que les instructions quittent cet ''Instruction Reorder Buffer'' dans l'ordre du programme. Elles ne peuvent en sortir que quand elles ont été exécutées et qu'elles n'ont causé aucune exception. Ce qui fait qu'il se comporte comme un ROB de ce point de vue là. Difficile de dire si l'''Instruction Reorder Buffer'' est un réel mélange entre un ROB et un ''scheduler'', ou s’il est réellement conçu avec deux structures séparées. Dans ce qui suit, je pars du principe que les deux structures sont séparées. Le processeur contient deux ''schedulers'' : une réservée aux µops mémoire (LOAD et STORE), l'autre pour les opérations entières/flottantes. Elles ont chacune 28 entrées, ce qui permet de mémoriser 56 µops au maximum. Les deux peuvent recevoir 4 µops par cycle de la part des décodeurs. Là encore, précisons que les choses ne sont pas claires pour ce qui est de la séparation. L'article de Microprocessor report dit que les deux sont physiquement séparées, et que cette séparation physique permet de simplifications (les opérations mémorisent des noms de registres plus court que les adresses demandées par les µops LOAD/STORE). Mais l'autre document cité laisse penser que l''''Instruction Reorder Buffer'' est une structure unique. À chaque cycle, le processeur peut émettre deux instructions de calcul et deux instructions mémoire. Les deux ''schedulers'' ont pour cela chacune deux ports d'émission. Les deux ports d'émission pour les µops mémoire sont identiques, et le cache L1 est un cache double port, ce qui permet d'exécuter deux lectures/écritures par cycle. Pour ce qui est des µops entières/flottantes, le processeur a dupliqué toutes ses unités de calcul : il a deux ALU entières, deux ''barrel shifters'', deux FPU de type FMAC, et deux unités de division flottante. Vraisemblablement, il y a deux ports d'émission, chacun étant connecté à une unité de chaque type. : S'il n'utilisait pas l'exécution dans le désordre, ce processeur aurait donc quatre pipelines : deux pipelines entiers identiques et deux pipelines mémoire. Et il aurait une superscalarité presque parfaite s'il était un CPU à double émission ! À chaque cycle, le ''scheduler'' émet les deux µops les plus anciennes qui sont prêtes à être exécutées. La documentation dit que la fenêtre émet "la plus vielle instruction paire, et la plus vielle instruction impaire", ce qui sous-entend que le ''scheduler'' est segmentée en deux. C'est précisément la logique d'éveil et d'émission qui est segmentée, une partie gérant la moité de le ''scheduler'', une seconde logique d'éveil/''schedule'' gérant le reste. le ''scheduler''s n'implémente donc pas une vraie double émission, elle est partitionnée pour permettre d'émettre deux µops en même temps. L'avantage est une économie de transistors manifeste. Un inconvénient est que si les µops prêtes sont toutes dans la même moitié, une seule µops sera émise par cycle. Mais avec 2*14 entrées, le cas est assez rare pour que l'économie de transistors en vaille la peine. [[File:PA 8000 - microarchitecture.png|centre|vignette|upright=2|PA 8000 - microarchitecture]] ===La superscalarité avec une file/fenêtre d'instruction centralisée=== Plus haut, nous avons montré qu'un processeur pouvait avoir plus de ports d'émission que de ports de décodage. On dit aussi que sa ''largeur de décodage'' était supérieure à sa ''largeur d'émission''. La '''largeur de décodage''' est le nombre de µops fournies par l'unité de décodage par cycle d'horloge, la '''largeur d'émission''' est le nombre maximal de µops émises par cycle d'horloge. Et n'allez pas croire qu'un surplus de ports d'émission est du gâchis. Sur les processeurs avec exécution dans le désordre, ce surplus peut être utilisé. Mais avant toute chose, évacuons un détail. Vous avez sans doute pensé que le surplus peut être exploité par les instructions machines décodées en plusieurs µops . Par exemple, si une instruction est décodée en deux µops, on pourrait avoir un port d'émission en plus pour en profiter. Mais les ports de décodage sont *en sortie du décodeur*, et contiennent des µops, pas des instructions. Le surplus de ports d'émission peut occasionnellement utiliser le surplus de ports de décodage, mais cela implique que des µops ont été mises en attente dans l'unité d'émission, pour être émises par la suite. Et cela implique l'usage d'un ''scheduler'' ou d'une file de µops. Le principe est que les µops sont accumulées dans le ''scheduler'', en attendant leurs opérandes ou la résolution d'une dépendance. Et si l'occasion se présente, une µops est émise sur chaque port d'émission. Il y a donc un gain en performances, mais il faut faire quelques précisions sur son origine. La largeur d'émission utilisée ne peut pas dépasser, *en moyenne*, la largeur de décodage. Et c'est intuitif : un CPU qui décode 4 µops par cycle ne peut pas émettre 6 par cycle en moyenne, sur le temps long, il n'y a pas de µops en surplus qui sortent du vide. Par exemple, sur un processeur quadruple émission, si on analyse combien d'instructions sont émises par cycle, il peut y avoir des cycles où la largeur d'émission est totalement utilisée, mais ce sera compensé par des périodes où elle est fortement sous-utilisée. Les µops sont accumulées en cas de sous-utilisation, puis consommées en cas d'utilisation complète. Les deux périodes se compensent. Et c'est là que l'on peut comprendre d'où vient le gain en performance. Les cycles où les ports d'émission sont sous-utilisés existent systématiquement, que le processeur utilise l'exécution dans le désordre ou pas. Ils sont liés à la présence de dépendances de données, aux contraintes d’appariement, etc. Elles tendent à réduire la moyenne du nombre de µops émises par cycle. Par contre, ce sont les cycles de rattrapage, où les ports en surplus sont utilisés, qui font remonter la moyenne. Le gain en performance est donc lié à ces cycles de rattrapage, où les µops accumulées sont émises dans les ports en surplus. Et ils n'existent que sur les processeurs avec une file/fenêtre d'instruction. Réduire le nombre de ports d'émission permet de garder des ''schedulers'' et un ROB simples, rapides et économes en énergie. Et mine de rien, c'est là un compromis important : à quoi bon augmenter le nombre de ports d'émission si c'est pour que ce soit compensé par une fréquence plus faible ? Par contre, réduire le nombre de ports augmente la ''port contention'', surtout si on a mal réparti les ALU. Il faut donc trouver un compromis entre réduire le nombre de ports d'émission d'un côté, réduire la ''port contention'' de l'autre. La différence entre largeur de décodage et d'émission a un impact assez fort sur le banc de registre, et précisément sur son nombre de ports de lecture. Le banc de registre a besoin de plus de ports de lecture avec une fenêtre d’instruction qu'avec des stations de réservation. Rappelons la terminologie utilisée dans ce cours. Les ''schedulers'' se contentent de mémoriser la micro-opération et quelques bits pour détecter la disponibilité des opérandes. Par contre, les stations de réservations mémorisent aussi les opérandes des instructions. Et cette différence a une influence le nombre de ports de lecture du banc de registre. Supposons que toutes les instructions sont dyadiques, à deux opérandes. Comptons le nombre de ports nécessaires pour alimenter les unités de calcul, sans utiliser d'arbitre de banc de registre. Avec un ''scheduler'', il faut le double du nombre de ports d'émission. Mais avec des stations de réservation, il faut le double des ports de décodage. La raison est que les registres sont lus après émission avec un ''scheduler'', avant avec des stations de réservation (sous-entendu, après le décodage). Or, comme dit plus haut, les processeurs superscalaires larges ont souvent plus de ports d'émission que de décodage. ===La superscalarité à ''schedulers'' décentralisées=== Les processeurs précédents utilisaient une unité d'émission simple, qui pouvait utiliser l'émission dans l'ordre ou dans le désordre. Elle peut être remplacée par un ''scheduler'' centralisé dans que cela quoi que ce soit aux explications précédentes, idem avec une station de réservation centralisée. En soi, l'exécution dans le désordre est donc totalement compatible avec une implémentation simple de la superscalarité. Par contre, des subtilités surviennent avec les ''schedulers'' décentralisés. Pour rappel, sur ces processeurs, les µops sont émises en deux phases. Une première phase de ''dispatch'' qui envoie les µops vers le ''scheduler'' adéquat, sans détecter les dépendances de données. La seconde phase de ''schedule'' gère les dépendances de données, elle met en attente les µops en attendant que l'unité soit disponible pour les exécuter, en attendant aussi que les opérandes soient disponibles. Et à ce petit jeu, il y a une différence entre le nombre de µops qui sont ''dispatch par cycle'' et celles qui sont ''schedule''. Dit autrement, la largeur d'émission est scindée en une '''largeur de ''dispatch''''' et une '''largeur de ''schedule''. Par exemple, prenons un processeur triple émission avec deux stations de réservation : une pour les µops entières/mémoire, et une autre pour les µops flottantes. L'unité d'émission peut ''dispatch'' maximum trois µops par cycle : soit trois µops entières/mémoire, soit trois flottantes, soit un mix de trois µops différentes. Les stations de réservation, quant à elles, peuvent chacune ''schedule'' 3 µops par cycle, vers trois ALUs entières pour la station de réservation entière/mémoire, vers trois FPS pour la station de réservation flottante. De quoi ''dispatch'' trois µops, mais d'en ''schedule'' six, à chaque cycle. Et cet exemple ne sort pas de nulle part : les CPU x86 d'Intel et AMD sont globalement dans ce cas, même si les chiffres varient d'une microarchitecture à l'autre. L'exemple précédent colle parfaitement à la microarchitecture K7 d'AMD, utilisée sur les processeurs Athlon dans les années 2000. [[File:AMD K7.png|centre|vignette|upright=2.5|AMD K7, microarchitecture.]] L'exemple précédent avait assez d'unités entières/flottantes pour couvrir toute la largeur de décodage/''Dispatch''. Mais ce n'est pas toujours le cas, comme va le montrer l'exemple suivant. Le MIPS R10000, qui utilisait un mélange de files de µops et de ''schedulers'' : une file de µops les accès mémoire, une fenêtre pour les instructions entières et une autre pour les opérations flottantes. Les branchements et NOPs étaient exécutés dans une unité de branchement distincte. Les trois files/fenêtres peuvent mémoriser 16 µops. Le processeur avait deux ALU entières, une AGU de calcul d'adresse, un additionneur flottant et un multiplieur/diviseur flottant. Il y avait un multiplieur entier sur le port d'émission l'ALU 2. Le processeur décodait 4 instructions par cycle et produisait jusqu'à 4µops, qui étaient redistribuées sur les trois ''schedulers''. Chacune pouvait accepter 4 µops par cycle, ce qui fait que processeur pouvait ''dispatch'' 4 µops entières, ou 4 µops flottantes, ou 4 µops mémoire, ou un mélange de deux ou trois types de µops. Pour ce qui est du ''schedule'', le ''scheduler'' entière pouvait émettre 2 µops, la fenêtre flottante pouvait émettre une addition en même temps qu'une multiplication/divison flottante et qu'un branchement conditionnel flottant, et la file de µops mémoire ne pouvait émettre qu'une µop mémoire à la fois. En tout, cela fait 6 µops ''schedule'' pour 4 µops au ''dispatch''. [[File:R 10000.png|centre|vignette|upright=2.5|MIPS R10000, microarchitecture.]] ===La superscalarité à ''schedulers'' totalement décentralisées=== Prenons un cas extrême de fenêtre d'instruction décentralisée : celui où chaque ALU entière a sa propre station de réservation. En clair : une fenêtre d'instruction par ALU/FPU ! On parle de '''''schedulers'' totalement décentralisés'''. Vous vous dites que ce cas est un peu trop extrême pour être réaliste, mais il n'en est rien. C'est même très courant sur les architectures basse consommation, et sur pas mal de CPU x86 modernes. Une telle organisation entraine une légère perte de performance, comparé à un ''scheduler'' centralisée ou partiellement décentralisée. Et cela peut se comprendre par un exemple. Imaginez un processeur avec deux ALU, donc deux stations de réservation. Il arrivera qu'une station de réservation ait plusieurs µops prêtes, alors que l'autre en ait zéro. Dans une telle situation, une seule µop sera émise au cycle suivant, vu que chaque station de réservation a un seul port d'émission vers une seule ALU entière. Par contre, avec un ''scheduler'' centralisée double port, on aurait pu émettre les deux µops en même temps sur deux ALUs séparées. La perte de performance est donc liée au fait que les µops '''''prêtes''''' sont mal réparties dans les différentes stations de réservation. Il arrivera que des µops prêtes s'accumulent dans une station de réservation, alors que d'autres seront pleines, ou du moins sous-utilisées. Et ce n'est pas quelque chose qui peut être réglé à l'étape de ''dispatch'', car on ne sait pas encore quand les µops auront leurs opérandes de disponibles. [[File:Comparaison entre une station de réservation totalement décentralisée et une autre qui ne l'est pas.png|centre|vignette|upright=2.5|Comparaison entre une station de réservation totalement décentralisée et une autre qui ne l'est pas.]] Par contre, décentraliser totalement les ''schedulers'' entraine aussi un gain considérable en termes de consommation énergétique. Et c'est la raison pour laquelle les ''schedulers''s totalement décentralisées sont utilisées sur les architectures basse consommation. La perte de performance ne peut pas s'expliquer clairement à ce stade du cours, car il nous faudrait parler d'émission superscalaire. Le gain en matière d'énergie vient de l'économie de circuits, qui est assez drastique. Le gain en matière d'énergie vient de l'économie de circuits, qui est assez drastique. Je rappelle qu'une station de réservation a besoin, pour N instructions, d'environ N^2 circuits (des comparateurs, notamment). Prenons une station de réservation centralisée de 64 entrées et comparons avec 8 stations de 8 entrées chacune. Les deux donneront 64 entrées, mais la première aura un cout en circuit proportionnel à 64², alors que le second aura un cout en circuit de 8 *(8²). Entre les deux, le choix est clair : la seconde solution est plus économe. D'où l'utilisation de cette solution sur les microarchitectures basse consommation. ===L'unité de renommage superscalaire=== Avec la superscalarité, l'unité de renommage de registre doit gérer le cas où des instructions consécutives ont des dépendances de registre. Par exemple, prenons un processeur à double émission, qui renomme deux instructions consécutives. Si elles ont une dépendance de registre, le renommage de la seconde instruction dépend du renommage de la première. La première doit être renommée et le résultat du renommage est utilisé pour renommer la seconde, ce qui empêche d'utiliser deux unités de renommage séparées. Pour cela, elle renomme les registres sans tenir compte des dépendances, pour ensuite corriger le résultat. [[File:Unité de renommage superscalaire.png|centre|vignette|upright=2|Unité de renommage superscalaire.]] Seules les dépendances lecture-après-écriture doivent être détectées, les autres étant supprimées par le renommage de registres. Repérer ce genre de dépendances se fait assez simplement : il suffit de regarder si un registre de destination d'une instruction est un opérande d'une instruction suivante. [[File:Détection des dépendances sur un processeur superscalaire.png|centre|vignette|upright=2|Détection des dépendances sur un processeur superscalaire.]] Ensuite, il faut corriger le résultat du renommage en fonction des dépendances. Si une instruction n'a pas de dépendance avec une autre, on la laisse telle quelle. Dans le cas contraire, un registre opérande sera identique avec le registre de destination d'une instruction précédente. Dans ce cas, le registre opérande n'est pas le bon après renommage : on doit le remplacer par le registre de destination de l'instruction avec laquelle il y a dépendance. Cela se fait simplement en utilisant un multiplexeur dont les entrées sont reliées à l'unité de détection des dépendances. On doit faire ce replacement pour chaque registre opérande. [[File:Correction des dépendances sur un processeur superscalaire.png|centre|vignette|upright=2|Correction des dépendances sur un processeur superscalaire.]] ==Les optimisations des processeurs superscalaires larges== Les processeurs superscalaires larges ont des optimisations spécifiques, qui n'ont pas de sens sur les processeurs superscalaires étroits. Dans les grandes lignes, elles se classent en deux types. Les premières permettent de charger/décoder plus de 5-10 instructions simultanément. Le problème est alors que les branchements viennent mettre leur grain de sel et qu'il faut en tenir compte. Les secondes corrigent des problèmes qui apparaissent quand un CPU intègre plus de 5 à 10 unités de calcul. ===L'étape de chargement d'un CPU superscalaire large=== Charger plusieurs instructions pose de nombreux problèmes sur les processeurs superscalaires larges, qui émettent de 5 à 10 instructions simultanées. Pour rappel, la stratégie basique pour charger N instructions est de charger un bloc de N instructions consécutives. Les instructions après un branchement ne sont pas décodées ni exécutées, ce qui entraine une petite baisse de performance. Pour un N petit, la perte de performance est mineure. Mais pour un N large, elle devient suffisamment importante pour que la conception du CPU doit alors être repensée de fond en comble. Les analyses statistiques disent qu'il y a environ un branchement tous les 4 à 6 instructions. Un CPU a donc tendance à décoder des paquets de 3 à 5 instructions consécutives, avant qu'un branchement casse la dynamique. Or, cela pose des problèmes pour utiliser plusieurs décodeurs. L'implémentation basique, qui charge N instructions consécutives pour alimenter N décodeurs, fonctionne donc jusqu'à 4/6 décodeurs. Au-delà de 5 instructions, un CPU superscalaire doit être adapté pour gérer les branchements dans les paquets d'instruction qu'il émet. Le nombre de 5 instructions ne sort donc pas de nulle part. La première solution utilise un cache de µops, avec un ''front-end'' capable de charger/décoder 4/5 instructions à la fois, pas plus. L'idée est que la majorité des instructions proviennent du cache de µops (plus de 80%), ce qui fait qu'on peut émettre environ 10 instructions à partir du cache de µops, pas besoin d'avoir beaucoup de décodeurs. Les performances sont cependant dégradées lors d'un défaut de cache de µops. Les instructions doivent alors être chargées depuis le cache d'instruction, par paquets de 4-5, puis sont décodées par 4-5 décodeurs, ce qui ne permet pas d’alimenter les unités de calcul à plein régime. La solution précédente joue sur la distinction entre pots de décodage et d'émission. Elle permet d'émettre un grand nombre de µops sans pour autant charger un grand nombre d'instructions en même temps. En quelque sorte, ce n'est qu'une méthode de contournement, le CPU superscalaire reste de type étroit. Mais il est aussi possible d'utiliser un '''''front-end large''''', capable de charger une bonne dizaine d'instructions en même temps. La seule difficulté est de tenir compte de la présence de branchements. Pour rappel, avec un ''front-end'' étroit, les instructions situées après le premier branchement pris sont annulées, elles ne sont pas décodées ni exécutées. [[File:Fetch sur un processeur superscalaire avec prediction de branchements.png|centre|vignette|upright=2|Fetch sur un processeur superscalaire avec prédiction de branchements.]] Un ''front-end'' large charge les instructions de destination du branchement et les placent à sa suite. Ils chargent deux blocs à la fois et les fusionnent en un seul qui ne contient que les instructions présumées utiles. [[File:Cache d'instructions autoaligné.png|centre|vignette|upright=2|Cache d'instructions auto-aligné.]] Mais cela demande de charger deux blocs de mémoire en une fois, ce qui demande un cache d'instruction multiports. Il faut aussi ajouter un circuit pour assembler plusieurs morceaux de blocs en un seul : le fusionneur (''merger''). En pratique, cette solution demande d'ajouter un second port de lecture au cache, pour un cout en hardware important, avec un impact négatif sur le temps d'accès au cache. Et il faut rajouter le fusionneur, qui prend un étage de pipeline à lui tout seul. Et encore, cette solution ne gère pas le cas où un bloc contient plusieurs branchements ! [[File:Implémentation d'un cache d'instructions autoaligné.png|centre|vignette|upright=2|Implémentation d'un cache d'instructions auto-aligné.]] Les exemples précédents partent du principe qu'il n'y a qu'un seul branchement dans un bloc. Mais quand les blocs deviennent assez longs, il est fréquent d'avoir plusieurs branchements dans un bloc. Et il est même possible d'avoir plusieurs branchements pris. Dans un bloc de 8-10 instructions, ce n'est pas rare, et les CPU superscalaires à 8-10 voies sont la règle dans les CPU des années 2020. Pour gérer ce cas, il faut ajouter des ports supplémentaires au cache d'instruction et adapter le fusionneur, pour qu'il puisse fusionner trois ou quatre blocs. De plus, il faut utiliser une unité de prédiction de branchement capable de ''prédire plusieurs branchements par cycle''. ===Le décodage superscalaire large=== Le décodage des instructions n'est pas censé dépendre de l'implémentation du chargement. En théorie, une fois plusieurs blocs d'instruction fusionnés, on peut décoder les instructions en parallèle. Cependant, certains processeurs effectuent le décodage en tenant compte de la manière dont les branchements découpent les blocs. Les processeurs Atom d'Intel utilisent une solution de ce type, qui couple prédiction de branchement et décodage parallèle. Ils chargent/décodent des paquets de 3 instructions consécutives, chaque paquet étant séparé du précédent par un branchement. Pour cela, en plus d'avoir un fusionneur adapté, ils regroupent les décodeurs en ''clusters'', chacun regroupant 3 décodeurs, et pouvant décoder trois instructions consécutives. Les micro-architectures Tremont et Crestmont avaient deux ''clusters'' (6 décodeurs au total), la micro-architecture Darkmont en intègre trois (9 décodeurs au total). Avec deux ''clusters'', le fonctionnement est le suivant. Si le code est composé d'une suite d'instruction sans branchements, seul le premier ''cluster'' est utilisé, limitant le décodage à trois instructions par cycle. Par contre, si l'une des trois instructions décodée est un branchement, alors le second ''cluster'' décode les trois instructions situées après ce branchement, à partir de l'adresse de destination. Avec un troisième ''cluster'', c'est la même chose, sauf qu'il faut qu'il y ait un branchement dans les trois instructions décodées par le second ''cluster''. Mais comment faire pour savoir quels décodeurs activés, quels ''clusters'' sont actifs ? C'est la prédiction de branchement qui commande. Avec deux ''clusters'', elle détermine si un branchement est présent dans les trois instructions à charger, et quelle est son adresse de destination. Sans branchement, elle prévient les décodeurs et les trois instructions chargées sont décodées dans un ''cluster'' libre. Si elle prédit un branchement, elle charge les instructions adéquates, et active les deux ''clusters''. Avec trois branchements, c'est le même mécanisme, sauf que l'unité de prédiction de branchement doit être capable de prédire deux branchements par cycle. [[File:Front-end découplé de la microarchitecture Tremont.png|centre|vignette|upright=3|Front-end découplé de la microarchitecture Tremont.]] Il faut noter que les décodeurs d'un ''cluster'' sont des décodeurs simples, sans microcode. Sur les processeurs Tremont et Crestmont, le microcode était unique et était partagé entre tous les ''clusters''. Un seul ''cluster'' pouvait décoder une instruction complexe avec le microcode, l'autre devait se limiter à des instructions simples uniquement. Depuis Skymont, le microcode est partiellement dupliqué, avec un microcode par ''cluster''. Le cout en hardware peut paraitre prohibitif, pour un gain en performance faible. Sauf que c'est oublier que ce sont des processeurs Atom, sur lesquels beaucoup d'instructions sont microcodées. Les processeurs Atom ont un budget en transistor limité, ce qui fait qu'il est préférable pour eux d'implémenter des instructions en microcode que d'utiliser des unités de calcul dédiées ou des circuits de décodage complexes. Pour limiter la casse, le microcode n'est que partiellement dupliqué. Seul le microcode pour les instructions fréquente est dupliqué. Il y a un microcode secondaire pour certaines instructions, qui est lui unique et partagé par tous les ''clusters''. ===Le contournement sur les processeurs superscalaires larges=== Pour rappel, la technique du contournement (''register bypass'') permet au résultat d'une instruction d'être immédiatement utilisable en sortie de l'ALU, avant même d'être enregistré dans les registres. Implémenter la technique du contournement demande d'utiliser des multiplexeurs pour relier la sortie de l'unité de calcul sur son entrée si besoin. Il faut aussi des comparateurs pour détecter des dépendances de données. [[File:Pipeline Bypass.png|centre|vignette|upright=1|Pipeline Bypass]] La sortie de chaque ALU doit être reliée aux entrées de toutes les autres, avec les comparateurs qui vont avec. Sur les processeurs ayant plusieurs d'unités de calculs, cela demande beaucoup d’interconnexions et de comparateurs. Pour N unités de calcul, cela demande 2 * N² interconnexions, implémentées avec 2N multiplexeurs de N entrées chacun. Si c'est faisable pour 2 ou 3 ALUs, la solution est impraticable au-delà. Non seulement ce serait un enfer à câbler, mais les fils seraient tellement longs que la fréquence du processeur en prendrait un coup. Notez que cela vaut pour les processeurs superscalaires, mais aussi pour tout processeur avec beaucoup d'unités de calcul. En théorie, un CPU à exécution dans le désordre, non-superscalaire, mais avec beaucoup d'unités de calcul, fait face au même problème. En pratique, avoir une dizaine d'ALU implique processeur superscalaire à exécution dans le désordre. D'où le fait qu'on parle du problème maintenant. La seule solution praticable est de ne pas relier toutes les unités de calcul ensemble. À la place, on préfère regrouper les unités de calcul dans différents '''agglomérats''' ('''cluster'''). Le contournement est alors possible entre les unités d'un même agglomérat, mais pas entre agglomérats différents. Évidemment, certaines possibilités de contournement sont perdues, mais c'est compensé par un gain en fréquence et un cout en circuit/fils réduit. C'est un bon compromis, ce qui explique que presque tous les processeurs modernes l'utilisent. Les rares exceptions sont les processeurs POWER 4 et POWER 5, qui ont préféré se passer de contournement pour garder un processeur très simple et une fréquence élevée. ===Le banc de registre des processeurs superscalaires larges=== Pour émettre deux opérations entières simultanément, il faut lire deux fois plus d'opérandes. Et il faut aussi écrire deux résultats dans les registres, en même temps. Pour cela, on double les ports du banc de registre. En général, il faut au maximum 2 ports de lecture et un port d'écriture par unité de calcul. Le problème, c'est que plus un banc de registres a de ports, plus il utilise de circuits, est compliqué à concevoir, consomme de courant et chauffe. Avec plusieurs dizaines d'unités de calcul différentes, ajouter autant de ports impacterait la fréquence du banc de registres et réduirait les performances, voire est totalement impraticable à cause des contraintes thermiques. Les processeurs superscalaires larges doivent donc trouver des solutions. La première solution utilise un banc de registre unique, mais n'utilise pas autant de ports que le pire des cas le demanderait. Le processeur détecte quand il n'y a pas assez de ports pour servir toutes les micro-opérations. Quand ça arrive, l'unité d'émission émet assez de micro-opérations pour exploiter les ports disponibles, mais met en attente les micro-opérations en trop, le temps que les ports se libèrent. Pour cela, le banc de registre est géré par un circuit d'arbitrage spécialisé, intégré à l'unité d'émission, l’'''arbitre du banc de registres''' (''register file arbiter''). Une autre solution est de dupliquer le banc de registres en plusieurs exemplaires qui contiennent exactement les mêmes données, mais avec moins de ports de lecture/écriture. Un exemple est celui des processeurs POWER, Alpha 21264 et Alpha 21464. Sur ces processeurs, le banc de registre est dupliqué en plusieurs exemplaires, qui contiennent exactement les mêmes données. Les écritures dans les registres sont envoyées à tous les bancs de registres, afin de garantir que leur contenu est identique. Chaque exemplaire a exactement deux ports de lecture. La conception du processeur est simplifiée, que ce soit au niveau du câblage, que de la conception des bancs de registres. Une dernière solution découpe le banc de registres en plusieurs bancs de registres plus petits, avec un réseau d'interconnexions pour échanger des données entre bancs de registres. Dans la plupart des cas, cette séparation est invisible du point de vue de l'assembleur et du langage machine. Le processeur se charge de transférer les données entre bancs de registres suivant les besoins. Sur d'autres processeurs, les transferts de données se font via une instruction spéciale, souvent appelée ''COPY''. [[File:Banc de registres distribué.png|centre|vignette|upright=2|Banc de registres distribué.]] Sur de certains processeurs, un branchement est exécuté par une unité de calcul spécialisée. Or les registres à lire pour déterminer l'adresse de destination du branchement ne sont pas forcément dans le même agglomérat que cette unité de calcul. Pour éviter cela, certains processeurs disposent d'une unité de calcul des branchements dans chaque agglomérat. Dans les cas où plusieurs unités veulent modifier le ''program counter'' en même temps, un système de contrôle général décide quelle unité a la priorité sur les autres. Mais d'autres processeurs fonctionnent autrement : seul un agglomérat possède une unité de branchement, qui peut recevoir des résultats de tests de toutes les autres unités de calcul, quel que soit l’agglomérat. ==La macro-fusion : une optimisation du décodage parallèle== Les processeurs superscalaires supportent la technique dite de '''macro-fusion''', qui permet de fusionner deux-trois instructions consécutives en une seule micro-opération. Par exemple, il est possible fusionner une instruction de test et une instruction de saut en une seule micro-opération de branchement. Il s'agit là de l'utilisation la plus importante de la macro-fusion sur les processeurs x86 modernes. La macro-fusion est utilisée pour fusionner un test et un saut en un branchement unique. L'optimisation est présente sur la plupart des CPU superscalaires modernes. Les CPU x86 l'implémentent, mais aussi quelques CPU ARM et les processeurs Apple de série M (M1 à M5, et potentiellement plus quand ils seront sortis). La fusion des instructions se fait lors du décodage des instructions, grâce à la coopération des décodeurs. Elle marche systématiquement si l'instruction de test et le saut sont consécutives, qu'elles forment bien une paire d'instruction. Par contre, insérer une instruction entre les deux empêche la macro-fusion de faire son travail, sauf si l'instruction insérée est un NOP. Les processeurs ARM64 avaient une forme spécifique de macro-fusion, utilisée pour un cas très précis : charger une constante immédiate de 32 ou 64 bits, dans un registre 64 bits. Les CPU ARM 64 bits utilisent des instructions codées sur 32 bits, qui ne peuvent encoder que des constantes immédiates de 16 bits. Pour charger une constante de 32/64 bits, il faut s'y prendre en plusieurs fois. Une première instruction MOVZ charge les 16 premiers bits, puis 2 à 4 instructions MOVK remplissent le reste. MOVZ met à zéro les 48 bits de poids fort, MOVK permet de sélectionner le doublet à modifier dans le registre (on modifie 16 bits, dont on choisit la place, le reste du registre est laissé tel quel). ARM permet de fusionner cette suite d'instructions en une seule µop MOV avec une constante immédiate. On parle alors de '''''MOVZ + MOVK fusion'''''. Une dernière utilisation, [https://www2.eecs.berkeley.edu/Pubs/TechRpts/2016/EECS-2016-130.pdf proposées pour le jeu d'instruction RISC-V], fusionnait un calcul d'adresse et une instruction LOAD/STORE en une seule instruction d'accès mémoire. Elle a été envisagée à une époque où le jeu d'instruction RISC-V ne gérait pas les modes d'adressage base + indice. L'idée était d'avoir une unité mémoire qui gérait le mode d'adressage base + indice et de fusionner des instructions pour l'exploiter. Mais de nos jours, le jeu d'instruction RISC-V intègre le mode d'adressage base + indice, ce qui fait que la macro-fusion n'a aucun intérêt pour ce cas précis. La macro-fusion a de nombreuses limitations en pratique. En théorie, on pourrait l'utiliser au-delà des deux situations mentionnées plus haut. Par exemple, pour fusionner une addition et une multiplication en une seule instruction MAD. Mais l'intérêt est assez faible. Notons que la macro-fusion ne permet que de fusionner des paires d'instructions. Aller au-delà demanderait un cout en circuit trop important. Déjà que tester deux paires utilise pas mal de comparateurs... ==Le ''stack engine'' : une optimisation de la pile d'appel== Les processeurs modernes intègrent une optimisation liée au pointeur de pile. Pour rappel, sur les architectures modernes, le pointeur de pile est un registre utilisé pour gérer la pile d'appel, précisément pour savoir où se trouve le sommet de la pile. Il est manipulé par les instructions CALL, RET, PUSH et POP, mais aussi par les instructions d'addition/soustraction pour gérer des cadres de pile de taille variable. De plus, il peut servir d'opérande pour des instructions LOAD/STORE, afin de lire/écrire des variables locales, les arguments d'une fonction, et autres. C'est donc un registre général adressable, intégré au banc de registre, altéré par l'unité de calcul entière. L'incrémentation/décrémentation du pointeur de pile passe donc par l'unité de calcul, lors des instructions CALL, RET, PUSH et POP. Mais, l'optimisation que nous allons voir permet d'incrémenter/décrémenter le pointeur de pile sans passer par l'ALU, ou presque. L'idée est de s'inspirer des architectures avec une pile d'adresse de retour, qui intègrent le pointeur de pile dans le séquenceur et l'incrémentent avec un incrémenteur dédié. ===Le ''stack engine''=== L'optimisation que nous allons voir utilise un '''''stack engine''''' intégré à l'unité de contrôle, au séquenceur. Le processeur contient toujours un pointeur de pile dans le banc de registre, cela ne change pas. Par contre, il n'est pas incrémenté/décrémenté à chaque instruction CALL, RET, PUSH, POP. Un compteur intégré au séquenceur est incrémenté à la place, nous l’appellerons le '''compteur delta'''. La vraie valeur du pointeur de pile s'obtient en additionnant le compteur delta avec le registre dans le banc de registre. Précisons que si le compteur delta vaut zéro, la vraie valeur est dans le banc de registre et peut s'utiliser telle quelle. Lorsqu'une instruction ADD/SUB/LOAD/STORE utilise le pointeur de pile comme opérande, elle a besoin de la vraie valeur. Si elle n'est pas dans le banc de registre, le séquenceur déclenche l'addition compteur-registre pour calculer la vraie valeur. Finalement, le banc de registre contient alors la bonne valeur et l'instruction peut s'exécuter sans encombre. L'idée est que le pointeur de pile est généralement altéré par une série d'instruction PUSH/POP consécutives, puis des instructions LOAD/STORE/ADD/SUB utilisent le pointeur de pile final comme opérande. En clair, une bonne partie des incrémentations/décrémentation est accumulée dans le compteur delta, puis la vraie valeur est calculée une fois pour toutes et est utilisée comme opérande. On accumule un delta dans le compteur delta, et ce compteur delta est additionné quand nécessaire. Précisons que le compteur delta est placé juste après le décodeur d'instruction, avant même le cache de micro-opération, l'unité de renommage et l'unité d'émission. Ainsi, les incrémentations/décrémentations du pointeur de pile disparaissent dès l'unité de décodage. Elles ne prennent pas de place dans le cache de micro-opération, ni dans le ''scheduler'', ni dans la suite du pipeline. De nombreuses ressources sont économisées dans le ''front-end''. Mais utiliser un ''stack engine'' a aussi de nombreux avantages au niveau du chemin de données/''back-end''. Déjà, sur les processeurs à exécution dans le désordre, cela libère une unité de calcul qui peut être utilisée pour faire d'autres calculs. Ensuite, le compteur delta mémorise un delta assez court, de 8 bits sur le processeur Pentium M, un peu plus pour les suivants. L'incrémentation se fait donc via un incrémenteur 8 bits, pas une grosse ALU 32/64 bits. Il y a un gain en termes de consommation d'énergie, un incrémenteur 8 bits étant moins gourmand qu'une grosse ALU 32/64 bits. ===Les points de synchronisation du delta=== La technique ne fonctionne que si la vraie valeur du pointeur de pile est calculée au bon moment, avant chaque utilisation pertinente. Il y a donc des '''points de synchronisation''' qui forcent le calcul de la vraie valeur. Plus haut, nous avions dit que c'était à chaque fois qu'une instruction adresse le pointeur de pile explicitement, qui l'utilise comme opérande. Les instructions CALL, RET, PUSH et POP ne sont pas concernées par elles utilisent le pointeur de pile de manière implicite et ne font que l'incrémenter/décrémenter. Mais dans les faits, c'est plus compliqué. D'autres situations peuvent forcer une synchronisation, notamment un débordement du compteur delta. Le compteur delta est généralement un compteur de 8 bits, ce qui fait qu'il peut déborder. En cas de débordement du compteur, le séquenceur déclenche le calcul de la vraie valeur, puis réinitialise le compteur delta. La vraie valeur est donc calculée en avance dans ce cas précis. Précisons qu'un compteur delta de 8 bits permet de gérer environ 30 instructions PUSH/POP consécutives, ce qui rend les débordements de compteur delta assez peu fréquent. À noter que si le compteur delta vaut zéro, il n'y a pas besoin de calculer la vraie valeur, le séquenceur prend cette situation en compte. Un autre point de synchronisation est celui des interruptions et exceptions matérielles. Il faut que le compteur delta soit sauvegardé lors d'une interruption et restauré quand elle se termine. Idem lors d'une commutation de contexte, quand on passe d'un programme à un autre. Pour cela, le processeur peut déclencher le calcul de la vraie valeur lors d'une interruption, avant de sauvegarder les registres. Pour cela, le processeur intègre un mécanisme de sauvegarde automatique, qui mémorise la valeur de ce compteur dans le tampon de réordonnancement, pour forcer le calcul de la vraie valeur en cas de problème. La technique du ''stack engine'' est apparue sur les processeurs Pentium M d'Intel et les processeurs K10 d'AMD, et a été conservée sur tous les modèles ultérieurs. L'implémentation est cependant différente selon les processeurs, bien qu'on n'en connaisse pas les détails et que l'on doive se contenter des résultats de micro-benchmarks et des détails fournit par Intel et AMD. Selon certaines sources, dont les manuels d'optimisation d'Agner Fog, les processeurs AMD auraient moins de points de synchronisation que les processeurs Intel. De plus, leur ''stack engine'' serait placé plus loin que prévu dans le pipeline, après la file de micro-opération. ==La micro-fusion et la délamination== La '''micro-fusion''' est une optimisation qui retarde le décodage réel de certaines instructions assez loin dans le pipeline. Elle concerne surtout les instructions ''load-op'', mais pas que. D'autres instructions mémoire peuvent subir cette optimisation. L'essentiel est que, sans micro-fusion, ces instructions sont décodées en plusieurs micro-opérations. La micro-fusion retarde le décodage final de ces instructions, qui se fait assez tard dans le pipeline. Pour comprendre l'intérêt, nous allons devoir faire quelques explications. L'optimisation en question fait le décodage en deux temps. Prenons l'exemple d'une opération ''load-op'', qui est censée être décodée en deux micro-opérations : une lecture, puis une opération. Le décodage produit une '''macro-opération''' (terme d'Intel), qui est propagée dans le pipeline, pour être scindée en deux micro-opérations un peu avant les ALU et l'unité mémoire. La macro-opération est techniquement une micro-opération comme une autre, sauf que ce n'est pas la micro-opération finale. L'unité d'émission découpe cette macro-opération en deux micro-opérations, qui sont émises l'une après l'autre. Pour résumer, les instructions ''load-op'' ne sont complétement découpées en micro-opération lors de l'émission, pas lors du décodage. L'optimisation impacte ce qui se situe entre le décodeur d'instruction et l'unité d'émission : l'unité de renommage, la file de micro-opérations, le ''Loop Stream Detector'' et/ou le cache de micro-opération. L'intérêt de l'optimisation est que l'on fusionne deux micro-opérations en une seule macro-opération. Le cache de micro-opération et la file de micro-opération peuvent mémoriser plus de micro-opérations, vu que certaines sont fusionnées. Quant à l'unité de renommage, elle renomme une seule macro-opération au lieu de renommer deux micro-opérations, ce qui augmente le débit du renommage de registre. Par contre, cela complique un peu le travail de l'unité d'émission, qui doit découper les instructions ''load-op'' en deux et émettre les micro-opérations l'une après l'autre. Il faut noter qu'il n'y a pas de fusion proprement dite. Le décodeur ne décode pas deux micro-opérations séparées, avant de les fusionner. En réalité, il génère directement une macro-opération, qui correspond à deux micro-opérations, que ce soit plus tard dans le pipeline ou sur une autre architecture. D'ailleurs, la micro-fusion a lieu à l'intérieur d'une instruction, qui est censée être traduite en plusieurs micro-opérations. Et encore : pas toutes. La conséquence est que la technique n'a de sens que sur les processeurs CISC, avec des instructions assez complexes pour être décodées en plusieurs micro-opérations. En pratique, seuls les CPU x86 sont concernés. ===Les domaines de fusion=== La micro-fusion n'est pas spécifique aux processeurs superscalaires. En théorie, on peut l'implémenter sur un processeur non-superscalaire à émission dans l'ordre. Cependant, je ne connais aucun processeur à émission dans l'ordre qui implémente la micro-fusion, même si son implémentation est en théorie possible sur de tels processeurs. La micro-fusion est implémentée différemment selon que l'émission se fasse dans l'ordre, dans le désordre, avec un ''scheduler'', avec des stations de réservation, etc. J'ai dit plus haut que les micro-opérations sont générées lors de l'émission, mais le moment exact varie suivant le processeur. Pour simplifier le tout, nous parlerons de '''scission''' quand le processeur traduit une macro-opération en deux/trois micro-opérations. Le moment où a lieu la scission est théoriquement dans l'unité d'émission, mais celle-ci prend plusieurs formes selon que le processeur utilise l'émission dans l'ordre, dans le désordre, avec un ''scheduler'', avec des stations de réservation, etc. Les processeurs à exécution dans l'ordre sont le cas le plus simple. L'unité d'émission est alors en charge du découpage des macro-opérations en micro-opérations. La file de micro-opération ou le cache de micro-opérations mémorisent des macro-opérations. À l'opposé, le tampon de ré-ordonnancement mémorise lui des micro-opérations. Le reste du processeur n'est pas affecté. Sur les processeurs à exécution dans le désordre, les différences sont nombreuses. Le tampon de ré-ordonnancement peut mémoriser soit les micro-opérations finales, soit des macro-opérations. Il en est de même avec le ''scheduler'' et/ou les stations de réservation, qu'elles soient centralisées ou décentralisées. Tout dépend de comment se fait l'implémentation. Une implémentation simple effectue la scission des macro-opérations dans l'unité d'émission, comme sur les processeurs à exécution dans l'ordre. Sur de nombreux processeurs, l'unité d'émission et de renommage sont simplement fusionnées, ce qui fait que la scission a lieu juste après le renommage de registres. En conséquence, le tampon de re-ordonnancement et les ''schedulers'' ne voient que des micro-opérations. Les macro-opérations disparaissent juste avant. Cette implémentation est préférée avec un ''scheduler'' centralisée, car on voit mal comment scinder une macro-opération juste avant l'ALU. Une autre implémentation fait la scission en sortie de le ''scheduler'' ou des stations de réservation, qu'elles soient centralisées ou décentralisées. Dans ce cas, le tampon de re-ordonnancement fait de même. L'avantage est que le tampon de ré-ordonnancement stocke des macro-opérations, ce qui augmente sa taille effective. Par exemple, il utilise une seule entrée pour une instruction ''load-op'', au lieu de deux sans micro-fusion de ce type. ===La délamination=== La scission peut parfois avoir lieu plus tôt, dans des circonstances très précises. Concrètement, cela ne concerne que quelques micro-architectures d'Intel, pour des instructions très précises. La raison est les limitations du format des micro-opérations, pas une histoire d'optimisation. Le processeur aimerait pouvoir faire la micro-fusion, mais ne peut pas à cause de ces limitations. Une telle situation cause alors une '''délamination''' : les micro-opérations sont scindées précocement. Par exemple, sur la micro-architecture SandyBridge d'Intel, les opérations ''load-op'' sont fusionnées, sauf si elles utilisent l'adressage indicé. Les micro-opérations de ce processeur ne peuvent avoir que deux opérandes. Trois opérandes est de trop, et les opérations ''load-op'' en adressage indicé dépassent cette limite. Dans ce cas, les micro-opérations sont fusionnées en sortie du décodeur, mais sont scindés avant d’entrer dans la file de micro-opération. L'avantage n'est pas évident, vu que l'unité de renommage suit de près le décodeur d'instruction. Il est que le cache de micro-opérations mémorise des macro-opérations, pas deux micro-opérations. ===La micro-fusion des processeurs Intel et AMD=== La micro-fusion est apparue sur le Pentium M d'Intel, et a été conservée telle quelle sur les processeurs Intel suivants. Les processeurs AMD supportent la micro-fusion depuis au moins la micro-architecture AMD K8. Mieux que ça, la délamination n'était pas utilisée car les micro-opérations acceptaient plus de 2 opérandes. Que ce soit chez AMD ou Intel, elle concerne deux types d'instructions : les écritures mémoire et les instructions ''load-op''. Sur le Pentium M, il y avait quelques limitations, l'optimisation se limitant par exemple aux registres entiers et flottants, mais pas aux registres MMX, mais pas les registres SSE (nous verrons ces registres dans quelques chapitres). Mais les processeurs modernes n'ont plus cette limitation. La micro-fusion des CPU Intel concerne deux types d'instructions : les écritures mémoire et les instructions ''load-op''. Pour les écritures, la situation est plus complexe que pour les instructions ''load-op''. Sur les processeurs Intel précédents, les écritures étaient réalisées dans deux unités séparées : le calcul d'adresse dans une unité de calcul, l'écriture proprement dite dans l'unité mémoire. Elles prenaient donc deux micro-opérations. Le processeur a changé ses unités mémoire, ce qui fait qu'elle pouvait faire les deux en une seule micro-opération. Il s'agissait alors d'une optimisation du chemin de données, plus que de la micro-fusion proprement dite, mais je la mentionne ici malgré tout. La micro-fusion sur ce processeur avait un avantage en plus des avantages usuels : elle utilisait mieux les décodeurs. Les Pentium M avaient trois décodeurs pour décoder plusieurs instructions en même temps, chose qu'on détaillera dans le chapitre sur les processeurs superscalaires. Un seul décodeur pouvait décoder toutes les instructions, les deux autres ne peuvent décoder que les instructions simples, qui se décodent en une seule micro-opération. Avec la micro-fusion, les trois décodeurs peuvent gérer les écritures mémoire et les opérations ''load-op'', vu qu'elles deviennent des instructions simples. Sans cela, elles auraient été limitées au premier décodeur. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Le parallélisme mémoire | prevText=Le parallélisme mémoire | next=Les microarchitectures pour le x86 : haute performance | nextText=Les microarchitectures pour le x86 : haute performance }} </noinclude> 6jihqh78oxzfnnkcaunf30bjnoalutm 773639 773635 2026-09-29T21:20:50Z Mewtow 31375 773639 wikitext text/x-wiki Les processeurs vus auparavant ne peuvent émettre au maximum qu'une instruction par cycle d'horloge. Ils peuvent avoir plusieurs instructions qui s'exécutent en même temps, dans des unités de calcul séparées. C'est le cas dès qu'une instruction multi-cycles s'exécute. Par contre, ils ne peuvent démarrer qu'une seule instruction par cycle. Et quand on court après la performance, ce n'est pas assez ! Les concepteurs de processeurs ont inventés des processeurs qui émettent plusieurs instructions par cycle : les '''processeurs à émissions multiples'''. Un processeur à émission multiple charge plusieurs instructions en même temps, les décode en parallèle, puis les émet en même temps sur des unités de calculs séparées. Pour cela, il faut gérer les dépendances entre instructions, répartir les instructions sur différentes unités de calcul, et cela n'est pas une mince affaire. En général, pour un processeur à émission multiple capable d'émettre N instructions en parallèle, on parle de '''processeur à N voies''', ou encore un ''processeur à N pipelines''. [[File:Superscalarpipeline.svg|centre|vignette|upright=1.5|Pipeline RISC classique à cinq étages sur un processeur superscalaire. On voit bien que plusieurs instructions sont chargées en même temps.]] Les processeurs à émission multiple sont de deux types : les processeurs VLIW et les '''processeurs superscalaires'''. Nous mettons les processeurs VLIW de côté en attendant le prochain chapitre. La raison est qu'ils ont un jeu d'instruction spécialisé qui expose le parallélisme d'instruction directement au niveau du jeu d'instructions, là où les processeurs superscalaires restent des processeurs au jeu d'instruction normal. La différence principale entre processeur VLIW et superscalaire est qu'un processeur superscalaire répartit les instructions sur les unités de calcul à l’exécution, là où un processeur VLIW délègue cette tâche au compilateur. ==Le nombre de voies d'un processeur superscalaire== Les processeurs superscalaires les plus simples ne permettent que d'émettre deux micro-opérations à la fois, d'où leur nom de processeur ''dual issue'', ce qui se traduit en '''processeur à double émission'''. Les processeurs triple émission permettent eux d’émettre trois instructions à la fois. A l'opposé, les CPU superscalaires les plus puissants peuvent émettre jusqu'à 8-10 instructions simultanément. En 2026, les CPU superscalaires peuvent monter jusqu’à 10 µops émises en même temps, ce qui est énorme ! Et cela nous amène à faire une distinction entre les processeurs superscalaires dits '''étroits''' et ceux dits '''larges'''. Dans ce wikilivre, on part du principe que les processeurs superscalaires étroits émettent jusqu'à 4-5 µops à la fois, alors que les larges peuvent en émettre plus, l'intervalle entre les deux est une zone grise. Le nombre exact n'est pas fixé dans le marbre, la distinction est volontairement vague. Nous parlerons de la '''largeur d'un CPU superscalaire''' pour parler du nombre de voies, du nombre de µops émises en même temps. Plus un CPU superscalaire est large, plus il est performant ''toutes choses égales par ailleurs''. Mais dans les faits, vous pouvez oublier la partie en italique. Élargir un CPU superscalaire demande de rajouter beaucoup de circuits. Et ce cout en circuit aura un impact sur la performance. À budget en transistors limité, il y a un compromis entre élargir un CPU et rajouter du cache ou la taille des ''schedulers''/ROB et autres. ===Les contraintes d’appariement=== Prenons un processeur double émission, capable d'émettre deux instructions simultanément. Émettre deux instructions en même temps n'est pas toujours possible. Par exemple, si deux instructions sont dépendantes, on ne peut pas les émettre en même temps. Mais oublions un instant ces histoires de dépendances de données, et partons du principe que le CPU ait affaire à deux instructions indépendantes, une paire idéale. Un CPU double émission "parfait" pourrait exécuter n'importe quelle paire d'instruction. Par exemple, il pourrait émettre deux multiplications consécutives, deux lectures consécutives, une lecture et une écriture en même temps, etc. En pratique, aucun processeur ne permet cela. Implémenter un CPU superscalaire "parfait" aurait un cout en circuit beaucoup trop conséquent. Par exemple, pour émettre deux multiplications en même temps, il faudrait deux multiplieurs séparés. Idem pour exécuter deux accès mémoire simultané : cela demande d'avoir deux unités mémoire et un cache multiport. Mais en pratique, aucun CPU superscalaire ne fait cela. La totalité des CPU double émission se débrouille avec un seul circuit multiplieur et une seule unité mémoire. Et cela entraine l'apparition de dépendances structurelles, qui font que certaines paires d'instructions sont impossibles. Par exemple, impossible d'émettre deux multiplications en même temps avec un seul circuit multiplieur. Mais émettre une multiplication en parallèle d'une addition est parfaitement possible. Il y a donc des paires d'instructions autorisées et des paires interdites. Et la logique est la même sur les CPU à triple ou quadruple émission, et au-delà. : des triplets ou quadruplet d'instructions sont impossibles à émettre simultanément, alors que d'autres le sont. Pour le dire autrement, il y a des '''contraintes d'appariement''' sur les instructions à émettre en même temps. ===L'impact des contraintes d’appariement sur la performance=== Ces contraintes d’appariement ont un impact sur les performances, mais celui-ci peut être grandement mitigé. Les programmes informatiques utilisent en pratique beaucoup plus d'opérations entières de base que de multiplication, branchements et accès mémoire. Il y a environ 5 opérations entières de base pour une multiplication entière. En pratique, il est rare de devoir exécuter deux multiplications à la fois. Idem pour les décalages et rotations, qui sont assez éloignés les uns des autres. Deux branchements consécutifs sont quant à eux plus fréquents. Deux accès mémoire consécutifs est assez rare, mais ils restent assez proches les uns des autres malgré tout. La conséquence est que certaines paires d'instructions sont privilégiées par rapport au reste. Les paires regroupant deux calculs basiques (additions, soustractions, ...) sont systématiquement supportées, car dupliquer des ALU entières est facile. Les paires regroupant un calcul et une autre instruction sont elles aussi systématiquement supportées. Par contre, les paires avec deux branchements, deux accès mémoire, deux décalages/rotations, ou deux multiplications/divisions sont fréquemment interdites. Seuls les CPU superscalaires larges peuvent les permettre, et encore : sous conditions. Le résultat est que le processeur peut se débrouiller avec une seule unité mémoire et une unité de branchement. ===Terminologie pour la suite du chapitre=== Décrire les contraintes d’appariement demande de dire quelles combinaisons d’instructions sont autorisées ou interdites. Et pour cela, nous allons introduire les abréviations suivantes : * INT est un raccourci pour parler d'une opération entière simple, qu'une ALU entière peut exécuter. * MUL correspond à une opération entière complexe, typiquement une multiplication, éventuellement à une division. * FLOAT désigne une opération flottante, peut importe laquelle. * MEM désigne un accès mémoire, à savoir une instruction ou µop mémoire. * BRANCH désigne une instruction de branchement. Cette terminologie permettra de définir des paires d'instructions, qu'elles soient possibles ou interdites. Par exemple, l'expression INT + FLOAT désigne une paire d'instruction regroupant une instruction entière et une instruction flottante, peu importe l'ordre des deux instructions. Il en sera de même pour les triplets, quadruplets, ou plus. Par exemple, l'expression INT + INT + FLOAT + MUL désigne un quadruplet d'instructions regroupant : deux instructions entières, une instruction flottante, et une multiplication entière. J'utiliserais aussi des parenthèses pour regrouper certaines combinaisons. Par exemple, l'expression INT + (MUL /FLOAT) veut parler d'une paire d'instruction où la première est une opération entière basique, la seconde est : soit une multiplication, soit une opération flottante. ==Le ''front-end'' des processeurs superscalaires== Un processeur superscalaire doit charger, décoder, et exécuter plusieurs instructions par cycle. Par exemple, un processeur triple émission doit charger 3 instructions lors d'un premier cycle, puis les décoder au cycle suivant, et les exécuter au cycle suivant. Il travaille donc pas paquets de 3 instructions, dans cet exemple. Intuitivement, charger, décoder et exécuter plusieurs instructions à la fois demande de dupliquer des circuits. Par exemple, il faut dupliquer les décodeurs pour décoder plusieurs instructions. Les unités de calcul sont aussi dupliquées, sauf sur certains processeurs qui arrivent à ruser, mais laissons cela de côté pour plus tard. Mais d'autres circuits sont simplement modifiés, comme l'unité de chargement ou l'unité d'émission. Voyons ce qu'il en est dans le détail. {|class="wikitable" |- ! rowspan="2" | Processeur sans émission multiple | rowspan="2" | Chargement | rowspan="2" | Décodage | rowspan="2" | Renommage | rowspan="2" | Émission | Exécution / ALU | rowspan="2" | ''Commit''/ROB |- | Exécution / ALU |- ! rowspan="4" | Processeur superscalaire | rowspan="4" | Chargement | rowspan="2" | Décodage | rowspan="4" | Renommage | rowspan="4" | Émission | Exécution / ALU | rowspan="4" | ''Commit''/ROB |- | Exécution / ALU |- | rowspan="2" | Décodage | Exécution / ALU |- | Exécution / ALU |} Nous allons d'abord voir ce qu'il en est pour le ''front-end'', à savoir la partie du CPU qui s'occupe de charger et décoder les instructions. Elle regroupe l'unité de chargement, les décodeurs, l'unité de prédiction de branchement, la file de µops, la file d'instruction, et divers caches. En soi, les changements portent surtout sur l'unité de chargement et les décodeurs. ===Le chargement de plusieurs instructions consécutives=== Un processeur superscalaire charge plusieurs instructions en même temps, ''en tenant compte de la présence de branchements''. La partie en italique est importante et elle a une conséquence très forte : la manière de faire est fortement différente entre un CPU superscalaire étroit et large. Un CPU superscalaire étroit fait au plus simple : il charge un bloc de 2, 3, 4 instructions consécutives en mémoire RAM. Il faut alors doubler/tripler/quadrupler la taille du bus connecté au cache d'instruction. Par exemple, pour charger quatre instructions de 32 bits chacune, il suffit de lire un bloc de 128 bits dans le cache d'instruction. Un bloc de 8, 16, 32 octets est donc lu depuis le cache et est ensuite découpé en instructions, envoyées chacun à un décodeur. Charger plusieurs instructions consécutives ne marche bien qu'en absence de branchements. La présence de branchements casse cette dynamique, et il faut gérer leur présence. * Sans prédiction de branchement, toutes les instructions d'un bloc sont décodées et exécutées en même temps, même s'il y a un branchement dans le tas. * Avec prédiction de branchement, les instructions situées après le branchement ne sont pas décodées ni exécutées. L'unité de chargement coupe le bloc chargé au niveau du premier branchement pris, remplit les vides avec des NOP, avant d'envoyer le tout à l'unité de décodage. Les instructions à l'adresse de destination seront chargées au cycle suivant, en chargeant un nouveau bloc. [[File:Fetch sur un processeur superscalaire avec prediction de branchements.png|centre|vignette|upright=2|Fetch sur un processeur superscalaire avec prédiction de branchements.]] Un autre défaut est que sur le CPU charge un bloc de 128 bits à la fois, les instructions doivent être alignées sur 128 bits. Et on peut généraliser à n'importe quelle taille de bloc. Si les instructions ne sont pas alignées, il faut gérer la situation. Il arrive qu'une instruction soit à cheval sur deux blocs, avec un morceau dans le premier bloc, un autre dans le second. Dans ce cas, l'instruction est chargée en deux fois, et des circuits doivent gérer la situation pour recoller les morceaux. Sur les CPU avec des instructions de taille fixe, le problème ne survient que rarement. Mais il est fréquent avec des instructions de taille variable. Un autre défaut est lié aux branchements. Imaginez qu'un branchement s'exécute et branche vers une instruction de destination. Rien n'indique que l'instruction de destination sera au tout début d'un bloc. Si ça se trouve, elle sera en troisième position d'un bloc de 4 instructions. Une solution simple charge le bloc en respectant l'alignement, et les deux premières instructions du bloc ne sont pas à exécuter. Il y a donc une petite perte de performance. Certains CPU, comme l'IBM RS/6000, ont la machinerie charger un bloc de N instructions même s'il n'est pas aligné. La machinerie en question se trouve dans le cache d'instruction et est tout sauf simple à expliquer, ce qui fait que je me permets de la passer sous silence. Un détail, cependant : elle ne permet pas de charger des blocs qui sont à cheval sur deux lignes de cache. ===Le décodage parallèle des instructions=== Pour le décodage des instructions, plusieurs instructions sont décodées en même temps. On parle alors de '''décodage parallèle'''. Pour ce faire, un processeur superscalaire contient plusieurs décodeurs, chacun pouvant décoder une instruction en parallèle des autres. Prenons par exemple un processeur superscalaire à 4 voies : le décodage se fera dans quatre décodeurs séparés, qui fonctionneront en parallèle. Cependant, cette implémentation ne marche bien que pour les processeurs RISC, les processeurs CISC devant faire avec un microcode gourmand en circuits. Les processeurs CISC utilisent des décodeurs hybrides, avec un microcode qui complémente un décodeur câblé. Dupliquer le microcode aurait un cout en transistors trop important, ce qui fait que seuls les décodeurs câblés sont dupliqués. Les CPU CISC superscalaires disposent donc de plusieurs décodeurs simples, capables de décoder les instructions les plus courantes, avec un seul microcode. La conséquence est qu'il n'est pas possible de décoder deux instructions microcodées en même temps. Par contre, il reste possible de décoder plusieurs instructions non-microcodées ou une instruction microcodée couplée à une instruction non-microcodée. Vu qu'il est rare que deux instructions microcodées se suivent dans un programme, le cout en performance est extrêmement mineur. Il faut noter qu'une instruction correspond à une ou plusieurs µops. Il est donc possible de charger 5 instructions et de se retrouver avec 8 µops en sortie des décodeurs. Et c'est la source d'une distinction très importante. Plus haut, j'ai parlé de processeurs superscalaires à N voies. La terminologie peut avoir deux interprétations. La première est que le processeur charge/décode N instructions à la fois. Une seconde est qu'il est capable d'exécuter/émettre N µops en même temps. Les deux ne sont pas équivalentes, vu qu'un processeur superscalaire peut, par exemple, charger/décoder N instructions et émettre/exécuter N+2 µops. La distinction est particulièrement importante sur les processeurs superscalaires larges. Certains d'entre eux sont capables de charger 5 instructions et d'en émettre le double ! Un exemple classique était les processeurs Athlon d'AMD, qui pouvaient décoder deux instructions par cycle, mais émettre 4 µops par cycle. Ce n'était pas un problème, car beaucoup d'instructions, même basiques, étaient décodées en 2 µops. ===L'émission parallèle des instructions=== La superscalarité modifie en profondeur l'unité d'émission, notamment au niveau de son interface. Avant, elle recevait une micro-opération sur son entrée, et fournissait la micro-opération émise sur une sortie. Et cela vaut aussi bien pour une unité d'émission simple, un ''scoreboard'', un ''scheduler'' ou des stations de réservation. Mais avec l'émission multiple, les sorties et entrées sont dupliquées. Pour la double émission, il y a deux entrées vu qu'elle doit recevoir deux micro-opération décodées/renommées, et deux sorties pour émettre deux micro-opérations. Dans ce qui suit, nous ne parlerons pas d'entrée et de sortie, mais de '''ports de décodage''' et de '''ports d'émission'''. Les ports de décodage reçoivent des micro-opérations provenant de l'unité de décodage, les ports d'émissions sont pour les micro-opérations émises. Les ports d'émission injectent les micro-opérations émises dans le pipeline, elles sont propagées au banc de registre, aux ALUs, etc. Un processeur superscalaire a forcément plusieurs ports d'émission (et de décodage). Si l'interface de l'unité d'émission change, l'intérieur est tout autant modifié. Sur un CPU non-superscalaire, l'unité d'émission reçoit une µop "candidate à l'émission", et détecte les dépendances entre avec les µops en vol, en cours d'exécution dans le pipeline. Et c'est toujours le cas sur les processeurs superscalaires : l'unité d'émission détecte les dépendances entre les µops candidates et les µops en vol. Mais avec la siperscalarité, elle doit en plus tester les dépendances entre les µops candidates. Si l'unité d'émission est un ''scoreboard'', il doit détecter les dépendances entre instructions émises simultanément et les sérialiser si besoin. Avec un ''scheduler'', il n'y a pour ainsi dire rien à faire, vu que les dépendances sont éliminées par le renommage de registre et que les signaux de réveil gèrent les dépendances RAW. C'est la raison pour laquelle les processeurs superscalaires modernes n'utilisent pas de ''scoreboard''. ==Les processeurs implémentés avec plusieurs pipelines== Nous venons de voir comment la superscalarité impacte le ''front-end'', il est maintenant de voir ce qu'il en est de l'unité d'émission et des ''back-ends''. Un processeur superscalaire peut utiliser l'exécution dans le désordre et le renommage de registres, mais ce n'est pas une obligation. Historiquement, les premiers processeurs superscalaires n'utilisaient pas d'exécution dans le désordre. Le meilleur exemple est celui du Pentium 1 et 2 d'Intel. Ils étaient tous deux des processeurs superscalaires, mais n'avaient pas d'exécution dans le désordre, qui est apparue sur le Pentium 3. les explications sont plus simples si on met de côté l'exécution dans le désordre. Vous vous dites que l'implémentation d'un processeur superscalaire n'est pas la même suivant que le CPU utilise l'exécution dans le désordre, ou non. Mais dans les faits, la distinction est plus subtile que ca. Pour l'expliquer, je vais utiliser une classification originale, qui sépare les processeurs superscalaires en trois sous-types. La distinction se fait sur la manière dont la superscalarité est implémentée en matériel.La classification que j'utilise distingue : * Les processeurs avec plusieurs pipelines, sans exécution dans le désordre. * Les processeurs superscalaires avec un pipeline dynamique. * Les processeurs avec des ''schedulers'' décentralisés. La distinction n'est pas qu'une question d'implémentation matérielle. Elle impacte aussi le ratio entre instructions chargées/décodées et instructions émises. Vous vous dites que les deux sont égales, mais ce n'est le cas que sur les processeurs avec N pipelines ! Sur les autres processeurs, il est possible de décoder 4 instructions, mais d'en émettre maximum 6 par cycle ! Et sur les CPU avec des ''schedulers'' décentralisés, il y a aussi une différence entre le nombre d'instructions qui sont ''dispatch'' et ''schedule''. La catégorie la plus simple est celle des '''processeurs avec plusieurs pipelines'''. Ce sont des processeurs superscalaires sans exécution dans le désordre. Ils partent d'un processeur non-superscalaire, et ajoutent un second pipeline, en sortie de l'unité d'émission. Le second pipeline permet l'émission parallèle d'une seconde instruction. Le second pipeline n'est pas identique au pipeline originel, sur plusieurs points. Premièrement, il n'a pas exactement les mêmes circuits. Le second pipeline est généralement composé d'une unité de calcul, d'une FPU, éventuellement d'un second banc de registres, guère plus. Il permet d'exécuter une seconde opération de calcul, pas plus, ce qui est à l'origine de contraintes d'appariement assez fortes. De plus, il n'a pas forcément la même longueur, il peut avoir des étages en moins ou en plus. Il s'agit de la forme la plus simple de processeur superscalaire et nous allons leur consacrer cette section. ===La double émission entière-flottante=== L'exemple le plus simple utilise un second pipeline pour les opérations flottantes, séparé du pipeline originel. L'ajout d'un pipeline flottant permet d'émettre une micro-opération entière en même temps qu'une micro-opération flottante, ce qui s'appelle la '''double émission entière-flottante'''. La micro-opération entière s'exécute dans l'ALU entière, la micro-opération flottante dans la FPU. Les exemples les plus notables sont le PA-RISC 7100, le POWER 1 (RIOS .& et .9) et le PowerPC 601. L'Apollo DN10000 et l'Intel i860 utilisaient aussi cette forme de double émission, mais étaient des prototypes de CPU VLIW. [[File:Double émission entière-flottante.png|centre|vignette|upright=2|Double émission entière-flottante]] Pour bien expliquer les choses, prenons le processeur illustré ci-dessous, avec deux ''back-end'' séparés : un pour la FPU, et un autre pour le reste. Les instructions entières et mémoire passent toutes par le ''back-end'' généraliste. [[File:CPU non-superscalaire basique, avec une FPU.png|centre|vignette|upright=1.5|CPU non-superscalaire basique, avec une FPU]] Les deux ''back-end'' sont des pipelines séparés, mais il faut que l'unité d'émission soit spécialement conçue pour en profiter. Un processeur simple émission peut démarrer une seule µop par cycle : soit la µop est envoyée au ''back-end'' flottant, soit elle est envoyée au ''back-end'' général. Avec la double émission entière-flottante, le processeur peut envoyer une µop dans chaque pipeline, à chaque cycle. Vu que la FPU et son banc de registre forment déjà un pipeline séparé, les seules modifications se font au niveau du ''front-end'', unité d'émission inclue. {| |- |[[File:CPU simple émission avec une FPU.png|centre|vignette|upright=1.5|CPU simple émission avec une FPU.]] |[[File:Double émission entière flottante avec un second pipeline.png|centre|vignette|upright=1.5|CPU avec un second pipeline flottant.]] |} Notez que le terme double émission ''entière''-flottante est un peu trompeur. En réalité, la technique permet d'émettre une instruction flottante avec n'importe quelle autre instruction non-flottante, avec des restrictions pour les branchements. Il est par exemple possible d'exécuter un calcul flottant en parallèle d'un accès mémoire. Sur les CPU 32 bits, il est possible de faire les multiplications dans la FPU. Pour rappel, la FPU contient un multiplieur entier 53-54 bits, pour multiplier les mantisses de deux flottants 64 bits, qu'on peut utiliser pour faire les multiplications entières 32 bits. Cela permet d'émettre une multiplication en même temps qu'une opération entière dans l'ALU. Ainsi, le CPU pouvait émettre deux instructions : une opération entière de base, avec soit une multiplication, soit une opération flottante. En clair, une émission de type INT + (MUL /FLOAT). Par contre, on perd la possibilité d'émettre une multiplication entière avec une opération flottante, mais c'était un compromis qui en valait la peine. Le CPU PA-RISC 7100 implémentait cette optimisation. Il s'agissait d'un CPU double émission entière-flottante, qui utilisait donc un partitionnement assez simple. Le combo partitionnement + reconditionnement permettait ici de gagner en performance, pour un cout en matériel très limité. D’autant plus limité que le jeu d'instruction prévoyait le reconditionnement de la FPU. Les multiplications ne lisaient pas leurs opérandes dans les registres entiers, mais dans les registres flottants. ===La double émission entière=== Une autre possibilité ajoute un second pipeline, capable d'exécuter des opérations entières simples, appelé le pipeline entier. Le processeur supporte alors la '''double émission entière''', à savoir qu'ils peuvent émettre une opération entière en plus d'une autre instruction. L'opération entière en question est une opération simple, comme une addition, une soustraction, une opération bit à bit, une comparaison, etc. Les exemples classiques sont les processeurs Intel i960 et Pentium. L'implémentation était différente entre l'i960 et le Pentium : Le Pentium avait une seconde ALU entière, alors que le i960 rusait. Le Pentium dupliquait l'ALU entière, pour créer un second pipeline entier. Sur le Pentium originel, les contraintes d'appariement étaient assez strictes. Le Pentium avait une FPU, mais ne pouvait pas l'utiliser en double émission. Il lui était impossible d'exécuter une opération flottante en même temps qu'une opération entière (branchements inclus). Le Cyrix 6x86 était une sorte de Pentium produit par l'entreprise Cyrix, avec une microarchitecture différente. Il avait des contraintes d’appariement réduites. Par exemple, il pouvait émettre une opération flottante en parallèle d'une opération entière. Nous détaillerons ces processeurs dans le prochain chapitre, qui porte justement sur les CPU superscalaires x86. [[File:CPU simple et double émission avec un second pipeline entier.png|centre|vignette|upright=2.5|CPU simple et double émission avec un second pipeline entier.]] L'Intel i960 n'avait pas de FPU, juste une ALU entière et une unité mémoire. Il utilisait l'unité mémoire comme une seconde ALU entière limitée. Pour rappel, une unité mémoire contient une AGU, à savoir une ALU spécialisée dans les calculs d'adresse. Elle est capable de faire des additions, soustractions, et quelques décalages limités (des décalages par 2, 4, 8, pas plus). L'Intel i960 ajoutait des connexions entre AGU et banc de registre, afin que celle-ci serve de seconde unité de calcul. L'AGU est déjà reliée aux deux ports de lecture, pour lire les opérandes du calcul d'adresse, il suffit de la connecter sur le port d'écriture. Le processeur peut alors émettre deux instructions/µops entières, sous certaines conditions. [[File:Emission multiple des opérations entières, double émission.png|centre|vignette|upright=2|Émission multiple des opérations entières, double émission.]] ==Les processeurs superscalaires dynamiques== Les processeurs précédents, avec 2 pipelines, avaient une unité d'émission assez simple. Elle avait deux ports de décodage, et deux ports d'émission. Le nombre de ports de décodage et d'émission étaient identiques. Vous vous dites que c'est naturel, et intuitif, que c'est normal pour un processeur superscalaire. Mais en réalité, la majorité des processeurs superscalaires a plus de ports d'émission que de décodage. Expliquer pourquoi va cependant nous demander de parler de comment la superscalarité exploite les unités de calcul. Posons-nous cette question : de combien d'unités un processeur superscalaire a besoin ? Les unités en question ne sont nécessairement des unités de calcul, l'unité mémoire et l'unité de branchement comptent aussi. La réponse dépend du nombre de voies. Si le ''front-end'' charge et décode un paquet de N instructions, exécuter ces N instructions simultanément demandera là aussi au moins N unités de calcul. Notez le terme : ''au moins'', car c'est là tout l'enjeu de cette section. La réponse dépend aussi des contraintes d’appariement. Pour un CPU superscalaire "parfait", sans contraintes d’appariement, toutes les unités doivent être dupliquées, y compris l'unité mémoire. Un processeur à double émission parfaite devrait dupliquer l'ALU entière, le ''barrel shifter'', le circuit multiplieur, la FPU, l'unité mémoire, et l'unité de branchement, ce qui ferait passer de 6 unités à 12. Le cout en circuit est énorme, même pour de la double émission ! Et pour un CPU à N pipelines, le cout en circuit encore plus prohibitif ! En pratique, les processeurs superscalaires qui font ça sont très rares. La majeure partie des processeurs superscalaires utilisent d'autres techniques : le partitionnement, la duplication partielle des ALUs, la duplication des autres unités. ===Le partitionnement des unités fonctionnelles=== Les CPU superscalaires les plus simples ne dupliquent pas leurs unités de calcul, ils se contentent d'exploiter les unités existantes. Et pour expliquer comment, nous allons partir de l'exemple d'un processeur non-superscalaire contient une ALU entière, une FPU, une unité mémoire et une unité de branchement. Les quatre unités peuvent fonctionner en parallèle, à savoir qu'une unité peut exécuter une instruction à elle toute seule, sans interagir avec les autres. Cela suffit pour créer un processeur quadruple émission, qui peut émettre en même temps : une opération entière, une opération flottante, un branchement, un accès mémoire. Le principe marche aussi sur un processeur avec moins de 4 unités, par exemple sans FPU et/ou sans unité de branchement, ou avec au contraire des unités en plus. L'idée générale est d’émettre une µops séparée dans chaque unité fonctionnelle. Utiliser ainsi les unités existantes, pour rendre un CPU superscalaire, s'appelle le '''partitionnement superscalaire'''. Le terme n'est pas beaucoup utilisé en dehors de quelques vieux articles académiques. Le partitionnement est fortement dépendant du jeu d'instruction, car il demande de bien séparer instructions entières, flottantes, branchements et instructions mémoire. Et autant c'est bien le cas sur les CPU RISC, autant les CPU CISC ne sont pas dans ce cas. Les CPU CISC ont des instructions ''load-op'', qui effectuent une instruction arithmétique et une µop mémoire. Et ces instructions sont très compliquées à implémenter avec le partitionnement. Et au-delà de ça, les CPU CISC ont beaucoup d'instructions qui sont décodées en plusieurs µops, à exécuter dans un ordre bien précis. On peut pas émettre les µops en question simultanément. Le partitionnement a un cout en circuit très limité, pour un gain en performance lui aussi limité. Pour reprendre le CPU de l'exemple précédent, il est rare que l'on ait à exécuter ces quatre instructions en même temps. En pratique, les combinaisons fréquentes sont les combinaisons calcul + accès mémoire, calcul + branchement, calcul entier + calcul flottant. Utiliser une quadruple émission de ce type n'est donc pas une bonne idée, alors que la double émission parait plus adaptée. Et c'est là que la différence entre ports d'émission et de décodage devient intéressante. L'idée est d'avoir une unité d'émission avec deux ports de décodage, et 4 ports d'émission (un par unité). Les contraintes d’appariement varient alors suivant le processeur, mais la règle générale est que si deux micro-opérations tombent dans deux unités différentes, on peut les émettre en même temps. En clair, on peut émettre une opération entière avec une opération flottante, une opération entière avec un branchement, un accès mémoire avec un branchement, etc. Et cela rend le partitionnement bien plus intéressant que prévu. Les tout premiers CPU superscalaires étaient des CPU double émission, qui utilisaient le partitionnement avec : une ALU entière, une unité mémoire et une FPU. Nous parlerons de '''partitionnement INT-FLOAT-MEM'''. L'avantage sur la double émission flottante est que les combinaisons INT + MEM et FLOAT + MEM étaient autorisées. L'intérêt était d'émettre une opération en parallèle d'un accès mémoire, ce qui est un doublet d'instruction assez fréquent. Les exemples classiques sont l'HyperSPARC, de l'alpha 21064 et du PowerPC 603. Les contraintes d’appariement variaient grandement suivant le processeur. Le PowerPC 603 implémentait une double émission "parfaite". C'est à dire que toutes les combinaisons possibles à deux instructions étaient possibles, que ce soit INT + FLOAT, INT + MEM, FLOAT + MEM. En plus de cette double émission "parfaite", le CPU utilisait la technique dite de ''branch folding'', qui permettait d'exécuter un branchement sans utiliser d'unité de calcul, ce qui fait qu'il était qualifié de ''CPU 2-way + Branch''. A l'opposé, le processeur alpha 21064 avait pas mal de contraintes d’appariement, à savoir que certaines combinaisons de deux instructions étaient interdites, bien que compatibles avec les unités disponibles. Une des raisons est que le banc de registre n'avait pas assez de ports de lectures, ce qui fait que certaines combinaisons avec une écriture mémoire n'étaient pas permises. Les concepteurs avaient volontairement inséré ces contraintes afin de simplifier le design du processeur. Avant de poursuivre, précisons que la FPU regroupe un additionneur flottant et un multiplieur flottant. Et ce fait peut être exploité pour approfondir le partitionnement. La '''double émission FADD/FMUL''' permet d'émettre une addition flottante en même temps qu'une multiplication flottante. Elle a été utilisée sur les processeurs x86, Alpha et SPARC. Les autres circuits de calcul flottant sont souvent regroupés avec l'additionneur. La division est parfois e même port que le multiplieur flottant, parfois sur celui de l'additionneur (quand elle est microcodée et exécutée en enchainant les soustractions). ===La duplication des ALU entières=== Le partitionnement est une technique élégante, simple, facile à implémenter et au cout en circuits modeste. Mais il faut avouer que cela ne donne pas des CPU superscalaires très efficaces. La raison est que le partitionnement permet d'émettre des paires, triplets, quadruplets de micro-opérations qui sont rares en pratique. Les combinaisons les plus fréquentes en pratique sont des paires/triplets d'opérations entières, souvent des paires/triplets d'additions ou d'opérations entières simples. Il est donc primordial d'émettre plusieurs opérations entières simultanément. Le fait d'émettre et d'exécuter plusieurs opérations entières en même temps s'appelle l''''émission entière multiple'''. Pour exécuter la seconde/troisième opération entière, il faut dupliquer les ALU entières (ou réutiliser l'AGU comme ALU entière comme le fait l'Intel i960). Le processeur doit avoir deux ALU entières pour de la double émission entière, trois pour de triple émission entière, etc. De plus, il faut ajouter des ports au banc de registre, pour lire deux fois plus d'opérandes et décrire deux résultats. Et enfin, il faut rajouter un port d'émission pour pouvoir émettre une micro-opération entière en plus. [[File:Processeur non-superscalaire basique 03.png|centre|vignette|upright=2|Processeur non-superscalaire basique]] La tendance est de multiplier les ALU entières, mais pas le circuit multiplieur. Le cout en transistors est alors grandement réduit, au prix de l'apparition de dépendances structurelles. Le CPU peut émettre deux additions en même temps, ou une addition et une multiplication, mais pas deux multiplications. Il en est de même avec le ''barrel shifter'', qui n'est pas dupliqué. Il est donc possible d'émettre un décalage avec une opération de base, mais pas deux décalages en parallèle. Mais ces contraintes d’appariement ne sont pas un problème, car il est rare de devoir émettre deux multiplications/décalages en même temps. La plupart des programmes sont majoritairement remplis d'additions, avec des multiplications assez rares et des décalages qui le sont encore plus. La moyenne est proche d'une multiplication pour 4/5 additions. Vu que des multiplications consécutives sont très rares, dupliquer le multiplieur est presque inutile. Disposer de plusieurs circuits multiplieurs ou de plusieurs ''barrel shifters'' serait donc un cout en circuits qui ne servirait que rarement et n'en vaut pas la chandelle. Il faut noter que sur les CPU 32 bits, les multiplications peuvent être exécutées dans la FPU ou dans un multiplieur séparé, tout dépend de si le CPU exécute les multiplications dans la FPU ou pas. {|class="wikitable" |- ! Voie d'émission n°1 !! Voie d'émission n°2 !! Voie d'émission n°3 |- | ALU entière || ALU entière || FPU |} Reste à connecter les unités de calcul à l'unité d'émission (indirectement, car il y a des étages de pipeline entre les deux). Une implémentation basique utilisée un port d'émission par unité. Prenons l'exemple d'un CPU superscalaire avec 4 ALU entières, une FPU, et une unité mémoire. Vu qu'il y a 6 unités, cela fait donc 6 ports d'émission. L'exemple historique le plus impressionnant est celui du Motorola 88110, un CPU double émission qui possède 10 unités. Il contient deux ALU entières, un circuit multiplieur, un circuit diviseur, une unité de manipulation de bits, une unité mémoire, un additionneur flottant, et deux unités graphiques pour des calculs impliquant des pixels. Le multiplieur est utilisé à la fois pour les multiplications entières, flottantes et le produit de deux pixels. Idem pour le diviseur, qui sert pour les divisions entières et flottantes. Et chaque unité a son propre port d'émission. La conséquence est que les contraintes d'appariement du Motorola 88110 sont simples : tant que deux µops atterrissent dans des unités séparées, la paire est permise. Il est par exemple possible d'émettre simultanément deux opérations entières simples, vu qu'il y a deux ALU. Par contre, impossible d'émettre simultanément deux multiplications, deux divisions, deux opérations flottantes, deux manipulations de bit, deux accès mémoire, etc. De plus, le partage du multiplieur fait qu'on ne peut pas émettre une multiplication entière avec une multiplication flottante. Idem avec les divisions, vu que le diviseur est aussi partagé. Ce sont les seules contraintes. ===Le partage des ports d'émission=== La présence d'un circuit multiplieur et d'un ''barrel shifter'' pose des problèmes pour le partitionnement. Il est possible d'avoir un port d'émission dédié au multiplieur, et un autre au ''barrel shifter'', qui sont séparés de ceux pour l'ALU entière. Il est alors possible d'émettre une opération entière, une multiplication et un décalage, simultanément. Nous parlerons de '''partitionnement entier''' pour désigner cette possibilité. [[File:Partitionnement superscalaire entier.png|centre|vignette|upright=2|Partitionnement superscalaire entier.]] Le partitionnement entier est cependant très rare, car le gain en performance serait trop faible au regard des couts en circuit. Quelques processeurs historiques l'utilisaient, mais ce n'est plus le cas de nos jours. La raison est que les multiplications et les décalages sont assez rares dans le code, ce qui fait que le port d'émission associés sont sous-utilisés. Et un port d'émission a un cout en circuit assez important. Et c'est sans compter qu'ajouter des ports sur le banc de registres juste pour un multiplieur sous-utilisé n'en vaut pas la peine. L'idéal serait de trouver un moyen de réduire le nombre de ports d'émissions, sans réduire le nombre d'unités de calcul. [[File:Emission multiple des opérations entières, implémentation naive.png|vignette|Émission multiple des opérations entières, implémentation naive]] La solution consiste à '''partager les ports d'émission''', à savoir connecter un port d'émission à plusieurs unités de calcul. L'exemple classique est justement lié aux circuits multiplieur et ''barrel shifters''. L'idée est que le multiplieur et le ''barrel shifter'' sont mis sur le même port d'émission qu'une ALU entière. Prenons par exemple le processeur à double émission entière illustré ci-contre. Un port d'émission est relié à une ALU entière seule, et l'autre port d'émission alimente la seconde ALU entière et le multiplieur. La conséquence est que le processeur peut émettre deux opérations entières, dont une multiplication. Si on avait utilisé un port d'émission dédié au multiplieur, il aurait été possible d'émettre deux opérations entières et une multiplication. On perd donc une voie, mais on gagne en flexibilité et on économise des circuits. Notons que ce partage signifie aussi que le multiplieur partage les ports sur le banc de registre, ce qui fait une double économie. [[File:Emission multiple des opérations entières, implémentation courante.png|centre|vignette|upright=1.5|Émission multiple des opérations entières, implémentation courante]] En général, le ''barrel shifter'' et le multiplieur sont placés sur deux voies d'émission séparés, ce qui permet d'émettre un décalage et une multiplication en même temps. Les mettre sur le même port ne le permettrait pas. {|class="wikitable" |- ! Voie d'émission n°1 !! Voie d'émission n°2 !! Voie d'émission n°3 |- | * ALU entière * Multiplieur | * ALU entière * Barrel shifter | FPU |- | * Additions, soustractions, opérations bit à bit, etc. * Multiplication | * Additions, soustractions, opérations bit à bit, etc. * Décalages et rotations | Opération flottante |} Terminons concernant les multiplieurs avec une dernière subtilité. Pour rappel, les processeurs modernes intégrent en réalité deux multiplieurs différents. Le résultat d'une multiplication est très large et prend deux registres. Par exemple, une multiplication de deux opérandes 64 bits donne un résultat sur 128 bits, ce qui ne tient pas dans un registre, mais en prend deux. L'instruction de multiplication classique ne calcule que les 64 bits de poids faible. mais elle est complétée par d'autres instructions de multiplication qui peuvent faire le calcul complet. Pour résoudre le problème, les processeurs modernes intègrent deux instructions de multiplications : une qui calcule les bits de poids faible du résultat, une autre qui calcule les bits de poids fort. Et ces deux instructions sont associées à deux multiplieurs séparés, aux circuits différents. Le multiplieur qui calcule les bits de poids faible du résultat est appelé le ''low multiplier'', l'autre est appelé le ''high multiplier''. Le second multiplieur est souvent placé sur un second port d'émission, différent du premier multiplieur, partagé avec une ALU. L’avantage de mettre les deux multiplieurs sur deux ports d'émission différents est qu'une multiplication complète peut être réalisée en utilisant les deux multiplieurs en parallèle. Les deux sous-multiplications sont émises en même temps, exécutées en même temps. pas besoin d'exécuter l'une puis la seconde, d'où un gain performance appréciable. Nous venons de voir comment partager un port d'émission entre une ALU et un multiplieur. Mais au-delà de cet exemple, le partage des ports d'émission peut appliquer à n'importe quelle unité. Prenons l'exemple d'un CPU superscalaire avec 4 ALU entières, une FPU, et une unité mémoire. Vu qu'il y a 6 unités, cela fait donc 6 ports d'émission. Cependant, il est rare qu'un bloc de 6 instructions contienne exactement 4 opérations entières, une opération flottante, et un accès mémoire. Beaucoup de ports d'émission seraient sous-utilisés. La solution est de partager des ports d'émission, pour passer à la quadruple émission. Le CPU peut alors répartir 4 instructions sur les ports d'émission adéquats, à chaque cycle. Le CPU a donc 4 ports de décodage et 6 ports d'émission. Une implémentation classique permet n'importe quelle combinaison de 4 instructions compatibles avec les 6 unités. Par exemple, il devient possible d'émettre simultanément 4 additions, la combinaison 2 * INT + FLOAT + MEM, 3 * INT + MEM, et bien d'autres. L'exemple relie une ALU entière, la FPU et l'unité mémoire sur le même port. Le CPU a alors quatre ports d'émission, qui ne sont pas "identiques". Trois d'entre eux sont reliés à une ALU entière chacun, rien d'autre. Le quatrième est lui relié à une ALU entière, la FPU et l'unité mémoire. On économise alors deux ports d'émission, mais cela entraine l'apparition de contraintes d’appariement. Le CPU peut émettre 3 opérations entières + n'importe quelle autre opération. Mais les autres combinaisons sont interdites. Le CPU peut émettre 6 opérations entières simultanément, grâce à 6 ALU entières. Les accès mémoire ou opérations flottantes ne viennent pas en plus, mais en remplacement des opérations entières. Regrouper plusieurs ALU sur un même port d'émission est donc à l'origine de dépendances structurelles, de nouvelles contraintes d’appariement. Dans certaines situations de '''''port contention''''', on a assez d'ALU pour exécuter N micro-opérations, mais la répartition des ALUs sur les ports l'empêche. Impossible d'émettre deux micro-opérations sur deux ALU si elles sont sur le même port d'émission. On peut réduire les cas de ''port contention'' en répartissant correctement les ALU sur les ports d'émission, mais sans jamais les supprimer complétement. Un exemple est celui du PowerPC 604. Il implémentait la quadruple émission, alors qu'il avait 5 unités de calcul. Mais deux unités partageaient un même port d'émission. Dans le détail, il avait deux ALU entières, un circuit multiplieur/diviseur, une FPU, une unité mémoire. La FPU et le multiplieur étaient sur le même port d'émission. En conséquence, le CPU pouvait émettre seulement les combinaisons INT + INT + MEM + (MUL/FLOAT). : Il est intéressant de voir l'exemple d'un processeur superscalaire parfait, sans contraintes d'appariement, à N voies. Pour cela, on part d'un processeur non-superscalaire, avec M unités de calcul. Un tel processeur peut s'implémenter avec N ports d'émission, chacun relié à M unités de calcul possibles, ce qui fait que les M unités de calcul sont dupliquées en N exemplaires. Si on prend par exemple un CPU non-superscalaire avec une ALU, une FPU, une unité mémoire et une unité de branchement, un port d'émission sera relié à une ALU, une FPU, une unité mémoire et une unité de branchement. ===La duplication des autres unités fonctionnelles=== Dupliquer les ALU entière est une première étape, mais il est aussi possible de dupliquer les autres unités fonctionnelles. Par exemple, il est possible de dupliquer l'unité mémoire ou l'unité de branchement. Reste à voir quelles unités dupliquer, et pourquoi. Précisons que dans ce qui va suivre, nous allons parler de la duplication des unités en général, pas seulement des unités mémoire/branchement. Nous allons continuer de parler de la duplication des ALU entières dans ce qui suit, mais de manière plus générale. Pour un processeur à N voies, il est théoriquement possible de dupliquer toutes les unités en N exemplaires. Mais ce n'est jamais fait en pratique, car le cout en circuits serait trop important et le gain en performance trop faible. Mieux vaut dupliquer certaines unités bien précises, quitte à avoir des contraintes d'appariement. Et à ce petit jeu, toutes les duplications ne se valent pas, certaines sont plus rentables en matière de performance, le cout en circuit n'est pas le même selon l'unité, etc. La rentabilité en performance dépend surtout des contraintes d'appariement. Les contraintes d'appariement entrainent une baisse de performance significatives si elles interdisent des paires d'instructions fréquentes. Aussi, les opérations très fréquentes, souvent appairées, gagnent à dupliquer l'unité associée. Et au contraire, les unités rarement utilisées ne doivent pas être dupliquées. Il se trouve que les unités les plus utilisées sont les ALU entières, suivies par les unités mémoire et l'unité de branchement. Le cout en circuit n'est aussi pas le même. Dupliquer les ALU entière est trivial, car elles ont un budget en transistors assez faible. Les circuits multiplieurs, diviseurs, et les ''barrel shifter'' ont eux un cout en transistor plus élevés. Si on devait faire un classement, on aurait : ALU entière < ''barrel shifter'' < multiplieur. Pour les unités mémoire, le cout en transistor est là aussi conséquent. Le résultat final est que dupliquer les ALU entières est privilégié sur le reste, comme l'a vu dans la section précédente. Les unités mémoire arrivent en seconde place, suivie par les multiplieurs/''barrel shifter'' à la troisième place, et les unités de branchement à la quatrième place. Les CPU superscalaires larges ont donc tendance à multiplier les unités mémoire en second. Les multiplieurs et ''barrel shifters'' sont eux aussi dupliqués sur les CPU superscalaires larges, mais cela vient souvent après avoir dupliqué les unités mémoire. La raison est que les accès mémoire sont critiques pour la performance des CPU à exécution dans le désordre, pas les multiplications. Pour les unités de branchement, une subtilité complique le fait d'en installer plusieurs. Que faire quand deux branchements sont pris ? La solution la plus simple est de ne pas se trouver dans cette situation : on n'utilise qu'une seule unité de branchement et on n’exécute qu'un seul branchement par cycle. La majorité des processeurs superscalaires étroits font ainsi. Les processeurs superscalaires larges ont cependant deux unités de branchements, mais ils n'acceptent qu'un seul branchement pris à la fois. Si les deux branchements pris sont exécutés en même temps, le processeur n’exécute que le plus récent, dans l'ordre du programme. ===Les CPU superscalaires mélangent les trois techniques=== Les CPU superscalaires utilisent toutes les techniques à la fois : partitionnement, duplication de l'ALU entière, duplication des autres unités fonctionnelles. Chaque processeur utilise ces trois stratégies à sa sauce, en fonction de son budget en transistor. Les quatre techniques ont cependant un cout en circuit différent, et donnent des gains de performances eux aussi forts différents. * Le '''partitionnement superscalaire''' a un cout en circuit modéré, car on n'a pas besoin de dupliquer d'ALU. * La '''duplication des ALU entières''' est la technique la plus importante : elle a un cout en circuit modéré, et donne des gains en performance impressionnants. * La '''duplication des autres unités''' a un cout en circuit variable, pour des gains en performance eux aussi variables. * Le '''partage des ports d'émission''' réduit le cout en circuit du CPU, pour des pertes de performances mineures si bien fait. L'usage du partitionnement seul, sans duplication, était surtout le fait des processeurs commercialisés entre les années 1989 et 1993. Le partage des ports d'émission a lui aussi mis un peu de temps pour s'imposer. Globalement, les processeurs superscalaires ont évolués progressivement, pour se rapprocher d'une sorte de standard. Mais pour comprendre ce qu'est ce standard, et en quoi les CPU historiques s'en sont progressivement rapprochés, il faut étudier l'histoire des CPU superscalaires. L'histoire des CPU superscalaires a commencé dès 1960, mais est resté un projet de recherche pendant plusieurs décennies. De nombreux designs ont été conçus, mais abandonnés avant la production, comme l'ACS-1 d'IBM. Les années 1980 ont vu l'arrivée de prototypes de processeurs VLIW, mais qui n'étaient pas superscalaires. Par exemple, l'Apollo DN10000 et l'Intel i860 pouvaient émettre deux instructions à la fois, sous conditions, mais demandaient que le compilateur fasse une bonne partie du travail. Les premiers CPU superscalaires commercialisés sont sortis en 1989. Deux CPUs superscalaires sont sortis cette année-là : le RS/6000 d'IBM et l'i960CA d'Intel. Puis, la compétition s'est aussi lancée dans la bataille. Les CPU commercialisés avant l'année 1993 étaient à double émission, à l'exception du SuperSPARC qui utilisait la triple émission. Les modèles après 1993 hésitaient entre double et quadruple émission. Dans le tableau ci-dessous, les processeurs quadruple émission sont en bleu, les triple émission sont en rouge, les autres ne sont pas en couleur. {|class="wikitable" |- ! !! IBM !! HP PA-RISC !! SPARC !! Intel!! Alpha !! Autres |- ! 1989 | RS/6000 || || || i960CA || || |- ! 1990 | || || || || || |- ! 1991 | || || || || || Motorola 88110 |- ! 1992 | RSC || PA 7100 || class="f_rouge | SuperSPARC || || 21064 || |- ! 1993 | PPC 601 || || HyperSPARC || Pentium || || |- ! 1994 | class="f_bleu | POWER 2 || PA 7200 || || || class="f_bleu | 21164 || |- ! 1995 | 603/604 || class="f_bleu | PA 8000 || class="f_bleu | UltraSPARC 1 || Microarchitecture P6 (+ concurrence AMD) || || class="f_bleu | MIPS R1000 |- ! 1996 | class="f_bleu | 620 || || || || class="f_bleu | 21264 || |- ! ... || ... || ... || ... || ... || ... || ... |} Les premiers CPU à double émission sont assez représentatifs des CPU à double émission modernes. Il faut dire que se limiter à deux voies ne permet pas de faire beaucoup de choses. Voici le tableau chronologique disant quel CPU utilisait quelle technique. * Les CPU en vert utilisaient la double émission entière-flottante. * Les CPU en rouge utilisaient la double émission entière "pure". * Les CPU en jaune utilisaient un ''partitionnement complet'' entre ALU, FPU et unité mémoire. * Les CPU sans couleur utilisaient un grand nombre d'unités, avec beaucoup de ports d'émission. * Les CPU barrés utilisent la triple ou quadruple émission et seront vu dans la section suivante. {|class="wikitable" |- ! !! IBM !! HP PA-RISC !! SPARC !! Intel!! Alpha !! Autres |- ! 1989 | class="f_vert | RS/6000 || || || class="f_rouge | i960CA || || |- ! 1990 | || || || || || |- ! 1991 | || || || || || Motorola 88110 |- ! 1992 | class="f_vert | RSC || class="f_vert | PA 7100 || <s>SuperSPARC</s> || || class="f_jaune | 21064 || |- ! 1993 | class="f_vert | PPC 601 || || class="f_jaune | HyperSPARC || class="f_rouge | Pentium || || |- ! 1994 | <s>POWER 2</s> || PA 7200 || || || <s>21164</s> || |} C'est en 1994, que la quadruple émission est arrivée et que les CPU ont essayé divers implémentations. Il y avait alors trois stratégies pour la double/triple/quadruple émission, qui partageaient des problèmes similaires. La première implémentation dupliquait les ALUs et les FPUs, ce qui permettait d'émettre deux opérations flottantes avec deux opérations entières. Le POWER 2 dupliquait ses FPUs à la perfection, alors que le 21264 séparait l'additionneur et le multiplieur flottant. Les accès mémoire étaient traités comme des opérations entières et le processeur pouvait souvent en émettre deux à la fois. Mais une telle organisation n'est plus utilisée de nos jours, car, sans instructions flottantes à exécuter, elle est équivalente à de la double émission. La seconde implémentation utilisait deux ALU entières (dont un multiplieur), une unité mémoire et une FPU. Cette organisation est intéressante, mais encore trop stricte pour donner de bons résultats, les quadruplets avec exactement deux opérations entières, un accès mémoire et une opération flottante étant trop rares. L'usage de ces 4 unités en double ou triple émission a été utilisé sur le PA 7200 et le SuperSPARC. Malheureusement, en plus de problèmes au niveau de son cache, le SuperSPARC avait de nombreuses contraintes d’appariement, car le banc de registre n'avait pas assez de ports pour alimenter certaines combinaisons d'instructions. De plus, s'il émettait une multiplication, il ne pouvait pas émettre de seconde µop. Enfin, une troisième implémentation utilisait un grand nombre d'unités fort différentes, bien plus que quatre, avec au minimum deux ALU entières. Prenons l'exemple de l'UltraSPARC, qui avait : deux ALU entières, une unité mémoire, une unité de branchement, un additionneur flottant, un multiplieur flottant, un diviseur flottant (aussi utilisé pour le calcul des racines carrées), et 2 unités graphiques pour les calculs sur des pixels. En tout, cela fait 9 unités différentes, pour de la quadruple émission. Dans le même genre, les processeurs MIPS R8000 et R10000 avaient une implémentation plus moderne, dans le sens où toutes les unités étaient dupliquées. Le CPU avait deux ALU, deux FPU et deux unités mémoire. Il pouvait donc émettre quatre instructions à la fois, tant que le paquet collait avec ces six unités. Moitié opérations entières, moitié opérations mémoire, avec de quoi remplacer les opérations entières par des opérations flottantes. Le PA 8000, lui, dupliquait toutes ses unités en deux exemplaires, ce qui n'est pas l'idéal, aucun processeur moderne ne fait cela aujourd'hui. Le tout est résumé dans le tableau ci-dessous, avec : * en vert les CPU utilisant la première stratégie ; * en rouge les CPU utilisant la seconde stratégie ; * en jaune les CPU utilisant la troisième stratégie. {|class="wikitable" |+ Processeurs quadruple émission historiques |- ! Année !! Processeur !! Unités |- ! 1991 | class="f_jaune | Motorola 88110 || class="f_jaune | 2 ALU + MUL + DIV + BIT + MEM + FADD + 2 unités graphiques |- |- ! rowspan="2" | 1994 | class="f_vert | POWER 2 || class="f_vert | 2 ALU/MEM + 2 FPU (+ 2 Branchements via ''branch folding'') |- | class="f_rouge | 21164 || class="f_rouge | 2 ALU + FPU + MEM |- ! rowspan="3" | 1995 | PA 8000 || 2 ALU + 2 ''barrel shifters'' + 2 MEM + 2 FPU (FMA) + 2 FPU (DIV et SQRT) + 2 SIMD |- | class="f_jaune | UltraSPARC 1 || class="f_jaune | 2 ALU + MEM + BRANCH + FADD + FMULFDIV + 2 unités graphiques |- | MIPS R8000 et R10000 || 2 ALU + 2 FPU + 2 MEM |- ! rowspan="2" | 1996 | class="f_rouge | 620 || class="f_rouge | 2 ALU + FPU + MEM |- | class="f_vert | 21264 || class="f_vert | 2 ALU/MEM + 2 FPU (FADD + FMUL) |} Malheureusement, ces CPUs historiques n'avaient ni assez d'unités de calcul entières, ni d'unités mémoire, pour remplir la quadruple émission. Environ la moitié des instructions d'un programme correspond à des instructions entières. Pour en profiter, un processeur à N voies doit disposer d'au minimum N/2 ALU entières, l'idéal étant d'aller au-delà. Les CPU superscalaires historiques avaient 2 ALU pour de la quadruple émission, ce qui était très limite. En comparaison, les CPU superscalaires modernes mettent le paquet niveau ALU entière. La plupart des CPU x86 modernes descendent rarement sous les 2/3, la plupart remplissent presque la totalité de la largeur du CPU. Pour donner un exemple, la microarchitecture Golden Cove d'Intel est un processeur à 6 voies, avec 5 ALU entières. Pour être précis, un programme informatique exécute environ 40% de son code dans des instructions arithmétiques, un autre 40% dans les accès mémoire, et un le reste pour... le reste. La conséquence est que les processeurs modernes dupliquent leurs unités mémoire. Par exemple, la microarchitecture ''Golden Cove'' d'Intel dispose de trois unités mémoire : deux spécialisées dans les écritures, trois dans les lectures. La microarchitecture ''Gracemont'' utilise la pentuple émission et peut émettre 4 µops entières et 4 µops mémoire. Notez que le ratio est équilibré entre opérations entières et mémoire, avec soit égalité, soit un avantage pour les ALU entières. Une autre régularité est que la largeur totale du processeur peut être occupée par des opérations entières/mémoire. Pour le dire autrement, sur un processeur quadruple émission, il pourra émettre un mix de 4 instructions entière/mémoire, avec zéro opération flottante. Idem avec des processeurs triples ou pentuple émission, voire plus. Si le processeur émet une opération flottante, elle remplace une opération entière. Prenons l'exemple des processeurs AMD K6, sortis en 1997, juste avant les AMD Athlon. Ils avaient 10 unités de calcul, 6 ports d'émission, 4 ports de décodage. Voici exactement comment étaient répartie les unités de calcul sur les ports d'émission. C'était des processeurs quadruple émission, ce qui fait que la moitié de la largeur du processeur sert pour des opérations entières, et l'autre moitié pour les accès mémoire. {|class="wikitable" |- ! Port d'émission n°1 !! Port d'émission n°2 !! Port d'émission n°3 !! Port d'émission n°4 !! Port d'émission n°5 !! Port d'émission n°6 ! |- | ALU entière || ALU entière || FPU || Unité de branchement || Unité LOAD || Unité STORE |- | || Multiplieur || || || || Unité de calcul d'adresse (instruction LEA) |- | || ''Barrel shifter'' || || || || Unité pour les instructions PUSH |} Les microarchitectures K7, K8 et K10, utilisées sur les anciens CPU AMD Athlon, sont un exemple moins représentatif. Ces microarchitectures utilisent le partage des ports d'émission au maximum. C'était des microarchitectures à triple émission, avec six ports d’émission. Il y avait trois ports d'émission pour les opérations flottantes, et trois ports d'émission pour les micro-opérations entières/mémoire. Il y avait trois ALU entières et trois unités mémoire, chaque ALU partageait un port d'émission avec une unité mémoire. Elle pouvait donc émettre soit trois opérations entières, soit trois µops mémoire, soit un mix des deux. En plus des mix avec les opérations flottantes et branchements. {|class="wikitable" |- ! Port d'émission n°1 !! Port d'émission n°2 !! Port d'émission n°3 !! Port d'émission n°4 !! Port d'émission n°5 !! Port d'émission n°6 ! |- | ALU entière || ALU entière || ALU entière || FADD || FMUL || FPU (autres opérations) |- | Multiplieur || || || || || |- | LOAD/STORE || LOAD/STORE || LOAD/STORE || || || |} Les CPU superscalaires larges dupliquent les multiplieurs et/ou les ''barrel shifters'', et même les unités de branchement. La raison est que quand la largeur du CPU augmente, le processeur traite des paquets d'instructions de plus en plus gros. Par exemple, pour un CPU à 10 voies, cela veut dire émettre 10 instructions en même temps. Il est alors plus fréquent d'avoir deux multiplications, deux décalages, deux accès mémoire, deux branchements. Par exemple, la moyenne est d'une multiplication tous les 5 instructions. Les CPU superscalaires à 10 voies ont donc tendance à avoir deux multiplications par paquet d'instruction, en moyenne. Avoir deux multiplieurs est alors un gain en performance clair. Par exemple, la microarchitecture ''Golden Cove'' a deux ''barrel shifters''. C'est une architecture à 6 voies. {|class="wikitable" |- ! Port d'émission n°1 !! Port d'émission n°2 !! Port d'émission n°3 !! Port d'émission n°4 !! Port d'émission n°5 !! Port d'émission n°6 !! Port d'émission n°7 !! Port d'émission n°8 !! Port d'émission n°9 !! Port d'émission n°10 |- | ALU entière || ALU entière || ALU entière || ALU entière || ALU entière || LOAD || LOAD || LOAD || STORE || STORE |- | ''Barrel shifter'' || Multiplieur || Multiplieur || ''Barrel shifter'' || || || || || || |- | Branchements || Diviseur || || Branchements || || || || || || |} ==Les µops mémoire sur les processeurs superscalaires== Plus haut, nous avons volontairement passé sous silence les accès mémoire. La raison à cela est que leur support sur les CPU superscalaire peut se faire de plusieurs manières différentes, qu'il vaut mieux expliquer dans une section dédiée. Les différentes implémentations sont décrites dans la liste suivante, nous allons les voir une par une. * Avec la première méthode, les accès mémoire sont exécutés par le pipeline pour les opérations entières. * Avec la seconde méthode, les accès mémoire ont un pipeline dédié ; c'est l'''émission parallèle des accès mémoire''. * Avec la troisième méthode, il est possible d'émettre plusieurs accès mémoire simultanément : c'est l'''émission multiple des accès mémoire''. Voyons ces trois cas dans le détail. Nous verrons notamment les différentes formes d'émission multiple des accès mémoire. ===Les accès mémoire traités dans le pipeline entier=== Dans le cas le plus simple, les accès mémoire sont traités comme des opérations entières un peu spéciales. L'unité mémoire est sur le même port d'émission que l'ALU entière, ce qui fait que les accès mémoire remplacent des opérations entières. Faire ainsi permet d'utiliser une ALU entière pour les calculs d'adresse, pas besoin de rajouter une unité de calcul d'adresse séparée. Typiquement, un processeur de ce type place l'unité mémoire après l'unité de calcul. Les opérations entières n'utilisent que l'ALU entière, mais pas l'unité mémoire. Les accès mémoire exécutent un calcul d'adresse dans l'ALU entière, puis l'adresse calculée est envoyée à l'unité mémoire. Le tout est illustré ci-dessous, dans le cas d'un processeur historique à double émission entière-flottante. [[File:Processeur non-superscalaire basique 01.png|centre|vignette|upright=1.5|Processeur non-superscalaire basique]] Un exemple de CPU double émission de ce type est celui du Power PC 440, un CPU destiné à l'embarqué. Vu qu'il était destiné à l'embarqué, il n'avait pas de FPU, il n'avait pas besoin de manipuler de nombres flottants. Il n'a donc que des ALU entières, un multiplieur et une unité mémoire. Il dispose de deux ports d'émission. Le premier est connecté à une ALU entière et un circuit multiplieur, le second est relié à l'unité mémoire et une seconde ALU entière. Une organisation simple, mais très efficace ! [[File:PowerPC 440.png|centre|vignette|upright=2|Microarchitecture du PowerPC 440.]] L'implémentation économise une unité de calcul d'adresse, mais n'a pas de cout en performance significatif. Les accès mémoire étant très lents, émettre une µop entière en parallèle d'un accès mémoire ne sert pas à grand-chose. On peut émettre cette µop entière un cycle plus tard, elle sera terminée avant même que l'accès mémoire soit terminé, même si l'accès mémoire se fait dans le cache L1 ou L2. Pour comprendre pourquoi, faisons quelques calculs. Un accès mémoire prend deux-trois cycles quand il tombe dans le cache L1. Et on doit attendre qu'il soit terminé pour en émettre un nouveau. Combien d'instructions arithmétiques peut-on lancer pendant ce temps, sur un CPU triple émission ? Au premier cycle, on peut en émettre 2 (l'instruction mémoire prend une place, donc 3-1), puis 3 au second cycle. Ce qui fait 5 instructions arithmétiques au total. Or, il se trouve qu'il y a une instruction d'accès mémoire pour 5 instructions arithmétiques, environ. Par contre, ce compromis change quand on passe à la quadruple émission, voire au-delà. Dans ce cas, il devient intéressant de pouvoir émettre une nouvelle instruction mémoire à chaque cycle. Ce qui nous amène à la section suivante... ===L'émission parallèle des accès mémoire=== A partir de la quadruple émission, la tendance a été de séparer l'unité mémoire des ALU entières. Cela permet d'émettre des µops mémoire en même temps que des µops entières et/ou flottantes., ce qui porte le nom d''''émission parallèle des µops mémoire''', ou encore ''émission mémoire parallèle''. Par exemple, un processeur quadruple émission peut émettre en même temps deux opérations entières, une opération flottante et un accès mémoire. L'accès mémoire vient en plus des opérations entières, il n'est pas possible de remplacer l'accès mémoire par une opération entière. La technique ne permet pas de faire les calculs d'adresse dans l'ALU entière. Il faut donc utiliser une unité de calcul d'adresse séparée. Elle est intégrée dans l'unité mémoire, qui fait l'interface entre le cache et le banc de registres. Le cout en circuits est très faible, car les unités de calcul d'adresse n'utilisent guère plus qu'un additionneur et un circuit de décalage très simple. L'émission mémoire parallèle est plus facile à implémenter sur les CPU RISC, qui ont des instructions mémoire séparées du reste. Les CPU CISC ne sont pas dans ce cas, ce qui fait que séparer l'unité mémoire du pipeline entier est compliqué. Les CPU superscalaires historiques étaient pour moité des CPU RISC et pour moitié des CPU CISC, ce qui fait qu'ils n'utilisaient pas ou peu l'émission mémoire parallèle. Les premiers processeurs superscalaires se contenaient de l'émission parallèle mémoire, ils ne pouvaient émettre qu'un seul accès mémoire à la fois, l'unité mémoire n'était pas dupliquée. Et ce n'est pas tant un problème que ça, du moins sur les processeurs à double ou triple émission. En effet, il est rare que l'unité mémoire doive faire deux accès simultanés. Notons que le processeur peut exécuter une instruction mémoire en parallèle d'un calcul ou d'un branchement, seuls les accès mémoire simultanés sont impossibles. ===L'émission multiple des accès mémoire avec une LSQ=== Les processeurs superscalaires larges travaillent sur des paquets de 8 à 10 instructions, il est plus fréquent d'avoir plusieurs accès mémoire par paquet. Dans ces conditions, il est utile d'avoir une '''émission multiple des accès mémoire''', à savoir d'émettre plusieurs micro-opérations mémoire en même temps. Les processeurs superscalaires modernes sont capables d'émettre plusieurs lectures/écritures simultanément. Par exemple, ils peuvent émettre une lecture en même temps qu'une écriture, ou plusieurs lectures, ou plusieurs écritures. Il faut noter que selon le processeur, il peut y avoir des restrictions quant aux accès mémoire émis en même temps. Par exemple, certains processeurs peuvent émettre une lecture avec une écriture en même temps, mais pas deux lectures ni deux écritures. Ou encore, ils peuvent émettre deux lectures, une lecture et une écriture, mais pas deux écritures en même temps. Dans la majorité des cas, les processeurs ne permettent pas d'émettre deux écritures en même temps, alors qu'ils supportent plusieurs lectures. Il faut dire que les lectures sont plus fréquentes que les écritures. Les processeurs qui autorisent toutes les combinaisons de lecture/écriture possibles, sont rares. L'émission multiple des accès mémoire s'implémente dans l'unité mémoire. Pour rappel, l'unité mémoire s'interpose entre le cache L1 et le reste du pipeline. Dans le cas le plus simple, elle incorpore une ''load/store queue'' et des unités de calcul d'adresse. L'émission multiple des accès mémoire demande de rendre la ''Load-store queue'' multi-ports, afin de gérer plusieurs micro-opérations mémoire simultanées. Il faut aussi dupliquer les unités de calcul d'adresse reliées à la LSQ, chaque port d'émission mémoire devant avoir sa propre unité de calcul d'adresse. : Dans ce qui suit, nous parlerons d'AGU (''Adress Generation Unit'') pour désigner les unités de calcul d'adresse, et de LSQ pour designer la ''Load-store queue''. [[File:Processeur non-superscalaire basique 02.png|vignette|upright=1|Processeur non-superscalaire basique]] Dupliquer les ports de la LSQ et les AGU est nécessaire. Mais qu'en est-il du cache ? La réponse varie suivant le processeur. Il y a deux grandes méthodes pour implémenter l'émission multiple des accès mémoire. La première méthode ajoute des ports de lecture/écriture au cache de données, pour faire des lectures/écritures simultanées. Il faut alors dupliquer des unités de calcul, rajouter les ports sur le cache, mais aussi rajouter des ports sur la ''load/store queue'', pour qu'elle échange des données/commandes mémoire avec le cache. Le cout en circuits est alors conséquent La seconde duplique les unités de calcul, mais pas les ports d'accès au cache. Les accès mémoire sont alors accumulés dans la ''load/store queue'', qui sont ensuite traités un par un par le cache. Un exemple est celui des processeurs AMD de micro-architecture K7 K8, à savoir les anciens AMD Athlon et AMD Athlon 64, qui pouvaient calculer trois adresses simultanément, mais ne pouvaient faire qu'un seul accès au cache par cycle. Le cout en circuit est modéré : les unités de calcul coutent très peu, les ports de la ''load/store queue'' coutent déjà un peu plus. Quelques processeurs utilisaient des solutions intermédiaires. Un processeur utilisant cette technique est, par exemple, capable d'émettre quatre µops mémoire en même temps, mais avec seulement deux ports sur le cache. Un exemple classique étant les Pentium 1 et 2 d'Intel, dont nous parlerons dans le chapitre suivant. ===L'émission séparée des LOAD et STORE=== De rares processeurs ont des ports d'émission qui peuvent faire indifféremment lecture comme écritures. Mais les processeurs modernes préfèrent séparer ports d'émission pour les lectures et les écritures. Un exemple est celui des processeurs Intel de micro-architecture Nehalem, qui avaient un port de lecture et un port d'écriture tous deux reliés à la ''Load-store queue'', chacun avec leur propre unité de calcul d'adresse. Comme autre exemple, les processeurs skylake ont une LSQ avec deux ports de lecture et un port d'écriture, ce qui permet d'émettre deux lectures en même temps qu'une écriture. Dans cette section, nous allons étudier le cas avec des ports séparés pour les lectures et écritures. En général, les processeurs ont un peu plus de ports de lectures que d'écritures. Une raison est qu'un programme a, en moyenne, un tout petit peu plus de lectures que d'écritures. Mais la différence n'est pas énorme, c'est un léger déséquilibre. Une seconde raison est que l'exécution dans le désordre marche bien mieux quand les lectures ont lieu le plus tôt possible. Donc mieux vaut privilégier les lectures à l'émission, pour qu'elles se fassent un peu en avance. En pratique, la différence n'est pas très marquée. Il est courant d'avoir un port de lecture et un d'écriture, les CPU superscalaires très larges ont souvent deux ports de lecture et deux d'écriture. A la rigueur, quelques CPU ont trois ports de lecture et deux d'écriture. Le cas le plus simple est celui où on peut émettre une lecture et une écriture en même temps. Il s'implémente facilement si la LSQ est en réalité une simple ''Store queue'', à savoir qu'elle met en avance les écritures uniquement. Pour rappel, les écritures sont mises en attente dans la ''Store queue'', mais les lectures sont exécutées immédiatement. Une fois l'adresse à lire connue, la lecture consulte la ''Store queue'' pour détecter les dépendances de données, puis s'exécute. La donnée à lire est lue soit depuis la ''Store queue'', soit depuis le cache. [[File:Emission LOAD - Store séparée.png|vignette|upright=1|Émission LOAD - Store séparée]] L'implémentation de l'émission multiple est alors très simple. La ''Store queue'' a déjà deux ports, avec un pour les lectures et un autre pour les écritures. Idem pour le cache, qui a naturellement un port de lecture et un d'écriture. Émettre une lecture et une écriture simultanément ne demande donc pas de modification digne de ce nom. La ''Store queue'' doit juste supporter une lecture et une écriture simultanée. Ajouter l'émission d'une seconde lecture n'est pas compliquée : il faut juste rajouter un second port de lecture sur le cache et la ''Store queue''. Pour rappel, l'unité mémoire est précédée par une structure qui met en attente les micro-opérations mémoire avant leur émission finale. La structure en question varie suivant l'implémentation, mais un cas particulier se marie bien avec l'émission multiple des µops mémoire. Il s'agit du cas avec une file de µops séparée pour les lectures et une autre pour les écritures, appelées respectivement la ''file de µops LOAD'' et la ''file de µops STORE''. Il est alors possible d'émettre une lecture et une écriture lors du même cycle d'horloge. Le port de lecture alimente une unité de calcul d'adresse dédiée, directement reliée au cache. Le port d'écriture du cache alimente une unité de calcul, qui est suivie par une file d'écriture, elle-même reliée au cache. Les processeurs AMD de micro-architecture K6 utilisaient cette technique. [[File:Double émission avec le Load Ordering, Store Ordering.jpg|centre|vignette|upright=2.5|Double émission avec le Load Ordering, Store Ordering]] ==Les CPU superscalaire à exécution dans le désordre== La superscalarité modifie aussi les circuits dédiés à l'exécution dans le désordre. Elle modifie les unités de renommage de registre, le ROB et les autres structures liées à l'exécution dans le désordre, au sens large. Aucune structure n'est épargnée. Elles ont tous des prots de lecture/écriture en plus, afin d'encaisser l'émission, le ''commit'' ou le renommage simultané de plusieurs µops. Par exemple, le ROB doit être modifié pour émettre et terminer plusieurs instructions en même temps, en ajoutant des ports de lecture/écriture. Pour un CPU superscalaire à 8 voies, on se dit que le ROB peut retirer 8 µops par cycle maximum. Mais certains processeurs récents ont un ROB qui peut retirer le double ! Un exemple est celui des CPU de micro-architecture Skymont, qui peuvent émettre 8 µops par cycle, mais en retirer 16. Quelques CPU de marque AMD étaient aussi dans ce cas. L'avantage est que cela permet de réduire la taille du ROB, du banc de registre et de quelques autres structures matérielles liées à l'exécution dans le désordre. Le gain sur-compense le cout en transistor nécessaire pour retirer 16 µops par cycle. Dans cette section, nous allons voir comment les étages du pipeline dédiés à l'exécution dans le désordre sont modifiées sur un CPU superscalaire. ===L'exemple du PA-RISC PA 8000=== Avant de commencer, nous allons voir un processeur superscalaire assez simple, le PA 8000, de HP, qui implémente le jeu d'instruction PA-RISC. Bien que très ancien, il implémentait l'exécution dans le désordre et le renommage de registre. Le peu d'informations que nous avons sur ce processeurs proviennent des documents "THE HP PA-8000 RISC CPU" par Ashok Kumar, et l'article de microprocessor report "PA-8000 Combines Complexity and Speed". Ils ne donnent malheureusement pas énormémment d'informations et je devrais être amené à faire quelques suppositions dans ce qui suit. Avant de commencer, parlons de détails sans lien avec la superscalarité. Ce processeur, comme beaucoup de processeurs PA-RISC, n'intégrait pas de cache de niveau L2 dans le processeur, qui était déporté en-dehors du CPU, sur la carte mère. Le processeur préférait utiliser ses transistors pour avoir un cache L1 assez large, quitte à ce qu'il soit plus lent. La lenteur du cache était prévue, le processeur compensait celle-ci en utilisant l'exécution dans le désordre, bien que ce ne soit pas parfait. Les CPU PA-RISC avant le PA 8000 utilisaient un pipeline à vagues ''wave pipeline'', ce qui était assez peu commun, mais le PA 8000 repasse à un pipeline synchrone classique. Passons maintenant à la superscalarité. Le PA 8000 est un processeur quadruple émission, qui peut émettre, à chaque cycle, deux opérations et deux accès mémoire. Le renommage de registre utilise des registres de renommage séparés des registres architecturaux, comme c'était la mode à l'époque. Le budget en transistor faisait que c'était soit ça, soit le renommage dans le ROB, faute de mieux. Le processeur utilise une implémentation ''Read After Issue'', ce qui veut dire que les opérandes des instructions sont lues après l'émission, juste avant l'exécution. Le processeur peut aussi ''commit'' deux opérations et deux accès mémoire par cycle, ce qui revient à transférer les résultats des registres de renommage vers les registres architecturaux. L'exécution dans le désordre est prise en charge par une structure matérielle unique, qui ressemble à une fusion entre un ROB et un ''scheduler''. Et c'est là que je vais devoir faire des suppositions. Le document "THE HP PA-8000 RISC CPU" nomme cette structure : l''''''Instruction Reorder Buffer'''''. Il utilise pas moins de 850 000 transistors, et prend 20% de la taille du ''die''. L'article "THE HP PA-8000 RISC CPU" laisse fortement sous-entendre qu'il s'agit une structure unique, faite d'un seul tenant, mais l'article de microprocessor report dit le contraire par moment. Il est décrit comme un ''scheduler'', à savoir qu'il détecte les dépendances entre instruction et les émet. Il gère aussi la détection des mauvaises prédictions de branchement et peut annuler les instructions chargées à tort, en les retirant de le ''scheduler''. Il est aussi précisé que les instructions quittent cet ''Instruction Reorder Buffer'' dans l'ordre du programme. Elles ne peuvent en sortir que quand elles ont été exécutées et qu'elles n'ont causé aucune exception. Ce qui fait qu'il se comporte comme un ROB de ce point de vue là. Difficile de dire si l'''Instruction Reorder Buffer'' est un réel mélange entre un ROB et un ''scheduler'', ou s’il est réellement conçu avec deux structures séparées. Dans ce qui suit, je pars du principe que les deux structures sont séparées. Le processeur contient deux ''schedulers'' : une réservée aux µops mémoire (LOAD et STORE), l'autre pour les opérations entières/flottantes. Elles ont chacune 28 entrées, ce qui permet de mémoriser 56 µops au maximum. Les deux peuvent recevoir 4 µops par cycle de la part des décodeurs. Là encore, précisons que les choses ne sont pas claires pour ce qui est de la séparation. L'article de Microprocessor report dit que les deux sont physiquement séparées, et que cette séparation physique permet de simplifications (les opérations mémorisent des noms de registres plus court que les adresses demandées par les µops LOAD/STORE). Mais l'autre document cité laisse penser que l''''Instruction Reorder Buffer'' est une structure unique. À chaque cycle, le processeur peut émettre deux instructions de calcul et deux instructions mémoire. Les deux ''schedulers'' ont pour cela chacune deux ports d'émission. Les deux ports d'émission pour les µops mémoire sont identiques, et le cache L1 est un cache double port, ce qui permet d'exécuter deux lectures/écritures par cycle. Pour ce qui est des µops entières/flottantes, le processeur a dupliqué toutes ses unités de calcul : il a deux ALU entières, deux ''barrel shifters'', deux FPU de type FMAC, et deux unités de division flottante. Vraisemblablement, il y a deux ports d'émission, chacun étant connecté à une unité de chaque type. : S'il n'utilisait pas l'exécution dans le désordre, ce processeur aurait donc quatre pipelines : deux pipelines entiers identiques et deux pipelines mémoire. Et il aurait une superscalarité presque parfaite s'il était un CPU à double émission ! À chaque cycle, le ''scheduler'' émet les deux µops les plus anciennes qui sont prêtes à être exécutées. La documentation dit que la fenêtre émet "la plus vielle instruction paire, et la plus vielle instruction impaire", ce qui sous-entend que le ''scheduler'' est segmentée en deux. C'est précisément la logique d'éveil et d'émission qui est segmentée, une partie gérant la moité de le ''scheduler'', une seconde logique d'éveil/''schedule'' gérant le reste. le ''scheduler''s n'implémente donc pas une vraie double émission, elle est partitionnée pour permettre d'émettre deux µops en même temps. L'avantage est une économie de transistors manifeste. Un inconvénient est que si les µops prêtes sont toutes dans la même moitié, une seule µops sera émise par cycle. Mais avec 2*14 entrées, le cas est assez rare pour que l'économie de transistors en vaille la peine. [[File:PA 8000 - microarchitecture.png|centre|vignette|upright=2|PA 8000 - microarchitecture]] ===La superscalarité avec une file/fenêtre d'instruction centralisé=== Plus haut, nous avons montré qu'un processeur pouvait avoir plus de ports d'émission que de ports de décodage. On dit aussi que sa ''largeur de décodage'' était supérieure à sa ''largeur d'émission''. La '''largeur de décodage''' est le nombre de µops fournies par l'unité de décodage par cycle d'horloge, la '''largeur d'émission''' est le nombre maximal de µops émises par cycle d'horloge. Et n'allez pas croire qu'un surplus de ports d'émission est du gâchis. Sur les processeurs avec exécution dans le désordre, ce surplus peut être utilisé. Mais avant toute chose, évacuons un détail. Vous avez sans doute pensé que le surplus peut être exploité par les instructions machines décodées en plusieurs µops . Par exemple, si une instruction est décodée en deux µops, on pourrait avoir un port d'émission en plus pour en profiter. Mais les ports de décodage sont *en sortie du décodeur*, et contiennent des µops, pas des instructions. Le surplus de ports d'émission peut occasionnellement utiliser le surplus de ports de décodage, mais cela implique que des µops ont été mises en attente dans l'unité d'émission, pour être émises par la suite. Et cela implique l'usage d'un ''scheduler'' ou d'une file de µops. Le principe est que les µops sont accumulées dans le ''scheduler'', en attendant leurs opérandes ou la résolution d'une dépendance. Et si l'occasion se présente, une µops est émise sur chaque port d'émission. Il y a donc un gain en performances, mais il faut faire quelques précisions sur son origine. La largeur d'émission utilisée ne peut pas dépasser, *en moyenne*, la largeur de décodage. Et c'est intuitif : un CPU qui décode 4 µops par cycle ne peut pas émettre 6 par cycle en moyenne, sur le temps long, il n'y a pas de µops en surplus qui sortent du vide. Par exemple, sur un processeur quadruple émission, si on analyse combien d'instructions sont émises par cycle, il peut y avoir des cycles où la largeur d'émission est totalement utilisée, mais ce sera compensé par des périodes où elle est fortement sous-utilisée. Les µops sont accumulées en cas de sous-utilisation, puis consommées en cas d'utilisation complète. Les deux périodes se compensent. Et c'est là que l'on peut comprendre d'où vient le gain en performance. Les cycles où les ports d'émission sont sous-utilisés existent systématiquement, que le processeur utilise l'exécution dans le désordre ou pas. Ils sont liés à la présence de dépendances de données, aux contraintes d’appariement, etc. Elles tendent à réduire la moyenne du nombre de µops émises par cycle. Par contre, ce sont les cycles de rattrapage, où les ports en surplus sont utilisés, qui font remonter la moyenne. Le gain en performance est donc lié à ces cycles de rattrapage, où les µops accumulées sont émises dans les ports en surplus. Et ils n'existent que sur les processeurs avec une file/fenêtre d'instruction. Réduire le nombre de ports d'émission permet de garder des ''schedulers'' et un ROB simples, rapides et économes en énergie. Et mine de rien, c'est là un compromis important : à quoi bon augmenter le nombre de ports d'émission si c'est pour que ce soit compensé par une fréquence plus faible ? Par contre, réduire le nombre de ports augmente la ''port contention'', surtout si on a mal réparti les ALU. Il faut donc trouver un compromis entre réduire le nombre de ports d'émission d'un côté, réduire la ''port contention'' de l'autre. La différence entre largeur de décodage et d'émission a un impact assez fort sur le banc de registre, et précisément sur son nombre de ports de lecture. Le banc de registre a besoin de plus de ports de lecture avec une fenêtre d’instruction qu'avec des stations de réservation. Rappelons la terminologie utilisée dans ce cours. Les ''schedulers'' se contentent de mémoriser la micro-opération et quelques bits pour détecter la disponibilité des opérandes. Par contre, les stations de réservations mémorisent aussi les opérandes des instructions. Et cette différence a une influence le nombre de ports de lecture du banc de registre. Supposons que toutes les instructions sont dyadiques, à deux opérandes. Comptons le nombre de ports nécessaires pour alimenter les unités de calcul, sans utiliser d'arbitre de banc de registre. Avec un ''scheduler'', il faut le double du nombre de ports d'émission. Mais avec des stations de réservation, il faut le double des ports de décodage. La raison est que les registres sont lus après émission avec un ''scheduler'', avant avec des stations de réservation (sous-entendu, après le décodage). Or, comme dit plus haut, les processeurs superscalaires larges ont souvent plus de ports d'émission que de décodage. ===La superscalarité à ''schedulers'' décentralisés=== Les processeurs précédents utilisaient une unité d'émission simple, qui pouvait utiliser l'émission dans l'ordre ou dans le désordre. Elle peut être remplacée par un ''scheduler'' centralisé dans que cela quoi que ce soit aux explications précédentes, idem avec une station de réservation centralisé. En soi, l'exécution dans le désordre est donc totalement compatible avec une implémentation simple de la superscalarité. Par contre, des subtilités surviennent avec les ''schedulers'' décentralisés. Pour rappel, sur ces processeurs, les µops sont émises en deux phases. Une première phase de ''dispatch'' qui envoie les µops vers le ''scheduler'' adéquat, sans détecter les dépendances de données. La seconde phase de ''schedule'' gère les dépendances de données, elle met en attente les µops en attendant que l'unité soit disponible pour les exécuter, en attendant aussi que les opérandes soient disponibles. Et à ce petit jeu, il y a une différence entre le nombre de µops qui sont ''dispatch par cycle'' et celles qui sont ''schedule''. Dit autrement, la largeur d'émission est scindée en une '''largeur de ''dispatch''''' et une '''largeur de ''schedule''. Par exemple, prenons un processeur triple émission avec deux stations de réservation : une pour les µops entières/mémoire, et une autre pour les µops flottantes. L'unité d'émission peut ''dispatch'' maximum trois µops par cycle : soit trois µops entières/mémoire, soit trois flottantes, soit un mix de trois µops différentes. Les stations de réservation, quant à elles, peuvent chacune ''schedule'' 3 µops par cycle, vers trois ALUs entières pour la station de réservation entière/mémoire, vers trois FPS pour la station de réservation flottante. De quoi ''dispatch'' trois µops, mais d'en ''schedule'' six, à chaque cycle. Et cet exemple ne sort pas de nulle part : les CPU x86 d'Intel et AMD sont globalement dans ce cas, même si les chiffres varient d'une microarchitecture à l'autre. L'exemple précédent colle parfaitement à la microarchitecture K7 d'AMD, utilisée sur les processeurs Athlon dans les années 2000. [[File:AMD K7.png|centre|vignette|upright=2.5|AMD K7, microarchitecture.]] L'exemple précédent avait assez d'unités entières/flottantes pour couvrir toute la largeur de décodage/''Dispatch''. Mais ce n'est pas toujours le cas, comme va le montrer l'exemple suivant. Le MIPS R10000, qui utilisait un mélange de files de µops et de ''schedulers'' : une file de µops les accès mémoire, une fenêtre pour les instructions entières et une autre pour les opérations flottantes. Les branchements et NOPs étaient exécutés dans une unité de branchement distincte. Les trois files/fenêtres peuvent mémoriser 16 µops. Le processeur avait deux ALU entières, une AGU de calcul d'adresse, un additionneur flottant et un multiplieur/diviseur flottant. Il y avait un multiplieur entier sur le port d'émission l'ALU 2. Le processeur décodait 4 instructions par cycle et produisait jusqu'à 4µops, qui étaient redistribuées sur les trois ''schedulers''. Chacune pouvait accepter 4 µops par cycle, ce qui fait que processeur pouvait ''dispatch'' 4 µops entières, ou 4 µops flottantes, ou 4 µops mémoire, ou un mélange de deux ou trois types de µops. Pour ce qui est du ''schedule'', le ''scheduler'' entière pouvait émettre 2 µops, la fenêtre flottante pouvait émettre une addition en même temps qu'une multiplication/divison flottante et qu'un branchement conditionnel flottant, et la file de µops mémoire ne pouvait émettre qu'une µop mémoire à la fois. En tout, cela fait 6 µops ''schedule'' pour 4 µops au ''dispatch''. [[File:R 10000.png|centre|vignette|upright=2.5|MIPS R10000, microarchitecture.]] ===La superscalarité à ''schedulers'' totalement décentralisés=== Prenons un cas extrême de fenêtre d'instruction décentralisé : celui où chaque ALU entière a sa propre station de réservation. En clair : une fenêtre d'instruction par ALU/FPU ! On parle de '''''schedulers'' totalement décentralisés'''. Vous vous dites que ce cas est un peu trop extrême pour être réaliste, mais il n'en est rien. C'est même très courant sur les architectures basse consommation, et sur pas mal de CPU x86 modernes. Une telle organisation entraine une légère perte de performance, comparé à un ''scheduler'' centralisé ou partiellement décentralisé. Et cela peut se comprendre par un exemple. Imaginez un processeur avec deux ALU, donc deux stations de réservation. Il arrivera qu'une station de réservation ait plusieurs µops prêtes, alors que l'autre en ait zéro. Dans une telle situation, une seule µop sera émise au cycle suivant, vu que chaque station de réservation a un seul port d'émission vers une seule ALU entière. Par contre, avec un ''scheduler'' centralisé double port, on aurait pu émettre les deux µops en même temps sur deux ALUs séparées. La perte de performance est donc liée au fait que les µops '''''prêtes''''' sont mal réparties dans les différentes stations de réservation. Il arrivera que des µops prêtes s'accumulent dans une station de réservation, alors que d'autres seront pleines, ou du moins sous-utilisées. Et ce n'est pas quelque chose qui peut être réglé à l'étape de ''dispatch'', car on ne sait pas encore quand les µops auront leurs opérandes de disponibles. [[File:Comparaison entre une station de réservation totalement décentralisé et une autre qui ne l'est pas.png|centre|vignette|upright=2.5|Comparaison entre une station de réservation totalement décentralisé et une autre qui ne l'est pas.]] Par contre, décentraliser totalement les ''schedulers'' entraine aussi un gain considérable en termes de consommation énergétique. Et c'est la raison pour laquelle les ''schedulers''s totalement décentralisés sont utilisées sur les architectures basse consommation. La perte de performance ne peut pas s'expliquer clairement à ce stade du cours, car il nous faudrait parler d'émission superscalaire. Le gain en matière d'énergie vient de l'économie de circuits, qui est assez drastique. Le gain en matière d'énergie vient de l'économie de circuits, qui est assez drastique. Je rappelle qu'une station de réservation a besoin, pour N instructions, d'environ N^2 circuits (des comparateurs, notamment). Prenons une station de réservation centralisé de 64 entrées et comparons avec 8 stations de 8 entrées chacune. Les deux donneront 64 entrées, mais la première aura un cout en circuit proportionnel à 64², alors que le second aura un cout en circuit de 8 *(8²). Entre les deux, le choix est clair : la seconde solution est plus économe. D'où l'utilisation de cette solution sur les microarchitectures basse consommation. ===L'unité de renommage superscalaire=== Avec la superscalarité, l'unité de renommage de registre doit gérer le cas où des instructions consécutives ont des dépendances de registre. Par exemple, prenons un processeur à double émission, qui renomme deux instructions consécutives. Si elles ont une dépendance de registre, le renommage de la seconde instruction dépend du renommage de la première. La première doit être renommée et le résultat du renommage est utilisé pour renommer la seconde, ce qui empêche d'utiliser deux unités de renommage séparées. Pour cela, elle renomme les registres sans tenir compte des dépendances, pour ensuite corriger le résultat. [[File:Unité de renommage superscalaire.png|centre|vignette|upright=2|Unité de renommage superscalaire.]] Seules les dépendances lecture-après-écriture doivent être détectées, les autres étant supprimées par le renommage de registres. Repérer ce genre de dépendances se fait assez simplement : il suffit de regarder si un registre de destination d'une instruction est un opérande d'une instruction suivante. [[File:Détection des dépendances sur un processeur superscalaire.png|centre|vignette|upright=2|Détection des dépendances sur un processeur superscalaire.]] Ensuite, il faut corriger le résultat du renommage en fonction des dépendances. Si une instruction n'a pas de dépendance avec une autre, on la laisse telle quelle. Dans le cas contraire, un registre opérande sera identique avec le registre de destination d'une instruction précédente. Dans ce cas, le registre opérande n'est pas le bon après renommage : on doit le remplacer par le registre de destination de l'instruction avec laquelle il y a dépendance. Cela se fait simplement en utilisant un multiplexeur dont les entrées sont reliées à l'unité de détection des dépendances. On doit faire ce replacement pour chaque registre opérande. [[File:Correction des dépendances sur un processeur superscalaire.png|centre|vignette|upright=2|Correction des dépendances sur un processeur superscalaire.]] ==Les optimisations des processeurs superscalaires larges== Les processeurs superscalaires larges ont des optimisations spécifiques, qui n'ont pas de sens sur les processeurs superscalaires étroits. Dans les grandes lignes, elles se classent en deux types. Les premières permettent de charger/décoder plus de 5-10 instructions simultanément. Le problème est alors que les branchements viennent mettre leur grain de sel et qu'il faut en tenir compte. Les secondes corrigent des problèmes qui apparaissent quand un CPU intègre plus de 5 à 10 unités de calcul. ===L'étape de chargement d'un CPU superscalaire large=== Charger plusieurs instructions pose de nombreux problèmes sur les processeurs superscalaires larges, qui émettent de 5 à 10 instructions simultanées. Pour rappel, la stratégie basique pour charger N instructions est de charger un bloc de N instructions consécutives. Les instructions après un branchement ne sont pas décodées ni exécutées, ce qui entraine une petite baisse de performance. Pour un N petit, la perte de performance est mineure. Mais pour un N large, elle devient suffisamment importante pour que la conception du CPU doit alors être repensée de fond en comble. Les analyses statistiques disent qu'il y a environ un branchement tous les 4 à 6 instructions. Un CPU a donc tendance à décoder des paquets de 3 à 5 instructions consécutives, avant qu'un branchement casse la dynamique. Or, cela pose des problèmes pour utiliser plusieurs décodeurs. L'implémentation basique, qui charge N instructions consécutives pour alimenter N décodeurs, fonctionne donc jusqu'à 4/6 décodeurs. Au-delà de 5 instructions, un CPU superscalaire doit être adapté pour gérer les branchements dans les paquets d'instruction qu'il émet. Le nombre de 5 instructions ne sort donc pas de nulle part. La première solution utilise un cache de µops, avec un ''front-end'' capable de charger/décoder 4/5 instructions à la fois, pas plus. L'idée est que la majorité des instructions proviennent du cache de µops (plus de 80%), ce qui fait qu'on peut émettre environ 10 instructions à partir du cache de µops, pas besoin d'avoir beaucoup de décodeurs. Les performances sont cependant dégradées lors d'un défaut de cache de µops. Les instructions doivent alors être chargées depuis le cache d'instruction, par paquets de 4-5, puis sont décodées par 4-5 décodeurs, ce qui ne permet pas d’alimenter les unités de calcul à plein régime. La solution précédente joue sur la distinction entre pots de décodage et d'émission. Elle permet d'émettre un grand nombre de µops sans pour autant charger un grand nombre d'instructions en même temps. En quelque sorte, ce n'est qu'une méthode de contournement, le CPU superscalaire reste de type étroit. Mais il est aussi possible d'utiliser un '''''front-end large''''', capable de charger une bonne dizaine d'instructions en même temps. La seule difficulté est de tenir compte de la présence de branchements. Pour rappel, avec un ''front-end'' étroit, les instructions situées après le premier branchement pris sont annulées, elles ne sont pas décodées ni exécutées. [[File:Fetch sur un processeur superscalaire avec prediction de branchements.png|centre|vignette|upright=2|Fetch sur un processeur superscalaire avec prédiction de branchements.]] Un ''front-end'' large charge les instructions de destination du branchement et les placent à sa suite. Ils chargent deux blocs à la fois et les fusionnent en un seul qui ne contient que les instructions présumées utiles. [[File:Cache d'instructions autoaligné.png|centre|vignette|upright=2|Cache d'instructions auto-aligné.]] Mais cela demande de charger deux blocs de mémoire en une fois, ce qui demande un cache d'instruction multiports. Il faut aussi ajouter un circuit pour assembler plusieurs morceaux de blocs en un seul : le fusionneur (''merger''). En pratique, cette solution demande d'ajouter un second port de lecture au cache, pour un cout en hardware important, avec un impact négatif sur le temps d'accès au cache. Et il faut rajouter le fusionneur, qui prend un étage de pipeline à lui tout seul. Et encore, cette solution ne gère pas le cas où un bloc contient plusieurs branchements ! [[File:Implémentation d'un cache d'instructions autoaligné.png|centre|vignette|upright=2|Implémentation d'un cache d'instructions auto-aligné.]] Les exemples précédents partent du principe qu'il n'y a qu'un seul branchement dans un bloc. Mais quand les blocs deviennent assez longs, il est fréquent d'avoir plusieurs branchements dans un bloc. Et il est même possible d'avoir plusieurs branchements pris. Dans un bloc de 8-10 instructions, ce n'est pas rare, et les CPU superscalaires à 8-10 voies sont la règle dans les CPU des années 2020. Pour gérer ce cas, il faut ajouter des ports supplémentaires au cache d'instruction et adapter le fusionneur, pour qu'il puisse fusionner trois ou quatre blocs. De plus, il faut utiliser une unité de prédiction de branchement capable de ''prédire plusieurs branchements par cycle''. ===Le décodage superscalaire large=== Le décodage des instructions n'est pas censé dépendre de l'implémentation du chargement. En théorie, une fois plusieurs blocs d'instruction fusionnés, on peut décoder les instructions en parallèle. Cependant, certains processeurs effectuent le décodage en tenant compte de la manière dont les branchements découpent les blocs. Les processeurs Atom d'Intel utilisent une solution de ce type, qui couple prédiction de branchement et décodage parallèle. Ils chargent/décodent des paquets de 3 instructions consécutives, chaque paquet étant séparé du précédent par un branchement. Pour cela, en plus d'avoir un fusionneur adapté, ils regroupent les décodeurs en ''clusters'', chacun regroupant 3 décodeurs, et pouvant décoder trois instructions consécutives. Les micro-architectures Tremont et Crestmont avaient deux ''clusters'' (6 décodeurs au total), la micro-architecture Darkmont en intègre trois (9 décodeurs au total). Avec deux ''clusters'', le fonctionnement est le suivant. Si le code est composé d'une suite d'instruction sans branchements, seul le premier ''cluster'' est utilisé, limitant le décodage à trois instructions par cycle. Par contre, si l'une des trois instructions décodée est un branchement, alors le second ''cluster'' décode les trois instructions situées après ce branchement, à partir de l'adresse de destination. Avec un troisième ''cluster'', c'est la même chose, sauf qu'il faut qu'il y ait un branchement dans les trois instructions décodées par le second ''cluster''. Mais comment faire pour savoir quels décodeurs activés, quels ''clusters'' sont actifs ? C'est la prédiction de branchement qui commande. Avec deux ''clusters'', elle détermine si un branchement est présent dans les trois instructions à charger, et quelle est son adresse de destination. Sans branchement, elle prévient les décodeurs et les trois instructions chargées sont décodées dans un ''cluster'' libre. Si elle prédit un branchement, elle charge les instructions adéquates, et active les deux ''clusters''. Avec trois branchements, c'est le même mécanisme, sauf que l'unité de prédiction de branchement doit être capable de prédire deux branchements par cycle. [[File:Front-end découplé de la microarchitecture Tremont.png|centre|vignette|upright=3|Front-end découplé de la microarchitecture Tremont.]] Il faut noter que les décodeurs d'un ''cluster'' sont des décodeurs simples, sans microcode. Sur les processeurs Tremont et Crestmont, le microcode était unique et était partagé entre tous les ''clusters''. Un seul ''cluster'' pouvait décoder une instruction complexe avec le microcode, l'autre devait se limiter à des instructions simples uniquement. Depuis Skymont, le microcode est partiellement dupliqué, avec un microcode par ''cluster''. Le cout en hardware peut paraitre prohibitif, pour un gain en performance faible. Sauf que c'est oublier que ce sont des processeurs Atom, sur lesquels beaucoup d'instructions sont microcodées. Les processeurs Atom ont un budget en transistor limité, ce qui fait qu'il est préférable pour eux d'implémenter des instructions en microcode que d'utiliser des unités de calcul dédiées ou des circuits de décodage complexes. Pour limiter la casse, le microcode n'est que partiellement dupliqué. Seul le microcode pour les instructions fréquente est dupliqué. Il y a un microcode secondaire pour certaines instructions, qui est lui unique et partagé par tous les ''clusters''. ===Le contournement sur les processeurs superscalaires larges=== Pour rappel, la technique du contournement (''register bypass'') permet au résultat d'une instruction d'être immédiatement utilisable en sortie de l'ALU, avant même d'être enregistré dans les registres. Implémenter la technique du contournement demande d'utiliser des multiplexeurs pour relier la sortie de l'unité de calcul sur son entrée si besoin. Il faut aussi des comparateurs pour détecter des dépendances de données. [[File:Pipeline Bypass.png|centre|vignette|upright=1|Pipeline Bypass]] La sortie de chaque ALU doit être reliée aux entrées de toutes les autres, avec les comparateurs qui vont avec. Sur les processeurs ayant plusieurs d'unités de calculs, cela demande beaucoup d’interconnexions et de comparateurs. Pour N unités de calcul, cela demande 2 * N² interconnexions, implémentées avec 2N multiplexeurs de N entrées chacun. Si c'est faisable pour 2 ou 3 ALUs, la solution est impraticable au-delà. Non seulement ce serait un enfer à câbler, mais les fils seraient tellement longs que la fréquence du processeur en prendrait un coup. Notez que cela vaut pour les processeurs superscalaires, mais aussi pour tout processeur avec beaucoup d'unités de calcul. En théorie, un CPU à exécution dans le désordre, non-superscalaire, mais avec beaucoup d'unités de calcul, fait face au même problème. En pratique, avoir une dizaine d'ALU implique processeur superscalaire à exécution dans le désordre. D'où le fait qu'on parle du problème maintenant. La seule solution praticable est de ne pas relier toutes les unités de calcul ensemble. À la place, on préfère regrouper les unités de calcul dans différents '''agglomérats''' ('''cluster'''). Le contournement est alors possible entre les unités d'un même agglomérat, mais pas entre agglomérats différents. Évidemment, certaines possibilités de contournement sont perdues, mais c'est compensé par un gain en fréquence et un cout en circuit/fils réduit. C'est un bon compromis, ce qui explique que presque tous les processeurs modernes l'utilisent. Les rares exceptions sont les processeurs POWER 4 et POWER 5, qui ont préféré se passer de contournement pour garder un processeur très simple et une fréquence élevée. ===Le banc de registre des processeurs superscalaires larges=== Pour émettre deux opérations entières simultanément, il faut lire deux fois plus d'opérandes. Et il faut aussi écrire deux résultats dans les registres, en même temps. Pour cela, on double les ports du banc de registre. En général, il faut au maximum 2 ports de lecture et un port d'écriture par unité de calcul. Le problème, c'est que plus un banc de registres a de ports, plus il utilise de circuits, est compliqué à concevoir, consomme de courant et chauffe. Avec plusieurs dizaines d'unités de calcul différentes, ajouter autant de ports impacterait la fréquence du banc de registres et réduirait les performances, voire est totalement impraticable à cause des contraintes thermiques. Les processeurs superscalaires larges doivent donc trouver des solutions. La première solution utilise un banc de registre unique, mais n'utilise pas autant de ports que le pire des cas le demanderait. Le processeur détecte quand il n'y a pas assez de ports pour servir toutes les micro-opérations. Quand ça arrive, l'unité d'émission émet assez de micro-opérations pour exploiter les ports disponibles, mais met en attente les micro-opérations en trop, le temps que les ports se libèrent. Pour cela, le banc de registre est géré par un circuit d'arbitrage spécialisé, intégré à l'unité d'émission, l’'''arbitre du banc de registres''' (''register file arbiter''). Une autre solution est de dupliquer le banc de registres en plusieurs exemplaires qui contiennent exactement les mêmes données, mais avec moins de ports de lecture/écriture. Un exemple est celui des processeurs POWER, Alpha 21264 et Alpha 21464. Sur ces processeurs, le banc de registre est dupliqué en plusieurs exemplaires, qui contiennent exactement les mêmes données. Les écritures dans les registres sont envoyées à tous les bancs de registres, afin de garantir que leur contenu est identique. Chaque exemplaire a exactement deux ports de lecture. La conception du processeur est simplifiée, que ce soit au niveau du câblage, que de la conception des bancs de registres. Une dernière solution découpe le banc de registres en plusieurs bancs de registres plus petits, avec un réseau d'interconnexions pour échanger des données entre bancs de registres. Dans la plupart des cas, cette séparation est invisible du point de vue de l'assembleur et du langage machine. Le processeur se charge de transférer les données entre bancs de registres suivant les besoins. Sur d'autres processeurs, les transferts de données se font via une instruction spéciale, souvent appelée ''COPY''. [[File:Banc de registres distribué.png|centre|vignette|upright=2|Banc de registres distribué.]] Sur de certains processeurs, un branchement est exécuté par une unité de calcul spécialisée. Or les registres à lire pour déterminer l'adresse de destination du branchement ne sont pas forcément dans le même agglomérat que cette unité de calcul. Pour éviter cela, certains processeurs disposent d'une unité de calcul des branchements dans chaque agglomérat. Dans les cas où plusieurs unités veulent modifier le ''program counter'' en même temps, un système de contrôle général décide quelle unité a la priorité sur les autres. Mais d'autres processeurs fonctionnent autrement : seul un agglomérat possède une unité de branchement, qui peut recevoir des résultats de tests de toutes les autres unités de calcul, quel que soit l’agglomérat. ==La macro-fusion : une optimisation du décodage parallèle== Les processeurs superscalaires supportent la technique dite de '''macro-fusion''', qui permet de fusionner deux-trois instructions consécutives en une seule micro-opération. Par exemple, il est possible fusionner une instruction de test et une instruction de saut en une seule micro-opération de branchement. Il s'agit là de l'utilisation la plus importante de la macro-fusion sur les processeurs x86 modernes. La macro-fusion est utilisée pour fusionner un test et un saut en un branchement unique. L'optimisation est présente sur la plupart des CPU superscalaires modernes. Les CPU x86 l'implémentent, mais aussi quelques CPU ARM et les processeurs Apple de série M (M1 à M5, et potentiellement plus quand ils seront sortis). La fusion des instructions se fait lors du décodage des instructions, grâce à la coopération des décodeurs. Elle marche systématiquement si l'instruction de test et le saut sont consécutives, qu'elles forment bien une paire d'instruction. Par contre, insérer une instruction entre les deux empêche la macro-fusion de faire son travail, sauf si l'instruction insérée est un NOP. Les processeurs ARM64 avaient une forme spécifique de macro-fusion, utilisée pour un cas très précis : charger une constante immédiate de 32 ou 64 bits, dans un registre 64 bits. Les CPU ARM 64 bits utilisent des instructions codées sur 32 bits, qui ne peuvent encoder que des constantes immédiates de 16 bits. Pour charger une constante de 32/64 bits, il faut s'y prendre en plusieurs fois. Une première instruction MOVZ charge les 16 premiers bits, puis 2 à 4 instructions MOVK remplissent le reste. MOVZ met à zéro les 48 bits de poids fort, MOVK permet de sélectionner le doublet à modifier dans le registre (on modifie 16 bits, dont on choisit la place, le reste du registre est laissé tel quel). ARM permet de fusionner cette suite d'instructions en une seule µop MOV avec une constante immédiate. On parle alors de '''''MOVZ + MOVK fusion'''''. Une dernière utilisation, [https://www2.eecs.berkeley.edu/Pubs/TechRpts/2016/EECS-2016-130.pdf proposées pour le jeu d'instruction RISC-V], fusionnait un calcul d'adresse et une instruction LOAD/STORE en une seule instruction d'accès mémoire. Elle a été envisagée à une époque où le jeu d'instruction RISC-V ne gérait pas les modes d'adressage base + indice. L'idée était d'avoir une unité mémoire qui gérait le mode d'adressage base + indice et de fusionner des instructions pour l'exploiter. Mais de nos jours, le jeu d'instruction RISC-V intègre le mode d'adressage base + indice, ce qui fait que la macro-fusion n'a aucun intérêt pour ce cas précis. La macro-fusion a de nombreuses limitations en pratique. En théorie, on pourrait l'utiliser au-delà des deux situations mentionnées plus haut. Par exemple, pour fusionner une addition et une multiplication en une seule instruction MAD. Mais l'intérêt est assez faible. Notons que la macro-fusion ne permet que de fusionner des paires d'instructions. Aller au-delà demanderait un cout en circuit trop important. Déjà que tester deux paires utilise pas mal de comparateurs... ==Le ''stack engine'' : une optimisation de la pile d'appel== Les processeurs modernes intègrent une optimisation liée au pointeur de pile. Pour rappel, sur les architectures modernes, le pointeur de pile est un registre utilisé pour gérer la pile d'appel, précisément pour savoir où se trouve le sommet de la pile. Il est manipulé par les instructions CALL, RET, PUSH et POP, mais aussi par les instructions d'addition/soustraction pour gérer des cadres de pile de taille variable. De plus, il peut servir d'opérande pour des instructions LOAD/STORE, afin de lire/écrire des variables locales, les arguments d'une fonction, et autres. C'est donc un registre général adressable, intégré au banc de registre, altéré par l'unité de calcul entière. L'incrémentation/décrémentation du pointeur de pile passe donc par l'unité de calcul, lors des instructions CALL, RET, PUSH et POP. Mais, l'optimisation que nous allons voir permet d'incrémenter/décrémenter le pointeur de pile sans passer par l'ALU, ou presque. L'idée est de s'inspirer des architectures avec une pile d'adresse de retour, qui intègrent le pointeur de pile dans le séquenceur et l'incrémentent avec un incrémenteur dédié. ===Le ''stack engine''=== L'optimisation que nous allons voir utilise un '''''stack engine''''' intégré à l'unité de contrôle, au séquenceur. Le processeur contient toujours un pointeur de pile dans le banc de registre, cela ne change pas. Par contre, il n'est pas incrémenté/décrémenté à chaque instruction CALL, RET, PUSH, POP. Un compteur intégré au séquenceur est incrémenté à la place, nous l’appellerons le '''compteur delta'''. La vraie valeur du pointeur de pile s'obtient en additionnant le compteur delta avec le registre dans le banc de registre. Précisons que si le compteur delta vaut zéro, la vraie valeur est dans le banc de registre et peut s'utiliser telle quelle. Lorsqu'une instruction ADD/SUB/LOAD/STORE utilise le pointeur de pile comme opérande, elle a besoin de la vraie valeur. Si elle n'est pas dans le banc de registre, le séquenceur déclenche l'addition compteur-registre pour calculer la vraie valeur. Finalement, le banc de registre contient alors la bonne valeur et l'instruction peut s'exécuter sans encombre. L'idée est que le pointeur de pile est généralement altéré par une série d'instruction PUSH/POP consécutives, puis des instructions LOAD/STORE/ADD/SUB utilisent le pointeur de pile final comme opérande. En clair, une bonne partie des incrémentations/décrémentation est accumulée dans le compteur delta, puis la vraie valeur est calculée une fois pour toutes et est utilisée comme opérande. On accumule un delta dans le compteur delta, et ce compteur delta est additionné quand nécessaire. Précisons que le compteur delta est placé juste après le décodeur d'instruction, avant même le cache de micro-opération, l'unité de renommage et l'unité d'émission. Ainsi, les incrémentations/décrémentations du pointeur de pile disparaissent dès l'unité de décodage. Elles ne prennent pas de place dans le cache de micro-opération, ni dans le ''scheduler'', ni dans la suite du pipeline. De nombreuses ressources sont économisées dans le ''front-end''. Mais utiliser un ''stack engine'' a aussi de nombreux avantages au niveau du chemin de données/''back-end''. Déjà, sur les processeurs à exécution dans le désordre, cela libère une unité de calcul qui peut être utilisée pour faire d'autres calculs. Ensuite, le compteur delta mémorise un delta assez court, de 8 bits sur le processeur Pentium M, un peu plus pour les suivants. L'incrémentation se fait donc via un incrémenteur 8 bits, pas une grosse ALU 32/64 bits. Il y a un gain en termes de consommation d'énergie, un incrémenteur 8 bits étant moins gourmand qu'une grosse ALU 32/64 bits. ===Les points de synchronisation du delta=== La technique ne fonctionne que si la vraie valeur du pointeur de pile est calculée au bon moment, avant chaque utilisation pertinente. Il y a donc des '''points de synchronisation''' qui forcent le calcul de la vraie valeur. Plus haut, nous avions dit que c'était à chaque fois qu'une instruction adresse le pointeur de pile explicitement, qui l'utilise comme opérande. Les instructions CALL, RET, PUSH et POP ne sont pas concernées par elles utilisent le pointeur de pile de manière implicite et ne font que l'incrémenter/décrémenter. Mais dans les faits, c'est plus compliqué. D'autres situations peuvent forcer une synchronisation, notamment un débordement du compteur delta. Le compteur delta est généralement un compteur de 8 bits, ce qui fait qu'il peut déborder. En cas de débordement du compteur, le séquenceur déclenche le calcul de la vraie valeur, puis réinitialise le compteur delta. La vraie valeur est donc calculée en avance dans ce cas précis. Précisons qu'un compteur delta de 8 bits permet de gérer environ 30 instructions PUSH/POP consécutives, ce qui rend les débordements de compteur delta assez peu fréquent. À noter que si le compteur delta vaut zéro, il n'y a pas besoin de calculer la vraie valeur, le séquenceur prend cette situation en compte. Un autre point de synchronisation est celui des interruptions et exceptions matérielles. Il faut que le compteur delta soit sauvegardé lors d'une interruption et restauré quand elle se termine. Idem lors d'une commutation de contexte, quand on passe d'un programme à un autre. Pour cela, le processeur peut déclencher le calcul de la vraie valeur lors d'une interruption, avant de sauvegarder les registres. Pour cela, le processeur intègre un mécanisme de sauvegarde automatique, qui mémorise la valeur de ce compteur dans le tampon de réordonnancement, pour forcer le calcul de la vraie valeur en cas de problème. La technique du ''stack engine'' est apparue sur les processeurs Pentium M d'Intel et les processeurs K10 d'AMD, et a été conservée sur tous les modèles ultérieurs. L'implémentation est cependant différente selon les processeurs, bien qu'on n'en connaisse pas les détails et que l'on doive se contenter des résultats de micro-benchmarks et des détails fournit par Intel et AMD. Selon certaines sources, dont les manuels d'optimisation d'Agner Fog, les processeurs AMD auraient moins de points de synchronisation que les processeurs Intel. De plus, leur ''stack engine'' serait placé plus loin que prévu dans le pipeline, après la file de micro-opération. ==La micro-fusion et la délamination== La '''micro-fusion''' est une optimisation qui retarde le décodage réel de certaines instructions assez loin dans le pipeline. Elle concerne surtout les instructions ''load-op'', mais pas que. D'autres instructions mémoire peuvent subir cette optimisation. L'essentiel est que, sans micro-fusion, ces instructions sont décodées en plusieurs micro-opérations. La micro-fusion retarde le décodage final de ces instructions, qui se fait assez tard dans le pipeline. Pour comprendre l'intérêt, nous allons devoir faire quelques explications. L'optimisation en question fait le décodage en deux temps. Prenons l'exemple d'une opération ''load-op'', qui est censée être décodée en deux micro-opérations : une lecture, puis une opération. Le décodage produit une '''macro-opération''' (terme d'Intel), qui est propagée dans le pipeline, pour être scindée en deux micro-opérations un peu avant les ALU et l'unité mémoire. La macro-opération est techniquement une micro-opération comme une autre, sauf que ce n'est pas la micro-opération finale. L'unité d'émission découpe cette macro-opération en deux micro-opérations, qui sont émises l'une après l'autre. Pour résumer, les instructions ''load-op'' ne sont complétement découpées en micro-opération lors de l'émission, pas lors du décodage. L'optimisation impacte ce qui se situe entre le décodeur d'instruction et l'unité d'émission : l'unité de renommage, la file de micro-opérations, le ''Loop Stream Detector'' et/ou le cache de micro-opération. L'intérêt de l'optimisation est que l'on fusionne deux micro-opérations en une seule macro-opération. Le cache de micro-opération et la file de micro-opération peuvent mémoriser plus de micro-opérations, vu que certaines sont fusionnées. Quant à l'unité de renommage, elle renomme une seule macro-opération au lieu de renommer deux micro-opérations, ce qui augmente le débit du renommage de registre. Par contre, cela complique un peu le travail de l'unité d'émission, qui doit découper les instructions ''load-op'' en deux et émettre les micro-opérations l'une après l'autre. Il faut noter qu'il n'y a pas de fusion proprement dite. Le décodeur ne décode pas deux micro-opérations séparées, avant de les fusionner. En réalité, il génère directement une macro-opération, qui correspond à deux micro-opérations, que ce soit plus tard dans le pipeline ou sur une autre architecture. D'ailleurs, la micro-fusion a lieu à l'intérieur d'une instruction, qui est censée être traduite en plusieurs micro-opérations. Et encore : pas toutes. La conséquence est que la technique n'a de sens que sur les processeurs CISC, avec des instructions assez complexes pour être décodées en plusieurs micro-opérations. En pratique, seuls les CPU x86 sont concernés. ===Les domaines de fusion=== La micro-fusion n'est pas spécifique aux processeurs superscalaires. En théorie, on peut l'implémenter sur un processeur non-superscalaire à émission dans l'ordre. Cependant, je ne connais aucun processeur à émission dans l'ordre qui implémente la micro-fusion, même si son implémentation est en théorie possible sur de tels processeurs. La micro-fusion est implémentée différemment selon que l'émission se fasse dans l'ordre, dans le désordre, avec un ''scheduler'', avec des stations de réservation, etc. J'ai dit plus haut que les micro-opérations sont générées lors de l'émission, mais le moment exact varie suivant le processeur. Pour simplifier le tout, nous parlerons de '''scission''' quand le processeur traduit une macro-opération en deux/trois micro-opérations. Le moment où a lieu la scission est théoriquement dans l'unité d'émission, mais celle-ci prend plusieurs formes selon que le processeur utilise l'émission dans l'ordre, dans le désordre, avec un ''scheduler'', avec des stations de réservation, etc. Les processeurs à exécution dans l'ordre sont le cas le plus simple. L'unité d'émission est alors en charge du découpage des macro-opérations en micro-opérations. La file de micro-opération ou le cache de micro-opérations mémorisent des macro-opérations. À l'opposé, le tampon de ré-ordonnancement mémorise lui des micro-opérations. Le reste du processeur n'est pas affecté. Sur les processeurs à exécution dans le désordre, les différences sont nombreuses. Le tampon de ré-ordonnancement peut mémoriser soit les micro-opérations finales, soit des macro-opérations. Il en est de même avec le ''scheduler'' et/ou les stations de réservation, qu'elles soient centralisés ou décentralisés. Tout dépend de comment se fait l'implémentation. Une implémentation simple effectue la scission des macro-opérations dans l'unité d'émission, comme sur les processeurs à exécution dans l'ordre. Sur de nombreux processeurs, l'unité d'émission et de renommage sont simplement fusionnées, ce qui fait que la scission a lieu juste après le renommage de registres. En conséquence, le tampon de re-ordonnancement et les ''schedulers'' ne voient que des micro-opérations. Les macro-opérations disparaissent juste avant. Cette implémentation est préférée avec un ''scheduler'' centralisé, car on voit mal comment scinder une macro-opération juste avant l'ALU. Une autre implémentation fait la scission en sortie de le ''scheduler'' ou des stations de réservation, qu'elles soient centralisés ou décentralisés. Dans ce cas, le tampon de re-ordonnancement fait de même. L'avantage est que le tampon de ré-ordonnancement stocke des macro-opérations, ce qui augmente sa taille effective. Par exemple, il utilise une seule entrée pour une instruction ''load-op'', au lieu de deux sans micro-fusion de ce type. ===La délamination=== La scission peut parfois avoir lieu plus tôt, dans des circonstances très précises. Concrètement, cela ne concerne que quelques micro-architectures d'Intel, pour des instructions très précises. La raison est les limitations du format des micro-opérations, pas une histoire d'optimisation. Le processeur aimerait pouvoir faire la micro-fusion, mais ne peut pas à cause de ces limitations. Une telle situation cause alors une '''délamination''' : les micro-opérations sont scindées précocement. Par exemple, sur la micro-architecture SandyBridge d'Intel, les opérations ''load-op'' sont fusionnées, sauf si elles utilisent l'adressage indicé. Les micro-opérations de ce processeur ne peuvent avoir que deux opérandes. Trois opérandes est de trop, et les opérations ''load-op'' en adressage indicé dépassent cette limite. Dans ce cas, les micro-opérations sont fusionnées en sortie du décodeur, mais sont scindés avant d’entrer dans la file de micro-opération. L'avantage n'est pas évident, vu que l'unité de renommage suit de près le décodeur d'instruction. Il est que le cache de micro-opérations mémorise des macro-opérations, pas deux micro-opérations. ===La micro-fusion des processeurs Intel et AMD=== La micro-fusion est apparue sur le Pentium M d'Intel, et a été conservée telle quelle sur les processeurs Intel suivants. Les processeurs AMD supportent la micro-fusion depuis au moins la micro-architecture AMD K8. Mieux que ça, la délamination n'était pas utilisée car les micro-opérations acceptaient plus de 2 opérandes. Que ce soit chez AMD ou Intel, elle concerne deux types d'instructions : les écritures mémoire et les instructions ''load-op''. Sur le Pentium M, il y avait quelques limitations, l'optimisation se limitant par exemple aux registres entiers et flottants, mais pas aux registres MMX, mais pas les registres SSE (nous verrons ces registres dans quelques chapitres). Mais les processeurs modernes n'ont plus cette limitation. La micro-fusion des CPU Intel concerne deux types d'instructions : les écritures mémoire et les instructions ''load-op''. Pour les écritures, la situation est plus complexe que pour les instructions ''load-op''. Sur les processeurs Intel précédents, les écritures étaient réalisées dans deux unités séparées : le calcul d'adresse dans une unité de calcul, l'écriture proprement dite dans l'unité mémoire. Elles prenaient donc deux micro-opérations. Le processeur a changé ses unités mémoire, ce qui fait qu'elle pouvait faire les deux en une seule micro-opération. Il s'agissait alors d'une optimisation du chemin de données, plus que de la micro-fusion proprement dite, mais je la mentionne ici malgré tout. La micro-fusion sur ce processeur avait un avantage en plus des avantages usuels : elle utilisait mieux les décodeurs. Les Pentium M avaient trois décodeurs pour décoder plusieurs instructions en même temps, chose qu'on détaillera dans le chapitre sur les processeurs superscalaires. Un seul décodeur pouvait décoder toutes les instructions, les deux autres ne peuvent décoder que les instructions simples, qui se décodent en une seule micro-opération. Avec la micro-fusion, les trois décodeurs peuvent gérer les écritures mémoire et les opérations ''load-op'', vu qu'elles deviennent des instructions simples. Sans cela, elles auraient été limitées au premier décodeur. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Le parallélisme mémoire | prevText=Le parallélisme mémoire | next=Les microarchitectures pour le x86 : haute performance | nextText=Les microarchitectures pour le x86 : haute performance }} </noinclude> eoahxt9bnb6mw8ozbzm2f01yt3929wy 773678 773639 2026-09-29T23:03:53Z Mewtow 31375 /* L'exemple du PA-RISC PA 8000 */ 773678 wikitext text/x-wiki Les processeurs vus auparavant ne peuvent émettre au maximum qu'une instruction par cycle d'horloge. Ils peuvent avoir plusieurs instructions qui s'exécutent en même temps, dans des unités de calcul séparées. C'est le cas dès qu'une instruction multi-cycles s'exécute. Par contre, ils ne peuvent démarrer qu'une seule instruction par cycle. Et quand on court après la performance, ce n'est pas assez ! Les concepteurs de processeurs ont inventés des processeurs qui émettent plusieurs instructions par cycle : les '''processeurs à émissions multiples'''. Un processeur à émission multiple charge plusieurs instructions en même temps, les décode en parallèle, puis les émet en même temps sur des unités de calculs séparées. Pour cela, il faut gérer les dépendances entre instructions, répartir les instructions sur différentes unités de calcul, et cela n'est pas une mince affaire. En général, pour un processeur à émission multiple capable d'émettre N instructions en parallèle, on parle de '''processeur à N voies''', ou encore un ''processeur à N pipelines''. [[File:Superscalarpipeline.svg|centre|vignette|upright=1.5|Pipeline RISC classique à cinq étages sur un processeur superscalaire. On voit bien que plusieurs instructions sont chargées en même temps.]] Les processeurs à émission multiple sont de deux types : les processeurs VLIW et les '''processeurs superscalaires'''. Nous mettons les processeurs VLIW de côté en attendant le prochain chapitre. La raison est qu'ils ont un jeu d'instruction spécialisé qui expose le parallélisme d'instruction directement au niveau du jeu d'instructions, là où les processeurs superscalaires restent des processeurs au jeu d'instruction normal. La différence principale entre processeur VLIW et superscalaire est qu'un processeur superscalaire répartit les instructions sur les unités de calcul à l’exécution, là où un processeur VLIW délègue cette tâche au compilateur. ==Le nombre de voies d'un processeur superscalaire== Les processeurs superscalaires les plus simples ne permettent que d'émettre deux micro-opérations à la fois, d'où leur nom de processeur ''dual issue'', ce qui se traduit en '''processeur à double émission'''. Les processeurs triple émission permettent eux d’émettre trois instructions à la fois. A l'opposé, les CPU superscalaires les plus puissants peuvent émettre jusqu'à 8-10 instructions simultanément. En 2026, les CPU superscalaires peuvent monter jusqu’à 10 µops émises en même temps, ce qui est énorme ! Et cela nous amène à faire une distinction entre les processeurs superscalaires dits '''étroits''' et ceux dits '''larges'''. Dans ce wikilivre, on part du principe que les processeurs superscalaires étroits émettent jusqu'à 4-5 µops à la fois, alors que les larges peuvent en émettre plus, l'intervalle entre les deux est une zone grise. Le nombre exact n'est pas fixé dans le marbre, la distinction est volontairement vague. Nous parlerons de la '''largeur d'un CPU superscalaire''' pour parler du nombre de voies, du nombre de µops émises en même temps. Plus un CPU superscalaire est large, plus il est performant ''toutes choses égales par ailleurs''. Mais dans les faits, vous pouvez oublier la partie en italique. Élargir un CPU superscalaire demande de rajouter beaucoup de circuits. Et ce cout en circuit aura un impact sur la performance. À budget en transistors limité, il y a un compromis entre élargir un CPU et rajouter du cache ou la taille des ''schedulers''/ROB et autres. ===Les contraintes d’appariement=== Prenons un processeur double émission, capable d'émettre deux instructions simultanément. Émettre deux instructions en même temps n'est pas toujours possible. Par exemple, si deux instructions sont dépendantes, on ne peut pas les émettre en même temps. Mais oublions un instant ces histoires de dépendances de données, et partons du principe que le CPU ait affaire à deux instructions indépendantes, une paire idéale. Un CPU double émission "parfait" pourrait exécuter n'importe quelle paire d'instruction. Par exemple, il pourrait émettre deux multiplications consécutives, deux lectures consécutives, une lecture et une écriture en même temps, etc. En pratique, aucun processeur ne permet cela. Implémenter un CPU superscalaire "parfait" aurait un cout en circuit beaucoup trop conséquent. Par exemple, pour émettre deux multiplications en même temps, il faudrait deux multiplieurs séparés. Idem pour exécuter deux accès mémoire simultané : cela demande d'avoir deux unités mémoire et un cache multiport. Mais en pratique, aucun CPU superscalaire ne fait cela. La totalité des CPU double émission se débrouille avec un seul circuit multiplieur et une seule unité mémoire. Et cela entraine l'apparition de dépendances structurelles, qui font que certaines paires d'instructions sont impossibles. Par exemple, impossible d'émettre deux multiplications en même temps avec un seul circuit multiplieur. Mais émettre une multiplication en parallèle d'une addition est parfaitement possible. Il y a donc des paires d'instructions autorisées et des paires interdites. Et la logique est la même sur les CPU à triple ou quadruple émission, et au-delà. : des triplets ou quadruplet d'instructions sont impossibles à émettre simultanément, alors que d'autres le sont. Pour le dire autrement, il y a des '''contraintes d'appariement''' sur les instructions à émettre en même temps. ===L'impact des contraintes d’appariement sur la performance=== Ces contraintes d’appariement ont un impact sur les performances, mais celui-ci peut être grandement mitigé. Les programmes informatiques utilisent en pratique beaucoup plus d'opérations entières de base que de multiplication, branchements et accès mémoire. Il y a environ 5 opérations entières de base pour une multiplication entière. En pratique, il est rare de devoir exécuter deux multiplications à la fois. Idem pour les décalages et rotations, qui sont assez éloignés les uns des autres. Deux branchements consécutifs sont quant à eux plus fréquents. Deux accès mémoire consécutifs est assez rare, mais ils restent assez proches les uns des autres malgré tout. La conséquence est que certaines paires d'instructions sont privilégiées par rapport au reste. Les paires regroupant deux calculs basiques (additions, soustractions, ...) sont systématiquement supportées, car dupliquer des ALU entières est facile. Les paires regroupant un calcul et une autre instruction sont elles aussi systématiquement supportées. Par contre, les paires avec deux branchements, deux accès mémoire, deux décalages/rotations, ou deux multiplications/divisions sont fréquemment interdites. Seuls les CPU superscalaires larges peuvent les permettre, et encore : sous conditions. Le résultat est que le processeur peut se débrouiller avec une seule unité mémoire et une unité de branchement. ===Terminologie pour la suite du chapitre=== Décrire les contraintes d’appariement demande de dire quelles combinaisons d’instructions sont autorisées ou interdites. Et pour cela, nous allons introduire les abréviations suivantes : * INT est un raccourci pour parler d'une opération entière simple, qu'une ALU entière peut exécuter. * MUL correspond à une opération entière complexe, typiquement une multiplication, éventuellement à une division. * FLOAT désigne une opération flottante, peut importe laquelle. * MEM désigne un accès mémoire, à savoir une instruction ou µop mémoire. * BRANCH désigne une instruction de branchement. Cette terminologie permettra de définir des paires d'instructions, qu'elles soient possibles ou interdites. Par exemple, l'expression INT + FLOAT désigne une paire d'instruction regroupant une instruction entière et une instruction flottante, peu importe l'ordre des deux instructions. Il en sera de même pour les triplets, quadruplets, ou plus. Par exemple, l'expression INT + INT + FLOAT + MUL désigne un quadruplet d'instructions regroupant : deux instructions entières, une instruction flottante, et une multiplication entière. J'utiliserais aussi des parenthèses pour regrouper certaines combinaisons. Par exemple, l'expression INT + (MUL /FLOAT) veut parler d'une paire d'instruction où la première est une opération entière basique, la seconde est : soit une multiplication, soit une opération flottante. ==Le ''front-end'' des processeurs superscalaires== Un processeur superscalaire doit charger, décoder, et exécuter plusieurs instructions par cycle. Par exemple, un processeur triple émission doit charger 3 instructions lors d'un premier cycle, puis les décoder au cycle suivant, et les exécuter au cycle suivant. Il travaille donc pas paquets de 3 instructions, dans cet exemple. Intuitivement, charger, décoder et exécuter plusieurs instructions à la fois demande de dupliquer des circuits. Par exemple, il faut dupliquer les décodeurs pour décoder plusieurs instructions. Les unités de calcul sont aussi dupliquées, sauf sur certains processeurs qui arrivent à ruser, mais laissons cela de côté pour plus tard. Mais d'autres circuits sont simplement modifiés, comme l'unité de chargement ou l'unité d'émission. Voyons ce qu'il en est dans le détail. {|class="wikitable" |- ! rowspan="2" | Processeur sans émission multiple | rowspan="2" | Chargement | rowspan="2" | Décodage | rowspan="2" | Renommage | rowspan="2" | Émission | Exécution / ALU | rowspan="2" | ''Commit''/ROB |- | Exécution / ALU |- ! rowspan="4" | Processeur superscalaire | rowspan="4" | Chargement | rowspan="2" | Décodage | rowspan="4" | Renommage | rowspan="4" | Émission | Exécution / ALU | rowspan="4" | ''Commit''/ROB |- | Exécution / ALU |- | rowspan="2" | Décodage | Exécution / ALU |- | Exécution / ALU |} Nous allons d'abord voir ce qu'il en est pour le ''front-end'', à savoir la partie du CPU qui s'occupe de charger et décoder les instructions. Elle regroupe l'unité de chargement, les décodeurs, l'unité de prédiction de branchement, la file de µops, la file d'instruction, et divers caches. En soi, les changements portent surtout sur l'unité de chargement et les décodeurs. ===Le chargement de plusieurs instructions consécutives=== Un processeur superscalaire charge plusieurs instructions en même temps, ''en tenant compte de la présence de branchements''. La partie en italique est importante et elle a une conséquence très forte : la manière de faire est fortement différente entre un CPU superscalaire étroit et large. Un CPU superscalaire étroit fait au plus simple : il charge un bloc de 2, 3, 4 instructions consécutives en mémoire RAM. Il faut alors doubler/tripler/quadrupler la taille du bus connecté au cache d'instruction. Par exemple, pour charger quatre instructions de 32 bits chacune, il suffit de lire un bloc de 128 bits dans le cache d'instruction. Un bloc de 8, 16, 32 octets est donc lu depuis le cache et est ensuite découpé en instructions, envoyées chacun à un décodeur. Charger plusieurs instructions consécutives ne marche bien qu'en absence de branchements. La présence de branchements casse cette dynamique, et il faut gérer leur présence. * Sans prédiction de branchement, toutes les instructions d'un bloc sont décodées et exécutées en même temps, même s'il y a un branchement dans le tas. * Avec prédiction de branchement, les instructions situées après le branchement ne sont pas décodées ni exécutées. L'unité de chargement coupe le bloc chargé au niveau du premier branchement pris, remplit les vides avec des NOP, avant d'envoyer le tout à l'unité de décodage. Les instructions à l'adresse de destination seront chargées au cycle suivant, en chargeant un nouveau bloc. [[File:Fetch sur un processeur superscalaire avec prediction de branchements.png|centre|vignette|upright=2|Fetch sur un processeur superscalaire avec prédiction de branchements.]] Un autre défaut est que sur le CPU charge un bloc de 128 bits à la fois, les instructions doivent être alignées sur 128 bits. Et on peut généraliser à n'importe quelle taille de bloc. Si les instructions ne sont pas alignées, il faut gérer la situation. Il arrive qu'une instruction soit à cheval sur deux blocs, avec un morceau dans le premier bloc, un autre dans le second. Dans ce cas, l'instruction est chargée en deux fois, et des circuits doivent gérer la situation pour recoller les morceaux. Sur les CPU avec des instructions de taille fixe, le problème ne survient que rarement. Mais il est fréquent avec des instructions de taille variable. Un autre défaut est lié aux branchements. Imaginez qu'un branchement s'exécute et branche vers une instruction de destination. Rien n'indique que l'instruction de destination sera au tout début d'un bloc. Si ça se trouve, elle sera en troisième position d'un bloc de 4 instructions. Une solution simple charge le bloc en respectant l'alignement, et les deux premières instructions du bloc ne sont pas à exécuter. Il y a donc une petite perte de performance. Certains CPU, comme l'IBM RS/6000, ont la machinerie charger un bloc de N instructions même s'il n'est pas aligné. La machinerie en question se trouve dans le cache d'instruction et est tout sauf simple à expliquer, ce qui fait que je me permets de la passer sous silence. Un détail, cependant : elle ne permet pas de charger des blocs qui sont à cheval sur deux lignes de cache. ===Le décodage parallèle des instructions=== Pour le décodage des instructions, plusieurs instructions sont décodées en même temps. On parle alors de '''décodage parallèle'''. Pour ce faire, un processeur superscalaire contient plusieurs décodeurs, chacun pouvant décoder une instruction en parallèle des autres. Prenons par exemple un processeur superscalaire à 4 voies : le décodage se fera dans quatre décodeurs séparés, qui fonctionneront en parallèle. Cependant, cette implémentation ne marche bien que pour les processeurs RISC, les processeurs CISC devant faire avec un microcode gourmand en circuits. Les processeurs CISC utilisent des décodeurs hybrides, avec un microcode qui complémente un décodeur câblé. Dupliquer le microcode aurait un cout en transistors trop important, ce qui fait que seuls les décodeurs câblés sont dupliqués. Les CPU CISC superscalaires disposent donc de plusieurs décodeurs simples, capables de décoder les instructions les plus courantes, avec un seul microcode. La conséquence est qu'il n'est pas possible de décoder deux instructions microcodées en même temps. Par contre, il reste possible de décoder plusieurs instructions non-microcodées ou une instruction microcodée couplée à une instruction non-microcodée. Vu qu'il est rare que deux instructions microcodées se suivent dans un programme, le cout en performance est extrêmement mineur. Il faut noter qu'une instruction correspond à une ou plusieurs µops. Il est donc possible de charger 5 instructions et de se retrouver avec 8 µops en sortie des décodeurs. Et c'est la source d'une distinction très importante. Plus haut, j'ai parlé de processeurs superscalaires à N voies. La terminologie peut avoir deux interprétations. La première est que le processeur charge/décode N instructions à la fois. Une seconde est qu'il est capable d'exécuter/émettre N µops en même temps. Les deux ne sont pas équivalentes, vu qu'un processeur superscalaire peut, par exemple, charger/décoder N instructions et émettre/exécuter N+2 µops. La distinction est particulièrement importante sur les processeurs superscalaires larges. Certains d'entre eux sont capables de charger 5 instructions et d'en émettre le double ! Un exemple classique était les processeurs Athlon d'AMD, qui pouvaient décoder deux instructions par cycle, mais émettre 4 µops par cycle. Ce n'était pas un problème, car beaucoup d'instructions, même basiques, étaient décodées en 2 µops. ===L'émission parallèle des instructions=== La superscalarité modifie en profondeur l'unité d'émission, notamment au niveau de son interface. Avant, elle recevait une micro-opération sur son entrée, et fournissait la micro-opération émise sur une sortie. Et cela vaut aussi bien pour une unité d'émission simple, un ''scoreboard'', un ''scheduler'' ou des stations de réservation. Mais avec l'émission multiple, les sorties et entrées sont dupliquées. Pour la double émission, il y a deux entrées vu qu'elle doit recevoir deux micro-opération décodées/renommées, et deux sorties pour émettre deux micro-opérations. Dans ce qui suit, nous ne parlerons pas d'entrée et de sortie, mais de '''ports de décodage''' et de '''ports d'émission'''. Les ports de décodage reçoivent des micro-opérations provenant de l'unité de décodage, les ports d'émissions sont pour les micro-opérations émises. Les ports d'émission injectent les micro-opérations émises dans le pipeline, elles sont propagées au banc de registre, aux ALUs, etc. Un processeur superscalaire a forcément plusieurs ports d'émission (et de décodage). Si l'interface de l'unité d'émission change, l'intérieur est tout autant modifié. Sur un CPU non-superscalaire, l'unité d'émission reçoit une µop "candidate à l'émission", et détecte les dépendances entre avec les µops en vol, en cours d'exécution dans le pipeline. Et c'est toujours le cas sur les processeurs superscalaires : l'unité d'émission détecte les dépendances entre les µops candidates et les µops en vol. Mais avec la siperscalarité, elle doit en plus tester les dépendances entre les µops candidates. Si l'unité d'émission est un ''scoreboard'', il doit détecter les dépendances entre instructions émises simultanément et les sérialiser si besoin. Avec un ''scheduler'', il n'y a pour ainsi dire rien à faire, vu que les dépendances sont éliminées par le renommage de registre et que les signaux de réveil gèrent les dépendances RAW. C'est la raison pour laquelle les processeurs superscalaires modernes n'utilisent pas de ''scoreboard''. ==Les processeurs implémentés avec plusieurs pipelines== Nous venons de voir comment la superscalarité impacte le ''front-end'', il est maintenant de voir ce qu'il en est de l'unité d'émission et des ''back-ends''. Un processeur superscalaire peut utiliser l'exécution dans le désordre et le renommage de registres, mais ce n'est pas une obligation. Historiquement, les premiers processeurs superscalaires n'utilisaient pas d'exécution dans le désordre. Le meilleur exemple est celui du Pentium 1 et 2 d'Intel. Ils étaient tous deux des processeurs superscalaires, mais n'avaient pas d'exécution dans le désordre, qui est apparue sur le Pentium 3. les explications sont plus simples si on met de côté l'exécution dans le désordre. Vous vous dites que l'implémentation d'un processeur superscalaire n'est pas la même suivant que le CPU utilise l'exécution dans le désordre, ou non. Mais dans les faits, la distinction est plus subtile que ca. Pour l'expliquer, je vais utiliser une classification originale, qui sépare les processeurs superscalaires en trois sous-types. La distinction se fait sur la manière dont la superscalarité est implémentée en matériel.La classification que j'utilise distingue : * Les processeurs avec plusieurs pipelines, sans exécution dans le désordre. * Les processeurs superscalaires avec un pipeline dynamique. * Les processeurs avec des ''schedulers'' décentralisés. La distinction n'est pas qu'une question d'implémentation matérielle. Elle impacte aussi le ratio entre instructions chargées/décodées et instructions émises. Vous vous dites que les deux sont égales, mais ce n'est le cas que sur les processeurs avec N pipelines ! Sur les autres processeurs, il est possible de décoder 4 instructions, mais d'en émettre maximum 6 par cycle ! Et sur les CPU avec des ''schedulers'' décentralisés, il y a aussi une différence entre le nombre d'instructions qui sont ''dispatch'' et ''schedule''. La catégorie la plus simple est celle des '''processeurs avec plusieurs pipelines'''. Ce sont des processeurs superscalaires sans exécution dans le désordre. Ils partent d'un processeur non-superscalaire, et ajoutent un second pipeline, en sortie de l'unité d'émission. Le second pipeline permet l'émission parallèle d'une seconde instruction. Le second pipeline n'est pas identique au pipeline originel, sur plusieurs points. Premièrement, il n'a pas exactement les mêmes circuits. Le second pipeline est généralement composé d'une unité de calcul, d'une FPU, éventuellement d'un second banc de registres, guère plus. Il permet d'exécuter une seconde opération de calcul, pas plus, ce qui est à l'origine de contraintes d'appariement assez fortes. De plus, il n'a pas forcément la même longueur, il peut avoir des étages en moins ou en plus. Il s'agit de la forme la plus simple de processeur superscalaire et nous allons leur consacrer cette section. ===La double émission entière-flottante=== L'exemple le plus simple utilise un second pipeline pour les opérations flottantes, séparé du pipeline originel. L'ajout d'un pipeline flottant permet d'émettre une micro-opération entière en même temps qu'une micro-opération flottante, ce qui s'appelle la '''double émission entière-flottante'''. La micro-opération entière s'exécute dans l'ALU entière, la micro-opération flottante dans la FPU. Les exemples les plus notables sont le PA-RISC 7100, le POWER 1 (RIOS .& et .9) et le PowerPC 601. L'Apollo DN10000 et l'Intel i860 utilisaient aussi cette forme de double émission, mais étaient des prototypes de CPU VLIW. [[File:Double émission entière-flottante.png|centre|vignette|upright=2|Double émission entière-flottante]] Pour bien expliquer les choses, prenons le processeur illustré ci-dessous, avec deux ''back-end'' séparés : un pour la FPU, et un autre pour le reste. Les instructions entières et mémoire passent toutes par le ''back-end'' généraliste. [[File:CPU non-superscalaire basique, avec une FPU.png|centre|vignette|upright=1.5|CPU non-superscalaire basique, avec une FPU]] Les deux ''back-end'' sont des pipelines séparés, mais il faut que l'unité d'émission soit spécialement conçue pour en profiter. Un processeur simple émission peut démarrer une seule µop par cycle : soit la µop est envoyée au ''back-end'' flottant, soit elle est envoyée au ''back-end'' général. Avec la double émission entière-flottante, le processeur peut envoyer une µop dans chaque pipeline, à chaque cycle. Vu que la FPU et son banc de registre forment déjà un pipeline séparé, les seules modifications se font au niveau du ''front-end'', unité d'émission inclue. {| |- |[[File:CPU simple émission avec une FPU.png|centre|vignette|upright=1.5|CPU simple émission avec une FPU.]] |[[File:Double émission entière flottante avec un second pipeline.png|centre|vignette|upright=1.5|CPU avec un second pipeline flottant.]] |} Notez que le terme double émission ''entière''-flottante est un peu trompeur. En réalité, la technique permet d'émettre une instruction flottante avec n'importe quelle autre instruction non-flottante, avec des restrictions pour les branchements. Il est par exemple possible d'exécuter un calcul flottant en parallèle d'un accès mémoire. Sur les CPU 32 bits, il est possible de faire les multiplications dans la FPU. Pour rappel, la FPU contient un multiplieur entier 53-54 bits, pour multiplier les mantisses de deux flottants 64 bits, qu'on peut utiliser pour faire les multiplications entières 32 bits. Cela permet d'émettre une multiplication en même temps qu'une opération entière dans l'ALU. Ainsi, le CPU pouvait émettre deux instructions : une opération entière de base, avec soit une multiplication, soit une opération flottante. En clair, une émission de type INT + (MUL /FLOAT). Par contre, on perd la possibilité d'émettre une multiplication entière avec une opération flottante, mais c'était un compromis qui en valait la peine. Le CPU PA-RISC 7100 implémentait cette optimisation. Il s'agissait d'un CPU double émission entière-flottante, qui utilisait donc un partitionnement assez simple. Le combo partitionnement + reconditionnement permettait ici de gagner en performance, pour un cout en matériel très limité. D’autant plus limité que le jeu d'instruction prévoyait le reconditionnement de la FPU. Les multiplications ne lisaient pas leurs opérandes dans les registres entiers, mais dans les registres flottants. ===La double émission entière=== Une autre possibilité ajoute un second pipeline, capable d'exécuter des opérations entières simples, appelé le pipeline entier. Le processeur supporte alors la '''double émission entière''', à savoir qu'ils peuvent émettre une opération entière en plus d'une autre instruction. L'opération entière en question est une opération simple, comme une addition, une soustraction, une opération bit à bit, une comparaison, etc. Les exemples classiques sont les processeurs Intel i960 et Pentium. L'implémentation était différente entre l'i960 et le Pentium : Le Pentium avait une seconde ALU entière, alors que le i960 rusait. Le Pentium dupliquait l'ALU entière, pour créer un second pipeline entier. Sur le Pentium originel, les contraintes d'appariement étaient assez strictes. Le Pentium avait une FPU, mais ne pouvait pas l'utiliser en double émission. Il lui était impossible d'exécuter une opération flottante en même temps qu'une opération entière (branchements inclus). Le Cyrix 6x86 était une sorte de Pentium produit par l'entreprise Cyrix, avec une microarchitecture différente. Il avait des contraintes d’appariement réduites. Par exemple, il pouvait émettre une opération flottante en parallèle d'une opération entière. Nous détaillerons ces processeurs dans le prochain chapitre, qui porte justement sur les CPU superscalaires x86. [[File:CPU simple et double émission avec un second pipeline entier.png|centre|vignette|upright=2.5|CPU simple et double émission avec un second pipeline entier.]] L'Intel i960 n'avait pas de FPU, juste une ALU entière et une unité mémoire. Il utilisait l'unité mémoire comme une seconde ALU entière limitée. Pour rappel, une unité mémoire contient une AGU, à savoir une ALU spécialisée dans les calculs d'adresse. Elle est capable de faire des additions, soustractions, et quelques décalages limités (des décalages par 2, 4, 8, pas plus). L'Intel i960 ajoutait des connexions entre AGU et banc de registre, afin que celle-ci serve de seconde unité de calcul. L'AGU est déjà reliée aux deux ports de lecture, pour lire les opérandes du calcul d'adresse, il suffit de la connecter sur le port d'écriture. Le processeur peut alors émettre deux instructions/µops entières, sous certaines conditions. [[File:Emission multiple des opérations entières, double émission.png|centre|vignette|upright=2|Émission multiple des opérations entières, double émission.]] ==Les processeurs superscalaires dynamiques== Les processeurs précédents, avec 2 pipelines, avaient une unité d'émission assez simple. Elle avait deux ports de décodage, et deux ports d'émission. Le nombre de ports de décodage et d'émission étaient identiques. Vous vous dites que c'est naturel, et intuitif, que c'est normal pour un processeur superscalaire. Mais en réalité, la majorité des processeurs superscalaires a plus de ports d'émission que de décodage. Expliquer pourquoi va cependant nous demander de parler de comment la superscalarité exploite les unités de calcul. Posons-nous cette question : de combien d'unités un processeur superscalaire a besoin ? Les unités en question ne sont nécessairement des unités de calcul, l'unité mémoire et l'unité de branchement comptent aussi. La réponse dépend du nombre de voies. Si le ''front-end'' charge et décode un paquet de N instructions, exécuter ces N instructions simultanément demandera là aussi au moins N unités de calcul. Notez le terme : ''au moins'', car c'est là tout l'enjeu de cette section. La réponse dépend aussi des contraintes d’appariement. Pour un CPU superscalaire "parfait", sans contraintes d’appariement, toutes les unités doivent être dupliquées, y compris l'unité mémoire. Un processeur à double émission parfaite devrait dupliquer l'ALU entière, le ''barrel shifter'', le circuit multiplieur, la FPU, l'unité mémoire, et l'unité de branchement, ce qui ferait passer de 6 unités à 12. Le cout en circuit est énorme, même pour de la double émission ! Et pour un CPU à N pipelines, le cout en circuit encore plus prohibitif ! En pratique, les processeurs superscalaires qui font ça sont très rares. La majeure partie des processeurs superscalaires utilisent d'autres techniques : le partitionnement, la duplication partielle des ALUs, la duplication des autres unités. ===Le partitionnement des unités fonctionnelles=== Les CPU superscalaires les plus simples ne dupliquent pas leurs unités de calcul, ils se contentent d'exploiter les unités existantes. Et pour expliquer comment, nous allons partir de l'exemple d'un processeur non-superscalaire contient une ALU entière, une FPU, une unité mémoire et une unité de branchement. Les quatre unités peuvent fonctionner en parallèle, à savoir qu'une unité peut exécuter une instruction à elle toute seule, sans interagir avec les autres. Cela suffit pour créer un processeur quadruple émission, qui peut émettre en même temps : une opération entière, une opération flottante, un branchement, un accès mémoire. Le principe marche aussi sur un processeur avec moins de 4 unités, par exemple sans FPU et/ou sans unité de branchement, ou avec au contraire des unités en plus. L'idée générale est d’émettre une µops séparée dans chaque unité fonctionnelle. Utiliser ainsi les unités existantes, pour rendre un CPU superscalaire, s'appelle le '''partitionnement superscalaire'''. Le terme n'est pas beaucoup utilisé en dehors de quelques vieux articles académiques. Le partitionnement est fortement dépendant du jeu d'instruction, car il demande de bien séparer instructions entières, flottantes, branchements et instructions mémoire. Et autant c'est bien le cas sur les CPU RISC, autant les CPU CISC ne sont pas dans ce cas. Les CPU CISC ont des instructions ''load-op'', qui effectuent une instruction arithmétique et une µop mémoire. Et ces instructions sont très compliquées à implémenter avec le partitionnement. Et au-delà de ça, les CPU CISC ont beaucoup d'instructions qui sont décodées en plusieurs µops, à exécuter dans un ordre bien précis. On peut pas émettre les µops en question simultanément. Le partitionnement a un cout en circuit très limité, pour un gain en performance lui aussi limité. Pour reprendre le CPU de l'exemple précédent, il est rare que l'on ait à exécuter ces quatre instructions en même temps. En pratique, les combinaisons fréquentes sont les combinaisons calcul + accès mémoire, calcul + branchement, calcul entier + calcul flottant. Utiliser une quadruple émission de ce type n'est donc pas une bonne idée, alors que la double émission parait plus adaptée. Et c'est là que la différence entre ports d'émission et de décodage devient intéressante. L'idée est d'avoir une unité d'émission avec deux ports de décodage, et 4 ports d'émission (un par unité). Les contraintes d’appariement varient alors suivant le processeur, mais la règle générale est que si deux micro-opérations tombent dans deux unités différentes, on peut les émettre en même temps. En clair, on peut émettre une opération entière avec une opération flottante, une opération entière avec un branchement, un accès mémoire avec un branchement, etc. Et cela rend le partitionnement bien plus intéressant que prévu. Les tout premiers CPU superscalaires étaient des CPU double émission, qui utilisaient le partitionnement avec : une ALU entière, une unité mémoire et une FPU. Nous parlerons de '''partitionnement INT-FLOAT-MEM'''. L'avantage sur la double émission flottante est que les combinaisons INT + MEM et FLOAT + MEM étaient autorisées. L'intérêt était d'émettre une opération en parallèle d'un accès mémoire, ce qui est un doublet d'instruction assez fréquent. Les exemples classiques sont l'HyperSPARC, de l'alpha 21064 et du PowerPC 603. Les contraintes d’appariement variaient grandement suivant le processeur. Le PowerPC 603 implémentait une double émission "parfaite". C'est à dire que toutes les combinaisons possibles à deux instructions étaient possibles, que ce soit INT + FLOAT, INT + MEM, FLOAT + MEM. En plus de cette double émission "parfaite", le CPU utilisait la technique dite de ''branch folding'', qui permettait d'exécuter un branchement sans utiliser d'unité de calcul, ce qui fait qu'il était qualifié de ''CPU 2-way + Branch''. A l'opposé, le processeur alpha 21064 avait pas mal de contraintes d’appariement, à savoir que certaines combinaisons de deux instructions étaient interdites, bien que compatibles avec les unités disponibles. Une des raisons est que le banc de registre n'avait pas assez de ports de lectures, ce qui fait que certaines combinaisons avec une écriture mémoire n'étaient pas permises. Les concepteurs avaient volontairement inséré ces contraintes afin de simplifier le design du processeur. Avant de poursuivre, précisons que la FPU regroupe un additionneur flottant et un multiplieur flottant. Et ce fait peut être exploité pour approfondir le partitionnement. La '''double émission FADD/FMUL''' permet d'émettre une addition flottante en même temps qu'une multiplication flottante. Elle a été utilisée sur les processeurs x86, Alpha et SPARC. Les autres circuits de calcul flottant sont souvent regroupés avec l'additionneur. La division est parfois e même port que le multiplieur flottant, parfois sur celui de l'additionneur (quand elle est microcodée et exécutée en enchainant les soustractions). ===La duplication des ALU entières=== Le partitionnement est une technique élégante, simple, facile à implémenter et au cout en circuits modeste. Mais il faut avouer que cela ne donne pas des CPU superscalaires très efficaces. La raison est que le partitionnement permet d'émettre des paires, triplets, quadruplets de micro-opérations qui sont rares en pratique. Les combinaisons les plus fréquentes en pratique sont des paires/triplets d'opérations entières, souvent des paires/triplets d'additions ou d'opérations entières simples. Il est donc primordial d'émettre plusieurs opérations entières simultanément. Le fait d'émettre et d'exécuter plusieurs opérations entières en même temps s'appelle l''''émission entière multiple'''. Pour exécuter la seconde/troisième opération entière, il faut dupliquer les ALU entières (ou réutiliser l'AGU comme ALU entière comme le fait l'Intel i960). Le processeur doit avoir deux ALU entières pour de la double émission entière, trois pour de triple émission entière, etc. De plus, il faut ajouter des ports au banc de registre, pour lire deux fois plus d'opérandes et décrire deux résultats. Et enfin, il faut rajouter un port d'émission pour pouvoir émettre une micro-opération entière en plus. [[File:Processeur non-superscalaire basique 03.png|centre|vignette|upright=2|Processeur non-superscalaire basique]] La tendance est de multiplier les ALU entières, mais pas le circuit multiplieur. Le cout en transistors est alors grandement réduit, au prix de l'apparition de dépendances structurelles. Le CPU peut émettre deux additions en même temps, ou une addition et une multiplication, mais pas deux multiplications. Il en est de même avec le ''barrel shifter'', qui n'est pas dupliqué. Il est donc possible d'émettre un décalage avec une opération de base, mais pas deux décalages en parallèle. Mais ces contraintes d’appariement ne sont pas un problème, car il est rare de devoir émettre deux multiplications/décalages en même temps. La plupart des programmes sont majoritairement remplis d'additions, avec des multiplications assez rares et des décalages qui le sont encore plus. La moyenne est proche d'une multiplication pour 4/5 additions. Vu que des multiplications consécutives sont très rares, dupliquer le multiplieur est presque inutile. Disposer de plusieurs circuits multiplieurs ou de plusieurs ''barrel shifters'' serait donc un cout en circuits qui ne servirait que rarement et n'en vaut pas la chandelle. Il faut noter que sur les CPU 32 bits, les multiplications peuvent être exécutées dans la FPU ou dans un multiplieur séparé, tout dépend de si le CPU exécute les multiplications dans la FPU ou pas. {|class="wikitable" |- ! Voie d'émission n°1 !! Voie d'émission n°2 !! Voie d'émission n°3 |- | ALU entière || ALU entière || FPU |} Reste à connecter les unités de calcul à l'unité d'émission (indirectement, car il y a des étages de pipeline entre les deux). Une implémentation basique utilisée un port d'émission par unité. Prenons l'exemple d'un CPU superscalaire avec 4 ALU entières, une FPU, et une unité mémoire. Vu qu'il y a 6 unités, cela fait donc 6 ports d'émission. L'exemple historique le plus impressionnant est celui du Motorola 88110, un CPU double émission qui possède 10 unités. Il contient deux ALU entières, un circuit multiplieur, un circuit diviseur, une unité de manipulation de bits, une unité mémoire, un additionneur flottant, et deux unités graphiques pour des calculs impliquant des pixels. Le multiplieur est utilisé à la fois pour les multiplications entières, flottantes et le produit de deux pixels. Idem pour le diviseur, qui sert pour les divisions entières et flottantes. Et chaque unité a son propre port d'émission. La conséquence est que les contraintes d'appariement du Motorola 88110 sont simples : tant que deux µops atterrissent dans des unités séparées, la paire est permise. Il est par exemple possible d'émettre simultanément deux opérations entières simples, vu qu'il y a deux ALU. Par contre, impossible d'émettre simultanément deux multiplications, deux divisions, deux opérations flottantes, deux manipulations de bit, deux accès mémoire, etc. De plus, le partage du multiplieur fait qu'on ne peut pas émettre une multiplication entière avec une multiplication flottante. Idem avec les divisions, vu que le diviseur est aussi partagé. Ce sont les seules contraintes. ===Le partage des ports d'émission=== La présence d'un circuit multiplieur et d'un ''barrel shifter'' pose des problèmes pour le partitionnement. Il est possible d'avoir un port d'émission dédié au multiplieur, et un autre au ''barrel shifter'', qui sont séparés de ceux pour l'ALU entière. Il est alors possible d'émettre une opération entière, une multiplication et un décalage, simultanément. Nous parlerons de '''partitionnement entier''' pour désigner cette possibilité. [[File:Partitionnement superscalaire entier.png|centre|vignette|upright=2|Partitionnement superscalaire entier.]] Le partitionnement entier est cependant très rare, car le gain en performance serait trop faible au regard des couts en circuit. Quelques processeurs historiques l'utilisaient, mais ce n'est plus le cas de nos jours. La raison est que les multiplications et les décalages sont assez rares dans le code, ce qui fait que le port d'émission associés sont sous-utilisés. Et un port d'émission a un cout en circuit assez important. Et c'est sans compter qu'ajouter des ports sur le banc de registres juste pour un multiplieur sous-utilisé n'en vaut pas la peine. L'idéal serait de trouver un moyen de réduire le nombre de ports d'émissions, sans réduire le nombre d'unités de calcul. [[File:Emission multiple des opérations entières, implémentation naive.png|vignette|Émission multiple des opérations entières, implémentation naive]] La solution consiste à '''partager les ports d'émission''', à savoir connecter un port d'émission à plusieurs unités de calcul. L'exemple classique est justement lié aux circuits multiplieur et ''barrel shifters''. L'idée est que le multiplieur et le ''barrel shifter'' sont mis sur le même port d'émission qu'une ALU entière. Prenons par exemple le processeur à double émission entière illustré ci-contre. Un port d'émission est relié à une ALU entière seule, et l'autre port d'émission alimente la seconde ALU entière et le multiplieur. La conséquence est que le processeur peut émettre deux opérations entières, dont une multiplication. Si on avait utilisé un port d'émission dédié au multiplieur, il aurait été possible d'émettre deux opérations entières et une multiplication. On perd donc une voie, mais on gagne en flexibilité et on économise des circuits. Notons que ce partage signifie aussi que le multiplieur partage les ports sur le banc de registre, ce qui fait une double économie. [[File:Emission multiple des opérations entières, implémentation courante.png|centre|vignette|upright=1.5|Émission multiple des opérations entières, implémentation courante]] En général, le ''barrel shifter'' et le multiplieur sont placés sur deux voies d'émission séparés, ce qui permet d'émettre un décalage et une multiplication en même temps. Les mettre sur le même port ne le permettrait pas. {|class="wikitable" |- ! Voie d'émission n°1 !! Voie d'émission n°2 !! Voie d'émission n°3 |- | * ALU entière * Multiplieur | * ALU entière * Barrel shifter | FPU |- | * Additions, soustractions, opérations bit à bit, etc. * Multiplication | * Additions, soustractions, opérations bit à bit, etc. * Décalages et rotations | Opération flottante |} Terminons concernant les multiplieurs avec une dernière subtilité. Pour rappel, les processeurs modernes intégrent en réalité deux multiplieurs différents. Le résultat d'une multiplication est très large et prend deux registres. Par exemple, une multiplication de deux opérandes 64 bits donne un résultat sur 128 bits, ce qui ne tient pas dans un registre, mais en prend deux. L'instruction de multiplication classique ne calcule que les 64 bits de poids faible. mais elle est complétée par d'autres instructions de multiplication qui peuvent faire le calcul complet. Pour résoudre le problème, les processeurs modernes intègrent deux instructions de multiplications : une qui calcule les bits de poids faible du résultat, une autre qui calcule les bits de poids fort. Et ces deux instructions sont associées à deux multiplieurs séparés, aux circuits différents. Le multiplieur qui calcule les bits de poids faible du résultat est appelé le ''low multiplier'', l'autre est appelé le ''high multiplier''. Le second multiplieur est souvent placé sur un second port d'émission, différent du premier multiplieur, partagé avec une ALU. L’avantage de mettre les deux multiplieurs sur deux ports d'émission différents est qu'une multiplication complète peut être réalisée en utilisant les deux multiplieurs en parallèle. Les deux sous-multiplications sont émises en même temps, exécutées en même temps. pas besoin d'exécuter l'une puis la seconde, d'où un gain performance appréciable. Nous venons de voir comment partager un port d'émission entre une ALU et un multiplieur. Mais au-delà de cet exemple, le partage des ports d'émission peut appliquer à n'importe quelle unité. Prenons l'exemple d'un CPU superscalaire avec 4 ALU entières, une FPU, et une unité mémoire. Vu qu'il y a 6 unités, cela fait donc 6 ports d'émission. Cependant, il est rare qu'un bloc de 6 instructions contienne exactement 4 opérations entières, une opération flottante, et un accès mémoire. Beaucoup de ports d'émission seraient sous-utilisés. La solution est de partager des ports d'émission, pour passer à la quadruple émission. Le CPU peut alors répartir 4 instructions sur les ports d'émission adéquats, à chaque cycle. Le CPU a donc 4 ports de décodage et 6 ports d'émission. Une implémentation classique permet n'importe quelle combinaison de 4 instructions compatibles avec les 6 unités. Par exemple, il devient possible d'émettre simultanément 4 additions, la combinaison 2 * INT + FLOAT + MEM, 3 * INT + MEM, et bien d'autres. L'exemple relie une ALU entière, la FPU et l'unité mémoire sur le même port. Le CPU a alors quatre ports d'émission, qui ne sont pas "identiques". Trois d'entre eux sont reliés à une ALU entière chacun, rien d'autre. Le quatrième est lui relié à une ALU entière, la FPU et l'unité mémoire. On économise alors deux ports d'émission, mais cela entraine l'apparition de contraintes d’appariement. Le CPU peut émettre 3 opérations entières + n'importe quelle autre opération. Mais les autres combinaisons sont interdites. Le CPU peut émettre 6 opérations entières simultanément, grâce à 6 ALU entières. Les accès mémoire ou opérations flottantes ne viennent pas en plus, mais en remplacement des opérations entières. Regrouper plusieurs ALU sur un même port d'émission est donc à l'origine de dépendances structurelles, de nouvelles contraintes d’appariement. Dans certaines situations de '''''port contention''''', on a assez d'ALU pour exécuter N micro-opérations, mais la répartition des ALUs sur les ports l'empêche. Impossible d'émettre deux micro-opérations sur deux ALU si elles sont sur le même port d'émission. On peut réduire les cas de ''port contention'' en répartissant correctement les ALU sur les ports d'émission, mais sans jamais les supprimer complétement. Un exemple est celui du PowerPC 604. Il implémentait la quadruple émission, alors qu'il avait 5 unités de calcul. Mais deux unités partageaient un même port d'émission. Dans le détail, il avait deux ALU entières, un circuit multiplieur/diviseur, une FPU, une unité mémoire. La FPU et le multiplieur étaient sur le même port d'émission. En conséquence, le CPU pouvait émettre seulement les combinaisons INT + INT + MEM + (MUL/FLOAT). : Il est intéressant de voir l'exemple d'un processeur superscalaire parfait, sans contraintes d'appariement, à N voies. Pour cela, on part d'un processeur non-superscalaire, avec M unités de calcul. Un tel processeur peut s'implémenter avec N ports d'émission, chacun relié à M unités de calcul possibles, ce qui fait que les M unités de calcul sont dupliquées en N exemplaires. Si on prend par exemple un CPU non-superscalaire avec une ALU, une FPU, une unité mémoire et une unité de branchement, un port d'émission sera relié à une ALU, une FPU, une unité mémoire et une unité de branchement. ===La duplication des autres unités fonctionnelles=== Dupliquer les ALU entière est une première étape, mais il est aussi possible de dupliquer les autres unités fonctionnelles. Par exemple, il est possible de dupliquer l'unité mémoire ou l'unité de branchement. Reste à voir quelles unités dupliquer, et pourquoi. Précisons que dans ce qui va suivre, nous allons parler de la duplication des unités en général, pas seulement des unités mémoire/branchement. Nous allons continuer de parler de la duplication des ALU entières dans ce qui suit, mais de manière plus générale. Pour un processeur à N voies, il est théoriquement possible de dupliquer toutes les unités en N exemplaires. Mais ce n'est jamais fait en pratique, car le cout en circuits serait trop important et le gain en performance trop faible. Mieux vaut dupliquer certaines unités bien précises, quitte à avoir des contraintes d'appariement. Et à ce petit jeu, toutes les duplications ne se valent pas, certaines sont plus rentables en matière de performance, le cout en circuit n'est pas le même selon l'unité, etc. La rentabilité en performance dépend surtout des contraintes d'appariement. Les contraintes d'appariement entrainent une baisse de performance significatives si elles interdisent des paires d'instructions fréquentes. Aussi, les opérations très fréquentes, souvent appairées, gagnent à dupliquer l'unité associée. Et au contraire, les unités rarement utilisées ne doivent pas être dupliquées. Il se trouve que les unités les plus utilisées sont les ALU entières, suivies par les unités mémoire et l'unité de branchement. Le cout en circuit n'est aussi pas le même. Dupliquer les ALU entière est trivial, car elles ont un budget en transistors assez faible. Les circuits multiplieurs, diviseurs, et les ''barrel shifter'' ont eux un cout en transistor plus élevés. Si on devait faire un classement, on aurait : ALU entière < ''barrel shifter'' < multiplieur. Pour les unités mémoire, le cout en transistor est là aussi conséquent. Le résultat final est que dupliquer les ALU entières est privilégié sur le reste, comme l'a vu dans la section précédente. Les unités mémoire arrivent en seconde place, suivie par les multiplieurs/''barrel shifter'' à la troisième place, et les unités de branchement à la quatrième place. Les CPU superscalaires larges ont donc tendance à multiplier les unités mémoire en second. Les multiplieurs et ''barrel shifters'' sont eux aussi dupliqués sur les CPU superscalaires larges, mais cela vient souvent après avoir dupliqué les unités mémoire. La raison est que les accès mémoire sont critiques pour la performance des CPU à exécution dans le désordre, pas les multiplications. Pour les unités de branchement, une subtilité complique le fait d'en installer plusieurs. Que faire quand deux branchements sont pris ? La solution la plus simple est de ne pas se trouver dans cette situation : on n'utilise qu'une seule unité de branchement et on n’exécute qu'un seul branchement par cycle. La majorité des processeurs superscalaires étroits font ainsi. Les processeurs superscalaires larges ont cependant deux unités de branchements, mais ils n'acceptent qu'un seul branchement pris à la fois. Si les deux branchements pris sont exécutés en même temps, le processeur n’exécute que le plus récent, dans l'ordre du programme. ===Les CPU superscalaires mélangent les trois techniques=== Les CPU superscalaires utilisent toutes les techniques à la fois : partitionnement, duplication de l'ALU entière, duplication des autres unités fonctionnelles. Chaque processeur utilise ces trois stratégies à sa sauce, en fonction de son budget en transistor. Les quatre techniques ont cependant un cout en circuit différent, et donnent des gains de performances eux aussi forts différents. * Le '''partitionnement superscalaire''' a un cout en circuit modéré, car on n'a pas besoin de dupliquer d'ALU. * La '''duplication des ALU entières''' est la technique la plus importante : elle a un cout en circuit modéré, et donne des gains en performance impressionnants. * La '''duplication des autres unités''' a un cout en circuit variable, pour des gains en performance eux aussi variables. * Le '''partage des ports d'émission''' réduit le cout en circuit du CPU, pour des pertes de performances mineures si bien fait. L'usage du partitionnement seul, sans duplication, était surtout le fait des processeurs commercialisés entre les années 1989 et 1993. Le partage des ports d'émission a lui aussi mis un peu de temps pour s'imposer. Globalement, les processeurs superscalaires ont évolués progressivement, pour se rapprocher d'une sorte de standard. Mais pour comprendre ce qu'est ce standard, et en quoi les CPU historiques s'en sont progressivement rapprochés, il faut étudier l'histoire des CPU superscalaires. L'histoire des CPU superscalaires a commencé dès 1960, mais est resté un projet de recherche pendant plusieurs décennies. De nombreux designs ont été conçus, mais abandonnés avant la production, comme l'ACS-1 d'IBM. Les années 1980 ont vu l'arrivée de prototypes de processeurs VLIW, mais qui n'étaient pas superscalaires. Par exemple, l'Apollo DN10000 et l'Intel i860 pouvaient émettre deux instructions à la fois, sous conditions, mais demandaient que le compilateur fasse une bonne partie du travail. Les premiers CPU superscalaires commercialisés sont sortis en 1989. Deux CPUs superscalaires sont sortis cette année-là : le RS/6000 d'IBM et l'i960CA d'Intel. Puis, la compétition s'est aussi lancée dans la bataille. Les CPU commercialisés avant l'année 1993 étaient à double émission, à l'exception du SuperSPARC qui utilisait la triple émission. Les modèles après 1993 hésitaient entre double et quadruple émission. Dans le tableau ci-dessous, les processeurs quadruple émission sont en bleu, les triple émission sont en rouge, les autres ne sont pas en couleur. {|class="wikitable" |- ! !! IBM !! HP PA-RISC !! SPARC !! Intel!! Alpha !! Autres |- ! 1989 | RS/6000 || || || i960CA || || |- ! 1990 | || || || || || |- ! 1991 | || || || || || Motorola 88110 |- ! 1992 | RSC || PA 7100 || class="f_rouge | SuperSPARC || || 21064 || |- ! 1993 | PPC 601 || || HyperSPARC || Pentium || || |- ! 1994 | class="f_bleu | POWER 2 || PA 7200 || || || class="f_bleu | 21164 || |- ! 1995 | 603/604 || class="f_bleu | PA 8000 || class="f_bleu | UltraSPARC 1 || Microarchitecture P6 (+ concurrence AMD) || || class="f_bleu | MIPS R1000 |- ! 1996 | class="f_bleu | 620 || || || || class="f_bleu | 21264 || |- ! ... || ... || ... || ... || ... || ... || ... |} Les premiers CPU à double émission sont assez représentatifs des CPU à double émission modernes. Il faut dire que se limiter à deux voies ne permet pas de faire beaucoup de choses. Voici le tableau chronologique disant quel CPU utilisait quelle technique. * Les CPU en vert utilisaient la double émission entière-flottante. * Les CPU en rouge utilisaient la double émission entière "pure". * Les CPU en jaune utilisaient un ''partitionnement complet'' entre ALU, FPU et unité mémoire. * Les CPU sans couleur utilisaient un grand nombre d'unités, avec beaucoup de ports d'émission. * Les CPU barrés utilisent la triple ou quadruple émission et seront vu dans la section suivante. {|class="wikitable" |- ! !! IBM !! HP PA-RISC !! SPARC !! Intel!! Alpha !! Autres |- ! 1989 | class="f_vert | RS/6000 || || || class="f_rouge | i960CA || || |- ! 1990 | || || || || || |- ! 1991 | || || || || || Motorola 88110 |- ! 1992 | class="f_vert | RSC || class="f_vert | PA 7100 || <s>SuperSPARC</s> || || class="f_jaune | 21064 || |- ! 1993 | class="f_vert | PPC 601 || || class="f_jaune | HyperSPARC || class="f_rouge | Pentium || || |- ! 1994 | <s>POWER 2</s> || PA 7200 || || || <s>21164</s> || |} C'est en 1994, que la quadruple émission est arrivée et que les CPU ont essayé divers implémentations. Il y avait alors trois stratégies pour la double/triple/quadruple émission, qui partageaient des problèmes similaires. La première implémentation dupliquait les ALUs et les FPUs, ce qui permettait d'émettre deux opérations flottantes avec deux opérations entières. Le POWER 2 dupliquait ses FPUs à la perfection, alors que le 21264 séparait l'additionneur et le multiplieur flottant. Les accès mémoire étaient traités comme des opérations entières et le processeur pouvait souvent en émettre deux à la fois. Mais une telle organisation n'est plus utilisée de nos jours, car, sans instructions flottantes à exécuter, elle est équivalente à de la double émission. La seconde implémentation utilisait deux ALU entières (dont un multiplieur), une unité mémoire et une FPU. Cette organisation est intéressante, mais encore trop stricte pour donner de bons résultats, les quadruplets avec exactement deux opérations entières, un accès mémoire et une opération flottante étant trop rares. L'usage de ces 4 unités en double ou triple émission a été utilisé sur le PA 7200 et le SuperSPARC. Malheureusement, en plus de problèmes au niveau de son cache, le SuperSPARC avait de nombreuses contraintes d’appariement, car le banc de registre n'avait pas assez de ports pour alimenter certaines combinaisons d'instructions. De plus, s'il émettait une multiplication, il ne pouvait pas émettre de seconde µop. Enfin, une troisième implémentation utilisait un grand nombre d'unités fort différentes, bien plus que quatre, avec au minimum deux ALU entières. Prenons l'exemple de l'UltraSPARC, qui avait : deux ALU entières, une unité mémoire, une unité de branchement, un additionneur flottant, un multiplieur flottant, un diviseur flottant (aussi utilisé pour le calcul des racines carrées), et 2 unités graphiques pour les calculs sur des pixels. En tout, cela fait 9 unités différentes, pour de la quadruple émission. Dans le même genre, les processeurs MIPS R8000 et R10000 avaient une implémentation plus moderne, dans le sens où toutes les unités étaient dupliquées. Le CPU avait deux ALU, deux FPU et deux unités mémoire. Il pouvait donc émettre quatre instructions à la fois, tant que le paquet collait avec ces six unités. Moitié opérations entières, moitié opérations mémoire, avec de quoi remplacer les opérations entières par des opérations flottantes. Le PA 8000, lui, dupliquait toutes ses unités en deux exemplaires, ce qui n'est pas l'idéal, aucun processeur moderne ne fait cela aujourd'hui. Le tout est résumé dans le tableau ci-dessous, avec : * en vert les CPU utilisant la première stratégie ; * en rouge les CPU utilisant la seconde stratégie ; * en jaune les CPU utilisant la troisième stratégie. {|class="wikitable" |+ Processeurs quadruple émission historiques |- ! Année !! Processeur !! Unités |- ! 1991 | class="f_jaune | Motorola 88110 || class="f_jaune | 2 ALU + MUL + DIV + BIT + MEM + FADD + 2 unités graphiques |- |- ! rowspan="2" | 1994 | class="f_vert | POWER 2 || class="f_vert | 2 ALU/MEM + 2 FPU (+ 2 Branchements via ''branch folding'') |- | class="f_rouge | 21164 || class="f_rouge | 2 ALU + FPU + MEM |- ! rowspan="3" | 1995 | PA 8000 || 2 ALU + 2 ''barrel shifters'' + 2 MEM + 2 FPU (FMA) + 2 FPU (DIV et SQRT) + 2 SIMD |- | class="f_jaune | UltraSPARC 1 || class="f_jaune | 2 ALU + MEM + BRANCH + FADD + FMULFDIV + 2 unités graphiques |- | MIPS R8000 et R10000 || 2 ALU + 2 FPU + 2 MEM |- ! rowspan="2" | 1996 | class="f_rouge | 620 || class="f_rouge | 2 ALU + FPU + MEM |- | class="f_vert | 21264 || class="f_vert | 2 ALU/MEM + 2 FPU (FADD + FMUL) |} Malheureusement, ces CPUs historiques n'avaient ni assez d'unités de calcul entières, ni d'unités mémoire, pour remplir la quadruple émission. Environ la moitié des instructions d'un programme correspond à des instructions entières. Pour en profiter, un processeur à N voies doit disposer d'au minimum N/2 ALU entières, l'idéal étant d'aller au-delà. Les CPU superscalaires historiques avaient 2 ALU pour de la quadruple émission, ce qui était très limite. En comparaison, les CPU superscalaires modernes mettent le paquet niveau ALU entière. La plupart des CPU x86 modernes descendent rarement sous les 2/3, la plupart remplissent presque la totalité de la largeur du CPU. Pour donner un exemple, la microarchitecture Golden Cove d'Intel est un processeur à 6 voies, avec 5 ALU entières. Pour être précis, un programme informatique exécute environ 40% de son code dans des instructions arithmétiques, un autre 40% dans les accès mémoire, et un le reste pour... le reste. La conséquence est que les processeurs modernes dupliquent leurs unités mémoire. Par exemple, la microarchitecture ''Golden Cove'' d'Intel dispose de trois unités mémoire : deux spécialisées dans les écritures, trois dans les lectures. La microarchitecture ''Gracemont'' utilise la pentuple émission et peut émettre 4 µops entières et 4 µops mémoire. Notez que le ratio est équilibré entre opérations entières et mémoire, avec soit égalité, soit un avantage pour les ALU entières. Une autre régularité est que la largeur totale du processeur peut être occupée par des opérations entières/mémoire. Pour le dire autrement, sur un processeur quadruple émission, il pourra émettre un mix de 4 instructions entière/mémoire, avec zéro opération flottante. Idem avec des processeurs triples ou pentuple émission, voire plus. Si le processeur émet une opération flottante, elle remplace une opération entière. Prenons l'exemple des processeurs AMD K6, sortis en 1997, juste avant les AMD Athlon. Ils avaient 10 unités de calcul, 6 ports d'émission, 4 ports de décodage. Voici exactement comment étaient répartie les unités de calcul sur les ports d'émission. C'était des processeurs quadruple émission, ce qui fait que la moitié de la largeur du processeur sert pour des opérations entières, et l'autre moitié pour les accès mémoire. {|class="wikitable" |- ! Port d'émission n°1 !! Port d'émission n°2 !! Port d'émission n°3 !! Port d'émission n°4 !! Port d'émission n°5 !! Port d'émission n°6 ! |- | ALU entière || ALU entière || FPU || Unité de branchement || Unité LOAD || Unité STORE |- | || Multiplieur || || || || Unité de calcul d'adresse (instruction LEA) |- | || ''Barrel shifter'' || || || || Unité pour les instructions PUSH |} Les microarchitectures K7, K8 et K10, utilisées sur les anciens CPU AMD Athlon, sont un exemple moins représentatif. Ces microarchitectures utilisent le partage des ports d'émission au maximum. C'était des microarchitectures à triple émission, avec six ports d’émission. Il y avait trois ports d'émission pour les opérations flottantes, et trois ports d'émission pour les micro-opérations entières/mémoire. Il y avait trois ALU entières et trois unités mémoire, chaque ALU partageait un port d'émission avec une unité mémoire. Elle pouvait donc émettre soit trois opérations entières, soit trois µops mémoire, soit un mix des deux. En plus des mix avec les opérations flottantes et branchements. {|class="wikitable" |- ! Port d'émission n°1 !! Port d'émission n°2 !! Port d'émission n°3 !! Port d'émission n°4 !! Port d'émission n°5 !! Port d'émission n°6 ! |- | ALU entière || ALU entière || ALU entière || FADD || FMUL || FPU (autres opérations) |- | Multiplieur || || || || || |- | LOAD/STORE || LOAD/STORE || LOAD/STORE || || || |} Les CPU superscalaires larges dupliquent les multiplieurs et/ou les ''barrel shifters'', et même les unités de branchement. La raison est que quand la largeur du CPU augmente, le processeur traite des paquets d'instructions de plus en plus gros. Par exemple, pour un CPU à 10 voies, cela veut dire émettre 10 instructions en même temps. Il est alors plus fréquent d'avoir deux multiplications, deux décalages, deux accès mémoire, deux branchements. Par exemple, la moyenne est d'une multiplication tous les 5 instructions. Les CPU superscalaires à 10 voies ont donc tendance à avoir deux multiplications par paquet d'instruction, en moyenne. Avoir deux multiplieurs est alors un gain en performance clair. Par exemple, la microarchitecture ''Golden Cove'' a deux ''barrel shifters''. C'est une architecture à 6 voies. {|class="wikitable" |- ! Port d'émission n°1 !! Port d'émission n°2 !! Port d'émission n°3 !! Port d'émission n°4 !! Port d'émission n°5 !! Port d'émission n°6 !! Port d'émission n°7 !! Port d'émission n°8 !! Port d'émission n°9 !! Port d'émission n°10 |- | ALU entière || ALU entière || ALU entière || ALU entière || ALU entière || LOAD || LOAD || LOAD || STORE || STORE |- | ''Barrel shifter'' || Multiplieur || Multiplieur || ''Barrel shifter'' || || || || || || |- | Branchements || Diviseur || || Branchements || || || || || || |} ==Les µops mémoire sur les processeurs superscalaires== Plus haut, nous avons volontairement passé sous silence les accès mémoire. La raison à cela est que leur support sur les CPU superscalaire peut se faire de plusieurs manières différentes, qu'il vaut mieux expliquer dans une section dédiée. Les différentes implémentations sont décrites dans la liste suivante, nous allons les voir une par une. * Avec la première méthode, les accès mémoire sont exécutés par le pipeline pour les opérations entières. * Avec la seconde méthode, les accès mémoire ont un pipeline dédié ; c'est l'''émission parallèle des accès mémoire''. * Avec la troisième méthode, il est possible d'émettre plusieurs accès mémoire simultanément : c'est l'''émission multiple des accès mémoire''. Voyons ces trois cas dans le détail. Nous verrons notamment les différentes formes d'émission multiple des accès mémoire. ===Les accès mémoire traités dans le pipeline entier=== Dans le cas le plus simple, les accès mémoire sont traités comme des opérations entières un peu spéciales. L'unité mémoire est sur le même port d'émission que l'ALU entière, ce qui fait que les accès mémoire remplacent des opérations entières. Faire ainsi permet d'utiliser une ALU entière pour les calculs d'adresse, pas besoin de rajouter une unité de calcul d'adresse séparée. Typiquement, un processeur de ce type place l'unité mémoire après l'unité de calcul. Les opérations entières n'utilisent que l'ALU entière, mais pas l'unité mémoire. Les accès mémoire exécutent un calcul d'adresse dans l'ALU entière, puis l'adresse calculée est envoyée à l'unité mémoire. Le tout est illustré ci-dessous, dans le cas d'un processeur historique à double émission entière-flottante. [[File:Processeur non-superscalaire basique 01.png|centre|vignette|upright=1.5|Processeur non-superscalaire basique]] Un exemple de CPU double émission de ce type est celui du Power PC 440, un CPU destiné à l'embarqué. Vu qu'il était destiné à l'embarqué, il n'avait pas de FPU, il n'avait pas besoin de manipuler de nombres flottants. Il n'a donc que des ALU entières, un multiplieur et une unité mémoire. Il dispose de deux ports d'émission. Le premier est connecté à une ALU entière et un circuit multiplieur, le second est relié à l'unité mémoire et une seconde ALU entière. Une organisation simple, mais très efficace ! [[File:PowerPC 440.png|centre|vignette|upright=2|Microarchitecture du PowerPC 440.]] L'implémentation économise une unité de calcul d'adresse, mais n'a pas de cout en performance significatif. Les accès mémoire étant très lents, émettre une µop entière en parallèle d'un accès mémoire ne sert pas à grand-chose. On peut émettre cette µop entière un cycle plus tard, elle sera terminée avant même que l'accès mémoire soit terminé, même si l'accès mémoire se fait dans le cache L1 ou L2. Pour comprendre pourquoi, faisons quelques calculs. Un accès mémoire prend deux-trois cycles quand il tombe dans le cache L1. Et on doit attendre qu'il soit terminé pour en émettre un nouveau. Combien d'instructions arithmétiques peut-on lancer pendant ce temps, sur un CPU triple émission ? Au premier cycle, on peut en émettre 2 (l'instruction mémoire prend une place, donc 3-1), puis 3 au second cycle. Ce qui fait 5 instructions arithmétiques au total. Or, il se trouve qu'il y a une instruction d'accès mémoire pour 5 instructions arithmétiques, environ. Par contre, ce compromis change quand on passe à la quadruple émission, voire au-delà. Dans ce cas, il devient intéressant de pouvoir émettre une nouvelle instruction mémoire à chaque cycle. Ce qui nous amène à la section suivante... ===L'émission parallèle des accès mémoire=== A partir de la quadruple émission, la tendance a été de séparer l'unité mémoire des ALU entières. Cela permet d'émettre des µops mémoire en même temps que des µops entières et/ou flottantes., ce qui porte le nom d''''émission parallèle des µops mémoire''', ou encore ''émission mémoire parallèle''. Par exemple, un processeur quadruple émission peut émettre en même temps deux opérations entières, une opération flottante et un accès mémoire. L'accès mémoire vient en plus des opérations entières, il n'est pas possible de remplacer l'accès mémoire par une opération entière. La technique ne permet pas de faire les calculs d'adresse dans l'ALU entière. Il faut donc utiliser une unité de calcul d'adresse séparée. Elle est intégrée dans l'unité mémoire, qui fait l'interface entre le cache et le banc de registres. Le cout en circuits est très faible, car les unités de calcul d'adresse n'utilisent guère plus qu'un additionneur et un circuit de décalage très simple. L'émission mémoire parallèle est plus facile à implémenter sur les CPU RISC, qui ont des instructions mémoire séparées du reste. Les CPU CISC ne sont pas dans ce cas, ce qui fait que séparer l'unité mémoire du pipeline entier est compliqué. Les CPU superscalaires historiques étaient pour moité des CPU RISC et pour moitié des CPU CISC, ce qui fait qu'ils n'utilisaient pas ou peu l'émission mémoire parallèle. Les premiers processeurs superscalaires se contenaient de l'émission parallèle mémoire, ils ne pouvaient émettre qu'un seul accès mémoire à la fois, l'unité mémoire n'était pas dupliquée. Et ce n'est pas tant un problème que ça, du moins sur les processeurs à double ou triple émission. En effet, il est rare que l'unité mémoire doive faire deux accès simultanés. Notons que le processeur peut exécuter une instruction mémoire en parallèle d'un calcul ou d'un branchement, seuls les accès mémoire simultanés sont impossibles. ===L'émission multiple des accès mémoire avec une LSQ=== Les processeurs superscalaires larges travaillent sur des paquets de 8 à 10 instructions, il est plus fréquent d'avoir plusieurs accès mémoire par paquet. Dans ces conditions, il est utile d'avoir une '''émission multiple des accès mémoire''', à savoir d'émettre plusieurs micro-opérations mémoire en même temps. Les processeurs superscalaires modernes sont capables d'émettre plusieurs lectures/écritures simultanément. Par exemple, ils peuvent émettre une lecture en même temps qu'une écriture, ou plusieurs lectures, ou plusieurs écritures. Il faut noter que selon le processeur, il peut y avoir des restrictions quant aux accès mémoire émis en même temps. Par exemple, certains processeurs peuvent émettre une lecture avec une écriture en même temps, mais pas deux lectures ni deux écritures. Ou encore, ils peuvent émettre deux lectures, une lecture et une écriture, mais pas deux écritures en même temps. Dans la majorité des cas, les processeurs ne permettent pas d'émettre deux écritures en même temps, alors qu'ils supportent plusieurs lectures. Il faut dire que les lectures sont plus fréquentes que les écritures. Les processeurs qui autorisent toutes les combinaisons de lecture/écriture possibles, sont rares. L'émission multiple des accès mémoire s'implémente dans l'unité mémoire. Pour rappel, l'unité mémoire s'interpose entre le cache L1 et le reste du pipeline. Dans le cas le plus simple, elle incorpore une ''load/store queue'' et des unités de calcul d'adresse. L'émission multiple des accès mémoire demande de rendre la ''Load-store queue'' multi-ports, afin de gérer plusieurs micro-opérations mémoire simultanées. Il faut aussi dupliquer les unités de calcul d'adresse reliées à la LSQ, chaque port d'émission mémoire devant avoir sa propre unité de calcul d'adresse. : Dans ce qui suit, nous parlerons d'AGU (''Adress Generation Unit'') pour désigner les unités de calcul d'adresse, et de LSQ pour designer la ''Load-store queue''. [[File:Processeur non-superscalaire basique 02.png|vignette|upright=1|Processeur non-superscalaire basique]] Dupliquer les ports de la LSQ et les AGU est nécessaire. Mais qu'en est-il du cache ? La réponse varie suivant le processeur. Il y a deux grandes méthodes pour implémenter l'émission multiple des accès mémoire. La première méthode ajoute des ports de lecture/écriture au cache de données, pour faire des lectures/écritures simultanées. Il faut alors dupliquer des unités de calcul, rajouter les ports sur le cache, mais aussi rajouter des ports sur la ''load/store queue'', pour qu'elle échange des données/commandes mémoire avec le cache. Le cout en circuits est alors conséquent La seconde duplique les unités de calcul, mais pas les ports d'accès au cache. Les accès mémoire sont alors accumulés dans la ''load/store queue'', qui sont ensuite traités un par un par le cache. Un exemple est celui des processeurs AMD de micro-architecture K7 K8, à savoir les anciens AMD Athlon et AMD Athlon 64, qui pouvaient calculer trois adresses simultanément, mais ne pouvaient faire qu'un seul accès au cache par cycle. Le cout en circuit est modéré : les unités de calcul coutent très peu, les ports de la ''load/store queue'' coutent déjà un peu plus. Quelques processeurs utilisaient des solutions intermédiaires. Un processeur utilisant cette technique est, par exemple, capable d'émettre quatre µops mémoire en même temps, mais avec seulement deux ports sur le cache. Un exemple classique étant les Pentium 1 et 2 d'Intel, dont nous parlerons dans le chapitre suivant. ===L'émission séparée des LOAD et STORE=== De rares processeurs ont des ports d'émission qui peuvent faire indifféremment lecture comme écritures. Mais les processeurs modernes préfèrent séparer ports d'émission pour les lectures et les écritures. Un exemple est celui des processeurs Intel de micro-architecture Nehalem, qui avaient un port de lecture et un port d'écriture tous deux reliés à la ''Load-store queue'', chacun avec leur propre unité de calcul d'adresse. Comme autre exemple, les processeurs skylake ont une LSQ avec deux ports de lecture et un port d'écriture, ce qui permet d'émettre deux lectures en même temps qu'une écriture. Dans cette section, nous allons étudier le cas avec des ports séparés pour les lectures et écritures. En général, les processeurs ont un peu plus de ports de lectures que d'écritures. Une raison est qu'un programme a, en moyenne, un tout petit peu plus de lectures que d'écritures. Mais la différence n'est pas énorme, c'est un léger déséquilibre. Une seconde raison est que l'exécution dans le désordre marche bien mieux quand les lectures ont lieu le plus tôt possible. Donc mieux vaut privilégier les lectures à l'émission, pour qu'elles se fassent un peu en avance. En pratique, la différence n'est pas très marquée. Il est courant d'avoir un port de lecture et un d'écriture, les CPU superscalaires très larges ont souvent deux ports de lecture et deux d'écriture. A la rigueur, quelques CPU ont trois ports de lecture et deux d'écriture. Le cas le plus simple est celui où on peut émettre une lecture et une écriture en même temps. Il s'implémente facilement si la LSQ est en réalité une simple ''Store queue'', à savoir qu'elle met en avance les écritures uniquement. Pour rappel, les écritures sont mises en attente dans la ''Store queue'', mais les lectures sont exécutées immédiatement. Une fois l'adresse à lire connue, la lecture consulte la ''Store queue'' pour détecter les dépendances de données, puis s'exécute. La donnée à lire est lue soit depuis la ''Store queue'', soit depuis le cache. [[File:Emission LOAD - Store séparée.png|vignette|upright=1|Émission LOAD - Store séparée]] L'implémentation de l'émission multiple est alors très simple. La ''Store queue'' a déjà deux ports, avec un pour les lectures et un autre pour les écritures. Idem pour le cache, qui a naturellement un port de lecture et un d'écriture. Émettre une lecture et une écriture simultanément ne demande donc pas de modification digne de ce nom. La ''Store queue'' doit juste supporter une lecture et une écriture simultanée. Ajouter l'émission d'une seconde lecture n'est pas compliquée : il faut juste rajouter un second port de lecture sur le cache et la ''Store queue''. Pour rappel, l'unité mémoire est précédée par une structure qui met en attente les micro-opérations mémoire avant leur émission finale. La structure en question varie suivant l'implémentation, mais un cas particulier se marie bien avec l'émission multiple des µops mémoire. Il s'agit du cas avec une file de µops séparée pour les lectures et une autre pour les écritures, appelées respectivement la ''file de µops LOAD'' et la ''file de µops STORE''. Il est alors possible d'émettre une lecture et une écriture lors du même cycle d'horloge. Le port de lecture alimente une unité de calcul d'adresse dédiée, directement reliée au cache. Le port d'écriture du cache alimente une unité de calcul, qui est suivie par une file d'écriture, elle-même reliée au cache. Les processeurs AMD de micro-architecture K6 utilisaient cette technique. [[File:Double émission avec le Load Ordering, Store Ordering.jpg|centre|vignette|upright=2.5|Double émission avec le Load Ordering, Store Ordering]] ==Les CPU superscalaire à exécution dans le désordre== La superscalarité modifie aussi les circuits dédiés à l'exécution dans le désordre. Elle modifie les unités de renommage de registre, le ROB et les autres structures liées à l'exécution dans le désordre, au sens large. Aucune structure n'est épargnée. Elles ont tous des prots de lecture/écriture en plus, afin d'encaisser l'émission, le ''commit'' ou le renommage simultané de plusieurs µops. Par exemple, le ROB doit être modifié pour émettre et terminer plusieurs instructions en même temps, en ajoutant des ports de lecture/écriture. Pour un CPU superscalaire à 8 voies, on se dit que le ROB peut retirer 8 µops par cycle maximum. Mais certains processeurs récents ont un ROB qui peut retirer le double ! Un exemple est celui des CPU de micro-architecture Skymont, qui peuvent émettre 8 µops par cycle, mais en retirer 16. Quelques CPU de marque AMD étaient aussi dans ce cas. L'avantage est que cela permet de réduire la taille du ROB, du banc de registre et de quelques autres structures matérielles liées à l'exécution dans le désordre. Le gain sur-compense le cout en transistor nécessaire pour retirer 16 µops par cycle. Dans cette section, nous allons voir comment les étages du pipeline dédiés à l'exécution dans le désordre sont modifiées sur un CPU superscalaire. ===L'exemple du PA-RISC PA 8000=== Avant de commencer, nous allons voir un processeur superscalaire assez simple, le PA 8000, de HP, qui implémente le jeu d'instruction PA-RISC. Bien que très ancien, il implémentait l'exécution dans le désordre et le renommage de registre. Le peu d'informations que nous avons sur ce processeurs proviennent des documents "THE HP PA-8000 RISC CPU" par Ashok Kumar, et l'article de microprocessor report "PA-8000 Combines Complexity and Speed". Ils ne donnent malheureusement pas énormémment d'informations et je devrais être amené à faire quelques suppositions dans ce qui suit. Avant de commencer, parlons de détails sans lien avec la superscalarité. Ce processeur, comme beaucoup de processeurs PA-RISC, n'intégrait pas de cache de niveau L2 dans le processeur, qui était déporté en-dehors du CPU, sur la carte mère. Le processeur préférait utiliser ses transistors pour avoir un cache L1 assez large, quitte à ce qu'il soit plus lent. La lenteur du cache était prévue, le processeur compensait celle-ci en utilisant l'exécution dans le désordre, bien que ce ne soit pas parfait. Les CPU PA-RISC avant le PA 8000 utilisaient un pipeline à vagues ''wave pipeline'', ce qui était assez peu commun, mais le PA 8000 repasse à un pipeline synchrone classique. Passons maintenant à la superscalarité. Le PA 8000 est un processeur quadruple émission, qui peut émettre, à chaque cycle, deux opérations et deux accès mémoire. Le renommage de registre utilise des registres de renommage séparés des registres architecturaux, comme c'était la mode à l'époque. Le budget en transistor faisait que c'était soit ça, soit le renommage dans le ROB, faute de mieux. Le processeur utilise une implémentation ''Read After Issue'', ce qui veut dire que les opérandes des instructions sont lues après l'émission, juste avant l'exécution. Le processeur peut aussi ''commit'' deux opérations et deux accès mémoire par cycle, ce qui revient à transférer les résultats des registres de renommage vers les registres architecturaux. L'exécution dans le désordre est prise en charge par une structure matérielle unique, qui ressemble à une fusion entre un ROB et un ''scheduler''. Et c'est là que je vais devoir faire des suppositions. Le document "THE HP PA-8000 RISC CPU" nomme cette structure : l''''''Instruction Reorder Buffer'''''. Il utilise pas moins de 850 000 transistors, et prend 20% de la taille du ''die''. L'article "THE HP PA-8000 RISC CPU" laisse fortement sous-entendre qu'il s'agit une structure unique, faite d'un seul tenant, mais l'article de microprocessor report dit le contraire par moment. Il est décrit comme un ''scheduler'', à savoir qu'il détecte les dépendances entre instruction et les émet. Il gère aussi la détection des mauvaises prédictions de branchement et peut annuler les instructions chargées à tort, en les retirant de le ''scheduler''. Il est aussi précisé que les instructions quittent cet ''Instruction Reorder Buffer'' dans l'ordre du programme. Elles ne peuvent en sortir que quand elles ont été exécutées et qu'elles n'ont causé aucune exception. Ce qui fait qu'il se comporte comme un ROB de ce point de vue là. Difficile de dire si l'''Instruction Reorder Buffer'' est un réel mélange entre un ROB et un ''scheduler'', ou s’il est réellement conçu avec deux structures séparées. Dans ce qui suit, je pars du principe que les deux structures sont séparées. Le processeur contient deux ''schedulers'' : une réservée aux µops mémoire (LOAD et STORE), l'autre pour les opérations entières/flottantes. Elles ont chacune 28 entrées, ce qui permet de mémoriser 56 µops au maximum. Les deux peuvent recevoir 4 µops par cycle de la part des décodeurs. Là encore, précisons que les choses ne sont pas claires pour ce qui est de la séparation. L'article de Microprocessor report dit que les deux sont physiquement séparées, et que cette séparation physique permet de simplifications (les opérations mémorisent des noms de registres plus court que les adresses demandées par les µops LOAD/STORE). Mais l'autre document cité laisse penser que l''''Instruction Reorder Buffer'' est une structure unique. À chaque cycle, le processeur peut émettre deux instructions de calcul et deux instructions mémoire. Les deux ''schedulers'' ont pour cela chacune deux ports d'émission. Les deux ports d'émission pour les µops mémoire sont identiques, et le cache L1 est un cache double port, ce qui permet d'exécuter deux lectures/écritures par cycle. Pour ce qui est des µops entières/flottantes, le processeur a dupliqué toutes ses unités de calcul : il a deux ALU entières, deux ''barrel shifters'', deux FPU de type FMAC, et deux unités de division flottante. Vraisemblablement, il y a deux ports d'émission, chacun étant connecté à une unité de chaque type. : S'il n'utilisait pas l'exécution dans le désordre, ce processeur aurait donc quatre pipelines : deux pipelines entiers identiques et deux pipelines mémoire. Et il aurait une superscalarité presque parfaite s'il était un CPU à double émission ! À chaque cycle, le ''scheduler'' émet les deux µops les plus anciennes qui sont prêtes à être exécutées. La documentation dit que le ''scheduler'' émet "la plus vielle instruction paire, et la plus vielle instruction impaire", ce qui sous-entend que le ''scheduler'' est segmentée en deux. C'est précisément la logique d'éveil et d'émission qui est segmentée, une partie gérant la moité de le ''scheduler'', une seconde logique d'éveil/''schedule'' gérant le reste. le ''scheduler''s n'implémente donc pas une vraie double émission, elle est partitionnée pour permettre d'émettre deux µops en même temps. L'avantage est une économie de transistors manifeste. Un inconvénient est que si les µops prêtes sont toutes dans la même moitié, une seule µops sera émise par cycle. Mais avec 2*14 entrées, le cas est assez rare pour que l'économie de transistors en vaille la peine. [[File:PA 8000 - microarchitecture.png|centre|vignette|upright=2|PA 8000 - microarchitecture]] ===La superscalarité avec une file/fenêtre d'instruction centralisé=== Plus haut, nous avons montré qu'un processeur pouvait avoir plus de ports d'émission que de ports de décodage. On dit aussi que sa ''largeur de décodage'' était supérieure à sa ''largeur d'émission''. La '''largeur de décodage''' est le nombre de µops fournies par l'unité de décodage par cycle d'horloge, la '''largeur d'émission''' est le nombre maximal de µops émises par cycle d'horloge. Et n'allez pas croire qu'un surplus de ports d'émission est du gâchis. Sur les processeurs avec exécution dans le désordre, ce surplus peut être utilisé. Mais avant toute chose, évacuons un détail. Vous avez sans doute pensé que le surplus peut être exploité par les instructions machines décodées en plusieurs µops . Par exemple, si une instruction est décodée en deux µops, on pourrait avoir un port d'émission en plus pour en profiter. Mais les ports de décodage sont *en sortie du décodeur*, et contiennent des µops, pas des instructions. Le surplus de ports d'émission peut occasionnellement utiliser le surplus de ports de décodage, mais cela implique que des µops ont été mises en attente dans l'unité d'émission, pour être émises par la suite. Et cela implique l'usage d'un ''scheduler'' ou d'une file de µops. Le principe est que les µops sont accumulées dans le ''scheduler'', en attendant leurs opérandes ou la résolution d'une dépendance. Et si l'occasion se présente, une µops est émise sur chaque port d'émission. Il y a donc un gain en performances, mais il faut faire quelques précisions sur son origine. La largeur d'émission utilisée ne peut pas dépasser, *en moyenne*, la largeur de décodage. Et c'est intuitif : un CPU qui décode 4 µops par cycle ne peut pas émettre 6 par cycle en moyenne, sur le temps long, il n'y a pas de µops en surplus qui sortent du vide. Par exemple, sur un processeur quadruple émission, si on analyse combien d'instructions sont émises par cycle, il peut y avoir des cycles où la largeur d'émission est totalement utilisée, mais ce sera compensé par des périodes où elle est fortement sous-utilisée. Les µops sont accumulées en cas de sous-utilisation, puis consommées en cas d'utilisation complète. Les deux périodes se compensent. Et c'est là que l'on peut comprendre d'où vient le gain en performance. Les cycles où les ports d'émission sont sous-utilisés existent systématiquement, que le processeur utilise l'exécution dans le désordre ou pas. Ils sont liés à la présence de dépendances de données, aux contraintes d’appariement, etc. Elles tendent à réduire la moyenne du nombre de µops émises par cycle. Par contre, ce sont les cycles de rattrapage, où les ports en surplus sont utilisés, qui font remonter la moyenne. Le gain en performance est donc lié à ces cycles de rattrapage, où les µops accumulées sont émises dans les ports en surplus. Et ils n'existent que sur les processeurs avec une file/fenêtre d'instruction. Réduire le nombre de ports d'émission permet de garder des ''schedulers'' et un ROB simples, rapides et économes en énergie. Et mine de rien, c'est là un compromis important : à quoi bon augmenter le nombre de ports d'émission si c'est pour que ce soit compensé par une fréquence plus faible ? Par contre, réduire le nombre de ports augmente la ''port contention'', surtout si on a mal réparti les ALU. Il faut donc trouver un compromis entre réduire le nombre de ports d'émission d'un côté, réduire la ''port contention'' de l'autre. La différence entre largeur de décodage et d'émission a un impact assez fort sur le banc de registre, et précisément sur son nombre de ports de lecture. Le banc de registre a besoin de plus de ports de lecture avec une fenêtre d’instruction qu'avec des stations de réservation. Rappelons la terminologie utilisée dans ce cours. Les ''schedulers'' se contentent de mémoriser la micro-opération et quelques bits pour détecter la disponibilité des opérandes. Par contre, les stations de réservations mémorisent aussi les opérandes des instructions. Et cette différence a une influence le nombre de ports de lecture du banc de registre. Supposons que toutes les instructions sont dyadiques, à deux opérandes. Comptons le nombre de ports nécessaires pour alimenter les unités de calcul, sans utiliser d'arbitre de banc de registre. Avec un ''scheduler'', il faut le double du nombre de ports d'émission. Mais avec des stations de réservation, il faut le double des ports de décodage. La raison est que les registres sont lus après émission avec un ''scheduler'', avant avec des stations de réservation (sous-entendu, après le décodage). Or, comme dit plus haut, les processeurs superscalaires larges ont souvent plus de ports d'émission que de décodage. ===La superscalarité à ''schedulers'' décentralisés=== Les processeurs précédents utilisaient une unité d'émission simple, qui pouvait utiliser l'émission dans l'ordre ou dans le désordre. Elle peut être remplacée par un ''scheduler'' centralisé dans que cela quoi que ce soit aux explications précédentes, idem avec une station de réservation centralisé. En soi, l'exécution dans le désordre est donc totalement compatible avec une implémentation simple de la superscalarité. Par contre, des subtilités surviennent avec les ''schedulers'' décentralisés. Pour rappel, sur ces processeurs, les µops sont émises en deux phases. Une première phase de ''dispatch'' qui envoie les µops vers le ''scheduler'' adéquat, sans détecter les dépendances de données. La seconde phase de ''schedule'' gère les dépendances de données, elle met en attente les µops en attendant que l'unité soit disponible pour les exécuter, en attendant aussi que les opérandes soient disponibles. Et à ce petit jeu, il y a une différence entre le nombre de µops qui sont ''dispatch par cycle'' et celles qui sont ''schedule''. Dit autrement, la largeur d'émission est scindée en une '''largeur de ''dispatch''''' et une '''largeur de ''schedule''. Par exemple, prenons un processeur triple émission avec deux stations de réservation : une pour les µops entières/mémoire, et une autre pour les µops flottantes. L'unité d'émission peut ''dispatch'' maximum trois µops par cycle : soit trois µops entières/mémoire, soit trois flottantes, soit un mix de trois µops différentes. Les stations de réservation, quant à elles, peuvent chacune ''schedule'' 3 µops par cycle, vers trois ALUs entières pour la station de réservation entière/mémoire, vers trois FPS pour la station de réservation flottante. De quoi ''dispatch'' trois µops, mais d'en ''schedule'' six, à chaque cycle. Et cet exemple ne sort pas de nulle part : les CPU x86 d'Intel et AMD sont globalement dans ce cas, même si les chiffres varient d'une microarchitecture à l'autre. L'exemple précédent colle parfaitement à la microarchitecture K7 d'AMD, utilisée sur les processeurs Athlon dans les années 2000. [[File:AMD K7.png|centre|vignette|upright=2.5|AMD K7, microarchitecture.]] L'exemple précédent avait assez d'unités entières/flottantes pour couvrir toute la largeur de décodage/''Dispatch''. Mais ce n'est pas toujours le cas, comme va le montrer l'exemple suivant. Le MIPS R10000, qui utilisait un mélange de files de µops et de ''schedulers'' : une file de µops les accès mémoire, une fenêtre pour les instructions entières et une autre pour les opérations flottantes. Les branchements et NOPs étaient exécutés dans une unité de branchement distincte. Les trois files/fenêtres peuvent mémoriser 16 µops. Le processeur avait deux ALU entières, une AGU de calcul d'adresse, un additionneur flottant et un multiplieur/diviseur flottant. Il y avait un multiplieur entier sur le port d'émission l'ALU 2. Le processeur décodait 4 instructions par cycle et produisait jusqu'à 4µops, qui étaient redistribuées sur les trois ''schedulers''. Chacune pouvait accepter 4 µops par cycle, ce qui fait que processeur pouvait ''dispatch'' 4 µops entières, ou 4 µops flottantes, ou 4 µops mémoire, ou un mélange de deux ou trois types de µops. Pour ce qui est du ''schedule'', le ''scheduler'' entière pouvait émettre 2 µops, la fenêtre flottante pouvait émettre une addition en même temps qu'une multiplication/divison flottante et qu'un branchement conditionnel flottant, et la file de µops mémoire ne pouvait émettre qu'une µop mémoire à la fois. En tout, cela fait 6 µops ''schedule'' pour 4 µops au ''dispatch''. [[File:R 10000.png|centre|vignette|upright=2.5|MIPS R10000, microarchitecture.]] ===La superscalarité à ''schedulers'' totalement décentralisés=== Prenons un cas extrême de fenêtre d'instruction décentralisé : celui où chaque ALU entière a sa propre station de réservation. En clair : une fenêtre d'instruction par ALU/FPU ! On parle de '''''schedulers'' totalement décentralisés'''. Vous vous dites que ce cas est un peu trop extrême pour être réaliste, mais il n'en est rien. C'est même très courant sur les architectures basse consommation, et sur pas mal de CPU x86 modernes. Une telle organisation entraine une légère perte de performance, comparé à un ''scheduler'' centralisé ou partiellement décentralisé. Et cela peut se comprendre par un exemple. Imaginez un processeur avec deux ALU, donc deux stations de réservation. Il arrivera qu'une station de réservation ait plusieurs µops prêtes, alors que l'autre en ait zéro. Dans une telle situation, une seule µop sera émise au cycle suivant, vu que chaque station de réservation a un seul port d'émission vers une seule ALU entière. Par contre, avec un ''scheduler'' centralisé double port, on aurait pu émettre les deux µops en même temps sur deux ALUs séparées. La perte de performance est donc liée au fait que les µops '''''prêtes''''' sont mal réparties dans les différentes stations de réservation. Il arrivera que des µops prêtes s'accumulent dans une station de réservation, alors que d'autres seront pleines, ou du moins sous-utilisées. Et ce n'est pas quelque chose qui peut être réglé à l'étape de ''dispatch'', car on ne sait pas encore quand les µops auront leurs opérandes de disponibles. [[File:Comparaison entre une station de réservation totalement décentralisé et une autre qui ne l'est pas.png|centre|vignette|upright=2.5|Comparaison entre une station de réservation totalement décentralisé et une autre qui ne l'est pas.]] Par contre, décentraliser totalement les ''schedulers'' entraine aussi un gain considérable en termes de consommation énergétique. Et c'est la raison pour laquelle les ''schedulers''s totalement décentralisés sont utilisées sur les architectures basse consommation. La perte de performance ne peut pas s'expliquer clairement à ce stade du cours, car il nous faudrait parler d'émission superscalaire. Le gain en matière d'énergie vient de l'économie de circuits, qui est assez drastique. Le gain en matière d'énergie vient de l'économie de circuits, qui est assez drastique. Je rappelle qu'une station de réservation a besoin, pour N instructions, d'environ N^2 circuits (des comparateurs, notamment). Prenons une station de réservation centralisé de 64 entrées et comparons avec 8 stations de 8 entrées chacune. Les deux donneront 64 entrées, mais la première aura un cout en circuit proportionnel à 64², alors que le second aura un cout en circuit de 8 *(8²). Entre les deux, le choix est clair : la seconde solution est plus économe. D'où l'utilisation de cette solution sur les microarchitectures basse consommation. ===L'unité de renommage superscalaire=== Avec la superscalarité, l'unité de renommage de registre doit gérer le cas où des instructions consécutives ont des dépendances de registre. Par exemple, prenons un processeur à double émission, qui renomme deux instructions consécutives. Si elles ont une dépendance de registre, le renommage de la seconde instruction dépend du renommage de la première. La première doit être renommée et le résultat du renommage est utilisé pour renommer la seconde, ce qui empêche d'utiliser deux unités de renommage séparées. Pour cela, elle renomme les registres sans tenir compte des dépendances, pour ensuite corriger le résultat. [[File:Unité de renommage superscalaire.png|centre|vignette|upright=2|Unité de renommage superscalaire.]] Seules les dépendances lecture-après-écriture doivent être détectées, les autres étant supprimées par le renommage de registres. Repérer ce genre de dépendances se fait assez simplement : il suffit de regarder si un registre de destination d'une instruction est un opérande d'une instruction suivante. [[File:Détection des dépendances sur un processeur superscalaire.png|centre|vignette|upright=2|Détection des dépendances sur un processeur superscalaire.]] Ensuite, il faut corriger le résultat du renommage en fonction des dépendances. Si une instruction n'a pas de dépendance avec une autre, on la laisse telle quelle. Dans le cas contraire, un registre opérande sera identique avec le registre de destination d'une instruction précédente. Dans ce cas, le registre opérande n'est pas le bon après renommage : on doit le remplacer par le registre de destination de l'instruction avec laquelle il y a dépendance. Cela se fait simplement en utilisant un multiplexeur dont les entrées sont reliées à l'unité de détection des dépendances. On doit faire ce replacement pour chaque registre opérande. [[File:Correction des dépendances sur un processeur superscalaire.png|centre|vignette|upright=2|Correction des dépendances sur un processeur superscalaire.]] ==Les optimisations des processeurs superscalaires larges== Les processeurs superscalaires larges ont des optimisations spécifiques, qui n'ont pas de sens sur les processeurs superscalaires étroits. Dans les grandes lignes, elles se classent en deux types. Les premières permettent de charger/décoder plus de 5-10 instructions simultanément. Le problème est alors que les branchements viennent mettre leur grain de sel et qu'il faut en tenir compte. Les secondes corrigent des problèmes qui apparaissent quand un CPU intègre plus de 5 à 10 unités de calcul. ===L'étape de chargement d'un CPU superscalaire large=== Charger plusieurs instructions pose de nombreux problèmes sur les processeurs superscalaires larges, qui émettent de 5 à 10 instructions simultanées. Pour rappel, la stratégie basique pour charger N instructions est de charger un bloc de N instructions consécutives. Les instructions après un branchement ne sont pas décodées ni exécutées, ce qui entraine une petite baisse de performance. Pour un N petit, la perte de performance est mineure. Mais pour un N large, elle devient suffisamment importante pour que la conception du CPU doit alors être repensée de fond en comble. Les analyses statistiques disent qu'il y a environ un branchement tous les 4 à 6 instructions. Un CPU a donc tendance à décoder des paquets de 3 à 5 instructions consécutives, avant qu'un branchement casse la dynamique. Or, cela pose des problèmes pour utiliser plusieurs décodeurs. L'implémentation basique, qui charge N instructions consécutives pour alimenter N décodeurs, fonctionne donc jusqu'à 4/6 décodeurs. Au-delà de 5 instructions, un CPU superscalaire doit être adapté pour gérer les branchements dans les paquets d'instruction qu'il émet. Le nombre de 5 instructions ne sort donc pas de nulle part. La première solution utilise un cache de µops, avec un ''front-end'' capable de charger/décoder 4/5 instructions à la fois, pas plus. L'idée est que la majorité des instructions proviennent du cache de µops (plus de 80%), ce qui fait qu'on peut émettre environ 10 instructions à partir du cache de µops, pas besoin d'avoir beaucoup de décodeurs. Les performances sont cependant dégradées lors d'un défaut de cache de µops. Les instructions doivent alors être chargées depuis le cache d'instruction, par paquets de 4-5, puis sont décodées par 4-5 décodeurs, ce qui ne permet pas d’alimenter les unités de calcul à plein régime. La solution précédente joue sur la distinction entre pots de décodage et d'émission. Elle permet d'émettre un grand nombre de µops sans pour autant charger un grand nombre d'instructions en même temps. En quelque sorte, ce n'est qu'une méthode de contournement, le CPU superscalaire reste de type étroit. Mais il est aussi possible d'utiliser un '''''front-end large''''', capable de charger une bonne dizaine d'instructions en même temps. La seule difficulté est de tenir compte de la présence de branchements. Pour rappel, avec un ''front-end'' étroit, les instructions situées après le premier branchement pris sont annulées, elles ne sont pas décodées ni exécutées. [[File:Fetch sur un processeur superscalaire avec prediction de branchements.png|centre|vignette|upright=2|Fetch sur un processeur superscalaire avec prédiction de branchements.]] Un ''front-end'' large charge les instructions de destination du branchement et les placent à sa suite. Ils chargent deux blocs à la fois et les fusionnent en un seul qui ne contient que les instructions présumées utiles. [[File:Cache d'instructions autoaligné.png|centre|vignette|upright=2|Cache d'instructions auto-aligné.]] Mais cela demande de charger deux blocs de mémoire en une fois, ce qui demande un cache d'instruction multiports. Il faut aussi ajouter un circuit pour assembler plusieurs morceaux de blocs en un seul : le fusionneur (''merger''). En pratique, cette solution demande d'ajouter un second port de lecture au cache, pour un cout en hardware important, avec un impact négatif sur le temps d'accès au cache. Et il faut rajouter le fusionneur, qui prend un étage de pipeline à lui tout seul. Et encore, cette solution ne gère pas le cas où un bloc contient plusieurs branchements ! [[File:Implémentation d'un cache d'instructions autoaligné.png|centre|vignette|upright=2|Implémentation d'un cache d'instructions auto-aligné.]] Les exemples précédents partent du principe qu'il n'y a qu'un seul branchement dans un bloc. Mais quand les blocs deviennent assez longs, il est fréquent d'avoir plusieurs branchements dans un bloc. Et il est même possible d'avoir plusieurs branchements pris. Dans un bloc de 8-10 instructions, ce n'est pas rare, et les CPU superscalaires à 8-10 voies sont la règle dans les CPU des années 2020. Pour gérer ce cas, il faut ajouter des ports supplémentaires au cache d'instruction et adapter le fusionneur, pour qu'il puisse fusionner trois ou quatre blocs. De plus, il faut utiliser une unité de prédiction de branchement capable de ''prédire plusieurs branchements par cycle''. ===Le décodage superscalaire large=== Le décodage des instructions n'est pas censé dépendre de l'implémentation du chargement. En théorie, une fois plusieurs blocs d'instruction fusionnés, on peut décoder les instructions en parallèle. Cependant, certains processeurs effectuent le décodage en tenant compte de la manière dont les branchements découpent les blocs. Les processeurs Atom d'Intel utilisent une solution de ce type, qui couple prédiction de branchement et décodage parallèle. Ils chargent/décodent des paquets de 3 instructions consécutives, chaque paquet étant séparé du précédent par un branchement. Pour cela, en plus d'avoir un fusionneur adapté, ils regroupent les décodeurs en ''clusters'', chacun regroupant 3 décodeurs, et pouvant décoder trois instructions consécutives. Les micro-architectures Tremont et Crestmont avaient deux ''clusters'' (6 décodeurs au total), la micro-architecture Darkmont en intègre trois (9 décodeurs au total). Avec deux ''clusters'', le fonctionnement est le suivant. Si le code est composé d'une suite d'instruction sans branchements, seul le premier ''cluster'' est utilisé, limitant le décodage à trois instructions par cycle. Par contre, si l'une des trois instructions décodée est un branchement, alors le second ''cluster'' décode les trois instructions situées après ce branchement, à partir de l'adresse de destination. Avec un troisième ''cluster'', c'est la même chose, sauf qu'il faut qu'il y ait un branchement dans les trois instructions décodées par le second ''cluster''. Mais comment faire pour savoir quels décodeurs activés, quels ''clusters'' sont actifs ? C'est la prédiction de branchement qui commande. Avec deux ''clusters'', elle détermine si un branchement est présent dans les trois instructions à charger, et quelle est son adresse de destination. Sans branchement, elle prévient les décodeurs et les trois instructions chargées sont décodées dans un ''cluster'' libre. Si elle prédit un branchement, elle charge les instructions adéquates, et active les deux ''clusters''. Avec trois branchements, c'est le même mécanisme, sauf que l'unité de prédiction de branchement doit être capable de prédire deux branchements par cycle. [[File:Front-end découplé de la microarchitecture Tremont.png|centre|vignette|upright=3|Front-end découplé de la microarchitecture Tremont.]] Il faut noter que les décodeurs d'un ''cluster'' sont des décodeurs simples, sans microcode. Sur les processeurs Tremont et Crestmont, le microcode était unique et était partagé entre tous les ''clusters''. Un seul ''cluster'' pouvait décoder une instruction complexe avec le microcode, l'autre devait se limiter à des instructions simples uniquement. Depuis Skymont, le microcode est partiellement dupliqué, avec un microcode par ''cluster''. Le cout en hardware peut paraitre prohibitif, pour un gain en performance faible. Sauf que c'est oublier que ce sont des processeurs Atom, sur lesquels beaucoup d'instructions sont microcodées. Les processeurs Atom ont un budget en transistor limité, ce qui fait qu'il est préférable pour eux d'implémenter des instructions en microcode que d'utiliser des unités de calcul dédiées ou des circuits de décodage complexes. Pour limiter la casse, le microcode n'est que partiellement dupliqué. Seul le microcode pour les instructions fréquente est dupliqué. Il y a un microcode secondaire pour certaines instructions, qui est lui unique et partagé par tous les ''clusters''. ===Le contournement sur les processeurs superscalaires larges=== Pour rappel, la technique du contournement (''register bypass'') permet au résultat d'une instruction d'être immédiatement utilisable en sortie de l'ALU, avant même d'être enregistré dans les registres. Implémenter la technique du contournement demande d'utiliser des multiplexeurs pour relier la sortie de l'unité de calcul sur son entrée si besoin. Il faut aussi des comparateurs pour détecter des dépendances de données. [[File:Pipeline Bypass.png|centre|vignette|upright=1|Pipeline Bypass]] La sortie de chaque ALU doit être reliée aux entrées de toutes les autres, avec les comparateurs qui vont avec. Sur les processeurs ayant plusieurs d'unités de calculs, cela demande beaucoup d’interconnexions et de comparateurs. Pour N unités de calcul, cela demande 2 * N² interconnexions, implémentées avec 2N multiplexeurs de N entrées chacun. Si c'est faisable pour 2 ou 3 ALUs, la solution est impraticable au-delà. Non seulement ce serait un enfer à câbler, mais les fils seraient tellement longs que la fréquence du processeur en prendrait un coup. Notez que cela vaut pour les processeurs superscalaires, mais aussi pour tout processeur avec beaucoup d'unités de calcul. En théorie, un CPU à exécution dans le désordre, non-superscalaire, mais avec beaucoup d'unités de calcul, fait face au même problème. En pratique, avoir une dizaine d'ALU implique processeur superscalaire à exécution dans le désordre. D'où le fait qu'on parle du problème maintenant. La seule solution praticable est de ne pas relier toutes les unités de calcul ensemble. À la place, on préfère regrouper les unités de calcul dans différents '''agglomérats''' ('''cluster'''). Le contournement est alors possible entre les unités d'un même agglomérat, mais pas entre agglomérats différents. Évidemment, certaines possibilités de contournement sont perdues, mais c'est compensé par un gain en fréquence et un cout en circuit/fils réduit. C'est un bon compromis, ce qui explique que presque tous les processeurs modernes l'utilisent. Les rares exceptions sont les processeurs POWER 4 et POWER 5, qui ont préféré se passer de contournement pour garder un processeur très simple et une fréquence élevée. ===Le banc de registre des processeurs superscalaires larges=== Pour émettre deux opérations entières simultanément, il faut lire deux fois plus d'opérandes. Et il faut aussi écrire deux résultats dans les registres, en même temps. Pour cela, on double les ports du banc de registre. En général, il faut au maximum 2 ports de lecture et un port d'écriture par unité de calcul. Le problème, c'est que plus un banc de registres a de ports, plus il utilise de circuits, est compliqué à concevoir, consomme de courant et chauffe. Avec plusieurs dizaines d'unités de calcul différentes, ajouter autant de ports impacterait la fréquence du banc de registres et réduirait les performances, voire est totalement impraticable à cause des contraintes thermiques. Les processeurs superscalaires larges doivent donc trouver des solutions. La première solution utilise un banc de registre unique, mais n'utilise pas autant de ports que le pire des cas le demanderait. Le processeur détecte quand il n'y a pas assez de ports pour servir toutes les micro-opérations. Quand ça arrive, l'unité d'émission émet assez de micro-opérations pour exploiter les ports disponibles, mais met en attente les micro-opérations en trop, le temps que les ports se libèrent. Pour cela, le banc de registre est géré par un circuit d'arbitrage spécialisé, intégré à l'unité d'émission, l’'''arbitre du banc de registres''' (''register file arbiter''). Une autre solution est de dupliquer le banc de registres en plusieurs exemplaires qui contiennent exactement les mêmes données, mais avec moins de ports de lecture/écriture. Un exemple est celui des processeurs POWER, Alpha 21264 et Alpha 21464. Sur ces processeurs, le banc de registre est dupliqué en plusieurs exemplaires, qui contiennent exactement les mêmes données. Les écritures dans les registres sont envoyées à tous les bancs de registres, afin de garantir que leur contenu est identique. Chaque exemplaire a exactement deux ports de lecture. La conception du processeur est simplifiée, que ce soit au niveau du câblage, que de la conception des bancs de registres. Une dernière solution découpe le banc de registres en plusieurs bancs de registres plus petits, avec un réseau d'interconnexions pour échanger des données entre bancs de registres. Dans la plupart des cas, cette séparation est invisible du point de vue de l'assembleur et du langage machine. Le processeur se charge de transférer les données entre bancs de registres suivant les besoins. Sur d'autres processeurs, les transferts de données se font via une instruction spéciale, souvent appelée ''COPY''. [[File:Banc de registres distribué.png|centre|vignette|upright=2|Banc de registres distribué.]] Sur de certains processeurs, un branchement est exécuté par une unité de calcul spécialisée. Or les registres à lire pour déterminer l'adresse de destination du branchement ne sont pas forcément dans le même agglomérat que cette unité de calcul. Pour éviter cela, certains processeurs disposent d'une unité de calcul des branchements dans chaque agglomérat. Dans les cas où plusieurs unités veulent modifier le ''program counter'' en même temps, un système de contrôle général décide quelle unité a la priorité sur les autres. Mais d'autres processeurs fonctionnent autrement : seul un agglomérat possède une unité de branchement, qui peut recevoir des résultats de tests de toutes les autres unités de calcul, quel que soit l’agglomérat. ==La macro-fusion : une optimisation du décodage parallèle== Les processeurs superscalaires supportent la technique dite de '''macro-fusion''', qui permet de fusionner deux-trois instructions consécutives en une seule micro-opération. Par exemple, il est possible fusionner une instruction de test et une instruction de saut en une seule micro-opération de branchement. Il s'agit là de l'utilisation la plus importante de la macro-fusion sur les processeurs x86 modernes. La macro-fusion est utilisée pour fusionner un test et un saut en un branchement unique. L'optimisation est présente sur la plupart des CPU superscalaires modernes. Les CPU x86 l'implémentent, mais aussi quelques CPU ARM et les processeurs Apple de série M (M1 à M5, et potentiellement plus quand ils seront sortis). La fusion des instructions se fait lors du décodage des instructions, grâce à la coopération des décodeurs. Elle marche systématiquement si l'instruction de test et le saut sont consécutives, qu'elles forment bien une paire d'instruction. Par contre, insérer une instruction entre les deux empêche la macro-fusion de faire son travail, sauf si l'instruction insérée est un NOP. Les processeurs ARM64 avaient une forme spécifique de macro-fusion, utilisée pour un cas très précis : charger une constante immédiate de 32 ou 64 bits, dans un registre 64 bits. Les CPU ARM 64 bits utilisent des instructions codées sur 32 bits, qui ne peuvent encoder que des constantes immédiates de 16 bits. Pour charger une constante de 32/64 bits, il faut s'y prendre en plusieurs fois. Une première instruction MOVZ charge les 16 premiers bits, puis 2 à 4 instructions MOVK remplissent le reste. MOVZ met à zéro les 48 bits de poids fort, MOVK permet de sélectionner le doublet à modifier dans le registre (on modifie 16 bits, dont on choisit la place, le reste du registre est laissé tel quel). ARM permet de fusionner cette suite d'instructions en une seule µop MOV avec une constante immédiate. On parle alors de '''''MOVZ + MOVK fusion'''''. Une dernière utilisation, [https://www2.eecs.berkeley.edu/Pubs/TechRpts/2016/EECS-2016-130.pdf proposées pour le jeu d'instruction RISC-V], fusionnait un calcul d'adresse et une instruction LOAD/STORE en une seule instruction d'accès mémoire. Elle a été envisagée à une époque où le jeu d'instruction RISC-V ne gérait pas les modes d'adressage base + indice. L'idée était d'avoir une unité mémoire qui gérait le mode d'adressage base + indice et de fusionner des instructions pour l'exploiter. Mais de nos jours, le jeu d'instruction RISC-V intègre le mode d'adressage base + indice, ce qui fait que la macro-fusion n'a aucun intérêt pour ce cas précis. La macro-fusion a de nombreuses limitations en pratique. En théorie, on pourrait l'utiliser au-delà des deux situations mentionnées plus haut. Par exemple, pour fusionner une addition et une multiplication en une seule instruction MAD. Mais l'intérêt est assez faible. Notons que la macro-fusion ne permet que de fusionner des paires d'instructions. Aller au-delà demanderait un cout en circuit trop important. Déjà que tester deux paires utilise pas mal de comparateurs... ==Le ''stack engine'' : une optimisation de la pile d'appel== Les processeurs modernes intègrent une optimisation liée au pointeur de pile. Pour rappel, sur les architectures modernes, le pointeur de pile est un registre utilisé pour gérer la pile d'appel, précisément pour savoir où se trouve le sommet de la pile. Il est manipulé par les instructions CALL, RET, PUSH et POP, mais aussi par les instructions d'addition/soustraction pour gérer des cadres de pile de taille variable. De plus, il peut servir d'opérande pour des instructions LOAD/STORE, afin de lire/écrire des variables locales, les arguments d'une fonction, et autres. C'est donc un registre général adressable, intégré au banc de registre, altéré par l'unité de calcul entière. L'incrémentation/décrémentation du pointeur de pile passe donc par l'unité de calcul, lors des instructions CALL, RET, PUSH et POP. Mais, l'optimisation que nous allons voir permet d'incrémenter/décrémenter le pointeur de pile sans passer par l'ALU, ou presque. L'idée est de s'inspirer des architectures avec une pile d'adresse de retour, qui intègrent le pointeur de pile dans le séquenceur et l'incrémentent avec un incrémenteur dédié. ===Le ''stack engine''=== L'optimisation que nous allons voir utilise un '''''stack engine''''' intégré à l'unité de contrôle, au séquenceur. Le processeur contient toujours un pointeur de pile dans le banc de registre, cela ne change pas. Par contre, il n'est pas incrémenté/décrémenté à chaque instruction CALL, RET, PUSH, POP. Un compteur intégré au séquenceur est incrémenté à la place, nous l’appellerons le '''compteur delta'''. La vraie valeur du pointeur de pile s'obtient en additionnant le compteur delta avec le registre dans le banc de registre. Précisons que si le compteur delta vaut zéro, la vraie valeur est dans le banc de registre et peut s'utiliser telle quelle. Lorsqu'une instruction ADD/SUB/LOAD/STORE utilise le pointeur de pile comme opérande, elle a besoin de la vraie valeur. Si elle n'est pas dans le banc de registre, le séquenceur déclenche l'addition compteur-registre pour calculer la vraie valeur. Finalement, le banc de registre contient alors la bonne valeur et l'instruction peut s'exécuter sans encombre. L'idée est que le pointeur de pile est généralement altéré par une série d'instruction PUSH/POP consécutives, puis des instructions LOAD/STORE/ADD/SUB utilisent le pointeur de pile final comme opérande. En clair, une bonne partie des incrémentations/décrémentation est accumulée dans le compteur delta, puis la vraie valeur est calculée une fois pour toutes et est utilisée comme opérande. On accumule un delta dans le compteur delta, et ce compteur delta est additionné quand nécessaire. Précisons que le compteur delta est placé juste après le décodeur d'instruction, avant même le cache de micro-opération, l'unité de renommage et l'unité d'émission. Ainsi, les incrémentations/décrémentations du pointeur de pile disparaissent dès l'unité de décodage. Elles ne prennent pas de place dans le cache de micro-opération, ni dans le ''scheduler'', ni dans la suite du pipeline. De nombreuses ressources sont économisées dans le ''front-end''. Mais utiliser un ''stack engine'' a aussi de nombreux avantages au niveau du chemin de données/''back-end''. Déjà, sur les processeurs à exécution dans le désordre, cela libère une unité de calcul qui peut être utilisée pour faire d'autres calculs. Ensuite, le compteur delta mémorise un delta assez court, de 8 bits sur le processeur Pentium M, un peu plus pour les suivants. L'incrémentation se fait donc via un incrémenteur 8 bits, pas une grosse ALU 32/64 bits. Il y a un gain en termes de consommation d'énergie, un incrémenteur 8 bits étant moins gourmand qu'une grosse ALU 32/64 bits. ===Les points de synchronisation du delta=== La technique ne fonctionne que si la vraie valeur du pointeur de pile est calculée au bon moment, avant chaque utilisation pertinente. Il y a donc des '''points de synchronisation''' qui forcent le calcul de la vraie valeur. Plus haut, nous avions dit que c'était à chaque fois qu'une instruction adresse le pointeur de pile explicitement, qui l'utilise comme opérande. Les instructions CALL, RET, PUSH et POP ne sont pas concernées par elles utilisent le pointeur de pile de manière implicite et ne font que l'incrémenter/décrémenter. Mais dans les faits, c'est plus compliqué. D'autres situations peuvent forcer une synchronisation, notamment un débordement du compteur delta. Le compteur delta est généralement un compteur de 8 bits, ce qui fait qu'il peut déborder. En cas de débordement du compteur, le séquenceur déclenche le calcul de la vraie valeur, puis réinitialise le compteur delta. La vraie valeur est donc calculée en avance dans ce cas précis. Précisons qu'un compteur delta de 8 bits permet de gérer environ 30 instructions PUSH/POP consécutives, ce qui rend les débordements de compteur delta assez peu fréquent. À noter que si le compteur delta vaut zéro, il n'y a pas besoin de calculer la vraie valeur, le séquenceur prend cette situation en compte. Un autre point de synchronisation est celui des interruptions et exceptions matérielles. Il faut que le compteur delta soit sauvegardé lors d'une interruption et restauré quand elle se termine. Idem lors d'une commutation de contexte, quand on passe d'un programme à un autre. Pour cela, le processeur peut déclencher le calcul de la vraie valeur lors d'une interruption, avant de sauvegarder les registres. Pour cela, le processeur intègre un mécanisme de sauvegarde automatique, qui mémorise la valeur de ce compteur dans le tampon de réordonnancement, pour forcer le calcul de la vraie valeur en cas de problème. La technique du ''stack engine'' est apparue sur les processeurs Pentium M d'Intel et les processeurs K10 d'AMD, et a été conservée sur tous les modèles ultérieurs. L'implémentation est cependant différente selon les processeurs, bien qu'on n'en connaisse pas les détails et que l'on doive se contenter des résultats de micro-benchmarks et des détails fournit par Intel et AMD. Selon certaines sources, dont les manuels d'optimisation d'Agner Fog, les processeurs AMD auraient moins de points de synchronisation que les processeurs Intel. De plus, leur ''stack engine'' serait placé plus loin que prévu dans le pipeline, après la file de micro-opération. ==La micro-fusion et la délamination== La '''micro-fusion''' est une optimisation qui retarde le décodage réel de certaines instructions assez loin dans le pipeline. Elle concerne surtout les instructions ''load-op'', mais pas que. D'autres instructions mémoire peuvent subir cette optimisation. L'essentiel est que, sans micro-fusion, ces instructions sont décodées en plusieurs micro-opérations. La micro-fusion retarde le décodage final de ces instructions, qui se fait assez tard dans le pipeline. Pour comprendre l'intérêt, nous allons devoir faire quelques explications. L'optimisation en question fait le décodage en deux temps. Prenons l'exemple d'une opération ''load-op'', qui est censée être décodée en deux micro-opérations : une lecture, puis une opération. Le décodage produit une '''macro-opération''' (terme d'Intel), qui est propagée dans le pipeline, pour être scindée en deux micro-opérations un peu avant les ALU et l'unité mémoire. La macro-opération est techniquement une micro-opération comme une autre, sauf que ce n'est pas la micro-opération finale. L'unité d'émission découpe cette macro-opération en deux micro-opérations, qui sont émises l'une après l'autre. Pour résumer, les instructions ''load-op'' ne sont complétement découpées en micro-opération lors de l'émission, pas lors du décodage. L'optimisation impacte ce qui se situe entre le décodeur d'instruction et l'unité d'émission : l'unité de renommage, la file de micro-opérations, le ''Loop Stream Detector'' et/ou le cache de micro-opération. L'intérêt de l'optimisation est que l'on fusionne deux micro-opérations en une seule macro-opération. Le cache de micro-opération et la file de micro-opération peuvent mémoriser plus de micro-opérations, vu que certaines sont fusionnées. Quant à l'unité de renommage, elle renomme une seule macro-opération au lieu de renommer deux micro-opérations, ce qui augmente le débit du renommage de registre. Par contre, cela complique un peu le travail de l'unité d'émission, qui doit découper les instructions ''load-op'' en deux et émettre les micro-opérations l'une après l'autre. Il faut noter qu'il n'y a pas de fusion proprement dite. Le décodeur ne décode pas deux micro-opérations séparées, avant de les fusionner. En réalité, il génère directement une macro-opération, qui correspond à deux micro-opérations, que ce soit plus tard dans le pipeline ou sur une autre architecture. D'ailleurs, la micro-fusion a lieu à l'intérieur d'une instruction, qui est censée être traduite en plusieurs micro-opérations. Et encore : pas toutes. La conséquence est que la technique n'a de sens que sur les processeurs CISC, avec des instructions assez complexes pour être décodées en plusieurs micro-opérations. En pratique, seuls les CPU x86 sont concernés. ===Les domaines de fusion=== La micro-fusion n'est pas spécifique aux processeurs superscalaires. En théorie, on peut l'implémenter sur un processeur non-superscalaire à émission dans l'ordre. Cependant, je ne connais aucun processeur à émission dans l'ordre qui implémente la micro-fusion, même si son implémentation est en théorie possible sur de tels processeurs. La micro-fusion est implémentée différemment selon que l'émission se fasse dans l'ordre, dans le désordre, avec un ''scheduler'', avec des stations de réservation, etc. J'ai dit plus haut que les micro-opérations sont générées lors de l'émission, mais le moment exact varie suivant le processeur. Pour simplifier le tout, nous parlerons de '''scission''' quand le processeur traduit une macro-opération en deux/trois micro-opérations. Le moment où a lieu la scission est théoriquement dans l'unité d'émission, mais celle-ci prend plusieurs formes selon que le processeur utilise l'émission dans l'ordre, dans le désordre, avec un ''scheduler'', avec des stations de réservation, etc. Les processeurs à exécution dans l'ordre sont le cas le plus simple. L'unité d'émission est alors en charge du découpage des macro-opérations en micro-opérations. La file de micro-opération ou le cache de micro-opérations mémorisent des macro-opérations. À l'opposé, le tampon de ré-ordonnancement mémorise lui des micro-opérations. Le reste du processeur n'est pas affecté. Sur les processeurs à exécution dans le désordre, les différences sont nombreuses. Le tampon de ré-ordonnancement peut mémoriser soit les micro-opérations finales, soit des macro-opérations. Il en est de même avec le ''scheduler'' et/ou les stations de réservation, qu'elles soient centralisés ou décentralisés. Tout dépend de comment se fait l'implémentation. Une implémentation simple effectue la scission des macro-opérations dans l'unité d'émission, comme sur les processeurs à exécution dans l'ordre. Sur de nombreux processeurs, l'unité d'émission et de renommage sont simplement fusionnées, ce qui fait que la scission a lieu juste après le renommage de registres. En conséquence, le tampon de re-ordonnancement et les ''schedulers'' ne voient que des micro-opérations. Les macro-opérations disparaissent juste avant. Cette implémentation est préférée avec un ''scheduler'' centralisé, car on voit mal comment scinder une macro-opération juste avant l'ALU. Une autre implémentation fait la scission en sortie de le ''scheduler'' ou des stations de réservation, qu'elles soient centralisés ou décentralisés. Dans ce cas, le tampon de re-ordonnancement fait de même. L'avantage est que le tampon de ré-ordonnancement stocke des macro-opérations, ce qui augmente sa taille effective. Par exemple, il utilise une seule entrée pour une instruction ''load-op'', au lieu de deux sans micro-fusion de ce type. ===La délamination=== La scission peut parfois avoir lieu plus tôt, dans des circonstances très précises. Concrètement, cela ne concerne que quelques micro-architectures d'Intel, pour des instructions très précises. La raison est les limitations du format des micro-opérations, pas une histoire d'optimisation. Le processeur aimerait pouvoir faire la micro-fusion, mais ne peut pas à cause de ces limitations. Une telle situation cause alors une '''délamination''' : les micro-opérations sont scindées précocement. Par exemple, sur la micro-architecture SandyBridge d'Intel, les opérations ''load-op'' sont fusionnées, sauf si elles utilisent l'adressage indicé. Les micro-opérations de ce processeur ne peuvent avoir que deux opérandes. Trois opérandes est de trop, et les opérations ''load-op'' en adressage indicé dépassent cette limite. Dans ce cas, les micro-opérations sont fusionnées en sortie du décodeur, mais sont scindés avant d’entrer dans la file de micro-opération. L'avantage n'est pas évident, vu que l'unité de renommage suit de près le décodeur d'instruction. Il est que le cache de micro-opérations mémorise des macro-opérations, pas deux micro-opérations. ===La micro-fusion des processeurs Intel et AMD=== La micro-fusion est apparue sur le Pentium M d'Intel, et a été conservée telle quelle sur les processeurs Intel suivants. Les processeurs AMD supportent la micro-fusion depuis au moins la micro-architecture AMD K8. Mieux que ça, la délamination n'était pas utilisée car les micro-opérations acceptaient plus de 2 opérandes. Que ce soit chez AMD ou Intel, elle concerne deux types d'instructions : les écritures mémoire et les instructions ''load-op''. Sur le Pentium M, il y avait quelques limitations, l'optimisation se limitant par exemple aux registres entiers et flottants, mais pas aux registres MMX, mais pas les registres SSE (nous verrons ces registres dans quelques chapitres). Mais les processeurs modernes n'ont plus cette limitation. La micro-fusion des CPU Intel concerne deux types d'instructions : les écritures mémoire et les instructions ''load-op''. Pour les écritures, la situation est plus complexe que pour les instructions ''load-op''. Sur les processeurs Intel précédents, les écritures étaient réalisées dans deux unités séparées : le calcul d'adresse dans une unité de calcul, l'écriture proprement dite dans l'unité mémoire. Elles prenaient donc deux micro-opérations. Le processeur a changé ses unités mémoire, ce qui fait qu'elle pouvait faire les deux en une seule micro-opération. Il s'agissait alors d'une optimisation du chemin de données, plus que de la micro-fusion proprement dite, mais je la mentionne ici malgré tout. La micro-fusion sur ce processeur avait un avantage en plus des avantages usuels : elle utilisait mieux les décodeurs. Les Pentium M avaient trois décodeurs pour décoder plusieurs instructions en même temps, chose qu'on détaillera dans le chapitre sur les processeurs superscalaires. Un seul décodeur pouvait décoder toutes les instructions, les deux autres ne peuvent décoder que les instructions simples, qui se décodent en une seule micro-opération. Avec la micro-fusion, les trois décodeurs peuvent gérer les écritures mémoire et les opérations ''load-op'', vu qu'elles deviennent des instructions simples. Sans cela, elles auraient été limitées au premier décodeur. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Le parallélisme mémoire | prevText=Le parallélisme mémoire | next=Les microarchitectures pour le x86 : haute performance | nextText=Les microarchitectures pour le x86 : haute performance }} </noinclude> 0q9ors94stnodo6ev9ycmgi1ivdscsi Fonctionnement d'un ordinateur/Les jeux d'instructions 0 69027 773574 765325 2026-09-29T14:27:29Z Mewtow 31375 /* Les différences entre CISC et RISC */ 773574 wikitext text/x-wiki Les instructions d'un processeur dépendent fortement du processeur utilisé. Le '''jeu d'instructions''' d'un processeur définit la liste des instructions supportées, ainsi que la manière dont elles sont encodées en mémoire. Le jeu d'instruction des PC actuels est le x86, un jeu d'instructions particulièrement ancien, apparu en 1978. Les macintoshs utilisent un jeu d'instruction différent : le PowerPC. Mais les architectures x86 et Power PC ne sont pas les seules au monde : il existe d'autres types d'architectures qui sont très utilisées dans le monde de l’informatique embarquée et dans tout ce qui est tablettes et téléphones portables derniers cris. On peut citer notamment les architectures ARM, MIPS et SPARC. Pour résumer, il existe différents jeux d'instructions, que l'on peut classer suivant divers critères. ==Les jeux d'instruction RISC vs CISC== Dans le chapitre précédent, nous avons vu comment sont encodées les instructions, ainsi que de nombreux paramètres : les modes d'adressage supportés, leur encodage, la taille des instructions, l'encodage de l'opcode, etc. Et tous ces paramètres sont suffisant pour parler des processeurs RISC et CISC. Il s'agit d'une classification qui sépare les processeurs en deux catégories : * les '''RISC''' (''reduced instruction set computer''), au jeu d'instruction simple ; * et les '''CISC''' (''complex instruction set computer''), qui ont un jeu d'instruction étoffé. Reste à expliquer ce que l'on veut dire quand on parler de jeu d'instruction "simple" ou "complexe". Et la différence n'est pas simple. Surtout que le terme CISC regroupe, comme on le verra, des architectures bien différentes. ===Les différences entre CISC et RISC=== La différence la plus intuitive est le nombre d'instructions supporté. Les processeurs CISC supportent beaucoup d'instructions, , alors que les processeurs RISC se contentent d'un petit nombre d'instructions assez simples. Un autre critère, très lié au précédent, est la complexité des instructions en question. Les processeurs CISC incorporent souvent des instructions complexes, comme le calcul de la division, de la racine carrée, de l'exponentielle, des puissances, des fonctions trigonométriques. Plus fréquent, on trouvait des instructions de contrôle élaborées pour gérer les appels de fonction, simplifier l'implémentation des boucles, etc. La différence principale fait la distinction entre les architectures LOAD-STORE (RISC) et celles qui ne le sont pas (CISC). Les processeurs RISC sont des '''architectures LOAD-STORE'''. Sur celles-ci, seules les instructions d'accès mémoire peuvent lire ou écrire en mémoire. Les autres instructions ne peuvent accéder qu'aux registres : elles lisent leurs opérandes dans les registres et enregistrent leur résultat dans les registres. En conséquence, les instructions de calcul ne peuvent prendre que des noms de registres ou des constantes comme opérandes, via les modes d'adressage immédiat et à registre. Pour le dire autrement, elles ne gèrent que les instructions reg-reg et cst-reg, pas les instructions ''load-op''. La distinction se fait uniquement au niveau des instructions de calcul/branchement. Les premiers processeurs RISC se contentaient de deux instructions d'accès mémoire : LOADq et STORE. Elles ont d'ailleurs donné leur nom à ce type d'architecture. Mais dans les faits, les processeurs RISC modernes peuvent gérer d'autres instructions d'accès à la mémoire. Par exemple, les processeurs ARM7 supportent des instructions de copie mémoire-mémoire nommées CPYP, CPYM et CPYE. Et ce n'est pas incompatible avec un processeur RISC, ni avec une architecture LOAD-STORE. De telles instructions ont beau être assez complexes, ça reste des instructions d'accès mémoire. Même si elles font plusieurs accès mémoire par instruction, c'est comme si on avait fusionné un LOAD suivi d'un STORE en une seule instruction. Les architectures LOAD-STORE sont les seules à avoir une stricte séparation entre instructions d'accès mémoire et instructions de calcul. À l'opposé, les processeurs CISC ne sont pas des architectures LOAD-STORE, leurs instructions de calcul/branchement peuvent effectuer des accès mémoire, soit pour aller chercher leurs opérandes en RAM, soit pour écrire un résultat. Elles peuvent même en faire plusieurs si plusieurs opérandes sont en mémoire, encore que ce ne soit pas possible sur tous les jeux d'instructions. Au minimum, les processeurs CISC gèrent les instructions ''load-op''. Quelques processeurs CISC anciens supportent tous les modes d'adressage possibles pour les opérandes et le résultat, qui peuvent tous trois être lus/écrits dans les registres ou la RAM. Les deux propriétés précédentes, à savoir un grand nombre d'instruction et des modes d'adressages complexes, se marient bien avec des instructions de longueur variable. Les instructions d'un processeur CISC sont de taille variable pour diverses raisons, mais la variété des modes d'adressage y est pour beaucoup. Quand une même instruction peut incorporer soit deux noms de registres, soit deux adresses, soit un nom de registre et une adresse, sa taille ne sera pas la même dans les trois cas. Les processeurs RISC ne sont pas concernés par ce problème. Les instructions de calcul n'utilisent que deux-trois modes d'adressages simples, qui demandent d'encoder des registres ou des constantes immédiates de petite taille. Les autres instructions se débrouillent avec des adresses et éventuellement un nom de registre. Le tout peut être encodé sur 32 ou 64 bits sans problèmes. {|class="wikitable" |+ Différences CISC/RISC |- ! Propriété !! CISC !! RISC |- ! scope="col" | Instructions | * Nombre d'instructions élevé, parfois plus d'une centaine. * Parfois, présence d'instructions complexes (fonctions trigonométriques, gestion de texte, autres). * Supportent des types de données complexes : texte, listes chainées, etc. * Instructions de taille variable. | * Faible nombre d'instructions, moins d'une centaine. * Pas d'instruction complexes. * Types supportés limités aux entiers (adresses comprises) et flottants. * Instructions de taille fixe. |- ! scope="col" | Modes d'adressage | * Support des instructions ''load op'', systématique * Souvent, support d'instructions multi-accès (plusieurs accès mémoires par instruction). | * Architecture LOAD-STORE. * Un seul accès mémoire par instruction maximum |- ! scope="col" | Registres | * Peu de registres : rarement plus de 16 registres entiers. | * Beaucoup de registres, souvent plus de 32. |} Les jeux d'instruction CISC sont moins nombreux que les jeu d'instructions RISC. Les jeux d'instructions RISC les plus connu sont ARM, RISC-V, MIPS, Power et PowerPC, PA-RISC, et de nombreux autres. Pour le CISC, le x86 et le z/ architecture d'IBm sont les deux jeux d'instruction restants. A vrai dire, si on omet les anciens jeux d'instruction CISC utilisés sur les anciens ''mainframes'', ce sont les deux seuls utilisés à l'heure actuelle. : Pour ceux qui veulent en savoir plus sur le jeu d'instruction et les processeurs, PA-RISC, ce site vous donnera toutes les informations possibles : [https://www.openpa.net/ Open PA-RISC]. ===Les performances relatives des CISC/RISC=== Pour comprendre quels sont les avantages et désavantages des processeurs CISC comparé au RISC, nous allons étudier leur performance et leur ''code density''. Pour ce qui est de la performance, les choses ne sont pas clairement tranchées. Pour comprendre pourquoi, nous allons partir d'une équation déjà abordée dans un chapitre antérieur, qui donne le temps que met un programme à s'exécuter. Le temps que met un programme pour s’exécuter est le produit : * du nombre moyen d'instructions exécutées par le programme ; * de la durée moyenne d'une instruction, en seconde. : <math>T = N \times T_\text{instruction}</math>, avec N le nombre moyen d'instruction du programme et <math>T_\text{instruction}</math> la durée moyenne d'une instruction. Le nombre moyen d'instructions exécuté par un programme s'appelle l'''Instruction path length'', ou encore '''longueur du chemin d'instruction''' en français. Si on utilise le nombre ''moyen'' d’instructions, c'est car il n'est pas forcément le même d'une exécution à l'autre, notamment en présence de conditions ou de boucles. Le processeurs CISC intègrent des instructions complexes, que les processeurs RISC doivent émuler à partir d'une suite d'opérations plus simples. Par exemple, les instructions ''load-op'' sont émulées avec une instruction LOAD suivie d'une instruction de calcul. En clair, les processeurs CISC ont un avantage pour le paramètre N, la longueur du chemin d'instruction. Par contre, il n'est pas garantit que les instructions complexes soient aussi rapides que la suite d'instruction RISC équivalente, car les processeurs RISC ont un avantage pour le terme <math>T_\text{instruction}</math>. Voyons pourquoi. Les processeurs CISC gèrent un grand nombre d'instructions et de modes d'adressage, ce qui les rend plus gourmands en transistors. Non pas qu'il faille ajouter plus de circuits de calcul, les CISC se débrouillent bien avec les circuits usuels pour les 4 opérations basiques. Le vrai problème est le support des nombreux modes d'adressage, des instructions de taille variable, et le grand nombre de variantes de la même opération. En conséquence, les circuits de contrôle du processeur sont plus complexes et utilisent beaucoup de transistors. Le budget en transistors utilisé pour les circuits de contrôle ne sont pas disponibles pour autre chose, comme de la mémoire cache ou des registres. De plus, cela a tendance à limiter la fréquence du processeur. Les processeurs RISC sont eux plus économes, ils ont moins d'instructions, moins de circuits de contrôle. Ils peuvent utiliser plus de transistors pour autre chose, souvent de la mémoire cache ou des registres. Les processeurs RISC peuvent se permettre d'utiliser beaucoup de registres, ils ont le budget en transistor pour. Et c'est sans compter que la simplicité des circuits de contrôle et des connexions intra-processeur (le bus interne au CPU qu'on verra dans quelques chapitres) fait qu'on peut faire fonctionner le processeur à plus haute fréquence. Si les registres sont plus nombreux sur les architectures RISC, ce n'est pas qu'une question de budget en transistors. Une autre raison est que les architectures LOAD-STORE ont besoin de plus de registres pour faire le même travail que les architectures à registres, du fait de l'absence d'instructions ''load-op''. La ''register pressure'' est donc légèrement plus importante, ce qui est compensée en ajoutant des registres. ===La densité de code relative entre RISC et CISC=== Si la performance ne donne pas de vainqueur clair entre CISC et RISC, il y a cependant un second critère sur lequel la victoire est bien plus nette. Il s'agit de la '''densité de code''', à savoir la taille des programmes mesurée en octets. De nos jours, la taille des programmes n'est pas importante au point d'être un problème, ce n'est pas ca qui prendra plusieurs gibioctets de mémoire. Par contre, au tout début de l'informatique, la mémoire était chère et limitée, avoir des programmes petits était un avantage clair. La taille d'un programme dépend de deux choses : le nombre d'instructions et leur taille. Et ces deux paramètres sont influencés par le caractère CISC/RISC. Comme dit plus haut, les architectures CISC ont un avantage pour le nombre d'instruction N, du fait de la présence d'instructions ''load-op'' et d'instructions complexes. Mais elles ont aussi un avantage pour la taille des instructions. Les instructions des processeurs CISC sont de taille variable, là où celles des processeurs RISC sont de taille fixe. Les instructions CISC ont une taille allant de très courtes à très longues, celles des RISC sont de taille moyenne. Mais le fait d'avoir des instructions très courtes l'emporte sur les processeurs CISC. Une minorité de processeurs RISC arrivent à obtenir une densité de code proche de celle des processeurs CISC. Pour cela, ils ont classes d'instructions de taille différente. Un exemple est jeu d'instruction RISC-V, où il existe des instructions "normales" de 32 bits et des instructions "compressées" de 16 bits. Le processeur charge un mot de 32 bits, ce qui fait qu'il peut lire entre une et deux instructions à la fois. Au tout début de l'instruction, un bit est mis à 0 ou 1 selon que l'instruction soit longue ou courte. Le reste de l'instruction varie suivant sa longueur. De telles instructions de taille quasi-variables permettent de grandement gagner en densité de code. Il faut noter que sur les processeurs modernes, avoir une bonne densité de code a un impact secondaire sur les performances. En effet, les processeurs modernes ont une mémoire cache qui sert à la fois pour les données, mais aussi pour les instructions chargées depuis la mémoire. Les instructions sont conservées dans le cache après leur exécution, pour une exécution ultérieure (ce qui implique une boucle). Si une instruction est dans le cache, elle est lue directement depuis le cache, sans passer par un long accès en mémoire RAM. Les processeurs modernes ont notamment un petit cache d'instruction, spécialement dédié aux instructions. Plus la densité de code est bonne, plus le cache d'instruction pourra contenir d'instructions, plus il sera efficace, plus il filtrera d'accès mémoire. ===Un petit historique de la distinction entre processeurs CISC et RISC=== Les jeux d'instructions CISC sont les plus anciens et étaient à la mode jusqu'à la fin des années 1980. À cette époque, on programmait rarement avec des langages de haut niveau et beaucoup de programmeurs codaient en assembleur. Avoir un jeu d'instruction complexe, avec des instructions de "haut niveau" facilitait la vie des programmeurs. Et leur meilleure densité de code était un sérieux avantage, car la mémoire était rare et chère. Au cours des années 70-80, la mémoire est devenue moins chère et les langages de haut niveau sont devenus la norme. Le contexte technologique ayant changé, les processeurs CISC étaient à réévaluer. Est-ce que les instructions complexes des processeurs CISC sont vraiment utiles ? Pour le programmeur qui écrit ses programmes en assembleur, elles le sont. Mais avec les langages de haut niveau, la réponse dépend de l'efficacité des compilateurs. Des analyses assez anciennes, effectuées par IBM, DEC et quelques laboratoires de recherche, ont montré que les compilateurs utilisaient les instructions ''load-op'' correctement, mais n'utilisaient pas les instructions complexes. Les analyses plus récentes fournissent la même conclusion. La faible densité de code n'était pas un problème, vu que les mémoires ont une capacité suffisante, encore que ce soit à nuancer. L'idée de créer des processeurs RISC commença à germer. Mais les processeurs RISC durent attendre un peu avant de percer. Par exemple, l'IBM 801, un processeur au jeu d'instruction très sobre, fût un véritable échec commercial. C'est dans les années 1980 que les processeurs possédant un jeu d'instruction simple devinrent à la mode. Cette année-là, un scientifique de l'université de Berkeley décida de créer un processeur possédant un jeu d'instruction contenant seulement un nombre réduit d'instructions simples, possédant une architecture particulière. Ce processeur était assez novateur et incorporait de nombreuses améliorations qu'on retrouve encore dans nos processeurs haute performances actuels, ce qui fit son succès : les processeurs RISC étaient nés. Les CISC et les RISC ont chacun des avantages et des inconvénients, qui rendent le RISC/CISC adapté ou pas selon la situation. Par exemple, on mettra souvent un processeur RISC dans un système embarqué, devant consommer très peu et être peu cher. Mais de nos jours, la performance d'un processeur dépend assez peu du fait que le processeur soit un RISC ou un CISC. Les processeurs modernes disposent de tellement de transistors qu'implémenter des instructions complexes a un impact négligeable. Pour donner une référence, le support des instructions complexes sur les processeurs x86 est estimé à 2 à 3% des transistors de la puce, alors que 50% du budget en transistor des processeurs modernes part dans le cache. Les processeurs actuels sont de plus en plus difficiles à ranger dans des catégories précises. Les processeurs actuels sont conçus d'une façon plus pragmatique : au lieu de respecter à la lettre les principes du RISC et du CISC, on préfère intégrer les instructions qui fonctionnent, peu importe qu'elles viennent de processeurs purement RISC ou CISC. Par exemple, les processeurs ARM récents ont intégré des instructions de copie mémoire, qui sont assez ''borderline'' et sont plutôt attendues sur les processeurs CISC. En parallèle des architectures CISC et RISC, d'autres classes de jeux d'instructions sont apparus. Nous verrons beaucoup de jeux d'instructions dans la suite du cours. Entre les architectures à capacité, les processeurs VLIW, les architectures ''dataflow'', les processeurs SIMD, les ''Digital Signal Processor'', les ''transport-triggered architectures'', les architectures associatives, les architectures neuromorphiques et les achitectures systoliques, il y aura de quoi faire. La plupart de ces jeux d'instructions sont implantés dans des processeurs spécialisés, qu'on fabrique pour une utilisation particulière. Malheureusement, nous ne pouvons pas en parler pour le moment. La suite de ce chapitre va se focaliser sur des jeu d'instruction proches du RISC ou du CISC. ==Les processeurs avec plusieurs jeu d'instruction== Il faut signaler que certains processeur supportent plusieurs jeu d'instruction à la fois. Les processeurs x86 des PC sont dans ce cas, mais aussi les processeurs ARM utilisés partout ailleurs. ===La compatibilité entre 32 et 64 bits=== Le cas des processeurs x86 est assez simple à comprendre. Ils ont beaucoup évolués dans le temps, commençant comme des processeurs 8 bits, puis 16 bits, suivis par des 32 bits et enfin des processeurs 64 bits. Et à chaque transition, le jeu d'instruction a évolué. Le x86 8 bit n'est pas le même que le x86 16 bits, qui est lui-même différent du x86 32 bits, etc. La raison est que pour étendre les adresses, il fallait modifier l'encodage des instructions. Et quitte à modifier l'encodage des instructions, autant en rajouter d'autres, et supprimer des instructions devenus inutiles. Une autre raison est qu'Intel et AMD ont rajouté des registres lors du passage au 32 bits, et idem lors du passage au 64 bits. Le jeu d'instruction x86 16 bits avait trop peu de registres pour des besoins actuels, ce qui fait qu'Intel et AMD ont décidé d'en rajouter. Et vu que rajouter des registres impactait l'encodage des instructions, cela ne pouvait se faire qu'à l'occasion d'un changement de jeu d'instruction. Une dernière raison est que la mémoire virtuelle n'est pas gérée de la même manière entre les processeurs 16, 32 et 64 bits. Mais nous ne pouvons en parler à ce stade du cours. Mais là encore, cela impacte le jeu d'instruction et le modèle mémoire du processeur, bien que d'une manière assez limitée. Cela revient à ajouter des registres, en supprimer d'autres, modifier l'interprétation de registres existants, etc. Ces changements se sont fait progressivement, ce qui fait que les jeux d'instruction 8/16/32/64 bits se ressemblent beaucoup, mais au point d'être parfaitement compatible. Exécutez un code prévu pour un CPU 16 bits sur un CPU 32 bits, vous aurez des problèmes. Pour éviter cela, les processeurs x86 supportent les différents modes d’instruction existants, par souci de compatibilité. Il est possible de configurer un processeur x86 en mode 16 bits, pour lui faire exécuter du code 16 bits directement, sans interprétation ou émulation d'instruction via exceptions matérielles. Ou encore, on peut mettre un CPU 64 bits en mode 32 bits, pour qu'il exécute du code 32 bits. Les modes en question sont : * le mode réel en 8 et 16 bits ; * le mode protégé 16 bit et sa variante 32 bits ; * le mode long en 64 bits, avec deux sous-modes de compatibilité pour exécuter du code 16 et 32 bits. Si l'ordinateur dispose d'un BIOS, il est démarré en mode réel, puis il passe en mode long pour laisser la main à un système d'exploitation 64 bits. Le mode protégé n'est pas utilisé, sauf éventuellement pour des besoins d'émulation. Si l'ordinateur dispose d'un UEFI, le processeur est lancé en mode long et y reste, que ce soit pour l'UEFI ou le système d'exploitation ou autre. Les modes réels et protégés ne sont utilisés que quand il faut émuler du vieux code. Il existe d'autres modes, comme le ''System Management Mode'' qui laisse la main au BIOS/UEFI, et un mode ''Virtual 8086'' qu'on ne peut pas expliquer à ce moment. Les deux seront cependant détaillés dans quelques chapitres. Le ''System Management Mode'' sera abordé dans le chapitre sur les interruptions, le mode ''Virtual 8086'' sera abordé dans le chapitre sur la virtualisation accélérée en matériel. [[File:AMD64StateDiagram.svg|centre|vignette|upright=2|Modes supportés par les CPU x86.]] Les processeurs ARM sont aussi dans ce cas. Leur jeu d'instruction de base a beaucoup évolué dans le temps. L'ARM de base était un jeu d'instruction 32 bits, mais une variante 64 bits a vu le jour par la suite. Comme pour les CPU x86, les CPU ARM 64 bits supportent deux modes d'exécution : un 32 bits et un 64 bits, là encore pour des questions de compatibilité. ===Les jeux d'instruction compacts des processeurs RISC=== Quelques CPU RISC 32 bits supportaient un '''jeu d'instruction compact''', en plus de leur d'instruction classique. Il s'agissait d'un second jeu d’instruction avec une densité de code excellente, qui avait pour but de diminuer la taille des programmes. La technique a été introduite sur des CPU 32 bits, et le jeu d'instruction utilisait des instructions codées sur 16 bits. L'exemple type est celui des Les processeurs ARM, qui incorporent un jeu d'instruction compact appelé ''thumb'', que nous allons détailler dans ce qui suit. Le mode ''thumb'' était présent sur les processeurs ARM 32 bits, mais il a été conservé lors du passage au 64 bits. Le ''thumb'' encode les instructions sur 16 bits, soit deux fois moins que l'ARM 32 bits normal. Il ne s'agissait pas d'un jeu d'instruction totalement séparé de l'ARM normal, mais d'un sous-ensemble de l'ARM normal, utilisant un encodage différent. Concrètement, toute instruction ''thumb'' 16 bits a un équivalent en ARM 32 bits. Par contre, la réciproque n'est pas vraie. Et l'encodage des deux instructions n'est pas le même, ce qui est évident vu que les instructions ''thumb'' sont encodées sur 16 bits et les équivalentes sur 32. Les instructions ''thumb'' ont des limitations que les instructions ARM 32 bits n'ont pas. Par exemple, les instructions ''thumb'' ont un accès restreint aux registres de status et du co-processeur. De plus, la majorité des instructions ''thumb'' n'ont accès qu'à la moitié des registres du processeur. Les instructions arithmétiques et les décalages sont séparés en mode ''thumb'', alors que chaque instructions arithmétiques peut ajouter un décalage à une opérande en mode ARM 32 bits. Les instructions pour le co-processeur ne sont pas disponibles en ''thumb''. Autre exemple : la gestion des instructions à prédicats. L'ARM 32 bits normal utilise la prédication totale, à savoir que toutes les instructions s'exécutent ou non selon la valeur d'un résultat de comparaison, stocké dans un registre de prédicat. Toute instruction encode donc quelques bits pour choisir ce registre. Cela est supprimé avec ''thumb''. A part quelques branchements, les instructions ne sont pas prédicatées et s'exécutent inconditionnellement. Les deux jeux d'instruction ont un mode d'exécution chacun, ce qui veut dire que le processeur est configuré pour fonctionner en mode ''thumb'' ou en mode ARM 32 bits. En clair, on ne peut pas mélanger les deux jeu d'instructions en même temps. La raison est qu'une même suite de bit correspondait soit à une instruction ARM normale, soit à deux instructions thumbs. Pour faire la différence, il faut préciser dans quel mode d'exécution le CPU est : mode ARM ou mode ''thumb''. Le processeur interprète les instructions correctement en tenant compte de ce mode. Niveau implémentation, la gestion des instructions ''thumb'' est assez simple : le processeur convertit les instructions ''thumb'' en leur équivalent ARM 32 bits, juste après les avoir chargées. Une seconde version du jeu d'instruction ''thumb'' a vu le jour, sur les processeurs ARMv6T2, avec ''thumb-2''. Elle avait pour particularité d'utiliser des instructions de taille variable. Rien d'aussi développé que ce qu'on a sur les CPU CISC, comme les CPU x86. Les instructions ARM ''thumb-2'' faisaient soit 16 bits, soit 32 bits. Concrètement, les instructions 16 bits de ''thumb-1'' étaient reprises à l'identique, ''thumb-2'' se contentait d'ajouter des instructions en plus codées sur 32 bits. Les instructions ajoutées étaient des instruction mémoire, des instructions de configuration du CPU, des instructions de manipulation de bit, et quelques autres. Un ajout particulièrement notable est l'ajout d'une instruction IT, qui active l’exécution conditionnelle des instructions suivantes. L'instruction teste une condition et calcule un prédicat, qui est ensuite utilisé pour décider de l'exécution des instructions suivantes. L'exécution conditionnelle marche jusqu'à 4 instructions consécutives. Le nombre exact est configurable et va de 1 à 4 instructions consécutives après l'instruction IT. La condition est configurable pour les 1 à 4 instructions : chaque instruction peut s'exécuter si la condition est vraie, ou au contraire fausse. Un masque de 4 bits décide de quelle condition utiliser pour chaque instruction. Il y a un bit par instruction, qui vaut 1 si la condition doit être vérifiée, 0 si on veut la condition inverse. Il faut noter que quelques processeurs ARM implémentent uniquement le jeu d'instruction ''thumb-1/2'', pas l'ARM 32 bits normal. Ce sont des processeurs faible performance, à destination de systèmes embarqués, qui ont besoin d'une densité de code correcte, comme les CPU ARM Cortex série M. : Il est arrivé que certains CPU ARM en supportent trois : le jeu d'instruction ARM 32 bits classique, le mode ''Thumb'' qu'on décrira plus bas, et une extension nommée Jazelle JBX qui accélérait les programmes écrits en Java (elle exécutait du ''bytecode'' JAVA sur le processeur, nous détaillerons cela dans un autre chapitre). Les CPU ARM n'étaient pas les seuls à utiliser la même technique. Les CPU SuperH d'Hitachi ont été les premiers à implémenter cette technique, avant ARM. Lors du passage de 16 à 32 bits, ces CPU Hitachi ont ajouté un jeu d'instruction de 16 bits à leurs CPU 32 bits, très similaire au jeu d'instruction 16 bits d'avant. Et c'est ce jeu d'instruction compact qui a servi d'inspiration à ARM. Les CPU MIPS ont tenté la même approche, avec l'inclusion du jeu d’instruction MIPS16e, de 16 bits lui aussi. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=L'encodage des instructions | prevText=L'encodage des instructions | next=La pile d'appel et les fonctions | nextText=La pile d'appel et les fonctions }} </noinclude> mbuss74ppzkemthul780uppegxb2xzl Fonctionnement d'un ordinateur/Sommaire 0 69596 773613 773301 2026-09-29T20:27:40Z Mewtow 31375 /* L’exécution dans le désordre */ 773613 wikitext text/x-wiki __NOTOC__ * [[Fonctionnement d'un ordinateur/Introduction|Introduction]] ==Le codage des informations== * [[Fonctionnement d'un ordinateur/L'encodage des données|L'encodage des données]] * [[Fonctionnement d'un ordinateur/Le codage des nombres|Le codage des nombres]] * [[Fonctionnement d'un ordinateur/Les codes de détection/correction d'erreur|Les codes de détection/correction d'erreur]] ==Les circuits électroniques== * [[Fonctionnement d'un ordinateur/Les portes logiques|Les portes logiques]] ===Les circuits combinatoires=== * [[Fonctionnement d'un ordinateur/Les circuits combinatoires|Les circuits combinatoires]] * [[Fonctionnement d'un ordinateur/Les circuits de masquage|Les circuits de masquage]] * [[Fonctionnement d'un ordinateur/Les circuits de sélection|Les circuits de sélection]] * [[Fonctionnement d'un ordinateur/Les circuits incrémenteurs/décrémenteurs|Les circuits incrémenteurs/décrémenteurs]] ===Les circuits séquentiels=== * [[Fonctionnement d'un ordinateur/Les bascules : des mémoires de 1 bit|Les bascules : des mémoires de 1 bit]] * [[Fonctionnement d'un ordinateur/Les circuits synchrones et asynchrones|Les circuits synchrones et asynchrones]] * [[Fonctionnement d'un ordinateur/Les registres et mémoires adressables|Les registres et mémoires adressables]] * [[Fonctionnement d'un ordinateur/Les compteurs et timers|Les compteurs et timers]] * [[Fonctionnement d'un ordinateur/Les registres à décalage et les LSFR|Les registres à décalage et les LSFR]] ===Les circuits de calcul et de comparaison=== * [[Fonctionnement d'un ordinateur/Les circuits de décalage et de rotation|Les circuits de décalage et de rotation]] * [[Fonctionnement d'un ordinateur/Les circuits pour l'addition et la soustraction|Les circuits pour l'addition et la soustraction]] * [[Fonctionnement d'un ordinateur/Les circuits de comparaison|Les circuits de comparaison]] * [[Fonctionnement d'un ordinateur/Les unités arithmétiques et logiques entières (simples)|Les unités arithmétiques et logiques entières (simples)]] * [[Fonctionnement d'un ordinateur/Les circuits pour l'addition multiopérande|Les circuits pour l'addition multiopérande]] * [[Fonctionnement d'un ordinateur/Les circuits pour la multiplication et la division|Les circuits pour la multiplication et la division]] * [[Fonctionnement d'un ordinateur/Les circuits de calcul logique et bit à bit|Les circuits de calcul logique et bit à bit]] * [[Fonctionnement d'un ordinateur/Les circuits de calcul flottant|Les circuits de calcul flottant]] * [[Fonctionnement d'un ordinateur/Les circuits de calcul trigonométriques|Les circuits de calcul trigonométriques]] ===Les circuits intégrés à semi-conducteurs=== * [[Fonctionnement d'un ordinateur/Les transistors et portes logiques|Les transistors et portes logiques]] * [[Fonctionnement d'un ordinateur/Les circuits intégrés|Les circuits intégrés]] * [[Fonctionnement d'un ordinateur/L'interface électrique entre circuits intégrés et bus|L'interface électrique entre circuits intégrés et bus]] ==L'architecture d'un ordinateur== * [[Fonctionnement d'un ordinateur/L'architecture de base d'un ordinateur|L'architecture de base d'un ordinateur]] * [[Fonctionnement d'un ordinateur/La hiérarchie mémoire|La hiérarchie mémoire]] * [[Fonctionnement d'un ordinateur/La performance d'un ordinateur|La performance d'un ordinateur]] * [[Fonctionnement d'un ordinateur/La loi de Moore et les tendances technologiques|La loi de Moore et les tendances technologiques]] * [[Fonctionnement d'un ordinateur/Les techniques de réduction de la consommation électrique d'un processeur|Les techniques de réduction de la consommation électrique d'un processeur]] ==Les bus électroniques et la carte mère== * [[Fonctionnement d'un ordinateur/La carte mère, chipset et BIOS|La carte mère, chipset et BIOS]] * [[Fonctionnement d'un ordinateur/Les bus et liaisons point à point (généralités)|Les bus et liaisons point à point (généralités)]] * [[Fonctionnement d'un ordinateur/Les encodages spécifiques aux bus|Les encodages spécifiques aux bus]] * [[Fonctionnement d'un ordinateur/Les liaisons point à point|Les liaisons point à point]] * [[Fonctionnement d'un ordinateur/Les bus électroniques|Les bus électroniques]] * [[Fonctionnement d'un ordinateur/Quelques exemples de bus et de liaisons point à point|Quelques exemples de bus et de liaisons point à point]] ==Les mémoires RAM/ROM== * [[Fonctionnement d'un ordinateur/Les différents types de mémoires|Les différents types de mémoires]] * [[Fonctionnement d'un ordinateur/L'interface d'une mémoire électronique|L'interface d'une mémoire électronique]] * [[Fonctionnement d'un ordinateur/Le bus mémoire|Le bus mémoire]] ===La micro-architecture d'une mémoire adressable=== * [[Fonctionnement d'un ordinateur/Les cellules mémoires|Les cellules mémoires]] * [[Fonctionnement d'un ordinateur/Le plan mémoire|Le plan mémoire]] * [[Fonctionnement d'un ordinateur/Contrôleur mémoire interne|Le contrôleur mémoire interne]] * [[Fonctionnement d'un ordinateur/Mémoires évoluées|Les mémoires évoluées]] ===Les mémoires primaires=== * [[Fonctionnement d'un ordinateur/Les mémoires ROM|Les mémoires ROM : Mask ROM, PROM, EPROM, EEPROM, Flash]] * [[Fonctionnement d'un ordinateur/Les mémoires SRAM synchrones|Les mémoires SRAM synchrones]] * [[Fonctionnement d'un ordinateur/Les mémoires RAM dynamiques (DRAM)|Les mémoires RAM dynamiques (DRAM)]] * [[Fonctionnement d'un ordinateur/Contrôleur mémoire externe|Le contrôleur mémoire externe]] ===Les mémoires exotiques=== * [[Fonctionnement d'un ordinateur/Les mémoires associatives|Les mémoires associatives]] * [[Fonctionnement d'un ordinateur/Les mémoires FIFO et LIFO|Les mémoires FIFO et LIFO]] ==Le processeur== ===L'architecture externe=== * [[Fonctionnement d'un ordinateur/Langage machine et assembleur|Langage machine et assembleur]] * [[Fonctionnement d'un ordinateur/Les registres du processeur|Les registres du processeur]] * [[Fonctionnement d'un ordinateur/Le modèle mémoire : alignement et boutisme|Le modèle mémoire : alignement et boutisme]] * [[Fonctionnement d'un ordinateur/Les modes d'adressage|Les modes d'adressage]] * [[Fonctionnement d'un ordinateur/L'encodage des instructions|L'encodage des instructions]] * [[Fonctionnement d'un ordinateur/Les jeux d'instructions|Les jeux d'instructions]] * [[Fonctionnement d'un ordinateur/La pile d'appel et les fonctions|La pile d'appel et les fonctions]] * [[Fonctionnement d'un ordinateur/Les interruptions et exceptions|Les interruptions et exceptions]] ===La micro-architecture=== * [[Fonctionnement d'un ordinateur/Les composants d'un processeur|Les composants d'un processeur]] * [[Fonctionnement d'un ordinateur/Le chemin de données|Le chemin de données]] * [[Fonctionnement d'un ordinateur/L'unité de chargement et le program counter|L'unité de chargement et le program counter]] * [[Fonctionnement d'un ordinateur/L'unité de contrôle|L'unité de contrôle]] * [[Fonctionnement d'un ordinateur/L'implémentation matérielle des branchements|L'implémentation matérielle des branchements]] ===Les jeux d'instruction anciens, avant les registres généraux ou exotiques=== * [[Fonctionnement d'un ordinateur/Les architectures à accumulateur|Les architectures à accumulateur]] * [[Fonctionnement d'un ordinateur/Les architectures à pile et mémoire-mémoire|Les architectures à pile et mémoire-mémoire]] * [[Fonctionnement d'un ordinateur/Les processeurs 8 bits et moins|Les processeurs 8 bits et moins]] ===L'espace d'adressage du processeur et la multiprogrammation=== * [[Fonctionnement d'un ordinateur/L'espace d'adressage du processeur|L'espace d'adressage du processeur]] * [[Fonctionnement d'un ordinateur/L'abstraction mémoire et la mémoire virtuelle|L'abstraction mémoire et la mémoire virtuelle]] ==Les entrées-sorties et périphériques== * [[Fonctionnement d'un ordinateur/Les méthodes de synchronisation entre processeur et périphériques|Les méthodes de synchronisation entre processeur et périphériques]] * [[Fonctionnement d'un ordinateur/L'adressage des périphériques|L'adressage des périphériques]] * [[Fonctionnement d'un ordinateur/Les périphériques et les cartes d'extension|Les périphériques et les cartes d'extension]] ==Les mémoires de stockage== * [[Fonctionnement d'un ordinateur/Les mémoires de masse : généralités|Les mémoires de masse : généralités]] * [[Fonctionnement d'un ordinateur/Les disques durs|Les disques durs]] * [[Fonctionnement d'un ordinateur/Les solid-state drives|Les solid-state drives]] * [[Fonctionnement d'un ordinateur/Les disques optiques|Les disques optiques]] * [[Fonctionnement d'un ordinateur/Compléments sur les mémoires de masse|Compléments sur les mémoires de masse]] ==La ou les mémoires caches== * [[Fonctionnement d'un ordinateur/Les mémoires cache|Les mémoires cache]] * [[Fonctionnement d'un ordinateur/Le préchargement|Le préchargement]] * [[Fonctionnement d'un ordinateur/Le Translation Lookaside Buffer|Le ''Translation Lookaside Buffer'']] ==Le parallélisme d’instructions== * [[Fonctionnement d'un ordinateur/Le pipeline|Le pipeline]] ===Les branchements et le ''front-end''=== * [[Fonctionnement d'un ordinateur/La prédiction de branchement|La prédiction de branchement]] * [[Fonctionnement d'un ordinateur/Les optimisations du chargement des instructions|Les optimisations du chargement des instructions]] ===Les pipelines multicycles simples=== * [[Fonctionnement d'un ordinateur/Les pipelines multicycles|Les pipelines multicycles]] * [[Fonctionnement d'un ordinateur/L'émission dans l'ordre des instructions|L'émission dans l'ordre des instructions]] * [[Fonctionnement d'un ordinateur/Le contournement (data forwarding)|Le contournement (data forwarding)]] * [[Fonctionnement d'un ordinateur/Les premiers processeurs Intel|Les premiers processeurs Intel]] ===L’exécution dans le désordre=== * [[Fonctionnement d'un ordinateur/L'exécution dans le désordre|L'exécution dans le désordre]] * [[Fonctionnement d'un ordinateur/Le renommage de registres|Le renommage de registres]] * [[Fonctionnement d'un ordinateur/Le scoreboarding et l'algorithme de Tomasulo|Le scoreboarding et l'algorithme de Tomasulo]] * [[Fonctionnement d'un ordinateur/Les implémentations modernes de l'OOO|Les implémentations modernes de l'OOO]] ===Les optimisations des accès mémoire=== * [[Fonctionnement d'un ordinateur/La désambiguïsation mémoire|La désambiguïsation mémoire]] * [[Fonctionnement d'un ordinateur/Le parallélisme mémoire|Le parallélisme mémoire]] ===L'émission multiple=== * [[Fonctionnement d'un ordinateur/Les processeurs superscalaires|Les processeurs superscalaires]] * [[Fonctionnement d'un ordinateur/Les microarchitectures pour le x86 : haute performance|Les microarchitectures pour le x86 : haute performance]] * [[Fonctionnement d'un ordinateur/Les microarchitectures pour le x86 : basse consommation|Les microarchitectures pour le x86 : basse consommation]] * [[Fonctionnement d'un ordinateur/Les processeurs VLIW et EPIC|Les processeurs VLIW et EPIC]] * [[Fonctionnement d'un ordinateur/Les architectures dataflow|Les architectures dataflow]] ==Les architectures parallèles== * [[Fonctionnement d'un ordinateur/Les architectures parallèles|Les architectures parallèles]] * [[Fonctionnement d'un ordinateur/Architectures multiprocesseurs et multicœurs|Les architectures multiprocesseurs et multicœurs]] * [[Fonctionnement d'un ordinateur/Architectures multithreadées et Hyperthreading|Les architectures multithreadées et Hyperthreading]] * [[Fonctionnement d'un ordinateur/Les architectures à parallélisme de données|Les architectures à parallélisme de données]] * [[Fonctionnement d'un ordinateur/La cohérence des caches|La cohérence des caches]] * [[Fonctionnement d'un ordinateur/Les sections critiques et le modèle mémoire|Les sections critiques et le modèle mémoire]] ==Annexes== ===Les nombres flottants : FPUs et coprocesseurs=== * [[Fonctionnement d'un ordinateur/Un exemple de jeu d'instruction : l'extension x87|Un exemple de jeu d'instruction : l'extension x87]] * [[Fonctionnement d'un ordinateur/Les coprocesseurs : FPU et IO|Les coprocesseurs : FPU et IO]] ===Les jeux d’instruction spécialisés=== * [[Fonctionnement d'un ordinateur/Les ISA optimisés pour la compilation/interprétation|Les ISA optimisés pour la compilation/interprétation]] * [[Fonctionnement d'un ordinateur/Les processeurs de traitement du signal|Les processeurs de traitement du signal]] * [[Fonctionnement d'un ordinateur/Les architectures actionnées par déplacement|Les architectures actionnées par déplacement]] ===Réseaux de neurones et accélérateurs d'IA=== * [[Fonctionnement d'un ordinateur/Les architectures systoliques|Les architectures systoliques]] * [[Fonctionnement d'un ordinateur/Les architectures neuromorphiques|Les réseaux de neurones matériels]] ===Les autres annexes=== * [[Fonctionnement d'un ordinateur/L'accélération matérielle de la virtualisation|L'accélération matérielle de la virtualisation]] * [[Fonctionnement d'un ordinateur/Le matériel réseau|Le matériel réseau]] * [[Fonctionnement d'un ordinateur/La tolérance aux pannes|La tolérance aux pannes]] * [[Fonctionnement d'un ordinateur/Les circuits de conversion analogique-numérique|Les circuits de conversion analogique-numérique]] * [[Fonctionnement d'un ordinateur/Les ordinateurs de première génération : tubes à vide et mémoires|Les ordinateurs de première génération : tubes à vide et mémoires]] * [[Fonctionnement d'un ordinateur/Les ordinateurs à encodages non-binaires|Les ordinateurs à encodages non-binaires]] * [[Fonctionnement d'un ordinateur/Les circuits réversibles|Les circuits réversibles]] {{autocat}} 0pz7zg4j2v72z2x5gxnv81u9hoombkp 773666 773613 2026-09-29T22:19:19Z Mewtow 31375 /* L’exécution dans le désordre */ 773666 wikitext text/x-wiki __NOTOC__ * [[Fonctionnement d'un ordinateur/Introduction|Introduction]] ==Le codage des informations== * [[Fonctionnement d'un ordinateur/L'encodage des données|L'encodage des données]] * [[Fonctionnement d'un ordinateur/Le codage des nombres|Le codage des nombres]] * [[Fonctionnement d'un ordinateur/Les codes de détection/correction d'erreur|Les codes de détection/correction d'erreur]] ==Les circuits électroniques== * [[Fonctionnement d'un ordinateur/Les portes logiques|Les portes logiques]] ===Les circuits combinatoires=== * [[Fonctionnement d'un ordinateur/Les circuits combinatoires|Les circuits combinatoires]] * [[Fonctionnement d'un ordinateur/Les circuits de masquage|Les circuits de masquage]] * [[Fonctionnement d'un ordinateur/Les circuits de sélection|Les circuits de sélection]] * [[Fonctionnement d'un ordinateur/Les circuits incrémenteurs/décrémenteurs|Les circuits incrémenteurs/décrémenteurs]] ===Les circuits séquentiels=== * [[Fonctionnement d'un ordinateur/Les bascules : des mémoires de 1 bit|Les bascules : des mémoires de 1 bit]] * [[Fonctionnement d'un ordinateur/Les circuits synchrones et asynchrones|Les circuits synchrones et asynchrones]] * [[Fonctionnement d'un ordinateur/Les registres et mémoires adressables|Les registres et mémoires adressables]] * [[Fonctionnement d'un ordinateur/Les compteurs et timers|Les compteurs et timers]] * [[Fonctionnement d'un ordinateur/Les registres à décalage et les LSFR|Les registres à décalage et les LSFR]] ===Les circuits de calcul et de comparaison=== * [[Fonctionnement d'un ordinateur/Les circuits de décalage et de rotation|Les circuits de décalage et de rotation]] * [[Fonctionnement d'un ordinateur/Les circuits pour l'addition et la soustraction|Les circuits pour l'addition et la soustraction]] * [[Fonctionnement d'un ordinateur/Les circuits de comparaison|Les circuits de comparaison]] * [[Fonctionnement d'un ordinateur/Les unités arithmétiques et logiques entières (simples)|Les unités arithmétiques et logiques entières (simples)]] * [[Fonctionnement d'un ordinateur/Les circuits pour l'addition multiopérande|Les circuits pour l'addition multiopérande]] * [[Fonctionnement d'un ordinateur/Les circuits pour la multiplication et la division|Les circuits pour la multiplication et la division]] * [[Fonctionnement d'un ordinateur/Les circuits de calcul logique et bit à bit|Les circuits de calcul logique et bit à bit]] * [[Fonctionnement d'un ordinateur/Les circuits de calcul flottant|Les circuits de calcul flottant]] * [[Fonctionnement d'un ordinateur/Les circuits de calcul trigonométriques|Les circuits de calcul trigonométriques]] ===Les circuits intégrés à semi-conducteurs=== * [[Fonctionnement d'un ordinateur/Les transistors et portes logiques|Les transistors et portes logiques]] * [[Fonctionnement d'un ordinateur/Les circuits intégrés|Les circuits intégrés]] * [[Fonctionnement d'un ordinateur/L'interface électrique entre circuits intégrés et bus|L'interface électrique entre circuits intégrés et bus]] ==L'architecture d'un ordinateur== * [[Fonctionnement d'un ordinateur/L'architecture de base d'un ordinateur|L'architecture de base d'un ordinateur]] * [[Fonctionnement d'un ordinateur/La hiérarchie mémoire|La hiérarchie mémoire]] * [[Fonctionnement d'un ordinateur/La performance d'un ordinateur|La performance d'un ordinateur]] * [[Fonctionnement d'un ordinateur/La loi de Moore et les tendances technologiques|La loi de Moore et les tendances technologiques]] * [[Fonctionnement d'un ordinateur/Les techniques de réduction de la consommation électrique d'un processeur|Les techniques de réduction de la consommation électrique d'un processeur]] ==Les bus électroniques et la carte mère== * [[Fonctionnement d'un ordinateur/La carte mère, chipset et BIOS|La carte mère, chipset et BIOS]] * [[Fonctionnement d'un ordinateur/Les bus et liaisons point à point (généralités)|Les bus et liaisons point à point (généralités)]] * [[Fonctionnement d'un ordinateur/Les encodages spécifiques aux bus|Les encodages spécifiques aux bus]] * [[Fonctionnement d'un ordinateur/Les liaisons point à point|Les liaisons point à point]] * [[Fonctionnement d'un ordinateur/Les bus électroniques|Les bus électroniques]] * [[Fonctionnement d'un ordinateur/Quelques exemples de bus et de liaisons point à point|Quelques exemples de bus et de liaisons point à point]] ==Les mémoires RAM/ROM== * [[Fonctionnement d'un ordinateur/Les différents types de mémoires|Les différents types de mémoires]] * [[Fonctionnement d'un ordinateur/L'interface d'une mémoire électronique|L'interface d'une mémoire électronique]] * [[Fonctionnement d'un ordinateur/Le bus mémoire|Le bus mémoire]] ===La micro-architecture d'une mémoire adressable=== * [[Fonctionnement d'un ordinateur/Les cellules mémoires|Les cellules mémoires]] * [[Fonctionnement d'un ordinateur/Le plan mémoire|Le plan mémoire]] * [[Fonctionnement d'un ordinateur/Contrôleur mémoire interne|Le contrôleur mémoire interne]] * [[Fonctionnement d'un ordinateur/Mémoires évoluées|Les mémoires évoluées]] ===Les mémoires primaires=== * [[Fonctionnement d'un ordinateur/Les mémoires ROM|Les mémoires ROM : Mask ROM, PROM, EPROM, EEPROM, Flash]] * [[Fonctionnement d'un ordinateur/Les mémoires SRAM synchrones|Les mémoires SRAM synchrones]] * [[Fonctionnement d'un ordinateur/Les mémoires RAM dynamiques (DRAM)|Les mémoires RAM dynamiques (DRAM)]] * [[Fonctionnement d'un ordinateur/Contrôleur mémoire externe|Le contrôleur mémoire externe]] ===Les mémoires exotiques=== * [[Fonctionnement d'un ordinateur/Les mémoires associatives|Les mémoires associatives]] * [[Fonctionnement d'un ordinateur/Les mémoires FIFO et LIFO|Les mémoires FIFO et LIFO]] ==Le processeur== ===L'architecture externe=== * [[Fonctionnement d'un ordinateur/Langage machine et assembleur|Langage machine et assembleur]] * [[Fonctionnement d'un ordinateur/Les registres du processeur|Les registres du processeur]] * [[Fonctionnement d'un ordinateur/Le modèle mémoire : alignement et boutisme|Le modèle mémoire : alignement et boutisme]] * [[Fonctionnement d'un ordinateur/Les modes d'adressage|Les modes d'adressage]] * [[Fonctionnement d'un ordinateur/L'encodage des instructions|L'encodage des instructions]] * [[Fonctionnement d'un ordinateur/Les jeux d'instructions|Les jeux d'instructions]] * [[Fonctionnement d'un ordinateur/La pile d'appel et les fonctions|La pile d'appel et les fonctions]] * [[Fonctionnement d'un ordinateur/Les interruptions et exceptions|Les interruptions et exceptions]] ===La micro-architecture=== * [[Fonctionnement d'un ordinateur/Les composants d'un processeur|Les composants d'un processeur]] * [[Fonctionnement d'un ordinateur/Le chemin de données|Le chemin de données]] * [[Fonctionnement d'un ordinateur/L'unité de chargement et le program counter|L'unité de chargement et le program counter]] * [[Fonctionnement d'un ordinateur/L'unité de contrôle|L'unité de contrôle]] * [[Fonctionnement d'un ordinateur/L'implémentation matérielle des branchements|L'implémentation matérielle des branchements]] ===Les jeux d'instruction anciens, avant les registres généraux ou exotiques=== * [[Fonctionnement d'un ordinateur/Les architectures à accumulateur|Les architectures à accumulateur]] * [[Fonctionnement d'un ordinateur/Les architectures à pile et mémoire-mémoire|Les architectures à pile et mémoire-mémoire]] * [[Fonctionnement d'un ordinateur/Les processeurs 8 bits et moins|Les processeurs 8 bits et moins]] ===L'espace d'adressage du processeur et la multiprogrammation=== * [[Fonctionnement d'un ordinateur/L'espace d'adressage du processeur|L'espace d'adressage du processeur]] * [[Fonctionnement d'un ordinateur/L'abstraction mémoire et la mémoire virtuelle|L'abstraction mémoire et la mémoire virtuelle]] ==Les entrées-sorties et périphériques== * [[Fonctionnement d'un ordinateur/Les méthodes de synchronisation entre processeur et périphériques|Les méthodes de synchronisation entre processeur et périphériques]] * [[Fonctionnement d'un ordinateur/L'adressage des périphériques|L'adressage des périphériques]] * [[Fonctionnement d'un ordinateur/Les périphériques et les cartes d'extension|Les périphériques et les cartes d'extension]] ==Les mémoires de stockage== * [[Fonctionnement d'un ordinateur/Les mémoires de masse : généralités|Les mémoires de masse : généralités]] * [[Fonctionnement d'un ordinateur/Les disques durs|Les disques durs]] * [[Fonctionnement d'un ordinateur/Les solid-state drives|Les solid-state drives]] * [[Fonctionnement d'un ordinateur/Les disques optiques|Les disques optiques]] * [[Fonctionnement d'un ordinateur/Compléments sur les mémoires de masse|Compléments sur les mémoires de masse]] ==La ou les mémoires caches== * [[Fonctionnement d'un ordinateur/Les mémoires cache|Les mémoires cache]] * [[Fonctionnement d'un ordinateur/Le préchargement|Le préchargement]] * [[Fonctionnement d'un ordinateur/Le Translation Lookaside Buffer|Le ''Translation Lookaside Buffer'']] ==Le parallélisme d’instructions== * [[Fonctionnement d'un ordinateur/Le pipeline|Le pipeline]] ===Les branchements et le ''front-end''=== * [[Fonctionnement d'un ordinateur/La prédiction de branchement|La prédiction de branchement]] * [[Fonctionnement d'un ordinateur/Les optimisations du chargement des instructions|Les optimisations du chargement des instructions]] ===Les pipelines multicycles simples=== * [[Fonctionnement d'un ordinateur/Les pipelines multicycles|Les pipelines multicycles]] * [[Fonctionnement d'un ordinateur/L'émission dans l'ordre des instructions|L'émission dans l'ordre des instructions]] * [[Fonctionnement d'un ordinateur/Le contournement (data forwarding)|Le contournement (data forwarding)]] * [[Fonctionnement d'un ordinateur/Les premiers processeurs Intel|Les premiers processeurs Intel]] ===L’exécution dans le désordre=== * [[Fonctionnement d'un ordinateur/L'exécution dans le désordre|L'exécution dans le désordre]] * [[Fonctionnement d'un ordinateur/Le renommage de registres|Le renommage de registres]] * [[Fonctionnement d'un ordinateur/Les implémentations modernes de l'OOO|Les implémentations modernes de l'OOO]] * [[Fonctionnement d'un ordinateur/Le scoreboarding et l'algorithme de Tomasulo|Le scoreboarding et l'algorithme de Tomasulo]] ===Les optimisations des accès mémoire=== * [[Fonctionnement d'un ordinateur/La désambiguïsation mémoire|La désambiguïsation mémoire]] * [[Fonctionnement d'un ordinateur/Le parallélisme mémoire|Le parallélisme mémoire]] ===L'émission multiple=== * [[Fonctionnement d'un ordinateur/Les processeurs superscalaires|Les processeurs superscalaires]] * [[Fonctionnement d'un ordinateur/Les microarchitectures pour le x86 : haute performance|Les microarchitectures pour le x86 : haute performance]] * [[Fonctionnement d'un ordinateur/Les microarchitectures pour le x86 : basse consommation|Les microarchitectures pour le x86 : basse consommation]] * [[Fonctionnement d'un ordinateur/Les processeurs VLIW et EPIC|Les processeurs VLIW et EPIC]] * [[Fonctionnement d'un ordinateur/Les architectures dataflow|Les architectures dataflow]] ==Les architectures parallèles== * [[Fonctionnement d'un ordinateur/Les architectures parallèles|Les architectures parallèles]] * [[Fonctionnement d'un ordinateur/Architectures multiprocesseurs et multicœurs|Les architectures multiprocesseurs et multicœurs]] * [[Fonctionnement d'un ordinateur/Architectures multithreadées et Hyperthreading|Les architectures multithreadées et Hyperthreading]] * [[Fonctionnement d'un ordinateur/Les architectures à parallélisme de données|Les architectures à parallélisme de données]] * [[Fonctionnement d'un ordinateur/La cohérence des caches|La cohérence des caches]] * [[Fonctionnement d'un ordinateur/Les sections critiques et le modèle mémoire|Les sections critiques et le modèle mémoire]] ==Annexes== ===Les nombres flottants : FPUs et coprocesseurs=== * [[Fonctionnement d'un ordinateur/Un exemple de jeu d'instruction : l'extension x87|Un exemple de jeu d'instruction : l'extension x87]] * [[Fonctionnement d'un ordinateur/Les coprocesseurs : FPU et IO|Les coprocesseurs : FPU et IO]] ===Les jeux d’instruction spécialisés=== * [[Fonctionnement d'un ordinateur/Les ISA optimisés pour la compilation/interprétation|Les ISA optimisés pour la compilation/interprétation]] * [[Fonctionnement d'un ordinateur/Les processeurs de traitement du signal|Les processeurs de traitement du signal]] * [[Fonctionnement d'un ordinateur/Les architectures actionnées par déplacement|Les architectures actionnées par déplacement]] ===Réseaux de neurones et accélérateurs d'IA=== * [[Fonctionnement d'un ordinateur/Les architectures systoliques|Les architectures systoliques]] * [[Fonctionnement d'un ordinateur/Les architectures neuromorphiques|Les réseaux de neurones matériels]] ===Les autres annexes=== * [[Fonctionnement d'un ordinateur/L'accélération matérielle de la virtualisation|L'accélération matérielle de la virtualisation]] * [[Fonctionnement d'un ordinateur/Le matériel réseau|Le matériel réseau]] * [[Fonctionnement d'un ordinateur/La tolérance aux pannes|La tolérance aux pannes]] * [[Fonctionnement d'un ordinateur/Les circuits de conversion analogique-numérique|Les circuits de conversion analogique-numérique]] * [[Fonctionnement d'un ordinateur/Les ordinateurs de première génération : tubes à vide et mémoires|Les ordinateurs de première génération : tubes à vide et mémoires]] * [[Fonctionnement d'un ordinateur/Les ordinateurs à encodages non-binaires|Les ordinateurs à encodages non-binaires]] * [[Fonctionnement d'un ordinateur/Les circuits réversibles|Les circuits réversibles]] {{autocat}} fe4bjelnyk04p2k13iezzr1v8xxavk9 Vocabulaire anglais-français à l'intention des apprenants avancés/T 0 78025 773696 770054 2026-09-30T09:02:24Z Wisdood 66322 773696 wikitext text/x-wiki {{../Index}} === T === * tab (n) : 1/ compte - to keep tabs on sb : surveiller qn, avoir l’œil sur qn ; 2/ mémorandum ; 3/ étiquette (f) ; 4/ (Inf.) onglet ; 5/ - ear-tabs : oreillons (chapeau) * tabby (a) : [chat] tigré(e) * table (n) : 1/ (le meuble) a/ table (f) - to lay the table : mettre la table - autopsy table : table d’autopsie - diaper-changing table : table à langer - dressing table (brit.) : coiffeuse (f) - negotiating table : table des négociations - trestle table : table à tréteaux - vanity table : table de toilette - table cloth : nappe (de table) (aussi tablecloth) - table mat : dessous de plat ; b/ (expressions) - to turn the tables : renverser les rôles, retourner la situation ; 2/ (= couverts, au restaurant) - table for two, please : deux couverts, s’il vous plaît ; 3/ (dans un livre) table (des matières) - table of contents : table des matières ; 4/ tableau - (the) league table : (le) palmarès ; 5/ - (the) water table : (la) nappe phréatique * tablecloth (n) : nappe (f) (aussi table cloth) * tablet (n) (fa p) : 1/ comprimé (n) - sugar-coated tablet : comprimé dragéifié ; 2/ (Inf.) tablette (f) - digitizing tablet : tablette graphique - graphics tablet : tablette graphique - tablet computer : tablette tactile * tablet-friendly (ac) : (Inf.) facile à consulter sur tablette * tabletop (n) : 1/ dessus de table ; 2/ table (f), plateau - tabletop games : (Jeux vidéo) jeux de table, jeux de plateau * tableware (n. ind. sing.) : vaisselle de table * tabloid (n) : quotidien populaire - tabloid journalism : journalisme à sensation * tabular (a) : sous forme de tableau - tabular report : état sous forme de tableau * tachometer (n) : compte-tour (masc.) (syn. revolution counter) * tack (n) : 1/ (Naut.) bord, bordée (f) ; 2/ tactique (f) * tack (v) (intr.) : [navire] louvoyer, tirer des bords * tackle (n) : matériel (syn. gear) * tackle (v) (tr.) : 1/ s’attaquer à, tenter de résoudre (an issue,une question, a problem, un problème, a topic, un sujet) - to tackle a problem : s’attaquer à un problème - to tackle climate change : s'attaquer au dérèglement climatique - to tackle a controversial topic : aborder un sujet controversé ; 2/ saisir (a thief, un voleur), (Rugby) plaquer * tacky (a) : de mauvais goût, minable * tact (n) : tact, doigté (n) * tactful (a) : plein(e) de tact * tactless (a) : dépourvu(e) de tact * tactic (n) : tactique (f) - scare tactic : tactique d’intimidation - well-tried tactic : tactique ayant fait ses preuves * tad (n) : - a tad (loc. adv.) : un petit peu, un tantinet (fam.) - He is a tad immature : Il est un tantinet immature * tag (n) : 1/ étiquette (f) - identifying tag : étiquette d’identification - microwave tag : étiquette hyperfréquence - price tag : a/ étiquette de prix ; b/ prix ; 2/ mot-clé - RF-ID tag : étiquette d’identification par radiofréquence - tag cloud (Inf.) : nuage de mots-clés (syn. word cloud) ; 3/ - skin tag : acrochordon * tag (v) (tr.) : étiqueter, marquer * taikonaut (n) : taïkonaute, astronaute chinois * tail (n) : 1/ queue (f) - pony tail : queue de cheval ; 2/ (Aéro.) empennage, dérive (f) - triple tail : empennage triple dérive, triple dérive ; 3/ - tail pipe : tuyau d’échappement * tailback (n) (brit.) : embouteillage, bouchon * tailcoat (n) : habit * tail gate / tailgate (n) : hayon * tail-gate / tailgate (vc) : 1/ (tr.) conduire trop près du véhicule précédent, coller au train à qn - to be tail-gated : se faire coller au train (fam.), se faire coller au cul (vulg.) ; 2/ (intr.) pique-niquer à l’arrière de sa voiture en stationnement * tail off (v) (intr.) : [personnes, chiens] s’éparpiller, s’égrener, diminuer progressiveemnt * tailor (n) : tailleur (d’habits) * tailor (v) (tr.) : 1/ faire des vêtements pour (qn), habiller (qn) - Who tailors you? : Qui est-ce qui vous habille ? ; 2/ adapter (to, à) - to tailor a machine to the customer's requirements : adapter une machine aux exigences du client * tailpiece (n) : partie finale (f), partie terminale (f), appendice * tailpipe (n) : tuyau d’échappement * tails (n) : pile (au jeu de pile ou face) - Heads or tails? : (litt. face ou pile ?) Pile ou face ? * taint (n) : (fig.) tache (f), souillure (f), déshonneur * taint (v) (tr.) : 1/ infecter, contaminer ; 2/ (fig.) salir, souiller * tainted (a) : 1/ avarié(e) - tainted feed : aliments avariés (pl.) (pour animaux) - tainted food : nourriture avariée (f) ; 2/ contaminé(e) - tainted blood : sang contaminé * Taiwan (n pr.) : Taïwan (sans article défini) * Taiwanese (a) : taïwanais(e) * Tajik (a) : tadjik(e) (sans maj.) * Tajikistan (n pr.) : (le) Tadjikistan * Tajik (n pr.) : Tadjik * Tajiki (n) : (le) tadjik (la langue) * take (n) : 1/ (Cin.) prise de vue (f), prise ; 2/ point de vue, avis, sentiment, interprétation (f) - What’s your take on this case ? : Quel est votre avis sur cette affaire ? * take (v) (took, taken) : 1/ (tr.) prendre - to take a step : prendre une mesure ; 2/ mettre (du temps) - the time it takes : le temps qu’il faut mettre - the time taken : le temps mis ; 3/ (intr.) - to take to + forme -ing : se mettre à + inf. - to take to travelling : se mettre à voyager ; 3/ (tr.) emporter (qch), emmener (qn) (to, à/en) - to take one’s child to the emergency room : emmener son enfant aux urgences ; 4/ (tr.) faire - to take a paternity test : faire un teste de paternité * take-along (mod.) : à emporter, transportable * take away (v) (took, taken) (tr.) : 1/ enlever, retirer - Take away all this clutter! : Vire-moi / Virez-moi tout ce bordel ! ; 2/ prendre livraison de (an order, une commande), emporter (des plats, des boissons) - drinks to take away : boissons à emporter * takeaway (mod.) : à emporter - takeaway food : plats (pl.) à emporter * take back (v) (took, taken) (tr.) : retirer (des paroles) - Take that back! : Retire ce qu tu viens de dire ! * take down (v) (took, taken) (tr.) : 1/ descendre, baisser ; 2/ prendre note de, noter - to take down notes : prendre des notes ; 3/ démonter, enlever * takedown (n) : 1/ enlèvement retrait, ; 2/ démontage, démantèlement (anton. set-up / setup) * take in (v) (took, taken) (tr.) : rouler, abuser * taken (pp de to take) * taken aback (ppa) : surpris(e), interloqué(e), déconcerté(e) * take off (v) (took, taken) : (tr.) retirer - to take oneself off to bed : aller se coucher ; 2/ (intr.) : décoller, prendre son essor * take-off / takeoff (n) : 1/ (Av.) décollage - vertical take-off : décollage vertical - takeoff speed : vitesse de décollage - take-off thrust : poussée au décollage - Takeoff power! : Pleins gaz !, Mets / Mettez les gaz ! (litt. « puissance de décollage ») ; 2/ - a take-off on… : une imitation de, une caricature de, chose qui s’inspire de * take on (v) (took, taken) (tr.) : se mesurer à, affronter * take out (v) (took, taken) (tr.) : 1/ sortir - to take out a knife : sortir un couteau - to take out the garbage : sortir la poubelle - to take the dog out for a walk : sortir promener le chien ; 2/ prendre, contracter - to take out a loan : faire un emprunt ; 3/ prendre, adopter - to take out the French citizenship : adopter la citoyenneté française * take over (v) (took, taken) : 1/ (tr.) prendre en main, pendre le contrôle de, prendre la direction de ; (intr.) prendre la relève ; 2/ (tr.) racheter (une société) * takeover (n) : 1/ prise (f), reprise (f) ; 2/ prise en main - takeover bid : offre publique d’achat (OPA) - takeover target : cible pour OPA * taker (n) : 1/ preneur, preneuse - hostage taker : preneur d’otages ; 2/ consommateur, consommatrice, amateur, amatrice - drug taker : consommateur de drogue, toxicomane * taking (n) : prise (f) - the taking of the Bastille : la prise de la Bastille * take up (v) (took, taken) (tr.) : 1/ se mettre à (a hobby, un passe-temps) - to take up photography : se mettre à la photographie, se lancer dans la photographie ; 2/ accepter (une proposition, une invitation) - to take up an invitation : accepter une invitation ; 3/ relever (un défi) - to take up a challenge : relever un défi ; 4/ prendre, occuper (de la place, de l’espace, du temps) - to take up space : occuper de l'espace * tale (n) : histoire (f) - to tell a similar tale : raconter la même histoire * talent (n) : talent - talent scout : dénicheur de talents * talented (a) : talentueux/-euse * talk (n) : 1/ paroles (f pl.) - idle talk : paroles en l'air - pep talk : paroles d’encouragement - trash talk : (de la) provocation, (de la) provoc’ - talk show : débat télévisé, émission-débat (f) (syn. chat show) ; 2/ conversation (f), sujets de conversation (pl.) ; 3/ (talks, pl.) pourparlers (pl.) - to be in talks with… : être en pourparlers avec… crunch talks : pourparlers de crise ; 4/ exposé oral * talk (v) : (tr.) dire, raconter - to talk claptrap : raconter des boniments - expression you're talking : You're talking much more money : Il faut compter bien plus d'argent, Il s'agit de bien plus d'argent ; (intr.) parler, causer (about, de) - to talk in sign language : communiquer par signes - I know what I’m talking about : Je sais ce dont je parle, Je sais ce que je dis * talkative (a) : bavard(e) * talk down (v) : (tr.) minimiser, dénigrer (qch) ; (intr.) to talk down to sb : a/ s’adresser à qn d’un ton condescendant ; b/ prendre qn de haut * talker (n) : bavard (n), moulin à paroles (fam.) - smooth talker : beau parleur, baratineur, embobelineur * talking (a) : parlant(e) - talking film : film parlant * talking (n) : bavardage, bavardages (pl.) - repeated talking : bavardages incessants - talking shop : forum (de discussion), lieu de parlottes * talking of (loc. prép.) (fam.) : en parlant de (syn. speaking of) * tall (a) : grand(e) (par la taille), haut(e) * tallness (n) : taille (f), hauteur (f) (d’un bâtiment) * tallow (n) : suif - beef tallow : suif de bœuf * tallow (v) (tr.) : couvrir de suif, suiffer * tally (v) (intr.) : correspondre (with, à), concorder (with, avec) * talon (n) (fa) : serre (f), griffe (f) (d'oiseau) * tamarind (n) : tamarin (fruit du tamarinier) * tame (a) : 1/ [animal] apprivoisé(e), domestique ; 2/ insipide, fade, ennuyeux/-euse ; 3/ [individu] réservé(e), mou/molle * tame (v) (tr.) : 1/ dompter, dresser ; 2/ apprivoiser, domestiquer ; 2/ atténuer * tamper (v) (intr.) : (to tamper with sth) altérer - This lock has been tampered with : On a cherché à crocheter cette serrure * tamper-proof (ac) : [serrure, emballage] inviolable, qui ne peut être trafiqué * tamping (n) : bourrage - tamping bar : bourroir * tang (n) : saveur (f), odeur piquante (f) * tangerine (n) : tangerine (f) (variété de mandarine) * tangle (v) (tr.) : enchevêtrer * tangled (ppa) : enchevêtré(e) * tango (n) : (le) tango * tango (v) (tangoed, tangoed) (intr.) : danser le tango - It takes two to tango : les torts sont partagés * tank (n) : 1/ réservoir - fish tank : aquarium - fuel tank (Aéro.) : réservoir de carburant - hot-water tank : chauffe-bain (syn. hot-water cylinder) - immersion tank (brit.) : ballon d’eau chaude - refrigerant tank : réservoir de fluide réfrigérant - tank top : a/ (brit.) : pull sans manches (des années 1970), b/ (amér.) débardeur, marcel, camisole (Q) ; 2/ fosse (f) - septic tank : fosse septique ; 3/ (fig.) - think tank (amér.) : groupe de réflexion, laboratoire d'idées, boîte à idées * tank (v) : 1/ (tr.) conserver dans un réservoir ; 2/ (intr.) s’effondrer - Corporate profits are tanking : Les bénéfices des entreprises s’effondrent * tankard (n) (brit.) : chope * tanker (n) : (selon le cas) pétrolier, bateau-citerne, camion-citerne - road tanker : camion-citerne * tantalise (brit.) / tantalize (amér.) (v) (tr.) : 1/ tourmenter ; 2/ émoustiller * tantalising (brit.) / tantalizing (amér.) (a) : 1/ qui engendre un espoir toujours déçu : 2/ qui met l’eau à la bouche, (irrésistiblement) tentant(e), émoustillant(e) (syn. tempting) * tantalisingly (brit.) / tantalizing (amér.) (adv.) : 1/ cruellement ; 2/ de manière tentante * tantamount (a) : qui équivaut à - it’s tantamount to... : cela équivaut à... * tantrum (n) : crise de colère, accès de colère, colère, accès de rage, caca nerveux (péj.) - [child] to have a tantrum : [enfant] faire une colère, piquer une colère - to be subject to trantrums : être soupe au lait - to put oneself in a tantrum : prendre la mouche - She is in her tantrums : Elle est dans un de ses accès de colère - temper tantrum : accès de colère, accès de rage - to throw a temper tantrum : piquer une colère * tap (n) : 1/ (Usin.) taraud ; 2/ (brit.) robinet - to turn on the tap : ouvrir le robinet (anton. to turn off the tap) * tap (n) : 1/ tape, tapotement ; 2/ taps (pl.) claquettes - tap dancing : (les) claquettes * tap (v) : 1/ (tr.) (Usin.) tarauder ; 2/ (tr.) percer (un fût) ; 3/ (tr.) exploiter, tirer parti de (syn. to exploit) - to tap a new market : exploiter un nouveau marché ; (intr.) - to tap into a database : puiser dans une base de données, consulter une base de données ; 4/ (tr.) mettre sur table d’écoute * tap (v) (tr.) : 1/ tapoter sur, tapoter à, taper sur, taper à ; 2/ actionner - to tap a key : actionner une touche * tape (n) (fa) : 1/ bande (f), ruban - magnetic tape : bande magnétique - punched tape : ruban perforé, bande perforée - tape reader : lecteur de bande - tape recording : enregistrement sur bande - to put sth on tape : enregistrer qch sur bande ; 2/ (Mus.) (abr. de cassette tape) cassette (f) - mix tapes (pl.) : démos (f pl.), chutes d'essais, ébauches (f pl.) (de musicien hip hop) - radio broadcast tapes : enregistrements d’émissions radiophoniques ; 3/ ruban (adhésif) - duct tape : ruban adhésif en toile, chatterton - sticky tape : ruban adhésif * tape (v) (tr.) (fa) : 1/ enregistrer sur bande / sur cassette - to tape a show : enregistrer un spectacle, enregistrer une émission ; 2/ fixer (avec du ruban adhésif), protéger (par de l’adhésif), isoler (à l’aide d’adhésif) * taped (ppa) : enregistré(e) sur bande / sur cassette - taped interview : entretien enregistré * taper (v) (fa) : 1/ (intr.) devenir plus étroit(e) ; 2/ (tr.) effiler ; (intr.) [doigts] s’effiler * tape-record (v) (tr.) : enregistrer sur bande / sur cassette * tapered (a) : effilé(e) * tapestry (n) (pl. tapestries) : tapisserie (f) (l’objet) * tapeworm (n) : ver solitaire * tapper (n) : pianoteur * tapping (n) : (Usin.) taraudage - tapping machine : machine à tarauder * tar (n) : goudron - tar pit : fosse à goudron * tarantula (n) : tarentule (f) * tar baby (n) (pl. tar babies) (amér.) : sac de nœuds, situation délicate (f) - to get mired in a tar baby of one’s own : se retrouver empêtré par sa faute dans une situation intenable * tarball (n) (litt. « boule de goudron ») : (Inf.) archive tar, archive TAR - unpacked tarball arhive tar décompressée * tardiness (n) 1/ lenteur (f) ; 2/ caractère tardif ; 3/ retard(s) pris (dans l’accomplissement d’une tâche) - tardiness of job completion : retards pris dans l’exécution de tâches, tâches terminées en retard - tardiness costs : coûts liés aux retards * tardy (a) : 1/ lent(e), qui prend son temps ; 2/ tardif/-ive ; 3/ qui est en retard, qui a pris du retard - tardy job : tâche qui a pris du retard * target (n) : 1/ cible (f) - to be a target for thieves : être la cible de voleurs - prime target : cible de choix ; 2/ but, objectif, (en mod.) visé(e) - high-priority target : cible prioritaire - target audience : public visé * target (v) (tr.) : viser, cibler - to target an audience : viser un public * targeted (ppa) : visé(e), ciblé(e) - targetd assassinations : assassinats ciblés * tariff (n) : tarif - tariff policies : politiques tarifaires (f pl.) * tarnish (v) :1/ (tr.) ternir ; (intr.) se ternir ; 2/ (fig.) ternir, salir (une réputation) - to tarnish the image of… : salir l’image de… * tarp (n) (tronc. de tarpaulin : bâche) : - camouflage tarp : bâche de camouflage * tarpaulin (n) : bâche (f) * tarry (v) (intr.) (lit.) : rester (syn. to remain) * tart (n) (fa p) : 1/ tarte (f) (aux fruits) - apple tart : tarte aux pommes ; 2/ (brit.) a/ pute (f) (vulg.), grue (f) - society tart : demi-mondaine (fém.) ; b/ pouffiasse (f) (vulg.), pétasse (f) (vulg.), salope (f) (vulg.) * tartness (n) : aigreur (f) (of taste, du goût, of a remark, d’une remarque) * task (n) : 1/ tâche (f) - to carry out a task : effectuer une tâche - to do repetitive tasks : accomplir des tâches répétitives - to handle a variety of tasks : effectuer diverses tâches - to perform a task : accomplir une tâche, exécuter une tâche - set of tasks : ensemble de tâches (var. task set) - a Sisyphean task : une tâche sisyphéenne, une tâche impossible, le rocher de Sisyphe - household tasks : tâches ménagères - routine tasks tâches courantes - to be off task : dévier de sa mission, n’être plus soi-même ; 2/ (expressions) - to take sb to task : s’en prendre à qn * taskmaster (n) : 1/ surveillant, chef de corvée ; 2/ (fig.) chef exigeant, tyran * tassel (n) : (Habillement) gland * taste (n) : goût - a taste for sth : un penchant pour qch, du goût pour qch - There is no accounting for taste : Des goûts et des couleurs on ne discute pas * taste (v) (tr.) : 1/ goûter ; 2/ déguster * tasty (a) : savoureux/-euse * tatters (n pl.) : haillons (pl.), lambeaux (pl.) - in tatters : en haillons, en lambeaux * tattoo (n) : tatouage (la chose) - to flaunt a new tattoo : exhiber un nouveau tatouage * tattooed (ppa) : tatoué(e) * tatty (a) : 1/ [objet] miteux/-euse ; 2/ [individu] dépenaillé(e) ; 3/ bas de gamme, de mauvais goût * tattyhead (n) (brit.) : crétin(e), imbécile * taught (prét. de to teach) * taught (pp de to teach) * taunt (n) : raillerie (f), sarcasme * taunt (v) (tr.) : provoquer, narguer * taut (a) : tendu(e) * tautology (n) : (figure de style) tautologie (f), répétition (f) * tawny (a) : [couleur] fauve * tax (n) (pl. taxes) : impôt - to evade taxes : ne pas payer ses impôts - after tax : après impôts, impôts déduits - before tax : avant impôts, impôts non déduits - property taxes : impôts fonciers - tax collection : recouvrement de l’impôt - tax evasion : fraude fiscale (f) - tax liability : obligations fiscales (f pl.), impôts à payer (pl.) * tax (v) (tr.) : imposer * taxable (a) : imposable - taxable income : revenu imposable * tax-free (ac) : non soumis(e) à l’impôt - tax-free lottery winnings : gains à la loterie non soumis à l’impôt * taxi (n) : taxi - to flag down a taxi : héler un taxi * taxing (a) : éprouvant(e) * taxpayer (n) : contribuable (n) * Taylorism (n) : (le) taylorisme * Taser (n) (init. de Thomas A. Swift's Electrical Rifle) : taser, pistolet à impulsion électrique, foudroyeur * tea (n) : thé - to make tea : faire du thé - to sip tea : siroter du thé - a cup of tea : une tasse de thé - It’s not my cup of tea : Ce n’est pas mon genre - tea break : pause pour le thé - tea cup : tasse à thé - tea leaf : a/ feuille de thé, b/ informateur (de la police) - tea towel (brit.) : torchon - tea sipper : a/ (l’objet) gobelet à thé ; b/ (la personne) siroteur de thé * teach (v) (taught, taught) : enseigner (sb sth, qch à qn) - that's what they were taught : c'est ce qu'on leur a enseigné * teachable (a) : [élève, étudiant] éducable, réceptif/-ive, ouvert(e) à tout enseignement (anton. unteachable) * teacher (n) : instituteur / institutrice (du primaire), maître / maîtresse (d’école), professeur (n) (du secondaire), enseignant(e) - the teacher's desk : (selon le cas) le bureau du professeur / de l’instituteur - to be teacher’s pet : être le chouchou du professeur / de l’instituteur - the teachers’ room : la salle des professeurs (fam., des profs) (syn. the staff room) - special needs teacher : éducateur spécialisé, éducatrice spécialisée - substitute teacher : remplaçant, remplaçante (n) - teacher training : formation des enseignants * teachership (n) : professorat * teaching (n) : enseignement - language teaching : (l')enseignement des langues - mixed ability teaching : pédagogie différenciée (f) - remedial teaching : soutien scolaire - second language teaching : (l')enseignement des langues étrangères - English language teaching (ELT) : (l’)enseignement de l’anglais - teaching methods méthodes d’enseignement - teaching software : logiciels d’enseignement * teachware (n ind. sing.) : logiciels (pl.) d’enseignement * tea leaf (n) : 1/ feuille de thé ; 2/ informateur (de la police) * team (n) : 1/ attelage ; 2/ (Sport) équipe (f) - the away team : l’équipe qui se déplace, l’équipe en déplacement, les visiteurs (pl.) - cheer team : troupe de chauffeurs de salle - the home team : l’équipe qui reçoit, l’équipe locale - team building : renforcement de l’esprit d’équipe - team management : gestion du travail en équipe - team work : travail en équipe * team-based (ac) : en équipe - team-based practices : travail en équipe * team up (v) (intr.) : faire équipe (with, avec) * teamwork (n) : travail d’équipe, travail en équipe (aussi team work) * tear (n) : larme (f) - to be suffused with tears : être baigné(e) de larmes - to break down into tears : éclater en sanglots - to shed tears : verser des larmes - tear drop : larme - tear jerker : livre / film qui fait jaillir les larmes, livre / film à l'eau de rose * tear (n) : déchirure (f), lacération (f) - tear resistance : résistance à la lacération * tear (v) (tore, torn) (tr.) : déchirer - to tear to ribbons : mettre en lambeaux * tear down (v) (tore, torn) (tr.) : jeter à bas, démolir, raser - to tear down statues : jeter à bas des statues, déboulonner des statues * teardrop-shaped (ac) : en forme de larme * tear-filled (ac) : empli de larmes * tear-resistant (ac) : résistant à la déchirure, résistant à la lacération, non déchirable, non lacérable - tear-resistant plastic : plastique indéchirable * tease (v) (tr.) : taquiner * teaser (n) : 1/ taquin (n) ; 2/ casse-tête (le jeu) - brain teaser : casse-tête * tech (a) (tronc. de technical) : technique - tech issues : ennuis techniques, problèmes techniques - tech lingo : jargon technique - tech support : assistance technique (f) - tech words and phrases : mots et expressions techniques * tech (n) (abr. de technical college) : établissement technique (pour élèves âgés de 11 à 18 ans) * tech (n) (tronc. de technician) : technicien(ne) - to dispatch a tech to the customer site : envoyer un technicien chez le client - electronic tech : électronicien * tech (n) (tronc. de technology) : (la) techno - big tech : (les) géants de la technologie, (les) géants technologiques (pl.), (les) GAFAM (acronyme formé des init. de Google, Amazon, Facebook, Apple, Microsoft) (aussi big tech companies : grandes sociétés technologiques) - current tech : (la) techno actuelle - the tech bubble : la bulle technologique, la déconfiture des valeurs technologiques (en 2000) * tech-centric (ac) : féru(e) de technologie - a tech-centric lot : un groupe féru de technologie * techie (n) : 1/ technicien(ne) ; 2/ spécialiste (anton. non-techie) * technical (a) : technique - a technical achievement : une prouesse technique (f) - technical English : (l’)anglais technique - technical enhancement : amélioration technique (f) - technical improvement : amélioration technique - technical jargon : jargon technique - technical manager : directeur technique, directrice technique - technical noun : nom technique - technical specifications : caractéristiques techniques - technical support : assistance technique - technical term : terme technique - technical troubleshooting : résolution de problèmes techniques - technical writer : rédacteur technique, rédactrice technique * technically (adv.) (fa p) : 1/ techniquement - Technically, … (a m p) (t d p) : Au point de vue technique, ..., Sur le plan technique, … ; 2/ en fait ; 3/ en principe, en théorie, théoriquement * technically advanced (ac) : à la pointe de la technique - technically advanced appliance : appareil très évolué techniquement * technically disabled (ac) : hors d’état de fonctionner * technically feasible (ac) : réalisable sur le plan technique - technically feasible project : projet techniquement réalisable, projet réalisable sur le plan technique * technically flawfree (ac) : techniquement sans défaut, techniquement parfait(e) * technically oriented (ac) : tourné(e) vers la technique, à dominante technique, s’intéressant à la technique - technically oriented coursework : cours de type technique - technically oriented education : éducation technique (f) - technically oriented readers : lecteurs s’intéressant à la techniques * technically reliable (ac) : d’une fiabilité absolue * technically savvy (a) : très averti(e) sur le plan technique - technically savvy user : utilisateur très avert sur le plan technique * technically sound (ac) : techniquement sûr/sure, techniquement au point - technically sound product : produit techniquement sûr * technician (n) : technicien(ne) (n) - service technician : technicien de maintenance * technique (n) : technique (f) (prise individuellement) - to embrace a technique : adopter une technique - manufacturing techniques : techniques de fabrication - production techniques : techniques de production * techno (n) (abr. de techno music : musique techno) : (la) techno - techno musician : musicien de techno - techno rhythm : rythme de techno, tythme techno * technobabble (n) : (le) jargon technique * techno house (n) : (Mus.) (la) techno house * technological (a) : technologique - the techological revolution : la révolution technologique * technologically (adv.) : sur le plan technologique, du point de vue technologique * technologically advanced (ac) : à la pointe de la technologie * technologise (brit.) / technologize (amér.) (v) (tr.) : techniciser, rendre plus technique, insuffler de la technologie dans - to technologize the production process : techniciser les opérations de production * technologist (n) : technicien, technicien-spécialiste, expert, technologue (Q, catégorie intermédiaire entre technicien et ingénieur) - architectural technologist : technologue en architecture (Q) - computational technologist : technicien de calcul - educational technologist : technicien pédagogique, technopédagogue - electronics technologist : technicien en électronique - environmental technologist : technicien spécialiste du milieu - food technologist : nutritionniste - garment technology : technicien de confection - geological technologist : technicien-spécialiste en géologie - information technologist : technicien en informatique - mechanical engineering technologist : technicien en génie mécanique - medical laboratory technologist : technicien de laboratoire médical - medical technologist : expert en technologie médicale - nuclear medicine technologist : technologue en médecine nucléaire (Q) - orthopaedic technologist : technicien orthopédiste - radiology technologist : manipulateur en radiologie - surgical technologist : technologue chirurgical (Q) (syn. operating room technician) * technology (n) (pl. technologies) : 1/ technologie (f) - to embrace a technology : adopter une technologie - green technology (abr. green tech) : technologies vertes (f pl.) - information technology : informatique (n) (f) - production technology : technologie de production, productique (n) (f) - technology English : (l’)anglais de la technologie - technology enthusiast : passionné de technologie ; 2/ (Éduc.) (la) technologie - design and technology (abr. D&T/DT) : (G.-B.) conception et fabrication (de produits industriels) * technology conversant (ac) : qui s’y connaît en technologie * technology-driven (ac) : impulsé(e) par la technologie - the technology-driven growth of communication : la croissance des communications impulsée par la technologie * technology-intensive (ac) : à forte composante technologique * techno music (n) : (la) musique techno, (la) musique technoïde (musique de danse électronique répétitive fondée sur le rythme et des basses amplifiées, créée en 1985 en Grande-Bretagne) (abr. techno) * technospeak (n) : (le) jargon technique * tech-savvy (ac) : qui se débrouille bien dans le domaine technique, techno-futé(e) * tectonic (a) : tectonique * tectonics (n) (sing.) : (la) tectonique - plate tectonics : (la) tectonique des plaques * teddy (n) (pl. teddies) : robe de nuit (féminine) * tedious (a) : fastidieux/-euse, laborieux/-euse, ennuyeux/-euse (syn. uninteresting) * tediously (adv.) : de façon ennuyeuse * tediousness (n) : ennui, monotonie (f) * teen (n) (tronc. de teenager) : ado (n) * teen (a) : pour les ados, pour les jeunes - teen film : film pour ados - teen magazine : revue pour ados * teenage (n) : adolescence (f) * teenager (n) : adolescent, ado (fam.) - the bratty teenager : l'ado en révolte * teens (n pl.) : 1/ nombres 13 à 19 - the high teens : les nombres 17 à 19 - the low teens : les nombres 13-14 ; 2/ pourcentages 13 à 19% - U.S. shipments dropped into the low teens in 1989 : les livraisons américaines baissèrent jusqu'à 13-14% en 1989 ; 3/ âge de 13 à 19 ans, adolescence - still in his/her teens : encore adolescent(e) * teeter (v) (intr.) : chanceler (syn. to be unsteady) * teethe (v) (intr.) : faire ses dents * teething (n) : faire ses dents - teething troubles : (fig.) défauts de jeunesse * telecoms (n sing.) (tronc. de telecommunications) : (les) télécoms (f pl.) * telecommunications (n sg, faux pl.) : (les) télécommunications (f pl.) - telecommunications carrier : exploitant de réseau de télécommunications * telegraph (n) : télégraphe - telegraph pole : poteau télégraphique * telegraph (v) (tr.) : 1/ télégraphier - to telegraph sb : télégraphier à qn - to telegraph sth to sb : télégraphier qch à qn ; 2/ faire connaître, annoncer, signaler - to telegraph one’s intentions : faire connaître ses intentions * telephone (n) : téléphone (le système et l’objet) - coinless public telephone : téléphone public sans encaissement - telephone line : ligne téléphonique (f) - telephone number : numéro téléphonique * teleoperation (n) : manipulation à distance * teleoperator (n) télémanipulateur * teleportation (n) : téléportation (f) * telescope (n) : télescope - space telescope : télescope spatial * teleshopping (n) : achats à domicile (pl.) * teleski (n) : téléski, tire-fesse (fam.) (masc.) (syn. ski lift) * teletypewriter (n) : téléimprimeur, téléscripteur * televise (v) (tr.) : téléviser * television (n) : (la) télévision - I saw it on television : Je l'ai vu à la télévision - cable television : (la) télévision par câble, (le) câble - digital television : télévision numérique - high-definition television : télévision haute définition (abr. HDTV) - pay-per-view television : télévision à la carte - pay television : télévision payante - television host : animateur de télé (ex. : Larry King) - television journalist : journaliste de télévision, journaliste à la télévision - television presenter : animateur télé - television program(me) : émission de télé - television reporter : journaliste de télévision, journaliste à la télé - television set : poste de télévision * telewriter (n) : téléscripteur * telewriting (n) : télé-écriture (f) * tell (n) : (Archéo.) tumulus, tertre * tell (n) : indice * tell (v) (told, told) : 1/ raconter - to tell a similar tale : raconter la même histoire ; 2/ dire - to tell sb sth : indiquer qch à qn * tell-all (ac) : [récit, livre] où l’on déballe tout, sans concession - a tell-all memoir : un déballage * tell-all (n) : récit où l’on déballe tout, déballage, récit sans concession * teller (n) : diseur/-euse - fortune teller : diseuse de bonne aventure * telling (n) : - fortune telling : dire la bonne aventure * tell off (v) (told, told) (tr.) : rabrouer (qn) * telly (n) (abr. de television) (fam.) : télé (f), téloche (f) (fam.) - to watch telly : regarder la téloche * temper (n) : 1/ humeur (f) - to lose one’s temper : se mettre en colère - temper tantrum : accès de colère, accès de rage ; 2/ tempérament * temper (v) (tr.) : 1/ tempérer, modérer ; 2/ (Métallurgie) tremper (du métal) * temperament (n) : tempérament * temperamental (a) : 1/ [individu] d’humeur instable, facilement déprimé(e), facilement exalté(e) ; 2/ [individu] caractériel(le), lunatique ; 3/ [machine] qui n’en fait qu’à sa tête * temperamentally (adv.) : par nature, viscéralement * temperance (n) : tempérance (f) - temperance beverage : boisson non alcoolisée (f) * temperature (n) : température (f) - room temperature : température ambiante * temperature-sensitive (ac) : sensible aux écarts de température * template (n) : 1/ gabarit ; 2/ (Inf.) feuille de style, fond de plan * temple (n) (fa p) : 1/ (le) temple (où l'on prie) - masonic temple : temple maçonnique ; 2/ (la) tempe * tempting (a) : tentant(e) * tempo (n) : 1/ tempo - to set the tempo : donner le tempo ; 2/ rythme, cadence (f) - in tempo : dans le tempo, en rythme - accelerated tempo : rythme accéléré - slow tempo : rythme lent * temporarily (adv.) : temporairement - [production] to be temporarily halted : [production] s’interrompre temporairement * temporary (a) : temporaire * tempter (n) : tentateur * temptress (n) (pl. temptresses) : 1/ tentatrice (f) ; 2/ allumeuse (f) * ten (a) : dix * ten (n) : dizaine (f) - tens of millions of dollars : des dizaines de millions de dollars * tenable (a) : tenable, soutenable, défendable * tenant (n) : locataire (m/f) (syn. a renter) * tend (v) (fa p) : (tr.) entretenir (un jardin), s’occuper de, avoir la charge de - to tend a bar : tenir un bar ; (intr.) (to tend to) soigner (un malade), s'occuper (d'invités) - to tend to the needs of sb : subvenir aux besoins de qn * tend (v) (intr.) : tendre - to tend to + inf. : avoir tendance à + inf., tendre à + inf. * tender (n) (en compo.) : personne qui s’occupe de, personne chargée de - bar tender : responsable du bar * tending (n) : tenue (f) - bar tending : tenue d’un bar * tendril (n) : vrille (f) (of a plant, d'une plante) * tenement (n) : immeuble (de rapport) * tenet (n) : principe (f) - Financial aid is a basic tenet of Islam : L’aumône est un principe fondamental de l’Islam * tenfold (a) : décuple, multiplié(e) par 10 * ten-hour (ac) : de dix heures - ten-hour shifts : journées de travail de dix heures * Tenn. : abr. de Tennessee, (le) Tennessee * tenner (n) : 1/ (brit.) (arg.) billet de dix livres (syn. ten-pound note) ; 2/ (amér.) (arg.) billet de dix dollars (syn. ten-dollar bill) * Tennessean (n pr.) : habitant(e) du Tennessee * Tennessee (n pr.) : (le) Tennessee - in Spring Hill, Tennessee : à Spring Hill dans le Tennessee * tennis (n) : 1/ (Sport) (la) paume - real tennis : (la) courte paume (syn. amér. court tennis) ; 2/ (le) tennis - lawn tennis : (le) tennis sur gazon * tense (a) : tendu(e) * tense (n) (Gram.) : temps - the future tense : le futur - the future perfect tense : le futur antérieur - the past tense : le passé - the perfect tense : le parfait - the present tense : le présent - the present perfect tense : le passé composé - the tense rules in English : les règles de l’emploi des temps en anglais * tensioner (n) : (Méca.) galet * tent (n) : tente (f) - tent trailer : tente-caravane (f) (caravane dont les parois de toile se replient pour le transport) * tentatively (adv.) : 1/ avec hésitation, prudemment, timidement - tentatively speaking, … (mod. phr.) : on peut envsager que…; 2/ provisoirement, temporairement ; 3/ peut-être * tenterhooks (n pl.) : dans l’expression to be on tenterhooks : être sur des charbons ardents * tenuous (a) : [lien, soupçon] ténu(e) * tenure (n) : 1/ jouissance (f) (of a property, d’une propriété) ; 2/ occupation (f) (d’un poste), fonction occupée (f) - during his tenure as chairman : alors qu’il occupait le poste de président ; 3/ (amér.) le fait d’être titulaire, poste de titulaire - to have tenure : être titulaire - granting of tenure : titularisation (f) - No tenure means no job protection : Sans titularisation, pas de sécurité de l’emploi * tenured (ppa) : qui est titulaire - tenured academia : chaires universitaires (f pl.) * tepid (a) : [liquide] tiède * terabyte (n) : (Inf.) téraoctet * term (n) (fa p) : 1/ terme, période (f), durée (f) - long term : long terme, longue durée - short term : court terme, courte durée ; 2/ mandat (d’un élu) ; 3/ trimestre - the autumn term : le premier trimestre - school term : trimestre scolaire - the spring term : le second trimestre - the summer term : le troisième trimestre - term paper : dissertation trimestrielle (f) ; 4/ (au pl. terms) conditions (f pl.) - easy terms : facilités de paiement ; 5/ (au pl. terms) dispositions (f pl.), clauses (f pl.) (d'un contrat) - the terms of the licence : les clauses de la licence ; 6/ (au pl. terms) termes, rapports - the breakdown in terms of time : la répartition horaire - in terms of : sous l’angle de, sous le rapport de, en matière de, sur le plan de, au niveau de, pour ce qui est de, en ce qui concerne, du point de vue de, quant à, relativement à, en fait de - in computing terms : sur le plan informatique - in terms of airline security : en matière de sécurité aérienne ; 7/ a/ terme, mot, vocable, b/ expression (f), locution (f) - to bring a new meaning to a term : donner une nouvelle acception à une expression - common term : terme courant - household term : terme d’usage courant, terme connu de tout le monde - generic term : terme générique - related term : terme associé - research term : terme d’une interrogation (dans un moteur de recherche) - specific term : terme spécifique (dans un thésaurus) - techie term : terme technique - technical term : terme technique - umbrella term : terme générique, expression générique - in layman’s terms : a/ en termes simples, en langage de tous les jours ; b/ (selon le cas) en termes non scientifiques, en termes non techniques - search terms (Inf.) : terminologie de recherche - term base : base terminologique (f) - term weighting : pondération des termes (effectuée par un moteur de recherche) * term (v) (tr.) : appeler (sth, qch) * terminal (n) : 1/ borne (f) ; 2/ terminal (informatique) - data terminal : terminal de consultation * terminate (v) (fa p) : 1/ (tr.) mettre fin à, mettre un terme à, terminer - to terminate a pregnancy : mettre fin à une grossesse, interrompre une grossesse ; (intr.) se terminer ; 2/ (tr.) résilier - to terminate a contract : résilier un contrat ; 3/ (tr.) liquider (qn) - They had him terminated : Ils l’ont fait liquider * termination (n) : 1/ fin (f), terme, résiliation (f) ; 2/ interruption de grossesse, avortement, IVG (fém.) * terminology (n) : terminologie (f) - grammar terminology : terminologie grammaticale * terrace (n) (fa p) : 1/ terrasse (f), gradin - agricultural terrace : terrasse agricole, terrasse de culture - cultivated terrace : terrasse de culture, terrasse agricole ; 2/ (brit.) rangée de maisons uniformes * terraform (v) (tr.) : terraformer * terraforming (n) : terraformation (f) * terrible (a) : épouvantable, affreux/-euse - It's terrible! : C'est affreux ! * terribly (adv.) : 1/ horriblement mal, affreusement mal, très mal ; 2/ extrêmement * terrier (n) : terrier (le chien) * terrific (a) : (fam.) super, génial * territorial (a) : territorial(e) - territorial integrity : intégrité territoriale (f) * terror (n) : terreur (f) - terror ordeal : épreuve terrifiante (f) * terror-proof (ac) : protégé(e) contre les terroristes - terror-proof airport : aéroport protégé contres les terroristes * terrorism (n) : terrorisme - to combat terrorism : combattre le terrorisme * terrorist (a) : terroriste (a) * terrorist (n) : terroriste (n) * terse (a) : laconique * tersely (adv.) : laconiquement * tertiary (a) : tertiaire - tertiary education : (le) troisième cycle * tesselated (ppa) : en mosaïque * tesselation (n) : mosaïque (f) * test (n) : 1/ essai, test - to conduct a test : procéder à un essai - to try out a test : effectuer un essai - black-box test : test de la boîte opaque - comparative tests : essais comparatifs - crash test : simulation de collisions - endurance test : essai d’endurance - inkblot test : test de Rorschach - paternity test : test de paternité - regulation test : essai réglementaire - white-box test : test de la boîte transparente - wind-tunnel tests : essais en soufflerie - test bench : banc d’essais, banc de tests, banc-test - test center : centre d’essais - test flight : vol d’essai - test pilot : pilote d’essai - test rig : banc d’essai - test stand : banc d’essais, banc de tests, banc-test ; 2/ (Éduc.) contrôle - grammar test : contrôle de grammaire - vocabulary test : contrôle de vocabulaire * test (v) : (tr.) évaluer, essayer, tester ; (intr.) faire une analyse * test and approve (v coord.) : (tr.) éprouver et approuver, tester et approuver * testament (n) : 1/ testament ; 2/ (Testament) Testament (une des deux parties de la Bible) - the New Testament : le Nouveau Testament - the Old Testament : l’Ancien Testament ; 3/ - to be a testament to sth : attester qch, témoigner de qch * test drive / test-drive (vc) (tr.) : essayer (une auto) sur route * tester (n) : banc d’essais, banc-test * test-fire (vc) (tr.) : tester la mise à feu de (une fusée, un missile) - to test-fire an intercontinental ballistic missile : faire un essai de mise à feu d’un missile balistique intercontinental * test-firing (nc) : essai de mise à feu, essai de tir (d’une fusée, d’un missile) * testify (v) (intr.) : témoigner (against, contre), (to, de) * testing (n) : essais (pl.), tests (pl.), contrôles (pl.) - testing on animals : (l’)expérimentation animale (f) - pressure testing : essais en pression - testing bench : banc d'essais, banc de tests, banc-test - (the) testing department : (le) service des contrôles, (le) Contrôle * test run / test-run (v) (tr.) : faire faire un bout d’essai à, faire faire un galop d'essai à * testy (a) : irritable * tetanus (n) : (le) tétanos - to get a tetanus jab : se faire vacciner contre le tétanos * tether (n) : 1/ laisse (f) ; 2/ longe (f) * tether (v) (tr.) : attacher (syn. to fasten) * tethered (ppa) : captif/-ive (anton. untethered) * Tex. : abr. de Texas, (le) Texas * Texan (a) : texan(e) (sans maj.) - Texan twang : accent texan * Texan (n pr.) : Texan (l’habitant) * Texas (n pr.) : (le) Texas - to move to Texas : aller vivre au Texas * text (n) : 1/ (selon le cas) a/ (du) texte, un (texte) - mangled text : texte mutilé - overladen text : texte trop touffu - to liven one’s text with clip art : égayer son texte avec des images prêtes à l’emploi - to type a text into a PC : taper un texte sur un PC - Please note text is subject to revision : Texte non définitif, Texte susceptible d’être modifié - See main text : Voir corps du texte ; b/ (des) textes - non-fictional text : textes non littéraires (pl.), œuvres (pl.) qui ne sont pas d’imagination ; 2/ langage texto, langage SMS * text-book (brit.) / textbook (amér.) (n) : manuel (scolaire) - to write a textbook : écrire un manuel (scolaire) - physics textbook : manuel de physique * text-book (brit.) / textbook (amér.) (a) : classique, typique - It’s textbook! : C’est un cas classique !, C’est un cas typique ! - a textbook case : un cas typique, un cas d’école * textile (a) : textile * textile (n) : textile * textual (a) : textuel * textually (adv.) : textuellement * texture (n) : texture (f) * Thai (a) : thaïlandais(e) (sans maj.) * Thai (n pr.) : Thaïlandais (le ressortissant) * Thai (n) : (le) thaï (la langue) * Thailand (n pr.) : (la) Thaïlande * than (après un compar.) : que - rather than : plutôt que * thank (n) : remerciement - Many thanks for your comments on my photos : Un grand merci pour votre appréciation de mes photos * thankfully (adv.) : 1/ avec gratitude, avec reconnaissance ; 2/ (a m p, en tête de phrase) : Heureusement, … , Dieu merci, … * thank (v) (tr.) : remercier * thanks! (interj.) : merci ! - Thanks be to God! : Dieu merci ! * thanks to (loc. prép.) : grâce à * that (pron. dém.) : cela, ça - That having been said, … : Cela étant, … * that (pron. rel.) : qui * that (adv.) : si, tellement - The weather isn’t that bad! : Le temps n’est pas si mauvais que ça ! * that (conj. complétive) : que * thatch (n) : chaume * that is to say (m d l) (parfois abrégé en that is) : 1/ c'est-à-dire ; 2/ du moins * That said, … (m d l) : Cela dit, ... * thaw (n) : 1/ dégel, fonte des neiges ; 2/ (Polit.) détente (f) * thaw (v) (tr. et intr.) : (tr.) faire fondre, dégeler ; (intr.) fondre, dégeler * the (art. déf.) : le, la, les * theatre (brit.) / theater (amér.) (n) (fa p) : 1/ théâtre - musical theatre : a/ (le) théâtre lyrique, (l’)opérette - musical theatre productions : spectacles de comédie musicale ; b/ (la) comédie musicale ; 2/ (amér., theater) cinéma - drive-in theater (amér.) : cinéma en plein air, ciné-parc (Can.) - movie theater : salle de cinéma ; 3/ salle (f) (d'opération, de conférences), amphithéâtre - operating theatre : salle d'opération * theatrical (a) : 1/ de théâtre, théâtral(e) - theatrical critic : critique de théâtre ; 2/ [discours] théâtral(e), dramatique ; 3/ au cinéma, en salle - theatrical release : sortie en salle * theatrically (adv .) : 1/ théâtralement, de manière dramatique ; 2/ (Cin.) dans les cinémas, dans les salles obscures, en salle - [film] to be theatrically released : [film] sortir en salle * thee (pron. pers. objet) (arch.) : te, t' (avant voyelle ou 'h' non aspiré), toi (après prép.) - Rules are for thee but not for me : Les règles, c’est pour toi et non pas pour moi * theft (n) : vol - snatch theft : vol à l’arraché * The goal: … (m d l) (t d p) (fam.) : Le but visé est de …, But de l'opération : … * the instant (that) (loc. conj. de temps) : dès que, aussitôt que * their (adj. poss.) : leur(s) * them (pron. pers. objet) : eux/elles, les * theme (n) : 1/ thème - theme channel : (Télé.) chaîne thématique ; 2/ (Éduc.) (amér.) rédaction * the minute (that) (loc. conj. de temps) : dès que, aussitôt que * the moment (that) (loc. conj. de temps) : dès que, aussitôt que * then (adv.) 1/ alors, à ce moment-là, à l'époque ; 2/ puis, ensuite ; 3/ (souvent en liaison avec une subordonnée par if ou when) alors, en ce cas, dans ce cas * thence (adv.) : 1/ de là ; 2/ de cela * then-chairman (ac) : président à l’époque * theoretical (a) : théorique - theoretical principles : principes théoriques * theoretically (adv.) : théoriquement - Theoretically, … (a m p) (t d p) : En théorie, * theoretician (n) : théoricien * theorist (n) : théoricien - conspiracy theorist : adepte des théories conspirationnistes, quelqu’un qui voit des complots partout - cultural theorist : théoricien de la culture - economic theorist : économiste - legal theorist : juriste - literary theorist : théoricien de la littérature - political theorist : théoricien politique - social theorist : sociologue - UFO theorist ovnilogue * theory (n) (pl. theories) : 1/ (la) théorie (f) - in theory : en théorie (anton. in practice : en pratique) - social theory : (la) sociologie ; 2/ thèse (f), théorie (anglic.) - to introduce a theory : présenter une thèse ; 3/ fable (f), allégation fausse (f), récit mensonger - conspiracy theory : a/ thèse conspirationniste ; b/ conspirationnisme - He’s all into conspiracy theory : Il donne à fond dans le conspirationnisme - whacky theory : thèse farfelue * therapeutic (a) : 1/ thérapeutique ; 2/ relaxant(e), apaisant(e) * therapy (n) : thérapie (f) - gene therapy : thérapie génique * there (adv.) : 1/ là, y - to get there : s’y rendre, y parvenir - down there : là-bas - round there : par là, de ce côté là- up there : là-haut ; 2/ - There is ample room in my car : Il y a suffisamment de place dans ma voiture - There are some grounds for hope : Il y a des raisons d’espérer - there was no marketing strategy at all : il n'y avait pas du tout de stratégie d'attaque du marché - There were no fatalities : Il n'y eut pas de morts * thereafter (adv.) : ensuite, par la suite * The reason is … (m d l) (t d p) : La raison en est que … * thereby (adv.) : de ce fait, par là, à cause de cela * therefore (adv.) : par conséquent * therein (adv.) : 1/ à ce moment ; 2/ à cet endroit, là - Therein is the difficulty : Là est la difficulté * The result is (that) ... (m d l) (t d p) : Le résultat, c'est que …, Cela fait que … * therewith (adv.) : sur ce, avec cela, en outre * thermal (a) (fa p) : 1/ thermal(e) ; 2/ thermique - thermal insulation : isolation thermique (f) - thermal power : énergie thermique (f) - thermal power plant : centrale thermique (f) - thermal relay : relais thermique - thermal shock : choc thermique ; 3/ thermosensible - thermal paper : papier thermosensible * thermonuclear (n) : thermonucléaire - thermonuclear bomb : bombe thermonucléaire * thermoplastic (a) : thermoplastique * thermostat (n) : thermostat * thesaurus (n) (pl. thesauruses ou thesauri) : 1/ dictionnaire de synonymes ; 2/ recueil - a thesaurus of concepts : un recueil de concepts * these (adj. dém.) : ces - these days : de nos jours * these (pron. dém.) : ceux-ci / celles-ci * thesis (n) (pl. theses) : thèse (f) - a threadbare thesis : une thèse usée jusqu’à la corde * The upshot is (that) … (m d l) (t d p) : Le résultat, c'est que …, Cela fait que … * they (pron. pers. sujet) : ils / elles * thick (a) : 1/ épais/épaisse - an object 5.00 mm thick : un objet de 5 mm d’épaisseur ; 2/ dru(e) * thicken (v) : (tr.) épaissir ; (intr.) s’épaissir * thicket (n) : fourré (n) * thick-lippped (ac) : lippu(e) * thickness (n) (pl. thicknesses) : épaisseur (f) * thick-skinned (ac) : qui a la peau dure * thief (n) (pl. thieves) : voleur/-euse (n) - to be a target for thieves : être la cible de voleurs * thieving (a) : voleur/-euse * thigh (n) : cuisse (f) * thigh-high (ac) : montant jusqu’aux cuisses - thigh-high boots : cuissardes (f pl.) * thilk (a) (arch.) : ce, cette * thilk (pron.) : celui-ci, celle-ci * thimble (n) : dé à coudre * thin (a) : mince, fin(e) - as thin as a wafer : mince comme une feuille de papier - thin film : pellicule fine (f), film mince, couche mince (f) * thin down (v) (tr.) : diluer (de la peinture) * thine (pro. poss.) (arch.) : le tien (masc.), la tienne (fém.), les tiens (masc. pl.), les tiennes (fém. pl.) * thing (n) : 1/ chose (f), objet - among other things : entre autres choses : - the whole thing : la totalité - for one thing : d’abord ; une raison c’est que… - the Internet of Things : l’Internet des objets (connectés) ; 2/ (expressions) - It’s just the thing : C’est tout à fait cela - It’s not the thing : Ce n’est pas ce qu’il faut, cela ne se fait pas - I wasn’t feeling quite the thing : Je n’étais pas tout à fait dans mon assiette - The thing is to know what you want : Ce qu’il faut, c’est savoir ce qu’on veut - I said no such thing : Je n’ai rien dit de tel / de semblable ; 3/ (au pl. things : les choses, la situation) - to overstate things : exagérer la situation - to foul things up : foutre la pagaille - Things are looking up! : Les choses s’arrangent ! - Things don’t always go as happily : Les choses ne se passent pas toujours avec autant de bonheur - Things were getting strained : La situation devenait tendue * think (v) (thought, thought) : A/ (verbe transitif) 1/ penser à, réfléchir à ; 2/ penser, croire - I personally think that… : Personnellement, je pense que… - I personally think that… : Personnellement, je pense que… - I still think that… : Je continue de penser que… ; 3/ juger, considérer - to be thought to be… : être considéré comme étant… - Think yourself lucky! : Estime-toi / Estimez-vous heureux ! (heureuse au fém.) ; 4/ (s’)imaginer ; 5/ penser à, se rappeler ; 6/ penser, s’attendre à ; B/ (verbe intransitif) 1/ penser, raisonner ; 2/ penser (of sth, about sth, à qch), réfléchir (about sth, of sth, à qch) - Don’t think about it! Just do it! : Ne réfléchis pas, vas-y / lance-toi / fonce ! - Don’t even think of it! : À ta place, je m’abstiendrais ! - to think twice before doing sth : y réfléchir à deux fois avant de faire qch ; 3/ (s’)imaginer - If you think that I will give up you’re much mistaken : Si tu crois que je vais laisser tomber, tu te trompes grandement ; 4/ penser, croire * thinker (n) : penseur, penseuse - wishful thinker : personne qui prend ses désirs pour des réalités * thinking (n) : 1/ (la) pensée (le processus) - heterodox thinking : pensée hétérodoxe (f), réflexion hétérodoxe (f) ; 2/ (l’)esprit - critical thinking : (l’)esprit critique ; 3/ opinion (f), sentiment (on sth, sur qch) * think tank / thinktank (n) (amér.) : groupe de réflexion, cellule de réflexion (f), centre d’étude, réservoir d’idées, boîte à idées (f) - advocacy think tank : groupe de défense, groupe de plaidoyer * thinktanker (n) (amér.) : membre de groupe de réflexion, intellectuel(le) (n) * thinly (adv.) : 1/ de manière éparse ; 2/ de manière peu convaincante ; 3/ faiblement, à peine - thinly veiled threat : menace à peine voilée (f) * thinness (n) : minceur (f) * thin-skinned (ac) : 1/ qui a la peau fine ; 2/ (fig.) qui a l’épiderme sensible, qui se froisse facilement, susceptible, chatouilleux/-euse * third (a) : 1/ troisième ; 2. tiers/tierce - (a) third party : (une) tierce personne * third (adv.) : tertio (aussi Third, … en t d p) * third (n) : tiers - to have fallen by a third : avoir diminué d'un tiers * thirdly (adv.) : troisièmement, en troisième lieu, tertio (aussi Thirdly, … en t d p) * third-rate (ac) : 1/ de troisième ordre ; 2/ de qualité inférieure, au rabais, minable - third-rate politician : politicien au rabais * third-world (ac) : du tiers monde - third-world nation : pays du tiers monde * third-worlder (n) : habitant du tiers monde, habitante du tiers monde, tiers mondiste * thirdworldise (brit.) / -ize (amér.) (v) (tr.) : tiersmondiser * thirdworldised (brit.) / -ized (amér.) (ppa) : tiersmondisé(e) * thirst (n) : soif (f) * thirsty (a) : assoiffé(e) * thirties (n pl.) : 1/ nombres 30 à 39 ; 2/ températures 30 à 39 (f pl.) ; 3/ latitudes 30 à 39 (f pl.) ; 4/ années 30 à 39 (f pl.) * this (adj. dém.) : ce, cette * this (pron. dém.) : celui-ci, celle-ci * This is because … (a m p) (t d p) : C’est parce que …, Cela vient du fait que …, La raison en est que … * this is why (m d l) : c'est pourquoi * This means that … (m d l) (t d p) : 1/ Cela veut dire que …, En d'autes termes… ; 2/ Il en résulte que …, Cela fait que ... * thistle (n) : chardon * thither (adv.) : là * thorn (n) : épine (f) - a thorn in my side (fig.) : une épine dans le pied - the crown of thorns : la couronne d’épines * thorny (a) : épineux/-euse - thorny issue : problème épineux * thorough (a) : 1/ complet/-ète, total(e), intégral(e) (syn. total) ; 2/ exhaustif/-ive, approfondi(e), minutieux/-euse, effectué(e) à fond, complet/-ète - to give sth a thorough overhaul : faire subir une révision complète à qch * thoroughbred (n) : pur-sang * thoroughfare (n) : artère (f) (dans une ville) * thorough-going (ac) / thoroughgoing (a) : approfondi(e), en profondeur * thoroughly (adv.) : 1/ complètement, intégralement, tout à fait (syn. totally) - thoroughly automated : intégralement automatisé ; 2/ de façon exhaustive, de façon approfondie, à fond, en profondeur, minutieusement - to be thoroughly familiar with sth : connaître qch à fond, connaître qch de façon exhaustive * those (adj. dém.) : ces * those (pron. dém.) : ceux-ci, celles-ci - those that : ceux / celles qui * though (conj. de concession) : bien que, quoique cf. although * though (adv.) (en fin de phrase, après virgule ou dans la phrase, entre virgules) : mais, cependant, pourtant, malgré tout, quand même * thought (prét. de to think) * thought (pp de to think) * thought (n) : pensée (f), réflexion (f) - to require a lot of thought : exiger beaucoup de réflexion - lucid thought : (la) lucidé des idées - the trend of my thoughts : le cours de mes pensées - We had to have second thoughts : Nous dûmes nous raviser * thoughtful (a) : 1/ pensif/-ive ; 2/ attentionné(e) * thoughtfully (adv.) : pensivement * thoughtless (a) : irréfléchi(e), étourdi(e) * thoughtlessly (adv.) : de manière irréfléchie * thousand (n) : millier * thousandfold (a) : multiplié(e) par mille * (a) thousandfold (loc. adv.) : mille fois * thrash about (v) (intr.) : se débattre * thrash around (v) (intr.) : se débattre * thrashing (n) : correction (f) (syn. beating) * thread (n) : 1/ fil - to hang by a thread : ne tenir qu’à un fil ; 2/ filet - left-handed thread : filet à pas gauche, filet à gauche - right-hande thread : filet à pas droit, filet à droite * thread (v) (tr.) : (Usin.) fileter * threadbare (a) : élimé(e), rapé(e), usé(e) - a threadbare thesis : une thèse usée jusqu’à la corde * threading (n) : filetage (Usin.) * threat (n) : menace (f) (against, contre) - to issue threats : lancer des menaces - empty threat : vaine menace, menace en l’air - verbal threat : menace verbale (f) - threat detection : (la) détection de menaces * threaten (v) (tr.) : 1/ menacer ; 2/ mettre en danger - to threaten lives : mettre des vies (humaines) en danger * threatening (a) : menaçant(e) * threateningly (adv.) : de façon menaçante * three (a) : trois * three (n) : trois * three-bay (ac) : à trois stalles - three-bay garage : garage à trois stalles * three-bladed (ac) : [hélice] à trois pales * three-D / 3-D (ac) : tridimensionnel(le) * three-day (ac) : de trois jours * three-dimensional (ac) : tridimensionnel(le), à trois dimensions * three-engine (ac) : trimoteur * threefold (a) : triple, multiplié(e) par trois * three-hour (ac) : de trois heures - a three-hour running time (Cin.) : une durée de trois heures (pour un film) * three-lane (ac) : à trois voies * three-piece (ac) : trois pièces - three-piece suit : costume trois pièces * three-prong (ac) : (Élect.) à trois broches - three-prong power outlet : prise de courant à trois broches * three-shift (ac) : en trois-huit - three-shift continuous working : travail en continu en trois-huit * threesome (n) : 1/ trio ; 2/ (Golf) partie à trois ; 3/ (Sex.) ménage à trois, plan à trois * three-tonner (n) : camion de trois tonnes * three-way (ac) : à trois - three-way sex scene : (Porno.) plan à trois * thresh (v) (tr.) : (Agric.) battre (wheat, etc., du blé, etc.) - to thresh grains : battre des céréales - threshing sledge : planche à dépiquer (f) * thresher (n) : (Agr.) batteuse (f) (la machine) * threshing (n) : (Agr.) battage - threshing floor : aire à battre (f) - threshing machine : batteuse (f) * threshold (n) : seuil - to stand on the threshold of… : être sur le seuil de… * threw (prét. de to throw) * thrice (adv.) (arch. ou hum.) : trois fois * thrift (n) : parcimonie (f) * thrifty (a) : économe * thrill (n) : frisson, émoi, émotion (f), excitation (f) * thrill (v) : 1/ (tr.) faire frémir, donner des frissons à ; (intr.) frémir ; 2/ (tr.) faire vibrer (d’émotion), émouvoir ; (intr.) frémir (d’excitation), vibrer, s'émouvoir (over, à la vue de) * thriller (n) : 1/ histoire à sensation ; 2/ (selon le cas) roman policier, film policier, film à gros frissons, film d'angoisse * thrilling (a) : passionnant(e), excitant(e) (syn. exciting) * thrill-packed (ac) : bourré(e) de sensations fortes, trépidant(e) * thrill seeker (n) : amateur de sensations fortes * thrive (v) (throve, thriven ; aussi régulier) (intr.) : prospérer - If you want to live and thrive, let a spider run alive : Si vous voulez vivre et prospérer, laissez la vie sauve à l’araignée * thriven (pp de to thrive) * thriving (a) : florissant(e), prospère - to be thriving : être prospère, être florissant, être en pleine santé * throat (n) : gorge (f) * throes (n pl.) : affres (f pl.) - to be in one’s death throes : être à l’agonie, agoniser - in the throes of : en proie à (an illness, une maladie, a crisis, une crise) * throne (n) : trône * throneless (a) : sans trône, détroné(e) - throneless king : roi sans trône * throng (n) (lit.) : foule (f) * throttle (n) : accélérateur (de voiture, de moto), commande des gaz (d’avion) * throttle (v) (tr.) : 1/ étrangler (syn. to strangle) ; 2/ mettre au ralenti (un moteur) * through (prép.) : 1/ à travers (un volume) ; 2/ par, par le biais de, au moyen de, via - (to) connect (to the Internet) through a phone line and modem : se connecter à l'Internet au moyen d'une ligne téléphonique et d'un modem ; 3/ passant par ; 4/ + x (angular) degrees : sur x degrés d'angle ; 5/ (amér. = to) jusqu'à, à - from Monday through Friday : du lundi au vendredi - rows 1 through 24 : les lignes 1 à 24 ; 6/ + subst. / gér. : du fait de, à cause de + subst. / inf. passé, pour + subst. / inf. passé - through transposition of numbers : à cause d'une inversion de numéros ; 7/ grâce à - through the use of : grâce à l'emploi de ; 8/ (angl. amér. = to) jusqu’à * through (a) : 1/ traversant(e) - through bolt : boulon traversant ; 2/ fini(e), terminé(e) - We are through! : Entre nous, c’est terminé ! - to be through with sth : a/ en avoir assez de qch ; b/ to be through with sb : avoir rompu avec qn * throughout (prép.) : 1/ d'un bout à l'autre de, pendant tout(e) + durée - throughout the machine’s operating life : pendant toute la durée de fonctionnement de la machine ; 2/ dans tout(e) … + domaine : throughout Europe : dans toute l’Europe * throve (prét. de to thrive) * throw (v) (threw, thrown) (tr.) : 1/ jeter, lancer, balancer - to throw a wrench in the works : mettre des bâtons dans les roues - throw pillow (amér.) : coussin décoratif (brit. scatter cushion) - throw rug : carpette (f), petit tapis ; 2/ troubler, déconcerter, désarçonner - That threw me for a second : Cela me désarçonna pendant quelques instants * throw (n) : lancer - the hammer throw : le lancer de marteau * throw around (v) (threw, thrown) (tr.) : lancer - all the numbers being thrown around : tous les chiffres brandis ici et là * throw away (v) (threw, thrown) (tr.) : jeter au rebut, jeter au panier * throw back (v) (threw, thrown) (tr.) : rejeter * thrower (n) : - hammer thrower : lanceur de marteau - flame-thrower : lance-flamme (masc.) * throw in (v) (threw, thrown) (tr.) : ajouter (qch), donner (qch) par dessus le marché - He goes to church at Christmas and Easter, throw in a few weddings and funerals : Il va à l’église à Noël et à Pâques, ajoutez-y quelques mariages et funérailles * thrown (pp de to throw) * throw over (v) (threw, thrown) (tr.) : abandonner (un ami) * thrust (n) : poussée (f) (en architecture, en propulsion) - take-off thrust : poussée au décollage - thrust reverser : inverseur de poussée * thrust (v) (thrust, thrust) (tr.) : fourrer, pousser (into, dans) - to be thrust into the spotlight : se retrouver sous les feux des projecteurs * thrust (prét. de to thrust) * thrust (p. passé de to thrust) * thruster (n) : propulseur * thud (n) : bruit sourd * thug (n) : voyou * thuggery (n) : comportement de voyou, violence * thumb (n) : 1/ pouce - to stand out like a sore thumb : faire tache ; 2/ (expressions) - You’ll be under her thumb : Tu seras sous sa domination, Tu seras sous sa botte * thumb (v) : 1/ (tr.) toucher du pouce, laisser des traces de doigts sur ; 2/ feuilleter (a book, un livre) ; (intr.) - to thumb through a book : feuilleter un livre ; 3/ (tr.) - to thumb a lift : faire signe du pouce aux automobilistes, faire de l’auto-stop, faire du stop (fam.) * thumbnail (n) (abr. de thumbnail image) : vignette (f), imagette (f) * thumbs-down (n) : (le geste) pouce vers le bas, pouce en bas - thumbs-down verdict : verdict défavorable * thumbs-down (v) (tr.) : donner un avis défavorable à, refuser * thumbsucker (n) : blanc bec * thump (v) : 1/ (tr.) donner un coup de poing à, filer un marron à (fig.) ; 2/ (tr.) cogner ; 3/ (intr.) [cœur] cogner (dans la poitrine) * thump (n) : 1/ coup, marron (fig.) ; 2/ - thumps (pl.) : battements, cognements (du cœur dans la poitrine) * thumper (n) : 1/ cogneur ; 2/ bonimenteur - Bible thumper : bigot, bigote (en pays protestant) * thunder (n) : tonnerre - to steal sb’s thunder : ravir la vedette à qn * thunderous (a) : tonnant(e), tonitruant(e) - thunderous silence : silence assourdissant * Thursday (n) : jeudi (sans maj.) * thus (adv.) 1/ (m d ph) Thus, ... : Ainsi (= Par conséquent) ; 2/ ainsi (= de cette manière) * thusly (adv.) : 1/ (m d ph) Thusly, ... : Par conséquent, ... ; 2/ (adv. de manière) ainsi, de cette manière * thwart (v) (tr.) : contrecarrer (a plan, un plan, a person, une personne) * thx : abr. de thanks! merci ! * thy (adj. poss.) (arch.) : ton (masc.), ta (fém.), tes (masc. et fém. pl.) * thyme (n) : thym * thyristor (n) : thyristor - thyristor controller : variateur à thyristor * tick (n) (brit.) : coche (f), croix (f) - to mark sth with a tick : cocher qch * tick (n) : tique (f) (l’insecte) * tick (v) (brit.) (tr.) : cocher * tick (v) (intr.) : faire tic tac, battre * ticker (n) : 1/ palpitant (n), cœur ; 2/ bande défilante (f) - news ticker : lecteur de nouvelles - ticker headline : titre de lecteur de nouvelles * ticket (n) (fa) : 1/ billet (de cinéma, etc.) - return ticket (brit.) : billet aller-retour ; 2/ (Politique) liste (f) - to be elected on the Pasqua - De Villiers ticket in the European parliament : être élu sur la liste Pasqua - De Villiers au parlement européen * tickle (n) : chatouillement, chatouille (f) * tickle (v) : (tr .) chatouiller ; (intr.) chatouiller * tickler (n) (amér.) : aide-mémoire (masc.) * ticklish (a) : chatouilleux/-euse * tick-riddled (ac) : [animal] infesté(e) de tiques * tidal (a) : relatif à la marée - tidal energy : force marémotrice (f) - tidal wave : raz de marée - tidal basin : avant-port * tidbit (n) (amér.) : bon morceau * tide (n) : marée (f) - The tide is in : C'est la marée haute - The tide is out : C'est la marée basse - We’ve been cut off by the tide : Nous avons été coupés de la terre par la marée, Nous avons été surpris par la marée * tidings (n pl.) (lit.) : nouvelles (f pl.) * tide over (v) (tr.) : aider (qn) à surmonter (une difficulté), aider (qn) à passer (une mauvaise période) - May I have 1,000 pounds to tide me over until next month? : Puis-je avoir mille livres pour m’aider à passer le cap de la fin du mois ? * tidy (v) (tr.) : ranger * tie (n) : lien - zip ties : attaches à glissière, collier de serrage * tie (v) (tr.) : lier, attacher * tier (n) : étage, niveau, gradin * tier (v) (tr.) : disposer en gradins, constituer en niveaux * tie-up (n) (amér.) : - traffic tie-up : embouteillage (syn. brit. traffic jam) * tie up (v) (tr.) : lier * tiff (n) : querelle (f) - to have a bit of a tiff (amér.) : avoir une petite querelle * TIG (n) (init. de tungsten - inert gas) : TIG - TIG welding : soudage au TIG * tig (n) : jeu du chat * tiger (n) : tigre (pour le fém., cf. tigress) - paper tiger : tigre de papier, colosse aux pieds d’argile * tight (a) : 1/ étroit(e) ; 2/ tendu(e), serré(e), sans jeu ; 3/ ne laissant rien passer, hermétique, étanche, imperméable - to be as tight as a duck’s arse : être on ne peut plus radin * tight (adv.) : 1/ étroitement ; 2/ de façon très tendue, de façon très serrée, fermement - to hold sth tight : a/ serrer fermement ; b/ serrer fort (dans ses bras) - to hold tight (intr.) : a/ ne pas bouger, attendre ; b/ se préparer ; 3/ hermétiquement - Sleep tight! : Dors / Dormez bien, Fais / Faites de beaux rêves ! * tighten (v) : 1/ (tr.) serrer, resserrer - to tighten a bolt : serrer un boulon - to tighten one’s belt : se serrer la ceinture ; (intr.) se serrer, se resserrer ; 2/ (tr.) tendre ; (intr.) se tendre * tightening (n) : serrage, resserrement - belt tightening : serrage de ceinture, politique de rigueur - tightening nut : écrou tendeur - tightening strap : bande de serrage * tight-fisted (ac) : radin(e) * tight-fitting (ac) : [clothes, vêtements] moulant(e), près du corps * tight-knit (ac) : très uni(e) - tight-knit community : communauté très unie (f) * tight-lipped (ac) : qui reste bouche cousue, muet(te) comme une carpe * tightly (adv.) : 1/ étroitement ; 2/ hermétiquement ; 3/ fermement, solidement * tightly coupled (ac) : à couplage étroit * tightly packed (ac) : étroitement serré(e) * tight-packed (ac) : étroitement serré(e) - tight-packed crowd : foule compacte (f) * tights (n pl.) : collants (pl.) * tightwad (n) : radin, radine * tigress (n) : tigresse (fém. de tiger, tigre) * tike (n) : voir tyke (n) * tile (n) : 1/ carreau (on a wall, a floor, sur un mur, un sol) - floor tile : carreau de sol - wall tile : carreau mural ; 2/ tuile (f) (on a roof, sur un toit) - ridge tile : tuile faîtière - stone tile : lause / lauze (f) * tile (v) (tr.) : 1/ carreler ; 2/ couvrir de tuiles, poser des tuiles sur * till (v) (tr.) : labourer - to till the soil : labourer la terre * till (conj. de temps) (cf. until) : 1/ jusqu'à ce que ; 2/ après principale négative) (ne ... que) lorsque, tant que (ne ... pas) * tillage (n) : labourage * tiller (n) : barre (d'un bateau) * tilt (n) : 1/ inclinaison (f), pente (f) ; 2/ penchant ; 3/ (Cin.) panoramique vertical ; 4/ (expressions) - at full tilt : à toute allure, à toute blinde (fam.) - to run full tilt against sth : se jeter tête baissée contre qch * tilt (v) : (tr.) renverser, faire basculer, incliner - to tilt backward : incliner vers l’arrière - to tilt forward : incliner vers l’avant ; (intr.) s’incliner * tilt down (n) : panoramique vertical haut-bas, panoramique descendant * tilted (ppa) : incliné(e), déversé(e) * tilt up (n) : panoramique vertical bas-haut, panoramique ascendant * timber (n) (brit.) : 1/ bois de construction ; 2/ poutre (f) - oaken timbers : poutres de chêne * time (n) : 1/ temps - I did not have time : Je n’ai pas eu le temps - free time : temps libre - spare time : temps libres (pl.), moments perdus (pl.) - preposition of time : (Gram.) préposition de temps - time bomb : bombe à retardement - time lapse : a/ laps de temps, temps écoulé (between… and…, entre… et…) ; b/ (Phot.) accéléré (n) - time lapse video : vidéo en accéléré - time machine : machine à remonter le temps - time travel : voyages temporels (pl.) (syn. voyages in time : voyages dans le temps) - time traveller : voyageur temporel - time zone : fuseau horaire ; 2/ times (pl.) : temps (pl.), époque (sing.) - the end times : les temps derniers, les temps ultimes, la fin du monde ; 3/ durée (f), temps - air time : (Radio) temps d’antenne - flight time : temps de vol - running time (Cin.) : durée (d’un film) - in no time (at all) : en un rien de temps (syn. in less than no time) ; 4/ moment - (at) any time : à n’importe quel moment, à tout moment - at one time : il y eut un moment où, il fut un temps où ; 5/ (l’)heure (qu’il est) - What time is it? : Quelle heure est-il ? - What’s the time? (incorrect) : Quelle heure il est ? (incorrect) - at the current time : à l’heure actuelle - It’s at times like this that… : C’est à des moments comme ça que… - drinking-up time (brit.) : (dans un pub) (l’) heure de finir son verre - time stamp : date et heure, données d’horodotage (f pl.), horodotage ; 6/ horaire - prime time : tranche horaire de plus forte écoute (19 h 30-23 h), début de soirée - access prime time : tranche horaire 18 h 30 - 20 h ou 19 h - 20 h, avant-soirée (f) - programme times (pl.) : horaire (sing.) des émissions ; 7/ fois - n times as + adj. : n fois plus + adj. - n times less + adj. : n fois moins + adj. - n times more + adj. : n fois plus + adj. - n times as much + subst. sing. / as many + subst. plur. : n fois plus de + subst. - n times the figure of / the rate of / the cost of / the size of : n fois le chiffre de / le taux de / le coût de / la taille de ; 8/ (Mus.) mesure (f) - to beat time : battre la mesure - to keep time : rester en mesure, jouer en mesure ; 9/ temps accordé à qn - Thank you for your time : Merci de m’avoir accordé un peu de votre temps, Merci d’avoir pris le temps de m’écouter, Merci de m’avoir reçu, Merci de votre accueil * time (v) (tr.) : 1/ minuter, chronométrer ; 2/ synchroniser * time-consuming (ac) : qui prend du temps, chronophage * time-intensive (ac) : qui exige beaucoup de temps, qui demande un temps fou, de longue haleine - time-intensive investigations : recherches qui demandent un temps fou - time-intensive training : formation de longue haleine * time lapse (n) : 1/ temps écoulé, laps de temps (between… and…, entre… et…) ; 2/ (Cin., Vidéo) mouvement accéléré, accéléré (masc.) - time lapse capturing : capture automatique en rafale - time lapse sequence : séquence en accéléré - time lapse video : vidéo en accéléré * time lapse (v) (intr.) : (Cin., Vidéo) passer en accéléré * timeless (a) : 1/ intemporel(le) - timeless beauty : beauté intemporelle (f) ; 2/ éternel(le) - timeless question : question éternelle (f) * time line / timeline (n) : 1/ axe temporel ; 2/ frise chronologique (au prop.) ; 3/ chronologie (f) - historical timeline : (f), historique (n masc.) ; 4/ calendrier (d’un projet) ; 4/ (rés. soc.) journal * timer (n) : 1/ minuterie (f) ; 2/ minuteur, sablier ; 3/ chronomètre ; 3/ (amér.) old timer : a/ ancien, personne âgée (f) ; b/ vétéran * time-sensitive (ac) : urgent(e) - difficult, time-sensitive decisions : décisions difficieles, urgentes * time-serving / timeserving (ac) : opportuniste (m/f) * time-serving / timeserving (n) : opportunisme * time-space (n double) : 1/ (l’)espace-temps ; 2/ (mod.) spatio-temporel(le) * time-stamp / timestamp (n) : date et heure, données d’horodotage (pl.), horodotage * time-stamped / timestamped (a) : horodaté(e) - timestamped image : image horodatée * timetable (n) : emploi du temps * time-tested (ac) : éprouvé(e), qui a fait ses preuves * timid (a) (fa) : timide, craintif /-ive * timidly (adv.) : timidement, craintivement * timing (n) : 1/ minutage, chronométrage ; 2/ synchronisation (f) * tin (n) : 1/ étain ; 2/ fer blanc - tin opener (brit.) : ouvre-boîte (masc.) (syn. amér. can opener) * tinge (n) : teinte (f) * tingle (v) (intr.) : picoter * tinker (n) : rétameur - He’s no tinker! : Ce n’est pas n’importe qui ! * tinker (v) : (tr.) bricoler, tripatouiller, toucher à ; (intr.) (to tinker with sth) jouer avec qch, bricoler qch * tinkering (n) : bricolage * tinkle (n) : tintement * tinkle (v) (intr.) : tinter * tin-plated (ac) : étamé(e) - tin-plated copper : cuivre étamé * tiny (a) : minuscule * tip (n) : 1/ bout, extrémité (f), pointe (f) ; 2/ astuce (f), tuyau (fam.) - tricks and tips : astuces et tuyaux * tip (v) (tr.) : renseigner, tuyauter (fam.) * tip off (v) (tr.) : tuyauter * tip-off (n) : tuyau (le renseignement) * tipsy (a) : un peu ivre, pompette * tiptoe (v) (intr.) : marcher sur la pointe des pieds * tire (v) : (tr.) fatiguer ; (intr.) se fatiguer - to tire of sth : se lasser de qch * tired (ppa) : fatigué(e) * tiredness (n) : fatigue (f) * tireless (a) : [individu] infatigable, [travail] soutenu * tirelessly (adv.) : infatigablement, inlassablement * tiresome (a) : fastidieux/-euse * tissue (n) (fa p) : 1/ tissu (du corps humain) ; 2/ (abr. de paper tissue) mouchoir en papier * titch (n) (brit.) : 1/ mioche, chiard, mouflet ; 2/ nain, nabot, minus * tit (n) : sein, néné (fam.), nichon (vulg.) - big tits : gros nichons - natural tits : seins naturels * tithe (n) : dîme (f) - tithe barn : grange dimière (f), grange à dîmes * title (n) : 1/ titre ; 2/ (Presse) titre - press title titre de presse - major title : titre de premier plan - online-only title : titre n’existant qu’en ligne * titled (ppa) : titré(e) (anton. untitled) - titled nobility : noblesse titrée * title-worthy (ac) : qui correspond au titre - a not so title-worthy account : un compte rendu qui ne correspond pas tellement au titre * titter (v) (intr.) : rire bêtement * titty (n) (pl. titties) (fam.) : néné (fam.), nichon (vulg.) * tizz (n) (brit.) : voir tizzy * tizzy (n) : affolement, panique (f) - to be in a tizzy : être dans tous ses états (syn. to be in a flutter) - to go into a tizzy : s’affoler, paniquer * TMI (jarg. Web) (init. de too much information, tu en dis trop, je ne tiens pas à le savoir) * to (prép.) : 1/ jusquà, à ; 2/ (= according to) selon, suivant, conformément à * to and from (prép. coordonnées) (avec mouvement) : en arrivant à + subst. et en sortant de + subst. * toast (n) : 1/ (ind. sing.) pain grillé - slice of toast : tranche de pain grillé ; 2/ a toast : verre que l’on boit en l’honneur de qn, un toast - I believe a toast is in order : Je pense qu’un toast s’impose ; 3/ (expression) - to be toast : être grillé, être cuit, être foutu * toast (v) (tr.) : 1/ (tr.) faire griller ; 2/ (tr.) se réchauffer (one’s hands, les mains, one’s feet) les pieds) devant un feu ; 3/ (tr.) boire à la santé de, lever son verre à ; (intr.) porter un toast, lever son verre * toaster (n) : 1/ grille-pain (masc.) - to plug in a toaster : brancher un grille-pain ; 2/ - feet toaster : appareil pour se réchauffer les pieds * tobacco (n) : tabac - a plug of tobacco : une chique * tobacconist (n) : buraliste (m/f) * Toby (n pr.) : Toby - Toby jug : chope Toby * toby (n) (abr. de Toby jug) : chope Toby * today (adv.) : aujourd’hui - today’s special : le plat du jour - today's world : le monde actuel - today’s youth : la jeunesse actuelle * toddle (v) (intr.) : 1/ marcher à petits pas chancelants, trottiner ; 2/ (fig.) se promener tout doucement, faire un petit tour - to toddle one’s way : aller son petit bonhomme de chemin * toddler (n) : 1/ enfant en bas âge, tout petit (à la démarche encore hésitante) ; 2/ personne qui trottine * toddy (n) : grog - hot toddy : grog bien chaud * to-do (mod.) : - to-do list : liste de choses à faire, ce qui est à faire, tâches à faire (f pl), tâches en attente * toe (n) : orteil - to stub one’s toe : se cogner le doigt de pied - the big toe : le gros orteil - the little toe : le petit orteil - wide-set toes : orteils très écartés * toehold (n) : 1/ (en escalade) prise (f) (pour le pied) ; 2/ (fig.) pied - to give sb a toehold in… : permettre à qn de prendre pied dans… * toenail (n) : ongle de pied - ingrown toenail : ongle de pied incarné * together (adv.) : 1/ ensemble - We are all in this together : On est tous dans le même bâteau / la même galère ; 2/ (après un verbe, en postposition) - to fit together (tr.) : assembler ; (intr.) s’assembler - to hold together (tr.) : faire tenir ensemble; (intr.) tenir ensemble - [plant] to be held together by wire and chewing gum : [installation] ne plus tenir que par des bouts de ficelle - to ink together (tr.) : relier entre eux/elles - to link computers together : relier des ordinateurs entre eux - to piece together (tr.) : a/ rassembler les fragments de ; b/ reconstituer - to put back together (tr.) : remonter, réassembler - to short together (tr.) : court-circuiter (les bornes d’une batterie) - Shorting the battery terminals together may cause sparks, burns or a fire : Le court-circuitage des bornes de la batterie peut causer des étincelles, des brûlures ou un incendie * together with (loc. prép.) : (selon le cas) en combinaison avec, couplé avec, avec, en y ajoutant, en plus de, en même temps que, ainsi que * toggle (n) : bouton - toggle switch : (Élect.) va-et-vient - toggle button (Électron.) : interrupteur à bascule * toggle (v) : (tr.) basculer, appuyer sur, activer (un commutateur) ; (intr.) - to toggle between… and… : passer de… à… * togs (n pl.) (brit.) (fam.) : 1/ affaires (f pl.) ; 2/ fringues (pl.) (fam.), frusques (pl.) (fam.), nippes (f pl.) * toil (n) : labeur * toil (v) (intr.) : travailler dur, peiner * toilet (n sing.) : toilettes (f. pl.), w.-c. (m pl.) - The toilet is on the ground floor : Les toilettes / Les w.-c. sont au rez-de-chaussée - toilet bowl : cuvette (des toilettes) - toilet paper : (du) papier toilettes, (du) papier hygiénique (syn. lavatory paper) - pit toilet : latrines à fosse, toilettes extérieures (pl.) - dry pit toilet : toilettes sèches (pl.) * toiletries (n pl.) : objets de toilette, produits de toilette * to-ing and fro-ing (nv double) : allées-et-venues (pl.) * token (n) : 1/ jeton ; 2/ bon (syn. voucher) ; 3/ témoignage (syn. sign, symbol) * told (prét. de to tell) * told (pp de to tell) : - all told (après un nombre) : en tout - all told, … (en début de phrase) : tout compte fait, …, somme toute, … * tolerance (n) : 1/ tolérance (f) ; 2/ (Usin.) - machining tolerances : tolérances d’usinage * tolerant (a) : 1/ tolérant(e) ; 2/ libéral(e) * tolerate (v) (tr.) : supporter * toll (n) : 1/ péage ; 2/ tribut prélevé - to pay the highest toll : payer le plus lourd tribut ; 3/ prix à payer, conséquences (pl.) * tomato (n) (pl. tomatoes) : tomate (f) * tomcat (n) : matou * tommy gun (n) : pistolet automatique * tone (n) : 1/ ton - the tone is pitch perfect : le ton est juste ; 2/ (Mus.) tonalité (f) - ringing tone : tonalité d’appel - tone control : réglage de la tonalité (d'une guitare électrique) * tone deaf (ac) : - to be tone deaf : ne pas avoir l'oreille musicale (anton. to have a perfect pitch ear : avoir l'oreille absolue) * tongs (n pl.) : 1/ pincettes ; 2/ pince (sing.) à sucre * tongue (n) : 1/ langue (dans la bouche) ; 2/ langue (parlée ou écrite), langage - to try to master another tongue : essayer de maîtriser une autre langue - mother tongue : langue maternelle - native tongue : langue maternelle - regional tongue : langue régionale - second tongue : a/ deuxième langue ; b/ langue étrangère - unwritten tongue : langue non écrite * tonsil (n) : amygdale - to have one’s tonsils out : se faire enlever les amygdales - tonsil stone : pierre d’amygdale * tonsillitis (n) : amygdalite (f) * took (prét. de to take) * tool (n) : outil - set of tools : ensemble d’outils - assessment tool : outil d'évaluation - cutting tool (Usin.) : outil de coupe - machine-tool (Usin.) : machine-outil - maintenance tool : outil de maintenance - plugging tool : enficheur - predictive tool : outil de prévision - unplugging tool : désenficheur - tool belt : porte-outil (la courroie) - tool bit : mèche d’outil - tool changer (Usin.) : système de changement d’outils, changeur d’outils - tool compensation (Usin., commande numérique) : correction d’outils - tool head (Usin.) : tête à outil - tool holder (Usin.) : porte-outil - tool kit : boîte à outils, trousse à outils - tool pusher : (industrie pétrolière) outilleur - tool rack : porte-outil mural * tooth (n) (pl. teeth) : 1/ dent - to have a sweet tooth : aimer les sucreries, être amateur de sucreriess, avoir le bec sucré ; 2/ rouage - tooth of wheel : rouage * toothache (n) : mal de dents * toothbrush (n) : brosse à dents - toothbrush holder : porte-brosse à dent * tooth-eroding (ac) : qui abîme les dents * toothless (a) : édenté(e) * toothpaste (n) : (de la) pâtre dentifrice * top (n) : 1/ sommet, cime, haut - at the top of… : au sommet de… - from the top down : de haut en bas, en partant du haut - on top of that : qui plus est, en plus de cela - mountain top : sommet ; 2/ dessus (d’une table) ; 3/ (Mus.) tête - to be top of the pops : être en tête des chansons à succès ; 4/ haut (d’un vêtement) - low-cut top : haut échancré, haut décolleté - tank top : a/ (brit.) : pull sans manches (des années 1970), b/ (amér.) débardeur, marcel, camisole (Q) * top (a) : 1/ supérieur(e), haut placé(e) - top company executive : cadre supérieur - top dog (arg.) : grand patron, grand manitou (aussi topdog) - top layer : couche supérieure - top man : chef - top management : cadres supérieurs (pl.) - top performance : rendement supérieur - top spot : (Mus.) première place - [song] to make the top spot : [chanson] décrocher la première place ; 2/ super (fam.) - top tips : super astuces * top (v) (tr.) : 1/ être en tête de - to top the league table : être en tête du palmarès ; 2/ dépasser * top-end (ac) : (de) haut de gamme * top-flight (ac) : 1/ de haut vol, de haute volée - top-flight busineesman : homme d’affaires de haut vol ; 2/ de première qualité, de premier ordre * topgallant (n) : (voile, mât, vergue de) perroquet * top-heavy (ac) : 1/ mal équilibré(e), instable - top-heavy tower : tour au sommet instable ; 2/ (fig.) [organisation] pléthorique au sommet * topic (n) : 1/ sujet (de conversation, de discussion), thème - This is off (the) topic : C’est hors sujet - to introduce a topic : aborder un sujet - every conceivable topic : tous les sujets qu'on peut imaginer - trending topic : sujet dans l’air du temps - topic ban : (WP) restriction thématique (f) ; 2/ sujet d'actualité * topical (a) : d’actualité * topicality (n) : actualité (d’un sujet) * top-loader (nc) : machine à chargement vertical, machine à chargement par le haut / par le dessus * top-loading (ac) : à chargement par le haut / par le dessus, à chargement vertical - top-loading washing machine : machine à laver à chargement par le dessus * topmost (a) : le plus élévé, le plus haut - the topmost branch : la branche la plus haute * top-notch (ac) : de premier ordre * top off (v) (tr.) : 1/ remplir à ras bord ; 2/ parachever, parfaire, compléter, terminer en beauté ; 3/ couronner (fig.) * top-of-the-line (ac) : de haut de gamme (anton. bottom-of-the-line : de bas de gamme) * topper (n) : 1/ chapeau haut-de-forme (syn. top hat) ; 2/ chose remarquable (f), summum, comble ; 3/ personne remarquable (f), quelqu’un de super (fam.) ; 4/ - mattress topper : surmatelas * topping (n) : garniture (f), nappage (si liquide), dessus * topple (over) (v) : (tr.) renverser ; (intr.) tomber * top-quality (ac) : extra (syn. first-rate) * topsoil (n) : terre végétale (f) * top-to-bottom (ac) : de haut en bas, de fond en comble - top-to-bottom restructuring : restructuration de fond en comble * top up (v) : (intr.) faire le plein (with, de) * torch (n) : 1/ torche (f) - torch song : chanson d’amour triste, chanson mélo ; 2/ lampe de poche, lampe torche (f) (amér. flashlight) ; 3/ (abr. de blowtorch) chalumeau ; 4/ - water torch : appareil à découper par jet d'eau * torch (v) (tr.) : mettre le feu à, brûler, cramer (fam.) * tore (prét. de to tear) * torment (n) : tourment, souffrance (f) * torment (v) (tr.) : 1/ tourmenter, faire souffrir ; 2/ (fam.) embêter * tormenter (n) : voir tormentor (n) * tormentor (n) : persécuteur, bourreau (syn. harasser) * torn (p. passé de to tear) * tornado (n) : tornade (f) - tornado chaser : chasseur de tornades - tornado chasing : chasse à la tornade, chasse aux tornades, traque des tornades * torpedo (n) : torpille (f) - torpedo launcher : lance-torpille (m) (l’appareil) (syn. torpedo tube) * torque (n) : (Phys.) couple - torque value : valeur du couple ; (Indust.) couple de serrage (d’un boulon) * torque (v) (tr.) : serrer (un écrou, etc.) * torrent (n) : torrent * torrential (a) : torrentiel(le) - torrential rain : pluie torrentielle (f) * torsional (a) : tors(e), tordu(e), courbe * torsionally (adv.) : en torsion * torsionally stiff (ac) : rigide en torsion - torsionally stiff couplings (pl.) : accouplements rigides en torsion (pl.) * torso (n) : 1/ torse (partie du corps) ; 2/ buste (de statue) ; 3/ œuvre inachevée (f), œuvre mutilée (f) * tort (n) (fa) : délit - action in tort : action en reponsabilité délictuelle - maritime tort (Droit) : délit maritime - tort lawyer (amér.) : avocat spécialisé en responsabilité délictuelle * tortoise shell / tortoiseshell (n) : écaille de tortue (le matériau) - glasses in tortoiseshell : lunettes en écaille de tortue * torture (n) : torture (f) * torture (v) (tr.) : torturer - to torture onseself : se torturer l’esprit * tortured (ppa) : 1/ torturé(e) ; 2/ aberrant(e) - tortured logic : raisonnements aberrants (pl.) * torturer (n) : tortionnaire (n) * torus (n) (pl. tori) : tore (masc.) * toss (n) : jeter (n), lancer (n) * toss (v) (tr.) : lancer, balancer, balarguer - tossing the caber : (Écosse) (le) lancer de troncs * tosser (n) : lanceur - caber tosser : (Écosse) lanceur de troncs * to such an extent that (loc. conj. de conséquence) : à tel point que, à telle enseigne que * to this end (m d l) : à cet effet * totter (v) (intr.) : chanceler * total (a) : total(e), absolu(e), intégral(e) * total (v) (tr.) : totaliser - to total more than FF400m : atteindre un total de plus de 400 m de francs * totaled (a) (amér.) : [auto] bousillé(e) * totalitarian (a) : totalitaire * totalitarianism (n) : totalitarisme * totally (adv.) : entièrement, totalement * totally new (ac) : entièrement nouveau/-velle * totally reliable (ac) : d’une fiabilité absolue * totally unmanned (ac) : entièrement robotisé(e) - totally unmanned production : fabrication entièrement robotisée * tote (n) : fourre-tout (sorte de sac) (masc.) - tote bag : sac fourre-tout, sac cabas * tote (v) (amér.) (fam.) : trimballer, emporter avec soi * TOTP (n) (abr. formée des initiales de l’émission de télévision britannique Top of the Pops) * touch (n) : 1/ contact - to lose touch with… : perdre le contact avec… - to put sb in touch with… : mettre qn en contact avec… 2/ (Mus.) main (au sens figuré), patte (idem), style - the French touch : la patte française (f), l'école française (f) * touch (v) : (tr.) toucher ; (intr.) [article] to touch on… : [article] traiter de… * touch-and-go (n) : situation où le résultat dépend d’un rien * touchdown (n) : atterrissage, arrivée au sol * touch down (v) (intr.) : [avion] atterrir * touching (prép.) : pour ce qui touche à * touching up (n) : retouches (f pl.) * touch off (v) (tr.) : 1/ faire partir, tirer (au canon, avec une mèche), faire exploser (une mine) ; 2/ susciter (une guerre, une révolution, une émeute) * touch up (v) (tr.) : retoucher * tough (a) : 1/ dur(e), endurci(e) - a tough guy : un dur - tough nuts : des durs ; 2/ rude - to have a tough time of it : en voir de dures * tough (n) (amér.) : dur à cuire, voyou * toughen (v) : (tr.) durcir, endurcir ; (intr.) durcir, s’endurcir * toughened (ppa) : blindé(e) - toughened glass window : vitre blindée (f) * tour (n) : 1/ (Presse) tournée (f), voyage, visite (f) - press tour : voyage de presse, visite des services de presse ; 2/ (Mus.) tournée - on tour : en tournée * tour (v) : 1/ (tr.) visiter - to tour a country : visiter un pays ; 2/ (tr.) [chanteur, troupe de théâtre] faire une tournée en/à… * tourer (n) : 1/ voiture de tourisme (f), routière (f) - a grand tourer : une voiture de grand tourisme, une grand tourisme ; 2/ (Mus.) entrepreneur de tournées * touring (n) : tourisme * tourism (n) : (le) tourisme - mass tourism : (le) tourisme de masse - tourism reporting : journalisme touristique * tourist (n) : touriste (m/f) - tourist resort : centre touristique - tourist trap : piège à touristes, attrape-touriste (masc.) * tournament (n) (fa) : tournoi * tourniquet (n) : ligature (f), garrot * tousle (v) (tr.) : ébouriffer (les cheveux) * tousled (a) : [cheveux] ébouriffé(s) * tow (v) (tr.) : tracter, remorquer - to tow a ship : remorquer un navire * towards (brit) / toward (amér.) (prép.) : 1/ en direction de, vers ; 2/ + lieu ou temps : aux alentours de, vers ; 3/ + gér. : en vue de, pour, en prévision de * towed (ppa) : remorqué(e) - towed convoy : convoi remorqué (anton. pushed convoy) * towel (n) : 1/ serviette (f) - dish towel : torchon - hand towel : essuie-main (masc.) - paper towels (pl.) (amér.) : (de l’)essuie-tout (syn. brit. kitchen paper) - tea towel (brit.) : torchon - towel rack : porte-serviette (masc.) (syn. towel rail) ; 2/ (locution) - to chuck in the towel : (fig.) jeter l’éponge * towelling (n) : - Turkish towelling : (du) tissu éponge * tower (n) : tour (f) - bell tower : clocher - rain tower : (Cin.) tour à pluie (f), machine à pluie (f) - tower block : immeuble tour - lifeguard tower : poste de sauvetage, guérite de sauveteur (f) * towing (n) : tractage, remorquage - towing of ships : remorquage de navires - sailplane towing : remorquage de planeurs - towing vehicle : véhicule de dépannage, dépanneuse * town (n) : ville (f) - the outskirts of the town : les abords de la ville - ghost town : ville fantôme - native town : ville natale - town planner : urbaniste (m/f) - town planning : urbanisme * township (n) : commune (f) * toxic (a) : 1/ toxique - toxic waste : déchets toxiques (pl.) ; 2/ (fam.) nocif/-ive, néfaste * toxicity (n) : 1/ toxicité (f) ; 2/ (fam.) caractère nocif, caractère néfaste * toxin (n) : toxine (f) * toy (n) : jouet - anal toy : (Sex.) jouet anal - sex toy : (Sex.) accessoire érotique, jouet intime * toy (v) (intr.) : jouer (with, avec) * toyotism (n) : (le) toyotisme * toyshop (n) : magasin de jouets * trace (n) : 1/ trace (f) - ground traces : traces au sol ; 2/ pointe (f), soupçon ; 3/ trait (du harnais) * trace (v) (tr.) : localiser, trouver, retrouver, dépister - to trace a UFO by radar : suivre un ovni au radar * trace off (v) (tr.) : décalquer * trache (n) (abr. fam. de tracheotomy : trachéotomie, f) : trachéo (f) (fam.) - I could not breathe, so they had to cut a trache in : Je ne pouvais plus respirer, on m’a donc fait une trachéo * tracheotomy (n) : trachéotomie (f) * track (n) : 1/ piste (f) - to keep track of… : se tenir au courant de…, suivre l’évolution de… - to lose track of… : perdre la notion de… - the beaten tracks : les sentiers battus ; 2/ voie (ferrée) (f) ; 3/ circuit - race track : piste de course automobile, circuit automobile ; 4/ (Mus.) a/ piste ; b/ morceau - that's my favourite track on the album : c'est le morceau que je préfère dans cet album - sound track : bande sonore (f) (de film) * track (v) (tr.) : 1/ suivre à la trace, traquer, poursuivre, pister - to track a UFO by radar : suivre un ovni au radar ; 2/ repérer, localiser ; 3/ suivre la progression de - to track sb’s progress : suivre pas à pas le cheminement de qn * track down (v) (tr.) : débusquer, dénicher * tracker (n) : traqueur/-euse (n m/f), pisteur/-euse (n m/f) * tracking (n) : 1/ pistage, poursuite (f) - location-based tracking : localisation électronique (f), pistage électronique - tracking shot : plan de poursuite (Cin.) ; 2/ suivi (n) - inventory tracking : suivi des stocks - work tracking : suivi du travail * tracklist (n) : liste des titres (f) (sur un albm, mini-album, etc.) (aussi tracklisting) * tract (n) : étendue (f) * tractable (a) : 1/ [personne] malléable, docile ; 2/ [objet] maniable * traction (n) : 1/ traction (f) - traction resistance : résistance à la traction ; 2/ adhérence (f) (des pneus) ; 3/ - [affair] to gain traction : [affaire] gagner du terrain, prendre de l’ampleur * tractor (n) : tracteur - all-purpose tractor : tracteur tous usages - tractor manufacturer : fabricant de tracteurs - tractor parts : pièces de tracteur * trade (n) : 1/ commerce (f) - commodity trade : commerce des produits de base - furniture trade : (l’)ameublement (l’activité) - maritime trade : commerce maritime - motor trade : (les) automobiles (en tant qu’activité) - pet trade : commerce des animaux de compagnie - slave trade : commerce des esclaves - tourist trade : tourisme - fair trade : commerce équitable - trade fair : foire commerciale (f) - trade mart : comptoir commercial - trade war : guerre commerciale (f) ; 2/ métier, profession (f) (syn. profession) - the trade : les professionnels (pl.) * trade (v) : 1/ (tr.) échanger (sth for sth, qch contre qch) ; 2/ (intr.) commercer, faire des affaires (with sb, avec qn) ; 3/ (intr.) faire des opérations en bourse * trademark (n) : 1/ marque (f) de fabrique ; 2/ signe distinctif * trade off (v) (tr.) : 1/ to trade sth off for sth : échanger qch contre qch ; 2/ sacrifier qch au profit de qch * trade-off (n) : 1/ échange ; 2/ compromis * trader (n) : 1/ marchand(e), commerçant(e), négociant(e) - camel trader : marchand de chameaux - fur trader : pelletier - horse trader : marchand de chevaux, maquignon - slave trader : marchand d'esclaves - sole trader : entrepreneur individuel, auto-entrepreneur - street trader : marchand ambulant ; 2/ (Fin.) négociateur/-trice, courtier/-tière, opérateur/-trice de marché, spéculateur/-trice - day-to-day trader : opérateur au jour le jour - day trader : courtier réalisant ses opérations sur une journée, négociateur sur séance - share trader : placeur/-euse en bourse - stock trader : opérateur en bourse, passeur/-euse d'ordres en bourse * trading (n) : 1/ échanges (pl.), commerce - trading licence : patente (f) ; 2/ (Fin., Bourse) opérations boursières (f pl.), transactions (f pl.), spéculation (f) - trading was heavy : le marché a été agité (anton. quiet : calme) - to halt trading : interrompre les transactions - bond trading : commerce de titres - cryptocurrency trading : opérations en cryptomonnaie - high-frequency trading : transactions à haute fréquence - insider trading : (le) délit d'initié (syn. brit. insider dealing) - the trading floor (amér.) : le parquet, la salle des marchés, l’enceinte des transactions (syn. brit. the dealing floor) * tradition (n) : tradition (f) - centuries-old tradition : tradition séculaire - long-established tradition : tradition établie de longue date * traditional (a) : traditionnel(le), classique - the traditional radio-telephone : le radio-téléphone classique * traditionalism (n) : traditionalisme * traditionalist (a) : traditionaliste - churches of a traditionalist persuasion : églises d’obédience traditionaliste * traditionally (adv.) : traditionnellement - Traditionally, … (t d p) : traditionnellement, ..., De tous temps, … * traduce (v) (tr.) (fa) : 1/ calomnier, diffamer (une personne ou une entité) - My enemies keep traducing me : Mes ennemis n'arrêtent pas de me diffamer ; 2/ (arch.) transmettre, léguer ; 3/ (arch.) traduire * traducement (n) : calomnie (f), diffamation (f), médisance (f) * traducer (n) : calomniateur/-trice (n m/f), diffamateur/-trice (n m/f) * traffic (n) (fa) : 1/ circulation (automobile) (f) - to gum up the traffic : entraver la circulation - [bridge] to be burdened with traffic : [pont] avoir à supporter une circulation - traffic accident : accident de la circulation - traffic collision : collision de véhicules - traffic fatalities : tués sur les routes - traffic growth : accroissement de la circulation - traffic island : refuge - traffic jam : embouteillage - traffic management : gestion de la circulation - traffic noise : bruit de la circulation - traffic tie-up : embouteillage ; 2/ circulation (de données), transit (de données) * trafficker (n) : trafiquant - organ trafficker : trafiquant d’organes * trafficking (n) : 1/ trafic - drug trafficking : trafic de drogues ; 2/ traite (f) - trafficking in persons : (la) traite des êtres humains (syn. human trafficking) * trail (n) : 1/ traînée (f), sillage - to leave a trail of destruction : tout détruire sur son passage ; 2/ sentier (de randonnée) - trail rides : promenades à cheval (f pl.) ; 3/ piste (f), trace (f), traces (f pl.) - money trail : les mouvements de fonds, le parcours de l’argent - to follow the money trail : remonter la piste financière, suivre les circuits empruntés par l’argent - paper trail : trace(s) écrite(s), trace(s) documentaire(s), trace(s) papier (Q) - to keep a paper trail of… : garder une trace écrite de… - to leave a paper trail : laisse des traces écrites * trailer (n) : 1/ (amér.) caravane (f), roulotte (f) (Q) - tent trailer : tente-caravane (f) (caravane dont les parois de toile se replient pour le transport) - vacation trailer : caravane de loisirs - trailer park : camp de caravanes - trailer trash (amér.) : racaille (f), pouilleux (pl.), cas sociaux (pl.) ; 2/ remorque (f) (à l’arrière d’une voiture, d’un tracteur) ; 3/ (Cin.) bande-annonce (f) - preview trailer : film annonce, bande annonce * train (n) : 1/ - to be in train : être en cours - Plans are in train to + inf. : Des plans sont en préparation pour + inf. - to set (a process) in train : mettre (un processus) en marche, enclencher (un processus) - to set a revolution in train : enclencher une révolution ; 3/ convoi - wagon train : convoi de chariots ; 4/ train - driverless train : train automatique - steam-powered train : train à vapeur - train driver : conducteur de train - train spotting : observation de trains * train (v) (tr.) (fa) : 1/ instruire, former, éduquer, entraîner (des personnes), dresser (des animaux) - to train engineers : former des ingénieurs ; 2/ faire grimper, mettre en espalier, diriger (garden trees, des arbres de jardin, etc.) * trained (a) (fa) : instruit(e), formé(e), éduqué(e), entraîné(e), dressé(e) - trained engineer : ingénieur de formation * trainee (n) (fa) : 1/ stagiaire m/f) - to work as a trainee for a company : travailler comme stagiaire pour une société ; 2/ apprenti, apprentie (chez un artisan) * trainer (n) : 1/ entraineur, instructeur/-trice, formateur/-trice, professeur - animal trainer : dresseur d’animaux, dompteur (pour des fauves) - fitness trainer : professeur de remise en forme ; 2/ - potty trainer : petit pot (pour enfants) * training (n) : instruction, formation - to offer training : dispenser une formation - certificate of completion of training : certificat de fin de stage - in-service training : formation sur le lieu de travail - on-the-job training : formation sur le tas - personnel training : formation du personnel - remedial training : remise à niveau - to do remedial training : faire de la remise à niveau - teacher training : formation des enseignants - vocational training : formation professionnelle - training certificate : certificat de stage - training course : stage - the training department : le service de formation - training period : stage - training practices : méthodes de formation, politique (sing.) suivie en matière de formation - training session : a/ séance d’entraînement ; b/ stage de formation * traitor (n) : 1/ traître ; 2/ félon * traitress (n) : 1/ traîtresse ; 2/ félonne * tram (n) (brit.) : tramway, tram (fam.) * tramp (n) : 1/ chemineau, cheminot, voyageur sans domicile, vagabond, clochard ; 2/ (fig.) traînée, salope (vulg.) ; 3/ randonnée - to go for a tramp : partir pour une randonnée * tramp (n) (abr. de ocean tramp, « vagabond des océans ») : cargo (sans ligne régulière) - tramp steamer : bateau à vapeur, vapeur (masc.) * tramp (v) (intr.) : 1/ marcher d’un pas lourd ; 2/ cheminer, voyager ; 3/ (Mar.) transporter à la demande ; 4/ faire une randonnée (syn. to hike) * tramping (n) : transport maritime à la demande * trample (v) : (tr.) - to trample sth : piétiner qch ; (intr.) to trample on sth : piétiner qch * tranny (n) (pl. trannies) : 1/ (Radio) (brit.) (abr. fam. de transistor set) poste à transistors ; 2/ (abr. fam. de transvestite) travesti * tranquil (a) (fa p) : 1/ tranquille ; 2/ serein(e), paisible * tranquility (amér.) / tranquillity (brit.) : tranquillité, quiétude * Trans. (tronc. de Translated by : traduit par / traduction de) : trad. * trans (a) (tronc. de transgender) : - a trans man : un homme trans – a trans woman : une femme trans - a trans person : une personne trans * trans (n) (pl. transes) (tronc. de trans person) : - a trans : un trans * transceiver (n) (contr. de transmitter-receiver) : émetteur-récepteur * transcontinental (a) : transcontinental(e) * transduce (v) (tr.) : 1/ convertir, transformer - to transduce energy from one form to another : convertir une forme d’énergie en une autre ; 2/ (Biol.) transduire (néol.) (transférer de l'ADN d'une cellule à une autre par l'intermédiaire d'un virus bactériophage) - to transduce cells : transduire des cellules * transduced (ppa) : transduit(e) - in vivo transduced cells : cellules transduites in vivo * transducer (n) (Électron.) : transducteur, senseur * transfer (n) : 1/ transfert - transfer operations : transferts (pl.) ; 2/ mutation ; 3/ virement - bank transfer : virement bancaire * transfer (v) (tr.) : 1/ transférer ; 2/ muter * transfer in (v) (intr.) : (Éduc.) être muté, arriver * transfer out (v) (intr.) : (Éduc.) être muté, partir * transferral (n) : transfert (to, à) * transfix (v) (tr.) : transpercer (syn. to pierce through) * transformative (a) : transformatif/-ive * transgender (a) : transgenre - a transgender person : une personne transgenre * transgender (n) : transgenre (n) * transgenderism (n) : transgénérisme * transgenderist (n) : transgénériste * transhumance (n) : transhumance (f) * transsexual (a) : transsexuel(le) * transsexual (n) : transsexuel (n masc.), transsexuelle (n fém.) * trans-Siberian (a) : transsibérien(ne) – (the) Trans-Siberian railway (brit.) / railroad (amér.) : (le) chemin de fer transsibérien * Trans-Siberian (the) (n pr.) : (le) Transsibérien * transistor (n) : (Électron.) transistor - transistor set : poste de radio à transistors * transit (n) : 1/ transport (de marchandises) ; 2/ (amér.) transports en commun (pl.) ; 3/ traversée (f) (d'une ville) - our transit through London : notre traversée de Londres * transitive (a) : (Gram.) transitif/-ive - transitive verb : verbe transitif * translate (v) : 1/ (tr.) traduire (into a language, en une langue) - to translate back into the original language : retraduire dans la langue d’origine -to translate sentence by sentence : traduire phrase après phrase ; (intr.) se traduire (as, par) ; 2/ (intr.) - to translate to … : se traduire par…, être rendu par… - The Russian « grom » translates to « thunder » in English : Le mot russe « grom » se traduit par le mot anglais « thunder » / est rendu par le mot anglais « thunder » ; 3/ (intr.) (fig., = se manifester par) - to translate into… : se traduire par - to translate into gains in quality : se traduire par des gains en qualité * translation (n) (fa p) : 1/ translation (f) ; 2/ déplacement ; 3/ traduction (f) - a literal translation from French : une traduction littérale depuis le français - sugar-coated translation : traduction édulcorée - translation mistake : erreur de traduction * translator (n) : traducteur/-trice * transmission (n) : 1/ transmission (f) ; 2/ transport - electric transmission line : ligne de transport d’électricité ; 3/ (amér.) the transmission : la boîte de vitesses * transmit (v) (tr.) : transmettre, envoyer * transmittable (a) : transmissible * transmitter/receiver (n double) : émetteur-récepteur * transpacific (a) : transpacifique - transpacific liner : paquebot transpacifique * transpire (v) (intr.) : 1/ commencer à être connu(e) ; 2/ se passer, se produire - I don’t know what transpired afterwards : Je ne sais pas ce qui s’est passé par la suite * transport (n) : 1/ transport (de marchandises) - dimensions for transport : cotes de transport - public transport : transports en commun (pl.) ; 2/ acheminement - mail transport : acheminent du courrier - transport charges : frais d’acheminement ; 3/ moyen de transport ; 4/ avion de transport - a commercial transport : un avion de transport commercial * transport (v) (tr.) : 1/ transporter ; 2/ acheminer ; 3/ transférer * transportable (a) : 1/ transportable ; 2/ pouvant être acheminé(e) ; 3/ transférable * transportation (n) (amér.) : transport - transportation company : société de transport (f) - US Department of Transportation : ministère américain des transports * transpose (v) (tr.) : 1/ - to transpose sth with sth : a/ changer qch en qch, b/ permuter qch et qch ; 2/ - to transpose sth to sth : transposer qch * transversal (a) : transversal(e) * transversally (adv.) : transversalement * trap (n) (fa p) : 1/ piège - to walk into a trap : aller droit dans un piège, tomber dans un piège - booby trap : (Milit.) a/ objet piégé ; b/ piège - fly trap : piège à mouches, attrape-mouche (orth. rect.) (aussi flytrap) - tourist trap : piège à touristes ; 2/ trappe (f) - trap door : trappe (aussi trapdoor) ; 3/ clapet (fig.), gueule (f) (vulg.) - Shut your trap! : Ferme ton clapet ! * trap (v) (tr.) : piéger * Trappist (a) : trappiste - to enter into a Trappist vow of silence : entrer à La Trappe * Trappist (n pr.) : trappiste * trash (n ind. sing.) : 1/ rebuts (pl.), détritus (pl.), déchets (pl.) - trash talk : échanges verbaux (pl.) - trash TV : (la) télé poubelle ; 2/ (amér.) (de la) racaille - subhuman trash : débris d’humanité (pl.), sous-hommes (pl.) - trailer trash (amér.) : cas sociaux (pl.), pouilleux (pl.) - trash talk : (de la) provocation - This is trash talk : C’est de la provoc’ * trash (v) (tr.) : 1/ (amér.) envoyer à la casse, jeter à la poubelle ; 2/ causer la perte de (syn. to cause the ruin of…) ; 3/ démolir (un film, un livre, un auteur) ; 4/ saccager, vandaliser (une chambre d’hôtel) * trash-laden (ac) : plein(e) de détritus - trash-laden floor : sol recouvert de détritus, sol jonché de détritus * trash talk (vc) (tr.) : parler en mal de (qn), dénigrer (qn) * trauma (n) : 1/ (pl. traumas) traumatisme (physique) ; 2/ (Indust.) traumatismes (pl.) (psychologiques) * traumatise (brit.) / traumatize (amér.) (v) (tr.) : traumatiser * travail (n) (fa p) : douleurs (f pl) de l’enfantement, travail * travel (n) : 1/ déplacement, course (f) - machine travel : (Usin.) course machine ; 2/ (n ind. sing.) voyages (pl.) - intercontinental travel : déplacements intercontinentaux - space travel : voyages (pl.) dans l'espace - time travel : voyages temporels (pl.) (syn. voyages in time : voyages dans le temps) - travel agency : agence de voyage - travel magazine : revue de voyage - travel news : info trafic - travel section : (Presse) pages (des) voyages - travel time : temps de transport - travel writing : (la) littérature de voyage, (les) écrits des voyageurs, (les) récits de voyage, (les) impressions de voyage * travel (v) (intr.) : 1/ se déplacer, cheminer - to travel at high speed : se déplacer à grande vitesse ; 2/ voyager - to travel in space : voyager dans l'espace - to travel round the world : voyager dans le monde entier * traveler (amér.) / traveller (brit.) (n) : voyageur - business traveller : voyageur d’affaires - time traveller : voyageur temporel * traveling (amér.) / travelling (brit.) (a) : itinérant(e) - travelling salesman : voyageur de commerce * traveling (amér.) / travelling (brit.) (n) : voyages (pl.) - to take to travelling : se mettre à voyager - travelling expenses : frais de voyage * traverse (v) (tr.) : traverser (d’un bout à l’autre) - [stone] to traverse the width of a wall : [pierre] traverser un mur de part en part * travesty (n) : parodie (f), farce (f) - travesty of justice : parodie de justice * trawl (n) : 1/ chalut ; 2/ (fig.) fouille (f) * trawl (v) : (tr.) fouiller, rechercher dans ; (intr.) pêcher au chalut - to trawl for information : aller à la pêche aux informations * tray (n) : plateau (de service) - to eat off a tray : manger dans un plateau - crumb tray : ramasse-miette (masc.) - drinks tray : plateau à boissons (d’un garçon de café) - drip tray : lèche-frite (masc.) (syn. drip pan) * treacherous (a) : 1/ traître/-esse, perfide, fourbe, sournois(e) ; 2/ dangereux/-euse, périlleux/-euse ; 3/ peu fiable * treacherously (adv.) : 1/ traîtreusement, perfidement, fourbement, sournoisement ; 2/ dangereusement * treachery (n) (fa) : traîtrise (f), perfidie (f) * treacle (n) (brit.) : mélasse (f) * tread (n) : 1/ semelle (f) (de chaussure) ; 2/ bande de roulement de pneu ; 3/ pneumatique, pneu (abr.) * tread (v) (trod, trodden) : (tr.) marcher sur - to tread a precarious path between... and... : louvoyer de façon précaire entre... et..., suivre une ligne ténue entre... et... ; (intr.) marcher (on, sur) - You're treading on thin ice : Vous vous avancez sur un terrain dangereux * treadmill (n) (fam.) : 1/ roue sans fin ; 2/ routine (f) * treason (n) : trahison (f) - treason charges : accusations de trahison * treasonous (a) : traître, perfide - a treasonous act : un acte de trahison, une trahison * treasure (n) : trésor - art treasure : trésor artistique, œuvre d’art - treasure hunter : chasseur de trésors * treasure (v) (tr.) : 1/ garder (qch) précieusement ; 2/ chérir (qn) * treasurer (n) : trésorier, trésorière * treasurership (n) : poste de trésorier * treat (n) : 1/ cadeau ; 2/ (of a meal, en parlant d'un repas) régal * treat (v) (tr.) : 1/ traiter, se comporter à l’égard de (qn, qch) ; 2/ traiter, soigner ; 3/ - to treat sb to sth : payer qch à qn, offrir qch à qn - How about I treat you? : Je t’invite (au restaurant) ? * treatment (n) : traitement - heat treatment : traitement thermique * treaty (n) (pl. treaties) : traité - leonine treaty : traité léonin, traité inégal - unequal treaty : traité inégal * treble (v) (tr.) : (tr.) tripler ; (intr.) tripler * tree (n) : 1/ arbre - to cut down a tree : couper un arbre - to fell a tree : abattre un arbre - to prune a tree : élaguer un arbre - ash tree : frêne - cashew tree : anacardier - chestnut tree : châtaignier - fir tree : sapin - fruiting tree : arbre fructifère - garden tree : arbre de jardin - hazel tree : noisetier - Judas tree : arbre de Judée - olive tree : olivier - yew tree : if ; 2/ (fig.) arbre (le schéma) - genealogical tree : arbre généalogique * tree-sitting (nc) : occupation d’arbres, bivouac arboricole * trek (n) : voyage en chariot traîné par des bœufs * trek (v) (intr.) : 1/ voyager dans de grands chariots traînés par des bœufs ; 2/ cheminer, voyager péniblement * tremendous (a) : formidable, extraordinaire * tremendously (adv.) : terriblement, extrêmement, très, beaucoup * tremor (n) : tremblement * trench (n) : 1/ tranchée, fossé ; 2/ (Géo.) fosse (f) - the Mariana Trench : la fosse des Mariannes * trench (v) (tr.) : creuser une tranchée dans, creuser un fossé dans - to dig out a trench down to 1.5 meters deep : creuser une tranchée jusqu’à 1, 5 m de profondeur * trencher (n) : trancheuse (f) * trend (n) : 1/ cours - the trend of my thoughts : le cours de mes pensées ; 2/ direction (f), orientation (f) - the trend of the coast : l’orientation de la côte ; 3/ tendance (f), évolution (f) - the trend away from… to… : l’abandon de… pour… - trend towards + subst. : tendance allant dans le sens de + subst. - deep-rooted trend : tendance de fond - trend forecaster (var. trends forecaster) : analyste de tendances, prévisionniste de tendances (syn. trend seer) - trend setter : personne qui donne le ton - trends specialist : spécialiste des tendances * trend (v) (intr.) : 1/ courir (towards, à), être en direction (towards, de) ; 2/ tendre (towards, vers) - to trend towards socialism : tendre vers le socialisme ; 3/ (Rés. soc.) to be trending : être « tendance », faire recette - The hashtag is trending on social media : Le mot-dièse fait recette sur les réseaux sociaux * trending (a) : (sur les réseaux sociaux) qui cartonne, « tendance » - to be trending : être dans l’air du temps - trending article : article qui fait recette / qui cartonne (fam.), article « tendance » - trending topic : sujet dans l’air du temps * trending (n) : analyse de tendances * trespass (n) : violation de propriété, entrée sans autorisation * trespass (v) : (tr.) enfreindre ; (intr.) entrer sans autorisation * trespassing (n) : - No trespassing! : Entrée interdite !, Propriété privée ! * trestle (n) : tréteau - trestle bridge (amér.) : pont à chevalets - trestle table : table à tréteaux * trial (n) : 1/ épreuve (f) - trial of strength : épreuve de force ; 2/ procès, jugement - trial by jury : procès devant jury, procès avec jury (aussi jury trial) ; 3/ mise à l’épreuve, essai de contrôle, essai, test - to give sb a trial : mettre qn à l’essai - to run trials : faire des essais - trial run : galop d’essai, passage * triangle (n) : triangle * triangle-shaped (ac) : en forme de triangle (syn. triangular-shaped) * triangular (a) : triangulaire - triangular arch : arc en mitre * traingular-arched (ac) : à arc en mitre * triangulate (v) (tr.) (fa p) : 1/ rendre triangulaire, trianguler ; 2/ recouper - to triangulate data : recouper des données * triangulating (n) 1/ triangulation (f) ; 2/ (fa) recoupement (de données), croisement (de données) - triangulating data : recoupement de données * tribal (a) : tribal(e) * tribe (n) : tribu (f) * tributary (n) (pl. tributaries) (fa) : affluent (n) (d'une rivière) * tribute (n) (fa p) : 1/ tribut ; 2/ hommage - to pay tribute to sb : rendre hommage à qn - tribute album : hommage musical * trick (n) : 1/ tour, blague (f), farce (f) - to play a trick on sb : jouer un tour à qn - dirty trick : coup tordu, sale tour, coup en vache (fam.) ; 2/ tour (de prestidigitation) - conjuring trick : tour de prestidigitation ; 3/ tour, combine (f), ruse (f), astuce (f) - tricks and tips : astuces et tuyaux - to try every trick in the trade : essayer tous les tours du métier, essayer toutes les ficelles du métier - social engineering tricks : techniques de manipulation sociale ; 4/ (expressions) - That will do the trick : Cela fera l’affaire * trick (v) (tr.) : mystifier * trickle (n) : filet, écoulement * trickle (v) (intr) : couler en un filet, couler goutte à goutte * trickle down (v) (intr.) : 1/ couler vers le bas ; 2/ (Écon.) ruisseler - to trickle down from the rich to the poor : se propager des riches aux pauvres, ruisseler sur les pauvres (anton. hum. : to trickle up : couler vers le haut) * trickle down (n) : (Écon.) ruissellement, retombées financières (f pl.) (anton. hum. trickle up : ruissellement inversé, remontées financières) - trickle down economics : (le) ruissellement économique - the trickle down theory : la théorie du ruissellement * trick of treat (v) (amér.) (intr.) : (à Halloween) faire la tournée des maisons pour soutirer des bonsbons * trickster (n) : 1/ farceur, farceuse ; 2/ arnaqueur, arnaqueuse, escroc * tricky (a) : [individu] rusé(e) ; [chose] délicat(e), difficile * tricolour (brit.) / tricolor (amér.) (a) : tricolore * tricolour (brit.) / tricolor (amér.) (n) : drapeau tricolore * tricycle (n) : tricycle * tried and true (paire adj.) : éprouvé(e), éprouvé(e) et avéré(e), qui a fait ses preuves - tried and true methods : méthodes éprouvées - tried and true strategy : stratégie qui a fait ses preuves * tried-and-tested (a) (tjrs épithète.) : éprouvé(e) - tried-and-tested method : méthode éprouvée * trifle (n) : bagatelle (f) * trigger (n) : gachette (f) - to press the trigger : appuyer sur la détente * trigger (v) (tr.) : déclencher, actionner * trigger off (v) (tr.) : déclencher, provoquer * trike (n) (forme familière de tricycle) : tricycle * trilateral (a) : trilatéral(e) - trilateral talks : pourparlers trilatéraux * trilby (n) : chapeau mou * trillion (n) (amér. = 10 puissance 12) : mille milliards * trim (a) : 1/ soigné(e), net(te) ; 2/ [personne] svelte, mince * trim (n) : 1/ (ind. sing.) : ornements (pl.), fioritures (f pl.) ; 2/ - a trim : une coupe (f) (de cheveux) - razor trim : coupe au rasoir * trim (v) (tr.) : garnir (with sth, de qch) * trimmer (a) (comp. de supér. de trim) * trimmer (n) : - grass trimmer : coupe-bordure (masc.) - hedge trimmer : taille-haie (masc.) * trinket (n) : colifichet - trinket bowl : vide-poche (masc.) * trip (n) : 1/ excursion (f), voyage, déplacement, séjour - boat trip : excursion en mer - business trip : déplacement professionnel - family trip : séjour en famille - field trip : excursion - language study trip : séjour linguistique - road trip : balade (en voiture, en moto), excursion, virée (f) (fam.), escapade (f) (fam.) ; 2/ (Drogue) trip (frngl.), délire - to have a bad trip : avoir un mauvais délire * trip (v) : 1/ (intr.) faire un voyage ; 2/ (tr.) déclencher ; (intr.) trébucher (over sth, sur qch) * triple (v) : (tr.) tripler ; (intr.) tripler * triple-jabbed (ac) (brit.) (fam.) : triplement vacciné(e), vacciné(e) trois fois (syn. triple vaxxed) * trip over (v) : (tr.) faire trébucher (par un croc en jambe) * tripper (n) : 1/ excursionniste (m/f), touriste (m/f) - day tripper : touriste d’un jour ; 2/ (Drogue) camé (n), drogué (n) * triumph (n) : triomphe - to relish one’s triumph : savourer son triomphe * triumph (v) (intr.) : triompher (over sth, de qch) * triumphal (a) : triomphal, de triomphe - triumphal arch : arc de triomphe * trivet (n) : trépied - as right as a trivet : stable comme un trépied * trivial (a) : insignifiant(e), dérisoire, futile * triviality (n) : 1/ caractère insignifiant, insignifiance (f) ; 2/ (a triviality) une futilité, une bagatelle * trod (prét. de to tread) * trodden (pp de to tread) * trodden (a) : - trodden path : sentier battu (var. well-trodden path) * Trojan (a) : troyen(ne) - Trojan horse : cheval de Troie * troll (n) : provocateur, provocatrice (dans un forum) - paid troll : provocateur dispendié * troll (v) (intr.) : 1/ pêcher à la traîne ; 2/ (fig.) afficher des messages provocateurs (dans un forum), faire de la provoc (fam.) - to troll for flames : chercher des noises - to troll for ladies : draguer des femmes - to troll for votes : aller à la pêche aux voix * trolley (n) : table roulante (f), chariot - shopping trolley : chariot de supermarché - unmanned trolley : chariot téléguidé * trolling (n) : affichage de messages provocateurs, (de la) provoc (fam.) * troops (n pl.) : (Milit.) - (the) troops : les hommes de troupe, la piétaille - newly minted troops : troupes fraîches (f pl.) * trope (n) : (figure de rhétorique) trope (masc.) * trophy (n) (pl. trophies) : trophée (masc.) - trophy hunter : chasseur de trophées * trot along (v) (intr.) (brit.) : se sauver * trot off (v) (intr.) (brit.) : se sauver * trot out (v) (tr.) : 1/ faire parader (un cheval) ; 2/ faire parade de, montrer, exhiber - to trot out one’s new hat : faire voir son chapeau neuf * trouble (n) (fa) : 1/ (n ind. sing.) ennuis (pl.), difficultés (f pl.), problèmes (pl.) - to stir up trouble : créer des problèmes ; 2/ (n ind. sing.) dérangement, peine (f) (qu’on se donne) - It's not worth the trouble : Ça n'en vaut pas la peine - I put myself to all that trouble for nothing : Je me suis donné toute cette peine pour des prunes ; 3/ (au pl. troubles) ennuis, désordres, conflits * trouble (v) (tr.) (fa) : 1/ inquiéter, préoccuper ; 2/ déranger - Sorry to trouble you : Désolé de te déranger / vous déranger * trouble-free / troublefree (a) : sans incidents, sans problèmes, sans ennuis, qui ne pose pas de problèmes, sans histoire * troublemaker (n) : trouble-fête (masc.) * trouble-shoot / troubleshoot (v) (tr.) : rechercher la cause d’une panne, dépanner * troubleshooter (n) : 1/ dépanneur ; 2/ médiateur, conciliateur * troubleshooting (n) : 1/ identification des défauts - troubleshooting guide : guide d’identification des défauts ; 2/ dépannage - technical troubleshooting : résolution de problèmes techniques * trough (n) : abreuvoir * trousers (n pl.) (brit.) : pantalon (sing.), froc (sing.) (fam.) - cargo trousers : pantalon de treillis (syn. amér. cargo pants) * trout (n) : truite (f) * troy (n adjectivé) : troy - troy weights : unités de poids troy * truancy (n) : (l’)école buissonnière (f), (l’)absentéisme scolaire (syn. skipping school) * truant (fa) : dans l'expression to play truant : faire l'école buissonnière, sécher les cours (substantif correspondant : truancy : (l’)école buissonnière, (l’)absentéisme scolaire) * truce (n) : trêve (f) * truck (n) (amér.) : 1/ camion - trucks shipping freight across the US : camions transportant du fret d’un bout à l’autre des États-Unis ; 2/ chariot - electric forklift truck : chariot élévateur électrique * trucker (n) (amér.) : camionneur, routier * trucking (n) : transport routier, camionnage - the trucking industry : le transport routier * truckload (n) (amér.) : (un) plein camion * truckmaker (n) (amér.) : constructeur de poids lourds * trudge (n) : bout de chemin - It's quite a trudge to my house : il y a un bon bout de chemin jusqu'à chez moi * trudge (v) (intr.) : marcher d’un pas pesant, marcher d’un pas lourd, marcher péniblement, marcher en traînant les pieds, se traîner - to trudge through the snow : avancer péniblement dans la neige * true (a) : 1/ vrai(e) - All this may well be true but… : Si cela est peut-être vrai, il n’empêche que… - It’s too good to be true : C’est trop beau pour être vrai - That is true (accent mis sur that) : C’est bien vrai - to ring true : sonner vrai ; 2/ réel(le) - to come true : se réaliser * true and accurate (paire adj.) : vrai(e) et exact(e), véridique et exact(e), conforme à la réalité, fidèle et exact(e) - The information contained therein is true and accurate : Les informations contenues dans ce rapport sont vraies et exactes - a true and accurate description : une description conforme à la réalité * true (v) (tr.) : dresser (une surface), rhabiller (une meule) * trueing / truing (n) : dressage (de surface), rhabillage (de meule) * truffle (n) : truffe (f) - to collect truffles : ramasser des truffes (syn. to pick truffles) - truffle hog : cochon truffier - truffle market : marché aux truffes - truffle oak : chêne truffier - truffle picker : ramasseur de truffes, caveur (dans le Quercy) * truly (adv.) : 1/ réellement ; 2/ (+ adj.) vraiment, réellement + adj. ; 3/ parfaitement ; 4/ sincèrement ; 5/ - Yours truly (en fin de lettre) : Salutations distinguées - yours truly : votre serviteur, bibi (fam.) - a dossier on yours truly, accusing me of being unpatriotic : un dossier accusant votre serviteur de ne pas être patriote * trump (n) : 1/ (Cartes) - trump card : atout ; 2/ (brit.) pet * trump (v) (tr.) : 1/ (tr.) (Cartes) couper (avec un atout) ; 2/ (tr.) (fig.) prendre le dessus sur, surpasser, battre ; 3/ (intr.) (brit.) péter * Trumper (n) : trumpiste (partisan de Donald Trump) * trumpet (n) : trompette (f) * trumpet (v) (tr.) : trompeter ; 2/ célébrer à grand bruit, crier sur tous les toits * trumpeted (ppa) : - much trumpeted : annoncé(e) à grand renfort de publicité, claironné(e) haut et fort * trump up (v) (tr.) : falsifier * truncheon (n) : matraque (f) * trundle (v) (tr.) : véhiculer, pousser * trundle along (v) (intr.) : rouler bruyamment * trunk (n) : 1/ malle (f) ; 2/ coffre (de voiture) - trunk fair (Can.) : vente depuis l’arrière de sa voiture (syn. boot fair) * truss (n) : ferme de charpente - bowstring truss : poutre en arc à tirant * truss (up) (v) (tr.) : ligoter * trust (n) : 1/ confiance (f) ; 2/ - brains trust : état-major ; 3/ groupe d’entreprises - investment trust : société d'investissement * trust (v) : 1/ (tr.) se fier à ; (intr.) croire - In God we trust (sur les dollars) : Nous avons foi en Dieu ; 2/ (tr.) faire confiance à ; 3/ (tr.) confier à - to be trusted with : se voir confier (qch) * trusted (a) : de confiance - trusted man : homme de confiance * trustful (a) : qui fait trop confiance, naïf/naïve * trusting (a) : qui a confiance, qui fait confiance, confiant(e) - to be very trusting of people : avoir beaucoup confiance dans les gens * trustworthy (a) : digne de confiance, à qui on peut se fier, fiable (anton. untrustworthy : qui n’est pas digne de confiance, à qui on ne peut se fier, qui n’est pas fiable * trusty (a) : digne de confiance, loyal(e), fidèle - And here’s a hand, my trusty friend / And gie’s a hand of thine (Auld Lang Syne, lyrics by Robert Burns) * truth (n) : vérité (f) - to distort the truth : travestir la vérité - to tell the truth : dire la vérité - and truth be told : et à dire vrai - the truth behind… : la vérité qui se cache derrière… - a scintilla of truth : une parcelle de vérité - an inconvenient truth : une vérité gênante - the simple truth : la vérité toute simple - the unvarnished truth : la vérité sans fard - truth drug : sérum de vérité * truther (n) (amér.) : complotiste, conspirationniste * truthful (a) : véridique - truthful journalism : journalisme honnête, journalisme qui dit la vérité * truthfulness (n) : véracité (f) * try (v) (tr.) : essayer - to try to master another tongue : essayer de maîtriser une autre langue * trying (a) : éprouvant(e), pénible - in these trying times : en ces moments pénibles, en ces temps difficiles * try-on / tryon (n) : manœuvre frauduleuse (f) (qui n’a pas abouti), tentative malhonnête (f) - It was just a try-on : On voulait simplement (me, te, le, la, vous, nous, les) faire marcher * try-out / tryout (n) : 1/ essai technique (d’une machine), mise au point (d’un outil), essai (d'un produit) ; 2/ audition (f) (d'un acteur) * try out (v) (tr.) : mettre à l’essai, faire un essai avec, faire l’essai de, essayer, tester, soumettre à des essais prolongés - to try out a test : effectuer un essai - to try sth out for the first time : étrenner qch - to try out unorthodox solutions : expérimenter des solutions peu orthodoxes * tryst (n) : rendez-vous galant * T-shaped (ac) : en forme de T * tub (n) : 1/ baquet (syn. (basin) ; 2/ bac, cuve (f) - collecting tub : bac de collecte ; 3/ (amér.) baignoire (f) - to fill the tub : faire couler un bain - bath tub : baignoire (f) * tubby (a) (fam.) : grassouillet(te) * (the) Tube (n pr.) (brit.) : (le) métro * tube (n) : 1/ tube - test tube : éprouvette (f) ; 2/ chambre à air - bicycle inner tube : chambre à air de bicyclette * tubeless (a) : sans chambre à air - tubeless tyre : pneu sans chambre * tuck (v) (tr.) : fourrer * tuck in (v) (tr.) : rentrer - to tuck one’s tie in : rentrer sa cravate * tuck-shop (nc) : magasin de friandises * Tuesday (n) : mardi (sans maj.) * tuft (n) : touffe (f) (of hair, de cheveux, of grass, d’herbe) * tug (n) : 1/ tir, traction (f) - tug of war : a/ tir à la corde ; b/ bras de fer, lutte acharnée (f), lutte finale (f) - You will have a trug to get him to join you : Vous aurez du mal à l’amener à se joindre à vous ; 2/ (fig.) tiraillement - One cannot leave one’s country without a tug : On ne quitte pas son pays sans déchirement ; 3/ remorqueur (aussi tugboat) - pusher tug : remorqueur-pousseur ; 4/ tracteur - airport tug : tracteur d’aéronefs * tug (v) : (tr.) tirer sur, tracter, remorquer ; (intr.) tirer (at sth, sur qch) * tugboat (n) : remorqueur (aussi tug) * tuition (n) : leçons (f pl.) (syn. lessons) * tumbler (n) : 1/ gobelet, timbale (f) ; 2/ verre droit, verre sans pied ; 3/ (Techno.) culbuteur * tumbrel (n) : tombereau * tumour (brit.) / tumor (amér.) : tumeur (f) - malignant tumour : tumeur maligne - to cause a tumour to regress : faire régresser une tumeur * tumour-inducing (ac) : tumorigène - tumour-inducing agent : agent tumorigène * tuna (n) : thon * tune (n) : 1/ air (de musique), mélodie (f) - to play a tune : jouer un air - to sing in tune / out of tune : chanter juste / faux - at the tune of + somme d’argent : à raison de + somme d’argent - catchy tune : air entraînant ; 2/ (expressions) - to call the tune : mener la danse - to change one’s tune : chanter un autre refrain * tune (v) (tr.) : accorder (un instrument) * tuned (ppa) : 1/ [instrument] accordé(e) ; 2/ - (à la radio) Stay tuned ! : Restez avec nous ! * tuneful (a) : mélodieux/-euse * tune in (v) (tr.) : se mettre à l’écoute de - to tune in the broadcasting networks : se mettre à l’écoute des réseaux de radiodiffusion * tuner (n) : accordeur * Tunisia (n pr.) : (la) Tunisie * Tunisian (a) : tunisien(ne) (sans maj.) * Tunisian (n pr.) : Tunisien (le ressortissant) * tunnel (n) : tunnel - wind tunnel : soufflerie (f) * turbidimeter (n) : opacimètre * turbine (n) : turbine (f) - steam turbine : turbine à vapeur - wind turbine : éolienne (f) - turbine blade : ailette (f) * turbo (préf.) : actionné(e) par une turbine * turbo cancer (n) : cancer foudroyant * turbocharged (ppa) : turbo-compressé(e) * turbo-charger (n) : turbo-compresseur * turbojet (n) : turboréacteur * tureen (n) : - soup tureen : soupière (f) * turf (n) : gazon * Turk (n pr.) : Turc/Turque (le ressortissant) * Turkey (n pr.) : (la) Turquie - European Turkey : la Turquie d’Europe * turkey (n) : 1/ dinde (f) - cold turkey : dinde (servie) froide - the cold turkey approach : la méthode du sevrage brutal - to go cold turkey on TV watching : essayer le sevrage brutal de la télé - to quit cold turkey : arrêter brusquement / du jour au lendemain / d'un coup net (de fumer, regarder la télé, etc.) ; 2/ (Cin.) navet (fam.) * Turkish (a) : turc/turque (sans maj.) * Turkish (n) : (le) turc (la langue) * turmeric (adj.) : 1/ relatif au safran des Indes ; 2/ relatif au curcuma (l’épice) - turmeric rhizomes : rhizomes (f pl) de curcuma * turmeric (n) : 1/ safran des Indes ; 2/ curcuma (l’épice) * turn (n) : 1/ tour, rotation (f) - to make a full 360-degree turn : faire un tour complet ; 2/ tournant - at every turn : à tout bout de champ, à tout propos - at the turn of the century : au tournant du siècle ; 3/ virage - to make right-angle turns : virer à angle droit - a 180-degree turn : un virage à 180° ; 4/ tournure (f) - turn of phrase : tournure ; 5/ changement - a turn for the better : une amélioration - My life has taken a turn for the better : Ma vie a pris meilleure tournure ; 6/ tour (dans un jeu, une queue d’attente) - to wait one’s turn : attendre son tour - to speak out of turn : a/ parler alors que ce n’est pas son tour, parler de façon intempestive ; b/ parler à tort et à travers, tenir des propos déplacés * turn (v) : 1/ (tr.) (Usin.) façonner au tour, tourner ; (intr.) tourner 2/ (tr.) - to turn sth into/to + subst. : transformer qch en + subst. - to turn sth to cinders : réduire qch en cendres ; (intr.) se transformer, se changer, se muer (into/to, en) ; 3/ to turn + adj. : devenir + adj. - [things] to turn sour : [choses] mal tourner, se gâter ; 4/ (tr.) dégager (un bénéfice) - to turn a profit : faire des bénéfices ; 5/ (expressions) - to turn a blind eye : fermer les yeux (to, sur) * turn around (v) (intr.) : faire demi-tour * turn back (v) (tr.) : tourner en sens inverse * turn down (v) (tr.) : 1/ (faire) baisser - to turn the thermostat down : baisser le thermostat ; 2/ rejeter, repousser (une proposition) * turned (ppa) : (Usin.) façonné au tour, tourné(e) - turned parts : pièces tournées (f pl.) * turned-up (ppa) : 1/ relevé(e) - turned-up sleeves : manches relevées ; 2/ [nez] retroussé(e) - turned-up nose : nez retroussé, nez en trompette * turn in (v) : 1/ (tr.) remettre, rendre (un devoir scolaire, un rapport) - to turn in one’s conclusions : remettre ses conclusions ; 2/ (intr.) aller se coucher, aller au lit, aller au pieu (fam.), se pieuter (fam.) * turning (n) : 1/ tournant - to reach a turning point (fig.) : arriver à un tournant (de son existence, etc.) ; 2/ (Usin.) tournage - wood turning : tournage du bois - turning machine : tour * turnkey (a) : (livré(e)) clés en main - turnkey delivery of complete plants : livraison d’usines complètes clés en main - turnkey plant : usiné clés en main * turnkey (n) : 1/ geôlier ; 2/ porte-clé (la personne) ; 3/ clé de sécurité * turn off (v) : 1/ (tr.) éteindre, couper, mettre hors tension - to turn off the tap : fermer le robinet ; (intr.) s’éteindre, se couper ; 3/ (tr.) rebuter * turn-off (n) : extinction (f) - power turn-off : mise hors tension * turn on (v) (tr.) : 1/ allumer, mettre sous tension, ouvrir - to turn on one's PC (Inf.) : mettre son PC sous tension - to turn on the tap : ouvrir le robinet ; 2/ activer - to turn on a feature (Inf.) : activer une fonction * turn-on (n) : allumage - power turn-on : mise sous tension * turn out (v) : (tr.) 1/ produire, fabriquer, sortir (syn. to produce) - to turn out cars : produire des voitures, sortir des voitures ; 2/ (intr.) (+ to be) s'avérer (être) ; 3/ (intr.) se montrer, s'assembler * turn over (v) (tr.) : 1/ retourner ; 2/ tourner (une page) - Turn over some more pages : Tourne encore quelques pages ; 3/ faire une rotation de - to turn over one's stock : faire une rotation de stock * turnover (n) : rotation (f) - stock turnover : rotation des stocks * turn round (v) : (tr.) faire tourner ; (intr.) tourner * turnstile (n) : 1/ tourniquet ; 2/ péage (le lieu) - turnstile jumping : sauter le tourniquet * turntable (n) : 1/ tourne-disque (masc.) ; 2/ platine (f) ; 3/ (Usin.) table tournante (f), plaque tournante (f) * turntablist (n) : platiniste (m/f) * turn-up (n) (pl. turn-ups) : revers (de bas de pantalon, de manche) - trousers with turn-ups : pantalons avec revers * turn up (v) : 1/ (tr.) relever, retrousser - to turn up one’s nose : faire la fine bouche ; 2/ (intr.) apparaître, se présenter ; 3/ (intr.) réapparaître * turpentine (n) : térébenthine (f) * turret (n) : tourrette (f) - tool turret : (Usin.) tourelle porte-outils * turtle (n) : tortue de mer (f) * tussle (n) : bagarre (f) * tutorial (n) : travaux pratiques (pl.), travaux dirigés (pl.) * TV (n) (abr. de television) : (la) télé(vision) - on TV : à la télé - cable TV : (la) télé par câble, (la) télé câblée - catch-up TV : (la) télé de rattrapage (syn. replay TV) - high-definition TV : (la) télé (à) haute définition - reality TV : (la) télé-réalité (syn. reality-based TV) - TV antenna : antenne de télé - TV broadcasting : télédiffusion - TV genres : types d'émission télé - TV graphics : (l’)infographie télévisuelle - TV journalist : journaliste télé, journaliste à la télé- TV reporter : reporter télé, reporter à la télé - TV set : poste de télé * twaddle (n) : fadaises (f pl.), âneries (f pl.) * twang (n) : 1/ son vibrant ; 2/ accent nasillard - Texan twang : accent texan * twat (n) (brit.) : 1/ (vulg.) chatte (f) (de la femme) ; 2/ con/conne, connard/connasse * tweak (v) (tr.) : 1/ pincer ; 2/ modifier * tweet (n) : mini-message, tweet (sur le site de microblogage Twitter) * tweet (v) (tr.) : diffuser (un message, un tweet) (sur le site de microblogage Twitter) * tweet-happy (ac) : - tweet-happy journalist : journaliste qui a le tweet facile * tweezer (v) (tr.) : extraire (une épine, une écharde), arracher (un poil) avec une pince * tweezers (n pl.) : pince (f sg.) (pour ramasser de petits objets, extraire une écharde, épiler, etc.), brucelles (f pl.) - a pair of tweezers : une pince * twenties (n pl.) : 1/ nombres de 20 à 29 ; 2/ températures de 20 à 29 ; 3/ latitudes de 20 à 29 ; 4/ années 20 à 29 - the Roaring Twenties : les Années Folles (f pl.) * twenty / 20 (a num.) : vingt / 20 * 24-hour (ac) : sur 24 heures - the 24-hour news cycle : le cycle de nouvelles sur 24 heures, les nouvelles changeant toutes les 24 heures, l’actualité en continu sur 24 heures * twerk (v) (intr.) (twist + jerk) : danser le twerk, twerker (néol.) * twerker (n) : twerkeur (néol.) * twerking (n) : (le) twerk (néol.) * twerp (n) (brit., fam.) : crétin * twice (adv.) : deux fois - to think twice before doing sth : y réfléchir à deux fois avant de faire qch - twice as + adj. : deux fois plus + adj. * twig (n) : brindille (f), petite branche (f), branchette (f) * twig (v) : (tr.) s’apercevoir de (qch), remarquer (qch) - He might twig something : Il pourrait bien s’apercevoir de qch ; (intr.) piger, saisir - I have twigged : J’ai pigé (syn. I have clicked) * twilight (n) : crépuscule * twin (n) : jumeau - fraternal twins : faux jumeaux, fausses jumelles - identical twins : vrais jumeaux * twine (n) : ficelle (f) * twine (v) : (tr.) tresser, entortiller, enrouler ; (intr.) s’enrouler (round, autour de) * twinge (n) : élancement (of pain, de douleur) * twinkle (v) (intr.) : scintiller * twin-row (ac) : à double rangée * twist (n) : 1/ torsion, tour de poignet ; 2/ zigzag * twist (v) (tr.) : 1/ tourner ; 2/ enrouler, entortiller ; 3/ tordre - to twist sb’s arm : tordre le bras à qn * twisted (ppa) : spiralé(e) - twisted cord : cordon spiralé * twisting (n) : torsion (f) * twist off (v) (tr.) : dévisser (le bouchon d’une bouteille) * twist-off (a) : dévissable - twist-off cap : bouchon dévissable * twitch (n) (pl. twitches) : 1/ mouvement convulsif, tressaillement, contraction musculaire (f) ; 2/ tic (facial ou corporel) * twitch (v) (intr.) : tressaillir, se convulser * twitter (v) (intr.) : pépier * two (a) : deux * two-dimensional (ac) : bidimensionnel(le), à deux dimensions * two-floored (ac) : à deux niveaux, sur deux niveaux, à deux étages, sur deux étages - a two-floored flat : un duplex * twofold (a) : double, multiplié(e) par deux * two-man (ac) : de deux ouvriers * two-seat (ac) : (à) deux places - two-seat roadster : décapotable (f) deux places * two-stage (ac) : [fusée] bi-étage * two-thirds (ac) : des deux tiers - a two-thirds majority : une majorité des deux tiers * two-tier (ac) : à deux niveaux, à deux étages - two-tier society : société à deux vitesses * two-way (ac) : 1/ à double sens - two-way street : rue à double sens ; 2/ bidirectionnel(le) - two-way radio : radio bidirectionnelle * tyke (n) (var. tike) : 1/ chien, roquet ; 2/ (fig.) coquin * type (n) : type - body types : morphologies corporelles (f pl.) * type (n ind. sing.) : caractères (pl.) d’imprimerie - display type : caractères de titre, caractères de titrage, caractères d'affiche - pied type : caractères en désordre * type (v) (tr.) : taper (à la machine), saisir (à la machine), dactylographier - to type a text into a PC : taper un texte sur un PC * typecast (a) : typé(e) - a typecast actor : un acteur typé * type in (v) (tr.) : saisir au clavier * typesetter (n) : 1/ typographe, compositeur ; 2/ machine à composer - photo typesetter : photocomposeuse (f) * typesetting (n) : composition (f) * typewrite (v) (-wrote, -written) (tr.) : taper à la machine, dactylographier * typewriter (n) : machine à écrire * typewrote (prét. de to typewrite) * typewritten (ppa de to typewrite) : écrit(e) à la machine, dactylographié(e) * typhus (n) : (le) typhus * typically (adv.) (fa p) : 1/ typiquement ; 2/ habituellement, généralement, en règle générale - typically (en incise) : à la base ; Typically, … (en t d p) : En général, …, En principe, … * typing (n) : dactylographie (f) * typist (n) : dactylo (f) * typo (n) (pl. typos) (Typo.) (tronc. de typographical error) : faute typographique (f), coquille (f), couille (f) (vulg.), faute de frappe (f), erreur d'impression (f) * typographical (a) : typographique * typographically (adv.) : typographiquement, sur le plan typographique * typography (n) : typographie (f) - typography manual : manuel de typographie - typography rules : règles de typographie * tyrant (n) : tyran * tyre (n) : pneumatique (n), pneu - tubeless tyre : pneu sans chambre * TYSM (jarg. Web) (init . de thank you so much, merci infiniment) oc7ghvvddltplb37kensuslw0v4lvdr Philosophie/Thalès de Milet/Textes et traductions période Principat Empire Romain 0 78966 773688 771390 2026-09-30T06:46:31Z Alex Mtlr 103840 /* Chapitre XVII. */ 773688 wikitext text/x-wiki {| border="0" cellpadding="0" width="100%" style="background: #f9f9f9" | colspan="3" height="25"|<div style="text-align: center;">[[Philosophie/Thalès de Milet|'''Thalès de Milet''']]</div> |- | width="33%"|'''[[Philosophie/Thalès de Milet/Textes_et_traductions_période_République_Romaine|Période République Romaine]]''' |- | width="33%"|'''[[Philosophie/Thalès de Milet/Textes_et_traductions_période_Grèce_Hellénistique|Période de la Grèce Hellénistique]]''' |- | width="33%"|'''[[Philosophie/Thalès de Milet/Textes_et_traductions_Ier_millénaire_AEC|Période de la Grèce Classique]]''' |} {{EnTravaux}} <span style="font-size:18pt;">Période du Principat de l’[[w:Empire_romain|''Empire'']] [[#Empire|<span id="Empire_back"><sup>'''I'''</sup></span>]] [[w:Rome_antique|''Romain'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Rome_back|<sup>🔄</sup>]]</span> <p style="text-align: right;">(16 janvier [[w:27_av._J.-C.|-27]] <sup>[[w:Ier_siècle_av._J.-C.|⏳]]</sup>, nomination de [[w:Auguste|'''Caius Iulius Caesar Octavianus''']] aux titres d’[[w:Auguste_(titre)|''Augustus'']] et de [[w:Princeps_senatus|''Princeps'']] par le [[w:Sénat_romain|''Sénat romain'']] — fin du [[w:IIIe_siècle|III<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]], création du système [[w:Tétrarchie|''tétrarchique'']] [[#tétrarchie|<span id="tétrarchie_back"><sup>'''II'''</sup></span>]] par [[w:Dioclétien|'''Dioclétien''']] [[#Dioclétien|<span id="Dioclétien_back"><sup>'''III'''</sup></span>]] pour faire face aux [[w:Invasions_barbares#Première_période_:_les_mouvements_migratoires_germaniques_du_IIIe_siècle|''incursions barbares'']]) {{Boîte déroulante début|titre=NdA Empire|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Empire_back|<span id="Empire"><sup>I</sup></span>]] Du nom commun latin imperium [[wikt:en:imperium#Latin|(en)]], « 1. L’empire, l’État, le gouvernement impérial, le royaume, la domination. 2. Le droit ou le pouvoir de commander ou d’avoir le contrôle ; domination. 3. Commandement ou autorité absolue sur l’empire (ou un autre régime politique) ; souveraineté ; domination. 4. (militaire) Autorité militaire, commandement (d’une armée). 5. L’exercice de l’autorité, de la règle, de la loi, du contrôle, de la souveraineté. 6. Un commandement, un ordre, une direction, une injonction.) »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ du verbe imperō, « 1. (avec datif) Commander, donner des ordres à, imposer, exiger. 2. Gouverner. »;<br /><p style="margin: 0 2em; text-indent: 30px;">➥ du préfixe prépositionnal in-, « 1. Dans, à l’intérieur. 2. Contre; dans; sur; vers. 3. (utiliser comme un intensifieur). 4. Attaché à des [[w:Aspect_inchoatif|''verbes inchoatifs'']], il peut exprimer le sens d’un changement en cours ou d’un achèvement partiel. »;<br /><p style="margin: 0 2em; text-indent: 30px;">➥ +‎ du verbe parō [[wikt:en:paro#Latin|(en)]], « 1. Arranger, ordonner, concevoir. 2. Fournir, meubler, préparer. 3. Résoudre, viser, décider. 4. Obtenir, acquérir, se procurer, se faire. »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ + du suffixe nominal abstractif‎ -ium [[wikt:en:-ium#Latin|(en)]], désignant parfois des offices et des groupes. »;<br /><p style="margin: 0 2em; text-indent: 15px;">L’historien spécialiste de l’[[w:Grèce_antique|''antiquité grecque'']] [[w:Moses_Finley|Moses Finley]] définit un empire par tout {{Info|''« exercice durable par un État d’une autorité, d’un pouvoir, ou d’un contrôle sur un ou plusieurs États, communautés ou peuples »''|Moses Finley, Économie et société en Grèce antique, La Découverte, 2007.}}. L’historien [[w:Jean_Tulard|Jean Tulard]], précise cette définition par {{Info|''cinq traits suivants''|Jean Tulard, Les Empires occidentaux de Rome à Berlin, PUF, 1997.}} : :::* '''Une volonté expansionniste ; :::* '''Une organisation centralisée ; :::* '''Des peuples encadrés par une armature politique et fiscale commune ; :::* '''La croyance en une supériorité d’essence ; :::* '''Un début et une fin clairement identifiés. <br /><p style="margin: 0 2em; text-indent: 15px;">'''[[#tétrarchie_back|<span id="tétrarchie"><sup>II</sup></span>]] Du nom commun grec ancien τετραρχία / tetrarkhía;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ du préfixe τετρα- / tétra- [[wikt:en:τετρα-#Ancient_Greek|(en)]], « quatre »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ + du suffixe -αρχία / -arkhía [[wikt:en:-αρχία#Ancient_Greek|(en)]], « -archie (forme de gouvernement ou de règle) »;<br /><p style="margin: 0 2em; text-indent: 15px;"> Système de gouvernement de l’Empire ''romain'' mis en place par Dioclétien à la fin du [[w:IIIe_siècle|III<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]], pour faire face aux invasions barbares. Il consiste en la division de la direction de l’empire entre, d’une part deux [[w:Empereur_romain|''empereurs'']] — les [[w:Auguste_(titre)|''augustes'']] —, d’autre part deux ''lieutenants'' (successeurs désignés des ''augustes'') — les [[w:C%C3%A9sar_(titre)|''césars'']]. <br /><br /><p style="margin: 0 2em; text-indent: 15px;">'''[[#Dioclétien_back|<span id="Dioclétien"><sup>III</sup></span>]] [[w:Nom_romain|Tria Nomina]] en latin {{Info|Gaius|praenomen, nom individuel du citoyen romain}} {{Info|Aurelius|nomen, nom de famille}} {{Info|Valerius|cognomen, surnom héréditaire, servant à distinguer les diverses branches d’une même gens}}, surnommé Dioclētiānus [[wikt:en:Diocletian#English|(en)]] lorsqu’il a été proclamé empereur par ses troupes;<br /><p style="margin: 0 2em; text-indent: 15px;"> Militaire et empereur, connu pour avoir séparé et élargi les services civils et militaires de l’empire, et réorganisé les divisions provinciales de l’empire, établissant le gouvernement le plus vaste et le plus bureaucratique de l’histoire de l’empire. En [[w:286|286]], il nomme son ''césar'', ou adjoint et successeur, [[w:Maximien_Hercule|Maximien]] ''Auguste'', co-empereur, et partage l’Empire entre l’Orient et l’Occident, puis en 293, y nomme respectivement [[w:Galère_(empereur_romain)|Maximien Galère]] et [[w:Constance_Chlore|Constance Chlore]] comme ''césar''.<br/><br/></div> ''' {{Boîte déroulante fin}} == [[w:Sénèque|'''Sénèque''']] [[#Sénèque|<span id="Sénèque_back"><sup>'''I'''</sup></span>]] == <p style="text-align: right;">([[w:5_av._J.-C.|-5]] <sup>[[w:Ier_siècle_av._J.-C.|⏳]]</sup> / [[w:1|1]] <sup>[[w:Ier_siècle|⏳]]</sup>, à [[w:Corduba|Corduba]] — 12 avril [[w:65|65]], à [[w:Rome_antique|''Rome'']], dans une maison de plaisance, la « quatrième pierre milliaire », contraint au [[w:Suicide_forcé|''suicide forcé'']] par l’empereur [[w:Néron|'''Néron''']] après avoir été dénoncé dans la [[w:Conjuration_de_Pison|''Conjuration de Pison'']], sans preuve selon [[w:Tacite|'''Tacite''']] [https://remacle.org/bloodwolf/historiens/tacite/annales15.htm <sup>Annales, l.V, §§LX-LXVI.</sup>]) [[s:Auteur:Sénèque_le_Jeune|<sup>📚</sup>]] [https://books.google.fr/books?id=_HZTvAxN7CIC&newbks=1&newbks_redir=0&lpg=PA3&dq=bibliogroup%3A%22Dictionnaire%20des%20philosophes%20antiques%22&hl=fr&pg=PA177#v=onepage&q&f=true {{Info|<sup>🔍</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume VI, §43 - Seneca (Lucius Annaeus –)}}] [[Fichier:Duble_herma_of_Socrates_and_Seneca_Antikensammlung_Berlin_03_.jpg|vignette|<p style="text-align: justify; text-indent: 15px;">Double-hermès du [[w:IIIe_siècle|III<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]], unique portrait de '''Sénèque''' nommé et authentifié, et associé à celui de '''Socrate''', dont le point commun est celui d’avoir été contraint de se donner la mort. Copie ''romaine'' d’un modèle fait du vivant même du philosophe [https://books.google.fr/books?id=_HZTvAxN7CIC&newbks=1&newbks_redir=0&lpg=PA3&dq=bibliogroup%3A%22Dictionnaire%20des%20philosophes%20antiques%22&hl=fr&pg=PA180#v=onepage&q&f=true {{Info|<sup>➕</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume VI, §43 - Seneca (Lucius Annaeus –), Iconographie}}] [https://books.google.fr/books?id=_HZTvAxN7CIC&newbks=1&newbks_redir=0&lpg=PA3&dq=bibliogroup%3A%22Dictionnaire%20des%20philosophes%20antiques%22&hl=fr&pg=PA201#v=onepage&q&f=true {{Info|<sup>➕➕</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume VI, §43 - Seneca (Lucius Annaeus –), Iconographie - contribution de J. Lang}}].<br /><p style="text-align: justify; text-indent: 15px;">Matériau : Marbre blanc-brunâtre, légèrement veiné, finement cristallin.<br /><p style="text-indent: 15px;">Provenance : ''Rome'', 1813.<br /><p style="text-align: justify; text-indent: 15px;">Exposition : Staatliche Museen zu Berlin, Antikensammlung, SK. 391 [https://recherche.smb.museum/detail/698814/doppelherme-des-sokrates-und-seneca-mit-namensbeischriften-der-dargestellten <sup>🔍</sup>].]] <div style="text-align: justify; margin: 0 1em; text-indent: 15px">Homme politique romain, philosophe stoïcien et dramaturge, il devient tour à tour conseiller à la cour impériale sous '''Caligula''' puis '''Claude''', est exilé en 41 en ''Corse'', où il écrit ses premiers traités philosophiques avant d’être rappelé comme tuteur du jeune '''Néron''' en 49, et enfin, lorsque ce dernier accède au pouvoir, en devient le conseiller et l’un des personnages les plus influents de l’Empire.</div> {{Boîte déroulante début|titre=NdA Sénèque|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Sénèque_back|<span id="Sénèque"><sup>I</sup></span>]] [[w:Nom_romain|Tria Nomina]] en latin {{Info|Lucius|praenomen, nom individuel du citoyen romain}} {{Info|Annaeus|nomen, nom de famille}} {{Info|Seneca|cognomen, surnom héréditaire, servant à distinguer les diverses branches d’une même gens}}'''<br/><br/></div> {{Boîte déroulante fin}} === [[w:Sénèque#Physique|Questions naturelles]] === <p style="text-align: right;">[[s:Questions_naturelles|📚]] <div style="text-align: justify; margin: 0 1em; text-indent: 15px">Ouvrage de philosophie naturelle écrit vers 65. Il ne s’agit pas d’une [[w:Encyclopédie|encyclopédie]] [[#encyclopédie|<span id="encyclopédie_back"><sup>'''I'''</sup></span>]] systématique comme l’[[w:Histoire_naturelle_(Pline_l'Ancien)|''Histoire naturelle'']] [[#Histoire_naturelle|<sup>⤵️</sup>]] de [[w:Pline_l'Ancien|'''Pline l’Ancien''']] [[#Pline_l’Ancien_I|<sup>⤵️</sup>]], bien que ces 2 œuvres représentent les rares ouvrages romains consacrés à l’étude du monde naturel. L’investigation de '''Sénèque''' se déroule principalement à travers la prise en compte des points de vue d’autres penseurs, ''grecs'' et ''romains'', bien qu’elle ne soit pas dénuée de pensées originales, dont éthiques conforment à la pensée ''stoïcienne''.</div> {{Boîte déroulante début|titre=NdA Questions naturelles|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#encyclopédie_back|<span id="encyclopédie"><sup>I</sup></span>]] Du nom commun [[w:Latin#Latin_humaniste|latin Renaissance]] encyclopaedīa [[wikt:en:encyclopaedia#Latin|(en)]]; de l’expression grec ancien ἐγκύκλῐος παιδείᾱ / enkúklios paideíā [https://dumas.ccsd.cnrs.fr/dumas-03927443/file/DONNADILLE-MR2-Pline-VERS-FINALE.pdf {{Info|<sup>🔍</sup>|Lisa Donnadille. Merveilles animalières dans les livres VIII à XI de l’Histoire naturelle de Pline l’Ancien. Littératures. 2020. ffdumas-03927443, p.21}}], « cercle de l’éducation ou des sciences, l’ensemble des sciences qui constituent une éducation complète »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ de l’adjectif ἐγκύκλιος / enkúklios, littéralement « qui est rond ou tourne en rond, circulaire », ou au sens figuré « qui revient en cercle sur soi-même, périodique », « qui embrasse un cercle entier »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ du nom commun παιδεία / paideía, « l’éducation »;'''<br /><p style="margin: 0 2em; text-align: center;">« ''Si à première vue la signification de cette expression semble être sans ambiguïté, sa portée réelle et la compréhension qu’en avaient les auteurs grecs puis latins font l’objet de débats parmi les spécialistes. En effet, deux interprétations sont possibles lorsqu’un auteur de l’Antiquité a recours à cette expression dans l’un de ses textes. Dans le premier cas, cela équivaudrait à parler d’une éducation ordinaire, commune à tous ; et dans le second cas, cela ferait référence à la quantité de connaissances et de sciences qu’il faudrait maîtriser au préalable avant de commencer l’étude d’un sujet précis, qui serait dans ce cas placé en haut d’une hiérarchie dans les savoirs.'' »<br /><p style="margin: 0 2em; text-align: right;">''' Lisa Donnadille. [https://dumas.ccsd.cnrs.fr/dumas-03927443/file/DONNADILLE-MR2-Pline-VERS-FINALE.pdf Merveilles animalières dans les livres VIII à XI de l’Histoire naturelle de Pline l’Ancien. Littératures. 2020. ffdumas-03927443], p.21'''<br/><br/></div> {{Boîte déroulante fin}} ==== Livre III — De l’eau ==== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">En prologue, Sénèque explique pourquoi il est plus important de s’intéresser à l’observation du monde, à sa connaissance et à sa compréhension plutôt qu’à sa conquête. Puis, il développe diverses théories sur la formation des rivières, les eaux souterraines et les propriétés de l’eau. Dans une critique morale aux chapitres XVII à XIX, il fustige la mauvaise pratique consistant à amener à table des poissons, notamment des rougets, vivants et à se délecter de leurs couleurs changeantes à l’agonie avant de les préparer devant les convives. En épilogue, il énonce son [[w:Eschatologie|''eschatologie'']], sa vision de la fin du monde où les êtres vivants seront anéantis par des raz-de-marée, marquant la fin d’un cycle du vivant et le début d’un autre.</div> ===== <div style="text-align: center;">Chapitre XIII.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage de la doctrine de '''Thalès''' faisant de l’eau l’élément à l’origine de la vie et critique d’une autre de la terre flottant dessus.</div> :'''Texte latin''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''13.''' Adiciam, ut '''Thales''' ait, «ualentissimum elementum est». Hoc fuisse primum putat, ex hoc surrexisse omnia. Sed nos quoque aut in eadem sententia, aut in uicinia eius sumus. Dicimus enim ignem esse qui occupet mundum et in se cuncta conuertat; hunc euanidum languentemque considere et nihil relinqui aliud in rerum natura igne restincto quam umoren; in hoc futuri mundi spem latere. Ita ignis exitus mundi est, umor primordium. Miraris ex hoc posse amnes semper exire qui pro omnibus fuit et ex quo sunt omnia? Hic umor in diductione rerum ad quartas redactus est, sic positus ut sufficere fluminibus edendis, ut riuis, ut fontibus posset.<br /><p style="text-indent: 15px;">'''14.''' Quae sequitur '''Thaletis''' inepta sententia est. Ait enim terrarum orbem aqua sustineri et uehi more nauigii mobilitateque eius fluctuare tunc cum dicitur tremere; non est ergo mirum si abundat umor ad flumina profundenda, cum in umore sit totus. Hanc ueterem et rudem sententiam explode. Nec est quod credas in hunc orbem aquam subire per rimas et facere sentinam.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/seneca.-cuestiones-naturales.-naturales-quaestiones.-vol.-i-1979/page/n1/mode/2up <u>L. Annaei Senecae, Natvrales Qvaestiones</u>], [https://archive.org/details/seneca.-cuestiones-naturales.-naturales-quaestiones.-vol.-i-1979/page/n261/mode/2up ''Liber Tertivs.''], [https://archive.org/details/seneca.-cuestiones-naturales.-naturales-quaestiones.-vol.-i-1979/page/n293/mode/2up ''chap. 13.-14.''], texte établi par Carmen Codoñer Merino [[w:es:Carmen_Codoñer_Merino|(es)]], Consejo Superior de Investigaciones Científicas, Madrid, 1979</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: justify; margin: 0 2em;">'''XIII.''' Aqua, ait '''Thales''', valentissimum elementum est : hoc fuisse primum putat, et hoc surrexisse omnia. Sed et nos quoque aut in eadem sententia, aut in ultima sumus. Dicimus enim ignem esse, qui occupet mundum, et in se cuncta convertat ; hunc evanidum considere, et nihil relinqui aliud in rerum natura, igne restincto, quam humorem : in hoc futuri mundi spem latere. Ita ignis exitus mundi est, humor primordium. Miraris amnes ex hoc posse exire semper, qui pro omnibus fuit, et ex quo sunt omnia? Hic humor in diductione rerum ad quartas redactus est, sic positus, ut fluminibus edendis sufficere, ut rivis, ut fontibus posset. Quæ sequitur, '''Thaletis''' inepta sententia est : ait enim , terrarum orbem aqua sustineri, et vehi more navigii, mobilitateque ejus fluctuare, tum quum dicitur tremere. Non est ergo mirum, si abundat humor ad flumina fundenda, quum mundus in humore sit totus. Hanc veterem et rudem sententiam explode : nec est quod credas, in hunc orbem aquam subire per rimas et facere sentiuam.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PP9#v=onepage&q&f=true <u>Œuvres Complètes de Sénèque, Tome Quatrième</u>], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA327#v=onepage&q&f=true ''Questions Naturelles, De Sénèque à Lucilius - Livre Troisième.''], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA342#v=onepage&q&f=true ''chap. XIII.''], traduction française de la collection Panckoucke, nouvelle édition très soigneusement revue par M. Charpentier et M. Félix Lemaistre, 1860</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''XIII.''' L’eau, dit '''Thalès''', est le plus puissant des éléments, le premier en date, celui par qui tout a pris vie. Nous pensons comme '''Thalès''', au moins sur le dernier point. En effet, nous prétendons que le feu doit s’emparer du monde entier et convertir tout en sa propre substance, puis s’évaporer, s’affaisser, s’éteindre et ne rien laisser autre chose dans la nature que l’eau ; qu’enfin l’eau recèle l’espoir du monde futur. Ainsi périra par le feu cette création dont l’eau fut le principe. Es-tu surpris que des fleuves sortent incessamment d’un élément qui a tenu lieu de tout, et duquel tout est sorti ? Quand les éléments furent séparés les uns des autres, l’eau fut réduite au quart de l’univers, et placée de manière à suffire à l’écoulement des fleuves, des ruisseaux, des fontaines. Mais voici une idée absurde de ce même '''Thalès'''. Il dit que la terre est soutenue par l’eau sur laquelle elle vogue comme un navire ; qu’à la mobilité d’un tel support sont dues les fluctuations qu’on appelle tremblements de terre. Ce ne sera donc pas merveille qu’il y ait assez d’eau pour entretenir les fleuves, si tout le globe est dans l’eau. Ce système grossier et suranné n’est que risible ; tu ne saurais admettre que l’eau pénètre notre globe par ses interstices, et que la cale est entr’ouverte.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[[s:Questions_naturelles_(trad._Baillard)|<u>Sénèque le Jeune</u>]], [[s:Questions_naturelles_(trad._Baillard)/Livre_3|''Livre III. chap. 13.'']], traduction par [[s:Auteur:Joseph_Baillard|Joseph Baillard]], Hachette, 1914<br />(également disponible [https://remacle.org/bloodwolf/philosophes/seneque/questionsnaturelles3.htm ici])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: justify; margin: 0 2em;">'''XIII.''' L’eau, dit '''Thalès''', est le plus puissant des éléments : elle existait avant tout, elle est le principe de tout. Nous pensons comme '''Thalès''', au moins sur le dernier point. En effet, nous croyons que le feu, s’emparant du monde entier, convertira tout en sa propre substance : mais il finira par cesser ses ravages, et quand il sera éteint, dans toute la nature il ne restera que l’eau, et cette eau renfermera le germe et l’espérance d’un monde futur. Ainsi par le feu s’accomplira la destruction de l’univers, et par l’eau sa réorganisation. Êtes-vous surpris, maintenant, qu’après avoir tenu lieu de tous les éléments, et les avoir produits tous, l’eau suffise à l’entretien perpétuel des fleuves ? Quand les éléments furent séparés les uns des autres, l’eau fut réduite au quart de l’univers, et dans une proportion convenable pour suffire à l’alimentation des fontaines, des ruisseaux et des rivières. Mais voici une idée absurde du même '''Thalès''' : il dit que la terre est soutenue par l’eau, et qu’elle flotte sur elle comme un navire ; que les tremblements de terre sont causés par les oscillations et les mouvements du fluide qui la soutient. Il n’est donc pas étonnant qu’il y ait assez d’eau pour alimenter les fleuves, puisque tout le globe est dans l’eau. Mais rejetons cette vieille et informe hypothèse, qui assimile les sources aux flots que la cale entr’ouverte laisse pénétrer dans le vaisseau.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PP9#v=onepage&q&f=true <u>Œuvres Complètes de Sénèque, Tome Quatrième</u>], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA327#v=onepage&q&f=true ''Questions Naturelles, De Sénèque à Lucilius - Livre Troisième.''], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA342#v=onepage&q&f=true ''chap. XIII.''], traduction française de la collection Panckoucke, nouvelle édition très soigneusement revue par M. Charpentier et M. Félix Lemaistre, 1860</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: justify; margin: 0 2em;">'''Chap. III.'''<br />''Opiniõ de Thales touchant l’eau.''<br /><p style="text-align: justify; text-indent: 15px;">L’eau , comme dit '''Thales''' , e[[w:S_long|{{Info|ſ|forme ancienne longue de la lettre s minuscule}}]]<nowiki>t</nowiki> le plus fort des Elemens. Il croit me{{Info|ſ|forme ancienne longue de la lettre s minuscule}}me qu’elle e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t le premier , & que toutes cho{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es en ont pris nai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ance. Pour moy ie {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uis de cette opinion , ou du moins de la derniere partie de cette opinion. Car nous [[#nous_stoiciens_NdT_dR|<span id="nous_stoiciens_NdT_dR_back"><sup>1</sup></span>]] di{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ons que c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t le feu qui enueloppera tout le monde , & qui conuertira en {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oy toutes cho{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es; qu’il deuiendra {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ans force quand il n’aura plus de nourriture , qu’apres que le feu {{Info|ſ|forme ancienne longue de la lettre s minuscule}}era e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}teint il ne demeurera rien de re{{Info|ſ|forme ancienne longue de la lettre s minuscule}}te à la nature que l’eau {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eulement , & que c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t en elle {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eule que con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i{{Info|ſ|forme ancienne longue de la lettre s minuscule}}te l’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}perance d’vn monde futur. Ain{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i le feu e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t la fin du monde , & l’eau en e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t le commencement. Vous e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tonnez-vous donc que les fleuues pui{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ent tou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iours {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ortir d’vn Element , qui e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t fait pour toutes cho{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es & dont toutes cho{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e font ? Lors que la nature fit le departement des Elemens , l’eau fut placée de telle {{Info|ſ|forme ancienne longue de la lettre s minuscule}}orte , qu’elle peut {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uffire pour les fleuues , pour les rui{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}eaux , pour les fontaines. Mais ce que '''Thales''' dit en {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uitte e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t ridicule , car il dit que le Globe de la terre e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tenu par les eaux ; qu’elles le portent comme vn vai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}eau , & qu’elles l’agitent de la me{{Info|ſ|forme ancienne longue de la lettre s minuscule}}me {{Info|ſ|forme ancienne longue de la lettre s minuscule}}orte , lors que nous croyons qu’il tremble. Il ne faut donc pas s’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tonner , s’il ya tou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iours a{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ez d’eau pour former de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i grands fleuues , puis que tout le monde nage fur l’eau. Mais me{{Info|ſ|forme ancienne longue de la lettre s minuscule}}pri{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ez cette vieille , & cette gro{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}iere opinion , & ne croyez pas que l’eau vienne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur la terre , comme par des fentes & par des creua{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}es , & qu’elle y {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oit {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eulement comme dans le fond d’vn vai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}eau.</div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#nous_stoiciens_NdT_dR_back|<span id="nous_stoiciens_NdT_dR"><sup>1.</sup></span>]] Les Stoïciens.''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=ktOcOg9lr54C&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles%20iii&hl=fr&pg=PA1#v=onepage&q&f=true <u>Seneque Des Qvestions Natvrelles</u>], [https://books.google.fr/books?id=ktOcOg9lr54C&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles%20iii&hl=fr&pg=PA202#v=onepage&q&f=true ''Livre Troisiesme. Des eaux.''], [https://books.google.fr/books?id=ktOcOg9lr54C&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles%20iii&hl=fr&pg=PA234#v=onepage&q&f=true ''chap. XIII.''], traduction par [[w:Pierre_Du_Ryer|Pierre Du Ryer]], A Lyon, Chez Christofle Fovrmy, 1663</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div> </div> <div style="text-align: center; margin: 0 auto;">― ● ―</div> ==== Livre IV — Du Nil ==== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">En prologue, '''Sénèque''' fait l’éloge de [[w:Lucilius_le_Jeune|'''Lucilius''']] [[#Lucilius|<span id="Lucilius_back"><sup>'''I'''</sup></span>]] avant de lui expliquer les dangers de la flatterie. Puis, il décrit la crue du [[w:Nil|''Nil'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Nil_back|<sup>🔄</sup>]], expose les théories tentant de l’expliquer et les réfute. En épilogue, il fait le procès du luxe, et plus particulièrement celui d’acheter de la neige, et donc de marchandiser l’eau, regrettant qu’on ne puisse faire de même avec l’air et le soleil.</div> {{Boîte déroulante début|titre=NdA Lucilius|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Lucilius_back|<span id="Lucilius"><sup>I</sup></span>]] Du nom propre latin Lucilius [[wikt:en:Lucilius#Latin|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;">Gouverneur ''romain'' de Sicile durant le règne de [[w:Néron|Néron]], ainsi qu’un ami et un correspondant de Sénèque.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:Ier_siècle_av._J.-C.|I<sup>er</sup> siècle {{Info|EC|de l’Ère Commune}}]], [[w:Campanie#Histoire|''Campanie'']], [[w:Quatorze_régions_de_la_Rome_augustéenne#Regio_I_:_Porte_Capène|''Regio I'']])'''<br/><br/></div> {{Boîte déroulante fin}} ===== <div style="text-align: center;">Chapitre II.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Réfutation par '''Sénèque''' d’une théorie explicite de '''Thalès''' sur la crue du ''Nil'' (théorie identique mais supposément implicite rapportée par [[w:Hérodote|'''Hérodote''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Chapitre_XX|<sup>🔄</sup>]]).</div> :'''Texte latin''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''2.''' [...] Si '''Thaleti''' credis, etesiae descendenti ''Nilo'' resistunt et cursum eius acto contra ostia mari sustinent. Ita reuerberatus in se recurrit, nec crescit, sed exitu prohibitus resistit et quacumque mox potuit ui congestus erumpit. '''Euthymenes''' ''Massiliensis'' testimonium dicit: «Nauigaui, inquit, ''Atlanticum'' mare. Inde ''Nilus'' fluit, maior, quamdiu etesiae tempus obseruant; tunc enim eicitur mare instantibus uentis. Cum resederunt, et pelagus conquiescit minorque descendenti inde uis ''Nilo'' est. Ceterum dulcis mari sapor est et similes ''Niloticis'' beluae». Quare ergo, si ''Nilum'' etesiae prouocant, et ante illos incipit incrementum eius et post eos durat? Praeterea non fit maior quo illi flauere uehementius, nec remittitur incitaturque, prout illis impetus fuit; quod fieret, si illorum uiribus cresceret. Quid quod etesiae litus ''Aegyptium'' uerberant et contra illos ''Nilus'' descendit, inde uenturus unde illi, si origo ab illis esset? Praeterea ex mari purus et caeruleus efflueret, non, ut nunc, turbidus ueniret. Adde quod testimonium eius testium turba coarguitur. Tunc erat mendacio locus; cum ignota essent externa, licebat illis fabulas mittere. Nunc uero tota exteri maris ora mercatorum nauibus stringitur, quorum nemo narrat initium ''Nili'' aut mare saporis alterius: quae natura credi uetat, quia dulcissimum quodque et leuissimum sol trahit. Praeterea quare hieme non crescit? Et tunc potest uentis concitari mare, aliquanto quidem majoribus; nam etesiae temperati sunt. Quod si e mari ferretur ''Atlantico'', semel oppleret ''Aegyptum''. At nunc per gradus crescit.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/seneca.-cuestiones-naturales.-naturales-quaestiones.-vol.-ii-1979/page/n1/mode/2up <u>L. Annaei Senecae, Natvrales Qvaestiones</u>], [https://archive.org/details/seneca.-cuestiones-naturales.-naturales-quaestiones.-vol.-ii-1979/page/n7/mode/2up ''Liber Qvartvs A.''], [https://archive.org/details/seneca.-cuestiones-naturales.-naturales-quaestiones.-vol.-ii-1979/page/n41/mode/2up ''chap. 2.''], texte établi par Carmen Codoñer Merino [[w:es:Carmen_Codoñer_Merino|(es)]], Consejo Superior de Investigaciones Científicas, Madrid, 1979</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: justify; margin: 0 2em;">'''II.''' [...] Si '''Thaleti''' credis, Etesiæ descendenti ''Nilo'' resistunt, et cursus ejus acto contra ostia mari sustinent : ita reverberatus in se recurrit : nec crescit, sed exitu prohibitus resistit, et quacumque mox potuit, inconcessus erumpit.<br /><p style="text-align: justify; text-indent: 15px;">'''Euthymenes''' ''Massiliensis'' testimonium dicit : « Navigavi, inquit, ''Atlanticum'' mare. Inde ''Nilus'' fluit major, quamdiu Etesiæ tempus observant : tunc enim ejicitur mare instantibus ventis. Quum resederint, et pelagus conquiescit, minorque descendenti inde vis ''Nilo'' est. Ceterum dulcis maris sapor est, et similes ''Niloticis'' belluæ. » Quare ergo, si ''Nilum'' Etesiæ provocant, et ante illos incipit incrementum ejus, et post eos durat ? Præterea non fit major, quo illi flavere vehementius. Nec remittitur, incitaturque, prout illis impetus fuit : quod fieret, si illorum viribus cresceret. Quid, quod Etesiæ littus ''ægyptium'' verberant, et contra illos ''Nilus'' descendit, inde venturus, unde illi, si origo ab illis esset ? Præterea ex mari purus et cæruleus efflueret, non ut nunc turbidus venit. Adde, quod testimonium ejus testium turba coarguitur. Tunc erat mendacio locus, quum ignota essent externa. Licebat illis fabulas mittere. Nunc vero tota exteri maris ora mercatorum navibus stringitur : quorum nemo narrat nunc cæruleum ''Nilum'', aut mare saporis alterius ; quod et natura credi vetat, quia dulcissimum quodque et levissimum sol trahit. Præterea quare hieme non crescit ? et tunc potest ventis concitari mare, aliquando quidem majoribus ; nam Etesiæ temperati sunt. Quod si e mari ferretur ''Atlantico'', semel oppleret ''Ægyptum''. At nunc per gradus crescit.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PP9#v=onepage&q&f=true <u>Œuvres Complètes de Sénèque, Tome Quatrième</u>], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA371#v=onepage&q&f=true ''Questions Naturelles, De Sénèque à Lucilius - Livre Quatrième.''], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA385#v=onepage&q&f=true ''chap. II.''], traduction française de la collection Panckoucke, nouvelle édition très soigneusement revue par M. Charpentier et M. Félix Lemaistre, 1860</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''II.''' [...] À en croire '''Thalès''', les vents étésiens repoussent le ''Nil'' à sa descente dans la mer, et suspendent son cours en poussant la mer contre ses embouchures. Ainsi refoulé, il revient sur lui-même, sans pour cela grossir ; mais l’issue lui étant barrée, il s’arrête, et bientôt, partout où il le peut, force le passage qui lui est refusé. [[w:Euthymènes|'''Euthymène''']] [[#Euthymènes|<span id="Euthymènes_back"><sup>'''I'''</sup></span>]], de ''Marseille'', en parle comme témoin : « J’ai navigué, dit-il, sur la mer ''Atlantique''. Elle cause le débordement du ''Nil'', tant que les vents étésiens se soutiennent ; car c’est leur souffle qui alors pousse cette mer hors de son lit. Dès qu’ils tombent, la mer aussi redevient calme, et le ''Nil'' à sa descente déploie moins de puissance. Du reste, l’eau de cette mer est douce, et nourrit des animaux semblables à ceux du ''Nil''. » Mais pourquoi, si les vents étésiens font gonfler le ''Nil'', la crue commence-t-elle avant la saison de ces vents, et dure-t-elle encore après ? D’ailleurs le fleuve ne grossit pas à mesure qu’ils soufflent plus violemment. Son plus ou moins de fougue n’est point réglé sur celle des vents étésiens, ce qui aurait lieu, si leur action le faisait hausser. Et puis ils battent la côte ''égyptienne'', le ''Nil'' descend à leur encontre : il faudrait qu’il vînt du même point qu’eux, si son accroissement était leur ouvrage. De plus, il sortirait pur et azuré de la mer, et non pas trouble comme il est. Ajoute que le témoignage d’'''Euthymène''' est réfuté par une foule d’autres. Le mensonge avait libre carrière, quand les plages étrangères étaient inconnues ; on pouvait de là nous envoyer des fables, À présent, la mer extérieure est côtoyée sur tous ses bords par des trafiquants dont pas un ne raconte qu’aujourd’hui le ''Nil'' soit azuré ou que l’eau de la mer soit douce. La nature elle-même repousse cette idée ; car les parties les plus douces et les plus légères sont pompées par le soleil. Et encore pourquoi le ''Nil'' ne croît-il pas en hiver ? Alors aussi la mer peut être agitée par des vents quelque peu plus forts que les étésiens, qui sont modérés. Si le mouvement venait de l’Atlantique, il couvrirait tout d’un coup l’Égypte : or l’inondation est graduelle.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[[s:Questions_naturelles_(trad._Baillard)|<u>Sénèque le Jeune</u>]], [[s:Questions_naturelles_(trad._Baillard)/Livre_4|''Livre IV.'']] ''chap. 2.'', traduction par [[s:Auteur:Joseph_Baillard|Joseph Baillard]], Hachette, 1914<br />(également disponible [https://remacle.org/bloodwolf/philosophes/seneque/questionsnaturelles4.htm ici])</div> {{Boîte déroulante début|titre=NdA trad. par Joseph Baillard de 1914|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Euthymènes_back|<span id="Euthymènes"><sup>I</sup></span>]] Du nom propre grec ancien Εὐθυμένης / Euthuménēs [[wikt:en:Εὐθυμένης#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;"> ➥ de l’adjectif εὐθύς / euthús, « 1. Droit, direct : (au sens moral) direct, ouvert, franc. »;<br /><p style="margin: 0 2em; text-indent: 15px;"> ➥ + du nom commun μενος / ménos, « 1. Esprit. 2. Désir, ardeur, souhait, but. 3. Colère. 4. Courage, esprit, vigueur. 5. Pouvoir, force. 6. Violence. »;<br /><p style="margin: 0 2em; text-indent: 15px;"> ➥ + du suffixe nominal‎ propre -ης / -ēs [[wikt:en:-ης#Suffix_2|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;"> Navigateur et explorateur de la mer Extérieure le long des côtes africaines (actuelle Atlantique sud).<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:VIeme_siècle_av._J.-C.|VI<sup>ème</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]], [[w:Marseille_antique#Massalia,_une_cité_grecque|''Massalia'']], actuelle Marseille)'''<br/><br/></div> {{Boîte déroulante fin}} <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: justify; margin: 0 2em;">'''II.''' [...] Selon '''Thalès''', le phénomène a pour cause les vents Étésiens, qui s’opposent au cours du ''Nil'' et font rebrousser ses eaux en sens inverse du mouvement qui le porte vers la mer. Refoulés sur eux-mêmes, les flots refluent sans pour cela grossir ; mais l’issue leur étant fermée, ils s’arrêtent, et bientôt ils s’ouvrent partout où ils peuvent le passage qui leur est refusé.<br /><p style="text-align: justify; text-indent: 15px;">'''Euthymène''' de ''Marseille'' en parle comme témoin : « J’ai navigué, dit-il, sur la mer ''Atlantique''. Le ''Nil'' roule des eaux plus abondantes, tant que durent les vents Étésiens ; car alors ils refoulent la mer sur le fleuve. Dès qu’ils se sont abattus et que la mer est devenue calme, le ''Nil'', qui peut redescendre vers celle-ci, diminue. Au reste, les eaux de cette mer sont douces et contiennent des animaux semblables à ceux du ''Nil''. » Dans cette hypothèse, qui donne les vents Étésiens pour cause des crues du ''Nil'', qu’on me dise pourquoi ces crues précèdent les vents, persistent quand les vents ne sont plus, enfin n’augmentent plus d’intensité et de violence, et ne diminuent pas selon la violence et l’impétuosité du vent même ; c’est pourtant ce qui devrait arriver, si les vents déterminaient la hausse des eaux. De plus, les vents Étésiens battent directement la côte ''égyptienne'' : pourquoi donc le ''Nil'' descend-il contre le souffle de ces vents, tandis qu’il devrait couler dans la même direction, s’il leur devait ses débordements ? Enfin, pourquoi, au lieu d’être diaphanes et azurés, ces flots, qu’on fait venir de la mer, sont-ils chargés de limon ? Ajoutez qu’une foule de témoignages réfutent '''Euthymène'''. On pouvait mentir, quand les plages étrangères étaient inconnues : c’était alors le temps des fables ; mais aujourd’hui mille vaisseaux marchands côtoient la mer extérieure ; personne ne dit que le ''Nil'' ait des flots d’azur ; personne ne donne à la mer une saveur douce, que la nature refuse à ses eaux : car le soleil en pompe sans cesse la partie la plus douce et la plus légère ; ensuite pourquoi le ''Nil'' ne croîtrait-il point pendant l’hiver ? la mer alors peut être battue par les vents, par des vents plus violents que les Étésiens, qui sont modérés. Enfin, si le mouvement venait de l’Atlantique, l’Égypte entière serait inondée tout d’un coup : or, l’inondation est graduelle.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PP9#v=onepage&q&f=true <u>Œuvres Complètes de Sénèque, Tome Quatrième</u>], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA371#v=onepage&q&f=true ''Questions Naturelles, De Sénèque à Lucilius - Livre Quatrième.''], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA385#v=onepage&q&f=true ''chap. II.''], traduction française de la collection Panckoucke, nouvelle édition très soigneusement revue par M. Charpentier et M. Félix Lemaistre, 1860</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: justify; margin: 0 2em;">'''Chap. II.'''<br />''En quelle fai[[w:S_long|{{Info|ſ|forme ancienne longue de la lettre s minuscule}}]]<nowiki>ó</nowiki> {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e fait l’accroi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ement du Nil.''<br /><p style="text-align: justify; text-indent: 15px;">[...] Si vous en croyez '''Thales''' , les vents Ethe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iens re{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tent au ''Nil'' en de{{Info|ſ|forme ancienne longue de la lettre s minuscule}}cendant dans la mer; & arre{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tent {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on cours, en pou{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ant la mer contre {{Info|ſ|forme ancienne longue de la lettre s minuscule}}es {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ept emboucheures. Si bien qu’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es {{Info|ſ|forme ancienne longue de la lettre s minuscule}}tant repou{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}é de la {{Info|ſ|forme ancienne longue de la lettre s minuscule}}orte il retourne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oy-me{{Info|ſ|forme ancienne longue de la lettre s minuscule}}me , & ne croi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t pas comme l’on pen{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e , mais par ce qu’il trouue vn ob{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tacle qui l’empe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}che de pa{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}er outre , il e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t contraint de s’arre{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ter , & ne pouuant plus pour{{Info|ſ|forme ancienne longue de la lettre s minuscule}}uiure {{Info|ſ|forme ancienne longue de la lettre s minuscule}}a cour{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e , il {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e re{{Info|ſ|forme ancienne longue de la lettre s minuscule}}pand par où il peut {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e répandre. '''Euthimenes''' de ''Mar{{Info|ſ|forme ancienne longue de la lettre s minuscule}}eille'' en rend ce te{{Info|ſ|forme ancienne longue de la lettre s minuscule}}moignage. I’ay nauigé, dit il, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur la mer ''Atlantique'' , & c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t par elle que le ''Nil'' deuient plus grand, lors que les vents Ethe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iens {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oufflent ; car alors cette mer {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ort pour ain{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i dire d’elle-me{{Info|ſ|forme ancienne longue de la lettre s minuscule}}me par la force & par la violence de ces vents. Mais lors qu’ils ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oufflent plus la mer demeure tranquille, & le Nil ne trouue plus rien qui l’empe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}che de de{{Info|ſ|forme ancienne longue de la lettre s minuscule}}cendre , Au re{{Info|ſ|forme ancienne longue de la lettre s minuscule}}te l’eau de la mer e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t douce en ce temps-là , & l’on y void des be{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tes {{Info|ſ|forme ancienne longue de la lettre s minuscule}}emblables à celles du Nil. Mais {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i les Ethe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iens {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont enfler le Nil, pourquoy {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on débordement commence il auant qu’ils {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oufflent & pourquoy dure - il encore lors qu’ils ont ce{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}é de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ouffler. Dauantage ils ne s’enfle pas plus que de cou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tume , quand ces vents {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oufflent auecque plus de violence qu’ils ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont ordinairement. Enfim il ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e hau{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}e & ne s’abai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}e pas {{Info|ſ|forme ancienne longue de la lettre s minuscule}}elon que leur impetuo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ité e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t plus ou moins grande , ce qui arriveroit {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ans doute s’il s’enfloit par la force de ces véts. Mais comme les Ete{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iens battent directement les bords de l’Egypte, & que le Nil de{{Info|ſ|forme ancienne longue de la lettre s minuscule}}cend contre eux ; il faudroit s’ils e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}toient cau{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on accroi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ement , qu’il commença{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t par l’endroit d’où ils viennent. Outre cela il {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ortiroit tout pur de la mer, & de la couleur de la mer, & ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eroit pas trouble & limonneux , comme il e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t. Et apres tout le te{{Info|ſ|forme ancienne longue de la lettre s minuscule}}moignage d’'''Euthimene''' , e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t condamné par le plus grand nombre. Il e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}toit permis de mentir quand on n’auoit point de connoi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ance des pays e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}trangers ; & alors on pouuoit facilement nous en enuoyer des fables. Mais aujourd’huy tous les riuages des mers les plus e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}loignées {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont remplis de vai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}eaux de marchands, & pas vn ne nous apporte que le ''Nil'' {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oit de la couleur de la mer, ou que la mer ait vn autre gou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t. Quand nous aurions des rai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ons pour nous la per{{Info|ſ|forme ancienne longue de la lettre s minuscule}}uader , la nature nous empe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}cheroit de le croire par ce que le Soleil en attire ce qu’il y a de plus leger & de plus doux. Dauantage pourquoy ne croi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t-il pas en Hyuer , puis que la met en ce temps là peut e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tre agitée par des vents plus violents, que les Ethe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iens qui {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont tou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iours moderez. Que {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i le ''Nil'' venoit de la mer ''Atlantique'' , il couuriroit l’Egypte tout d’vn coup, & neantmoins il ne la couure que peu à peu.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=gEzVYlz3c3cC&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles%20iii%20volume%202&hl=fr&pg=PA1#v=onepage&q&f=true <u>Seneque Des Qvestions Natvrelles</u>], [https://books.google.fr/books?id=gEzVYlz3c3cC&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles%20iii%20volume%202&hl=fr&pg=PA3#v=onepage&q&f=true ''Livre Qvatriesme. De la Nege, de la Greſle, & de la Pluye.''], [https://books.google.fr/books?id=gEzVYlz3c3cC&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles%20iii%20volume%202&hl=fr&pg=PA37#v=onepage&q&f=true ''chap. II.''], traduction par [[w:Pierre_Du_Ryer|Pierre Du Ryer]], A Lyon, Chez Christofle Fovrmy, 1663</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div> </div> <div style="text-align: center; margin: 0 auto;">― ● ―</div> ==== Livre VI — Des tremblements de terre ==== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">En prologue, '''Sénèque''' énonce le plan du livre, des causes des tremblements de terre et des peurs qu’ils provoquent, en s’appuyant sur celui de ''Campanie'' qui a récemment causé d’importants dégâts à ''Pompéi'' et à ''Herculanum''. Des chapitres IV à XX, de nombreuses théories sismiques sont présentées, la plupart liées au nom d’un philosophe qui les prône. Le feu, l’eau et l’air sont cités comme causes, et plusieurs d’entre-elles les combinent. À partir du chapitre XXIV, '''Sénèque''' développe sa propre opinion : l’air pénétrant, qui remplit complètement les cavités souterraines sous une forte pression, en est la cause. En épilogue, il explique à '''Lucilius''' quel comportement adopté en de telles situations, à savoir être courageux en ne craignant pas la mort</div> ===== <div style="text-align: center;">Chapitre VI.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Réfutation d’une théorie de '''Thalès''' de la Terre flottant sur l’eau, et témoignage d’une de ses preuves portant sur les tremblements de terre.</div> :'''Texte latin''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''6.''' In aqua causam esse nec ab uno dictum est nec uno modo. '''Thales''' ''Milesius'' totam terram subiecto iudicat umore portari et innare, siue illud oceanum uocas, siue magnum mare, siue alterius naturae simplicem adhuc aquam et umidum elementum. Hac, inquit, unda sustinetur orbis uelut aliquod grande nauigium et graue his aquis quas premit. Superuacuum est reddere causas propter quas existimat grauissimam partem mundi non posse spiritu tam tenui fugacique gestari; non enim nunc de situ terrarum sed de motu agitur. Illud argumenti loco ponit aquas esse in causa quibus hic orbis agitetur, quod in omni maiore motu erumpunt fere noui fontes, sicut in nauigiis quoque euenit ut, si inclinata sunt et abierunt in latus, aquam sorbeant, quae in omni eorum onere quae uehit, si immodice depressa sunt, aut superfunditur aut certe dextra sinistraque solito magis surgit. Hanc opinionem falsam esse non est diu colligendum. Nam, si terra aqua sustineretur et ea aliquando concuteretur, semper moueretur, nec agitari illam miraremur sed manere; deinde tota concuteretur, non ex parte; numquam enim nauis dimidia iactatur. Nunc uero terrarum non uniuersarum sed ex parte motus est. Quomodo ergo fieri potest ut, quod totum uehitur, totum non agitetur, si eo quo uehitur agitatum est? — At quare aquae erumpunt? — Primum omnium saepe tremuit terra et nihil umoris noui fluxit. Deinde, si ex hac causa unda prorumperet, a lateribus terrae circumfunderetur, sicut in fluminibus ac mari uidemus incidere ut incrementum aquarum, quotiens nauigia desidunt, in lateribus maxime appareat. Ad ultimum non tam exigua fieret quam tu dicis eruptio nec uelut per rimam sentina subreperet, sed fieret ingens inundatio ut ex infinito liquore et ferente uniuersa.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/seneca.-cuestiones-naturales.-naturales-quaestiones.-vol.-ii-1979/page/n1/mode/2up <u>L. Annaei Senecae, Natvrales Qvaestiones</u>], [https://archive.org/details/seneca.-cuestiones-naturales.-naturales-quaestiones.-vol.-ii-1979/page/n135/mode/2up ''Liber Qvintvs - De terrae motv''], [https://archive.org/details/seneca.-cuestiones-naturales.-naturales-quaestiones.-vol.-ii-1979/page/n155/mode/2up ''chap. 6.''], texte établi par Carmen Codoñer Merino [[w:es:Carmen_Codoñer_Merino|(es)]], Consejo Superior de Investigaciones Científicas, Madrid, 1979</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: justify; margin: 0 2em;">'''VI.''' In aqua causam esse, nec ab uno dictum est, nec uno modo. '''Thales''' ''Milesius'' totam terram subjecto judicat humore portari et innatare : sive illud Oceanum vocas, sive magnum mare, sive alterius naturæ simplicem adhuc aquam et humidum elementum. Hac, inquit, unda sustinetur orbis, velut aliquod grande navigium et grave his aquis, quas premit. Supervacuum est reddere causas, propter quas existimat, gravissimam partem mundi non posse spiritu tam tenui fugacique gestari ; non enim nunc de situ terrarum, sed de motu agitur. Illud argumenti loco ponit, aquas esse in causa, quibus hic orbis agitatur, quod in omui majore motu erumpunt fere novi fontes : sicut in navigiis quoque evenit, ut, si inclinata sunt et abiere in latus, aquam sorbeant, quæ in omni onere eorum quæ vehit, si immodice depressa sunt, aut superfunditur, aut certe dextra sinistraque solito magis surgit. Hanc opinionem falsam esse, non est diu colligendum ; nam, si terram aqua sustineret, et ea aliquando concuteretur : semper moveretur, nec agitari illam miraremur, sed manere. Tum tota concuteretur, non ex parte : nunquam enim navis dimidia jactatur. Nunc vero non terrarum universarum, sed ex parte motus est. Quomodo ergo fieri potest, ut quod totum vehitur, totum non agitetur, si eo quo vehitur, agitatum est ? At quare aquæ erumpunt ? Primum omnium sæpe tremuit terra, et nihil humoris novi fluxit. Deinde si ex hac causa unda prorumperet, a lateribus terræ circumfunderetur : sicut in fluminibus ac mari videmus accidere, ut incrementum aquarum, quoties navigia desidunt, in lateribus maxime appareat. Ad ultimum non tam exigua fieret quam dicit eruptio, nec velut per rimam sentina subreperet, sed fieret ingens inundatio, ut ex infinito liquore, et ferente universa.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PP9#v=onepage&q&f=true <u>Œuvres Complètes de Sénèque, Tome Quatrième</u>], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA420#v=onepage&q&f=true ''Questions Naturelles, De Sénèque à Lucilius - Livre Sixième.''], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA429#v=onepage&q&f=true ''chap. VI.''], traduction française de la collection Panckoucke, nouvelle édition très soigneusement revue par M. Charpentier et M. Félix Lemaistre, 1860</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''VI.''' Que l’eau soit cause des tremblements de terre, c’est ce qu’affirment divers auteurs et avec divers arguments. '''Thalès''' de ''Milet'' estime que le globe entier a pour support une masse d’eaux sur laquelle il flotte, et qu’on peut appeler Océan ou grande mer, ou élément jusqu’ici de nature simple, l’élément humide. Cette eau, dit-il, soutient la terre ; et l’immense navire pèse sur le liquide qu’il comprime. Il est superflu d’exposer les motifs qui font croire à '''Thalès''' que la partie de l’univers la plus pesante ne saurait porter sur une substance aussi ténue, aussi fugace que l’air : il ne s’agit pas maintenant de l’assiette du globe, mais de ses secousses. '''Thalès''' apporte en preuve de son système, que presque toujours les grandes secousses font jaillir des sources nouvelles, comme il arrive dans les navires qui, lorsqu’ils penchent et s’inclinent sur le flanc, sont envahis par l’eau ; toujours, s’il y a surcharge, l’eau vient couvrir le bâtiment, ou du moins s’élève à droite et à gauche plus que de coutume. La fausseté de cette opinion se démontre sans longs raisonnements. Si la terre était soutenue par l’eau, elle tremblerait quelquefois dans toute sa masse et toujours serait en mouvement ; ce ne serait pas son agitation qui étonnerait, mais son repos. Elle s’ébranlerait tout entière, non partiellement ; car ce n’est jamais la moitié seulement d’un navire qui est battue des flots. Or, les tremblements de notre terre ne sont pas universels, mais partiels. Comment serait-il possible qu’un corps porté tout entier par l’eau ne fût pas agité tout entier, quand ce fluide est agité ? « Mais d’où viennent les eaux qu’on a vues jaillir ? » D’abord, souvent la terre tremble, sans qu’il en sorte de nouvelles eaux. Ensuite, si telle était la cause de ces éruptions, elles n’auraient lieu qu’autour des flancs du globe ; ce que nous voyons arriver sur les fleuves et en mer : l’exhaussement de l’onde, à mesure que s’enfonce le navire, se remarque surtout aux flancs du bâtiment. Enfin l’éruption dont on parle ne serait pas si minime, et comme une voie d’eau qui s’infiltre par une fente légère ; l’inondation serait immense en raison de l’abîme infini sur lequel flotterait le monde.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[[s:Questions_naturelles_(trad._Baillard)|<u>Sénèque le Jeune</u>]], [[s:Questions_naturelles_(trad._Baillard)/Livre_6|''Livre VI.'']] ''chap. 6.'', traduction par [[s:Auteur:Joseph_Baillard|Joseph Baillard]], Hachette, 1914<br />(également disponible [https://remacle.org/bloodwolf/philosophes/seneque/questionsnaturelles6.htm ici])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: justify; margin: 0 2em;">'''VI.''' Plusieurs philosophes ont prétendu que l’eau est la cause de ces secousses : ce que chacun explique à sa manière. '''Thalès''' de ''Milet'' prétend que le globe entier a pour support une masse d’eau sur laquelle il flotte ; peu importe qu’on donne à cet amas le nom d’Océan, de grande mer ou d’eau élémentaire, eau simple. Cette eau, dit-il, soutient la terre comme un grand vaisseau pesant sur le liquide qu’il comprime. Il est inutile d’exposer les raisons qui font croire à '''Thalès''' que le corps le plus pesant de la nature ne peut être soutenu par un fluide aussi délié et aussi rare que l’air : car il s’agit ici des tremblements de terre et non de l’assiette du globe. La grande raison de '''Thales''' pour faire de l’eau la cause des secousses de la terre, c’est que, dans tout tremblement considérable, jaillissent des eaux nouvelles ainsi les vaisseaux se remplissent d’eau quand ils penchent d’un côté ; chargés à l’excès, ou ils sont submergés, ou ils s’enfoncent à droite et à gauche plus profondément dans la mer. Il ne faut pas longtemps discuter pour voir la fausseté de cette opinion. Si la terre était soutenue par les eaux, elle serait quelquefois fortement ébranlée, mais de plus elle serait toujours flottante, et il faudrait s’étonner non de son agitation , mais de son repos ; enfin, au lieu d’être ébranlée en partie, elle le serait tout entière : car jamais la moitié d’un vaisseau n’est battue des flots. Or, on sait que les secousses de la terre sont partielles et non universelles : comment se ferait-il donc que ce qui est entièrement porté par les eaux ne fût pas entièrement agité, tandis que les eaux mêmes le sont en totalité ? Mais, dit-on, qui fait jaillir les eaux ? D'abord, souvent la terre tremble sans qu’il se produise des eaux nouvelles ; ensuite, si telle était la cause de ces éruptions, les eaux se répandraient latéralement autour de la terre. Ainsi, par exemple, quand un vaisseau s’enfonce ou dans la mer ou dans les fleuves, c’est vers les bords surtout que l’accroissement devient sensible. Enfin les sources qui jaillissent ne seraient pas si peu considérables ; on ne pourrait pas les comparer à une voie d’eau qui pénètre par les fentes du fond de cale : ce serait une inondation immense comme l’abîme infini sur lequel flotterait le monde.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PP9#v=onepage&q&f=true <u>Œuvres Complètes de Sénèque, Tome Quatrième</u>], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA420#v=onepage&q&f=true ''Questions Naturelles, De Sénèque à Lucilius - Livre Sixième.''], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA429#v=onepage&q&f=true ''chap. VI.''], traduction française de la collection Panckoucke, nouvelle édition très soigneusement revue par M. Charpentier et M. Félix Lemaistre, 1860</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: justify; margin: 0 2em;">'''Chap. VI.'''<br />''Si l’eau e[[w:S_long|{{Info|ſ|forme ancienne longue de la lettre s minuscule}}]]<nowiki>t</nowiki> la cau{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e des tréblemés de terre.''<br /><p style="text-align: justify; text-indent: 15px;">Ce n'e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t pas vn homme {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eul qui a dit , que l’eau e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}toit cau{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e du tremblement de la terre ; & l’on ne l’a pas dit d’vne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eule façó. '''Thales''' ''Mile{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ien'' a crû que toute la terre e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}toit portée {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur l’eau , & qu’elle y nageoit, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oit que vous appelliez cette eau Ocean, ou que vous l’appelliez grade mer, ou vne eau d’vne autre nature , eau {{Info|ſ|forme ancienne longue de la lettre s minuscule}}imple , element humide. C’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur cette eau, dit-il, que le monde e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tenu, comme quelque vai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}eau d’vne grandeur deme{{Info|ſ|forme ancienne longue de la lettre s minuscule}}urée , qui charge les eaux qui le {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tiennent. Il {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eroit inutile de rapporter les rai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ons qui luy {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont croire que la plus pe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ante partie du móde ne peut e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tre {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tenuë par l’air qui e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ubtil, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i fluide & {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i delié ; & d’ailleurs, il ne s’agit pas icy de l’a{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}iete de la terre , mais du tremblement de la terre. Ain{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i pour preuue que les eaux {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont cau{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e que la terre tremble , il dit qu’il ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e fait pre{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que point de grands tremblemens de terre, qu’on n’en voye {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ortir en{{Info|ſ|forme ancienne longue de la lettre s minuscule}}uitte de nouuelles {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ources; que la terre re{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}emble en cela aux vai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}eaux qui ne peuuent pancher d’vn co{{Info|ſ|forme ancienne longue de la lettre s minuscule}}té, qu’ils ne pui{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ent de l’eau, qui {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e re{{Info|ſ|forme ancienne longue de la lettre s minuscule}}pand {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur toutes les cho{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es qu’ils portent , {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i elles {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont trop enfoncées; ou qui s’éleue de part & d’autre à la gauche , & à la droite. Il n’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t pas besoin d’vn long di{{Info|ſ|forme ancienne longue de la lettre s minuscule}}cours pour montrer la fau{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}eté de cette opinion ; car {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i l’eau {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tenoit la terre, quelquesfois elle trembleroit toute entiere, & {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eroit tou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iours en mouuement; & nous ne nous e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tonnerions point de la voir remuer, mais de la voir ferme & inébranlable. Elle trembleroit toute entiere , & non pas en partie , car vn vai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}eau n’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t iamais agité par vne moitié {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eulement ; & apres tout nous voyons que le tremblement ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e fait pas de toute la terre , mais {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eulement d’vne partie. Comment donc {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e peut-il faire que ce qui e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t porté tout entier ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oit pas entierement agité , {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i la cho{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e me{{Info|ſ|forme ancienne longue de la lettre s minuscule}}me qui porte e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}meuë & agitée ? Mais pourquoy {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ort-il de l’eau apres vn tremblement de terre ? Premierement la terre a {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ouuent tremblé {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ans qu’on en ayt veu {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ortir de nouuelles {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ources. D’ailleurs {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i l’eau {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ortoit par cette rai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}on elle {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e re{{Info|ſ|forme ancienne longue de la lettre s minuscule}}pandroit par les co{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tez de la terre , comme nous voyons dans les fleuues & dans la mer , où lors que le vai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}eau s’enfonce on remarque que l’eau s'éleue , principalement par les co{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tez. Enfin ces eaux ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ortiroient pas en {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i petite quantité, ny par vne fi petite ouuerture , mais il {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eroit vne grande inondation, comme procedant de cette abondance d’eaux qui {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tiennent tout l’vniuers.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=gEzVYlz3c3cC&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles%20iii%20volume%202&hl=fr&pg=PA1#v=onepage&q&f=true <u>Seneque Des Qvestions Natvrelles</u>], [https://books.google.fr/books?id=gEzVYlz3c3cC&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles%20iii%20volume%202&hl=fr&pg=PA141#v=onepage&q&f=true ''Livre Sixiesme. Des tremblemens de terre.''], [https://books.google.fr/books?id=gEzVYlz3c3cC&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles%20iii%20volume%202&hl=fr&pg=PA164#v=onepage&q&f=true ''chap. VI.''], traduction par [[w:Pierre_Du_Ryer|Pierre Du Ryer]], A Lyon, Chez Christofle Fovrmy, 1663</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Pline_l%27Ancien|'''Pline l’Ancien''']] [[#Pline|<span id="Pline_back"><sup>'''I'''</sup></span>]] == <p style="text-align: right;">([[w:23|23]]/[[w:24|24]], à [[w:Côme|''Novum Comum'']] ou [[w:Vérone|Vérone]] — [[w:79|79]], à [[w:Stabies|Stabies]], [[w:Mort_de_Pline_l%27Ancien|mort]] par asphyxie près de [[w:Pompéi|Pompéi]], lors de l’éruption du [[w:Vésuve|Vésuve]], en voulant observer le phénomène au plus près et en désirant porter secours aux victimes, alors en poste à [[w:Misène|''Misène'']] en tant que Préfet commandant la flotte militaire ''romaine'') <sup>[[w:Ier_siècle|⏳]]</sup> [[s:Auteur:Pline_l’Ancien|<sup>📚</sup>]] [https://books.google.fr/books?id=tRsuD3WJT-UC&newbks=1&newbks_redir=0&lpg=PA3&dq=bibliogroup%3A%22Dictionnaire%20des%20philosophes%20antiques%22&hl=fr&pg=PA876#v=onepage&q&f=true {{Info|<sup>🔍</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume Va, §204 - Plinius Secundus (Caius —)}}] <div style="text-align: justify; margin: 0 1em; text-indent: 15px">Haut fonctionnaire militaire et civique, issu de l’[[w:Chevalier_romain|''orde équestre'']], et écrivain prolifique dans de très nombreux domaines.</div> {{Boîte déroulante début|titre=NdA Pline l’Ancien|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Pline_back|<span id="Pline"><sup>I</sup></span>]] [[w:Nom_romain|Tria Nomina]] en latin {{Info|Caius|praenomen, nom individuel du citoyen romain}} {{Info|Plinius|nomen, nom de famille}} {{Info|Secundus|cognomen, surnom héréditaire, servant à distinguer les diverses branches d’une même gens}}'''<br/><br/></div> {{Boîte déroulante fin}} === [[w:Histoire_naturelle_(Pline_l'Ancien)|Histoire naturelle]] === <p style="text-align: right;">[[s:Histoire_naturelle_(Pline)|📚]] <div style="text-align: justify; margin: 0 1em; text-indent: 15px">Ouvrage de 37 livres dédié à l’empereur [[w:Titus_(empereur_romain)|'''Titus''']] [[#Titus|<span id="Titus_back"><sup>'''I'''</sup></span>]], dont il a été le ''{{Lang|la|contubernium}}'' pendant son service en tant que commandant des armées du ''Rhin'' en ''Germanie'' en [[w:47|47]]. '''Pline''' définit lui-même son enquête [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Histoire/Enquête_I|<sup>🔄</sup>]] sur la nature comme une reproduction de la vie — ''{{Lang|la|rerum natura, hoc est uita narratur}}'' (Livre I, Préface, 10), qu’il inscrit dans la tradition encyclopédique [[#encyclopédie_back|<sup>⤴️</sup>]] grecque mais s’en différencie par son exhaustivité : ''{{Lang|la|Jam omnia attingenda, quæ Græci}}'' ''{{Lang|grc|τάς έγχυχλοπαιδείας}}'' ''{{Lang|la|vocant : et tamen ignota aut incerta ingeniis facta; alia vero ita multis prodita, ut in fastidium sint adducta}}'' (Préface, 11). Il a, dans ce but, compilé « vingt mille faits dignes d’intérêt, tirés de la lecture d’environ deux mille volumes, [...] provenant de cent auteurs de choix » — ''{{Lang|la|Viginti millia rerum dignarum cura ex lectione voluminum circiter duum millium, [...] ex exquisitis auctoribus centum}}'' (Préface, 13).</div> {{Boîte déroulante début|titre=NdA Titus|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Titus_back|<span id="Titus"><sup>I</sup></span>]] Du nom propre latin Titus [[wikt:en:Titus#Latin|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;">Commandant militaire, notamment pendant la [[w:Premi%C3%A8re_guerre_jud%C3%A9o-romaine|''première guerre judéo-romaine'']], au cours de laquelle il prend ''Jérusalem'' que ses troupes mettent à sac et fait détruire le [[w:Second_temple_de_Jérusalem#Destruction|''Second Temple'']], et empereur ''romain'', de la dynastie des [[w:Flaviens|''Flaviens'']], de [[w:79|79]] à [[w:81|81]].<br /><p style="text-align: right; margin: 0 2em;">(30 décembre [[w:39|39]] , ''Rome'' — 13 septembre [[w:81|81]], mort par fièvre selon [[w:Suétone|Suétone]] [http://remacle.org/bloodwolf/historiens/suetone/titus.htm <sup>VdDC, Titus</sup>] ou par empoisonnement avec du venin de [[w:Aplysia|''lièvre marin'']] par son propre frère [[w:Domitien|Domitien]] selon [[w:Philostrate_d%27Ath%C3%A8nes|Philostrate]] [https://remacle.org/bloodwolf/roman/philiostrate/apollonius6.htm <sup>AdT, l. VI, chap. 32</sup>])<sup>[[w:Ier_siècle|⏳]]</sup>'''<br/><br/></div> {{Boîte déroulante fin}} ==== Livre II ==== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Enquête sur l’astronomie et la physique du monde, basée sur les quatre éléments : air, terre, eau et feu.</div> ===== <div style="text-align: center;">Chapitre IX.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage de la première prédiction grecque d’une éclipse solaire (ou lunaire selon les traductions) par '''Thalès'''.</div> :'''Texte latin''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''IX.''' Et rationem quidem defectus utriusque primus ''Romani'' generis in vulgus extulit '''Sulpicius Gallus''', qui consul cum '''Marcello''' fuit, sed tum tribunus militum, sollicitudine exercitu liberato, pridie quam '''Perseus''' rex superatus a '''Paulo''' est, in concionem ab imperatore productus ad prædicendam eclipsim, mox et composito volumine. Apud Græcos autem investigavit primus omnium '''Thales''' ''Milesius'', Olympiadis XLVIII anno quarto, prædicto solis defectu, qui '''Alyatte''' rege factus est, Urbis conditæ; anno CLXX. Post eos utriusque sideris cursum in sexcentos annos præcinuit '''Hipparchus''', menses gentium, diesque et horas, ac situs locorum, et visus populorum complexus, ævo teste, haud alio modo, quam consiliorum naturæ particeps. Viri ingentes supraque mortalium naturam, tantorum numinum lege deprehensa, et misera hominum mente absoluta, in defectibus scelera aut mortem aliquam siderum pavente (quo in metu fuisse '''Stesichori''' et '''Pindari''' vatum sublimia ora palam est deliquio Solis), et in Luna veneficia arguente mortalitate, et ob id crepitu dissono auxiliante. Quo pavore, ignarus causæ, '''Nicias''' ''Atheniensium'' imperator, veritus classem portu educere, opes eorum afflixit. Macti ingenio este, cæli interpretes, rerumque naturæ capaces, argumenti repertores, quo deos hominesque vinxistis. Quis enim hæc cernens, et statos siderum (quoniam ita placuit appellare) labores, non suæ necessitati mortalis genitus ignoscat ? Nunc confessa de iisdem breviter atque capitulatim attingam, ratione admodum necessariis locis strictimque reddita : nam neque instituti operis talis argumentatio est : neque omnium rerum afferri posse causas, minus mirum est, quam consfare in aliquibus.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/b24875958_0001/page/n7/mode/2up <u>Histoire Naturelle de Pline.</u>], [https://archive.org/details/b24875958_0001/page/98/mode/2up ''Livre II.''], [https://archive.org/details/b24875958_0001/page/106/mode/2up ''chap. IX.''], texte corrigé par [[w:Émile_Littré|M. É. Littré]], à partir de celui de [[w:Jean_Hardouin|Hardouin]], Librairie de Firmin-Didot et C<sup>ie</sup>, Paris, 1883<br />(également disponible une édition 1848 [[s:Page:Pline_l'ancien_-_Histoire_naturelle,_Littré,_T1_-_1848.djvu/130|ici]] et 1829 [https://gallica.bnf.fr/ark:/12148/bpt6k5773334c/f45.item là])</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''IX.''' Le premier ''Romain'' qui exposa publiquement la théorie des éclipses du soleil et de la lune est [[w:Caius_Sulpicius_Gallus|'''Sulpicius Gallus''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Caius_Sulpicius_Gallus_back|<sup>🔄</sup>]], qui fut consul avec [[w:Marcus_Claudius_Marcellus_(consul_en_-166)|'''Marcellus''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Marcellus-166_back|<sup>🔄</sup>]], mais qui alors était tribun militaire. La veille du jour où [[w:Persée_(roi)|'''Persée''']] [[#Persée_(roi)|<span id="Persée_(roi)_back"><sup>'''I'''</sup></span>]] fut défait par [[w:Lucius_Æmilius_Paullus_Macedonicus|'''Paul-Emile''']] [[#Lucius_Æmilius_Paullus_Macedonicus|<span id="Lucius_Æmilius_Paullus_Macedonicus_back"><sup>'''II'''</sup></span>]] il parut par ordre du général, afin de prévenir les alarmes de l’armée, devant les troupes assemblées pour annoncer l’éclipse qui allait survenir; peu de temps après, il composa un livre sur ce sujet. Le premier qui s’en occupa chez les ''Grecs'' fut '''Thalès''' de ''Milet'', dans la quatrième année de la quarante-huitième olympiade (an 585 av. J. C. [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#éclipse_back|<sup>🔄</sup>]]), l’an 170 de la fondation de ''Rome'', et prédit une éclipse de lune qui arriva sous le roi [[w:Alyatte_II|'''Alyatte''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Alyatte_back|<sup>🔄</sup>]]. Après eux, [[w:Hipparque_(astronome)|'''Hipparque''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Hipparque_back|<sup>🔄</sup>]] dressa pour six cents ans la table du cours du soleil et de la lune, déterminant les mois des divers calendriers, les jours, les heures, les localités et les aspects, suivant les contrées. Le cours des ans ne lui a donné aucun démenti, et il semble avoir été admis aux conseils de la nature. Génies puissants et élevés au dessus de l’humanité, ils ont découvert la loi qui régit ces grandes divinités, et ils ont délivré de ses craintes l’esprit misérable des hommes, qui dans les éclipses, tantôt croyaient voir une influence malfaisante ou une espèce de mort des astres, crainte qui, comme on sait, a, pour l’éclipse du soleil, troublé [[w:Stésichore|'''Stésichore''']] [[#Stésichore|<span id="Stésichore_back"><sup>'''III'''</sup></span>]] et [[w:Pindare|'''Pindare''']] [[#Pindare|<span id="Pindare_back"><sup>'''IV'''</sup></span>]], poètes sublimes, et tantôt attribuaient l’obscurcissement de la lune à des maléfices, et lui venaient en aide par un bruit dissonnant. Redoutant ce phénomène, dont il ignorait la cause, [[w:Nicias|'''Nicias''']] [[#Nicias|<span id="Nicias_back"><sup>'''V'''</sup></span>]], général des ''Athéniens'', n’osa pas faire sortir la flotte du port de [[w:Syracuse#Antiquité|''Syracuse'']], et ruina la puissance de sa patrie. Redoublez de génie, interprètes du ciel, vous dont l’intelligence, embrassant la nature, a inventé des théories qui ont créé un lien entre les dieux et les hommes [[#Vicistis_JH|<span id="Vicistis_JH_back"><sup>'''1'''</sup></span>]] ! A la vue de ce spectacle, à la vue des labeurs (puisque c’est le nom qu’on a voulu donner aux éclipses), des labeurs réguliers auxquels les astres sont soumis, quel mortel ne pardonnerait à la nécessité sous laquelle il est né ? Maintenant je vais parler, d’une manière brève et sommaire, des points sur lesquels on est d’accord en cette matière. Je ne donnerai que de courtes explications, et là où il sera tout à fait nécessaire; car les explications n’entrent pas dans le plan de cet ouvrage, et il n’y a pas moins de mérite à énumérer les causes de toutes choses qu’à s’appesantir sur quelques-unes.</div> <table cellspacing=15 align=center style="margin: 0 4em; font-size:85%;"> <tr> <td style="text-align: justify; margin: 0 4em;">'''[[#Vicistis_JH_back|<span id="Vicistis_JH"><sup>1</sup></span>]] Vicistis Vulg. — Vinxistis cod. Dalech. — Vinxistis me parait meilleur. Comp. ce que dit Pline plus loin, ch. 24, sur l’affinité de l’esprit humain avec les astres.'''</td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/b24875958_0001/page/n7/mode/2up <u>Histoire Naturelle de Pline.</u>], [https://archive.org/details/b24875958_0001/page/98/mode/2up ''Livre II.''], [https://archive.org/details/b24875958_0001/page/106/mode/2up ''chap. IX.''], texte corrigé par [[w:Émile_Littré|M. É. Littré]], à partir de celui de [[w:Jean_Hardouin|Hardouin]], Librairie de Firmin-Didot et C<sup>ie</sup>, Paris, 1883<br />(édition 1848 également disponible [[s:Page:Pline_l'ancien_-_Histoire_naturelle,_Littré,_T1_-_1848.djvu/130|ici]])</div> {{Boîte déroulante début|titre=NdA de trad. Jean Hardouin 1883|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Persée_(roi)_back|<span id="Persée_(roi)"><sup>I</sup></span>]] Du nom propre grec ancien Περσεύς / Perseús[[wikt:en:Περσεύς#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px">Dernier roi de [[w:Royaume_de_Mac%C3%A9doine|''Macédoine'']] de la dynastie des [[w:Antigonides|''Antigonides'']], vaincu en [[w:-168|-168]] à la [[w:bataille de Pydna|bataille de ''Pydna'']] à l’issue de la [[w:troisième guerre macédonienne|''troisième guerre macédonienne'']], causant la disparition du ''Royaume de Macédoine''.<br /><p style="text-align: right; margin: 0 2em;">([[w:Années_212_av._J.-C.|-212]]<sup>[[w:IIIe_siècle_av._J.-C.|⏳]]</sup>, [[w:Pella_(cité_antique)|''Pella'']], au nord de l’actuelle ''Grèce'' — [[w:Années_166_av._J.-C.|-166]]<sup>[[w:IIe_siècle_av._J.-C.|⏳]]</sup>, [[w:Alba_Fucens|''Alba Fucens'']], au centre de l’actuelle ''Italie'') <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Lucius_Æmilius_Paullus_Macedonicus_back|<span id="Lucius_Æmilius_Paullus_Macedonicus"><sup>II</sup></span>]] [[w:Nom_romain|Tria Nomina]] en latin {{Info|Lucius|praenomen, nom individuel du citoyen romain}} {{Info|Æmilius|nomen, nom de famille}} {{Info|Paullus|cognomen, surnom héréditaire, servant à distinguer les diverses branches d’une même gens}}, surnommé [[wikt:Macedonicus#Latin|Macedonicus]] par le [[w:Sénat_romain|''Sénat'']] à la suite de sa victoire;<br /><p style="margin: 0 2em; text-indent: 15px">Homme politique ''romain'', consul à 2 reprises en [[w:Années_182_av._J.-C.|-182]] et [[w:Années_169_av._J.-C.|-169]]. Il remporta la victoire contre le ''royaume de Macédoine'' à ''Pydna'' en battant le roi Persée [[#Persée_(roi)|<sup>I</sup>]], ce qui mit fin à la dynastie des ''Antigonides''.<br /><p style="text-align: right; margin: 0 2em;">([[w:Circa|{{Info|''ca.''|Circa, locution latine que l’on emploie pour indiquer l’approximation d’une date}}]] [[w:Années_230_av._J.-C.|-230]]<sup>[[w:IIIe_siècle_av._J.-C.|⏳]]</sup>, ''Rome'' — ''ca.'' [[w:Années_160_av._J.-C.|-160]]<sup>[[w:IIe_siècle_av._J.-C.|⏳]]</sup>, ''Rome'') <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Stésichore_back|<span id="Stésichore"><sup>III</sup></span>]] Du nom propre grec ancien Στησίχορος /Stēsíkhoros [[wikt:en:Στησίχορος#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;">➥ du verbe ἵστημι /hístēmi, « 1. (voix transitive, active des temps présent, imparfait, futur et 1er aoriste) : • Faire se tenir debout, se tenir debout; • Arrêter, rester, vérifier; • Mettre en place : - Faire monter, élever, réveiller, remuer; - Nommer, désigner; - Établir, instituer; • Mettre dans la balance, peser. 2. (voix intransitive, moyenne et passive, voix active du 2e aoriste, parfait et plus-que-parfait) : • Se tenir debout; • Se tenir immobile : (au sens figuré) Rester ferme; • Être dressé ou debout, se lever, s’élever : - (en général) Se lever, commencer; - (en marquant le pas) Être; - Être désigné. »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ +‎ du nom commun χορός / khorós, « 1. Danse en rond. 2. Danse accompagnée de chant, danse chorale. 3. Chœur, chorale, groupe de chanteurs et de danseurs. 4. Groupe, troupe. 5. Rangée. 6. Lieu de danse. 7. (théâtre) Chœur »;<br /><p style="margin: 0 2em; text-indent: 15px">Poète lyrique grec, considéré comme l’un des [[w:Neuf_lyriques_grecs|''neuf poètes lyriques'']] de la Grèce antique.<br /><p style="text-align: right; margin: 0 2em;">([[w:Circa|{{Info|''ca.''|Circa, locution latine que l’on emploie pour indiquer l’approximation d’une date}}]] [[w:Années_630_av._J.-C.|-630]]<sup>[[w:VIIe_siècle_av._J.-C.|⏳]]</sup>, [[w:Metauria|''Metauria'']], colonie de la [[w:Grande-Grèce|''Grande-Grèce'']], au sud de la région de [[w:Calabre|''Calabre'']], au sud de l’Italie — ''ca.'' [[w:Années_555_av._J.-C.|-555]]<sup>[[w:VIe_siècle_av._J.-C.|⏳]]</sup>, [[w:Catane|''Catane'']], colonie de la ''Grande-Grèce'', à l’est de la [[w:Sicile|''Sicile'']]) <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Pindare_back|<span id="Pindare"><sup>IV</sup></span>]] Du nom propre grec ancien Πίνδᾰρος /Píndaros [[wikt:en:Πίνδαρος#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px">Poète lyrique grec, considéré comme l’un des [[w:Neuf_lyriques_grecs|''neuf poètes lyriques'']] de la Grèce antique.<br /><p style="text-align: right; margin: 0 2em;">([[w:Années_518_av._J.-C.|-518]]<sup>[[w:VIe_siècle_av._J.-C.|⏳]]</sup>, [[w:Cynocéphales|''Cynocéphales'']], cité grecque située près de [[w:Thèbes_(Grèce)|''Thèbes'']], en [[w:Béotie|''Béotie'']] — [[w:Années_438_av._J.-C.|-438]]<sup>[[w:Ve_siècle_av._J.-C.|⏳]]</sup>, [[w:Árgos|''Árgos'']], cité grecque de la région de l’[[w:Argolide|''Argolide'']], à l’est de la [[w:Péloponnèse|''péninsule du Péloponnèse'']]) <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Nicias_back|<span id="Nicias"><sup>V</sup></span>]] Du nom propre grec ancien Νῑκίᾱς /Nīkíās [[wikt:en:Νικίας#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;">➥ du nom commun νίκη / níkē [[wikt:en:νίκη#Ancient_Greek|(en)]], « 1. Le fait de gagner : la victoire, le succès [avec le génitif "sur, dans quelque chose"] : • Les choses gagnées dans la victoire, les fruits de la victoire; • La supériorité, l’avantage. »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ + du suffixe nominal masculin -ίας / -ías [[wikt:en:-ίας#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px">Homme politique et général ''athénien'' durant la [[w:Guerre_du_Péloponnèse|''guerre du Péloponnèse'']], qui oppose la [[w:Ligue_de_Délos|''ligue de Délos'']], menée par ''Athènes'', et la [[w:Ligue_du_Péloponnèse|''ligue du Péloponnèse'']], sous l’[[w:Hégémonie|hégémonie]] de ''Sparte'' de [[w:Années_431_av._J.-C.|-431]] à [[w:Années_404_av._J.-C.|-404]]. Sa supersition liée à une éclipse lunaire, s’étant produite lors de l’[[w:Expédition_de_Sicile|''expédition de Sicile'']], est également relatée par [[w:Thucydide|Thucydide]] [http://remacle.org/bloodwolf/historiens/thucydide/livre7.htm#L <sup>{{Info|HdlgdP|Histoire de la guerre du Péloponnèse}} l.VII, §.L</sup>] et [[w:Plutarque|Plutarque]] [[#Plutarque_back|<sup>⤵️</sup>]] [http://remacle.org/bloodwolf/historiens/Plutarque/supestition.htm#23 <sup>{{Info|DlS|De la Superstition}} l.I</sup>].<br /><p style="text-align: right; margin: 0 2em;">([[w:Circa|{{Info|''ca.''|Circa, locution latine que l’on emploie pour indiquer l’approximation d’une date}}]] [[w:Années_470_av._J.-C.|-470]], ''Athènes'' — ''ca.'' [[w:Années_413_av._J.-C.|-413]], ''Syracuse'')<sup>[[w:Ve_siècle_av._J.-C.|⏳]]</sup>'''<br/><br/></div> {{Boîte déroulante fin}} <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: center; margin: 0 2em;">Des découvertes astronomiques : part de chaque observateur dans la science.<br /><p style="text-align: justify; text-indent: 15px;">'''IX.''' '''Sulpicius Gallus''' [[#Sulpicius_Gallus_AdG|<span id="Sulpicius_Gallus_AdG_back"><sup>'''1'''</sup></span>]] fut le premier ''Romain'' qui expliqua au vulgaire la raison des éclipses de soleil et de lune. Il fut consul avec '''Marcus Marcellus''' ; mais il n’était que tribun militaire lorsque la veille de la victoire que '''Paul Emile''' remporta sur '''Persée''' [[#Pridie_quam_Perses_rex_AdG|<span id="Pridie_quam_Perses_rex_AdG_back"><sup>'''2'''</sup></span>]], son général le fit paraître devant l’armée assemblée, pour lui annoncer l’éclipse qui allait arriver, et la délivrer de l’alarme qu’elle aurait pu en concevoir. Il composa bientôt après un volume sur ce sujet. Parmi les ''Grecs'', '''Thalès''' de ''Milet'' [[#Primus_omnium_Thales_AdG|<span id="Primus_omnium_Thales_AdG_back"><sup>'''3'''</sup></span>]] dirigea le premier ses recherches sur ce phénomène, et la quatrième année de la 48e olympiade, qui répond à l’an 170 [[#Anno_CLXX_AdG|<span id="Anno_CLXX_AdG_back"><sup>'''4'''</sup></span>]] de ''Rome'', il prédit l’éclipse de soleil qui eut lieu sous le règne d’'''Alyatte''' [[#Alyatte_rege_AdG|<span id="Alyatte_rege_AdG_back"><sup>'''5'''</sup></span>]]. Après eux, '''Hipparque''' dressa des tables du cours de ces deux astres pour six cents ans [[#In_sexcentos_annos_AdG|<span id="In_sexcentos_annos_AdG_back"><sup>'''6'''</sup></span>]] : mois, heures, jours, situations respectives des lieux, aspects du ciel selon les diverses nations [[#Menses_gentium_etc_AdG|<span id="Menses_gentium_etc_AdG_back"><sup>'''7'''</sup></span>]], tout y est compris, tout a été vérifié par le temps [[#Aevo_teste_AdG|<span id="Aevo_teste_AdG_back"><sup>'''8'''</sup></span>]]; on croirait l’astronome admis au conseil de la nature. Génies vastes et plus qu’humains, d’avoir ainsi surpris la loi de ces deux grandes divinités [[#Numinum_AdG|<span id="Numinum_AdG_back"><sup>'''9'''</sup></span>]], et affranchi d’effroi la malheureuse espèce humaine, qui tremblait en voyant dans chaque éclipse l’annonce de quelque grand crime, ou craignait la mort des astres [[#In_defectibus_scelera_etc_AdG|<span id="In_defectibus_scelera_etc_AdG_back"><sup>'''10'''</sup></span>]] (effroi dont '''Stésichore''' et '''Pindare''' [[#Pindari_AdG|<span id="Pindari_AdG_back"><sup>'''11'''</sup></span>]], ces poètes sublimes, ne furent point exempts dans les éclipses de soleil), ou qui attribuait à des enchantemens celles de la lune, et venait à son secours en faisant un bruit discordant [[#Crepitu_dissono_AdG|<span id="Crepitu_dissono_AdG_back"><sup>'''12'''</sup></span>]]. C’est pour en avoir ignoré la cause, que, frappé de cette même terreur, '''Nicias''' [[#Nicias_AdG|<span id="Nicias_AdG_back"><sup>'''13'''</sup></span>]], général des ''Athéniens'', n’osa pas faire sortir sa flotte du port, et causa la ruine de leur puissance. Gloire à vous, interprètes du ciel, génies aussi étendus que la nature, inventeurs d’une science qui enchaîne à une même destinée les dieux et les mortels ! Quel est donc l’homme qui, voyant les astres en travail (pour me servir du nom qu’il a plu de donner aux crises qu’ils, subissent périodiquement), ne se soumettra pas à sa destinée?<br /><p style="text-align: justify; text-indent: 15px;">Je vais maintenant toucher brièvement et sommairement les points sur lesquels on est d’accord dans cette matière, et j’en rendrai raison en passant, lorsque cela sera tout-à-fait nécessaire; car un développement de preuves n’est pas le but de l’ouvrage que j’ai entrepris, et il n’y a pas, je pense, moins de mérite à pouvoir rendre raison de toutes choses, qu’à s’arrêter à en prouver quelques-unes.</div> {{Boîte déroulante début|titre=Notes du traducteur|alignT=center}} <div style="text-align: justify; border: 2px; border-radius:15px; font-size:85%;"><br/> <table cellspacing=15 align=center style="margin: 0 4em;"> <tr> <td style="text-align: justify; margin: 0 4em; text-indent: 15px">'''[[#Sulpicius_Gallus_AdG_back|<span id="Sulpicius_Gallus_AdG"><sup>1</sup></span>]] [[w:Tite-Live|Tite-Live]], XLIV, 37, [[w:Quintilien|Quintilien]], I, 10, [[w:Plutarque|Plutarque]] [[#Plutarque_back|<sup>⤵️</sup>]], [[w:Vies_parallèles|''Vie de Paul Emile'']], [[w:Frontin|Frontin]], I, etc., prétendent, comme Pline, que Sulpicius Gallus prédit l’éclipse anx soldats romains. [[w:Cicéron|'''Cicéron''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Cicéron_back|<sup>🔄</sup>]] ([[w:De_Republica|''Répub.'']], I, 15 , page 44, ''édit. Maj.'') dit au contraire que l’éclipse était déjà arrivée lorsque Sulpicius Gailus commençait à s’efforcer d’ôter aux soldats romains la terreur qu’ils avaient conçue de cet événement, en leur expliquant les causes des éclipses.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Pridie_quam_Perses_rex_AdG_back|<span id="Pridie_quam_Perses_rex_AdG"><sup>2</sup></span>]] Selon Tite-Live (XLIV, 37), l’éclipse eut lieu dans la soirée du 3 septembre, cent huit ans avant J.-C., entre sept et dix heures (''ab hora secunda usque ad quartam noctis, quam pridie nonas sept, secula est dies''). M. [[w:Christian_Ludwig_Ideler|Ideler]] (''Chronologie'', II, 104) a calculé cette éclipse. Il a trouvé, comme M. de Nauze, que, selon le calendrier Julien, elle arriva dans la soirée du 21 juin de l’an 168 avant J.-C. à Rome, la lune commença à s’éclipser vers 5h.44’ du soir ; depuis 6h.51’ jusqu’à 8h.18’, la lune fut totalement éclipsée, ; à 9h.,24’, la lune ne fut plus obscurcie du tout. En Macédoine, tous ces phénomènes arrivèrent 39 minutes plus tard. Le 21 juin, le soleil se coucha à Rome et en Macédoine vers 7h.33’, et s’y montra alors à 44 1/2’ h. équatoriales. Ainsi, la première heure de la nuit finissait vers 8h.17’, la seconde vers 9h.2’, la troisième vers 9h.46’, la quatrième vers 10h.31’. La lune fut donc éclipsée totalement au moment où elle se leva dans la Macédoine, et cette éclipse totale y finit dans la seconde heure de la nuit ; au milieu de la quatrième, la lune ne fut plus obscurcie du tout. S’il est vrai, que cette éclipse lunaire, comme Pline, Tite-Live et d’autres le disent, fut prédite par Sulpicius Gallus, l’on devrait avouer que ce Romain s’entendait très-bien au calcul des éclipses lunaires. Mais les récits de Cicéron et de [[w:Valère_Maxime|Valère-Maxime]] ne seraient-ils pas plus vrais que ceux de Pline et de Tite-Live ?''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Primus_omnium_Thales_AdG_back|<span id="Primus_omnium_Thales_AdG"><sup>3</sup></span>]] Le même fait est rapporté par [[w:Hérodote|Hérodote]] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Hérodote_back|<sup>🔄</sup>]], I, 74, par [[w:Diogène_Laërce|Diogène Laërce]] [[#Diogène_Laërce_back|<sup>⤵️</sup>]], I, 6 , par [[w:Clément_d'Alexandrie|Clément d’Alexandrie]] [[#Clément_d'Alexandrie_back|<sup>⤵️</sup>]], ''Strom.'', I, page 302 , par Plutarque, ''Opinions des Philosophes'', II, 24, par [[w:Jean_Tzétzès|Tzetzès]], ''Chil.'' II, v. 869, et par Hardouin.<br /><p style="text-align: justify; text-indent: 15px;">Oltmann a publié une dissertation dans laquelle, à l’aide des tables astronomiques les plus modernes, il est arrivé à ce résultat, que l’éclipse solaire dont il est question ici eut lieu le 3o septembre 610 ans avant J.-C. L’éclipse était totale pour les environs de la ville d’[[w:Erzurum|Érzerum]] sur le [[w:Kızılırmak_(fleuve)|Halys]] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Halys_back|<sup>🔄</sup>]], où [[w:Volney|Volney]] place le champ de bataille des rois [[w:Alyatte_II|Halyattes]] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Alyatte_back|<sup>🔄</sup>]] et [[w:Cyaxare|Cyaxare]] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Cyaxare_back|<sup>🔄</sup>]]. La quatre-vingtième partie du disque solaire seule ne fut pas éclipsée pour le lieu de la terre où Oltmann place le champ de bataille, qui est situé, selon lui, sous 36° long. à l’est de Terro et sous 40° lat. sept. Dans le pays des Ioniens où Thalès prédit l’éclipse, selon Hérodote, l’éclipse se monta à 11 1/2’. M. [[w:Alphonse_Des_Vignoles|Desvignolles]] (''Chronologie de l’histoire sainte'', t. II, pag. 245 et suiv.) fixe l’éclipsé prédite par Thales au 38 mai de l’an 585 avant J.-C. ; son opinion a été adoptée depuis par presque tous les chronologistes et historiens, et par [[w:Gabriel_Brotier|Brotier]] et M. Alexandre. Elle a été réfutée avec succès par Oltmann, qui s’est servi de tables astronomiques bien plus exactes que celles de M. Desvignolles ; en effet, celui-ci a démontré par ses calculs que l’éclipse totale du soleil du 28 mai de l’an 585 avant J.-C., ne fut pas totale dans les lieux où les troupes du roi lydien Halyatte combattirent contre celles du roi Cyaxare ; que, dans ces régions, elle ne se monta pas à plus de 7 1/2 pouces, et que, d’ailleurs, le soleil ne s’était pas encore levé lorsque Féclipse était le plus forte pour les habitans des pays nommés. Mais Hérodote dit positivement que l’éclipse prédite par Thalès fut totale dans ces contrées, et qu’elle eut lieu en plein jour. (Voyez IDELER, ''Chronologie'', t. I, pag. 209 et 210.) Nous remarquerons pourtant avant de finir cette note que la date de Desvignolles est plus conforme que celle d’Oltmann à l’année dans laquelle l’éclipse prédite par Thalès, arriva selon Pline. En effet, le naturaliste romain dit que cette année est la six cent quatre-vingt-cinquième avant J.—C., et c’est justement le 28 mai de cette année que l’éclipse prédite par Thalès arriva, selon M. Desvignolles.<br /><p style="text-align: justify; text-indent: 15px;">Volney pense que l’éclipse en question arriva le 3 février de de l’an 626. Oltman a démontré, dans son Mémoire sur l’éclipse de Thalès, que celle de Volney était déjà passée lorsque le soleil se leva sur le champ de bataille des rois Halyattes et Cyaxare.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Anno_CLXX_AdG_back|<span id="Anno_CLXX_AdG"><sup>4</sup></span>]] L’an 170. C’est ainsi que l’on doit lire, et non CLX, comme l’ont fait Hardouin et Poinsinet; la quatrième année de la quarante-huitième olympiade, correspondant à l’an 170 de Rome, si l’on suppose avec [[w:Varron_(écrivain)|Varron]] que cette ville a été fondée dans la deuxième année de la 6e olympiade.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Alyatte_rege_AdG_back|<span id="Alyatte_rege_AdG"><sup>5</sup></span>]] Le nom de ce roi est écrit avec un esprit rude dans Hérodote, ce qui a donné lieu à [[w:Louis_Poinsinet_de_Sivry|Poinsinet]] et à d’autres traducteurs de Pline de substituer le mot Halyatte à celui d’Alyatte.<br /><p style="text-align: justify; text-indent: 15px;">Alyatte ou Halyatte fut roi de la Lydie et père de Crésus. Il faisait la guerre à Cyaxare, roi des Mèdes, lorsque l’éclipse solaire en question interrompit le combat.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#In_sexcentos_annos_AdG_back|<span id="In_sexcentos_annos_AdG"><sup>6</sup></span>]] On lit dans [[w:Georges_le_Syncelle|le Syncelle]] (''Chronolog.'', pag. 17) que les Chaldéens ont connu une période de six cents années solaires. [[w:Flavius_Josèphe|Josèphe]] [[#Flavius_Josèphe_back|<sup>⤵️</sup>]] ([[w:Antiquités_judaïques|''Ant. jud.'']], I, page 17 et 18, édit. Havercamp) dit que Dieu donna une longue vie aux patriarches pour qu’ils pussent cultiver avec succès les sciences astronomiques et géométriques, ce qu’ils n’auraient pu faire s’ils n’avaient pas vécu au moins six cents ans ; car la grande année ne finit pas plus tôt. Ainsi, il est certain qu’avant Hipparque les Chaldéens et d’autres peuples asiatiques ont connu une période de six cents années solaires. Mais [[w:Jean-Dominique_Cassini|Cassini]] ([[w:Jean-Dominique_Cassini#Mémoires_de_l’Académie_royale_des_sciences|''Anciens mém. de l’Acad.'']], t. VIII, pag. 4 et 5) et [[w:Jean_Sylvain_Bailly|Bailly]] (''Hist. de l’astr. ancienne'', t. II, liv. 3, Eclairciss.) ont prouvé que tous les six cents ans les nouvelles et pleines lunes n’arrivent pas seulement au même jour et à la même heure qu’auparavant, mais encore à la même minute. Ne serait-il donc pas probable qu’Hipparque, comme le dit Ideler (''Historische untersuchungen uber die astronomischen beobachtungen der alten'', Berlin 1806, page 417) a connu cette période chaldéenne, et que delà résulte l’étendue de six cents ans donnée à son calendrier selon Pline.<br /><p style="text-align: justify; text-indent: 15px;">[[w:Abel_Burja|Abel-Burja]] de Leipzig a tâché d’expliquer d’une autre manière la durée du calendrier d’Hipparque (''Astronomisches Jahrbuch'', 1797, pag. 233 et 234). [[w:Claude_Ptolémée|Ptolémée]] et [[w:Censorin_(grammairien)|Censorin]] racontent qu’Hipparque est auteur d’une période soli-lunaire de trois cent quatre années solaires. En la prenant deux fois, on obtient une période de six cent huit ans. Celle-ci fut abrégée par Hipparque de huit ans, afin d’obtenir un nombre entier de siècles pour son calendrier. Ideler a fait une objection très-juste contre cette opinion de Burja ; c’est que la période de six cent huit ans n’a aucun avantage sur celle de trois cent quatre ans. On ne voit donc pas ce qui a pu engager Hipparque à préférer le nombre de six cents ans à celui de trois cents, lorsqu’il composait son calendrier.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Menses_gentium_etc_AdG_back|<span id="Menses_gentium_etc_AdG"><sup>7</sup></span>]] C’est-à-dire il écrivit des éphémérides dans lesquelles il avait calculé d’avance les néomenies et les pleines lunes. Il fit aussi entrer dans son calendrier les longueurs des jours et des heures variables, [[w:ὧραι|ὧραι]] καιρικαι, ainsi que les aspects du ciel, ''visus populorum'', tels qu’ils eurent lieu chez les habitans de différentes contrées de la terre. Il ajouta une table des longitudes et des latitudes des principaux pays et villes du globe. Ptolémée (''Géogr.'', I, ch. 4) en dit autant d’Hipparque.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Aevo_teste_AdG_back|<span id="Aevo_teste_AdG"><sup>8</sup></span>]] Les tables d’Hipparque étaient dressées pour six cents ans. Cet astronome florissait vers cent cinquante ans avant J.-C. Ainsi, du temps de Pline, on avait encore à jouir de ces tables pour quatre cents ans environ. POINSINET.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Numinum_AdG_back|<span id="Numinum_AdG"><sup>9</sup></span>]] Pline donne souvent l’épithète de divinités aux planètes, à la lune, au soleil, à la terre et aux étoiles fixes.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#In_defectibus_scelera_etc_AdG_back|<span id="In_defectibus_scelera_etc_AdG"><sup>10</sup></span>]] Nous transcrivons ici ce beau passage de l’Uranographie de M. [[w:Louis-Benjamin_Francœur|Francoeur]], qui mérite d’être mis en parallèle avec celui de Pline pour l’élégance du style et les pensées, et qui renferme le meilleur commentaire que nous puissions donner de tout ce que Pline dit des terreurs que les éclipses causaient autrefois aux hommes ignorans. « L’histoire, dit M. Francoeur (page 93), est pleine des exemples de l’effroi causé par les éclipses, et des dangers que produisent l’ignorance et la superstition. Nicias avait résolu de quitter la Sicile avec son armée ; effrayé par une éclipse de lune, et voulant temporiser plusieurs jours pour s’assurer si l’astre n’avait rien perdu après cet évènenement, il manqua ainsi l’occasion de sa retraite; son armée fut détruite ; Nicias périt, et ce malheur commença la ruine d’Athènes.<br /><p style="text-align: justify; text-indent: 15px;">« Souvent on a vu des hommes adroits tirer parti de la frayeur du peuple pour l’amener à remplir leurs desseins. Christophe Colomb, réduit à faire subsister ses soldats des dons volontaires d’une nation sauvage et indigente, était prêt à voir tarir cette ressource et à périr de faim ; il annonce qu’il va priver le monde de la lumière de la lune. L’éclipse commence et la terreur s’empare des Indiens, qui reviennent apporter aux pieds de Colomb les tributs accoutumés.<br /><p style="text-align: justify; text-indent: 15px;">« Drusus (TACITE , Annales, I, 28) apaisa une sédition dans son armée, en prédisant une éclipse de lune, et, selon Tite-Live, Sulpicius Gallus, dans la guerre de Paul-Emile contre Persée, usa du même stratagème. Periclès, [[w:Agathocle_de_Syracuse|Agathocles de Syracuse]], [[w:Dion_de_Syracuse|Dion]], roi de Sicile, ont failli être victimes de l’ignorance de leurs soldats. [[w:Alexandre_le_Grand|Alexandre]], près d’[[w:Bataille_de_Gaugamèles|Arbelles]], est réduit à user de toute son adresse pour calmer la terreur qu’une éclipse avait jetée parmi ses troupes. Les hommes supérieurs, plutôt que de plier sous les circonstances qui les maîtrisent, mettent leur art à les tourner à leur profit.<br /><p style="text-align: justify; text-indent: 15px;">« Combien de fables établies d’après l’opinion que les éclipses sont l’effet du courroux céleste qui se venge des iniquités de l’homme en le privant de la lumière! Tantôt [[w:Diane_(mythologie)|Diane]] va trouver [[w:Endymion|Endymion]] dans les montagnes de Carie; tantôt les magiciennes de Thessalie font descendre la lune sur les herbes qu’elles destinent aux enchantemens. »<br /><br /><p style="text-align: center;">''Carmina vel cælo possunt deducere lunam.''<br /><p style="text-align: right; text-indent: 15px;">Virg., ''Eclog.'' VIII.<br /><br /><p style="text-align: justify; text-indent: 15px;">« Ici c’est un dragon qui dévore l’astre, et qu’on cherche à épouvanter par des cris ; le dieu tient le soleil enfermé dans un tuyau, et nous ôte ou nous rend la vue de cet astre à l’aide d’un volet, etc. Les progrès des sciences ont fait connaître le ridicule de ces opinions et de ces craintes, depuis qu’on a vu qu’il était possible de calculer par les tables astronomiques, et de prévoir long-temps d’avance l’instant où la colère du ciel devait éclater.<br /><p style="text-align: justify; text-indent: 15px;">« Cependant, naguère encore, l’épouvante a causé les revers des armées de Louis XIV, près de Barcelone, lors de l’éclipse totale de l’an 1706 [[w:en:Solar_eclipse_of_May_12,_1706|(en)]], et la devise, ''nec pluribus impar'', a prêté aux allusions injurieuses ! »''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Pindari_AdG_back|<span id="Pindari_AdG"><sup>11</sup></span>]] Pindare était le plus fameux poète de la Grèce après Homère. Il vint au monde l’an 134 avant l’ère chrétienne. POINSINET.<br /><p style="text-align: justify; text-indent: 15px;">Plutarque (''De la face de la lune'', pag. 931) dit aussi que Stésichore et Pindare craignaient beaucoup les éclipses. Le dernier poète a peint les terreurs que lui causaient ces phénomènes dans son poëme sur le soleil. HARDOUIN et DALECHAMP.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Crepitu_dissono_AdG_back|<span id="Crepitu_dissono_AdG"><sup>12</sup></span>]] Cet usage superstitieux dont Plutarque parle au long dans sa vie de Paul-Émile, a fourni un vers fort plaisant à Juvénal, lorsqu’après avoir épuisé toute sorte d’exagération pour représenter le bruit qu’une femme fait en criant, il finit par dire :<br /><br /><p style="text-align: center;">''Una laboranti poterit succurrere lunæ.''<br /><br /><p style="text-align: justify; text-indent: 15px;">« Elle seule, au besoin, décharmerait la lune. » POINSINET.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Nicias_AdG_back|<span id="Nicias_AdG"><sup>13</sup></span>]] Le même fait est raconté par Plutarque dans la vie de Nicias, par Quintilien, I, 10, et par d’autres écrivains anciens. HARDOUIN.''' </td> </tr> </table><br/><br/></div>{{Boîte déroulante fin}} <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k5773334c/f10.item <u>Histoire Naturelle de Pline. Tome Second</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k5773334c/f14.item ''Livre II.''], [https://gallica.bnf.fr/ark:/12148/bpt6k5773334c/f46.item ''chap. IX.''], traduction nouvelle par M. [[w:Stéphane_Ajasson_de_Grandsagne|Ajasson de Grandsagne]] [https://gallica.bnf.fr/ark:/12148/bpt6k5773334c/f311.item <sup>NOTES</sup>], C. L. F. Panckoucke, Paris, 1829</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: center; margin: 0 2em;">''Des inventions a[[w:S_long|{{Info|ſ|forme ancienne longue de la lettre s minuscule}}]]<nowiki />tronomiques, & de leurs Auteurs.''<br /><p style="text-align: justify; text-indent: 15px;">'''L'''E PREMIER d’entre les ''Romains'' qui rendit publique la théorie des éclip{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oleil & de lune, fut '''Sulpicius Gallus''' [[#Sulpicius_Gallus_LPdS|<span id="Sulpicius_Gallus_LPdS_back"><sup>'''1'''</sup></span>]], celui que '''Marcus Marcellus''' eut pour Collegue au Con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ulat : mais il n’étoit que Tribun Militaire [[#Tribun_Militaire_LPdS|<span id="Tribun_Militaire_LPdS_back"><sup>'''2'''</sup></span>]], lor{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’il di{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ipa l’allarme qu’auroient pu prendre nos troupes la veille de la victoire remportée {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur '''Per{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ée''' par '''Paul Emile''' ; car ce Général l’ayant produit devant les {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oldats a{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}emblés, il leur prédit une éclip{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e qui devoit arriver [[#éclipse_LPdS|<span id="éclipse_LPdS_back"><sup>'''3'''</sup></span>]] ; il compo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}a même en{{Info|ſ|forme ancienne longue de la lettre s minuscule}}uite un Ouvrage {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur ce {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ujet. Parmi les ''Grecs'', '''Thalès''' de ''Milet'' prédit l’an quatrieme de la quarante-huitieme olympiade l’éclip{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oleil qui arriva {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous le regne de '''Halyattes''' [[#Halyattes_LPdS|<span id="Halyattes_LPdS_back"><sup>'''4'''</sup></span>]], l’an cent {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oixante de la fondation de [[#cent_soixante_LPdS|<span id="cent_soixante_LPdS_back"><sup>'''5'''</sup></span>]] ''Rome''. Après eux, Hipparque [[#Hipparque_LPdS|<span id="Hipparque_LPdS_back"><sup>'''6'''</sup></span>]] dre{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}a des Tables en vers [[#En_vers_LPdS|<span id="En_vers_LPdS_back"><sup>'''7'''</sup></span>]] du cours de ces deux aftres pour fix cents ans. Dans ces Tables , de l’exactitude deſquelles notre âge rend encore témoignage [[#témoignage_LPdS|<span id="témoignage_LPdS_back"><sup>'''8'''</sup></span>]], il embra{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}e les éphémérides propres à chaque nation [[#chaque_nation_LPdS|<span id="chaque_nation_LPdS_back"><sup>'''9'''</sup></span>]], les jours, les heures, le {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ite re{{Info|ſ|forme ancienne longue de la lettre s minuscule}}pectif de chaque lieu, & les divers a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}pects du ciel relativement aux divers peuples, comme {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i la Nature l’eût admis à {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}eil intime. Per{{Info|ſ|forme ancienne longue de la lettre s minuscule}}onnages vraiment grands! génies plus qu’humains, d’avoir ain{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i {{Info|ſ|forme ancienne longue de la lettre s minuscule}}urpris les loix qui font mouvoir ces va{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tes pui{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ances du ciel ; & d’avoir guéri de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}es allarmes l’imagination malade des hommes, qui ju{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’alors, ou avoient toujours vu dans les éclip{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es l’annonce effrayante de quelque grand crime & de quelque mort (terreur dont Sté{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ikhore [[#Stésikhore_LPdS|<span id="Stésikhore_LPdS_back"><sup>'''10'''</sup></span>]] & Pindare [[#Pindare_LPdS|<span id="Pindare_LPdS_back"><sup>'''11'''</sup></span>]], ces Poètes {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ublimes, ne furent point exempts à l’égard des éclip{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es {{Info|ſ|forme ancienne longue de la lettre s minuscule}}olaires), ou attribuoient les ténebres dont {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e couvre la lune à des maléfices opérés par le mêlange de certaines herbes magiques ; & croyoient devoir la {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ecourir par un bruit di{{Info|ſ|forme ancienne longue de la lettre s minuscule}}cordant [[#bruit_discordant_LPdS|<span id="bruit_discordant_LPdS_back"><sup>'''12'''</sup></span>]]. Cette même terreur fut cau{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e que le Général Nicias [[#Nicias_LPdS|<span id="Nicias_LPdS_back"><sup>'''13'''</sup></span>]], peu au fait des cau{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es phy{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iques, & n’o{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ant pas, par {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uper{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tition, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ortir {{Info|ſ|forme ancienne longue de la lettre s minuscule}}a flotte du Port, mit Athenes à deux doigts de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}a perte. Honneur [[#Honneur_LPdS|<span id="Honneur_LPdS_back"><sup>'''14'''</sup></span>]] à vous, Interpretes du Ciel ! E{{Info|ſ|forme ancienne longue de la lettre s minuscule}}prits [[#Esprits_LPdS|<span id="Esprits_LPdS_back"><sup>'''15'''</sup></span>]] dont l’étendue {{Info|ſ|forme ancienne longue de la lettre s minuscule}}urpa{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}e celle de la Nature ; Inventeurs d’une méthode qui a{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ujettit les dieux comme les hommes, à une même de{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tinée ! Eh! qui pourroit, en voyant les a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tres même ''en cri{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e'' (pour me {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ervir de l’expre{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ion commune), ne pas {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oumettre à la néce{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ité où {{Info|ſ|forme ancienne longue de la lettre s minuscule}}a condition mortelle l’enchaîne.<br /><p style="text-align: justify; text-indent: 15px;">Pré{{Info|ſ|forme ancienne longue de la lettre s minuscule}}entement je vais toucher par articles fort courts & fort précis les points {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur le{{Info|ſ|forme ancienne longue de la lettre s minuscule}}quels on s’accorde le plus. Je ré{{Info|ſ|forme ancienne longue de la lettre s minuscule}}oudrai, chemin fai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ant, quelques que{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tions, lor{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que le cas l’exigera, mais toujours d’une maniere très {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ommaire ; car une analy{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e en forme d’arguments {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uivis excéderoit le but de cet Ouvrage : & puis, je pen{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e qu’il n’y a pas moins de mérite à rendre une rai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}on plau{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ible de toutes cho{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es, qu’à rendre une rai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}on bien {{Info|ſ|forme ancienne longue de la lettre s minuscule}}olide de deux ou trois cho{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eulement.</div> {{Boîte déroulante début|titre=Notes du traducteur|alignT=center}} <div style="text-align: justify; border: 2px; border-radius:15px; font-size:85%;"><br/> <table cellspacing=15 align=center style="margin: 0 4em;"> <tr> <td style="text-align: justify; margin: 0 4em; text-indent: 15px">'''[[#Sulpicius_Gallus_LPdS_back|<span id="Sulpicius_Gallus_LPdS"><sup>1</sup></span>]] Son premier prénom étoit Caïus. Voyez à {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ujet Tite-Live, l. 44. Valere maxime, l. 8. Quintilien, l. I. ch. 10. Plutarque, vie de Paul-Emile, &c.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Tribun_Militaire_LPdS_back|<span id="Tribun_Militaire_LPdS"><sup>2</sup></span>]] Ce grade répond à celui de Major-général des Troupes.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#éclipse_LPdS_back|<span id="éclipse_LPdS"><sup>3</sup></span>]] Cette éclip{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}elon Tite-Live, fut annoncée aux {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oldats pour la nuit {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uivante. Sulpicius Gallus leur prédit que la lune s’éclip{{Info|ſ|forme ancienne longue de la lettre s minuscule}}eroit entre la {{Info|ſ|forme ancienne longue de la lettre s minuscule}}econde heure de la nuit & la quatrieme. Plutarque ajoute qu’on étoit alors à l’i{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ue de l’été (''{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ub exitum a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tatis''). [[w:Paulin_II_d'Aquilée|Paul d’Aquilée]] écrit que cette éclip{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e arriva aux nones de Septembre (''nonas Septembris''), c’est-à-dire au 4 Septembre : c’étoit l’an 168 avant J.C. {{Info|ſ|forme ancienne longue de la lettre s minuscule}}elon le calcul d’[[w:James_Ussher|U{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}erius]].''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Halyattes_LPdS_back|<span id="Halyattes_LPdS"><sup>4</sup></span>]] Il paroît que Ciceron & Eu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ebe {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e trompent lor{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’ils placent cet événement {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous ''A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tiages'' : [[w:Hermolaos_(Macédoine)|Hermolaüs]] s’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t trompé d’après eux, en {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ub{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tituant ''A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tiages'' à ''Halyattes'' dans le texte de Pline, contre la foi des manu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}crits, & contre le témoignage d’Herodote qui place cet événement dans une guerre entre Halyattes, Roi de Sardes, & Cyaxare, Roi des Medes, pere d’A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tiages.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#cent_soixante_LPdS_back|<span id="cent_soixante_LPdS"><sup>5</sup></span>]] Les deux manu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}crits royaux portent ''anno CLX'' : c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t la leçon qu’il faut {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uivre. En effet, Rome, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}elon Varron, fut fondée l’an 2 de la {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ixieme olympiade, c’est-à-dire, dans l’année olympiadique 22. Mais comme chaque olympiade, depuis leur premiere in{{Info|ſ|forme ancienne longue de la lettre s minuscule}}titution, commençoit après le {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ol{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tice d’été, & comme l’année Romaine avoit toujours commencé au plus tard en Mars {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous Romulus, & depuis en Janvier {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous Numa, il s’en{{Info|ſ|forme ancienne longue de la lettre s minuscule}}uit que la premiere année de Rome, qui répondoit à l’année olympiadique 22, répondoit en même-tems, de quatre mois au moins, à l’année olympíadique 23. Selon ce calcul, la quatrieme année de la quarante-huitieme olympiade, répond en partie à l’an 160, & en partie à l’an 161 de la fondation de Rome, pui{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que 48 olympiades font cent quatre-vingt-douze années, de{{Info|ſ|forme ancienne longue de la lettre s minuscule}}quelles {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i vous ôtez 22 ans écoulés, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}elon Varron, entre la premiere olympiade & la fondation de Rome, il re{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tera 160 ans, & 161 ans {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i l’on a égard à l’enjambement réciproque des années olympiadiques {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur les années Romaines, & des années Romaines {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur les années olympiadiques. Il e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t donc évident que le calcul de Pline (''anno CLX'') e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t ju{{Info|ſ|forme ancienne longue de la lettre s minuscule}}te, en admettant l’hypothe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e chronologique de Varron, à laquelle on voit bien que notre Auteur s’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t conformé en cette occa{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ion particuliere encore qu’en plu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ieurs autres rencontres il paroi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}e affecter de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uivre le {{Info|ſ|forme ancienne longue de la lettre s minuscule}}y{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tême de Caton : vici{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}itude pardonnable dans un ouvrage de compilation où Pline a dû, comme malgré lui, adopter tantôt le {{Info|ſ|forme ancienne longue de la lettre s minuscule}}tyle d’un Auteur, tantôt celui d’un autre, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}elon la {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ource où il pui{{Info|ſ|forme ancienne longue de la lettre s minuscule}}oit pour l’heure. Si Pline eût {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uivi l’hypothe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e de Caton qui place la fondation de Rome deux ans plus tard que Varron, il eût fait tomber le rapport {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur l’année 157 ou 158 de la fondation de Rome. C’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t le parti que prend le Pere Hardouin, & c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t de là qu’il part pour propo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}er une correction dans le texte. Mais encore une fois, c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t commettre {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oi-même une faute que d’en trouver une chez Pline en cette occa{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ion ; pui{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que cet Auteur a été en droit de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ervir du {{Info|ſ|forme ancienne longue de la lettre s minuscule}}y{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tème Varronien, ou ce qui revient au même, de con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}erver la date Varronienne dont s’étoit {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ervi l’Auteur de qui il emprunte le fait hi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}torique en que{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tion.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Hipparque_LPdS_back|<span id="Hipparque_LPdS"><sup>6</sup></span>]] Voyez les notes {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur le premier livre au mot ''Hipparque'' : HIPPARCHUS (de Nicée, en Bithinie comme l’ob{{Info|ſ|forme ancienne longue de la lettre s minuscule}}erve [[w:Souda|Suidas]]), flori{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}oit dans la quatre-vingt-quatorzieme olympiade. Nous avons {{Info|ſ|forme ancienne longue de la lettre s minuscule}}es trois livres d’Enarrations {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur les Phénomenes d’[[w:Aratos_de_Soles|Aratus]] & d’[[w:Eudoxe_de_Cnide|Eudoxe]], traduits par le [[w:Paul_Petau|P. Petau]]. Il avoit compo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}é un autre livre ''De {{Info|ſ|forme ancienne longue de la lettre s minuscule}}tellarum inerrantium Con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}titutione'', {{Info|ſ|forme ancienne longue de la lettre s minuscule}}elon Suidas. Son livre du mois lunaire e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t cité par [[w:Claude_Galien|Galien]].''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#En_vers_LPdS_back|<span id="En_vers_LPdS"><sup>7</sup></span>]] ''En Vers.'' Je préfume que c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t-là le {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ens de ''præcinere'', qui ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ignifie pas {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eulement prédire, mais prédire en chant, c’est-à-dire en Vers. Sur ce pied-là, ce {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eroit d’un Poëme dans le genre de celui d’[[w:Aratos_de_Soles|Aratus]], dont il {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eroit ici que{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tion. Si par hazard Pline n’a point prétendu parler d’un Poëme, au-moins s’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t-il {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ervi d’une expre{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ion propre à dé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}igner ce genre d’écrire. Pour décider la que{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tion, il faudroit avoir tous les ouvrages d’Hipparque, & {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur-tout celui-ci.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#témoignage_LPdS_back|<span id="témoignage_LPdS"><sup>8</sup></span>]] Ces tables étoient dre{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ées pour {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ix cents ans. Or Hipparque flori{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}oit 150 ans avant J.C. Ain{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i du tems de Pline, on avoit encore à jouir de ces tables pour quatre cents ans ou environ.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#chaque_nation_LPdS_back|<span id="chaque_nation_LPdS"><sup>9</sup></span>]] La lune ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e levant pas & ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e couchant pas à la même heure pour toutes les nations, les diver{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es époques & pha{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es qu’elle forme n’appartiennent pas non plus au même point de tems pour tous les peuples, pui{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que les uns ont la nuit quand les autres ont le jour; & que même lor{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que la lune s’éclip{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e, la partie de l’heure où ce phénomene e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t {{Info|ſ|forme ancienne longue de la lettre s minuscule}}en{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ible, n’a pas la même évaluation pour tous les climats qui l’apperçoivent. Hipparque avoit donc eu égard à cette différence d’époques, relativement aux diver{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es longitudes, &par-con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}équent aux diver{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es nations, tellement que les tables de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}es éphémérides étoient accommodées à l’u{{Info|ſ|forme ancienne longue de la lettre s minuscule}}age de tous les peuples : ouvrage dont on ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}auroit trop regretter la perte, & qui jetteroit le plus grand jour {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur l’ancienne géographie.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Stésikhore_LPdS_back|<span id="Stésikhore_LPdS"><sup>10</sup></span>]] Ste{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ikhore, l’un des plus fameux Poètes de la Grece, dont, par malheur, nous avons perdu tous les ouvrages, à l’exception d’une vingtaine de lignes décou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ues. Il vivoit dans la quarante-deuxieme olympiade, c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t-à-dire, vers l’an {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ix cents dix avant J.C.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Pindare_LPdS_back|<span id="Pindare_LPdS"><sup>11</sup></span>]] Pindare, le plus fameux Poète de la Grece après Homere. Il vint au monde l’an 134 avant l’ere chrétienne.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#bruit_discordant_LPdS_back|<span id="bruit_discordant_LPdS"><sup>12</sup></span>]] Cet u{{Info|ſ|forme ancienne longue de la lettre s minuscule}}age {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uper{{Info|ſ|forme ancienne longue de la lettre s minuscule}}titieux a fourni un Vers fort plai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ant à Juvenal, lor{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’après avoir épui{{Info|ſ|forme ancienne longue de la lettre s minuscule}}é toute {{Info|ſ|forme ancienne longue de la lettre s minuscule}}orte d’exagération pour repré{{Info|ſ|forme ancienne longue de la lettre s minuscule}}enter le bruit qu’une femme fait en criant, il finit par dire :<br /><p style="text-align: justify; text-indent: 15px;">''Una laboranti poterit {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uccurrere luna.''<br /><p style="text-align: justify; text-indent: 15px;">Elle {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eule au be{{Info|ſ|forme ancienne longue de la lettre s minuscule}}oin décharmeroit la lune.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Nicias_LPdS_back|<span id="Nicias_LPdS"><sup>13</sup></span>]] C’étoit un Général Athénien, qui fut malheureux dans pre{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que toutes {{Info|ſ|forme ancienne longue de la lettre s minuscule}}es expéditions. Les Athéniens finirent par le condamner à mort. Il étoit contemporain d’[[w:Alcibiade|Alcibiade]] & de [[w:Lamachos|Lamachus]], & leur collegue dans le commandement. Voyez {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur le fait dont parle ici Pline, Quintilien, l. I. ch. 10, & Plutarque à l’article Nicias.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Honneur_LPdS_back|<span id="Honneur_LPdS"><sup>14</sup></span>]] Au lieu de ''macte ingenio'', le Pere Hardouin lit ''macti'' ; mais {{Info|ſ|forme ancienne longue de la lettre s minuscule}}elon les meilleurs Latini{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tes ''macte'' e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t indéclinable, ou pour mieux dire, c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t un adverbe qui répond au ''bravò'' des Italiens. Fe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tus prétend que ''macte'' e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t un compo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}é de ''magis auctus''.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Esprits_LPdS_back|<span id="Esprits_LPdS"><sup>15</sup></span>]] Cette apo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}trophe de Pline aux A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tronomes rappelle ces beaux Vers d'Ovide {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur le même {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ujet :<br />Felices animos quibus hæc cogno{{Info|ſ|forme ancienne longue de la lettre s minuscule}}cere primise<br /><p style="text-align: justify; text-indent: 15px;">Inque Domos {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uperas {{Info|ſ|forme ancienne longue de la lettre s minuscule}}candere cura fuit!<br />Credibile e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t illos pariter vitli{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que joci{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que<br /><p style="text-align: justify; text-indent: 15px;">Altius humanis ex{{Info|ſ|forme ancienne longue de la lettre s minuscule}}eruifle caput,<br />Non Venus aut Vinum {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ublimia pectora fregit<br /><p style="text-align: justify; text-indent: 15px;">Officiumve {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ori, militiæve labor :<br />Nec levis ambitio, perfu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}aque gloria fuco,<br /><p style="text-align: justify; text-indent: 15px;">Magnarumve fames {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ollicitavit opum.<br />Admovere oculis di{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tantia {{Info|ſ|forme ancienne longue de la lettre s minuscule}}idera no{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tris,<br /><p style="text-align: justify; text-indent: 15px;">Ætheraque ingenio {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uppo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}uere {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uo.<br />Sic petitur cœlum: non ut ferat O{{Info|ſ|forme ancienne longue de la lettre s minuscule}}lan Olympus<br /><p style="text-align: justify; text-indent: 15px;">Summaque Peliacus {{Info|ſ|forme ancienne longue de la lettre s minuscule}}idera tangat apex, &c.<br /><p style="text-align: right; text-indent: 15px;">Ovid. {{Info|ſ|forme ancienne longue de la lettre s minuscule}}a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t. l. I.''' </td> </tr> </table><br/><br/></div> {{Boîte déroulante fin}} <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=UnhluychtF8C&newbks=1&newbks_redir=0&dq=Histoire%20naturelle%20Pline&hl=fr&pg=PP7#v=onepage&q&f=true <u>Histoire Naturelle de Pline. Tome Premier</u>], [https://books.google.fr/books?id=UnhluychtF8C&newbks=1&newbks_redir=0&dq=Histoire%20naturelle%20Pline&hl=fr&pg=RA1-PA3#v=onepage&q&f=true ''Livre Second.''], [https://books.google.fr/books?id=UnhluychtF8C&newbks=1&newbks_redir=0&dq=Histoire%20naturelle%20Pline&hl=fr&pg=RA1-PA59#v=onepage&q&f=true ''Des inventions astronomiques, & de leurs Auteurs.''], traduction en françois, avec le texte latin rétabli d’après les meilleures leçons manu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}crites ; accompagnée de Notes critiques pour l’éclairci{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ement du texte, & d’Ob{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ervations {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur les connoi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ances des Anciens comparées avec les découvertes des Modernes, par M. [[w:Louis_Poinsinet_de_Sivry|Louis Poinsinet de Sivry]], Chez la veuve Desaint, Paris, 1771</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div> </div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ==== Livre XVIII ==== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Enquête sur l’agriculture</div> ===== <div style="text-align: center;">Chapitre LVII.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage d’une théorie astronomique de '''Thalès''', du [[w:Lever_héliaque|''coucher matinal'']] des [[w:Pléiades_(astronomie)|''Pléiades'']] 25 jours après l’[[w:Équinoxe_de_septembre|''équinoxe d’automne'']].</div> :'''Texte latin''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''LVII.''' Primum omnium dierum ipsorum anni solisque motus prope inexplicabilis ratio est. Ad CCCLXV adjiciunt etiamnum intercalarios diei noctisque quadrantes. Ita fit, ut tradi non possint certa siderum tempora. Accedit confessa rerum obscuritas, nunc præcurrenle, nec paucis diebus, tempestatum significatu, quod προϰειμασιν Græci vocant : nunc postveniente, quod ἐπιϰεἰμασιν : et plerumque alias citius, alias tardius cæli effectu ad terram deciduo : vulgo serenitate reddita, confectum sidus audimus. Præterea quum omnia hæc statis sideribus cæloque affixis constent, interveniunt motu stellarum grandines, imbres, et ipsi non levi effectu, ut docuimus, turbantque conceptæ spei ordinem. ldque ne nobis tantum putemus accidere, et reliqua fallit animalia sagaciora circa hoc, ut quo vita eorum constet : æstivasque alites præposteri aut præproperi rigores necant, hibernas æstus. Ideo '''Virgilius''' errantium quoque siderum rationem ediscendam præcipit, admonens observandum frigidæ Saturni stellæ transitum. Sunt qui certissimum veris indicium arbitrentur ob infirmitatem animalis, papilionis proventum. Id eo ipso anno, quum commentaremur hæc, notatum est, proventum eorum ter repetito frigore exstinctum, advenasque volucres a. d. VI kalendas februarii spem veris attulisse, mox sævissima hieme conflictatas. Res anceps : primum omnium a cælo peti legem : deinde eam argumentis esse quærendam. Super omnia est mundi convexitas, terrarumque globi differentia, eodem sidere alio tempore aliis aperiente se gentibus : quo fit ut causa ejus non lisdem diebus ubique valeat. Addidere difficultatem et auclores diversis in locis observando, mox etiam in iisdem diversa prodendo. Très autem fuere sectæ : ''Chaldæa'', ''Ægyptia'', ''Græca''. His addidit apud nos quartam Cæsar dictator, annos ad solis cursum redigens singulos, '''Sosigene''' perito scientiæ ejus adhibito. Et ea ipsa ratio postea comperto errore correcta est : ita ut XII annis continuis non intercalaretur, quia cœperat sidera annus morari, qui prius antecedebat. Et '''Sosigenes''' ipse trinis commentationibus, quanquam diligentior cæteris, non cessavit tamen addubitare, ipse semet corrigendo. Auctores prodidere ea, quos prætexuimus volumini huic, raro ullius sententia cum alio congruente. Minus hoc in reliquis mirum, quos diversi excusaverint tractus. Eorum qui in eadem regione dissedere, unam discordiam ponemus exempli gratia : occasum matutinum Vergiliarum '''Hesiodus''' (nam hujus quoque nomine exstat Astrologia) tradidit fieri, quum æquinoctium autumni conficeretur, '''Thales''' vigesimo quinto die ab æquinoctio, '''Anaximander''' vigesimo nono, '''Euctemon''' XLVIII. Nos sequemur observationem Cæsaris : maximeque hæc erit ''Italiæ'' ratio. Dicemus tamen et aliorum placita : quoniam non unius terræ, sed totius naturæ interpretes sumus, non auctoribus positis (id enim verbosum est), sed regionibus : legentes tantum meminerint, brevitatis gratia, quum ''Altica'' nominata fuerit, simul intelligere ''Cycladas'' insulas ; quum ''Macedonia'', ''Magnesiam'', ''Thraciam'' ; quum ''Ægyptus'', ''Phœnicen'', ''Cyprum'', ''Ciliciam'' ; quum ''Bœotia'', ''Locridem'', ''Phocidem'', et finitimos semper tractus ; quum ''Hellespontus'', ''Cherronesum'', et continentia usque ''Atho'' montem ; quum ''Ionia'', ''Asiam'', et insulas ''Asiæ'' ; quum ''Peloponnesus'', ''Achaiam'', et ad ''Hesperum'' jacentes terras. ''Chaldæi Assyriam'' et ''Babyloniam'' demonstrabunt. ''Africam'', ''Hispanias'', ''Gallias'' sileri non erit mirum. Nemo enim observavit in iis, qui siderum proderet exortus. Non tamen difficili ratione dignoscentur in illis quoque terris digestione circulorum, quam in sexto volumine fecimus : qua cognatio cæli, non gentium modo, verum urbium quoque singularum intelligitur, nota ex his terris, quas nominavimus, sumta convexitate circuli, pertinentis ad quas quisque quæret terras, et ad earum siderum exortus, per omnium circulorum pares umbras. Indicandum et illud, tempestates ipsas ardores suos habere quadrinis annis : et easdem non magna differentia reverti ratione solis : octonis vero augeri easdem, centesima revolvente se luna.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/b24875958_0001/page/n7/mode/2up <u>Histoire Naturelle de Pline.</u>], [https://archive.org/details/b24875958_0001/page/652/mode/2up ''Livre XVIII.''], [https://archive.org/details/b24875958_0001/page/684/mode/2up ''Chap. LVII.''], texte corrigé par [[w:Émile_Littré|M. É. Littré]], à partir de celui de [[w:Jean_Hardouin|Hardouin]], Librairie de Firmin-Didot et C<sup>ie</sup>, Paris, 1883<br />(également disponible une édition de 1831 [https://gallica.bnf.fr/ark:/12148/bpt6k5804072n/f339.item ici] et de 1848 [[s:Page:Pline_l'ancien_-_Histoire_naturelle,_Littré,_T1_-_1848.djvu/708|là]])</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''LVII.''' Avant tout, le calcul des jours même de l’année et du mouvement solaire est d’une difficulté presque insurmontable. Aux trois cent soixante-cinq jours on ajoute des jours intercalaires, produits de quarts de jour et de nuit ; de là vient qu’on ne peut indiquer des époques fixes pour les astres. Ajoutez une obscurité des choses avouée de tous : tantôt en effet la mauvaise saison, s’annonçant, anticipe même de plusieurs jours, ce que les Grecs appellent προϰεἰμασις (avant-hiver), et la belle saison retarde, ce qui est nommé ἐπιϰεἰμασις (arriere-hiver) : l’effet du ciel tombe sur la terre tantôt plus vite, tantôt plus tardivement ; et d’ordinaire c’est quand la sérénité est rétablie que nous entendons dire que l’action de l’astre est accomplie. En outre, car tous ces phénomènes dépendent d’astres réglés et fixés au ciel, le mouvement des étoiles amène intercurremment des grêles, des pluies qui ne sont pas non plus d’une faible action, comme nous l’avons enseigné (XVII, 2), et qui troublent l’ordre espéré. Et ne pensons pas que ces méprises n’arrivent qu’à nous; les autres animaux s’y trompent, bien que plus sagaces que nous sur ce point, vu que leur vie en dépend : l’on voit les oiseaux d’été tués par des froids hâtifs ou tardifs, et les oiseaux d’hiver par des chaleurs hâtives ou tardives. Aussi [[w:Virgile|'''Virgile''']] [[#Virgile|<span id="Virgile_back"><sup>'''I'''</sup></span>]] ([[w:Géorgiques|''Georg.'']], I, 335) recommande-t-il d’étudier encore le cours des astres errants, avertissant d’observer le passage de Saturne, planète froide. Il en est qui regardent comme l’indice le plus sûr du printemps l’apparition des papillons, à cause de la délicatesse de cet insecte. Or, l’année même où nous écrivions ceci (an 830 de ''Rome''), il a été noté que les papillons, ayant éclos, furent détruits à trois reprises par le froid, et que les oiseaux étrangers, ayant apporté l’espérance du printemps avant le 6 des calendes de février (27 janvier), eurent bientôt après à essuyer un hiver très-rigoureux. La double difficulté est d’abord d’avoir à demander au ciel la règle de toute chose, puis d’être obligé de contrôler cette règle par des faits apparents. Avant tout signalons la convexité du monde et les différences du globe terrestre, qui font que le même astre se montre à des temps divers suivant les nations, de sorte que l’influence ne s’en fait pas sentir partout aux mêmes jours. La difficulté a été encore accrue par les auteurs qui ont observé en des lieux différents, ou même qui, ayant observé dans les mêmes lieux, ont publié des résultats divergents. Il y a eu trois écoles, la ''Chaldéenne'', l’Égyptienne, la ''Grecque''. Une quatrième a été formée chez nous par le dictateur [[w:Jules_César|'''César''']], qui ramena l’année à la révolution solaire avec l’aide de [[w:Sosigène_d'Alexandrie|'''Sosigène''']] [[#Sosigène|<span id="Sosigène_back"><sup>'''II'''</sup></span>]], astronome habile. Et ce calcul même, où l’on découvrit une erreur, a été corrigé : pendant douze années consécutives on ne fit pas d’intercalation, attendu que l’année, qui auparavant anticipait, maintenant retardait sur les astres. '''Sosigène''' lui-même, quoique plus exact que les autres, n’a pas cessé, dans trois mémoires, de témoigner de ses doutes en se corrigeant lui-même. Les auteurs que nous avons indiqués au commencement de ce livre [[#auteurs_JH|<span id="auteurs_JH_back"><sup>'''1'''</sup></span>]] ont révélé ces discordances, l’avis de l’un s’accordant rarement avec l’avis de l’autre. Cela est moins étonnant dans ceux qui s’excuseront par la différence des lieux. Parmi ceux qui dans le même pays sont en désaccord, nous choisirons un exemple de dissidence : [[w:Hésiode|'''Hésiode''']] [[#Hésiode|<span id="Hésiode_back"><sup>'''III'''</sup></span>]] (car nous avons aussi sous son nom un livre sur les astres) a rapporté que le [[w:Lever_héliaque|''coucher matinal'']] des [[w:Pléiades_(astronomie)|''Pléiades'']] se faisait au moment de l’[[w:Équinoxe_de_septembre|''équinoxe d’automne'']] ; '''Thalès''', qu’il se faisait vingt-cinq jours après cet équinoxe; [[w:Anaximandre|'''Anaximandre''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Anaximandre_back|<sup>🔄</sup>]], vingt-neuf; [[w:Euctémon|'''Euctémon''']] [[#Euctémon|<span id="Euctémon_back"><sup>'''IV'''</sup></span>]], quarante-huit. Quant à nous, nous suivrons les calculs de '''César''' : ils se rapportent spécialement à l’Italie. Toutefois, nous relaterons aussi les opinions des autres ; car nous sommes les interprètes, non d’un seul pays, mais de la nature entière. Nous nommerons, non pas les auteurs, ce qui serait trop long, mais les pays. Les lecteurs auront seulement à se souvenir que, pour abréger, sous le nom d’[[w:Attique|''Attique'']] nous entendons aussi les [[w:Cyclades|''Cyclades'']]; sous celui de [[w:Macédoine_(province_romaine)|''Macédoine'']], la [[w:Magnésie_antique|''Magnésie'']] et la [[w:Thrace_(province_romaine)|''Thrace'']]; sous celui d’[[w:Égypte_romaine_et_byzantine|''Égypte'']], la [[w:Syrie-Phénicie_(province_romaine)|''Phénicie'']], [[w:Chypre_(province_romaine)|''Chypre'']] et la [[w:Cilicie|''Cilicie'']]; sous celui de [[w:Béotie#Antiquité|''Béotie'']], la [[w:Locride_(Grèce)|''Locride'']], la [[w:Phocide#Antiquité_et_période_byzantine|''Phocide'']] et les contrées limitrophes ; sous celui d’[[w:Hellespontique|''Hellespont'']], la [[w:Chersonèse_(cité_grecque)|''Chersonèse'']] et le continent jusqu’au [[w:Mont_Athos|''mont Athos'']]; sous celui d’[[w:Ionie|''Ionie'']], l’Asie et les îles ''Asiatiques'' ; sous celui de [[w:Péloponnèse#Antiquité|''Péloponnèse'']], l’[[w:Achaïe|''Achaïe'']] et les terres situées à l’occident; la [[w:Chaldée|''Chaldée'']] indiquera la [[w:Histoire_de_la_Syrie#Antiquité|''Syrie'']] et la [[w:Babylone_(civilisation)|''Babylonie'']]. On ne s’étonnera pas que je passe sous silence l’[[w:Afrique_romaine|''Afrique'']], l’[[w:Hispanie_romaine|''Espagne'']] et les [[w:Gaule|''Gaules'']], car personne dans ces contrées n’a laissé d’observations sur le lever des astres. Toutefois, il ne sera pas difficile de le calculer, même dans ces contrées, en étudiant la disposition des cercles que nous avons présentés dans le sixième livre (VI, 39). Grâce à cette étude, on connaît les relations astronomiques nou-seulement des nations, mais encore des villes en particulier : étant donnés les cercles déterminés par l’égalité des ombres, on choisit, dans les terres que nous avons nommées, le cercle qui a rapport à la localité objet du problème, et qui détermine en même temps le lever des astres pour cette localité. Il faut encore remarquer (II, 48) que tous les quatre ans les saisons ont leurs excès, et qu’elles reviennent les mêmes sans grande différence, en raison du soleil ; mais que tous les huit ans elles ont un redoublement, à la révolution de la centième lune.</div> <table cellspacing=15 align=center style="margin: 0 4em; font-size:85%;"> <tr> <td style="text-align: justify; margin: 0 4em;">'''[[#auteurs_JH_back|<span id="auteurs_JH"><sup>1</sup></span>]] Ce passage porte à croire que les auteurs dont Pline s’était servi pour composer chacun des livres de son ouvrage avaient été placés en tête du livre auquel ils se rapportaient. Les éditions mettent cette liste d’auteurs à la suite de la table de chaque livre, dans la table générale dressée par Pline lui-même.'''</td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/b24875958_0001/page/n7/mode/2up <u>Histoire Naturelle de Pline.</u>], [https://archive.org/details/b24875958_0001/page/652/mode/2up ''Livre XVIII.''], [https://archive.org/details/b24875958_0001/page/684/mode/2up ''Chap. LVII.''], texte corrigé par [[w:Émile_Littré|M. É. Littré]], à partir de celui de [[w:Jean_Hardouin|Hardouin]] [https://archive.org/details/b24875958_0001/page/708/mode/2up <sup>NOTES</sup>], Librairie de Firmin-Didot et C<sup>ie</sup>, Paris, 1883<br />(également disponible une édition 1848 [[s:Page:Pline_l'ancien_-_Histoire_naturelle,_Littré,_T1_-_1848.djvu/708|ici]])</div> {{Boîte déroulante début|titre=NdA de trad. Jean Hardouin 1883|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Virgile_back|<span id="Virgile"><sup>I</sup></span>]] [[w:Nom_romain|Tria Nomina]] en latin {{Info|Publius|praenomen, nom individuel du citoyen romain}} {{Info|Vergilius|nomen, nom de famille}} {{Info|Maro|cognomen, surnom héréditaire, servant à distinguer les diverses branches d’une même gens}};<br /><p style="margin: 0 2em; text-indent: 15px">Poète latin renommé dans les styles [[w:Épopée|''épique'']] (l’[[w:Énéide|''Énéide'']]), [[w:Poésie_pastorale|''pastorale'']] (les [[w:Bucoliques|''Bucoliques'']]) et [[w:Poésie_didactique|''didactique'']] (les [[w:Géorgiques|''Géorgiques'']]).<br /><p style="text-align: right; margin: 0 2em;">(15 octobre [[w:Années_70_av._J.-C.|-70]], [[w:Virgilio_(Lombardie)#Histoire|''Andes'']], au sud-est de l’actuelle [[w:Lombardie#Histoire|''Lombardie'']], au nord de l’Italie — 21 septembre [[w:Années_19_av._J.-C.|-19]], [[w:Brindisi#Histoire|''Brundisium'']], au sud-est des actuelles [[w:Pouilles#Domination_romaine|''Pouilles'']], au sud-est de l’Italie)<sup>[[w:Ier_siècle_av._J.-C.|⏳]]</sup> <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Sosigène_back|<span id="Sosigène"><sup>II</sup></span>]] Du nom propre grec ancien Σωσῐγένης / Sōsigénēs [[wikt:en:Σωσιγένης#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;">➥ du verbe σῴζω / sṓizō, « 1. Sauver : • Guérir ; • (rare chez Homère) Garder en sécurité, préserver ; • Garder, observer, maintenir ; • (généralement au milieu) Garder à l’esprit, se souvenir ; • Conduire en toute sécurité (à) ; • Secourir ; • Conserver pour. »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ + du nom commun‎ γένος / génos [[wikt:en:γένος#Ancient_Greek|(en)]], « 1. Race, souche, parenté : Descendance directe, par opposition à une relation collatérale. 2. Progéniture, descendant : (collectif) progéniture, postérité. 3. (en général) Race d’êtres : • Famille, clan, maison ; • Tribu, nation, race, en tant que subdivision de ἔθνος / éthnos [[wikt:en:ἔθνος#Ancient_Greek|(en)]] ; • Caste ; • Race d’animaux. 4. Âge, génération, période de la vie. 5. Sexe, genre : (grammaire) Genre grammatical. 6. Classe, sorte, genre : • (logique) L’opposé de εἶδος / eîdos [[wikt:en:εἶδος#Ancient_Greek|(en)]] ; • (taxonomie) Classe : • (taxonomie) Genre ; • Espèce de plante ; culture, produit ; matériau ; • Élément. »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ +‎ du suffixe nominal propre -ης / -ēs [[wikt:en:-ης#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;"> Astronome grec, connu pour avoir participer à la conception du [[w:Calendrier_julien|''calendrier julien'']] (instauré par Jules César en [[w:Années_46_av._J.-C.|-46]]/[[w:Années_45_av._J.-C.|-45]], lorsqu’il était [[w:Pontifex_maximus|''pontifex maximus'']]), avec une année commune de 365 jours divisée en 12 mois, et un jour intercalaire ajouté tous les 4 ans, lors des années bissextiles.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:Ier_siècle_av._J.-C.|I<sup>er</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]]) <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Hésiode_back|<span id="Hésiode"><sup>III</sup></span>]] Du nom propre grec ancien Ἡσῐ́οδος / Hēsíodos;<br /><p style="margin: 0 2em; text-indent: 15px">Poète ''grec'', renommé pour 2 ouvrages :<br /><p style="margin: 0 2em; text-indent: 15px;">• [[w:Théogonie_(Hésiode)|''la Théogonie'']], une généalogie des dieux (dans laquelle il présente la multitude des dieux célébrés par les mythes grecs où trois générations divines se succèdent : celle d’Ouranos, celle de Cronos, celle de Zeus qui sort triomphant) et une cosmogonie (qui retrace la création du monde à partir du Chaos) ;<br /><p style="margin: 0 2em; text-indent: 15px;">• et [[w:Les_Travaux_et_les_Jours|''les Travaux et les Jours'']], un almanac sur l’agriculture à destination de son frère Perses.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:VIIIe_siècle_av._J.-C.|VIII<sup>ème</sup>]] — [[w:VIIe_siècle_av._J.-C.|VII<sup>ème</sup>]] siècles {{Info|AEC|Avant l’Ère Commune}}) <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Euctémon_back|<span id="Euctémon"><sup>IV</sup></span>]] Du nom propre grec ancien Ευκτήμων / Euktémōn;<br /><p style="margin: 0 2em; text-indent: 15px;">Astronome ''athénien'', contemporain et collègue de l’astronome [[w:Méton|Méton]], avec qui, il a fait une série d’observations des [[w:Solstice|''solstices'']] afin de déterminer la durée de l’[[w:Année_tropique|''année tropique'']] [https://ecliptiqc.ca/Almageste_Livre3.php#III1 <sup>Ptolémée, Almageste, liv. III, chap. 1</sup>].<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:Ve_siècle_av._J.-C.|V<sup>ème</sup>]] siècle {{Info|AEC|Avant l’Ère Commune}})'''<br/><br/></div> {{Boîte déroulante fin}} <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: center; margin: 0 2em;">Des découvertes astronomiques : part de chaque observateur dans la science.<br /><p style="text-align: justify; text-indent: 15px;">'''LVII.''' D’abord, il est presque impossible de déterminer d’une manière précise le nombre des jours de l’année et le cours du soleil [[#Primum_omnium_dierum_AdG|<span id="Primum_omnium_dierum_AdG_back"><sup>'''1'''</sup></span>]]. Aux trois cent soixante-cinq jours qui composent l’année, on ajoute le quart d’un jour et d’une nuit, pour en faire ensuite un jour intercalaire ; de là il suit qu’on ne saurait indiquer avec précision le moment du lever et du coucher des astres. On convient qu’il y a encore dans cette théorie beaucoup d’obscurité ; en effet, les saisons quelquefois commencent plusieurs jours avant le terme qui leur a été fixé, ce que les ''Grecs'' appellent ''procheimasis'' ; d’autres fois, plusieurs jours après, ce qu’ils appellent ''épicheimasis'' [[#Accedit_confessa_rerum_obscuritas_AdG|<span id="Accedit_confessa_rerum_obscuritas_AdG_back"><sup>'''2'''</sup></span>]]. Presque toujours l’action des astres se fait sentir sur la terre ou plus tôt ou plus tard qu’il ne devrait ; aussi dit-on communément, lorsque le beau temps est revenu, que tel astre a produit son effet. Ces phénomènes dépendent des astres fixés à la voûte des cieux, ainsi que des étoiles, dont les mouvemens particuliers excitent des grêles et des pluies qui sont d’une très-grande conséquence pour les biens de la terre, comme nous l’avons observé, et amènent dans la température des changemens sur lesquels le laboureur ne pouvait compter. Non-seulement les hommes y sont trompés, mais aussi les animaux, bien plus habiles que nous à prévoir ces vicissitudes, puisque d’ailleurs leur vie en dépend ; en effet, on a vu des oiseaux d’été périr par des froids arrivés trop tôt ou trop tard, et des oiseaux d’hiver par des chaleurs également imprévues. Aussi '''Virgile''' veut-il qu’on étudie aussi le cours des ''planètes'', et qu’on observe avec soin le passage du froid ''Saturne'' [[#Ideo_Virgilius_errantium_quoque_siderum_rationem_ediscendam_prœcipit_AdG|<span id="Ideo_Virgilius_errantium_quoque_siderum_rationem_ediscendam_prœcipit_AdG_back"><sup>'''3'''</sup></span>]].<br /><p style="text-align: justify; text-indent: 15px;">Quelques-uns fixent le commencement du printemps à l’apparition des papillons, parce que ces insectes sont fort délicats. Néanmoins on a observé, dans l’année même où j’écris cette partie de mon ouvrage, que le froid, ayant repris trois fois, a fait périr autant de fois les papillons, et que les hirondelles qui, s’étaient montrées dès le 6 des [[w:Calendes|''kalendes'']] de février, et semblaient annoncer le retour du printemps, ont eu à essuyer un rigoureux hiver.<br /><p style="text-align: justify; text-indent: 15px;">C’est donc une science très-problématique que celle de l’influence des astres, et les inductions qu’elle fournit sont fort douteuses [[#Res_anceps_AdG|<span id="Res_anceps_AdG_back"><sup>'''4'''</sup></span>]]. Ce qui augmente la difficulté, c’est la convexité du ciel et la différence des climats de la terre : le même astre se montre ici dans un temps, et là dans un autre ; d’où il suit que son influence ne se fait pas sentir en même temps partout. Pour surcroît d’embarras, les observations recueillies par les auteurs ont été faites dans des lieux différens, et ceux du même pays ne s’accordent pas même entre eux. On compte trois écoles astronomiques, la ''chaldéenne'', l’égyptienne et la ''grecque''. Le dictateur '''César''' en a fondé, chez les ''Romains'', une quatrième, lorsqu’aidé de '''Sosigène''', habile astronome, il fixa la longueur de l’année à une révolution du soleil. On trouva dans la suite que son calendrier était défectueux, parce que l’année, auparavant plus courte, se trouvait alors plus longue que le cours du soleil. Pour y remédier, il fallut, pour douze années consécutives, supprimer les jours intercalaires. '''Sosigène''' lui-même, le mathématicien le plus exact de son temps, après avoir revu jusqu’à trois fois ses calculs, sembla toujours douter de leur justesse, et ne cessa jamais de se corriger lui-même. De tous les auteurs qui ont traité ce sujet, et que nous avons cités au commencement de ce livre, il en est rarement deux qui soient de même avis. Cette divergence d’opinions est moins surprenante et plus excusable chez ceux qui écrivaient en des pays différens. Mais que dire de ceux qui, habitant le même pays, sont néanmoins d’avis différens ? En voici un exemple : '''Hésiode''', qui nous a laissé aussi un ouvrage sur le cours des astres, fixe le coucher matutinal des ''Pléiades'' au moment de l’équinoxe d’automne ; '''Thales''' prétend qu’il n’arrive que vingt-cinq jours après ; '''Anaximandre''' en met vingt-neuf ; '''Euctémon''', quarante-huit.<br /><p style="text-align: justify; text-indent: 15px;">Quant à nous, nous suivrons les calculs de '''César''', qui se rapportent spécialement à l’Italie ; mais nous rapporterons aussi les observations étrangères, car notre plan n’est pas de traiter d’un seul pays, mais de la nature entière. Pour être moins longs, nous citerons les pays, et non les auteurs ; et, pour abréger davantage encore, les lecteurs se souviendront que, sous le nom d’Attique, il faut aussi entendre les ''Cyclades'' ; sous le nom de ''Macédoine'', la ''Magnésie'' et la ''Thrace'' ; sous le nom d’Égypte , la ''Phénicie'', l’île de ''Cypre'' et la ''Cilicie'' ; sous celui de ''Béotie'', la ''Locride'', la ''Phocide'' et les contrées voisines ; sous le nom d’Hellespont, la ''Chersonèse'' et partie du continent jusqu’au mont ''Athos'' ; sous le nom de l’Ionie, l’Asie et les îles ''Asiatiques'' ; sous le nom du ''Péloponnèse'', l’Achaïe et les pays adjacens au couchant ; enfin sous le nom de ''Chaldée'', l’Assyrie et la ''Babylonie''. On ne sera pas étonné que nous ne parlions ni de l’Afrique, ni de l’Espagne, ni des ''Gaules''. Aucun auteur dans ces contrées n’a laissé d’observations sur le lever ou le coucher des astres. Il ne sera pas difficile néanmoins de déterminer l’époque de ces phénomènes dans ces contrées, en étudiant la disposition des cercles, telle que nous l’avons présentée dans le sixième livre. Par ce moyen, on déterminera la position astronomique, non-seulement de chaque pays, mais encore de chaque ville dont nous avons pu parler, en prenant par les ombres égales de tous les cercles, une portion du cercle de telle contrée qu’on voudra choisir, et en calculant son rapport avec le lever des astres. Il faut faire observer encore que tous les quatre ans les chaleurs reviennent à peu près les mêmes pour chaque saison, en raison du mouvement du soleil, et que toutes les huitièmes années elles sont plus fortes, à cause de la centième lunaison.</div> <table cellspacing=15 align=center style="margin: 0 4em; font-size:85%;"> <tr> <td style="text-align: justify; margin: 0 4em;">'''[[#Primum_omnium_dierum_AdG_back|<span id="Primum_omnium_dierum_AdG"><sup>1</sup></span>]] Cf. sur la plupart des difficultés que le texte de notre auteur révèle, les notes relatives à l’astronomie, au livre II. L’année romaine fut d’abord celle des [[w:Albe_la_Longue|''Albains'']], c’est-à-dire lunaire ; dix mois la composaient, mars en était le premier : elle avait cinquante jours de moins que l’année lunaire réelle, et soixante-un de moins que l’année solaire, c’est-à-dire trois cent quatre jours seulement ; c’était là l’[[w:Calendrier_romain|{{Info|''année de Romulus''|le calendrier dit romuléen}}]]. [[w:Calendrier_romain|{{Info|''Numa''|le calendrier dit pompilien}}]] ajouta deux mois à cette année, janvier et février, et elle se trouva être composée de trois cent cinquante-cinq jours. Elle demeura ainsi jusqu’à Jules César, où commence l’[[w:Calendrier_julien|''année julienne'']], qui se compose de trois cent soixante-cinq jours, huit heures, auxquels [[w:Calendrier_grégorien|''Grégoire le Grand'']] ajouta onze minutes, pour arriver à la plus grande exactitude possible.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Accedit_confessa_rerum_obscuritas_AdG_back|<span id="Accedit_confessa_rerum_obscuritas_AdG"><sup>2</sup></span>]] L’entrée du soleil dans tel ou tel signe du zodiaque, son passage à l’équateur, etc., ne sont pas toujours le signal d’un changement dans la température. [[w:Végèce|Végèce]] a parlé des jours prokéimasiques et épikéiniasiques :''' {{Info|''Aut enim circa diem statutum, aut ante, vel postea, tempestates fieri, compertum est : unde præcedentes, ωροϰεἰμασιν : nascentes die solenni, επιϰεἰμασιν : subsequentes, μεταϰεἰμασιν, græco vocabulo nuncuperaverunt''|Car on a constaté que les tempêtes se produisent soit vers le jour fixé, soit avant, soit après : d’où les précédents, ωροϰεἰμασιν : nés le jour solennel, επιϰεἰμασιν : les suivants, μεταϰεἰμασιν, étaient appelés par le mot grec. TdA.}} '''(IV, 40).''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Ideo_Virgilius_errantium_quoque_siderum_rationem_ediscendam_prœcipit_AdG_back|<span id="Ideo_Virgilius_errantium_quoque_siderum_rationem_ediscendam_prœcipit_AdG"><sup>3</sup></span>]] <p style="margin: 0 6em; text-indent: 0px">'''{{Info|Hoc metuens, cæli menses et sidera serva,<br />Frigida Saturni sese quo stella receptet.|Craignant cela, gardez les lunes et les étoiles du ciel, le froid de Saturne lui-même, où l’étoile les recevra. TdA.}}'''<p style="text-align: right; margin: 0 6em; text-indent: 0px">''Georg.'', I, 335.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Res_anceps_AdG_back|<span id="Res_anceps_AdG"><sup>4</sup></span>]] Voici enfin quelques idées philosophiques qui se trouvent sous la plume de Pline ; malheureusement la cause par laquelle notre auteur explique l’influence des astres est problématique, et montre que les sciences astronomiques des anciens laissaient beaucoup à désirer. Les Grecs croyaient qu’il y avait autant de cieux que de planètes ; le huitième ciel, ou le firmament, était celui dès étoiles fixés.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Occasum_matutinum_Vergiliarum_Hesiodus_AdG_back|<span id="Occasum_matutinum_Vergiliarum_Hesiodus_AdG"><sup>5</sup></span>]] L’ouvrage auquel Pline fait allusion a été mentionné par [[w:Théon_d'Alexandrie|Théon]] qui le nomme Αστριϰὴ βίϐλος [[w:en:Astronomia_(poem)|(en)]]. Cet ouvrage est perdu.'''</td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k5804072n <u>Histoire Naturelle de Pline. Tome Onzième</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k5804072n/f196.item ''Livre XVIII.''], [https://gallica.bnf.fr/ark:/12148/bpt6k5804072n/f340.item ''chap. LVII.''], traduction nouvelle par M. [[w:Stéphane_Ajasson_de_Grandsagne|Ajasson de Grandsagne]] [https://gallica.bnf.fr/ark:/12148/bpt6k5804072n/f453.item <sup>NOTES</sup>], C. L. F. Panckoucke, Paris, 1829</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: center; margin: 0 2em;">''Divi[[w:S_long|{{Info|ſ|forme ancienne longue de la lettre s minuscule}}]]<nowiki />ion des jours & des nuits [[w:S_long|{{Info|ſ|forme ancienne longue de la lettre s minuscule}}]]<nowiki />uivant le cours du Soleil ; lever & coucher des étoiles ; ordre des [[w:S_long|{{Info|ſ|forme ancienne longue de la lettre s minuscule}}]]<nowiki />ai[[w:S_long|{{Info|ſ|forme ancienne longue de la lettre s minuscule}}]]<nowiki />ons ; tems où l’on [[w:S_long|{{Info|ſ|forme ancienne longue de la lettre s minuscule}}]]<nowiki />eme les bleds d’hiver.''<br /><p style="text-align: justify; text-indent: 15px;">'''D'''’ABORD il e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t pre{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que impo{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ible de déterminer au ju{{Info|ſ|forme ancienne longue de la lettre s minuscule}}te le nombre des jours de l’année, & le cours du Soleil ; car comme aux trois cents {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oixante & cinq jours dont l’année e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t compo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ée, on ajoute le quart d’un jour & d’une nuit, autrement {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ix heures, qui, au bout de quatre ans, font un jour intercalaire [[#jour_intercalaire_LPdS|<span id="jour_intercalaire_LPdS_back"><sup>'''1'''</sup></span>]], il arrive qu’on ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}auroit a{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}igner avec certitude le tems du lever & du coucher des a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tres. En {{Info|ſ|forme ancienne longue de la lettre s minuscule}}econd lieu, l’on convient qu’il y a dans cette théorie beaucoup d’ob{{Info|ſ|forme ancienne longue de la lettre s minuscule}}curité ; car quelquefois les {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ons [[#quelques_les_saisons_LPdS|<span id="quelques_les_saisons_LPdS_back"><sup>'''2'''</sup></span>]] commencent plu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ieurs jours avant le terme qui leur a été fixé, ce que les Grecs appellent ''prokheïma{{Info|ſ|forme ancienne longue de la lettre s minuscule}}is'' ; & d’autres fois plu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ieurs jours après, ce que ces mêmes Grecs expriment par le mot ''epikheïma{{Info|ſ|forme ancienne longue de la lettre s minuscule}}is'' : & l’on éprouve très {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ouvent que l’action des a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tres {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ait {{Info|ſ|forme ancienne longue de la lettre s minuscule}}entir {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur la terre, tantôt plutôt, tantôt plus tard. Au{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}i dit-on communément, lor{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que le beau tems e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t revenu, que tel a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tre a produit {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on effet. D’ailleurs comme tout cela dépend des globes céle{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tes, leur mouvement relatif excite quelquefois des grêles & des pluies, qui, comme nous l’avons déja [[#déjà_fait_observer_LPdS|<span id="déjà_fait_observer_LPdS_back"><sup>'''3'''</sup></span>]] fait ob{{Info|ſ|forme ancienne longue de la lettre s minuscule}}erver, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont de la plus grande con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}équence pour les biens de la terre, & qui renver{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ent l’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}pérance qu’on avoit du beau tems. Et non {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eulement les hommes y {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont trompés, mais au{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}i les animaux, quoiqu’ils aient bien plus de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}agacité que nous pour pre{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}entir ces vici{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}itudes du ciel, d’autant que leur vie en dépend. En effet, on voit quelquefois les oi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}eaux d’été mourir par des froids qui viennent trop tard ou trop tôt, & les oi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}eaux d’hiver par des chaleurs qui arrivent de même. C’est pourquoi '''Virgile''' veut qu’on étudie au{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}i le cours des planetes, & qu’on ob{{Info|ſ|forme ancienne longue de la lettre s minuscule}}erve à quelle partie du zodiaque répond la planete du froid Saturne [[#Saturne_LPdS|<span id="Saturne_LPdS_back"><sup>'''4'''</sup></span>]]. Quelques-uns croient que le {{Info|ſ|forme ancienne longue de la lettre s minuscule}}igne le plus certain du printems commencé, c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t lor{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’on voit des papillons, & cela parceque ces in{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ectes {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont fort délicats. Néanmoins on a remarqué que dans l’année même [[#lAnnée_dÉcriture_LPdS|<span id="lAnnée_dÉcriture_LPdS_back"><sup>'''5'''</sup></span>]] où j’écris ceci, le froid ayant recommencé ju{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’à trois fois, a fait mourir autant de fois les papillons ; & que les hirondelles, qui, s’étant montrées dès le vingt-{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ept de Janvier, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}embloient annoncer le retour du printems, ont en{{Info|ſ|forme ancienne longue de la lettre s minuscule}}uite e{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}uyé un très cruel hiver.<br /><p style="text-align: justify; text-indent: 15px;">C’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t donc une {{Info|ſ|forme ancienne longue de la lettre s minuscule}}cience très problématique que celle de l’influence des a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tres, & les inductions que l’on en tire {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont fort douteuses. Mais ce qui cau{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e le plus d’incertitude, c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t cette convexité du ciel & la différence des climats de la terre, parceque le même a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tre {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e montre ici dans un tems, & là dans un autre, d’où il ré{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ulte que {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on influence ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e fait pas {{Info|ſ|forme ancienne longue de la lettre s minuscule}}entir en même tems par-tout. Un autre {{Info|ſ|forme ancienne longue de la lettre s minuscule}}urcroît de difficulté, c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t que les ob{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ervations recueillies par les Auteurs ont été faites en différents lieux, & que ceux même qui ont écrit dans le même endroit ne s’accordent nullement entre eux dans ce qu’ils écrivent. On compte ju{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’à trois différentes {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ortes de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ectes en A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tronomie ; {{Info|ſ|forme ancienne longue de la lettre s minuscule}}avoir, celle des Chaldéens [[#secte_des_Chaldéens_LPdS|<span id="secte_des_Chaldéens_LPdS_back"><sup>'''5*'''</sup></span>]], celle des Egyptiens & celle des Grecs. On peut même dire que le Dictateur Cé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ar [[#Dictateur_César_LPdS|<span id="Dictateur_César_LPdS_back"><sup>'''6'''</sup></span>]] en produi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}it, chez les Romains, une quatrieme, lor{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’il rédui{{Info|ſ|forme ancienne longue de la lettre s minuscule}}it chaque année au cours du {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oleil, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ervant à cet effet du travail de So{{Info|ſ|forme ancienne longue de la lettre s minuscule}}igene, très habile A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tronome. Néanmoins on découvrit en{{Info|ſ|forme ancienne longue de la lettre s minuscule}}uite que le calendrier de Cé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ar étoit défectueux [[#calendrier_César_défectueux_LPdS|<span id="calendrier_César_défectueux_LPdS_back"><sup>'''7'''</sup></span>]], parceque l’année qui auparavant étoit plus courte que le cours du {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oleil, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e trouvoit alors plus longue : & pour corriger cette erreur, on ordonna que pendant douze années de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uite, il n’y auroit point de jour intercalaire [[#correction_erreur_LPdS|<span id="correction_erreur_LPdS_back"><sup>'''8'''</sup></span>]]. So{{Info|ſ|forme ancienne longue de la lettre s minuscule}}igene lui-même, quoique Mathématicien plus exact que les autres, ne lai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}a pas de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e conduire con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tamment en homme qui doutoit de la ju{{Info|ſ|forme ancienne longue de la lettre s minuscule}}te{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}e de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on propre calcul, pui{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’il en fit ju{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’à trois différentes corrections. De tous les Auteurs [[#Auteurs_calendrier_LPdS|<span id="Auteurs_calendrier_LPdS_back"><sup>'''9'''</sup></span>]] qui ont écrit {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur cette matiere, & que nous avons allégués au commencement de ce livre, il s’en trouve rarement deux qui {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oient de même {{Info|ſ|forme ancienne longue de la lettre s minuscule}}entiment. Cette variété e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t moins {{Info|ſ|forme ancienne longue de la lettre s minuscule}}urprenante, comme au{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}i plus excu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}able, chez ceux qui écrivoient en des pays différents. Mais que dire de ceux qui, écrivant dans le même pays, n’ont pas lai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}é d’être partagés d’opinion ? En voici un exemple. '''Hé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iode''', dont il y a au{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}i un ouvrage [[#ouvrage_astronomique_Hésiode_LPdS|<span id="ouvrage_astronomique_Hésiode_LPdS_back"><sup>'''10'''</sup></span>]] {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur le cours des a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tres, dit que les Pléiades {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e couchent le matin dans le tems même de l’équinoxe d’automne. '''Thalès''' [[#opinion_Thalès_Hésiode_Anaximandre_LPdS|<span id="opinion_Thalès_Hésiode_Anaximandre_LPdS_back"><sup>'''11'''</sup></span>]] dit que cela arrive vingt-cinq jours après. '''Anaximandre''' en met vingt-neuf ; '''Euctémon''' [[#Euctémon_LPdS|<span id="Euctémon_LPdS_back"><sup>'''12'''</sup></span>]] quarante-huit.<br /><p style="text-align: justify; text-indent: 15px;">Quant à nous, nous {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uivrons le calcul de Cé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ar, ayant principalement égard à l’Italie. Nous ne lai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}erons néanmoins de rapporter les opinions étrangeres, parceque notre objet n’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t pas de traiter d’un {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eul pays, mais de la Nature entiere. Seulement, pour éviter les longueurs, nous n’indiquerons que les pays où chaque opinion a lieu, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ans faire mention des auteurs de ces a{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ertions : & pour abréger encore davantage, les Lecteurs voudront bien {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ouvenir que quand il e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t parlé de l’Attique, il faut, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous ce nom, entendre au{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}i les Cyclades ; que {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous le nom de Macédoine, il faut entendre au{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}i la Magné{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ie & la Thrace ; {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous le nom de l’Egypte, la Phénicie, l’i{{Info|ſ|forme ancienne longue de la lettre s minuscule}}le de Chypre & la Cilicie; {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous celui de la Béotie, la Locride, la Phocide & les contrées voi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ines ; {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous le nom de l’Hel le{{Info|ſ|forme ancienne longue de la lettre s minuscule}}pont, la pre{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’i{{Info|ſ|forme ancienne longue de la lettre s minuscule}}le de Thrace & le pays de terre ferme, ju{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’au mont Athos ; {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous le nom de l’Ionie, l’A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ie & les i{{Info|ſ|forme ancienne longue de la lettre s minuscule}}les A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iatiques ; {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous le nom du Péloponne{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e, l’Achaïe & les contrées [[#contrées_adjacentes_ouest_Péloponnese_LPdS|<span id="contrées_adjacentes_ouest_Péloponnese_LPdS_back"><sup>'''13'''</sup></span>]] adjacentes qu’elle a à {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on couchant ; {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous le nom des Chaldéens, l’Assyrie & la Babylonie. Il ne faudra pas s’étonner {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i je ne parle ici ni de l’Afrique, ni de l’Espagne, ni des Gaules, pui{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que ces pays n’ont eu aucun Auteur qui ait écrit du cours des a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tres, ni de leur lever. Toutefois il ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}era pas difficile de connoître le tems où ils {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e levent dans ces pays-là même, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i l’on e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t in{{Info|ſ|forme ancienne longue de la lettre s minuscule}}truit de l’arrangement des cercles céle{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tes, tel que nous l’avons expliqué au {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ixieme livre de cet ouvrage ; car, par ce moyen, & par les {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eules notions que nous avons expo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ées en donnant une nomenclature des lieux, on {{Info|ſ|forme ancienne longue de la lettre s minuscule}}aura la po{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ition, non {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eulement de chaque pays, mais encore de chaque ville, en prenant par les ombres égales de tous les cercles, un {{Info|ſ|forme ancienne longue de la lettre s minuscule}}egment du cercle de tel pays qu’on voudra choi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ir, & en cherchant {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on rapport avec le lever des a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tres. Il faut remarquer au{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}i que de quatre [[#Columelle_LPdS|<span id="Columelle_LPdS_back"><sup>'''14'''</sup></span>]] en quatre ans les {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ons & les chaleurs reviennent à peu près les mêmes, & cela à cau{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e du mouvement du Soleil ; & que de huit en huit ans ces mêmes chaleurs reviennent plus con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}idérables, en vertu de la centieme lunai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}on.</div> {{Boîte déroulante début|titre=Notes du traducteur|alignT=center}} <div style="text-align: justify; border: 2px; border-radius:15px; font-size:85%;"><br/> <table cellspacing=15 align=center style="margin: 0 4em;"> <tr> <td style="text-align: justify; margin: 0 4em; text-indent: 15px">'''[[#jour_intercalaire_LPdS_back|<span id="jour_intercalaire_LPdS"><sup>1</sup></span>]] Con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ultez, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur toute cette que{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tion, nos notes 13 & 14 {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur le huitieme chapitre du {{Info|ſ|forme ancienne longue de la lettre s minuscule}}econd livre de Pline, tome 1, p. 41 & 42 :<br /><p style="text-align: justify; text-indent: 15px; margin: 0 5em;">(13) [[w:Suétone|Suétone]] s’exprime mieux, lor{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’il écrit : chaque quatrieme année ''quarto quoque anno''. Il est vrai que, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}elon le [[w:Jean_Hardouin|Pere Hardouin]], il faut comprendre dans la période de cinq ans, dont parle Pline, la premiere & la cinquieme année comme Bi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}extiles ; ce qui revient aux quatre années de Suétone, dont la quatrieme avoit un ''bi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ex'' ; mais en vérité cette explication est des plus forcées. Je {{Info|ſ|forme ancienne longue de la lettre s minuscule}}erois donc d’avis qu’il faudroit lire dans Pline comme dans Suétone, ''quarto anno'', {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i nous n’apprenions d’ailleurs de cet Hi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}torien, que dès le regne d’Augu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}te il s’étoit déja gli{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}é plu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ieurs abus & altérations dans l’année Julienne. On voit du moins qu’il y réforma plu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ieurs cho{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es, sous prétexte de la remettre {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur le pied où Cé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ar l’avoit in{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tituée. Cela me donneroit à pen{{Info|ſ|forme ancienne longue de la lettre s minuscule}}er qu’on fit dès-lors attention à la fau{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}eté & à l’excédence du calcul Julien ; mais qu’Augu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}te, par respect pour la mémoire de Cé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ar, affecta d’imputer la faute à la négligence des Prêtres chargés à Rome de l’in{{Info|ſ|forme ancienne longue de la lettre s minuscule}}pection du Calendrier ; qu’au demeurant, on découvrit l’abus, & qu’on e{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}aya d’y remédier, en n’ajoûtant un jour entier à l’année ordinaire que chaque ''cinquieme année'' comme Pline paroît l’articuler ici expre{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ement. Mais d’ailleurs il e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t évident qu’à la longue le période bi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}extile de quatre années en quatre années prévalut {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur celui de chaque cinquieme année, dont parle Pline ; & même il paroît que ceux qui, par la {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uite, voulurent {{Info|ſ|forme ancienne longue de la lettre s minuscule}}upputer les tems, récapitulerent, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ans exception, toutes les bi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}extiles quartenaires écoulées depuis l’in{{Info|ſ|forme ancienne longue de la lettre s minuscule}}titution Julienne ; car en 1582, on trouva par ce moyen que l’année étoit reculée de dix jours & plus; d’autant que l’excédence du calcul Julien, qui {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uppo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e à l’année révolue 365 jours & {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ix heures, au lieu de 365 jours 5 heures 49 minutes, 8 {{Info|ſ|forme ancienne longue de la lettre s minuscule}}econdes 17 tierces & 13 quarts qu’elle a réellement, forme tous les ans environ 11 minutes de trop, & tous les cent trente-quatre ans un jour entier d’excès. Le Pape Grégoire XIII trouvant donc l’année reculée de plus de dix jours ; ce qui dérangeoit l’économie annuelle des {{Info|ſ|forme ancienne longue de la lettre s minuscule}}olemnités, remédia à cet inconvénient en retranchant de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on autorité dix jours au mois d’Octobre de l’année 1582, où l’on étoit alors ; & en réglant qu’à l’avenir tous les quatre cents ans on omettroit trois années bi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}extiles. Ce réglement devint une loi pour pre{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que toute l’Europe chrétienne. L’autre maniere de compter fut appellée l’ancien {{Info|ſ|forme ancienne longue de la lettre s minuscule}}tyle. La Grande-Bretagne a long-tems per{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i{{Info|ſ|forme ancienne longue de la lettre s minuscule}}té à s’en {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ervir malgré {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on abus manife{{Info|ſ|forme ancienne longue de la lettre s minuscule}}te. Enfin le Parlement d’Angleterre, par acte du mois de Septembre 1752, a adopté la réforme Grégorienne.<br /><p style="text-align: justify; text-indent: 15px; margin: 0 4em;">(14) Le {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oleil, en fai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ant le tour du cercle oblique, parcourt réellement 360 degrés ou {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ections ; pui{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que tout cercle {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e divi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e en 360 parties appellées degrés : mais la me{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ure de chaque degré du cercle parcouru annuellement par le {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oleil, excede tant {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oit peu, c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t-à-dire de quelques légeres fractions de tems, la durée de chacun de nos jours révolus ; durée qui n’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t, comme on {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ait, que de 24 heures préci{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es ; le{{Info|ſ|forme ancienne longue de la lettre s minuscule}}quelles, comparées à un degré, en produi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ent, au bout de l’année, 365 & plus pour le cercle, au lieu de 360 {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eulement que le cercle requerroit. D’après une connoi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ance con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}u{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e de ces principes, Jules Cé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ar {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e voyant Dictateur, Grand-Pontife, & maître du monde, entreprit, l’an 140 avant J. C. de réformer les abus qui s’étoient gli{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}és, tant dans l’année Pompilienne, ou de Numa, que dans celle des Pontifes, encore plus irréguliere que celle de Numa. A cet effet, il fit venir d’Alexandrie le Philo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ophe So{{Info|ſ|forme ancienne longue de la lettre s minuscule}}igenes. Celui-ci décida fau{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ement que le cercle des jours de l’année révolue excédoit du nombres 5 joint au quart de 1 les 360 degrés du cercle oblique parcouru par le {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oleil : expo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}é faux, auquel le Dictateur, occupé d’autres {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oins, déféra {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ans autre examen. Jules Cé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ar régla donc, de l’avis de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tronome, que l’année {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eroit divisée en 365 jours ; & quant au quart de jour re{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tant, qui produit {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ix heures, il ordonna qu’on n’y auroit aucun égard pour chaque année particuliere ; mais que chaque quatrieme année on réuniroit la totalité de quatre fois {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ix heures, qui en font vingt-quatre, pour en compo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}er un jour entier; & qu’ain{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i cette quatrieme année auroit 366 jours. Il régla de plus, que ce jour intercalaire, ou ajoûté à chaque quatrieme année, seroit le 24 Février. Les Romains nommoient ce jour-là ''bis {{Info|ſ|forme ancienne longue de la lettre s minuscule}}exto calendas Martii'', c’est-à-dire, le ''{{Info|ſ|forme ancienne longue de la lettre s minuscule}}econd {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ixieme avant les calendes de Mars'' ; d’où il arriva que l’année où tomboit ce jour intercalaire fut appellée bis-{{Info|ſ|forme ancienne longue de la lettre s minuscule}}extile.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#quelques_les_saisons_LPdS_back|<span id="quelques_les_saisons_LPdS"><sup>2</sup></span>]] Végece dit pareillement, liv. 4, chap. 40 : ''Aut enim circa diem {{Info|ſ|forme ancienne longue de la lettre s minuscule}}tatutum, aut ante, vel po{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tea, tempe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tates fieri compertum e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t : unde præcedentes, ωροϰεἰμασιν : na{{Info|ſ|forme ancienne longue de la lettre s minuscule}}centes die {{Info|ſ|forme ancienne longue de la lettre s minuscule}}olenni, επιϰεἰμασιν : {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ub{{Info|ſ|forme ancienne longue de la lettre s minuscule}}equentes, μεταϰεἰμασιν, Græco vocabulo nuncuperaverunt'' [[#Accedit_confessa_rerum_obscuritas_AdG_back|<sup>⤴️</sup>]]. On lit au{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}i chez [[w:Columelle|Columelle]], dans {{Info|ſ|forme ancienne longue de la lettre s minuscule}}a Préface :''' {{Info|''Neque enim ſemper eumdem, cælum & annus, velut ex præſcripto habitum gerunt : nec omnibus annis eodem vultu venit aſtas, aut hyems, &c.''|Car le ciel et l’année ne portent pas toujours le même habit, comme par un précepte : ni l’automne n’arrive chaque année avec la même apparence, ni l’hiver, etc. TdA}} </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#déjà_fait_observer_LPdS_back|<span id="déjà_fait_observer_LPdS"><sup>3</sup></span>]] Au liv. 17, chap. 2.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Saturne_LPdS_back|<span id="Saturne_LPdS"><sup>4</sup></span>]] Ain{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i qu’il l’in{{Info|ſ|forme ancienne longue de la lettre s minuscule}}inue dans {{Info|ſ|forme ancienne longue de la lettre s minuscule}}es ''Géorg.'' liv. I, v. 335 :'''<br /><p style="margin: 0 6em; text-indent: 0px">{{Info|Hoc metuens, cæli menses et sidera serva,<br />Frigida Saturni sese quo stella receptet.|Craignant cela, gardez les lunes et les étoiles du ciel, le froid de Saturne lui-même, où l’étoile les recevra. TdA.}} </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#lAnnée_dÉcriture_LPdS_back|<span id="lAnnée_dÉcriture_LPdS"><sup>5</sup></span>]] Pline, au quatorzieme livre, chap. 4, comptoit deux cents trente ans depuis la mort de [[w:Cicéron|Cicéron]] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Cicéron_I|<sup>🔄</sup>]], arrivée l’an de Rome 600. L’année qu’il indique ici, & où il {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e trouvoit avoir compo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}é quatre livres de plus, e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t probablement la {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uivante, c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t-à-dire l’année 831 de la fondation de Rome.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#secte_des_Chaldéens_LPdS_back|<span id="secte_des_Chaldéens_LPdS"><sup>5*</sup></span>]] Sur l’année Chaldéenne, qui étoit la même que la Judaïque, con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ultez [[w:Eusèbe_de_Césarée|Eu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ebe]], ''Præpar. Evang.'' liv. 9, chap. 17, où il fait Abraham inventeur de l’a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tronomie chez les Chaldéens. Les A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}trologues Chaldéens étoient ordinairement des Prêtres des Dieux, tels que [[w:Bérose|Béro{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e]], auquel les Athéniens éleverent dans leur Gymna{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e une {{Info|ſ|forme ancienne longue de la lettre s minuscule}}tatue à langue dorée. Sur quoi voyez Pline, liv. 7, chap. 37. Ce Béro{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e étoit un Prêtre de [[w:Bēl|Belus]] ; il e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t cité par [[w:Clément_d'Alexandrie|Clément d’Alexandrie]], & par [[w:Flavius_Josèphe|Jo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}eph]] [[#Flavius_Josèphe_I|<sup>⤵️</sup>]], contre Apion, liv. 1. Sur l’année Egyptienne, & {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur l’ancienne année Grecque, con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ultez [[w:Hérodote|Hérodote]] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Hérodote_I|<sup>🔄</sup>]] liv. 2, n°. 4. Cicéron rend ju{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tice à l’étude que firent des a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tres les Egyptiens & les Babyloniens, liv. 1, de ''Divinat.'' n°. 16 :''' {{Info|''Ægyptii, & Babylonii, in camporum patentium aquoribus habitantes, cùm ex terra nihil emineret, quod contemplationi cæli officere poſſet, omnem curam in ſiderum cognitione poſuerunt''|Les Égyptiens et les Babyloniens, vivant dans les eaux des plaines découvertes, alors que rien ne dépassait de la terre qui pût gêner la contemplation du ciel, mettaient tous leurs soins dans la connaissance des étoiles. TdA}}. </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Dictateur_César_LPdS_back|<span id="Dictateur_César_LPdS"><sup>6</sup></span>]] Voyez les notes 13 & 14 {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur le chap. 8 du liv. 2, tome 1, p. 41 & 42.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#calendrier_César_défectueux_LPdS_back|<span id="calendrier_César_défectueux_LPdS"><sup>7</sup></span>]] Voyez les notes indiquées dans la note précédente ; & joignez-y les ob{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ervations {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uivantes, qui {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont de M. De{{Info|ſ|forme ancienne longue de la lettre s minuscule}}places, p. 339 : « Le calendrier chrétien, ayant {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uivi la réformation de Jules Cé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ar, il {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e trouva qu’en l’année 1582, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous le Pape Grégoire XIII, l’équinoxe étoit remontée ju{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’au 11 de Mars, au lieu du 21, où elle devoit être. Ce Pape, après avoir con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ulté Clavius & Ciaconius, les plus habiles A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tronomes du tems, ordonna qu’en cette même année 1582, on compteroit le 5 du mois d’Octobre, au lieu du 15, afin de retrancher les dix jours qui s’étoient gli{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}és de trop, en {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uivant la {{Info|ſ|forme ancienne longue de la lettre s minuscule}}upputation Julienne, depuis le Concile de Nicée, tenu en 325 : on convint encore de continuer l’intercalation d’un jour tous les quatre ans ; & qu’en outre, pour éviter dans la {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uite pareille erreur, il {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eroit fait un retranchement de trois jours intercalaires, dans l’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}pace de quatre {{Info|ſ|forme ancienne longue de la lettre s minuscule}}iecles, à cau{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e des onze minutes qui manquent aux {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ix heures des années, dont on compo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e l’année intercalaire, ou bi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}extile ; ces trois jours {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e retranchent en l’année qui finit les trois premiers {{Info|ſ|forme ancienne longue de la lettre s minuscule}}iecles. De célebres A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tronomes modernes ont fait voir que, malgré cette précaution, il y auroit encore, au bout de quatre cents ans, plu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ieurs jours de variation dans l’équinoxe ».''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#correction_erreur_LPdS_back|<span id="correction_erreur_LPdS"><sup>8</sup></span>]] Etabli par Jules Cé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ar, & qui revenoit tous les quatre ans. Ecoutons Suétone, vie de ce Dictateur, chap. 40 : {{Info|''Faſtos correxit, jampridem vitio Pontiſicum, per intercalandi licentiam adeo turbatos, ut neque meſſium feria aſtati, neque vindemiarum autumno competerent, annumque ad curſum ſolis accommodevit, ut CCCLXV dierum eſſet, & intercalario menſe ſublato, unus dies quarto quoque anno intercalaretur, &c''|Il corrigea les jeûnes, qui avaient toujours été une faute pontique, si perturbés par la permission de l’intercalation, que ni les fêtes du mois ne tenaient, ni les récoltes ne correspondaient à l’automne, et il ajusta l’année à la course du soleil, de sorte que c’était 365 jours, et après le mois intercalaire, un jour était intercalé tous les quatre ans, etc. TdA}}. On s’apperçut que cette correction de Jules Cé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ar étoit elle-même fautive. On tenta de nouveau de remédier au vice du calendrier ; {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur quoi con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ultez Solin, chapitre 1, p. 5 ; le P. Petau, ''de Doctr. temp.'' chap. 3 ; mais {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur-tout [[w:Macrobe|Macrobe]], qui s’exprime ain{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i, liv. 1, ''Saturn.'' chap. 14, p. 255 :''' {{Info|''Sacerdotes ſibi errorem novum ex ipſa emendatione ſecerunt. Nam cùm oporteret diem, qui ex quadrantibus conſit, quarto quoque anno conſecto, antequam quintus inciperet, intercalare, illi quarto non peracto ſed incipiente, intercalabant. Hic error ſex & triginta annis permanſit : quibus annis intercalati ſunt dies duodecim, cùm deberent intercalari novem. Sed hunc quoque errorem ſerò deprehenſum correxit Auguſtus, qui annos duodecim ſine intercalari die tranſigi juſſit : ut illi tres dies, qui per annos triginta & ſex vitio ſacerdotalis ſeſtinationis excreverant, ſequentibus annis duodecim, nullo die intercalato, devorarentur. Poſt hoc unum diem, ſecundùm ordinationem Caſaris, quinto quoque incipiente anno intercalari juſſit : & omnem hunc ordinem area tabula ad aternam cuſtodiam inciſione mandavit.''|Les prêtres retranchèrent une nouvelle erreur de leur correction. Car lorsqu’il fallait intercaler le jour qui est composé de quadrants, la quatrième année consécutive, avant que la cinquième ne commence, on intercalait ceux lorsque la quatrième n’était pas terminée mais commençait. Cette erreur a duré trente-six ans : années au cours desquelles douze jours ont été intercalés, alors qu’il aurait fallu en intercaler neuf. Mais cette erreur fut également détectée par Auguste, qui ordonna que douze années s’écoulèrent sans jour intercalaire : afin que ces trois jours, qui avaient été excrétés pendant les trente-six années du vice sacerdotal de cessation, soient dévorés dans le douze années suivantes, sans jour intercalaire. Après ce jour, selon l’ordonnance de César, il décréta que la cinquième année serait également intercalée : et tout l’ordre fut ordonné d’être gravé par le conseil du domaine pour la garde éternelle. TdA}}. </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Auteurs_calendrier_LPdS_back|<span id="Auteurs_calendrier_LPdS"><sup>9</sup></span>]] Ces Auteurs {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont Hiéron, Philomêtor, Attale, Archelaüs, Xénophon, Magon, Caton, Silanus, Varron, &c. dont Pline a fait mention {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur la fin du chapitre 3.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#ouvrage_astronomique_Hésiode_LPdS_back|<span id="ouvrage_astronomique_Hésiode_LPdS"><sup>10</sup></span>]] Nous apprenons de Théon que cet ouvrage {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e nommoit l’A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}trique, Ἀςριϰὴ ϐίϐλος. Voyez au{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}i {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur ce même ouvrage, une Epigramme de [[w:Callimaque_de_Cyr%C3%A8ne|Callimaque]] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Callimaque_I_de_Cyrène_II|<sup>🔄</sup>]], citée dans la vie d’Aratus, qui fait partie de l’Uranologie de [[w:Denis_Pétau|Petau]], liv. 2, ''Var. Di{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ert.'' chap. 9, p. 97.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#opinion_Thalès_Hésiode_Anaximandre_LPdS_back|<span id="opinion_Thalès_Hésiode_Anaximandre_LPdS"><sup>11</sup></span>]] Con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ultez, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur cette opinion de Thalès, ain{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i que {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur celles d’Hé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iode & d’Anaximandre, l’Uranologie citée note précédente.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Euctémon_LPdS_back|<span id="Euctémon_LPdS"><sup>12</sup></span>]] ''Euctemon'' ; ain{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i portent les manu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}crits, & non pas ''Eudemon''. J’ai traité d’Euctêmon (en Grec Εὐϰτημον) dans les notes alphabétiques du premier livre, & plus récemment dans la note 21 du chapitre précédent.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#contrées_adjacentes_ouest_Péloponnese_LPdS_back|<span id="contrées_adjacentes_ouest_Péloponnese_LPdS"><sup>13</sup></span>]] Telles que l’Elide, l’Arcadie, la Me{{Info|ſ|forme ancienne longue de la lettre s minuscule}}lénie.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Columelle_LPdS_back|<span id="Columelle_LPdS"><sup>14</sup></span>]] Columelle, liv. 3, chap. 6 :''' {{Info|''Quo tempore ſol in eamdem partem ſigniſeri per eoſdem numeros redit, per quos cursus ſui principium cæperat : quem circuitum meatus dierum integrorum mille quadringentorum ſexaginta unius [[w:Apocatastase|ὰ τοκατάςασιν]] vocant ſtudioſi rerum cæleſtium''|A ce moment-là, le soleil revient dans la même direction au moyen des mêmes nombres par lesquels il a commencé sa course : laquelle course de mille quatre cent soixante et un jours entiers est appelée ὰ τοκατάςασιν par ceux qui étudient les choses célestes. TdA}}.</td> </tr> </table><br/><br/></div> {{Boîte déroulante fin}} <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=JeyFTzG771cC&newbks=1&newbks_redir=0&dq=Louis%20Poinsinet%20de%20Sivry%20Pline%20l'ancien&hl=fr&pg=PP9#v=onepage&q&f=true <u>Histoire Naturelle de Pline. Tome Sixieme</u>], [https://books.google.fr/books?id=JeyFTzG771cC&newbks=1&newbks_redir=0&dq=Louis%20Poinsinet%20de%20Sivry%20Pline%20l'ancien&hl=fr&pg=PA257#v=onepage&q&f=true ''Livre Dix-huitieme.''], [https://books.google.fr/books?id=JeyFTzG771cC&newbks=1&newbks_redir=0&dq=Louis%20Poinsinet%20de%20Sivry%20Pline%20l'ancien&hl=fr&pg=PA455#v=onepage&q&f=true ''Diviſion des jours & des nuits ſuivant le cours du Soleil ; lever & coucher des étoiles ; ordre des ſaiſons ; tems où l’on ſeme les bleds d’hiver.''], traduction en françois, avec le texte latin rétabli d’après les meilleures leçons manu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}crites ; accompagnée de Notes critiques pour l’éclairci{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ement du texte, & d’Ob{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ervations {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur les connoi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ances des Anciens comparées avec les découvertes des Modernes, par M. [[w:Louis_Poinsinet_de_Sivry|Louis Poinsinet de Sivry]], Chez la veuve Desaint, Paris, 1771</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div> </div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ==== Livre XXXVI ==== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Enquête sur la nature des pierres.</div> ===== <div style="text-align: center;">Chapitre XVII.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage de la mesure de la hauteur des pyramides et autres édifices semblables par comparaison des longueurs d'ombre, par '''Thalès'''.</div> :'''Texte latin''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''XVII.''' [...] Mensuram altitudinis earum omniumque similium deprehendere, invenit '''Thales''' ''Milesius'' umbram metiendo, qua hora par esse corpori solet.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=L249AAAAcAAJ&hl=fr&pg=PP11#v=onepage&q&f=false <u>Histoire Naturelle de Pline ― Tome Second</u>], [https://books.google.fr/books?id=L249AAAAcAAJ&hl=fr&pg=PA500#v=onepage&q&f=false ''Livre XXXVI.''], [https://books.google.fr/books?id=L249AAAAcAAJ&hl=fr&pg=PA513#v=onepage&q&f=false ''Chap. XVII.''], texte corrigé par [[w:Émile_Littré|M. É. Littré]], à partir de celui de [[w:Jean_Hardouin|Hardouin]], Librairie de Firmin-Didot et C<sup>ie</sup>, Paris, 1850<br />(également disponible une édition de 1877 sur [https://gallica.bnf.fr/ark:/12148/bpt6k282082c/f517.image ''Gallica''])</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''XVII.''' [...] Le moyen de mesurer la hauteur des pyramides et autres édifices semblables, fut trouvé par '''Thalès''' de ''Milet'' : il mesura l’ombre à l’heure où elle est égale aux corps.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=L249AAAAcAAJ&hl=fr&pg=PP11#v=onepage&q&f=false <u>Histoire Naturelle de Pline ― Tome Second</u>], [https://books.google.fr/books?id=L249AAAAcAAJ&hl=fr&pg=PA500#v=onepage&q&f=false ''Livre XXXVI.''], [https://books.google.fr/books?id=L249AAAAcAAJ&hl=fr&pg=PA513#v=onepage&q&f=false ''Chap. XVII.''], texte corrigé par [[w:Émile_Littré|M. É. Littré]], à partir de celui de [[w:Jean_Hardouin|Hardouin]], Librairie de Firmin-Didot et C<sup>ie</sup>, Paris, 1850<br />(également disponible une édition de 1848 sur [https://remacle.org/bloodwolf/erudits/plineancien/livre36.htm ''Remacle''], sur [[s:Histoire_naturelle_(trad._Littré)/XXXVI|''wikisource'']] et une édition de 1877 sur [https://gallica.bnf.fr/ark:/12148/bpt6k282082c/f517.image ''Gallica''])</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Flavius_Josèphe|'''Flavius Josèphe''']] [[#Flavius_Josèphe|<span id="Flavius_Josèphe_back"><sup>'''I'''</sup></span>]] == <p style="text-align: right;">([[w:37|37]]/[[w:38|38]], à [[w:Histoire_de_Jérusalem#Période_romaine_et_byzantine_(63_av._J.-C._-_638)|''Jérusalem'']] — vers [[w:100|100]], à [[w:Rome_antique|''Rome'']]) [[w:Ier_siècle|<sup>⏳</sup>]] [[s:Auteur:Flavius_Josèphe|<sup>📚</sup>]] <div style="text-align: justify; margin: 0 1em; text-indent: 15px">[[w:historiographe|Historiographe]] ''romain'' [[w:Juifs|''juif'']] d’origine [[w:Judée_(province romaine)|''judéenne'']], il participe activement au début de la ''première guerre judéo-romaine'' en tant que commandant militaire de ''Galilée'' contre les Romains, avant de se rendre à [[w:Vespasien|'''Vespasien''']] [[#Vespasien|<span id="Vespasien_back"><sup>'''II'''</sup></span>]] lors de la prise de la garnison juive de la forteresse de [[w:Jotapata|''Jotapata'']] en juillet 67, et de devenir intermédiaire, interprète et négociateur entre les ''romains'' et les ''Juifs'' lors du siège de ''Jérusalem'' conduit par '''Titus''' [[#Titus_back|<sup>⤴️</sup>]] en 70. Après la fin de la grande révolte ''judéenne'', en 71, il s’établit auprès de son protecteur à ''Rome'' où il obtient la [[w:citoyenneté_romaine|''citoyenneté romaine'']].</div> {{Boîte déroulante début|titre=NdA Flavius Josèphe|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Flavius_Josèphe_back|<span id="Flavius_Josèphe"><sup>I</sup></span>]] De son nom de naissance Joseph ben (fils de) Matthatias, de l’hébreu יוסף בן מתתיהו / Yossef [[wikt:en:יוסף#Hebrew|(en)]] ben [[wikt:en:בן#Noun|(en)]] Matityahou [[wikt:en:מתתיהו#Hebrew|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;">• de la troisième personne du singulier [[w:Jussif|''jussive'']], signifiant ainsi « peut-il ajouter », du verbe הוֹסִיף / hosíf [[wikt:en:הוסיף#Hebrew|(en)]], « 1. Ajouter (quelque chose) à (quelque chose d'autre). 2. (littéraire) Continuer (à faire quelque chose). 3. (archaïque) Coordonné avec un autre verbe pour indiquer que l’action de ce verbe "ajoute" d’une manière ou d’une autre. »;<br /><p style="margin: 0 2em; text-indent: 15px;">• du nom commun בֵּן / bén, « 1. Fils. 2. (ne produit plus de mot ou d’expression) Un descendant mâle direct. 3. Un mec, un garçon. 4. (n’est plus productif, état de construction) Possesseur de (connaissance, capacité, etc.). 5. (État construit) Utilisé pour exprimer l’âge d’un homme, d’un garçon ou le référent d’un nom masculin : âge, âgé. »;<br /><p style="margin: 0 2em; text-indent: 15px;">• de la contraction du nom commun מַתָּנַת / mataná [[wikt:en:מתנה#Hebrew|(en)]], « cadeau, présent, don »;<br /><p style="margin: 0 2em; text-indent: 30px;">➥ du verbe נתן / natán [[wikt:en:נתן#Verb|(en)]], « 1. Donner. 2. Autoriser, permettre, laisser. 3. (archaïque) Mettre, placer. 4. (archaïque, hébreu biblique) Se transformer en. »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ et du nom propre יהוה / YHWH [[wikt:en:יהוה#Hebrew|(en)]], « (Judaïsme) Tétragramme : mot en quatre lettres hébraïques utilisé comme nom [[wikt:ineffable#Français|''ineffable'']] de Dieu dans la Bible hébraïque, diversement rendu par Yahweh ou Jéhovah. »;<br /><p style="margin: 0 2em; text-indent: 15px;">Son tria nomina à l’obtention de sa ''citoyenneté romaine'' est {{Info|Titus|praenomen, nom individuel du citoyen romain}} {{Info|Flavius|nomen, nom de famille}} {{Info|Josephus|cognomen, surnom héréditaire, servant à distinguer les diverses branches d’une même gens}}, prenant ainsi le nom de son bienfaiteur :<br /><br /><p style="margin: 0 2em; text-indent: 15px;">[[#Vespasien_back|<span id="Vespasien"><sup>II</sup></span>]] [[w:Nom_romain|Tria Nomina]] en latin {{Info|Titus|praenomen, nom individuel du citoyen romain}} {{Info|Flavius|nomen, nom de famille}} {{Info|Vespasianus|cognomen, surnom héréditaire, servant à distinguer les diverses branches d’une même gens}};<br /><p style="margin: 0 2em; text-indent: 15px;">[[w:L%C3%A9gat_(Rome_antique)|''Légat'']] lors de la [[w:Conqu%C3%AAte_romaine_de_la_Grande-Bretagne|''conquête de la Bretagne en 43'']] et lors de la [[w:Premi%C3%A8re_guerre_jud%C3%A9o-romaine|''rébellion juive de 66'']] en [[w:Jud%C3%A9e_(province_romaine)|''Judée'']]. Fin décembre 69, il est couronné empereur par le [[w:S%C3%A9nat_romain|''Sénat'']] après la guerre civile de l’[[w:Ann%C3%A9e_des_quatre_empereurs|''année des quatre empereurs'']], et fonde la dynastie des [[w:Flaviens|''Flaviens'']].<br /><p style="text-align: right; margin: 0 2em;">(17 novembre [[w:9|9]], près de [[w:Reate|''Reate'']] dans la région centrale italienne du [[w:Latium|''Latium'']] — 23/24 juin [[w:79|79]], à la station thermale de [[w:Aquae_Cutiliae|''Aquae Cutiliae'']], à l’est de ''Reate'')<sup>[[w:Ier_siècle|⏳]]</sup><br/><br/></div> ''' {{Boîte déroulante fin}} === [[w:Contre_Apion|Contre Apion]] === <p style="text-align: right;">[[s:Contre_Apion|📚]] {| cellpadding="0" align="{{{align|right}}}" style="margin-left: 2em; width:40%; border-spacing:3px; text-align:center; background-color:#F8F9FA; border:2px solid #C8CCD1" |- | style="border:solid 1px #F8F9FA" | [https://archive.org/details/contreapiontexte0000jose/page/n156/mode/1up {{Info|'''Éditions & Manuscrits'''|Flavius Josèphe Contre Apion, Théodore Reinach & Léon Blum, 1930}}] |- style="font-size:8pt; line-height:10pt; vertical-align:middle" | align="center" | <div style="margin-right: 1em; padding:0 0 4px 0; text-align:justify;">{{{légende| * La traduction ''latine'' a été imprimée dès 1480 à [[w:Vérone#Époque_moderne|''Vérone'']] par '''Pierre Maufer''' [[w:en:Petrus_Maufer|(en)]]. L’édition de cette traduction, due à [[w:Sigismund_Gelenius|'''Sigismond Gelenius''']] (''Paris'', 1535), qui constitue la « [[w:Vulgate|Vulgate]] », présente un texte souvent « amélioré » de façon arbitraire. La seule édition critique est celle de '''Ch. Boysen''' (''Vienne'', 1898) qui fait partie du [[w:Corpus_scriptorum_ecclesiasticorum_latinorum|{{Info|''Corpus scriptorum ecclesiasticorum latinorum''|Le corpus des écrits ecclésiastiques latins}}]]. Elle repose principalement sur les manuscrits L(aurentianus LXVI, 2), B(odleianus Canonicianus 148), R(egius Parisinus 5049) de la I<sup>re</sup> classe, C(heltenhamensis Phillipicus 12311), P(arisinus 1615), Pa(rsinus 5054) de la seconde. * Le texte grec est édité pour la première fois dans l’édition complète de '''Josèphe''' à [[w:Bâle#XVIe_siècle|''Bâle'']], chez [[w:Johann_Froben|''Froben'']], en 1544 par [[w:Arnoldus_Arlenius|'''Arlenius''']] qui a peut-être fait usage du ''Schleusingensis'' (un des fils du Laurentianus), mais a introduit grand nombre de corrections tantôt heureuses, et tantôt arbitraires. Par la suite notre traité n’a guère été imprimé que comme partie intégrante d’éditions complètes des œuvres de '''Josèphe'''. Les plus importantes sont celles de '''E. Bernard''' (1700), de [[w:John_Hudson_(classiciste)|'''Hudson''']] (1720) — le premier qui ait utilisé L —, de [[w:Sigebert_Havercamp|'''Havercamp''']] (1726), simple compilateur, de [[w:Karl_Wilhelm_Dindorf|'''L. Dindorf''']] (1847), de [[w:Immanuel_Bekker|'''Imm. Bekker''']] (1856), tout à fait manquée. L’édition critique de '''Niese''' [[w:en:Benedikt_Niese|(en)]] (1889) est la base de tous les travaux ultérieurs, notamment des éditions de '''Naber''' (1896) et de [[w:Henry_St._John_Thackeray|'''H. St. J. Thackeray''']] (coll. Loeb, 1926 : il n’a encore paru que le ''C. Apion'', la ''Vita'' et le commencement de la ''Guerre'') qui ont pu profiter aussi des conjectures de '''Cobet''', de '''Holwerda''', et de '''Herwerden'''.}}}</div> |} <div style="text-align: justify; margin: 0 1em; text-indent: 15px">Dernière œuvre écrite par '''Flavius Josèphe''', vers [[w:93|93]], dont l’objectif est de répondre aux critiques qu’ont soulevées ses [[w:Antiquit%C3%A9s_juda%C3%AFques|''Antiquités judaïques'']], de défendre l’ancienneté du peuple ''juif'' et du [[w:Judaïsme#Judaïsme_antique|''judaïsme'']] (Livre I) et les accusations d’[[w:Apion_(grammairien)|'''Apion''']] [[#Apion|<span id="Apion_back"><sup>'''I'''</sup></span>]] (Livre II).</div> {{Boîte déroulante début|titre=NdA Apion|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Apion_back|<span id="Apion"><sup>I</sup></span>]] Du nom propre grec ancien [[wikt:Apion#Latin|Ἀπίων / Apíôn]]; <br/><br /><p style="margin: 0 2em; text-indent: 15px;">'''[[w:Grammaticus|''Grammairien'']] [[#grammairien|<span id="grammairien_back"><sup>II</sup></span>]] et [[w:Polygraphe_(auteur)|''polygraphe'']] [[#polygraphe|<span id="Grammairien_back"><sup>III</sup></span>]] ''grec'' d’Alexandrie.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] seconde moitié du [[w:Ier_siècle_av._J.-C.|I<sup>er</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]] — première moitié du [[w:Ier_siècle|I<sup>er</sup> siècle {{Info|EC|de l’Ère Commune}}]]) <br /><br /><p style="margin: 0 2em; text-indent: 15px;">'''[[#grammairien_back|<span id="grammairien"><sup>II</sup></span>]] Du nom commun latin grammaticus [[wikt:en:grammaticus#Latin|(en)]]; du nom commun grec ancien γραμματικός / grammatikós [[wikt:en:γραμματικός#Noun|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px">➥ du nom commun γρᾰ́μμᾰ / grámma [[wikt:en:γράμμα#Noun|(en)]], « 1. Ce qui est écrit, ce qui est dessiné. 2. Lettre. 3. (au pluriel) Alphabet. 4. Écriture, livre. »;<br /><p style="margin: 0 2em; text-indent: 30px">➥ du verbe γράφω / gráphō [[wikt:en:γράφω#Ancient_Greek|(en)]], « 1. (Homérique) égratigner, couper en dedans. 2. Dessiner, esquisser, peindre. 3. Écrire. 4. Écrire, proposer une loi. 5. ([[w:Diathèse#Moyen|''voix moyenne'']]) : • (''[[w:Réflexivité_(grammaire)|réflexif]] indirect'') Écrire pour soi, noter ; • Accuser, poursuivre. 6. ([[w:Conjugaison_latine|''passif parfait'']]) Être écrit, être sous forme écrite. »;<br /><p style="margin: 0 2em; text-indent: 30px">➥ + du suffixe nominal de résultat‎ -μα / -ma [[wikt:en:-μα#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px">➥ +‎ du suffixe adjectival -ῐκός / -ikós, de ou se rapportant à, de la manière de ; « -ique »;<br /><p style="margin: 0 2em; text-indent: 15px">Enseignant responsable de la deuxième étape du système éducatif traditionnel, après l’apprentissage de l’alphabet, la lecture et l’écriture, et l’initiation au calcul avec un abaque chez un ''magister ludi'' [[w:en:Ludi_magister|(en)]] et avant celle de l’art du discours chez un [[w:Rhétorique#Rhétorique_dans_l'Antiquité_grecque|''rhéteur'']]. Le travail du grammairien était d’enseigner la lecture, l’analyse de textes des poètes antiques tels qu’Homère, Tite-Live et Virgile, et la grammaire [https://archive.wikiwix.com/cache/index2.php?url=http%3A%2F%2Fwww.antiquite.ac-versailles.fr%2Feducatio%2Fedrom2.htm#federation=archive.wikiwix.com&tab=url {{Info|<sup>➕</sup>|« L’école du grammaticus », ac-Versailles}}] [https://philo-lettres.fr/latin/rome_vie-quotidienne/ecole-romaine/ {{Info|<sup>➕➕</sup>|« L’École dans l’antiquité romaine, philo-lettres}}]. <br /><br /><p style="margin: 0 2em; text-indent: 15px;">'''[[#polygraphe_back|<span id="polygraphe"><sup>III</sup></span>]] Du nom commun grec ancien [[wikt:polygraphe|πολύγραφος / polýgraphos]], « qui écrit beaucoup de sujets »;<br /><p style="margin: 0 2em; text-indent: 15px">➥ de l’adjectif πολῠ́ς / polús [[wikt:en:πολύς#Ancient_Greek|(en)]], « (de nombre, au pluriel) Beaucoup de : • (avec des noms de multitude) Grand ; • (de quantité, avec des noms de masse) beaucoup de ; • (rare, d'une personne) Grand, puissant ; • (de son) Fort ; • (attributivement, adverbial) Fortement, pleinement ; • (d'espace) Large, grand ; • (de distance) Loin ; • (de temps) Long, en retard. »;<br /><p style="margin: 0 2em; text-indent: 15px">➥ +‎ du verbe γράφω / gráphō [[wikt:en:γράφω#Ancient_Greek|(en)]], « 1. (Homérique) égratigner, couper en dedans. 2. Dessiner, esquisser, peindre. 3. Écrire. 4. Écrire, proposer une loi. 5. (''voix moyenne'') : • (''réflexif indirect'') Écrire pour soi, noter ; • Accuser, poursuivre. 6. (''passif parfait'') Être écrit, être sous forme écrite. »;<br /><p style="margin: 0 2em; text-indent: 15px;">Le terme semble avoir été employé au cours de l’Antiquité dans un sens différent de celui que nous l’entendons aujourd’hui, pas dans le sens de diversité mais, de façon restreinte, le fait de composer un grand nombre de textes [https://eriac.univ-rouen.fr/la-polygraphie-comme-norme/ {{Info|<sup>➕</sup>|Isabelle Gassino, Université de Rouen et Dimitri Kasprzyk, université de Brest, « Colloque "La polygraphie comme norme" », 16 et 17 novembre 2017.}}].'''<br/><br/></div> {{Boîte déroulante fin}} ==== Livre I ==== ===== <div style="text-align: center;">Chapitre II.</div> ===== <div style="text-align: justify; margin: 0 1em;">Témoignage de '''Thales''' comme : * l’un des premiers ''philosophes grecs'' ayant traité des choses célestes et divines ; * disciple des ''Égyptiens'' et des ''Chaldéens'' (premier témoignage) ; * auteur de court(s)/rare(s) ouvrages (supposément unanimement admis), que les ''Grecs'' considéreraient comme les plus anciens, et douteraient, selon '''Flavius Josèphe''', de leur authenticité.</div> :'''Texte latin''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">qui autem historias apud eos conscribere temptauerunt, id est hi, qui circa '''Cadmum''' ''Milesium'', et '''Acusilaus''' ''Argiuus'' et post hunc quicumque alii fuisse referuntur, paululum tempus ''Persicam'' apud ''Helladium'' militiam praecesserunt. sed etiam eos, qui de caelestibus et diuinis primitus apud ''Graecos philosophati'' sund, id est '''Pherecydem''' ''Syrum'' et '''Pythagoram''' et '''Thaletem''' omnes concorditer confidentur ''Aegyptiorum'' et ''Chaldaeorum'' fuisse discipulos et breuiter conscripsisse quae a ''Graecis'' omnium antiquissima iudicantur ita ut uix ea credant ab illis fuisse conscripta.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[[w:Corpus_scriptorum_ecclesiasticorum_latinorum|<u>Corpus scriptorum ecclesiasticorum latinorum</u>]], [https://verlag.oeaw.ac.at/produkt/flavii-iosephi-opera-ex-versione-latina-antiqua-pars-vi-de-iudaeorum-vetustate-sive-contra-apionem-libri-ii/601067?name=flavii-iosephi-opera-ex-versione-latina-antiqua-pars-vi-de-iudaeorum-vetustate-sive-contra-apionem-libri-ii&product_form=5107 <u>Tome XXXVII, Flavius Iosephus, Contra Apionem</u>], ''Livre I'', ''chap. II.'', ''l.13, 14'', p.64, 1898</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">Οἱ μέντοι τὰς ἱστορίας ἐπιχειρήσαντες συγγράφειν παρ' αὐτοῖς, λέγω δὲ τοὺς περὶ '''Κάδμον''' τε τὸν ''Μιλήσιον'' καὶ τὸν ''Ἀργεῖον'' '''Ἀκουσίλαον''' καὶ μετὰ τοῦτον εἴ τινες ἄλλοι λέγονται γενέσθαι, βραχὺ τῆς ''Περσῶν'' ἐπὶ τὴν ''Ἑλλάδα'' στρατείας τῷ χρόνῳ προύλαβον. Ἀλλὰ μὴν καὶ τοὺς περὶ τῶν οὐρανίων τε καὶ θείων πρώτους παρ' ''Ἕλλησι φιλοσοφήσαντας'', οἷον '''Φερεκύδην''' τε τὸν ''Σύριον'' καὶ '''Πυθαγόραν''' καὶ '''Θάλητα''', πάντες συμφώνως ὁμολογοῦσιν ''Αἰγυπτίων'' καὶ ''Χαλδαίων'' γενομένους μαθητὰς ὀλίγα συγγράψαι, καὶ ταῦτα τοῖς ''Ἕλλησιν'' εἶναι δοκεῖ πάντων ἀρχαιότατα καὶ μόλις αὐτὰ πιστεύουσιν ὑπ' ἐκείνων γεγράφθαι.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://remacle.org/bloodwolf/historiens/Flajose/Apion1gr.htm <u>Φλαίίου Ἰωσήπου, περὶ ἀρχαιότητος Ἰουδαίων</u>, ''λόγος α''], ''chap. II.'', ''l.13, 14'', 1898</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">Quant aux Grecs qui ont entrepris d’écrire l’histoire, comme [[w:Cadmos_de_Milet|'''Cadmos''' de ''Milet'']], [[w:Acousilaos|'''Acousilaos''' d’Argos]] et ceux qu’on cite après lui, ils n’ont vécu que peu de temps [[#Cadmos_NdT_LB|<span id="Cadmos_NdT_LB_back"><sup>1</sup></span>]] avant [[w:Guerres_médiques|''l’expédition des Perses contre la Grèce'']]. Mais bien certainement les premiers ''philosophes grecs'' qui aient traité des choses célestes et divines, comme [[w:Phérécyde_de_Syros|'''Phérécyde''' de ''Syros'']] [[#Phérécyde_de_Syros_NdT_LB|<span id="Phérécyde_de_Syros_NdT_LB_back"><sup>2</sup></span>]], '''Pythagore''' et '''Thalès'''[[#Thales_NdT_LB|<span id="Thales_NdT_LB_back"><sup>3</sup></span>]] furent, tout le monde s’accorde là-dessus, les disciples des ''Égyptiens'' et des ''Chaldéens'' avant de composer leurs courts ouvrages, et ces écrits sont aux yeux des ''Grecs'' les plus anciens de tous ; à peine même les croient-ils authentiques.</div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Cadmos_NdT_LB_back|<span id="Cadmos_NdT_LB"><sup>1.</sup></span>]] En réalité, Cadmos paraît avoir fleuri vers le milieu [[w:VIe_siècle_av._J.-C.|VI<sup>ème</sup> siècle]] [{{Info|AEC|Avant l’Ère Commune}}].''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Phérécyde_de_Syros_NdT_LB_back|<span id="Phérécyde_de_Syros_NdT_LB"><sup>2</sup></span>]] Seul texte qui attribue une origine égyptienne ou chaldéenne aux doctrines de Phérécyde de Syros. Cependant [[w:Theodor_Gomperz|Gompers]], [https://archive.org/details/bub_gb_QrfVAAAAMAAJ/page/n434/mode/1up Griechische Denker, I, 430], identifie ᾿Ογηνός avec l’Ouginna babylonien.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Thales_NdT_LB_back|<span id="Thales_NdT_LB"><sup>3</sup></span>]] On retrouve chez [[w:Apollonios_de_Tyane|Apollonios de Tyane]] ([[w:Jamblique|Jamblique]] [[#Jamblique_back|<sup>⤵️</sup>]], Vit. Pyth. [[#Vie_de_Pythagore_back|<sup>⤵️</sup>]], 12) et [[w:Plutarque|Plutarque]] [[#Plutarque_back|<sup>⤵️</sup>]] l’idée que Thalès de Milet fut disciple des Égyptiens ; l’adjonction des Chaldéens est propre Josèphe.''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/contreapiontexte0000jose/page/n6/mode/1up?view=theater <u>Flavius Josèphe, Contre Apion</u>], ''Livre I'', [https://archive.org/details/contreapiontexte0000jose/page/n49/mode/1up?view=theater&q=Thales ''chap. 2''], traduction du grec ancien par Léon Blum, agrégé des Lettres, professeur au lycée Janson-de-Sailly, texte établi et annotée par [[w:Théodore_Reinach|Théodore Reinach]] Membre de l’[[w:Institut_de_France|Institut]], professeur au Collège de France, 1930<br />(édition bilingue de 1911 également disponible [https://remacle.org/bloodwolf/historiens/Flajose/Apion1.htm ici])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: justify; margin: 0 2em;">Quant aux Grecs qui ont entrepris d’écrire l’histoire, comme '''Cadmos''' de ''Milet'', '''Acousilaos''' d’''Argos'' et ceux qu’on nomme après lui, ils n’ont vécu que peu de temps[2] avant l’expédition des ''Perses'' contre la ''Grèce''. [14]. De même, les premiers ''philosophes grecs'' qui aient traité des choses célestes et divines, comme '''Phérécyde''' de ''Syros''[3], '''Pythagore''' et '''Thalès'''[4] furent, tout le monde s’accorde là dessus, les disciples des ''Égyptiens'' et des ''Chaldéens'' avant de composer leurs rares ouvrages, et ces écrits sont aux yeux des ''Grecs'' les plus anciens de tous ; à peine même les croient-ils authentiques.</div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Cadmos_NdT_LB_back|<span id="Cadmos_NdT_LB"><sup>1.</sup></span>]] En réalité, Cadmos paraît avoir fleuri vers le milieu [[w:VIe_siècle_av._J.-C.|VI<sup>ème</sup> siècle]] [{{Info|AEC|Avant l’Ère Commune}}].''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Phérécyde_de_Syros_NdT_LB_back|<span id="Phérécyde_de_Syros_NdT_LB"><sup>2</sup></span>]] Seul texte qui attribue une origine égyptienne ou chaldéenne aux doctrines de Phérécyde de Syros. Cependant [[w:Theodor_Gomperz|Gompers]], [https://archive.org/details/bub_gb_QrfVAAAAMAAJ/page/n434/mode/1up Griechische Denker, I, 430], identifie ᾿Ογηνός avec l’Ouginna babylonien.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Thales_NdT_LB_back|<span id="Thales_NdT_LB"><sup>3</sup></span>]] On retrouve chez [[w:Apollonios_de_Tyane|Apollonios de Tyane]] ([[w:Jamblique|Jamblique]] [[#Jamblique_back|<sup>⤵️</sup>]], Vit. Pyth. [[#Vie_de_Pythagore_back|<sup>⤵️</sup>]], 12) et [[w:Plutarque|Plutarque]] [[#Plutarque_back|<sup>⤵️</sup>]] l’idée que Thalès de Milet fut disciple des Égyptiens ; l’adjonction des Chaldéens est propre Josèphe.''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Flavius Josèphe, De l’ancienneté du peuple juif (Contre Apion)</u>, ''Livre I'', [[s:Page:Flavius_Josephe_-_Leon_Blum_-_Contre_Apion,_Leroux,_Paris,_1902.djvu/17|''Chap. 2'']], traduction de Léon Blum, agrégé des lettres, professeur au lycée du Havre, sous la direction de [[w:Théodore_Reinach|Théodore Reinach]], 1902.</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div> </div> <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Plutarque|'''Plutarque''']] [[#Plutarque|<span id="Plutarque_back"><sup>'''I'''</sup></span>]] == <p style="text-align: right;">([[w:Circa|{{Info|''ca.''|Circa, locution latine que l’on emploie pour indiquer l’approximation d’une date}}]] [[w:45|45]]'' <sup>[[w:Ier_siècle|⏳]]</sup>'', à [[w:Chéronée|''Chéronée'']] en [[w:Béotie|''Béotie'']] — {{Info|''ca.''|Circa, locution latine que l’on emploie pour indiquer l’approximation d’une date}} [[w:125|125]]'' <sup>[[w:IIe_siècle|⏳]]</sup>)[[s:Auteur:Plutarque|<sup>📚</sup>]] [https://books.google.fr/books?id=qfl1xwEACAAJ&lpg=PA1067&hl=fr&pg=PA1097#v=onepage&q&f=false {{Info|<sup>🔍</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume Vb, §210 - Plutarque de Chéronée}}] [[Fichier:Plutarch at Delphi.jpg|vignette|<p style="text-align: justify; text-indent: 15px;">Buste probable de Plutarque du [[w:IIe_siècle|II<sup>ème</sup>]] ou [[w:IIIe_siècle|III<sup>ème</sup>]] siècles {{Info|EC|de l’Ère Commune}}, en marbre de [[w:Marbre_de_Paros|''Paros'']].<br /><p style="text-align: justify; text-indent: 15px;">Provenance : découvert lors de fouilles près de l’angle sud-est du [[w:Temple d'Apollon (Delphes)|''temple d’Apollon'']] de [[w:Delphes|''Delphes'']], au côté d'une [[w:Fichier:Plutarch_stele_inscription_100_AD,_AM_of_Delphi_4070060092.jpg|''stèle'']] portant une inscription gravée : ΔΕΛΦΟΙ ΧΑΙΡΩΝΕΥΣΙΝ ΟΜΟΥ ΠΛΟΥΤΑΡΧΟΝ ΕΘΗΚΑΝ ΤΟΙΣ ΑΜΦΙΚΤΥΟΝΩΝ ΔΟΓΜΑΣΙ ΠΕΙΘΟΜΕΝΟΙ — Les ''Delphiens'', avec les ''Chéronéens'', dédièrent ce(tte image de) Plutarque, suivant les préceptes de l’[[w:Amphictyonie|''Amphictyonie'']].<br /><p style="text-align: justify; text-indent: 15px;">Exposition : Salle XIV, [[w:Mus%C3%A9e_arch%C3%A9ologique_de_Delphes|''Musée archéologique de Delphes'']].]] <div style="text-align: justify; margin: 0 1em; text-indent: 15px">Biographe, philosophe et moraliste grec, auteur d’une œuvre importante, comportant un ensemble varié de traités et de dialogues consacrés à des questions de philosophie morale, mais abordant aussi des sujets littéraires, politiques, scientifiques, religieux.</div> {{Boîte déroulante début|titre=NdA Plutarque|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Plutarque_back|<span id="Plutarque"><sup>I</sup></span>]] Du nom propre grec ancien πλούταρχος / ploútarkhos [[wikt:en:Πλούταρχος#Ancient_Greek|(en)]], « maître des richesses » ; <br /><p style="margin: 0 2em; text-indent: 15px">➥ du nom commun πλοῦτος / ploûtos [[wikt:en:πλοῦτος#Ancient_Greek|(en)]], « richesses » ;<br /><p style="margin: 0 2em; text-indent: 15px">➥ +‎ du nom commun ἀρχός / arkhós, « souverain, chef, prince »)'''<br/><br/></div> {{Boîte déroulante fin}} {{Boîte déroulante début|titre=Remarque|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>''' Dans la ''Vie de [[w:Lycurgue_(législateur)|Lycurgue]]'' et la ''Vie d’Agis et Cléomène'' (''Vies parallèles''), et le traité ''Un philosophe doit surtout converser avec les princes'' (''Œuvres morales''), il est fait mention d’un Thalès : il s’agit de [[w:Thalétas|Thalétas]], aussi appelé Thalès de [[w:Crète|''Crète'']], un musicien et poète, originaire de la cité de [[w:Gortyne|''Gortyne'']] en ''Crète'', et actif à la fin du [[w:VIIIe_siècle_av._J.-C.|VIII<sup>ème</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]] et au début du siècle suivant.'''<br/><br/></div> {{Boîte déroulante fin}} === [[w:Vies_parallèles|Vies parallèles]] [[#Vies_parallèles|<span id="Vies_parallèles_back"><sup>'''I'''</sup></span>]] === <div style="text-align: center; margin: 0 1em;">Recueil de 50 biographies de grands hommes de l’histoire, dont 46 présentées par paires : un ''Grec'' mis en parallèle avec un ''Romain'' [https://books.google.fr/books?id=qfl1xwEACAAJ&lpg=PA1059&hl=fr&pg=PA1115#v=onepage&f=false {{info|<sup>🔍</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume Vb, §210 - Plutarque de Chéronée, pp.1115 - 1119, (7) Le Moraliste et l’entreprise des Vies Parallèles}}]. {{Boîte déroulante début|titre=NdA Vies parallèles|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Vies_parallèles_back|<span id="Vies_parallèles"><sup>I</sup></span>]] En grec ancien Βίοι Παράλληλοι / Bíoi Parállêloi :<br /><p style="margin: 0 2em; text-indent: 15px;">➥ Du nom commun βῐ́ος / bĭ́os [[wikt:en:βίος#Ancient_Greek|(en)]], « Vie (souvent avec une connotation positive : la vie heureuse) » ;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ De l’adjectif πᾰρᾰ́λληλος / părắllēlos [[wikt:en:παράλληλος#Ancient_Greek|(en)]], « 1. À côté l’un de l’autre, côte à côte. 2. Parallèle à ou avec. 3. Pléonastique, redondant.<br /><p style="margin: 0 2em; text-indent: 30px;">➥ du préfixe παρα- / para- [[wikt:en:παρα-#Ancient_Greek|(en)]], « 1. À côté. 2. Contrairement à. » ;<br /><p style="margin: 0 2em; text-indent: 45px;">➥ de la préposition πᾰρᾰ́ / părắ [[wikt:en:παρά#Ancient_Greek|(en)]], « 1. [avec génitif] : • De ; • À cause de. 2. [avec datif] : • À, à côté de, près de. 3. [avec accusatif] : • Contraire à ; • À côté de, près de (avec les verbes de venir ou d’aller ; avec les verbes de mouvement passé ; avec les verbes de frapper ou de blesser) » ;<br /><p style="margin: 0 2em; text-indent: 30px;">➥ +‎ du pronom ᾰ̓λλήλων / ăllḗlōn [[wikt:en:ἀλλήλων#Ancient_Greek|(en)]], « Se rapportant à un sujet pluriel et exprimant une action bilatérale : l’un de l’autre, l’un à l’autre, l’un l’autre, l’un l’autre, mutuellement, réciproquement. » ;<br /><p style="margin: 0 2em; text-indent: 45px;">➥ À partir d’expressions telles que ᾰ̓́λλος ᾰ̓́λλον / ắllos ắllon, ᾰ̓́λλοι ᾰ̓́λλους / ắlloi ắllous, « les uns les autres », avec perte de λ soit par dissimilation, soit par allongement de α, ainsi que restauration de la deuxième voyelle initiale ή / ḗ.'''<br/><br/></div> {{Boîte déroulante fin}} ==== Vie de [[w:Solon|'''Solon''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Solon|<sup>🔄</sup>]] ==== <div style="text-align: center; margin: 0 1em;">Biographie de '''Solon''', qui précède celle de [[w:Publius_Valerius_Publicola_(consul_en_-509)|'''Publicola''']] [[#Publicola|<span id="Publicola_back"><sup>'''I'''</sup></span>]], et avec laquelle '''Plutarque''' la compare.</div> {{Boîte déroulante début|titre=NdA Vie de Solon|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Publicola_back|<span id="Publicola"><sup>I</sup></span>]] [[w:Nom_romain|Tria Nomina]] en latin {{Info|Publius|praenomen, nom individuel du citoyen romain}} {{Info|Valerius|nomen, nom de famille}} {{Info|Publicola ou Poplicola|cognomen, surnom héréditaire, servant à distinguer les diverses branches d’une même gens}}, « celui qui prend soin de l’armée. »[https://academic.oup.com/bics/advance-article/doi/10.1093/bics/qbaf002/8117642?login=false {{Info|<sup>🔍</sup>|M. Gallo, « Misinterpreting a compound name. The origin of the agnomen Publicola in Dionysius of Halicarnassus and Plutarch », Bulletin of the Institute of Classical Studies,‎ 22 avril 2025}}].<br /><p style="margin: 0 2em; text-indent: 15px">[[w:Consul_(Rome_antique)|Consul]] de la [[w:république_romaine|''République Romaine'']], à quatre reprises : en [[w:-509|-509]], [[w:-508|-508]], [[w:-507|-507]] et [[w:-504|-504]], et l’un des instaurateurs légendaires de la ''République Romaine'' en -509, suite au viol et au suicide de [[w:Lucrèce_(dame_romaine)|Lucrèce]], une femme aristocratique ''romaine'', par [[w:Sextus_Tarquin|Sextus Tarquin]], le fils du dernier [[w:Roi_de_Rome|roi de ''Rome'']] [[w:Tarquin_le_Superbe|Tarquin le Superbe]].<br /><p style="text-align: right; margin: 0 2em;">(date et lieu de naissance inconnu.e.s — [[w:-503|-503]], soit sur le champ de bataille pendant les [[w:Guerres_romano-sabelliennes|''guerres romano-sabelliennes'']], soit de maladie)<sup>[[w:VIe_siècle_av._J.-C.|⏳]]</sup> '''<br/><br/></div> {{Boîte déroulante fin}} ===== <div style="text-align: center;">Chapitre II.</div> ===== ====== <div style="text-align: center;">Paragraphe III.</div> ====== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage de '''Thalès''' ''commerçant''.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''III.''' Κωλύει δὲ οὐδὲν τὸν ἀγαθὸν καὶ πολιτικὸν ἄνδρα μήτε τῶν περιττῶν τὴν κτῆσιν ἐν σπουδῇ τίθεσθαι μήτε τῆς χρείας τῶν ἀναγκαίων καὶ ἱκανῶν καταφρονεῖν. Ἐν δὲ τοῖς τότε χρόνοις, καθ' Ἡσίοδον, ἔργον οὐδὲν ἦν ὄνειδος, οὐδὲ τέχνη διαφορὰν ἔφερεν, ἐμπορία δὲ καὶ δόξαν εἶχεν οἰκειουμένη τὰ βαρβαρικὰ καὶ προξενοῦσα φιλίας βασιλέων καὶ πραγμάτων ἐμπείρους ποιοῦσα πολλῶν. Ἔνιοι δὲ καὶ πόλεων οἰκισταὶ γεγόνασι μεγάλων, ὡς καὶ Μασσαλίας Πρῶτις ὑπὸ Κελτῶν τῶν περὶ τὸν Ῥοδανὸν ἀγαπηθείς. Καὶ Θαλῆν δέ φασιν ἐμπορίᾳ χρήσασθαι καὶ Ἱπποκράτην τὸν μαθηματικόν, καὶ Πλάτωνι τῆς ἀποδημίας ἐφόδιον ἐλαίου τινὸς ἐν Αἰγύπτῳ διάθεσιν γενέσθαι.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://remacle.org/bloodwolf/historiens/Plutarque/solon.htm <u>Plutarque, Vie de Solon</u>], ''chap. II'', ''§3'', traduction par [[w:Dominique_Ricard|Dominique Ricard]], 1844<br />(également disponible une édition de 1853 [https://remacle.org/bloodwolf/historiens/Plutarque/solonpierrron.htm ici] et de 1862 [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f16.item là])</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 390px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''III.''' Mais rien n’empêche l’homme de bien, le citoyen dévoué à son pays, de garder un juste milieu : il peut ne point s’attacher à la poursuite du superflu, sans pour cela mépriser le nécessaire et ce qui suffit à ses besoins.<br />Dans ce temps-là, pour parler comme [[w:Hésiode|'''Hésiode''']] [[#Hésiode|<span id="Hésiode_back"><sup>'''I'''</sup></span>]] [[#Hésiode_NdT_AP|<span id="Hésiode_NdT_AP_back"><sup>1</sup></span>]], il n’y avait pas de travail qui fût honteux; aucun art ne mettait de différence entre les hommes : le négoce surtout était honoré, qui met en possession des avantages dont jouissent les étrangers, gagne l’amitié des rois, et donne une grande expérience. On a même vu des trafiquants fonder de grandes villes : ainsi [[w:Mythe_fondateur_de_Marseille|'''Protis''']] bâtit [[w:Marseille_antique|''Marseille'']], après s'être concilié l’amitié des ''Gaulois'' qui habitent les bords du [[w:Rhône#Histoire|''Rhône'']]. '''Thales''' se livra, dit-on, au négoce, ainsi qu’[[w:Hippocrate_de_Chios|'''Hippocrate''']] [[#Hippocrate|<span id="Hippocrate_back"><sup>'''II'''</sup></span>]] le mathématicien[[#Hippocrate_NdT_AP|<span id="Hippocrate_NdT_AP_back"><sup>2</sup></span>]] ; et [[w:Platon|'''Platon''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Platon|<sup>🔄</sup>]] vendit de l’huile en [[w:Basse_Époque|''Égypte'']] , pour fournir aux frais de son voyage.</div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Hésiode_NdT_AP_back|<span id="Hésiode_NdT_AP"><sup>1.</sup></span>]] Œuvres et Jours, vers 309.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Hippocrate_NdT_AP_back|<span id="Hippocrate_NdT_AP"><sup>2</sup></span>]] Cet Hippocrate n’est point connu d’ailleurs.''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/viesdeshommesill01plut/page/n6/mode/1up?view=theater <u>Vie des Hommes Illustres de Plutarque</u>], [https://archive.org/details/viesdeshommesill01plut/page/182/mode/1up?view=theater ''Solon''], ''Chap. II'', ''§3'', [https://archive.org/details/viesdeshommesill01plut/page/184/mode/1up?view=theater p.184], traduit par [[w:Alexis_Pierron|Alexis Pierron]], professeur au lycée Louis-le-Grand, 1877<br />(également disponible une édition de 1853 [[s:Vies_des_hommes_illustres/Solon|ici]])</div> {{Boîte déroulante début|titre=NdA trad. par Alexis Pierron de 1877|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Hésiode_back|<span id="Hésiode"><sup>I</sup></span>]] Du nom propre grec ancien Ἡσῐ́οδος / Hēsĭ́odos [[wikt:en:Ἡσίοδος#Ancient_Greek|(en)]].<br /><p style="margin: 0 2em; text-indent: 15px">Berger sur les pentes du Mont [[w:Mont_Hélicon|Hélicon]] et un des plus grands poètes grecs. Il s’agit plus précisément d’un ''aède'' (il « chante » ses vers avec sa lyre) et un ''rhapsode'' (il « coud » des chants entre eux)[https://odysseum.eduscol.education.fr/hesiode-un-des-premiers-poetes-grecs {{Info|<sup>🔍</sup>|Hésiode, un des premiers poètes grecs - Odysseum, la maison numérique des Humanités}}]. <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Hippocrate_back|<span id="Hippocrate"><sup>II</sup></span>]] Du nom propre grec ancien Ῐ̔πποκρᾰ́της / Hĭppokrắtēs [[wikt:en:Ἱπποκράτης#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px">➥ du nom commun ῐ̔́ππος / hĭ́ppos [[wikt:en:ἵππος#Ancient_Greek|(en)]], « cheval »;<br /><p style="margin: 0 2em; text-indent: 15px">➥ + du nom commun‎ κρᾰ́τος / krắtos [[wikt:en:κράτος#Ancient_Greek|(en)]], « 1. Puissance, force. 2. Acte de force, acte de bravoure. 3. (au pluriel) Actes de violence. 4. Domination, pouvoir. »;<br /><p style="margin: 0 2em; text-indent: 15px">➥ +‎ du suffixe nominal -ης / -ēs.<br /><p style="margin: 0 2em; text-indent: 15px"> Mathématicien (géomètre) et astronome « para-pythagoricien », dont l’œuvre ne nous est pas parvenue.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] milieu du [[w:Ve_siècle_av._J.-C.|V<sup>ème</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]]) [https://books.google.fr/books?id=DrvWAAAAMAAJ&newbks=1&newbks_redir=0&lpg=PA764&vq=Hippocrate&dq=bibliogroup%3A%22Dictionnaire%20des%20philosophes%20antiques%22&hl=fr&pg=PA764#v=onepage&q&f=true {{Info|<sup>🔍</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume III, §151 - Hippocrate de Chios}}]'''<br/><br/></div> {{Boîte déroulante fin}} <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: center; margin: 0 2em;">'''II. Dans sa jeunesse il se livre au commerce maritime; la modicité de sa fortune et son goût pour la sagesse l’y décident. Faveur du commerce à cette époque ; grands noms qui l’ont illustré.'''<br /><br /><p style="text-align: justify; text-indent: 15px;">Mais rien n’empêche qu’un homme de bien, un sage politique tienne à cet égard un juste milieu, et que sans rechercher des richesses superflues, il ne méprise pas celles qui sont nécessaires et qui suffisent. Dans ce temps-là, comme dit [[w:Hésiode|'''Hésiode''']], aucun travail n’était regardé comme honteux; aucun art ne mettait de différence entre les hommes. Le commerce maritime surtout était honorable; il ouvrait des communications utiles avec les nations étrangères, procurait des alliances avec les rois, et donnait une grande expérience. On a même vu des commerçants fonder de grandes villes. Ainsi '''Protus''' gagna l’amitié des Gaulois qui habitaient les bords du ''Rhône'', et bâtit ''Marseille''. '''Thalès''' et '''Hippocrate''' le mathématicien firent aussi le commerce ; et '''Platon''' vendit de l’huile en ''Égypte'' pour fournir aux frais de son voyage.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f7.item <u>Plutarque, Vie de Solon</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f16.item ''chap. II''], traduction correcte et précédée du texte grec, par une société de professeurs et d’helléniste, 1862<br />(également disponible une édition de 1844 [https://remacle.org/bloodwolf/historiens/Plutarque/solon.htm#1a ici] et de 1829 [[s:Les_Vies_des_hommes_illustres/Vie_de_Solon|là]])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Mais rien n’empêche l’homme de-bien et l’homme politique ni se mettre en souci (rechercher) l’acquisition des choses superflues, ni mépriser l’usage des choses nécessaires et suffisantes. Or dans les temps d’alors, selon '''Hésiode''', aucun travail n’était sujet-de-honte, ni aucun métier n’apportait de différence entre les citoyens mais même le commerce-maritime avait de la gloire, rendant-amies les nations-barbares, et procurant des amitiés de rois, et faisant les hommes expérimentés d’affaires nombreuses. Et quelques-uns aussi sont devenus fondateurs de grandes villes, comme aussi le '''Protus''' de ''Marseille'' ayant été aimé par les ''Celtes'' ceux autour du ''Rhône''. Et on dit aussi '''Thalès''', avoir fait-usage du commerce-maritime et '''Hippocrate''' le mathématicien, et la vente d'une certaine huile en ''Égypte'' avoir été pour '''Platon''' ressource du voyage.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f7.item <u>Plutarque, Vie de Solon</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f16.item ''chap. II''], traduction littérale et juxtalinéaire présentant le mot à mot français en regard des mots grecs correspondants, par une société de professeurs et d’helléniste, 1862</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ====== <div style="text-align: center;">Paragraphe IV.</div> ====== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage de la sagesse de '''Thalès''' en ''philosophie naturelle''</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''IV.''' Φιλοσοφίας δὲ τοῦ ἠθικοῦ μάλιστα τὸ πολιτικόν, ὥσπερ οἱ πλεῖστοι τῶν σοφῶν, ἠγάπησεν. Ἐν δὲ τοῖς φυσικοῖς ἁπλοῦς ἐστι λίαν καὶ ἀρχαῖος, ὡς δῆλον ἐκ τούτων· [...].<br /><p style="text-indent: 15px">Καὶ ὅλως ἔοικεν ἡ Θάλεω μόνου σοφία τότε περαιτέρω τῆς χρείας ἐξικέσθαι τῇ θεωρίᾳ· τοῖς δὲ ἄλλοις ἀπὸ τῆς πολιτικῆς ἀρετῆς τοὔνομα τῆς σοφίας ὑπῆρξε.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://remacle.org/bloodwolf/historiens/Plutarque/solon.htm <u>Plutarque, Vie de Solon</u>], ''chap. II'', ''§4'', traduction par [[w:Dominique_Ricard|Dominique Ricard]], 1844<br />(également disponible une édition de 1853 [https://remacle.org/bloodwolf/historiens/Plutarque/solonpierrron.htm ici] et de 1862 [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f20.item là])</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 390px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''IV.''' Il s’attacha, comme presque tous les sages d’alors, à cette partie de la philosophie morale qui traite de la politique. Pour la philosophie naturelle, il en était aux rudiments, et aux notions du vieux temps sans plus; [...].<br /><p style="text-indent: 15px;">Aussi bien n’y eut-il, en somme, que '''Thalès''' dont la science dépassât alors les notions d’un usage vulgaire : tous les autres ne durent qu’à leurs connaissances politiques leur réputation de sagesse.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/viesdeshommesill01plut/page/n6/mode/1up?view=theater <u>Vie des Hommes Illustres de Plutarque</u>], [https://archive.org/details/viesdeshommesill01plut/page/182/mode/1up?view=theater ''Solon''], ''Chap. II'', ''§4'', [https://archive.org/details/viesdeshommesill01plut/page/185/mode/1up?view=theater p.185], traduit par [[w:Alexis_Pierron|Alexis Pierron]], professeur au lycée Louis-le-Grand, 1877<br />(également disponible une édition de 1853 [[s:Vies_des_hommes_illustres/Solon|ici]])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">A l’exemple des sages de son temps, il cultiva principalement cette partie de la morale qui traite de la politique. Il n’avait en physique que des connaissances très-superficielles, et en était aux premiers éléments de cette science, [...].<br/><p style="text-indent: 15px">En général '''Thalès''' fut, de tous les sages d’alors, le seul qui porta au delà des besoins de la vie la théorie des sciences ; tous les autres ne durent qu’à leurs connaissances politiques leur réputation de sagesse.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f7.item <u>Plutarque, Vie de Solon</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f20.item ''chap. II''], traduction correcte et précédée du texte grec, par une société de professeurs et d’helléniste, 1862<br />(également disponible une édition de 1844 [https://remacle.org/bloodwolf/historiens/Plutarque/solon.htm#1a ici] et de 1829 [[s:Les_Vies_des_hommes_illustres/Vie_de_Solon|là]])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Mais de la partie morale de la philosophie il embrassa surtout la partie politique, comme la plupart des sages d’alors. Mais dans les sciences physiques il est extrêmement simple (ignorant) et primitif, [...]. Et en-un-mot la science de '''Thalès''' seul paraît s’être avancée alors par la théorie plus loin que le besoin ; et le nom de la science a appartenu aux autres par-suite des qualités politiques.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f7.item <u>Plutarque, Vie de Solon</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f21.item ''chap. II''], traduction littérale et juxtalinéaire présentant le mot à mot français en regard des mots grecs correspondants, par une société de professeurs et d’helléniste, 1862</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ====== <div style="text-align: center;">Paragraphe V.</div> ====== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Version alternative du récit de la coupe de [[w:Bathyclès_de_Magnésie|'''Bathyclès''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Bathyclès_back|<sup>🔄</sup>]] par [[w:Callimaque_de_Cyrène|'''Callimaque''']] de [[w:Cyrène|''Cyrène'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Callimaque_back|<sup>🔄</sup>]].</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''V.''' Γενέσθαι δὲ μετ' ἀλλήλων ἔν τε Δελφοῖς ὁμοῦ λέγονται καὶ πάλιν ἐν Κορίνθῳ, Περιάνδρου σύλλογόν τινα κοινὸν αὐτῶν καὶ συμπόσιον κατασκευάσαντος. Ἔτι δὲ μᾶλλον εἰς ἀξίωμα καὶ δόξαν αὐτοὺς κατέστησεν ἡ τοῦ [[w:τρίπους#Grec_ancien|'''τρίποδος''']] περίοδος καὶ διὰ πάντων ἀνακύκλησις καὶ ἀνθύπειξις μετ' εὐμενείας φιλοτίμου γενομένη. Κῴων γάρ, ὥς φασι, καταγόντων σαγήνην, καὶ ξένων ἐκ Μιλήτου πριαμένων τὸν βόλον οὔπω φανερὸν ὄντα, χρυσοῦς ἐφάνη τρίπους ἑλκόμενος, ὃν λέγουσιν Ἑλένην πλέουσαν ἐκ Τροίας αὐτόθι καθεῖναι χρησμοῦ τινος ἀναμνησθεῖσαν παλαιοῦ. Γενομένης δὲ τοῖς ξένοις πρῶτον ἀντιλογίας πρὸς τοὺς ἁλιέας περὶ τοῦ τρίποδος, εἶτα τῶν πόλεων ἀναδεξαμένων τὴν διαφορὰν ἄχρι πολέμου προελθοῦσαν, ἀνεῖλεν ἀμφοτέροις ἡ Πυθία τῷ σοφωτάτῳ τὸν τρίποδα ἀποδοῦναι. Καὶ πρῶτον μὲν ἀπεστάλη πρὸς Θαλῆν εἰς Μίλητον, ἑκουσίως τῶν Κῴων ἑνὶ δωρουμένων ἐκείνῳ περὶ οὗ πρὸς ἅπαντας ὁμοῦ Μιλησίους ἐπολέμησαν. Θάλεω δὲ Βίαντα σοφώτερον ἀποφαίνοντος αὑτοῦ πρὸς ἐκεῖνον ἧκεν· ἀπ' ἐκείνου δ' αὖθις ἀπεστάλη πρὸς ἄλλον ὡς σοφώτερον. Εἶτα περιϊὼν καὶ ἀναπεμπόμενος οὕτως ἐπὶ Θαλῆν τὸ δεύτερον ἀφίκετο, καὶ τέλος εἰς Θήβας ἐκ Μιλήτου κομισθεὶς τῷ Ἰσμηνίῳ Ἀπόλλωνι καθιερώθη. Θεόφραστος δέ φησι,πρῶτον μὲν εἰς Πριήνην Βίαντι τὸν τρίποδα πεμφθῆναι, δεύτερον δ' εἰς Μίλητον Θαλῇ Βίαντος ἀποπέμψαντος· οὕτω δὲ διὰ πάντων πάλιν εἰς Βίαντα περιελθεῖν, τέλος δὲ εἰς Δελφοὺς ἀποσταλῆναι. Ταῦτα μὲν οὖν ὑπὸ πλειόνων τεθρύληται, πλὴν ὅτι τὸ δῶρον ἀντὶ τοῦ τρίποδος οἱ μὲν φιάλην ὑπὸ Κροίσου πεμφθεῖσαν, οἱ δὲ ποτήριον Βαθυκλέους ἀπολιπόντος εἶναι λέγουσιν.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://remacle.org/bloodwolf/historiens/Plutarque/solon.htm <u>Plutarque, Vie de Solon</u>], ''chap. II'', ''§5'', traduction par [[w:Dominique_Ricard|Dominique Ricard]], 1844<br />(également disponible une édition de 1853 [https://remacle.org/bloodwolf/historiens/Plutarque/solonpierrron.htm ici] et de 1862 [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f22.item là])</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 390px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''V.''' On raconte que les sept sages se réunirent une fois à [[w:Delphes|''Delphes'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Delphes_back|<sup>🔄</sup>]], et une autre fois à [[w:Histoire_de_Corinthe_dans_l%27Antiquité|''Corinthe'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Corinthe_back|<sup>🔄</sup>]], où [[w:Périandre|'''Périandre''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Périandre_back|<sup>🔄</sup>]] les avait convoqués pour leur offrir un banquet. Rien ne contribua tant à leur réputation et à leur gloire, que le renvoi qu’ils se firent successivement l’un à l’autre du trépied d’or, et l’honorable humilité avec laquelle ils refusèrent le prix tour à tour. Des hommes de [[w:Kos_(Dodécanèse)#Kos_à_l'époque_hellénistique|''Cos'']] [[#Cos|<span id="Cos_back"><sup>'''I'''</sup></span>]] venaient, dit-on, de jeter leur filet en mer : des étrangers de ''Milet'' achetèrent le coup, avant que les pêcheurs y eussent regardé. Il se trouva, dans le filet, un trépied d’or qu’[[w:Hélène_(mythologie)|'''Hélène''']] [[#Hélène|<span id="Hélène_back"><sup>'''II'''</sup></span>]], à ce qu’on prétend, pour obéir à un ancien oracle, avait jeté dans la mer à son retour de [[w:Troie|''Troie'']] [[#Troie|<span id="Troie_back"><sup>'''III'''</sup></span>]]. Ce fut un sujet de débat, d’abord entre les pêcheurs et les étrangers, ensuite entre les deux villes, qui prirent parti dans la querelle : la guerre allait s’allumer, lorsque la [[w:Pythie|''Pythie'']] [[#Pythie|<span id="Pythie_back"><sup>'''IV'''</sup></span>]], que les deux partis avaient consultée, commanda de donner le trépied au plus sage. On l’envoya d’abord à ''Milet'', pour '''Thalès''', et ceux de ''Cos'' cédèrent sans peine à un seul particulier ce qu’ils allaient disputer par les armes à tous les ''Milésiens'' ensemble. '''Thalès''' déclara que [[w:Bias_de_Priène|'''Bias''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Bias_back|<sup>🔄</sup>]] était plus sage que lui, et le lui fit passer. '''Bias''', avec la même modestie, le fit passer à un autre; et le trépied, après avoir été envoyé successivement à tous les sept, revint une seconde fois à '''Thalès'''. Enfin, il fut transporté de ''Milet'' à [[w:Thèbes_(Grèce)|''Thèbes'']] [[#Thèbes|<span id="Thèbes_back"><sup>'''V'''</sup></span>]], et consacré à Apollon [[w:en:Ismenus|''Isménien'']]. Cependant [[w:Théophaste|'''Théophaste''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Théophaste_back|<sup>🔄</sup>]] dit qu’on envoya le trépied d’abord à '''Bias''', dans ''Priène'' ; que '''Bias''' le fit porter à '''Thalès''' ; qu’après avoir passé alternativement chez tous les sages, il revint à '''Bias''', et qu’il finit par être envoyé à ''Delphes''. Telle est la tradition commune : seulement quelques-uns prétendent qu’il s’agissait de décerner non point un trépied, mais un vase que [[w:Crésus|'''Crésus''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Crésus_back|<sup>🔄</sup>]] avait envoyé ; et, suivant d’autres, c’était une coupe, héritage de '''Bathyclès'''.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/viesdeshommesill01plut/page/n6/mode/1up?view=theater <u>Vie des Hommes Illustres de Plutarque</u>], [https://archive.org/details/viesdeshommesill01plut/page/182/mode/1up?view=theater ''Solon''], ''Chap. II'', ''§5'', [https://archive.org/details/viesdeshommesill01plut/page/185/mode/1up?view=theater p.185], traduit par [[w:Alexis_Pierron|Alexis Pierron]], professeur au lycée Louis-le-Grand, 1877<br />(également disponible une édition de 1853 [[s:Vies_des_hommes_illustres/Solon|ici]])</div> {{Boîte déroulante début|titre=NdA trad. par Alexis Pierron de 1877|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Cos_back|<span id="Cos"><sup>I</sup></span>]] Du nom propre grec ancien Κῶς / Kôs [[wikt:en:Κῶς#Ancient_Greek|(en)]] ;<br /><p style="margin: 0 2em; text-indent: 15px">Île grecque l’archipel du [[w:Dodécanèse|''Dodécanèse'']], au Sud-Est de la [[w:Mer_Égée|''mer Égée'']], au large des côtes ''turques''. <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Hélène_back|<span id="Hélène"><sup>II</sup></span>]] Du nom propre grec ancien Ἑλένη / Helénē [[wikt:en:Ἑλένη#Ancient_Greek|(en)]] ;<br /><p style="margin: 0 2em; text-indent: 15px">Fille de [[w:Zeus|Zeus]] et de [[w:Léda (mythologie)|Léda]], considérée comme la plus belle femme du monde, uniquement surpassée par la déesse [[w:Aphrodite|Aphrodite]]. Elle est mariée à [[w:Ménélas|Ménélas]], roi de [[w:Sparte|Sparte]], et est enlevée par [[w:Pâris|Pâris]], prince [[w:Troie|''troyen'']] [[#Troie|<sup>'''III'''</sup>]], ce qui déclencha la [[w:guerre de Troie|guerre de Troie]] qui opposa ''Grecs'' et ''Troyens''. <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Troie_back|<span id="Troie"><sup>III</sup></span>]] Du nom propre grec ancien Τροίᾱ / Troíā [[wikt:en:Τροία#Ancient_Greek|(en)]] ; [[w:Troie#Toponymie|''toponymie incertaine'']] ;<br /><p style="margin: 0 2em; text-indent: 15px"> Cité semi-légendaire, située sur la colline d’''[[w:site archéologique de Troie|{{lang|tr|Hisarlık}}]]'', à l’entrée de l’''[[w:Hellespont|Hellespont]]'', non loin de la ''[[w:mer Égée|mer Égée]]'', au nord-ouest de la ''péninsule anatolienne'', dans la région ''[[w:Troade|Troade]]'' en ''[[w:Asie Mineure|Asie Mineure]]''.<br /><p style="margin: 0 2em; text-indent: 15px"> Le site a fait l’objet de nombreuses campagnes de fouilles, à la suite de celles entreprises par [[w:Heinrich Schliemann|Heinrich Schliemann]] en 1870, ponctuées par des découvertes fortement médiatisées, qui ont popularisé son identification avec la Troie homérique (qui reste un sujet de débat en l’absence de preuve décisive), le lieu principal des événements du ''[[w:cycle troyen|cycle troyen]]'' rapportés dans les ''[[w:Épopée|poèmes épiques]]'' ''[[w:Homère|homériques]]'' l’''[[w:Iliade|Iliade]]'' et l’''[[w:Odyssée|Odyssée]]''. <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Pythie_back|<span id="Pythie"><sup>IV</sup></span>]] Du nom commun grec ancien Πῡθῐ́ᾱ / Pūthĭ́ā,<br /><p style="margin: 0 2em; text-indent: 15px">➥ du nom propre Πῡθώ / Pūthṓ, « [[w:Delphes#Histoire_du_site|''Pythô'']], ancien nom de ''Delphes'' » ;<br /><p style="margin: 0 2em; text-indent: 15px">➥ +‎ du suffixe adjectival féminin -ῐος / -ĭos [[wikt:en:-ιος#Ancient_Greek|(en)]], « relatif à, appartenant à (de) ».<br /><p style="margin: 0 2em; text-indent: 15px">[[w:Divination_dans_la_Grèce_antique|''Oracle'']] du [[w:Temple_d%27Apollon_(Delphes)|''temple d’Apollon'']] à ''Delphes''.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:XIVe_siècle_av._J.-C.|XIV<sup>ème</sup>]]/[[w:VIIIe_siècle_av._J.-C.|VIII<sup>ème</sup>]] siècles {{Info|AEC|Avant l’Ère Commune}} — [[w:IVe_siècle_av._J.-C.|IV<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]]) <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Thèbes_back|<span id="Thèbes"><sup>V</sup></span>]] Du nom propre grec ancien Θῆβαι / Thêbai [[wikt:en:Θῆβαι#Ancient_Greek|(en)]], désigne indistinctement la cité ''grecque'' comme [[w:Thèbes_(Égypte)|celle ''égyptienne'']] ; mais leur étymologie diffère :<br /><p style="margin: 0 2em; text-indent: 15px;">➥ pour celle de la cité grecque, de l’[[w:Ionien-attique|''ionien-attique'']] Θήβη / Thḗbē ; du grec mycénien 𐀳𐀣 / te-qa (/Tʰēgʷā/) ;<br /><p style="margin: 0 2em; text-indent: 15px;">(➥ pour celle de la cité égyptienne, de l’égyptien démotique tꜣ-jpy, « Thèbes, littéralement "le temple" » ;<br /><p style="margin: 0 2em; text-indent: 30px;">➥ de l’article défini tꜣ [[wikt:en:tꜣ#Demotic_Egyptian|(en)]], « le/la » ;<br /><p style="margin: 0 2em; text-indent: 30px;">➥ + du nom propre et commun jpt [[wikt:en:jpt#Etymology_3|(en)]], « Louxor, littéralement "sanctuaire intérieur" »).<br /><p style="margin: 0 2em; text-indent: 15px">Cité grecque de la région de [[w:Béotie#Antiquité|''Béotie'']], au centre de la ''Grèce''.'''<br/><br/></div> {{Boîte déroulante fin}} <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">On raconte que les sept sages se trouvèrent un jour ensemble à ''Delphes'', et une autre fois à ''Corinthe'', chez '''Périandre''', qui les avait réunis pour un banquet. Rien ne contribua autant à leur réputation et à leur gloire, que la modestie empressée avec laquelle ils se renvoyèrent l’un à l’autre le trépied d’or. Des ''Milésiens'' qui se trouvaient à l’île de ''Cos'', avaient acheté d’avance de quelques pêcheurs ce que retirerait de l’eau le filet qu’ils allaient y jeter. Quand on l’eut tiré, il s’y trouva un trépied d’or qu’'''Hélène''', à ce qu’on prétend, pour obéir à un oracle, avait jeté dans la mer, à son retour de ''Troie''. Cet incident donna lieu à une vive dispute d’abord entre les pêcheurs et les étrangers, ensuite entre les deux villes, qui prirent parti dans la querelle et étaient près d’en venir aux mains, lorsque la ''Pythie'' consultée leur ordonna de porter ce trépied au plus sage. On l’envoya d’abord à '''Thalès''', et ceux de ''Cos'' cédèrent sans peine à un seul particulier ce qu’ils allaient disputer par les armes à tous les ''Milésiens'' ensemble. '''Thalès''' le renvoya à '''Bias''', qui, disait-il, était plus sage que lui ; '''Bias''', avec la même modestie, le fit passer à un autre ; et après avoir été envoyé successivement à tous les sept, il revint une seconde fois à '''Thalès''' : enfin il fut porté à ''Thèbes'', et consacré à ''Apollon Isménien''. '''Théophraste''' dit qu’on l’envoya d’abord à '''Bias''', qui demeurait à ''Priène'' ; que '''Bias''' le fit porter à '''Thalès''' ; qu’après avoir été envoyé alternativement à tous les sages, il revint à '''Bias''', et qu’enfin il fut porté à ''Delphes''. Telle est la tradition la plus commune sur ce fait ; seulement quelques auteurs disent que ce n’était pas un trépied, mais un vase que '''Crésus''' envoyait à ''Delphes''; suivant d’autres, c’était une coupe que '''Bathyclès''' avait laissée.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f7.item <u>Plutarque, Vie de Solon</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f22.item ''chap. II''], traduction correcte et précédée du texte grec, par une société de professeurs et d’helléniste, 1862<br />(également disponible une édition de 1844 [https://remacle.org/bloodwolf/historiens/Plutarque/solon.htm#1a ici] et de 1829 [[s:Les_Vies_des_hommes_illustres/Vie_de_Solon|là]])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Or ils (les sept sages) sont dits s’être trouvés aussi ensemble les uns avec les autres et à ''Delphes'' et de nouveau à ''Corinthe'', '''Périandre''' ayant préparé une certaine réunion commune d’eux et un banquet. Or le tour du trépied, et sa circulation à travers tous et sa cession se faisant avec une bienveillance pleine-d’émulation mit eux encore davantage en considération et renommée. Car des ''habitants-de-Cos'', comme on dit, jetant le filet, et des hôtes venus de ''Milet'' ayant acheté le coup qui n’était pas encore apparent, un trépied d’-or apparut étant retiré, lequel on dit '''Hélène''' naviguant pour revenir de ''Troie'' avoir jeté là, s’étant souvenue d’un certain oracle ancien. Mais une contestation ayant eu lieu d’abord aux hôtes vis-à-vis des pécheurs au sujet du trépied, ensuite les villes ayant pris-sur-elles le différend qui alla jusqu'à une guerre, la ''Pythie'' répondit aux-uns-et-aux-autres de donner le trépied au plus sage des hommes. Et d’abord il fut envoyé à '''Thalès''' à ''Milet'', les ''habitants-de-Cos'' donnant volontairement à celui-là seul le trépied, au sujet duquel ils avaient fait-la-guerre contre tous les ''Milésiens'' à-la-fois. Mais '''Thalès''' déclarant '''Bias''' plus sage que lui-même, il renvoya vers celui-là. Et de nouveau il fut envoyé par celui-là vers un autre, comme plus sage. Ensuite faisant-le-tour et étant envoyé-successivement ainsi il arriva pour la seconde fois à '''Thalès''' ; et à la fin transporté de ''Milet'' à ''Thèbes'', il fut consacré à ''Apollon Isménien''. Mais '''Théophraste''' dit le trépied avoir été envoyé d’abord à la vérité à ''Priène'' à '''Bias''', mais en-second-lieu à ''Milet'' à '''Thalès''', '''Bias''' l’ayant renvoyé ; et ainsi à travers tous (de l’un à l’autre) être venu-en-faisant-le-tour de nouveau à '''Bias''', et à la fin avoir été envoyé à ''Delphes''. Ces choses donc ont été répandues par plusieurs, excepté qu’ils disent le présent au lieu du trépied les uns être un vase à boire envoyé par '''Crésus''', les autres une coupe. '''Bathyclès''' rayant laissée (laissée par '''Bathyclès'''). </div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f7.item <u>Plutarque, Vie de Solon</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f23.item ''chap. II''], traduction littérale et juxtalinéaire présentant le mot à mot français en regard des mots grecs correspondants, par une société de professeurs et d’helléniste, 1862</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Chapitre VI.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;"> Récit d’une entrevue de '''Thalès''' avec '''Solon''', de son stoïcisme, de son célibat et de l’adoption du fils de sa sœur, '''Cybistus'''.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;"> '''VI.''' Ἰδίᾳ δ' Ἀναχάρσεώς τε πρὸς Σόλωνα καὶ πάλιν Θάλεω συνουσίαν τινὰ καὶ λόγους ἀναγράφουσι τοιούτους. [...]<br /><p style="text-indent: 15px"> '''VII.''' Πρὸς Θαλῆν δ' εἰς Μίλητον ἐλθόντα τὸν Σόλωνα θαυμάζειν ὅτι γάμου καὶ παιδοποιΐας τὸ παράπαν ἠμέληκε. Καὶ τὸν Θαλῆν τότε μὲν σιωπῆσαι, διαλιπόντα δ' ὀλίγας ἡμέρας ἄνδρα παρασκευάσαι ξένον, ἀρτίως ἥκειν φάσκοντα δεκαταῖον ἐξ Ἀθηνῶν. Πυθομένου δὲ τοῦ Σόλωνος εἰ δή τι καινὸν ἐν ταῖς Ἀθήναις, δεδιδαγμένον ἃ χρὴ λέγειν τὸν ἄνθρωπον, « οὐδέν,» εἰπεῖν, « ἕτερον, εἰ μὴ νὴ Δία νεανίσκου τινὸς ἦν ἐκφορὰ καὶ προὔπεμπεν ἡ πόλις. Ἦν γὰρ υἱός, ὡς ἔφασαν, ἀνδρὸς ἐνδόξου καὶ πρωτεύοντος ἀρετῇ τῶν πολιτῶν· οὐ παρῆν δέ, ἀλλ' ἀποδημεῖν ἔφασαν αὐτὸν ἤδη πολὺν χρόνον.» « Ὡς δυστυχὴς ἐκεῖνος,» φάναι τὸν Σόλωνα. « Τίνα δὲ ὠνόμαζον αὐτόν;» « ἤκουσα,» φάναι, « τοὔνομα,» τὸν ἄνθρωπον, « ἀλλ' οὐ μνημονεύω· πλὴν ὅτι πολὺς λόγος ἦν αὐτοῦ σοφίας καὶ δικαιοσύνης.» Οὕτω δὴ καθ' ἑκάστην ἀπόκρισιν τῷ φόβῳ προσαγόμενον τὸν Σόλωνα καὶ τέλος ἤδη συντεταραγμένον αὐτὸν ὑποβάλλειν τοὔνομα τῷ ξένῳ, πυνθανόμενον μὴ Σόλωνος ὁ τεθνηκὼς υἱὸς ὠνομάζετο. Φήσαντος δὲ τοῦ ἀνθρώπου, τὸν μὲν ὁρμῆσαι παίειν τὴν κεφαλὴν καὶ τἆλλα ποιεῖν καὶ λέγειν ἃ συμβαίνει τοῖς περιπαθοῦσι, τὸν δὲ Θαλῆν ἐπιλαβόμενον αὐτοῦ καὶ γελάσαντα, « ταῦτά τοι,» φάναι, « ὦ Σόλων, ἐμὲ γάμου καὶ παιδοποιΐας ἀφίστησιν, ἃ καὶ σὲ κατερείπει τὸν ἐρρωμενέστατον. Ἀλλὰ θάρρει τῶν λόγων ἕνεκα τούτων· οὐ γάρ εἰσιν ἀληθεῖς.» ταῦτα μὲν οὖν Ἕρμιππος ἱστορεῖν φησι Πάταικον, ὃς ἔφασκε τὴν Αἰσώπου ψυχὴν ἔχειν.<br /><p style="text-indent: 15px">'''VIII.''' Ἄτοπος δὲ καὶ ἀγεννὴς ὁ τῷ φόβῳ τῆς ἀποβολῆς τὴν κτῆσιν ὧν χρὴ προϊέμενος· οὕτω γὰρ ἄν τις οὐ πλοῦτον, οὐ δόξαν, οὐ σοφίαν ἀγαπήσειε παραγενομένην, δεδιὼς στέρεσθαι. Καὶ γὰρ ἀρετήν, ἧς κτῆμα μεῖζον οὐδὲν οὐδ' ἥδιον, ἐξισταμένην ὑπὸ νόσων καὶ φαρμάκων ὁρῶμεν· αὐτῷ τε '''Θαλῇ''' μὴ γήμαντι πλέον οὐδὲν εἰς ἀφοβίαν, εἰ μὴ καὶ φίλων κτῆσιν ἔφυγε καὶ οἰκείων καὶ πατρίδος. Ἀλλὰ καὶ παῖδα θετὸν ἔσχε ποιησάμενος αὐτὸς τὸν τῆς ἀδελφῆς, ὥς φασι, '''Κύβισθον'''.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://remacle.org/bloodwolf/historiens/Plutarque/solon.htm <u>Plutarque, Vie de Solon</u>], ''chap. II'', ''§§6-8'', traduction par [[w:Dominique_Ricard|Dominique Ricard]], 1844<br />(également disponible une édition de 1853 [https://remacle.org/bloodwolf/historiens/Plutarque/solonpierrron.htm ici] et de 1862 [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f26.item là])</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 390px; border: 2px solid; text-indent: 15px"><br /><div style="margin: 0 2em; text-align: justify; direction: ltr;">'''VI.''' '''Solon''' connut [[w:Anacharsis|'''Anacharsis''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Anacharsis_back|<sup>🔄</sup>]] et '''Thalès''', et l’on cite des mots qui s’étaient dits dans leurs entrevues. <br /><p style="text-align: center"> [...]<br /><p style="text-indent: 15px; text-align: justify;">'''Solon''' alla à ''Milet'', pour voir '''Thalès''' : là, il lui témoigna sa surprise dans ce qu’il n’avait jamais voulu se marier et avoir des enfants. '''Thalès''' ne répondit rien sur l’heure; mais, quelques jours après, il fit paraître un étranger, qui disait arriver d’''Athènes'', et qu’il n’en était parti que depuis dix jours. '''Solon''' demanda à cet homme s’il n’y avait rien de nouveau à ''Athènes''. Celui-ci, à qui '''Thalès''' avait fait la leçon, répondit qu’il n’y avait rien de nouveau , sinon la mort d’un jeune homme dont toute la ville menait les funérailles. C’était, en effet, à ce qu’on disait, le fils d’un personnage considérable, d’une vertu éprouvée : le père n’était pas alors à ''Athènes'', et il voyageait depuis longtemps. « L’infortuné père! s’écria '''Solon'''. Mais comment s’appelait-il? — Je l’ai entendu nommer, répondit l’étranger, mais j’ai oublié son nom ; je me souviens seulement qu’on ne parlait que de sa sagesse et de sa justice. » A chacune de ces réponses, '''Solon''' sentait augmenter ses craintes; enfin, ne se possédant plus , il suggéra le nom à l’étranger, et lui demanda si le mort n’était pas le fils de '''Solon'''. « Oui. » répondit l’étranger. A cette parole, '''Solon''' se frappa la tête, et il se mit à faire et à dire tout ce qu’inspire une douleur violente. Alors '''Thalès''' lui prit la main, et lui dit en riant : « Voilà, '''Solon''', ce qui m’éloigne de me marier et d’avoir des enfants. J’ai redouté le coup sous lequel tu fléchis, toi le plus ferme des hommes. Mais rassure-toi; car il n’y a rien de vrai dans tout ce qu’on vient de te dire. » [[w:Hermippe_de_Smyrne|'''Hermippus''']] [[#Hermippe|<span id="Hermippe_back"><sup>'''I'''</sup></span>]] rapporte cette histoire d’après '''Patécus''', celui qui prétendait avoir hérité de l’âme d’[[w:Ésope|'''Ésope''']] [[#Ésope|<span id="Ésope_back"><sup>'''II'''</sup></span>]].<br /><p style="text-indent: 15px">Pourtant il y a faute de sens et de cœur à refuser d’acquérir les choses nécessaires, par la crainte de les perdre. A ce compte, on devra n’aimer ni la richesse, ni la gloire, ni la sagesse, quand on les possède, de peur d’en être privé. En effet, la vertu, le plus grand des biens et le plus doux, nous quitte quelquefois par l’action de certaines maladies ou de certains breuvages. '''Thalès''' lui-même, en ne se mariant point, n’était pas pour cela à l’abri de la crainte, à moins qu’il n'eût renoncé aussi à ses parents, à ses amis, à sa patrie. Mais il n’en était rien : il avait adopté, dit-on, '''Cybisthus''', le fils de sa sœur. </div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/viesdeshommesill01plut/page/n6/mode/1up?view=theater <u>Vie des Hommes Illustres de Plutarque</u>], [https://archive.org/details/viesdeshommesill01plut/page/182/mode/1up?view=theater ''Solon''], ''Chap. II'', ''§6'', [https://archive.org/details/viesdeshommesill01plut/page/185/mode/1up?view=theater p.185], traduit par [[w:Alexis_Pierron|Alexis Pierron]], professeur au lycée Louis-le-Grand, 1877<br />(également disponible une édition de 1853 [[s:Vies_des_hommes_illustres/Solon|ici]])</div> {{Boîte déroulante début|titre=NdA trad. par Alexis Pierron de 1877|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Hermippe_back|<span id="Hermippe"><sup>I</sup></span>]] Du nom propre [[w:Nom_théophore|''théophore'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#théophore_back|<sup>🔄</sup>]] grec ancien Ἕρμιππος / Hérmippos [[wikt:en:Ἕρμιππος#Ancient_Greek|(en)]] ;<br /><p style="margin: 0 2em; text-indent: 15px">➥ du nom propre Ἑρμῆς / Hermês [[wikt:en:Ἑρμῆς#Ancient_Greek|(en)]], « Hermès » ;<br /><p style="margin: 0 2em; text-indent: 15px">➥ +‎ du nom commun ἵππος / híppos [[wikt:en:ἵππος#Ancient_Greek|(en)]], « cheval » ;<br /><p style="margin: 0 2em; text-indent: 15px">« Péripatéticien » grec, disciple de [[w:Callimaque_de_Cyr%C3%A8ne|Callimaque de ''Cyrène'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Callimaque_back|<sup>🔄</sup>]], auteur de nombreuses biographies toutes perdues, mais listées par plusieurs auteurs.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] seconde moitié du [[w:IIIe_siècle_av._J.-C.|III<sup>ème</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]]) [https://books.google.fr/books?id=DrvWAAAAMAAJ&newbks=1&newbks_redir=0&lpg=PA497&dq=bibliogroup%3A%22Dictionnaire%20des%20philosophes%20antiques%22&hl=fr&pg=PA655#v=onepage&q&f=false {{Info|<sup>🔍</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume III, §86 - Hermippe de Smyrne}}] <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Ésope_back|<span id="Ésope"><sup>II</sup></span>]] Du nom propre grec ancien Αἴσωπος / Aísōpos [[wikt:en:Αἴσωπος#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px">➥ du nom commun αἶσα / aîsa, « destin »;<br /><p style="margin: 0 2em; text-indent: 15px">➥ +‎ du nom commun ὄψ / óps, « voix »;<br /><br /><p style="margin: 0 2em; text-indent: 15px">Auteur grec de fable.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] seconde moitié du [[w:VIe_siècle_av._J.-C.|VI<sup>ème</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]]) [https://books.google.fr/books?id=DrvWAAAAMAAJ&newbks=1&newbks_redir=0&lpg=PA497&dq=bibliogroup%3A%22Dictionnaire%20des%20philosophes%20antiques%22&hl=fr&pg=PA240#v=onepage&q&f=false {{Info|<sup>🔍</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume III, §60 - Ésope(Αἴσωπος)}}]'''<br/><br/></div> {{Boîte déroulante fin}} <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">'''V.''' Voici les particularités qu’on raconte d’une entrevue de '''Solon''' avec '''Anacharsis''', et d’un entretien qu’il eut avec '''Thalès'''.<br /><p style="text-align: center"> [...]<br /><p style="text-indent: 15px; text-align: justify;">'''VI.''' '''Solon''', étant allé à ''Milet'' pour voir '''Thalès''', lui témoigna sa surprise de ce qu’il n’avait jamais voulu se marier et avoir des enfants. '''Thalès''' ne lui répondit rien dans le moment; mais ayant laissé passer quelques jours, il fit paraître un étranger qui disait arriver d’''Athènes'', d’où il était parti depuis dix jours. '''Solon''' lui demanda s’il n’y avait rien de nouveau, lorsqu’il en était parti. Cet homme, à qui '''Thalès''' avait fait la leçon, lui répondit qu’il n’y avait autre chose que la mort d’un jeune homme dont toute la ville accompagnait le convoi. C’était, disait-on, le fils d’un des premiers et des plus vertueux citoyens, qui n'’était pas alors à ''Athènes'' et qui voyageait depuis longtemps, « Le malheureux père! s’écria Solon. Comment s’appelle-t-il? ― Je l’ai entendu nommer, répondit l’étranger; mais j’ai oublié son nom; je me souviens seulement qu’on ne parlait que de sa sagesse et de sa justice. » A chacune de ces réponses, les craintes de '''Solon''' augmentaient; enfin, troublé, hors de lui-même, il suggéra le nom à l’étranger, et lui demanda si ce jeune homme n’était pas le fils de '''Solon'''. « C’est lui-même, » dit l’autre. A cette parole, '''Solon''', se frappant la tête, se mit à faire et à dire tout ce que la douleur la plus violente peut inspirer. Alors '''Thalès''' l’arrêta et lui dit en souriant : « Voilà, '''Solon''', ce qui m’a éloigné de me marier et d’avoir des enfants; j’ai redouté le coup qui vous accable aujourd’hui, et contre lequel toute votre fermeté est impuissante. Mais rassurez-vous ; il n’y a rien de vrai dans tout ce qu’on vient de vous dire. » '''Hermippus''' rapporte cette histoire d’après le récit qu’en fait '''Patécus''', qui prétendait avoir hérité de l’âme d’'''Ésope'''.<br /><p style="text-indent: 15px; text-align: justify;">'''VII.''' Cependant c’est manquer de sens et de courage que de renoncer à acquérir des choses nécessaires par la crainte de les perdre. A ce compte, il ne faudrait aimer ni la richesse, ni la gloire, ni la sagesse, quand on les possède, de peur d’en être privé. La vertu même, le plus grand et le plus agréable des biens, se perd souvent par l’effet. de quelques maladies ou de certains breuvages. '''Thalès''' lui-même, en ne se mariant point, n’était pas à l’abri de toute crainte, à moins qu’il ne renonçât aussi à ses parents, à ses amis et à sa patrie. Mais au contraire, il avait adopté '''Cybistus''', le fils de sa sœur. </div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f7.item <u>Plutarque, Vie de Solon</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f26.item ''chap. II''], traduction correcte et précédée du texte grec, par une société de professeurs et d’helléniste, 1862<br />(également disponible une édition de 1844 [https://remacle.org/bloodwolf/historiens/Plutarque/solon.htm#1a ici] et de 1829 [[s:Les_Vies_des_hommes_illustres/Vie_de_Solon|là]])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">'''V.''' Mais en particulier on rapporte une certaine entrevue et de tels discours et d’'''Anacharsis''' à '''Solon''' et une-autre-fois de '''Thalès'''.<br /><p style="text-align: center"> [...]<br /><p style="text-indent: 15px; text-align: justify;">'''VI.''' Et on raconte '''Solon''' étant venu vers '''Thalès''' à ''Milet'' s’étonner de ce qu’il avait négligé absolument le mariage et la création-d’enfants. Et '''Thalès''' alors à la vérité s’être tu, mais ayant laissé-d’intervalle peu-de jours, avoir aposté un homme étranger, disant être arrivé récemment parti-depuis-dix-jours d’''Athènes''. Et '''Solon''' s’étant informé si donc il y a quelque chose de nouveau à ''Athènes'', l’homme instruit des choses qu’il faut dire n’avoir dit aucune autre chose, si ce n’est :<br /><p style="text-indent: 15px"> « Par '''Jupiter''', il y avait le convoi d’un certain jeune-homme, et la ville l’accompagnait. Car il était fils, comme on disait, d’un homme illustre et étant-le-premier des citoyens par la vertu; mais il n’était-pas-présent, mais on disait lui être-en-voyage depuis un temps déjà long.<br /><p style="text-align: left; text-indent: 15px">― Combien cet homme-là est malheureux! avoir dit '''Solon'''. Mais quel (comment) appelaient-ils lui ?<br /><p style="text-align: left; text-indent: 15px">― J’ai entendu le nom, avoir dit l’homme (répondit l’étranger), mais je ne me le rappelle pas; excepté qu’un discours fréquent était de la sagesse et de la justice de lui. »<br /><p style="text-indent: 15px">'''Solon''' donc étant-approché ainsi de-la crainte à chaque réponse, et à la fin déjà étant tout-troublé, lui-même avoir suggéré le nom à l’étranger, demandant si le mort n’était pas nommé fils de '''Solon'''. Et l’homme ayant dit-oui, celui-ci ('''Solon''') avoir commencé à frapper sa tête, et à faire et à dire les autres choses, qu’il arrive de faire et de dire à ceux affligés-à-l’excès. Mais '''Thalès''' ayant arrêté lui, et ayant ri, avoir dit :<br /><p style="text-indent: 15px">« Ces choses donc, ô '''Solon''', écartent moi du mariage et de la création-d’enfants, lesquelles abattent même toi le très-fort. Mais aie-confiance quant-à ces discours: car ils ne sont pas vrais. »<br /><p style="text-indent: 15px">'''Hermippe''' donc dit '''Patécus''', qui disait-souvent avoir l’âme d’'''Ésope''', raconter ces choses. <br /><p style="text-indent: 15px">'''VII.''' Or il est absurde et dépourvu de courage celui rejetant par la crainte de la perte l’acquisition des choses qu’il faut; car ainsi quelqu’un n’aimerait pas la richesse, n’aimerait pas la gloire, n’aimerait pas la sagesse étant survenue à lui, craignant (par crainte) d’en être privé. Et en effet nous voyons la vertu, au prix de laquelle aucune possession n’est plus grande, ni plus agréable, déplacée (chassée) par des maladies et des breuvages; et rien de plus n’être pour l’exemption-de-crainte à '''Thalès''' lui-même ne s’étant pas marié, s’il n’avait pas évité la possession et d’amis et de parents et de patrie. Mais même il eut un fils adoptif se l’étant fait tel lui-même, celui de sa sœur, comme on dit '''Cybisthe'''.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f7.item <u>Plutarque, Vie de Solon</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f27.item ''chap. II''], traduction littérale et juxtalinéaire présentant le mot à mot français en regard des mots grecs correspondants, par une société de professeurs et d’helléniste, 1862</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ====== <div style="text-align: center;">Paragraphe XV.</div> ====== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;"> Testament d’inhumation de '''Thalès'''.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''XV.''' Καὶ φόβοι τινὲς ἐκ δεισιδαιμονίας ἅμα καὶ φάσματα κατεῖχε τὴν πόλιν, οἵ τε μάντεις ἄγη καὶ μιασμοὺς δεομένους καθαρμῶν προφαίνεσθαι διὰ τῶν ἱερῶν ἠγόρευον. Οὕτω δὴ μετάπεμπτος αὐτοῖς ἧκεν ἐκ Κρήτης Ἐπιμενίδης ὁ Φαίστιος, ὃν ἕβδομον ἐν τοῖς σοφοῖς καταριθμοῦσιν ἔνιοι τῶν οὐ προσιεμένων τὸν Περίανδρον. Ἐδόκει δέ τις εἶναι θεοφιλὴς καὶ σοφὸς περὶ τὰ θεῖα τὴν ἐνθουσιαστικὴν καὶ τελεστικὴν σοφίαν, διὸ καὶ παῖδα νύμφης ὄνομα Βάλτης καὶ Κούρητα νέον αὐτὸν οἱ τότε ἄνθρωποι προσηγόρευον. <br /><p style="text-align: center">[...]<br /><p style="text-indent: 15px; text-align: justify;">Τὸ δὲ μέγιστον, ἱλασμοῖς τισι καὶ καθαρμοῖς καὶ ἱδρύσεσι κατοργιάσας καὶ καθοσιώσας τὴν πόλιν ὑπήκοον τοῦ δικαίου καὶ μᾶλλον εὐπειθῆ πρὸς ὁμόνοιαν κατέστησε. Λέγεται δὲ τὴν Μουνυχίαν ἰδὼν καὶ καταμαθὼν πολὺν χρόνον, εἰπεῖν πρὸς τοὺς παρόντας ὡς τυφλόν ἐστι τοῦ μέλλοντος ἄνθρωπος· ἐκφαγεῖν γὰρ ἂν Ἀθηναίους τοῖς αὑτῶν ὀδοῦσιν, εἰ προῄδεσαν ὅσα τὴν πόλιν ἀνιάσει τὸ χωρίον· ὅμοιον δέ τι καὶ Θαλῆν εἰκάσαι λέγουσι· κελεῦσαι γὰρ αὐτὸν ἔν τινι τόπῳ τῆς Μιλησίας φαύλῳ καὶ παρορωμένῳ τελευτήσαντα θεῖναι, προειπὼν ὡς ἀγορά ποτε τοῦτο Μιλησίων ἔσται τὸ χωρίον. Ἐπιμενίδης μὲν οὖν μάλιστα θαυμασθείς, καὶ χρήματα διδόντων πολλὰ καὶ τιμὰς μεγάλας τῶν Ἀθηναίων, οὐδὲν ἢ θαλλὸν ἀπὸ τῆς ἱερᾶς ἐλαίας αἰτησάμενος καὶ λαβὼν ἀπῆλθεν. </div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://remacle.org/bloodwolf/historiens/Plutarque/solon.htm <u>Plutarque, Vie de Solon</u>], ''chap. II'', ''§15'', traduction par [[w:Dominique_Ricard|Dominique Ricard]], 1844<br />(également disponible une édition de 1853 [https://remacle.org/bloodwolf/historiens/Plutarque/solonpierrron.htm ici] et de 1862 [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f26.item là])</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 390px; border: 2px solid; text-indent: 15px"><br /><div style="margin: 0 2em; text-align: justify; direction: ltr;">'''XV.''' Au chagrin que ces pertes causèrent à ceux-ci [les ''Athéniens''], se joignirent des craintes superstitieuses dont la ville [''Athènes''] fut frappée, et qui venaient d’apparitions de spectres et de fantômes. Les devins déclarèrent aussi que l’état des victimes qu’ils avaient offertes annonçait des crimes et des profanations qu’il fallait expier. On fit donc venir de ''Crète'' [[w:Épiménide|'''Épiménide''']] [[#Épiménide|<span id="Épiménide_back"><sup>'''I'''</sup></span>]] le [[w:Phaistos|''Phestien'']] [[#Phaistos|<span id="Phaistos_back"><sup>'''II'''</sup></span>]], qui est mis au nombre des sept sages par ceux qui n’y comptent pas '''Périandre'''. Il passait pour un homme chéri des dieux, doué d’une grande sagesse, fort instruit des choses divines, surtout versé dans la science des inspirations et dans la connaissance des mystères; on l’appelait, même de son vivant, le nouveau [[w:Curètes|'''Curète''']], le fils de la nymphe '''Balté'''.<br /><p style="text-align: center">[...]<br /><p style="text-indent: 15px; text-align: justify;">Mais ce qui était plus important, il fit un grand nombre d’expiations et de sacrifices, il fonda plusieurs temples; et par ces différentes cérémonies il purifia entièrement la ville, en bannit l’impiété et l’injustice, et la rendit plus soumise, plus disposée à l’union et à la paix. On rapporte aussi que lorsqu’il vit le fort de [[w:Munichie|''Munychium'']] [[#Munichie|<span id="Munichie_back"><sup>'''III'''</sup></span>]], il le considéra longtemps, et dit à ceux qui l’accompagnaient : Que les hommes sont aveugles sur l’avenir ! Si les ''Athéniens'' pouvaient prévoir tous les maux que ce lieu doit un jour causer à leur ville, ils l’emporteraient à belles dents ». '''Thalès''' eut aussi, dit-on, un pressentiment à peu près semblable. Il ordonna qu’on l’enterrât dans le lieu le plus sauvage et le plus désert du territoire de ''Milet''; et il prédit aux ''Milésiens'' qu’un jour leur marché public y serait transporté. Les ''Athéniens'', pleins de reconnaissance et d’admiration pour '''Épiménide''', voulurent le combler d’honneurs et de présents; mais il ne demanda qu’une branche de l’olivier sacré, qui lui fut accordée, et il s’en retourna en ''Crète''.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/viesdeshommesill01plut/page/n6/mode/1up?view=theater <u>Vie des Hommes Illustres de Plutarque</u>], [https://archive.org/details/viesdeshommesill01plut/page/182/mode/1up?view=theater ''Solon''], ''Chap. II'', ''§15'',[https://archive.org/details/viesdeshommesill01plut/page/185/mode/1up?view=theater p.185], traduit par [[w:Alexis_Pierron|Alexis Pierron]], professeur au lycée Louis-le-Grand, 1877<br />(également disponible une édition de 1853 [[s:Vies_des_hommes_illustres/Solon|ici]])</div> {{Boîte déroulante début|titre=NdA trad. par Alexis Pierron de 1877|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Épiménide_back|<span id="Épiménide"><sup>I</sup></span>]] Du nom propre grec ancien Ἐπιμενίδης / Epimenídēs [[wikt:en:Ἐπιμενίδης#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px">Poète, philosophe et [[w:Iatromante|''iatromante'']] crétois.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] milieu du [[w:VIe_siècle_av._J.-C.|VI<sup>ème</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]]) <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Phaistos_back|<span id="Phaistos"><sup>II</sup></span>]] Du nom propre grec ancien Φαιστός / Phaistós [[wikt:en:Φαιστός#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px">Ancienne ville du Sud de la [[w:Histoire_de_la_Crète#Antiquité|''Crète'']].<br /><br /><p style="margin: 0 2em; text-indent: 15px">[[#Munichie_back|<span id="Munichie"><sup>III</sup></span>]] Du nom propre grec ancien Μουνιχία / Mounikhia [[wikt:en:Μουνυχία#Grec_ancien|(en)]] ;<br /><p style="margin: 0 2em; text-indent: 15px">Nom d’une colline du [[w:Le_Pirée|''Pirée'']] et de l’[[w:Port_de_Munichie|un des ports du ''Pirée'']].'''<br/><br/></div> {{Boîte déroulante fin}} <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">'''XII.''' Au chagrin que ces pertes causèrent à ceux-ci, se joignirent des craintes superstitieuses dont la ville fut frappée, et qui venaient d’apparitions de spectres et de fantômes. Les devins déclarèrent aussi que l’état des victimes annonçait des crimes et des profanations qu’il fallait expier. On fit donc venir de ''Crète'' '''Épiménide''' le ''Phestien'' qui est mis au nombre des sept sages par ceux qui n’y comptent pas '''Périandre'''. Il passait pour un homme chéri des dieux, doué d’une grande sagesse, fort instruit des choses divines, surtout versé dans la science des inspirations et dans la connaissance des mystères; on l’appelait, même de son vivant, le nouveau '''Curète''', le fils de la nymphe '''Balté'''.<br /><p style="text-align: center">[...]<br /><p style="text-indent: 15px; text-align: justify;">Mais ce qui était plus important, il fit un grand nombre d’expiations et de sacrifices; il fonda plusieurs temples; et par ces différentes cérémonies, il purifia entièrement la ville, en bannit l’impiété et l’injustice, et la rendit plus soumise, plus disposée à l’union et à la paix. On rapporte aussi que lorsqu’il vit ''Munychie'', il la considéra longtemps, et dit à ceux qui l’accompagnaient :<br /><p style="text-align: justify; text-indent: 15px"> « Que les hommes sont aveugles sur l’avenir! Si les ''Athéniens'' pouvaient prévoir tous les maux que ce lieu doit un jour causer à leur ville, il l’emporteraient à belles dents. »<br /><p style="text-align: justify; text-indent: 15px"> '''Thalès''' eut aussi, dit-on, un pressentiment à peu près semblable. Il ordonna qu’on l’enterrât dans le lieu le plus sauvage et le plus désert du territoire de ''Milet''; et il prédit aux ''Milésiens'' qu’un jour leur marché public y serait transporté. Les ''Athéniens'', pleins de reconnaissance et d’admiration pour '''Épiménide''', voulurent le combler d’honneurs et de présents; mais il ne demanda qu’une branche de l’olivier sacré, qui lui fut accordée, et il s’en retourna en ''Crète''.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f7.item <u>Plutarque, Vie de Solon</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f58.item ''chap. II''], traduction correcte et précédée du texte grec, par une société de professeurs et d’helléniste, 1862<br />(également disponible une édition de 1844 [https://remacle.org/bloodwolf/historiens/Plutarque/solon.htm#1a ici] et de 1829 [[s:Les_Vies_des_hommes_illustres/Vie_de_Solon|là]])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Et certaines craintes nées de la superstition en-même-temps aussi des apparitions occupaient la ville; et les devins disaient des impiétés et des souillures ayant-besoin de purifications être indiquées par les victimes. Et ainsi vint à eux mandé (ils firent venir) de ''Crète'' '''Épiménide''' le ''Phestien'', que quelques-uns de ceux n’admettant pas '''Périandre''' comptent le septième parmi les sages. Or il avait-la-réputation d’être un homme ami-des-dieux, et habile dans la science de-l’inspiration et des-mystères. C’est-pourquoi les hommes d’alors appelaient lui et fils de la nymphe de nom (nommée) '''Balté''', et nouveau '''Curète'''.<br /><p style="text-align: center">[...]<br /><p style="text-indent: 15px; text-align: justify;">Mais le plus grand (le plus important), ayant initié-aux-mystères et ayant purifié la ville par certaines expiations et purifications et fondations, il la rendit prêtant-l’oreille à la justice et plus obéissante pour la concorde. Et il est dit, ayant vu ''Munychie'' et l’ayant examinée un temps long, avoir dit à ceux présents, que l’homme est un être aveugle sur l’avenir ; car les ''Athéniens'' avoir dû manger ''Munychie'' avec les dents d’eux-mêmes, s’ils avaient prévu en combien de choses cette place affligera la ville. Et on dit aussi '''Thalès''' avoir conjecturé quelque chose de semblable; lui avoir ordonné en effet de placer lui ayant cessé de vivre dans un certain lieu de la ''Milésie'' méprisé et dédaigné, ayant prédit que cet endroit sera (serait) un jour le marché des ''Milésiens''. '''Épiménide''' donc ayant été admiré très-grandement, et les ''Athéniens'' lui donnant des sommes nombreuses et des honneurs grands, n’ayant demandé rien qu’un rameau détaché de l’olivier sacré et l’ayant pris (reçu) s’en alla.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f7.item <u>Plutarque, Vie de Solon</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f59.item ''chap. II''], traduction littérale et juxtalinéaire présentant le mot à mot français en regard des mots grecs correspondants, par une société de professeurs et d’helléniste, 1862</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto; color: #3366BB">═✳═</div> === [[w:Œuvres_morales|Œuvres morales]] [[#Œuvres_morales|<span id="Œuvres_morales_back"><sup>'''I'''</sup></span>]] === <div style="text-align: center; margin: 0 1em;">Ensemble de 78 textes de traitant de sujets extrêmement variés (religieux, éthiques, politiques, philosophiques, littéraires, historiques), et s'inscrivant dans des genres littéraires également divers (traité, différentes sortes de dialogues, lettres, réponses à des Questions ([[wikt:ζήτημα#Grec_ancien|''zetemata'']]), « dits » ([[w:Apophtegme|''apophtegmes'']])).</div> {{Boîte déroulante début|titre=NdA Le Banquet des Septs Sages|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Cléobuline_back|<span id="Cléobuline"><sup>I</sup></span>]] En grec ancien Ἠθικὰ / Ethikà [[wikt:en:ἠθικός#Ancient_Greek|(en)]], «1. Relatif au caractère ou au tempérament : • (d’une personne) Qui exprime ou manifeste sa nature ; • (théâtre) Conforme au personnage. 2. Éthique moral (relatif à la moralité) : (philosophie) Relatif à l’éthique (l’étude des principes régissant la conduite juste ou injuste) ; (d’un texte) qui traite de la conduite et de la vertu. 3. (rhétorique) Empreint de tact. » ; <br /><p style="margin: 0 2em; text-indent: 15px;">➥ du nom commun ἦθος / êthos [[wikt:en:ἦθος#Ancient_Greek|(en)]], « 1. Le lieu habituel ou coutumier (de quelque chose) : • Le domicile ou le lieu de résidence (d’une personne) ; • Le territoire (d’un animal). 2. Le caractère ; le tempérament : • (théâtre) Personnage (dramatique). 3. La coutume ; l’habitude : • (au pluriel) Les manières ; l’étiquette. » ;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ +‎ du suffixe adjectival -ῐκός/-ĭkós, « relatif à, à la manière de ; -ique ».<br /><br /><p style="margin: 0 2em; text-indent: 15px;">En latin Moralia ; de l’adjectif mōrālis [[wikt:en:moralis#Latin|(en)]], « Qui a trait aux mœurs ou à l'éthique ; moral. » ;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ du nom commun mōs [[wikt:en:mos#Latin|(en)]], « 1. Manière d’agir ; comportement ; conduite. 2. Coutume ; habitude ; pratique ; usage. 3. (surtout au pluriel) Caractère ; disposition ; inclination ; tempérament. 4. Volonté ; obstination ; humeur ; caprice. 5. (sens dérivé) Qualité ; nature ; mode ; façon. 6. (sens dérivé) Précepte ; loi ; règle. 7. (au pluriel uniquement) mœurs ; principes »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ + du suffixe adjectival -ālis [[wikt:en:-alis#Latin|(en)]]. Utilisé pour la première fois par Cicéron pour traduire le terme grec ancien ēthikós, « moral ». <br /><br /><p style="margin: 0 2em; text-indent: 15px;">En retraçant l’usage de l’adjectif ἠθικός à partir de la Rhétorique d’Aristote, le professeur de littérature latine [https://cv.hal.science/charles-guerin Charles Guérin] démontre que Cicéron l’utilise dans son dernier traité rhétorique non comme un équivalent du style moyen, mais comme une catégorie nouvelle permettant d’opposer éloquence du ''mouere'' [[wikt:en:movere#Latin|(en)]] et éloquence du ''conciliare'' [[wikt:en:conciliare#Latin|(en)]]. Cicéron réintroduit ainsi dans son traité la notion de conciliation du public qu’il avait tout d’abord éliminée de son architecture théorique (au profit de la notion de ''delectare'' [[wikt:en:delectare#Latin|(en)]]) afin de garantir la cohérence conceptuelle de sa doctrine. L’ἠθικόν correspond ainsi à l’idée d’une adaptation du style à l’orateur, non sur le mode pragmatique défendu par Aristote (chez qui la λέξις ἠθική désigne l’adaptation du style aux caractéristiques concrètes de l’orateur), mais sur un mode idéalisant : l’ἠθικόν est une catégorie stylistique prescriptive, celle du style de l’orateur accompli [https://hal.science/hal-03189440 {{Info|<sup>🔍</sup>|Charles Guérin. Orator 128: Cicéron et la catégorie rhétorique de l’ethikon. Pierre Chiron; Carlos Lévy. Les noms du style, Peeters, pp.143-164, 2010. ⟨hal-03189440⟩}}].<br /><br /></div> {{Boîte déroulante fin}} ==== Le Banquet des Sept Sages ==== {| cellpadding="0" align="{{{align|right}}}" style="margin-left: 2em; width:40%; border-spacing:3px; text-align:center; background-color:#F8F9FA; border:2px solid #C8CCD1" |- | style="border:solid 1px #F8F9FA" | '''Manuscrit''' [https://archive.org/details/p.-oxy.-16/Oxyrhynchus%20Papyri/P.%20Oxy.%2052/page/n66/mode/1up {{info|<sup>➕</sup>|The Oxyrhynchus Papyri, Volume LII, 1984}}] [https://books.google.fr/books?id=qfl1xwEACAAJ&lpg=PA1059&hl=fr&pg=PA1171#v=onepage&q=Plutarque&f=false {{info|<sup>➕➕</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume Vb, §210 - Plutarque de Chéronée, p.1171}}] |- style="font-size:8pt; line-height:10pt; vertical-align:middle" | align="center" | <div style="margin-right: 1em; padding:0 0 4px 0; text-align:justify;">{{{légende| Le P. Oxy. 3685 conserve les vestiges assez détériorés de deux colonnes du Banquet des Sept Sages, datant de la première moitié du [[w:IIe_siècle|II<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]], c’est-à-dire presque contemporain de '''Plutarque'''. Ce petit fragment de papyrus (9,6 x 8 cm) présente un intérêt à deux titres : * d’une part, sa datation étant proche de l’époque de '''Plutarque''', il apporte des éléments sur l’authenticité de l’œuvre ; * d’autre part, une partie du texte se retrouve également chez '''Stobée'''. Les doutes quant à l'attribution du Banquet des Sept Sages à Plutarque ne semblent être apparus qu'à une époque relativement récente ; en effet, l'ouvrage figure dans ce que l'on appelle le « Catalogue de Lamprias », une liste des œuvres de Plutarque dressée au [[w:IIIe_siècle|III<sup>ème</sup>]] ou au [[w:IVe_siècle|IV<sup>ème</sup>]] siècle {{Info|EC|de l’Ère Commune}}. Toutefois, ces réserves ont désormais été levées de manière convaincante par J. Defradas pp.7-12 de l’édition de la Budé de 1985. NB : Les [[w:Papyrus_d%27Oxyrhynque|''papyrus d’Oxyrhynque'']] constituent un ensemble de manuscrits découverts à la fin du [[w:XIXe_siècle|XIX<sup>ème</sup>]] et au début du [[w:XXe_siècle|XX<sup>ème</sup>]] siècles {{Info|EC|de l’Ère Commune}} par les papyrologues [[w:Bernard_Pyne_Grenfell|'''Bernard Pyne Grenfell''']] et [[w:Arthur_Surridge_Hunt|'''Arthur Surridge Hunt''']], dans une ancienne décharge située près d’[[w:Oxyrhynque|''Oxyrhynque'']], en ''Égypte''.}}}</div> |} <div style="text-align: center; margin: 0 1em;">Dialogue faisant intervenir 20 personnages, dont une liste des sept sages : '''Thalès''', [[w:Solon|'''Solon''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Solon_back|<sup>🔄</sup>]], [[w:Bias_de_Priène|'''Bias''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Bias_back|<sup>🔄</sup>]], [[w:Chilon|'''Chilon''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Chilon_back|<sup>🔄</sup>]], [[w:Cléobule|'''Cléobule''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Cléobule_back|<sup>🔄</sup>]], [[w:Pittacos_de_Mytil%C3%A8ne|'''Pittacos''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Pittacos_back|<sup>🔄</sup>]], [[w:Périandre|'''Périandre''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Périandre_back|<sup>🔄</sup>]].</div> <div style="text-align: left; margin: 0 1em;">À ceux-ci se rajoutent : * [[w:Anacharsis|'''Anacharsis''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Anacharsis_back|<sup>🔄</sup>]], * '''[[w:Ésope|Ésope]]''' [[#Ésope|<span id="Ésope_back"><sup>'''I'''</sup></span>]], * '''Dioclès''' le ''devin'' et narrateur (possiblement fictif) [[#Dioclès_Cléodème_Chersias|<span id="Dioclès_Cléodème_Chersias_back"><sup>'''II'''</sup></span>]], * '''Nicarque''' le destinataire du récit (possiblement fictif), * [[w:Cléobuline|'''Cléobuline''']] [[#Cléobuline|<span id="Cléobuline_back"><sup>'''III'''</sup></span>]], * '''Mélissa''' la conjointe de '''Périandre''', * '''Niloxène''', * '''Alexidème''' un bâtard du ''tyran'' [[w:Thrasybule_de_Milet|'''Thrasybule''' de ''Milet'']], * '''Ardalus''' le joueur de flûte [[w:Trézène_(ville)|''trézénien'']] [[#Trézène|<span id="Trézène_back"><sup>'''IV'''</sup></span>]], * '''Cléodème''' le ''médecin'' (possiblement fictif) [[#Dioclès_Cléodème_Chersias|<sup>'''II'''</sup>]], * '''Mnésiphile''' un disciple de '''Solon''', * '''Chersias''' le ''poète'' (possiblement fictif) [[#Dioclès_Cléodème_Chersias|<sup>'''II'''</sup>]], * [[w:Gorgias|'''Gorgias''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Gorgias_back|<sup>🔄</sup>]].</div> {{Boîte déroulante début|titre=NdA Le Banquet des Septs Sages|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Ésope_back|<span id="Ésope"><sup>I</sup></span>]] Du nom propre grec ancien Αἴσωπος / Aísōpos ;<br /><p style="margin: 0 2em; text-indent: 15px;">Sous le nom d’Ésope ont circulé dans l’antiquité différents recueils de fables qui ont connu un succès universel et ont été traduites et imitées dans toute la tradition littéraire postérieure. On peut y voir l’expression d’une éthique populaire, rationaliste et cosmopolite, qui n’est pas sans intérêt pour l’histoire de la philosophie. Selon Hérodote, (livre II, chap. 134), il serait un ancien esclave d’Iadmon de ''Samos''.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] seconde moitié du [[w:VIe_siècle_av._J.-C.|VI<sup>ème</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]], selon la Souda, ({{Info|s.v.|Abréviation du latin sub verbo, « À l’article, à l’entrée, au mot. »}} Αἴσωπος, Αι 334), il aurait été précipité du haut des [[w:Phédriades|''Roches Phédriades'']] à ''Delphes'' en la 54<sup>ème</sup> Olympiade (564/561))[https://books.google.fr/books?id=DrvWAAAAMAAJ&newbks=1&newbks_redir=0&lpg=PA5&dq=bibliogroup%3A%22Dictionnaire%20des%20philosophes%20antiques%22&hl=fr&pg=PA240#v=onepage&q&f=false {{Info|<sup>🔍</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume III, §60 - Ésope (Αἴσωπος)}}] <br /><br /><p style="margin: 0 2em; text-indent: 15px;">'''[[#Dioclès_Cléodème_Chersias_back|<span id="Dioclès_Cléodème_Chersias"><sup>II</sup></span>]] D’après l’historienne [https://research-bulletin.chs.harvard.edu/authors/zoe-stamatopoulou/ Zoe Stamatopoulou] [https://research-bulletin.chs.harvard.edu/2017/04/17/periander-plutarch-symposium/ {{info|<sup>🔍</sup>|Stamatopoulou, Zoe. “Constructing Periander in Plutarch’s Symposium of the Seven Sages.” CHS Research Bulletin 5, no. 1 (2016). http://nrs.harvard.edu/urn-3:hlnc.essay:StamatopoulouZ.Constructing_Periander.2016.}}], il s’agit de non-Sages individualisés par leur profession. <br /><br /><p style="margin: 0 2em; text-indent: 15px;">'''[[#Cléobuline_back|<span id="Cléobuline"><sup>III</sup></span>]] Du nom propre grec ancien Κλεοβουλίνη / Kleoboulinè ;<br /><p style="margin: 0 2em; text-indent: 15px">➥ de Κλεόβουλος / Kleóboulos [[wikt:en:Κλεόβουλος#Ancient_Greek|(en)]], « Cléobule, le père de Cléobuline » <br /><p style="margin: 0 2em; text-indent: 15px">➥ du suffixe adjectival féminin -ῑ́νη / -ī́nē [[wikt:en:-ίνη#Ancient_Greek|(en)]], relatif à la matière, au temps, etc. : « fait de, pendant la durée de » ;<br /><p style="margin: 0 2em; text-indent: 15px">Philosophe et poétesse grecque, célèbre pour ses énigmes, fille du [[w:Tyran|''tyran'']] de [[w:Rhodes|''Rhodes'']], Cléobule, qui la surnommerait Εὔμητις / Eúmētis, « la Prudente » selon Plutarque.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:VIe_siècle_av._J.-C.|VI<sup>ème</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]], originaire de [[w:Lindos|''Lindos'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Lindos_back|<sup>🔄</sup>]] sur l’île de ''Rhodes'') <br /><br /><p style="margin: 0 2em; text-indent: 15px;">'''[[#Trézène_back|<span id="Trézène"><sup>IV</sup></span>]] Du nom propre grec ancien Τροιζήν / Troizḗn [[wikt:en:Τροιζήν#Ancient_Greek|(en)]] ;<br /><p style="margin: 0 2em; text-indent: 15px">[[w:polis|Cité grecque]] du [[w:Péloponnèse|''Péloponnèse'']], sur la côte nord de l’[[w:Argolide|''Argolide'']]. '''<br/><br/></div> {{Boîte déroulante fin}} ===== <div style="text-align: center;">Paragraphe I.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">'''Dioclès''' raconte le Banquet des Sept Sages organisé par '''Périandre''', pendant lequel il fût l’hôte de '''Thalès'''.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§1. Ἦ που προϊὼν ὁ χρόνος, ὦ '''Νίκαρχε''', πολὺ σκότος ἐπάξει τοῖς πράγμασι καὶ πᾶσαν ἀσάφειαν, εἰ νῦν ἐπὶ προσφάτοις οὕτω καὶ νεαροῖς λόγοι ψευδεῖς συντεθέντες ἔχουσι πίστιν. οὔτε γὰρ μόνων, ὡς ὑμεῖς ἀκηκόατε, τῶν ἑπτὰ γέγονε τὸ συμπόσιον, ἀλλὰ πλειόνων ἢ δὶς τοσούτων (ἐν οἷς καὶ αὐτὸς ἤμην, συνήθης μὲν ὢν '''Περιάνδρῳ''' διὰ τὴν τέχνην, ξένος δὲ '''Θάλεω'''· παρ´ ἐμοὶ γὰρ κατέλυσεν ὁ ἀνὴρ '''Περιάνδρου''' κελεύσαντος), οὔτε τοὺς λόγους ὀρθῶς ἀπεμνημόνευσεν ὅστις ἦν ὑμῖν ὁ διηγούμενος· ἦν δ´ ὡς ἔοικεν οὐδεὶς τῶν παραγεγονότων. ἀλλ´ ἐπεὶ σχολή τε πάρεστι πολλὴ καὶ τὸ γῆρας οὐκ ἀξιόπιστον ἐγγυήσασθαι τὴν ἀναβολὴν τοῦ λόγου, προθυμουμένοις ὑμῖν ἀπ´ ἀρχῆς ἅπαντα διηγήσομαι. </div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §1'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§1. '''D<span style ="font-size:85%;">IOCLÈS</span>'''. Certainement le long cours des âges, mon cher '''Nicarque''', jettera sur les faits d’épaisses ténèbres et une complète incertitude, puisque dès aujourd’hui, à propos de choses si récentes et si nouvelles, des relations mensongères et controuvées obtiennent crédit. Car d’abord le banquet en question ne se composait pas seulement des sept sages, comme vous autres l’avez ouï dire. Les convives étaient plus du double de ce nombre. J’en faisais moi-même partie, comme familier de '''Périandre''' en raison de notre profession commune, et comme hôte de '''Thalès''' : ce dernier était en effet descendu chez moi sur la recommandation de '''Périandre'''. Ensuite, on ne vous en a pas rapporté fidèlement les entretiens lorsqu’on vous a fait ce récit. Il faut que celui de qui vous le tenez n’ait pas été un des convives. Mais puisque nous avons un ample loisir et que la vieillesse est un garant trop peu sûr pour nous autoriser à remettre cet entretien, je vais, suivant votre désir unanime, vous en raconter tous les détails à partir du commencement. </div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §1'', traduction par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870<br/>(également disponible [[s:Page:Plutarque_-_Œuvres_complètes_de_Plutarque_-_Œuvres_morales_et_œuvres_diverses,_tome_1,_1870.djvu/424|ici]])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">'''D<span style ="font-size:85%;">IOCLÈS</span>'''. Quelle incertitude et quelle obscurité la succession des temps ne doit-elle pas répandre sur l’histoire, mon cher '''Nicarque''', puisque, dans des faits récents, et qui se sont passés presque sous nos yeux, le faux prend la place du vrai ? Ce banquet n’était pas, comme on vous l’a dit, composé seulement des sept sages ; les convives étaient plus du double de ce nombre. J’y assistai moi-même, et comme ami de '''Périandre''', avec qui ma profession ma lié depuis longtemps [[#Dioclès_NdT_DR|<span id="Dioclès_NdT_DR_back"><sup>1</sup></span>]], et comme hôte de '''Thalès''', à qui '''Périandre''' avait fait marquer son logement chez moi. Celui qui vous a fait le récit de ce qui s’y est passé n’en était sûrement pas, et vous a trompé sur presque tous les points. Mais, puisque nous en avons le loisir, et que notre âge avancé ne nous permet guère de différer, je vais vous satisfaire et vous en raconter tous les détails.</div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Dioclès_NdT_DR_back|<span id="Dioclès_NdT_DR"><sup>1.</sup></span>]] Dioclès était devin.''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' pp.325, 326, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe II.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage de la simplicité de '''Thalès''', de sa mesure de la pyramide d’''Égypte'' [[#mesure_pyramide|<span id="mesure_pyramide_back"><sup>'''I'''</sup></span>]], et de son aversion des [[w:Tyran|''tyrans'']] et des rois.</div> {{Boîte déroulante début|titre=NdA Mesure de la Pyramide d’Égypte|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#mesure_pyramide_back|<span id="mesure_pyramide"><sup>I</sup></span>]]'''<br/><br/></div> {{Boîte déroulante fin}} :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§2. Παρεσκευάκει μὲν γὰρ οὐκ ἐν τῇ πόλει τὴν ὑποδοχὴν ὁ Περίανδρος, ἀλλ´ ἐν τῷ περὶ τὸ Λέχαιον ἑστιατορίῳ παρὰ τὸ τῆς Ἀφροδίτης ἱερόν, ἧς ἦν καὶ ἡ θυσία. μετὰ γὰρ τὸν ἔρωτα τῆς μητρὸς αὐτοῦ προεμένης τὸν βίον ἑκουσίως οὐ τεθυκὼς τῇ Ἀφροδίτῃ, τότε πρῶτον ἔκ τινων ἐνυπνίων τῆς Μελίσσης ὥρμησε τιμᾶν καὶ θεραπεύειν τὴν θεόν. Τῶν δὲ κεκλημένων ἑκάστῳ συνωρὶς ἱκανῶς κεκοσμημένη προσήχθη· καὶ γὰρ ὥρα θέρους ἦν, καὶ τὴν ὁδὸν ἅπασαν ὑπὸ πλήθους ἁμαξῶν καὶ ἀνθρώπων ἄχρι θαλάττης κονιορτὸς καὶ θόρυβος κατεῖχεν. ὁ μέντοι Θαλῆς τὸ ζεῦγος ἐπὶ ταῖς θύραις ἰδὼν καὶ μειδιάσας ἀφῆκεν. ἐβαδίζομεν οὖν ἐκτραπόμενοι διὰ τῶν χωρίων, καθ´ ἡσυχίαν, καὶ μεθ´ ἡμῶν τρίτος ὁ Ναυκρατίτης Νειλόξενος, ἀνὴρ ἐπιεικὴς καὶ τοῖς περὶ Σόλωνα καὶ Θαλῆν γεγονὼς ἐν Αἰγύπτῳ συνήθης. ἐτύγχανε δὲ πρὸς Βίαντα πάλιν ἀπεσταλμένος· ὧν δὲ χάριν οὐδ´ αὐτὸς ᾔδει, πλὴν ὑπενόει πρόβλημα δεύτερον αὐτῷ κομίζειν ἐν βιβλίῳ κατασεσημασμένον· εἴρητο γάρ, εἰ Βίας ἀπαγορεύσειεν, ἐπιδεῖξαι τοῖς σοφωτάτοις Ἑλλήνων τὸ βιβλίον. « Ἕρμαιον » ὁ Νειλόξενος ἔφη « μοι γέγονεν ἐνταῦθα λαβεῖν ἅπαντας ὑμᾶς, καὶ κομίζω τὸ βιβλίον ὡς ὁρᾷς ἐπὶ τὸ δεῖπνον. » ἅμα δ´ ἡμῖν ἐπεδείκνυε. Καὶ ὁ Θαλῆς γελάσας « εἴ τι κακόν, » εἶπεν, « αὖθις εἰς Πριήνην· διαλύσει γὰρ ὁ Βίας, ὡς διέλυσεν αὐτὸς τὸ πρῶτον. » « Τί δ´ ἦν, » ἔφην ἐγώ, « τὸ πρῶτον; » « Ἱερεῖον, » εἶπεν, « ἔπεμψεν αὐτῷ, κελεύσας τὸ πονηρότατον ἐξελόντα καὶ χρηστότατον ἀποπέμψαι κρέας. ὁ δ´ ἡμέτερος εὖ καὶ καλῶς τὴν γλῶτταν ἐξελὼν ἔπεμψεν· ὅθεν εὐδοκιμῶν δῆλός ἐστι καὶ θαυμαζόμενος. » « Οὐ διὰ ταῦτ´ » ἔφη « μόνον » ὁ Νειλόξενος, « ἀλλ´ οὐ φεύγει τὸ φίλος εἶναι καὶ λέγεσθαι βασιλέων καθάπερ ὑμεῖς, ἐπεὶ σοῦ γε καὶ τἄλλα θαυμάζει, καὶ τῆς [[wikt:en:πυραμίδος#Ancient_Greek|πυραμίδος]] τὴν μέτρησιν ὑπερφυῶς ἠγάπησεν, ὅτι πάσης ἄνευ πραγματείας καὶ μηδενὸς ὀργάνου δεηθεὶς ἀλλὰ τὴν βακτηρίαν στήσας ἐπὶ τῷ πέρατι τῆς σκιᾶς ἣν ἡ πυραμὶς ἐποίει, γενομένων τῇ ἐπαφῇ τῆς ἀκτῖνος δυεῖν τριγώνων, ἔδειξας ὃν ἡ σκιὰ πρὸς τὴν σκιὰν λόγον εἶχε τὴν πυραμίδα πρὸς τὴν βακτηρίαν ἔχουσαν. ἀλλ´, ὅπερ ἔφην, διεβλήθης μισοβασιλεὺς εἶναι, καί τινες ὑβριστικαί σου περὶ τυράννων ἀποφάσεις ἀνεφέροντο πρὸς αὐτόν, ὡς ἐρωτηθεὶς ὑπὸ Μολπαγόρου τοῦ Ἴωνος τί παραδοξότατον εἴης ἑωρακώς, ἀποκρίναιο ‘τύραννον γέροντα,’ καὶ πάλιν ἔν τινι πότῳ, περὶ τῶν θηρίων λόγου γενομένου, φαίης κάκιστον εἶναι τῶν μὲν ἀγρίων θηρίων τὸν τύραννον, τῶν δ´ ἡμέρων τὸν κόλακα· ταῦτα γάρ, εἰ καὶ πάνυ προσποιοῦνται διαφέρειν οἱ βασιλεῖς τῶν τυράννων, οὐκ εὐμενῶς ἀκούουσιν. » « Ἀλλὰ τοῦτο μέν, » εἶπεν ὁ Θαλῆς, « Πιττακοῦ ἐστιν, εἰρημένον ἐν παιδιᾷ ποτε πρὸς Μυρσίλον· ἐγὼ δὲ θαυμάσαιμ´ ἄν, » ἔφη, « οὐ τύραννον ἀλλὰ [[wikt:κυβερνήτης#Grec_ancien|'''κυβερνήτην''']] γέροντα θεασάμενος. πρὸς δὲ τὴν μετάθεσιν τὸ τοῦ νεανίσκου πέπονθα τοῦ βαλόντος μὲν ἐπὶ τὴν κύνα πατάξαντος δὲ τὴν μητρυιὰν καὶ εἰπόντος ‘οὐδ´ οὕτω κακῶς.’ διὸ καὶ Σόλωνα σοφώτατον ἡγησάμην οὐ δεξάμενον τυραννεῖν. καὶ Πιττακὸς οὗτος εἰ μοναρχίᾳ μὴ προσῆλθεν, οὐκ ἂν εἶπεν ὡς ‘χαλεπὸν ἐσθλὸν ἔμμεναι.’ Περίανδρος δ´ ἔοικεν ὥσπερ ἐν νοσήματι πατρῴῳ τῇ τυραννίδι κατειλημμένος οὐ φαύλως ἐξαναφέρειν, χρώμενος ὁμιλίαις ὑγιειναῖς ἄχρι γε νῦν καὶ συνουσίας ἀνδρῶν νοῦν ἐχόντων ἐπαγόμενος, ἃς δὲ '''Θρασύβουλος''' αὐτῷ κολούσεις τῶν ἄκρων οὑμὸς πολίτης ὑφηγεῖται μὴ προσιέμενος. γεωργοῦ γὰρ [[wikt:en:αἶρα#Ancient_Greek|αἴρας]] καὶ [[wikt:ononis|ὀνώνιδας]] ἀντὶ [[wikt:πυρός#Grec_ancien|πυρῶν]] καὶ [[wikt:κριθή#Grec_ancien|κριθῶν]] συγκομίζειν ἐθέλοντος οὐδὲν διαφέρει τύραννος ἀνδραπόδων μᾶλλον ἄρχειν ἢ ἀνδρῶν βουλόμενος· ἓν γὰρ ἀντὶ πολλῶν κακῶν ἀγαθὸν αἱ δυναστεῖαι τὴν τιμὴν ἔχουσι καὶ τὴν δόξαν, ἄνπερ ἀγαθῶν ὡς κρείττονες ἄρχωσι καὶ μεγάλων μείζονες εἶναι δοκῶσι· τὴν δ´ ἀσφάλειαν ἀγαπῶντας ἄνευ τοῦ καλοῦ προβάτων ἔδει πολλῶν καὶ ἵππων καὶ βοῶν ἄρχειν, μὴ ἀνθρώπων. ἀλλὰ γὰρ εἰς οὐδὲν προσήκοντας ἐμβέβληκεν ἡμᾶς, » ἔφη, « ὁ ξένος οὑτοσὶ λόγους, ἀμελήσας λέγειν τε καὶ ζητεῖν ἃ ἁρμόττει ἐπὶ δεῖπνον βαδίζουσιν. ἦ γὰρ οὐκ οἴει, καθάπερ ἑστιάσοντος ἔστι τις παρασκευή, καὶ δειπνήσοντος εἶναι; Συβαρῖται μὲν γὰρ ὡς ἔοικε πρὸ ἐνιαυτοῦ τὰς κλήσεις ποιοῦνται τῶν γυναικῶν, ὅπως ἐκγένοιτο κατὰ σχολὴν παρασκευασαμέναις ἐσθῆτι καὶ χρυσῷ φοιτᾶν ἐπὶ τὸ δεῖπνον· ἐγὼ δὲ πλείονος οἶμαι χρόνου δεῖσθαι τὴν ἀληθινὴν τοῦ δειπνήσοντος ὀρθῶς παρασκευήν, ὅσῳ χαλεπώτερόν ἐστιν ἤθει τὸν πρέποντα κόσμον ἢ σώματι τὸν περιττὸν ἐξευρεῖν καὶ ἄχρηστον. οὐ γὰρ ὡς ἀγγεῖον ἥκει κομίζων ἑαυτὸν ἐμπλῆσαι πρὸς τὸ δεῖπνον ὁ νοῦν ἔχων, ἀλλὰ καὶ σπουδάσαι τι καὶ παῖξαι καὶ ἀκοῦσαι καὶ εἰπεῖν ὡς ὁ καιρὸς παρακαλεῖ τοὺς συνόντας, εἰ μέλλουσι μετ´ ἀλλήλων ἡδέως ἔσεσθαι. καὶ γὰρ καὶ ὄψον πονηρὸν ἔστι παρώσασθαι, κἂν οἶνος ᾖ φαῦλος, ἐπὶ τὰς νύμφας καταφυγεῖν· σύνδειπνος δὲ κεφαλαλγὴς καὶ βαρὺς καὶ ἀνάγωγος παντὸς μὲν οἴνου καὶ ὄψου πάσης δὲ μουσουργοῦ χάριν ἀπόλλυσι καὶ λυμαίνεται, καὶ οὐδ´ ἀπεμέσαι τὴν τοιαύτην ἀηδίαν ἕτοιμόν ἐστιν, ἀλλ´ ἐνίοις εἰς ἅπαντα τὸν βίον ἐμμένει τὸ πρὸς ἀλλήλους δυσάρεστον, ὥσπερ ἑωλοκρασία τις ὕβρεως ἢ ὀργῆς ἐν οἴνῳ γενομένης. ὅθεν ἄριστα Χίλων, καλούμενος ἐχθές, οὐ πρότερον ὡμολόγησεν ἢ πυθέσθαι τῶν κεκλημένων ἕκαστον. ἔφη γὰρ ὅτι σύμπλουν ἀγνώμονα δεῖ φέρειν καὶ σύσκηνον οἷς πλεῖν ἀνάγκη καὶ στρατεύεσθαι· τὸ δὲ συμπόταις ἑαυτὸν ὡς ἔτυχε καταμιγνύειν οὐ νοῦν ἔχοντος ἀνδρός ἐστιν. ὁ δ´ Αἰγύπτιος σκελετός, ὃν ἐπιεικῶς εἰσφέροντες εἰς τὰ συμπόσια προτίθενται καὶ παρακαλοῦσι μεμνῆσθαι τάχα δὴ τοιούτους ἐσομένους, καίπερ ἄχαρις καὶ ἄωρος ἐπίκωμος ἥκων, ὅμως ἔχει τινὰ καιρόν, καὶ εἰ μὴ πρὸς τὸ πίνειν καὶ ἡδυπαθεῖν ἀλλὰ πρὸς φιλίαν καὶ ἀγάπησιν ἀλλήλων προτρέπεται, καὶ παρακαλεῖ τὸν βίον μὴ τῷ χρόνῳ βραχὺν ὄντα πράγμασι κακοῖς μακρὸν ποιεῖν. » </div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §2'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§2. La réception avait été préparée par '''Périandre''', non pas dans la ville même, mais dans son [[w:Cénacle|''cénacle'']] du port de [[w:Léchaion|''Léchée'']], près du temple de '''Vénus''' en l’honneur de laquelle il y avait même un sacrifice. Car depuis l’incestueux amour à la suite duquel sa mère avait volontairement abandonné la vie, '''Périandre''' n’avait pas sacrifié à '''Vénus''' ; et c’était alors la première fois que, d’après certains songes de '''Mélissa''' il s’était décidé à honorer la déesse et à lui rendre des hommages. Pour chacun des invités on avait amené un attelage approprié convenablement. Nous étions en été, et tout le long de la route, en raison du grand nombre de chariots et de piétons, ce n’était jusqu’à la mer que poussière et que bruit. Pourtant '''Thalès''', ayant vu l’attelage à notre porte, se mit à sourire et le renvoya. Nous partîmes donc à pied en faisant un détour, et à travers champs nous cheminâmes à loisir. Un troisième compagnon s’était joint à nous, '''Niloxène''' de ''Naucratie'', homme plein de mérite, que '''Thalès''' et '''Solon''' avaient autrefois beaucoup connu en ''Égypte''. Il se trouvait envoyé de nouveau vers '''Bias''' ; mais pour quelle mission ? Il n’en savait rien lui-même, hormis qu’il se soupçonnait porteur d’une seconde question à résoudre, contenue dans un pli cacheté; et il lui avait été dit, au cas où '''Bias''' renoncerait, de la présenter aux plus sages d’entre les Grecs. « C’est », dit '''Niloxène''', « une chance heureuse que de vous trouver ici tous, et j’apporte, comme vous voyez, cette lettre pour le banquet. » En même temps, il nous la faisait voir. '''Thalès''' se mit à rire : « Si c’est une question épineuse », dit-il, « qu’on aille encore à ''Priène'' : '''Bias''' la résoudra comme il a résolu la première. » — « Quelle était donc cette première question ? » lui demandai-je. — « Le roi d’Égypte », dit '''Thalès''', « avait envoyé à '''Bias''' une victime, en lui faisant dire d’en couper ce qu’il y avait de plus mauvais et de meilleur, et de le lui renvoyer. Notre sage, avec un discernement merveilleux, en ôta la langue et la fit porter au Roi. Voilà ce qui lui a valu une estime et une admiration si déclarée ». — « Cette raison n’est pas la seule », ajouta '''Niloxène''' ; « c’est encore, que '''Bias''' ne fuit pas, comme vous autres, l’amitié des rois eux-mêmes. Ainsi, vous, '''Thalès''', le roi d’Égypte vous admire beaucoup, et, entre autres choses, il a été, au-delà de ce qu’on peut dire, ravi de la manière dont vous avez mesuré la pyramide sans le moindre embarras et sans avoir eu besoin d’aucun instrument. Après avoir dressé votre bâton à l’extrémité de l’ombre que projetait la pyramide, vous construisîtes deux triangles par la tangence d’un rayon, et vous démontrâtes qu’il y avait la même proportion entre la hauteur du bâton et la hauteur de la pyramide qu’entre la longueur des deux ombres. Mais, comme j’ai dit, on vous accuse de détester les rois ; quelques boutades injurieuses prononcées par vous contre des ''tyrans'' ont été rapportées à [[w:Ahmôsis_II|'''Amasis''']]. Par exemple, l’Ionien '''Molpagore''' vous ayant demandé ce que vous aviez jamais vu de plus extraordinaire, vous lui auriez répondu : « C’est un tyran parvenu à la vieillesse. » Une autre fois, dans un festin, la conversation étant venue à tomber sur les bêtes féroces, vous auriez dit : « La plus méchante bête parmi les animaux sauvages, c’est le tyran, et parmi les animaux apprivoisés le flatteur. » De tels propos ne sont pas de ceux que les rois entendent avec plaisir, lors même qu’ils affectent de n’avoir rien de commun avec les tyrans. » Pour cette dernière réponse, dit '''Thalès''', elle est de '''Pittacus''' : il l’avait adressée un jour en plaisantant à '''Myrsile'''. Quant au premier propos, ce n’était pas « un tyran » que j’avais dit, mais « un [[wikt:κυβερνήτης#Grec_ancien|''pilote'']] », qui soit parvenu à la vieillesse. Toutefois, puisqu’on a changé la destination du mot, je fais comme le jeune homme qui, ayant jeté une pierre à un chien, atteignit sa belle-mère et s’écria : Même ainsi, ce n’est pas mal. » C’est pourquoi je regardai '''Solon''' comme éminemment sage lorsqu’il n’accepta pas la tyrannie ; et '''Pittacus''', s’il n’eût approché de la monarchie, n’aurait pas eu à dire : « Il est difficile d’être homme de bien. » Quant à '''Périandre''', il semble qu’ayant été saisi par le souverain pouvoir comme par une maladie de famille, il ne s’en tire pas trop mal. Il use, au moins jusqu’à présent, de sociétés salutaires. Il réunit, pour entretenir commerce avec eux, ses hommes remplis de sens ; et le conseil que lui a donné mon compatriote [[w:Thrasybule_de_Milet|'''Thrasybule''']] [[#Thrasybule|<span id="Thrasybule_back"><sup>'''I'''</sup></span>]], de décapiter l’aristocratie, il ne l’a pas accepté. Entre un laboureur qui aimerait mieux voir dans son champ de l’[[w:Ivraie|''ivraie'']] ou de l’[[w:Orobanche|''orobanche'']] que de l’orge ou du blé, et un tyran qui veut régner sur des esclaves plutôt que sur des hommes de coeur, je ne vois aucune différence. Un seul bien compense les maux nombreux attachés au pouvoir des tyrans : c’est la gloire et l’honneur qui leur sont réservés lorsque, commandant à des hommes vertueux, ils sont plus vertueux eux-mêmes, et qu’au milieu de grands ils se montrent plus grands. Ceux qui préfèrent leur sûreté en renonçant à ce beau rôle, étaient faits pour réunir sous leur main beaucoup de moutons, de chevaux et de boeufs, mais non des hommes. » « Du reste », continua '''Thalès''', « ce sont propos sans portée aucune que ceux où nous a jetés cet étranger, et nous avons omis de dire et de chercher les choses qui conviennent bien à des gens partis pour un banquet. Ne croyez-vous pas, '''Nicarque''', qu’il y ait des préparatifs à faire quand on vient prendre place à un festin, comme il y en a pour celui qui doit le donner ? Les [[w:Sybaris|''Sybarites'']] [[#Sybaris|<span id="Sybaris_back"><sup>'''II'''</sup></span>]], à ce qu’il paraît, s’y prennent un an d’avance pour adresser leurs invitations aux femmes, afin qu’elles puissent à loisir préparer leur toilette et leurs bijoux en or avant de se rendre au festin; et, selon moi, il faut plus de temps encore à un convive pour les préparatifs vraiment nécessaires, parce qu’il est plus difficile de trouver un ajustement convenable pour son moral que la vaine et inutile parure dont on s’inquiète pour son corps. Un homme sensé ne se transporte pas à un festin comme un bocal qu’il s’agit d’y remplir. Il songe à trouver là une occasion de passer tour à tour du sérieux au badinage, d’entendre et de tenir lui-même ces propos auxquels la circonstance invite les convives s’ils veulent se rendre la réunion agréable les uns aux autres. En effet on est libre de repousser un mauvais ragoût, et si le vin ne vaut rien on peut « recourir aux [[w:Naïades|''Naïades'']] »; mais un convive qui vous donne mal à la tête, qui est lourd, qui ne sait pas se conduire, vous fait perdre et vous gâte le plaisir de tout vin, de toute bonne chère, de toute musique. On n’est même pas le maître de se débarrasser aussi complétement qu’on le voudrait d’un tel désagrément. Quelques-uns en gardent tant qu’ils vivent du mécontentement les uns contre les autres : il leur semble qu’il leur reste comme un arrière-goût de viandes mal digérées, parce qu’ils conservent le souvenir d’injures ou de colères échangées dans le vin. C’est pour cela que '''Chilon''', invité hier, n’a pas voulu promettre avant d’avoir su le nom de chacun des convives : « Car on est bien obligé, a-t-il dit, de supporter un désagréable compagnon de traversée, de tente, quand il faut être sur terre ou à l’armée ; mais se mêler indifféremment à table avec les premiers venus, n’est pas le propre d’un homme sensé. » Le squelette des ''Égyptiens'', qu’ils ont la sage coutume de produire et de placer dans la salle du festin afin d’engager à se souvenir que l’on sera bientôt comme lui, survient là comme un convive assez désagréable et intempestif, mais enfin la présence s’en explique. Si cette vue n’excite pas à boire et à se réjouir, elle engage du moins à s’aimer, à se chérir les uns les autres, et elle exhorte à ne pas allonger par des tracas pénibles une existence dont la durée est si courte. </div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §2'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> {{Boîte déroulante début|titre=NdA trad. par Victor Bétolaud de 1870|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Thrasybule_back|<span id="Thrasybule"><sup>I</sup></span>]] Du nom propre grec ancien Θρᾰσῠ́βουλος / Thrăsŭ́boulos [[wikt:en:Θρασύβουλος#Ancient_Greek|(en)]] ;<br /><p style="margin: 0 2em; text-indent: 15px">➥ de l’adjectif [[wikt:θρασύς#Grec_ancien|θρᾰσύς / thrăsús]], « confiant, audacieux » ;<br /><p style="margin: 0 2em; text-indent: 15px">➥ +‎ du nom commun [[wikt:βουλή#Grec_ancien|βουλή / boulế]], « Volonté. Décision, conseil. Conseil, sénat athénien. »; du verbe [[wikt:βούλομαι#Grec_ancien|βούλομαι / boúlomai]], « Vouloir, désirer, souhaiter. Vouloir bien, consentir à. » ;<br /><p style="margin: 0 2em; text-indent: 15px">➥ +‎ -ος (-os).<br /><br /><p style="margin: 0 2em; text-indent: 15px">[[#Sybaris_back|<span id="Sybaris"><sup>II</sup></span>]] Du nom propre grec ancien Σῠ́βᾰρῐς / Sŭ́bărĭs [[wikt:en:Σύβαρις#Ancient_Greek|(en)]] ;<br /><p style="margin: 0 2em; text-indent: 15px">[[w:Colonisation grecque|Colonie grecque]] du sud de l’Italie (en [[w:Calabre|Calabre]] actuelle), fondée au [[w:VIIIe_siècle_av._J.-C.|VIII<sup>ème</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]] dans le cadre du mouvement d’établissement et d’[[w:Colonisation_grecque|''essaimage'']] des Grecs vers l’Occident, particulièrement en [[w:Grande-Grèce|''Grande-Grèce'']]. Réputée dès l’Antiquité pour sa richesse devenue proverbiale, ainsi que pour son emprise sur les peuples voisins et différentes cités grecques de son voisinage, elle est détruite à l’issue d’une [[w:Guerre entre Sybaris et Crotone|guerre]] qui l’oppose à [[w:Crotone|''Crotone'']] à la fin du [[w:VIe_siècle_av._J.-C.|VI<sup>ème</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]], et enfouie sous les eaux du fleuve ''Crathis'' (aujourd’hui [[Crati]]), avant de voir son site réoccupé, soixante ans plus tard, par la colonie [[w:Panhellénisme|''panhellénique'']] de [[w:Thourioï|''Thourioï'']].'''<br/><br/></div> {{Boîte déroulante fin}} <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">'''Périandre''' avait fait préparer le banquet, non à la ville même, mais au ''port de Léchée'' [[#Léchée_NdT_DR|<span id="Léchée_NdT_DR_back"><sup>1</sup></span>]], dans une salle voisine du ''temple de Vénus'', à qui l’on devait offrir un sacrifice. Depuis que sa mère, victime d’un malheureux amour [[#Cratée_NdT_DR|<span id="Cratée_NdT_DR_back"><sup>2</sup></span>]], s’était donné la mort, il n’avait pas encore sacrifié à cette déesse, et c’était la première fois qu’il y pensait, d’après un songe de '''Mélisse''' [[#Mélisse_NdT_DR|<span id="Mélisse_NdT_DR_back"><sup>3</sup></span>]]. Nous étions dans les plus grandes chaleurs de l’été. Le grand nombre des voitures et des gens de pied qui fréquentaient le chemin qui conduit à la mer, l’avaient couvert de poussière et le rendaient fort incommode pour les voyageurs. On avait amené, pour chaque convive, un char commode et proprement orné. '''Thalès''', en voyant le sien à ma porte, se mit à sourire et le refusa. Nous primes donc, à travers les champs, un sentier détourné, et nous allâmes, en nous promenant, suivis de '''Niloxène''' de ''Naucrate'' [[#Niloxène_NdT_DR|<span id="Niloxène_NdT_DR_back"><sup>4</sup></span>]], homme du plus grand mérite, que '''Thalès''' et '''Solon''' avaient autrefois beaucoup connu en ''Égypte''. Il était envoyé, pour la seconde fois, vers '''Bias''', sans savoir lui-même quel était l’objet de sa mission. Il se doutait seulement que la lettre dont '''Amasis''' l’avait chargé contenait une seconde question à résoudre. Il avait ordre, en cas que '''Bias''' refusât d’y répondre, de la proposer aux plus sages d’entre les ''Grecs''. Dès qu’il m’eut aperçu, il me dit en me montrant sa lettre : « J’ai du bonheur aujourd’hui. Cette lettre vous trouve tous réunis. Je la porte au banquet, comme vous voyez. - Si c’est une question épineuse, dit '''Thalès''' en souriant, retournez à ''Priene'' [[#Priene_NdT_DR|<span id="Priene_NdT_DR_back"><sup>5</sup></span>]], '''Bias''' la résoudra, comme il a résolu la première. - Quelle était cette première question, demandai-je à '''Thalès''' ? - Le roi d’Égypte, me répondit-il, avait envoyé une victime à '''Bias''', en lui faisant dire d’en couper ce qu’il y avait de meilleur et de plus mauvais, et de le lui renvoyer. Notre sage, fort habilement en ôta la langue, qu’il lui fit porter. Voilà ce qui lui a mérité l’estime et l’admiration de ce prince. - Ajoutez encore à cette première raison, dit '''Niloxène''', que '''Bias''' ne dédaigne pas, comme vous, l’amitié des rois ; car '''Amasis''' n’a pas moins d’estime pour vous ; il admire surtout la manière dont vous mesurâtes, avec la plus grande facilité et sans aucun instrument mathématique, la hauteur de la pyramide. En dressant votre bâton à l’extrémité de l’ombre qu’elle faisait sur la terre, le rayon solaire qui touchait le sommet de la pyramide et l’extrémité du bâton forma deux triangles ; et vous démontrâtes qu’il y avait la même proportion entre la hauteur du bâton et celle de la pyramide qu’entre la longueur des ombres projetées par l’une et par l’autre. Mais, comme je viens de le dire, on vous accuse, auprès de lui, d’être l’ennemi des rois, et on lui a rapporté plusieurs propos injurieux que vous avez tenus contre les tyrans [[#tyrans_NdT_DR|<span id="tyrans_NdT_DR_back"><sup>6</sup></span>]] ; entre autres que l’''Ionien'' '''Molpagore''' [[#Molpagore_NdT_DR|<span id="Molpagore_NdT_DR_back"><sup>7</sup></span>]] vous ayant demandé ce qui vous paraîtrait plus extraordinaire dans la vie, vous lui répondîtes : de voir vieillir un tyran. Une autre fois, comme on vint à parler, dans un repas, du naturel des animaux, vous dîtes que le plus méchant des animaux sauvages était le tyran, et des animaux domestiques, le flatteur. Les rois, quoiqu’ils affectent de ne rien avoir de commun avec les tyrans, n’aiment pas cependant ces sortes de discours. Cette dernière réponse, dit '''Thalès''', est de '''Pittacus''' ; il la fit un jour, en plaisantant, à ''Myrsile'' [[#Myrsile_NdT_DR|<span id="Myrsile_NdT_DR_back"><sup>8</sup></span>]]. Dans la première, je parlais d’un pilote, et non pas d’un tyran. Mais puisqu’on en a fait application au tyran, je dirai comme ce jeune homme qui, jetant une pierre à son chien, en avait atteint sa belle-mère : « Le coup n’est pas perdu. » Aussi jamais '''Solon''' ne montra-t-il plus de sagesse, à mon gré, que lorsqu’il refusa la tyrannie ; et si '''Pittacus''' n’eût pas été contraint de l’accepter, il n’eût point dit qu’il est à charge d’être vertueux [[#Pittacus_NdT_DR|<span id="Pittacus_NdT_DR_back"><sup>9</sup></span>]]. Il est vrai que '''Périandre''', qui a succédé à l’autorité des tyrans, paraît jusqu’ici opposer à ce mal héréditaire un remède puissant, par le soin qu’il a de rechercher les entretiens et les avis salutaires des hommes vertueux , et par l’horreur qu’il a témoignée pour le conseil barbare que notre compatriote '''Thrasybule''' lui donnait de faire mourir les grands. Un tyran qui veut commander à des esclaves, plutôt qu’à des hommes, ressemble à un laboureur qui aimerait mieux voir son champ couvert de passereaux et de sauterelles que d’orge et de froment. Le seul bien qui puisse compenser tant de maux attachés au pouvoir des tyrans, c’est d’avoir, même sur les plus grands et les plus vertueux de leurs sujets, la supériorité de l’honneur et de la vertu. Ceux qui préfèrent la sûreté à la gloire sont faits pour commander à des troupeaux, et non pour gouverner des hommes. « Mais '''Niloxène''' nous a jetés dans une conversation absolument étrangère à notre objet, et nous a fait négliger ce qui devait nous occuper en allant au banquet. Ne pensez-vous pas que les conviés ont, aussi bien que leur hôte, des apprêts à faire. Les ''Sybarites'', dit-on, prient les femmes à souper un an d’avance, afin qu’elles puissent préparer à loisir leurs habits et leurs bijoux [[#Sybarites_NdT_DR|<span id="Sybarites_NdT_DR_back"><sup>10</sup></span>]]. Pour moi, je pense qu’il faut encore plus de temps à un convive pour faire tous les préparatifs convenables, parcequ’il est bien plus difficile d’orner son esprit comme il faut, que de donner à son corps une parure vaine et superflue. Un homme sensé doit aller à un festin, non pour y remplir son estomac, comme un vase, mais pour écouter et tenir à son tour des propos utiles ou amusants, suivant les circonstances. C’est le seul moyen de rendre le repas agréable aux convives. En effet, on peut laisser un mauvais ragoût, et recourir à l’eau quand le vin n’est pas bon ; mais un convive désagréable, importun et fatigant, fait perdre tout le plaisir de la bonne chère et de la musique. On ne peut se délivrer de l’ennui qu’il cause, et souvent même une parole vive ou offensante qu’il se sera permise dans la liberté de la table, fait naître des aversions et des ressentiments qui ne finissent qu’avec la vie. Aussi '''Chilon''', invité hier à ce banquet, ne voulut-il accepter qu’après qu’on lui eut nommé tous les convives. Il disait avec raison, que quand on est sur mer ou dans un camp, il faut nécessairement supporter les compagnons qui nous sont associés, quelque fâcheux qu’ils soient ; mais dans un festin, il n’est pas d’un homme sensé de se mêler indifféremment avec toutes sortes de personnes. Le squelette que les ''Égyptiens'' placent ordinairement à côté d’eux dans leurs repas, en s’exhortant à penser qu’ils seront bientôt dans le même état, est, à la vérité, un compagnon de table assez triste et assez déplacé. Il est néanmoins utile, sinon pour les exciter au plaisir, du moins pour les porter à la bienveillance et à l’amitié réciproque, et pour les avertir de ne pas remplir d’aigreur et de querelles le temps si court de la vie [[#squelette_NdT_DR|<span id="squelette_NdT_DR_back"><sup>11</sup></span>]]. » </div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Léchée_NdT_DR_back|<span id="Léchée_NdT_DR"><sup>1</sup></span>]] L’isthme de ''Corinthe'' avait deux ports, l’un sur la côte orientale, appelé ''Cenchrées'' ; et l’autre sur la côte occidentale, nommé ''Léchée''. Pausanias, qui a donné une description si détaillée de la ''Grèce'', parle d’un ''temple de Vénus'', bâti sur le port de ''Cenchrées'', et dont la statue était de marbre ; mais il ne fait pas mention de celui que cite Plutarque, et qu’il place près du port occidental. ''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Cratée_NdT_DR_back|<span id="Cratée_NdT_DR"><sup>2</sup></span>]] La mère de Périandre se nommait Cratée. On peut voir dans Parthenius la manière dont elle conçut et nourrit une passion incestueuse pour son fils, les moyens qu'elle prit pour la satisfaire sans être connue, et comment elle fut découverte. Les remords qu’elle en eut l’obligèrent de se donner la mort.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Mélisse_NdT_DR_back|<span id="Mélisse_NdT_DR"><sup>3</sup></span>]] Mélisse était fille de Proclès, roi d’[[w:Épidaure_(cité_antique)|''Épidaure'']]. On prétend que Périandre en devint éperdument amoureux pour l’avoir vue dans l’habillement ordinaire aux femmes du ''Péloponnèse''. Cette passion toutefois ne l’empêcha pas de partager son cœur entre elle et plusieurs concubines. Elles parvinrent à l’irriter contre elle au point qu’un jour, par un mouvement de jalousie, il la frappa d’un coup de pied, sans songer qu’elle était enceinte, et la fit mourir.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Niloxène_NdT_DR_back|<span id="Niloxène_NdT_DR"><sup>4</sup></span>]] Niloxène signifie hôte du ''Nil'' : ce nom semble indiquer que c’est un personnage supposé.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Priene_NdT_DR_back|<span id="Priene_NdT_DR"><sup>5</sup></span>]] Ville d’''Ionie'', colonie des ''Thébains'' et patrie de Bias.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#tyrans_NdT_DR_back|<span id="tyrans_NdT_DR"><sup>6</sup></span>]] Par le mot [[wikt:τύραννος#Grec_ancien|τύραννος]], que nous ne pouvons rendre en français que par celui de tyran, les ''Grecs'' entendaient, non pas seulement, comme nous, un prince injuste et cruel ; mais, en général, tout homme qui s’était emparé de l’autorité monarchique dans un état libre, sans qu’elle lui fût légitimement acquise.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Molpagore_NdT_DR_back|<span id="Molpagore_NdT_DR"><sup>7</sup></span>]] Ce Molpagore est peut-être le père d’Aristagore, que Darius établit tyran à ''Milet''.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Myrsile_NdT_DR_back|<span id="Myrsile_NdT_DR"><sup>8</sup></span>]] Myrsile n’est guère mieux connu que Molpagore. Strabon le met au nombre de ces ''Lesbiens'' ambitieux, qui, du temps de Pittacus, s’étaient emparés de l’autorité souveraine à ''Lesbos'', et dont le poète [[w:Alcée_de_Mytilène|Alcée]] avait flétri la mémoire.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Pittacus_NdT_DR_back|<span id="Pittacus_NdT_DR"><sup>9</sup></span>]] Pittacus en se voyant forcé, dans sa vieillesse, de reprendre le gouvernement des affaires, prononça cette maxime.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Sybarites_NdT_DR_back|<span id="Sybarites_NdT_DR"><sup>10</sup></span>]] Cet usage des ''Sybarites'' n’avait lieu que dans les festins publics.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#squelette_NdT_DR_back|<span id="squelette_NdT_DR"><sup>11</sup></span>]] Cet usage, d’abord particulier aux ''Egyptiens'', avait ensuite passé chez les ''Grecs'', de qui les ''Romains'' l’empruntèrent. ''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' pp.326-330, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe III.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage de la reconnaissance de la sagesse de '''Cléobuline''' ''« Eumétis »'' par '''Thalès''', de l’humilité de ce dernier et de son [[w:Cynisme|''cynisme'']], en particulier à la vue d’un ''centaure'' [[#centaure|<span id="centaure_back"><sup>'''I'''</sup></span>]]. </div> {{Boîte déroulante début|titre=NdA centaure|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#centaure_back|<span id="centaure"><sup>I</sup></span>]] Il s’agit d’une adaptation d’une fable de [[w:Phèdre_(fabuliste)|Phèdre]] [[#Phèdre|<span id="Phèdre_back"><sup>II</sup></span>]], où Ésope [[#Ésope_back|<sup>⤴️</sup>]] remplace Thalès [https://books.openedition.org/pur/12177 {{info|<sup>🔍</sup>|Gourmelen, Laurent. « Imposture ou dualité : que faut-il penser de la naissance d’un centaure ? Sur un curieux passage du Banquet des Sept Sages (Plutarque, Moralia, 149 C-F) ». L’imposture dans la littérature, édité par Arlette Bouloumié, Presses universitaires de Rennes, 2011, https://doi.org/10.4000/books.pur.12177.}}] :'''<br /><br /><p style="margin: 0 2em; text-align: center;">« Un homme d’expérience en sait plus long qu’un devin. C’est un proverbe; d’où vient-il? on ne le dit pas. Ma fable, la première, va l’apprendre.<br /><br />Un fermier avait des brebis qui lui donnaient des agneaux à tête humaine. Épouvanté d’une monstruosité pareille, il court tout affligé consulter les devins. L’un répond que la vie du maître est menacée, et qu’il faut conjurer le péril par une victime. L’autre assure au fermier que sa femme lui est infidèle, et que cela signifie l’illégitimité des enfants; mais qu’un sacrifice important peut tout expier. Enfin, tous diffèrent d’opinion et ne font qu’aggraver le souci du paysan. '''Ésope''', vieillard plein de finesse et de sagacité, et que la nature ne put jamais tromper, se trouvait là par hasard : "Villageois, lui dit-il, si tu veux faire cesser ce prodige, donne des femmes tes bergers." » <br /><br /><p style="text-align: right; margin: 0 2em 0 1em;">'''[https://remacle.org/bloodwolf/fabulistes/phedre/livre3.htm <u>Fables de Phèdre</u>, livre III], §3 - Ésope et le paysan, traduites par M. E. Panckoucke, 1864.<br /><br /><p style="margin: 0 2em; text-indent: 15px;">[[#Phèdre_back|<span id="Phèdre"><sup>II</sup></span>]] [[w:Nom_romain|Tria Nomina]] en latin {{Info|Caius|praenomen, nom individuel du citoyen romain}} {{Info|Iulius|nomen, nom de famille}} {{Info|Phaedrus ou Phaeder|cognomen, surnom héréditaire, servant à distinguer les diverses branches d’une même gens}} ;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ du grec ancien Φαῖδρος / Phaîdros [[wikt:en:Φαῖδρος#Ancient_Greek|(en)]] ; de l’adjectif phaidrós / phaidrós [[wikt:en:φαιδρός#Ancient_Greek|(en)]], « 1. Lumineux, rayonnant. 2. (au sens figuré) Rayonnant de joie, brillant, joyeux. » ;<br /><p style="margin: 0 2em; text-indent: 15px;">Fabuliste latin d’origine ''[[w:thrace|thrace]]'', esclave à son arrivée à ''Rome'' et affranchi par un décret d’[[w:Auguste|Auguste]]. Près d’un tiers de son œuvre est repris d’Ésope dont il adapte les fables ; les deux autres tiers sont issus de son imagination. Tout comme son prédécesseur, Phèdre raconte des histoires d’animaux, mais il met en scène aussi des personnages humains et parmi ceux-ci Ésope :'''<br /><br /><p style="margin: 0 2em; text-align: center;">« C’est '''Ésope''' qui, le premier, a trouvé la matière : moi, je l’ai polie en vers [[w:Sénaire iambique|''sénaires'']]. Ce petit livre a un double mérite : il fait rire et il donne de sages conseils pour la conduite de la vie. À celui qui viendrait me reprocher injustement de faire parler non seulement les animaux, mais même les arbres, je rappellerai que je m’amuse ici à de pures fictions. »<br /><p style="margin: 0 2em; text-align: right;">'''Phèdre, ''Fables'', I, prologue'''<br /><br /><p style="margin: 0 2em; text-align: center;">« Le genre d’'''Ésope''' est tout en exemples, et on ne doit y chercher que le but de ses fables : corriger les erreurs des hommes, et exciter en eux une vive émulation. Quelle que soit donc la nature d’un récit, s’il captive, et remplit son objet, il se recommande de lui-même, sans aucun nom d’auteur. Aussi suivrai-je scrupuleusement les traces du vieillard. »<br /><p style="margin: 0 2em; text-align: right;">'''Phèdre, ''Fables'', II, prologue'''<br /><br /><p style="margin: 0 2em; text-indent: 15px;">'''Au total, il composera cent-vingt-trois fables, divisées en cinq livres.<br /><p style="text-align: right; margin: 0 2em;">(vers [[w:-14|-14]] <sup>[[w:Ier_siècle_av._J.-C.|⏳]]</sup>, en ''Thrace'' ― vers [[w:50|50]] <sup>[[w:Ier_siècle|⏳]]</sup>, lieu de décès inconnu)'''<br /><br /> </div>{{Boîte déroulante fin}} :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§3. Ἐν τοιούτοις λόγοις γενόμενοι κατὰ τὴν ὁδὸν ἀφικόμεθα πρὸς τὴν οἰκίαν, καὶ λούσασθαι μὲν ὁ Θαλῆς οὐκ ἠθέλησεν, ἀληλιμμένοι γὰρ ἦμεν· ἐπιὼν δὲ τούς τε δρόμους ἐθεᾶτο καὶ τὰς παλαίστρας καὶ τὸ ἄλσος τὸ παρὰ τὴν θάλατταν ἱκανῶς διακεκοσμημένον, ὑπ´ οὐδενὸς ἐκπληττόμενος τῶν τοιούτων, ἀλλ´ ὅπως μὴ καταφρονεῖν δοκοίη μηδ´ ὑπερορᾶν τοῦ Περιάνδρου τῆς φιλοτιμίας. τῶν δ´ ἄλλων τὸν ἀλειψάμενον ἢ λουσάμενον οἱ θεράποντες εἰσῆγον εἰς τὸν ἀνδρῶνα διὰ τῆς στοᾶς. Ὁ δ´ Ἀνάχαρσις ἐν τῇ στοᾷ καθῆστο, καὶ παιδίσκη προειστήκει τὴν κόμην ταῖς χερσὶ διακρίνουσα. ταύτην ὁ Θαλῆς ἐλευθεριώτατά πως αὐτῷ προσδραμοῦσαν ἐφίλησε καὶ γελάσας « οὕτως, » ἔφη, « ποίει καλὸν τὸν ξένον, ὅπως ἡμερώτατος ὢν μὴ φοβερὸς ᾖ τὴν ὄψιν ἡμῖν μηδ´ ἄγριος. » Ἐμοῦ δ´ ἐρομένου περὶ τῆς παιδὸς ἥτις εἴη, « τὴν σοφήν, » ἔφη, « καὶ περιβόητον ἀγνοεῖς Εὔμητιν; οὕτω γὰρ ταύτην ὁ πατὴρ αὐτός, οἱ δὲ πολλοὶ πατρόθεν ὀνομάζουσι Κλεοβουλίνην. » Καὶ ὁ Νειλόξενος εἶπεν « ἦ που τὴν περὶ τὰ αἰνίγματα δεινότητα καὶ σοφίαν, » ἔφη, « τῆς κόρης ἐπαινεῖς· καὶ γὰρ εἰς Αἴγυπτον ἔνια τῶν προβαλλομένων ὑπ´ αὐτῆς διῖκται. » « Οὐκ ἔγωγ´, » εἶπεν ὁ Θαλῆς· « τούτοις γὰρ ὥσπερ ἀστραγάλοις, ὅταν τύχῃ, παίζουσα χρῆται καὶ διαβάλλεται πρὸς τοὺς ἐντυχόντας. ἀλλὰ καὶ φρόνημα θαυμαστὸν καὶ νοῦς ἔνεστι πολιτικὸς καὶ φιλάνθρωπον ἦθος, καὶ τὸν πατέρα τοῖς πολίταις πραότερον ἄρχοντα παρέχει καὶ δημοτικώτερον. » « Εἶεν, » ὁ Νειλόξενος ἔφη, « καὶ φαίνεται βλέποντι πρὸς τὴν λιτότητα καὶ ἀφέλειαν αὐτῆς· Ἀνάχαρσιν δὲ πόθεν οὕτω τημελεῖ φιλοστόργως; » « Ὅτι, » ἔφη, « σώφρων ἀνήρ ἐστι καὶ πολυμαθής, καὶ τὴν δίαιταν αὐτῇ καὶ τὸν καθαρμόν, ᾧ χρῶνται Σκύθαι περὶ τοὺς κάμνοντας, ἀφθόνως καὶ προθύμως παραδέδωκε. καὶ νῦν οἶμαι περιέπειν αὐτὴν τὸν ἄνδρα καὶ φιλοφρονεῖσθαι, μανθάνουσάν τι καὶ προσδιαλεγομένην. » Ἤδη δὲ πλησίον οὖσιν ἡμῖν τοῦ ἀνδρῶνος ἀπήντησεν Ἀλεξίδημος ὁ Μιλήσιος (ἦν δὲ Θρασυβούλου τοῦ τυράννου νόθος) καὶ ἐξῄει τεταραγμένος καὶ σὺν ὀργῇ τινι πρὸς αὑτὸν οὐδὲν ἡμῖν γε σαφὲς διαλεγόμενος. ὡς δὲ τὸν Θαλῆν εἶδε, μικρὸν ἀνενεγκὼν καὶ καταστάς « οἵαν ὕβριν, » εἶπεν, « εἰς ἡμᾶς Περίανδρος ὕβρικεν, ἐκπλεῦσαι μὲν οὐκ ἐάσας ὡρμημένον ἀλλὰ προσμεῖναι δεηθεὶς τὸ δεῖπνον, ἐλθόντι δὲ νέμων κλισίαν ἄτιμον, Αἰολεῖς δὲ καὶ νησιώτας (καὶ τίνας γὰρ οὐχί;) Θρασυβούλου προτιμῶν· Θρασύβουλον γὰρ ἐν ἐμοὶ τὸν πέμψαντα προπηλακίσαι βουλόμενος καὶ καταβαλεῖν ὡς δὴ περιορῶν δῆλός ἐστιν. » « Εἶτ´, » ἔφη, « σὺ δέδιας μὴ καθάπερ Αἰγύπτιοι τοὺς ἀστέρας ὑψώματα καὶ ταπεινώματα λαμβάνοντας ἐν τοῖς τόποις οὓς διεξίασι γίγνεσθαι βελτίονας ἢ χείρονας ἑαυτῶν λέγουσιν, οὕτως ἡ περὶ σὲ διὰ τὸν τόπον ἀμαύρωσις ἢ ταπείνωσις γένηται; καὶ τοῦ Λάκωνος ἔσῃ φαυλότερος, ὃς ἐν χορῷ τινι κατασταθεὶς εἰς τὴν ἐσχάτην χώραν ὑπὸ τοῦ ἄρχοντος ‘εὖ γ´,’ εἶπεν, ‘ἐξεῦρες, ὡς καὶ αὕτα ἔντιμος γένηται.’ οὐ καταλαβόντας, » ἔφη, « τόπον μετὰ τίνας κατακείμεθα δεῖ ζητεῖν, μᾶλλον δ´ ὅπως εὐάρμοστοι τοῖς συγκατακειμένοις ὦμεν, ἀρχὴν καὶ λαβὴν φιλίας εὐθὺς ἐν αὐτοῖς ζητοῦντες, μᾶλλον δ´ ἔχοντες τὸ μὴ δυσκολαίνειν ἀλλ´ ἐπαινεῖν ὅτι τοιούτοις συγκατεκλίθημεν· ὡς ὅ γε τόπῳ κλισίας δυσχεραίνων δυσχεραίνει τῷ συγκλίτῃ μᾶλλον ἢ τῷ κεκληκότι, καὶ πρὸς ἀμφοτέρους ἀπεχθάνεται. » « Λόγος, » ἔφη, « ταῦτ´ ἄλλως ἐστίν » ὁ Ἀλεξίδημος, « ἔργῳ δὲ καὶ τοὺς σοφοὺς ὑμᾶς ὁρῶ τὸ τιμᾶσθαι διώκοντας, » καὶ ἅμα παραμειψάμενος ἡμᾶς ἀπῆλθε. Καὶ ὁ Θαλῆς πρὸς ἡμᾶς τὴν ἀτοπίαν τοῦ ἀνθρώπου θαυμάζοντας, « ἔμπληκτος, » ἔφη, « καὶ ἀλλόκοτος φύσει, ἐπεὶ καὶ μειράκιον ὢν ἔτι, μύρου σπουδαίου Θρασυβούλῳ κομισθέντος, εἰς ψυκτῆρα κατεράσας μέγαν καὶ προσεγχέας ἄκρατον ἐξέπιεν, ἔχθραν ἀντὶ φιλίας Θρασυβούλῳ διαπεπραγμένος. » Ἐκ τούτου περιελθὼν ὑπηρέτης « κελεύει σε Περίανδρος, » ἔφη, « καὶ Θαλῆν παραλαβόντα τοῦτον ἐπισκέψασθαι τὸ κεκομισμένον ἀρτίως αὐτῷ πότερον ἄλλως γέγονεν ἤ τι σημεῖόν ἐστι καὶ τέρας· αὐτὸς μὲν γὰρ ἔοικε τεταράχθαι σφόδρα, μίασμα καὶ κηλῖδα τῆς θυσίας ἡγούμενος. » ἅμα δ´ ἀπῆγεν ἡμᾶς εἴς τι οἴκημα τῶν περὶ τὸν κῆπον. ἐνταῦθα νεανίσκος ὡς ἐφαίνετο νομευτικός, οὔπω γενειῶν ἄλλως τε τὸ εἶδος οὐκ ἀγεννής, ἀναπτύξας τινὰ διφθέραν ἔδειξεν ἡμῖν βρέφος ὡς ἔφη γεγονὸς ἐξ ἵππου, τὰ μὲν ἄνω μέχρι τοῦ τραχήλου καὶ τῶν χειρῶν ἀνθρωπόμορφον, τὰ λοιπὰ δ´ ἔχον ἵππου, τῇ δὲ φωνῇ καθάπερ τὰ νεογνὰ παιδάρια κλαυθμυριζόμενον. ὁ μὲν οὖν Νειλόξενος, « Ἀλεξίκακε » εἰπών, ἀπεστράφη τὴν ὄψιν, ὁ δὲ Θαλῆς προσέβλεπε τῷ νεανίσκῳ πολὺν χρόνον, εἶτα μειδιάσας (εἰώθει δ´ ἀεὶ παίζειν πρὸς ἐμὲ περὶ τῆς τέχνης) « ἦ που τὸν καθαρμόν, ὦ Διόκλεις, » ἔφη, « κινεῖν διανοῇ καὶ παρέχειν πράγματα τοῖς ἀποτροπαίοις, ὥς τινος δεινοῦ καὶ μεγάλου συμβάντος; » « Τί δ´, » εἶπον, « οὐ μέλλω; στάσεως γάρ, ὦ Θαλῆ, καὶ διαφορᾶς τὸ σημεῖόν ἐστι, καὶ δέδια μὴ μέχρι γάμου καὶ γενεᾶς ἐξίκηται, πρὶν ἢ τὸ πρῶτον ἐξιλάσασθαι μήνιμα, τῆς θεοῦ δεύτερον ὡς ὁρᾷς προφαινούσης. » Πρὸς τοῦτο μηδὲν ἀποκρινάμενος ὁ Θαλῆς ἀλλὰ γελῶν ἀπηλλάττετο. καὶ τοῦ Περιάνδρου πρὸς τὰς θύρας ἀπαντήσαντος ἡμῖν καὶ διαπυθομένου περὶ ὧν εἴδομεν, ἀφεὶς ὁ Θαλῆς με καὶ λαβόμενος τῆς ἐκείνου χειρὸς ἔφη, « ἃ μὲν Διοκλῆς κελεύει δράσεις καθ´ ἡσυχίαν· ἐγὼ δέ σοι παραινῶ νέοις οὕτω μὴ χρῆσθαι νομεῦσιν ἵππων, ἢ διδόναι γυναῖκας αὐτοῖς. » Ἔδοξε μὲν οὖν μοι τῶν λόγων ἀκούσας ὁ Περίανδρος ἡσθῆναι σφόδρα· καὶ γὰρ ἐξεγέλασε καὶ τὸν Θαλῆν περιβαλὼν κατησπάσατο. κἀκεῖνος « οἶμαι δ´, » εἶπεν, « ὦ Διόκλεις, καὶ πέρας ἔσχε τὸ σημεῖον· ὁρᾷς γὰρ ἡλίκον κακὸν γέγονεν ἡμῖν, Ἀλεξιδήμου συνδειπνεῖν μὴ θελήσαντος. » </div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §3'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§3. Ce fut en tenant de tels propos chemin faisant, que nous arrivâmes à la maison. '''Thalès''' ne voulut pas se baigner : « Je me suis frotté d’huile. » dit-il. Il se promena donc de côté et d’autre, regardant les champs de course, les palestres, et le bois sacré, voisin de la mer, que l’on avait bien convenablement disposé. Ce n’était pas qu’il fût frappé par aucun de ces préparatifs, mais il voulait ne pas avoir l’air de mépriser '''Périandre''' et de faire peu de cas de l’empressement avec lequel celui-ci honorait ses hôtes. Pour les autres convives, à mesure qu’ils s’étaient parfumés ou baignés, les serviteurs les introduisaient par la galerie dans la salle du banquet. Or '''Anacharsis''' s’était installé dans cette galerie, et devant lui une jeune fille se tenait, lui séparant les cheveux avec ses mains. Lorsqu’entra '''Thalès''', elle s’élança très librement à sa rencontre, et '''Thalès''', après l’avoir embrassée, lui dit en riant : « Continue à rendre bien beau notre étranger, afin qu’étant devenu la douceur même il ne conserve pas au milieu de nous une mine à faire peur et un aspect sauvage. » Je lui demandai quelle était cette jeune enfant : « Quoi ! » me dit-il, « vous ne connaissez pas la savante et célèbre '''Eumétis''' ! car c’est ainsi que son père la nomme : le plus communément on l’appelle '''Cléobuline''', du nom paternel. » Et '''Niloxène''' : « C’est sans doute à cause de son talent et de son habileté pour les énigmes, que vous faites l’éloge de cette jeune fille : car quelques-unes de celles qu’elle a proposées sont parvenues jusqu’en ''Égypte''. » — « Ce n’est pas à cause de cela », répondit '''Thalès''' : « les énigmes sont pour elle des joujoux dont elle s’amuse à l’occasion pour faire sa partie avec ceux qui se rencontrent. Mais ce qui est admirable en elle c’est sa profondeur d’esprit, son sens politique, l’aménité de son caractère, et le talent qu’elle a de rendre plus douce l’autorité de son père et d’inspirer à celui-ci des sentiments plus humains à l’égard du peuple. » — « Soit », dit '''Niloxène''' ; « et cela se reconnaît à voir sa modestie et sa simplicité. Mais d’où vient qu’elle prend un soin si amoureux de la toilette d’'''Anacharsis''' ? » — Parce que c’est, répondit '''Thalès''', « un sage, un homme des plus instruits, et parce qu’il lui a communiqué, avec de nombreux détails et de grand coeur, l’ensemble des pratiques sanitaires et des purifications que les ''Scythes'' appliquent au traitement des malades. Et dans ce moment je suppose qu’elle l’entoure de soins et d’amitiés parce qu’elle s’instruit de quelque chose en conversant avec lui. » Comme nous étions déjà près de la salle, '''Alexidème''' le ''Milésien'' vint à notre rencontre. C’était un bâtard du tyran '''Thrasybule'''. Il était sorti tout troublé, et avec une sorte de fureur il se parlait à lui-même, mais ses paroles n’avaient rien de clair pour nous. Quand il eut vu '''Thalès''', il se remit un peu ; puis, s’arrêtant tout court : « Quel affront '''Périandre''' vient de nous faire ! Je voulais mettre à la voile : il ne l’a pas permis ; il m’a supplié de rester à son festin, et quand j’arrive, il me donne une des dernières places, faisant passer des [[w:Éoliens|''Éoliens'']], des insulaires (je ne sais qui il ne me préfère pas), les faisant passer, dis je, avant '''Thrasybule''', car c’est '''Thrasybule''' en ma personne, c’est celui par lequel je suis envoyé qu’il a l’intention de traîner dans la boue et de ravaler comme le méprisant : la chose est bien claire. » — « Eh quoi ! » lui dit '''Thalès''', « êtes-vous comme les ''Égyptiens'', qui prétendent que les astres, suivant qu’ils prennent une position élevée ou basse en parcourant leur orbite, ont une condition meilleure ou pire qu’ils ne l’avaient ? Craignez-vous, pareillement, qu’autour de vous, en raison de la place où vous serez, il ne se produise obscurité ou dépression ? Serez-vous moins résigné que certain ''Spartiate'' ? À je ne sais quelle représentation il avait été placé au dernier rang par le maître des cérémonies : « Voilà qui va bien », lui dit-il : « tu as trouvé moyen de rendre honorable ce lieu même. Quand nous avons pris une place nous ne devons pas chercher au-dessous de qui nous sommes installés, mais plutôt comment nous nous mettrons en bon accord avec nos voisins. À leur occasion nous ferons voir tout d’abord, ou plutôt nous l’éprouverons réellement, un désir d’initiative et de prise de possession en matière d’amitié, et nous manifesterons ce désir en nous félicitant, loin d’en montrer du dépit, de ce que l’on nous a placés en une telle compagnie. Mais celui qui se plaint du rang qu’on lui donne à table montre plus de mécontentement contre son commensal que contre son hôte, et il se rend odieux à l’un et à l’autre. » — « Paroles que tout cela, » dit '''Alexidème''', « et paroles sans portée ! Mais je vois que de fait, vous autres sages, vous recherchez aussi les honneurs. » En même temps il s’éloigna de nous et disparut. Une conduite si étrange nous semblait étonnante. « C’est », nous dit '''Thalès''', « un homme écervelé et naturellement bizarre. Vous allez en juger. Il était encore tout jeune ; on avait apporté à '''Thrasybule''' un parfum d’un très haut prix. '''Alexidème''' le versa dans un grand vase à rafraîchir, y mêla du vin pur, et avala le tout, rendant son père odieux au lieu de le faire aimer. » Au même moment parut un serviteur : « Vous êtes invité par '''Périandre''' », me dit-il, « à venir, en vous faisant accompagner de '''Thalès''' que voici, examiner l’objet qu’on lui a récemment apporté, afin que vous disiez si c’est une création toute fortuite, ou bien un présage et une monstruosité; car, pour ce qui est de '''Périandre''', il a l’air grandement troublé, pensant que c’est une souillure et une profanation pour son sacrifice. » En même temps, il nous emmena vers une des salles qui donnaient sur le jardin. Là un jeune homme paraissant appartenir à la classe des bergers, qui n’avait pas encore de barbe et dont la physionomie ne manquait pas de noblesse, déploya une espèce de couverture en cuir, et nous montra un petit enfant né, disait-il, d’une cavale. Par le haut, jusqu’au cou et aux mains, cette créature était de forme humaine ; mais le reste était d’un cheval, et sa voix avait quelque chose des vagissements poussés par les petits enfants qui viennent de naître. « Dieu préservateur ! » s’écria '''Niloxène''', et il détourna les yeux. Mais '''Thalès''' fixa longtemps son regard sur le jeune pâtre; puis s’étant mis à sourire, (car il avait l’habitude de plaisanter toujours avec moi sur ma profession) : « Eh bien, '''Dioclès''', » dit-il, « songez-vous à préparer quelque expiation, et à donner de la besogne aux dieux préservateurs, comme vous trouvant en présence de quelque événement grave et considérable ? » — « Pourquoi non ? » répondis-je : « j’y vois le présage de troubles et de discordes qui s’étendront, j’en ai peur, jusqu’à un mariage et une génération avant que le courroux de la déesse ait été apaisé, puisqu’elle fait, vous le savez, une seconde manifestation ». À ces paroles '''Thalès''' ne répondit rien : il se contenta de rire et de s’en aller. Et comme '''Périandre''' était à la porte, s’avançant pour nous interroger sur ce que nous venions de voir, '''Thalès''' me quitta et le prit par la main : « Ce que '''Dioclès''' prescrira, vous l’exécuterez à loisir », lui dit-il ; « mais moi j’ai un conseil à vous donner : pour faire paître vos juments ne prenez pas de jeunes garçons, ou bien à ceux-ci donnez des femmes. » Ces paroles me semblèrent causer, des qu’il les eut entendues, une vive satisfaction à '''Périandre''', car il éclata de rire et serra très affectueusement '''Thalès''' dans ses bras. '''Thalès''' alors : « '''Dioclès''' », me dit-il, « si je conjecture bien, le prodige reçoit déjà son accomplissement. Car vous voyez quel grand malheur nous est arrivé, '''Alexidème''' n’ayant pas voulu souper avec nous. »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §3'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Après avoir ainsi conversé pendant le chemin, nous arrivâmes au lieu destiné pour le banquet. '''Thalès''' ne voulut point entrer dans le bain, parcequ’il s’était déja parfumé, mais il se promena dans les dehors, s’arrêta à voir les luttes et les courses ; il alla voir le bocage voisin de la mer, qu’on avait décoré avec beaucoup de soin, non qu’il fût frappé de tout cet appareil, mais pour ne point paraître mépriser '''Périandre''' et dédaigner sa magnificence. Tous les autres convives, à mesure qu’ils sortaient du bain, étaient introduits par des esclaves dans la salle du banquet. '''Anacharsis''' seul était assis sous le portique, une jeune fille, debout, lui arrangeait les cheveux. Dès qu’elle vit '''Thalès''', elle accourut très librement au-devant de lui ; ce philosophe l’embrassa, et lui dit en riant : « Parez cet hôte du mieux que vous pourrez, afin que le plus doux des hommes n'’ait plus un extérieur sauvage et effrayant. » Je lui demandai quelle était cette jeune personne : « Eh quoi ! me répondit-il, vous ne connaissez pas la sage et fameuse '''Eumétis''' ? C’est le nom que '''Cléobule''' lui donne, mais les autres l’appellent '''Cléobuline''', du nom de son père. - Est-ce, dit '''Niloxène''', à cause de sa subtilité et de son adresse à composer des énigmes, que vous faites ainsi son éloge ? Quelques unes de celles qu’on lui attribue ont pénétré jusqu’en ''Egypte''. - Non, répliqua '''Thalès''' ; ces énigmes ne sont que des jouets dont elle s’amuse dans l’occasion pour éprouver la perspicacité de ceux qu’elle rencontre. Ce qu’elle a de vraiment admirable, c’est sa grande prudence, sa capacité pour les affaires, son humanité, et l’attention qu’elle a de rendre le gouvernement de son père doux et bienfaisant. - Il est vrai, reprit '''Niloxène''', que sa modestie et sa simplicité annoncent combien elle est populaire. Mais d’où viennent ces soins et cet intérêt pour '''Anacharsis''' ? - Parceque c’est un homme sensé et très instruit, répondit '''Thalès''', qu’il s’est fait un plaisir de lui apprendre en détail le régime et le traitement que les ''Scythes'' emploient dans les maladies. Je suis sûr que dans ce moment même où elle le pare avec tant de soin, elle s’entretient utilement avec lui, et cherche à s’instruire. » Nous approchions de la salle, lorsque nous rencontrâmes '''Alexidème''' de ''Milet'', fils naturel du tyran '''Thrasybule'''. Il sortait tout troublé, et d’un ton de colère murmurait quelques mots que nous ne pûmes entendre. Dès qu’il vit '''Thalès''', il se remit un peu ; et en lui adressant la parole, il lui dit : « Quel indigne affront '''Périandre''' vient de nous faire ! J’allais partir, il me retient, il me prie de rester à son festin ; et quand j’arrive, il m’y donne la dernière place : il préfère un ''éolien'', un insulaire, enfin je ne sais qui, à '''Thrasybule''', car il est évident que c’est '''Thrasybule''' que '''Périandre''' méprise, et brave ouvertement dans la personne de son envoyé [[#Thrasybule_NdT_DR|<span id="Thrasybule_NdT_DR_back"><sup>1</sup></span>]]. - Eh quoi ! lui dit '''Thalès''', craignez-vous que la place que vous occuperez à table ne vous rende plus grand ou plus petit, comme les ''Égyptiens'' disent que les astres brillent plus ou moins, suivant que le cercle qu’ils parcourent est plus ou moins élevé ? Et vous estimeriez-vous moins que ce ''Lacédémonien'', qui, dans une assemblée publique, placé par le magistrat au dernier rang, lui dit : Vous avez trouvé le moyen de rendre cette place honorable [[#place_honorable_NdT_DR|<span id="place_honorable_NdT_DR_back"><sup>2</sup></span>]] ? Doit-on en effet examiner après qui l’on est placé ? Ne faut-il pas plutôt s’accommoder de ceux qu’on a pour voisins, afin d’avoir une occasion naturelle de se lier avec eux, et loin de se fâcher du rang qu’on occupe, témoigner sa satisfaction de se trouver auprès d’eux ? Celui qui se plaint de la place qu’on lui assigne semble plus mécontent de son voisin que de son hôte, et se rend odieux à l’un et à l’autre . - Belles paroles que cela, repartit '''Alexidème'''. Mais, dans le fait, je vois que vous autres sages, vous recherchez les honneurs aussi bien que nous. » En même temps, il nous quitte brusquement, et s’en va. Une conduite si étrange nous étonna tous : « Ce jeune et homme, nous dit '''Thalès''', a montré dès l’enfance un caractère dur et emporté. Un jour qu’on avait fait présent à '''Thrasybule''' d’un parfum de grand prix, il le versa dans une coupe mêlé avec du vin, et l’avala, payant ainsi d’ingratitude la tendresse de son père. » Au même instant, un des gens de '''Périandre''' vint me prier d’aller avec '''Thalès''' voir quelque chose d’extraordinaire qu’on venait de lui apporter, afin de juger si c’était un jeu de la nature ou un prodige menaçant ; il nous dit qu’il en était tout troublé, et qu’il craignait que son sacrifice n’en fût souillé. En même temps, il nous conduit dans une salle qui donnait sur le jardin. Nous y trouvâmes un jeune homme sans barbe, d’une figure intéressante, qui avait l’air d’un berger. Il lève une espèce de peau, et nous fait voir un enfant qu’il disait être né d’une cavale, qui avait la tête, le cou et les mains d’un homme, et dans tout le reste, était fait comme un cheval. Sa voix ressemblait à celle d’un enfant qui vient de naître : « Dieu préservateur ! s’écria '''Niloxène''', en détournant la vue. » Mais '''Thalès''', qui a coutume de plaisanter avec moi sur mon art, après avoir longtemps considéré ce jeune homme, me dit en souriant : « Ne pensez-vous pas déja, '''Dioclès''', à faire des expiations ? Et pour détourner un présage si terrible, n’allez-vous pas donner bien de l’ouvrage aux dieux préservateurs ? - Pourquoi non ? lui répondis-je. Ce prodige, '''Thalès''', est un signe menaçant de troubles et de discorde ; et je crains bien que l’épouse et les enfants de '''Périandre''' n’en éprouvent les tristes suites, puisque enfin, comme vous voyez, avant que la déesse soit apaisée, elle donne une nouvelle marque de son courroux. » A ces mots, '''Thalès''' sourit et sortit sans rien répondre. Il vit, à la porte de la salle, '''Périandre''' venir au-devant de nous, pour savoir notre sentiment. Il me quitta, lui prit la main, et lui dit : « '''Dioclès''' vous parlera ; vous ferez à loisir ce qu’il vous dira. Pour moi, je pense que vous ne devez pas avoir, pour garder vos juments, des bergers aussi jeunes, ou que vous devez les marier. » Ce discours parut faire grand plaisir à '''Périandre''', car il en rit beaucoup, et embrassa affectueusement '''Thalès'''. Celui-ci s’adressant à moi : « Je crois, '''Dioclès''', me dit-il, que le prodige a déja eu son accomplissement. Vous voyez le malheur qui vient de nous arriver ; '''Alexidème''' a refusé de souper avec nous. » </div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Thrasybule_NdT_DR_back|<span id="Thrasybule_NdT_DR"><sup>1</sup></span>]]Dans les ''Propos de table'', on trouve une aventure pareille, arrivée chez Timon, frère de Plutarque ; mais le personnage n’est pas nommé. ''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#place_honorable_NdT_DR_back|<span id="place_honorable_NdT_DR"><sup>2</sup></span>]] Plutarque, dans les ''apophthegmes des Lacédémoniens'', nomme ce ''Spartiate'' Dæmonidas, et attribue un mot semblable au fameux Agésilas. ''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' pp.330-334, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe IV.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage du caractère désinvolte de '''Thalès'''.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§4. Ἐπεὶ δ´ εἰσήλθομεν, ἤδη μεῖζον ὁ Θαλῆς φθεγξάμενος « ποῦ δ´ » εἶπεν « ὁ ἀνὴρ κατακλινάμενος ἐδυσχέρανεν; » ἀποδειχθείσης δὲ τῆς χώρας περιελθὼν ἐκεῖ κατέκλινεν ἑαυτὸν καὶ ἡμᾶς « ἀλλὰ κἂν ἐπριάμην » εἰπών « Ἀρδάλῳ κοινωνεῖν μιᾶς τραπέζης. » ἦν δὲ Τροιζήνιος ὁ Ἄρδαλος, αὐλῳδὸς καὶ ἱερεὺς τῶν Ἀρδαλείων Μουσῶν, ἃς ὁ παλαιὸς Ἄρδαλος ἱδρύσατο ὁ Τροιζήνιος.<br /><p style="text-align: centre">[...]<br /><p style="text-align: justify; text-indent: 15px">καὶ ὁ Θαλῆς ἐμὲ προσαγορεύσας ἐπάνω τοῦ Βίαντος κατακείμενον « τί οὐκ ἔφρασας, » εἶπεν, « ὦ Διόκλεις, Βίαντι τὸν Ναυκρατίτην ξένον ἥκοντα μετὰ προβλημάτων βασιλικῶν αὖθις ἐπ´ αὐτόν, ὅπως νήφων καὶ προσέχων ἑαυτῷ τὸν λόγον δέχηται; » Καὶ ὁ Βίας « ἀλλ´ οὗτος μέν, » ἔφη, « πάλαι δεδίττεται ταῦτα παρακελευόμενος, ἐγὼ δὲ τὸν Διόνυσον οἶδα τά τ´ ἄλλα δεινὸν ὄντα καὶ Λύσιον ἀπὸ σοφίας προσαγορευόμενον, ὥστ´ οὐ δέδια τοῦ θεοῦ μεστὸς γενόμενος μὴ ἀθαρσέστερον ἀγωνίσωμαι. » Τοιαῦτα μὲν ἐκεῖνοι πρὸς ἀλλήλους ἅμα δειπνοῦντες ἔπαιζον·</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §4'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§4. Après que nous fûmes entrés, '''Thalès''' ayant déjà élevé plus haut la voix: « Où donc », dit-il, « l’avait-on placé, cet homme qui s’en est formalisé ? » Quand on lui eut montré l’endroit il fit le tour de la salle, et ce fut là-même qu’il se plaça et nous installa. « En vérité », ajouta-t-il, « j’aurais payé pour partager la même table qu’'''Ardalus'''. » Cet '''Ardalus''' était un joueur de flûte ''Trézénien'', prêtre des ''muses Ardalides'' auxquelles l’antique [[w:Ardalos|'''Ardalus''']] de ''Trézène'' avait dressé des statues.<br /><p style="text-align: center">[...]<br /><p style="text-indent: 15px">Moi, j’étais au-dessus de '''Bias''', et '''Thalès''' m’ayant interpellé : « '''Dioclès''' », me dit-il, « pourquoi n’avez-vous pas dit à '''Bias''' que l’étranger de ''Naucratie'' est venu une seconde fois le trouver avec des questions de la part de son prince, afin que ce soit à jeun qu’il reçoive ces communications et qu’il y applique son esprit ? » Et '''Bias''' : « Il y a longtemps », dit-il, « que '''Dioclès''' me menace de m’y contraindre ; mais je sais que '''Bacchus''', entre autres attributions merveilleuses, possède une sagacité qui l’a fait surnommer le dieu qui délie, de sorte que je ne crains pas, étant rempli de la divinité, que la confiance m’abandonne au moment de la lutte. » C’est ainsi que, pendant le repas, ils échangeaient entre eux des plaisanteries.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §4'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Quand nous fûmes dans la salle, il demanda, en élevant la voix : « Où est donc cette place qui a tant fâché notre homme ? » Quand on la lui eut montrée, il alla s’y placer avec nous : « Certes, ajouta-t-il, j’aurais payé pour être à la même table qu’'''Ardalus'''. » Cet '''Ardalus''' était un joueur de flûte ''træzenien'', prêtre du temple des muses ''Ardalides'', que l’ancien '''Ardalus''' avait fait bâtir à ''Træzène'' [[#Ardalus_NdT_DR|<span id="Ardalus_NdT_DR_back"><sup>1</sup></span>]].<br /><p style="text-align: center">[...]<br /><p style="text-indent: 15px">Comme j’étais au-dessus de '''Bias''', '''Thalès''' m’adressant la parole : « Pourquoi, me dit-il, ne pas avertir '''Bias''' que '''Niloxène''' vient une seconde fois de la part de son prince lui proposer des problèmes à résoudre ? Il y penserait plus librement, tandis qu’il est à jeun. - Il y a longtemps, répondit '''Bias''', que '''Dioclès''' me menace de le faire. Mais je connais la puissance de '''Bacchus''', et surtout cette sagesse qui lui a fait donner le surnom de [[wikt:λύσις#Grec_ancien|''Lysien'']] ou Dieu qui délie. Ainsi, quand je serai plein de ce dieu, je ne crains pas de combattre avec moins d'avantage. ». Ce ton de gaieté régna pendant le repas. </div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Ardalus_NdT_DR_back|<span id="Ardalus_NdT_DR"><sup>1</sup></span>]] Plutarque, dans son traité de la musique, dit qu’Ardalus, fils de Vulcain, selon la Fable, passait pour l’inventeur de la flûte.''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' pp.334, 335, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe VII.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Réflexions de '''Thalès''' sur le défi de sagacité posé par le roi des ''Éthiopiens'' au roi d’''Égypte'', [[w:Ahmôsis_II|'''Amasis''']], consistant à boire la mer. Ce dernier fait appel à '''Bias''' pour la résoudre, et celui-ci souhaite l’examiner en commun avec les sages. '''Chilon''' explique qu’il ne s’agit pas de faire disparaître tant d’eau salée, mais de rendre la domination d’'''Amasis''' potable et douce à ses sujets (§6).</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§7. [...] Ἐπὶ τούτῳ δ´ ὁ '''Θαλῆς''' ἔφησεν, εὐδαιμονίαν ἄρχοντος νομίζειν, εἰ τελευτήσειε γηράσας κατὰ φύσιν.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §7'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§7. [...] Après lui '''Thalès''' prit la parole : « J’estime que le bonheur pour un souverain, c’est s’il meurt de vieillesse et naturellement. ».</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §7'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Après lui, '''Thalès''' dit que le plus grand bonheur d’un prince serait ''de mourir de vieillesse''.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' p.339, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe IX.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Réflexions de '''Thalès''' sur le défi de sagacité posé par le roi d’''Égypte'', [[w:Ahmôsis_II|'''Amasis''']], au roi des ''Éthiopiens'', consistant en une série de questions : « Qu’y a-t-il de plus ancien ? Le temps. — De plus grand ? Le monde. — De plus habile/sage ? La vérité. — De plus beau ? La lumière. — De plus commun ? La mort. — De plus utile ? Dieu. — De plus nuisible ? Le mauvais Génie/démon. — De plus puissant/fort ? La Fortune. — De plus facile ? Le plaisir. ». '''Amasis''' fait encore appel à '''Bias''' pour analyser les réponses du roi des ''Éthiopiens'', qui les examinent également en commun avec les sages.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§9. Τούτων πάλιν ἀναγνωσθέντων, ὦ Νίκαρχε, γενομένης σιωπῆς Θαλῆς ἠρώτησε τὸν Νειλόξενον εἰ προσήκατο τὰς λύσεις ὁ Ἄμασις. ἐκείνου δ´ εἰπόντος ὅτι τὰς μὲν ἀπεδέξατο ταῖς δ´ ἐδυσκόλαινε, « καὶ μὴν οὐδέν, » εἶπεν ὁ Θαλῆς, « ἀνεπίληπτόν ἐστιν, ἀλλ´ ἔχει πάντα διαμαρτίας μεγάλας καὶ ἀγνοίας. οἷον εὐθὺς ὁ χρόνος πῶς ἂν εἴη πρεσβύτατον, εἰ τὸ μὲν αὐτοῦ γεγονὸς τὸ δ´ ἐνεστώς ἐστι τὸ δὲ μέλλον; ὁ γὰρ μεθ´ ἡμᾶς ἐσόμενος χρόνος καὶ πραγμάτων τῶν νῦν καὶ ἀνθρώπων νεώτερος ἂν φανείη. τὸ δὲ τὴν ἀλήθειαν ἡγεῖσθαι σοφίαν οὐδὲν ἐμοὶ δοκεῖ διαφέρειν τοῦ τὸ φῶς ὀφθαλμὸν ἀποφαίνειν. εἰ δὲ τὸ φῶς καλόν, ὥσπερ ἐστὶν, ἐνόμιζε, πῶς τὸν ἥλιον αὐτὸν παρεῖδε; τῶν δ´ ἄλλων ἡ μὲν περὶ θεῶν καὶ δαιμόνων ἀπόκρισις θράσος ἔχει καὶ κίνδυνον, ἀλογίαν δὲ καὶ πολλὴν ἡ περὶ τῆς τύχης· οὐ γὰρ ἂν μετέπιπτε ῥᾳδίως οὕτως, ἰσχυρότατον οὖσα τῶν ὄντων καὶ ῥωμαλεώτατον. οὐ μὴν οὐδ´ ὁ θάνατος κοινότατόν ἐστιν· οὐ γάρ ἐστι πρὸς τοὺς ζῶντας. ἀλλ´ ἵνα μὴ δοκῶμεν εὐθύνειν τὰς τῶν ἑτέρων ἀποφάσεις, ἰδίας ταῖς ἐκείνου παραβάλωμεν· ἐμαυτὸν δὲ παρέχω πρῶτον, εἰ βούλεται Νειλόξενος, ἐρωτᾶν καθ´ ἕκαστον. ὡς οὖν ἐγένοντο τότε, κἀγὼ νῦν διηγήσομαι τὰς ἐρωτήσεις καὶ τὰς ἀποκρίσεις· ‘Τί πρεσβύτατον;’ [[wikt:en:θεός#Ancient_Greek|‘θεός,’]] » ἔφη Θαλῆς· « ‘ἀγέν νητον γάρ ἐστι.’ ‘Τί μέγιστον;’ ‘τόπος· τἄλλα μὲν γὰρ ὁ κόσμος, τὸν δὲ κόσμον οὗτος περιέχει.’ ‘Τί κάλλιστον;’ ‘κόσμος· πᾶν γὰρ τὸ κατὰ τάξιν τούτου μέρος ἐστί.’ ‘Τί σοφώτατον;’ ‘χρόνος· τὰ μὲν γὰρ εὕρηκεν οὗτος ἤδη, τὰ δ´ εὑρήσει.’ ‘Τί κοινότατον;’ ‘ἐλπίς· καὶ γὰρ οἷς ἄλλο μηδέν, αὕτη πάρεστι.’ ‘Τί ὠφελιμώτατον;’ ‘ἀρετή· καὶ γὰρ τἄλλα τῷ χρῆσθαι καλῶς ὠφέλιμα ποιεῖ.’ ‘Τί βλαβερώτατον;’ ‘κακία· καὶ γὰρ τὰ πλεῖστα βλάπτει παραγενομένη.’ ‘Τί ἰσχυρότατον;’ ‘ἀνάγκη· μόνον γὰρ ἀνίκητον.’ ‘Τί ῥᾷστον;’ ‘τὸ κατὰ φύσιν, ἐπεὶ πρὸς ἡδονάς γε πολλάκις ἀπαγορεύουσιν.’ » <br /><br /><p style="text-indent: 15px;">§10. Ἀποδεξαμένων δὲ πάντων τὸν Θαλῆν, ὁ Κλεόδωρος εἶπε, « τοιαῦτ´ ἐρωτᾶν καὶ ἀποκρίνεσθαι βασιλεῦσιν, ὦ Νειλόξενε, προσῆκόν ἐστιν· ὁ δὲ προπίνων τὴν θάλατταν Ἀμάσιδι βάρβαρος ἐδεῖτο τῆς Πιττακοῦ βραχυλογίας, ᾗ πρὸς Ἀλυάττην ἐχρήσατο προστάττοντά τι καὶ γράφοντα Λεσβίοις ὑπερήφανον, ἀποκρινάμενος οὐδὲν ἀλλ´ ἢ μόνον κελεύσας κρόμμυα καὶ θερμὸν ἄρτον ἐσθίειν. »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §9'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§9. Cette lecture ainsi reproduite, mon cher '''Nicarque''', il se fit un moment de silence. Après quoi '''Thalès''' demanda à '''Niloxène''' si '''Amasis''' avait accepté de telles solutions. Il répondit que ce monarque avait accepté les unes et qu’il avait été mécontent des autres. « C’est qu’en effet », dit '''Thalès''', « il n’en est aucune qui soit irréprochable, et toutes sont grandement entachées d’erreur et d’ignorance. Ainsi, d’abord, comment le temps pourrait-il être ce qu’il y a de plus ancien, puisque, une partie étant écoulée, je le veux bien, une autre est le présent, une autre est l’avenir ? Le temps qui doit venir après nous est évidemment plus jeune que les hommes d’aujourd’hui, que les événements actuels. Croire que ce qu’il y a de plus habile, ce soit la vérité, c’est, à mon avis, ne pas émettre une autre opinion que celle-ci : l’oeil et la lumière sont tout un. Si du reste l’''Éthiopien'' a cru, ce qui est réel, la lumière plus belle que tout, pourquoi a-t-il négligé de nommer le soleil lui-même ? Des autres réponses, celle qui concerne la Divinité et le Génie est aussi téméraire que dangereuse ; et ce qu’il dit de la Fortune est tout à fait déraisonnable : car elle ne changerait pas avec tant de facilité, si elle était ce qu’il y a de plus puissant et de plus fort au monde. De même, la mort n’est pas ce qu’il y a de plus commun, puisqu’elle n’est pas commune aux vivants. Mais pour que nous ne semblions pas nous borner à redresser les réponses des autres, il faut y opposer nos propres solutions. Je m’y offre le premier, si '''Niloxène''' veut reprendre chaque question ». Telles que furent faites alors et les demandes et les réponses, je vais vous les reproduire aujourd’hui : Qu’y a-t-il de plus ancien ? C’est dieu, répondit '''Thalès''', attendu qu’il est incréé. — De plus grand ? L’espace : car si le monde contient le reste, à son tour il est contenu dans l’espace. — De plus beau ? Le monde : car tout ce qui est bien ordonné en fait partie. ― De plus habile ? Le temps : car c’est lui qui a découvert et qui découvrira tout. — De plus commun ? L’espérance : car ceux même qui n’ont rien autre chose la possèdent. — De plus utile ? La vertu : car elle rend toutes les autres choses utiles par le bon usage qu’elle en fait. — De plus nuisible ? Le vice : car il corrompt tout par sa présence. — De plus puissant ? La nécessité : car elle est seule invincible. De plus facile ? Ce qui est selon la nature : car, pour ce qui est du plaisir, il amène souvent la lassitude.<br /><br /><p style="text-indent: 15px;">§10. Tout le monde ayant accueilli ces réponses de '''Thalès''', '''Cléodème''' prit la parole : « Voilà », dit-il, « ô '''Niloxène''', les questions et les réponses qu’il est convenable de faire à des rois. Mais le barbare qui veut faire boire la mer à '''Amasis''' aurait besoin de la concision employée par '''Pittacus''' à l’égard d’[[w:Alyatte_II|'''Alyatte''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Alyatte_back|<sup>🔄</sup>]], quand celui-ci enjoignait aux ''Lesbiens'' un ordre des plus insolents. Il se contenta, pour toute réponse, de l’engager « à manger des oignons et du pain chaud. »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §9'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Cette lecture étant finie, il se fit un moment de silence ; après quoi, '''Thalès''' demanda si le roi d’''Égypte'' avait approuvé toutes ces solutions. '''Niloxène''' lui répondit qu’il avait adopté les unes et rejeté les autres : « Mais, reprit '''Thalès''', il n’en est aucune d’admissible, et qui ne soit marquée au coin de l’erreur et de l’ignorance. D'abord, comment le temps peut-il être ce qu’il y a de plus ancien, puisqu’on le divise en passé, présent et avenir ? Ce dernier est certainement moins ancien que les hommes et que les événements actuels. Dire que la vérité est la sagesse, c’est, ce me semble, confondre l’œil avec la lumière. Si d’ailleurs la lumière est, selon lui, ce qu'’il y a de plus beau, pourquoi ne pas nommer le soleil lui-même ? Quant aux autres réponses, celles qu’il a faites sur les dieux et les démons sont aussi hardies que dangereuses. Ce qu’il dit de la fortune est tout à fait déraisonnable. Si elle est réellement si forte et si puissante, comment change-t-elle avec tant de facilité ? Enfin la mort n’est pas ce qu’il y a de plus commun, puisqu’elle n’existe point parmi les vivants. Mais pour qu’on ne croie pas que nous voulons seulement critiquer, opposons à ces réponses nos solutions. Je m’offre le premier pour répondre , si '''Niloxène''' veut reprendre les questions . »<br /><br /><p style="text-indent: 15px;">'''Niloxène''' le fit, et '''Thalès''' donna ses réponses, que je vais vous répéter. Qu’y a-t-il de plus ancien ? Dieu ; car il est éternel. De plus grand ? l’espace ; il contient le monde, qui lui-même renferme tout le reste. De plus beau ? le monde ; tout ce qui est dans l’ordre en fait partie. De plus sage ? le temps ; il a découvert ou découvrira tout. De plus commun ? l’espérance ; elle reste à ceux mêmes qui n’ont rien. De plus utile ? la vertu; elle fait bien user de tout. De plus nuisible ? le vice ; il corrompt tout par sa présence. De plus fort ? la nécessité ; elle seule est invincible. De plus facile ? ce qui est selon la nature ; on se lasse souvent du plaisir même.<br /><br /><p style="text-indent: 15px;">Tout le monde applaudit aux solutions de '''Thalès''' : « Voilà, dit '''Cléodème''', les questions et les réponses qu’il convient à des rois de faire. Pour ce barbare, qui propose à votre prince de boire toute la mer, il lui fallait une réponse aussi courte que celle de '''Pittacus''' au roi de ''Lydie'' '''Alyatte''', qui , dans une lettre, donnait aux ''Lesbiens'' un ordre très impérieux. '''Pittacus''' se contenta de lui récrire : ''Mangez des ognons et du pain chaud'' [[#expression_proverbiale_mépris_NdT_DR|<span id="expression_proverbiale_mépris_NdT_DR_back"><sup>1</sup></span>]].</div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#expression_proverbiale_mépris_NdT_DR_back|<span id="expression_proverbiale_mépris_NdT_DR"><sup>1</sup></span>]] C’est-à-dire : pleurez ; expression proverbiale, pour témoigner du mépris à quelqu’un.''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' pp.341, 342, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe XI.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Réflexion de '''Thalès''' sur les gouvernements où la loi est égale pour tous.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§11. Ἐπὶ τούτῳ '''Θαλῆς''' τὴν μήτε πλουσίους ἄγαν μήτε πένητας ἔχουσαν πολίτας.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §11'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§11. Après lui '''Thalès''' : « que c’est celle qui n’a ni des citoyens trop riches, ni des citoyens trop pauvres. »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §11'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">'''Thalès''' : ''celle dont les citoyens ne sont ni trop riches ni trop pauvres''.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' p.345, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe XII.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Réflexion de '''Thalès''' sur la maison la mieux réglée.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§12. Ὁ δὲ '''Θαλῆς''' ἐν ᾧ πλείστην ἄγειν τῷ δεσπότῃ σχολὴν ἔξεστιν.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §12'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§12. '''Thalès''' : « celle où le maître peut avoir un très grand loisir. »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §12'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">'''Thalès''' : ''celle qui donne le moins d’affaires à son maître''.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' p.346, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe XIII.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Référence à l’anecdote de la coupe de [[w:Bathyclès_de_Magnésie|'''Bathyclès''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_période_Grèce_Hellénistique#Bathyclès_back|<sup>🔄</sup>]] par [[w:Callimaque_de_Cyrène|'''Callimaque''']] de [[w:Cyrène|''Cyrène'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_période_Grèce_Hellénistique#Callimaque_back|<sup>🔄</sup>]].</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§13. Ἐπεὶ δὲ καὶ οὗτος ἔσχεν ὁ λόγος τέλος, ἡ μὲν Εὔμητις ἐξῆλθε μετὰ τῆς Μελίσσης, τοῦ δὲ Περιάνδρου τῷ Χίλωνι προπιόντος εὐμεγέθη κύλικα, τῷ δὲ Βίαντι τοῦ Χίλωνος, Ἄρδαλος ἐπαναστὰς καὶ προσαγορεύσας τὸν Αἴσωπον, « σὺ δ´ οὐκ ἄν, » ἔφη, « διαπέμψαιο δεῦρο τὸ ποτήριον πρὸς ἡμᾶς, ὁρῶν τούτους ὥσπερ τὴν Βαθυκλέους κύλικα διαπεμπομένους ἀλλήλοις, ἑτέρῳ δὲ μὴ μεταδιδόντας; » Καὶ ὁ Αἴσωπος, « ἀλλ´ οὐδὲ τοῦτ´, » ἔφη, « τὸ ποτήριον δημοτικόν ἐστι· Σόλωνι γὰρ ἔκπαλαι παράκειται μόνῳ. »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §13'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§13. Ce texte de conversation se trouvant à son tour épuisé, et '''Eumétis''' étant sortie avec '''Mélissa''', '''Périandre''' but une grande coupe à '''Chilon''', et '''Chilon''', à '''Bias'''. '''Ardalus''' alors se leva, et interpellant '''Ésope''' : « Ne feras-tu pas, dit-il, circuler la coupe jusqu’à nous, quand tu vois qu’ils se la passent mutuellement comme s’il s’agissait de celle de '''Bathycle''' et qu’ils ne la partagent pas avec un autre ? » Et '''Esope''' : « Mais ce vase non plus, dit-il, n’est pas une propriété populaire : car voilà longtemps qu’il reste devant '''Solon''' tout seul ».</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §13'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Après tous ces propos, '''Mélisse''' sortit avec '''Eumétis'''. '''Périandre''' alors boit le premier dans une grande coupe, la présente à '''Chilon''' [[#Chilon_NdT_DR|<span id="Chilon_NdT_DR_back"><sup>1</sup></span>]], et celui-ci à '''Bias''', qui la remit à '''Solon'''. Comme ce dernier la gardait, '''Ardalus''' se lève , et s’adressant à '''Esope''' : « Ne nous ferez-vous point, lui dit-il, passer ce vase, que nos sages, comme vous voyez, se renvoient l’un à l’autre, ainsi que la coupe de '''Bathycle''', sans le faire parvenir jusqu’à nous [[#Bathycle_NdT_DR|<span id="Bathycle_NdT_DR_back"><sup>2</sup></span>]] ? ― Ce vase, lui répondit '''Esope''', n’est sûrement pas populaire, puisqu’il reste si longtemps devant '''Solon'''. »</div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Chilon_NdT_DR_back|<span id="Chilon_NdT_DR"><sup>1</sup></span>]] Cet usage était constant chez les anciens. A la fin du repas, on remplissait de vin une grande coupe. Le principal personnage de l’assemblée en buvait le premier, et la coupe passait ainsi de main en main.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Bathycle_NdT_DR_back|<span id="Bathycle_NdT_DR"><sup>2</sup></span>]] Tout le monde sait l’histoire du fameux trépied d’or, trouvé par des pêcheurs, qui, pour terminer leurs débats, ayant eu recours à l’oracle de ''Delphes'', reçurent ordre d’en faire présent au plus sage, et l’envoyèrent à Thalès. Après avoir passé successivement par les mains des sept sages, il revint à Thalès, qui le consacra dans un temple d’Apollon. Selon Léandre de ''Milet'', cité par Diogène Laërce, c’était une coupe d’or que l’''Arcadien'' Bathycle avait laissée, par son testament, au plus sage, et c’est ce dernier récit que Plutarque semble préférer.''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' p.347, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe XIV.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage de l’''espièglerie'' de '''Thalès'''.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§14. [...] '''Ἐπιστήσαντος''' δὲ τοῦ λόγου τὸ συμπόσιον ὁ μὲν '''Θαλῆς''' ἐπισκώπτων εὖ φρονεῖν ἔφη τὸν '''Ἐπιμενίδην''' ὅτι μὴ βούλεται πράγματα ἔχειν ἀλῶν τὰ σιτία καὶ πέττων ἑαυτῷ, καθάπερ '''Πιττακός'''. « ἐγὼ γάρ, » εἶπε, « τῆς ξένης ἤκουον ᾀδούσης πρὸς τὴν μύλην, ἐν [[w:Eresós|''Ἐρέσῳ'']] γενόμενος, ἄλει, μύλα, ἄλει· καὶ γὰρ '''Πιττακὸς''' ἄλει μεγάλας ''Μυτιλάνας'' βασιλεύων. »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §14'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§14. [...] Ces paroles ayant mis en arrêt les convives, '''Thalès''' dit en raillant qu’'''Epiménide''' avait bien raison de ne pas vouloir se donner l’embarras de moudre et de cuire lui-même son manger, comme faisait '''Pittacus''' : « Car je me souviens », ajouta-t-il, « qu’étant à ''Lesbos'', j’entendis mon hôtesse chanter à sa meule : Va ton train, meule, va ton train, puisque '''Pittacus''', le roi de la grande ''Mitylène'', s’occupe bien à moudre. »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §14'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Ce discours ayant frappé tout le monde, '''Thalès''' dit en plaisantant qu’il approuvait '''Epiménides''' [[#Epiménides_NdT_DR|<span id="Epiménides_NdT_DR_back"><sup>1</sup></span>]] de s’épargner la peine de moudre et de cuire lui-même son pain, comme faisait '''Pittacus'''. « Je me souviens , ajouta-t-il, qu’étant à ''Lesbos'', j’ai entendu une meunière qui chantait : ''Moulez, meule, moulez ; '''Pittacus''', qui règne dans la superbe Mitylène, s’occupe aussi à moudre'' [[#Pittacus_NdT_DR|<span id="Pittacus_NdT_DR_back"><sup>2</sup></span>]]. »</div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Epiménides_NdT_DR_back|<span id="Epiménides_NdT_DR"><sup>1</sup></span>]] Epiménides était un poète de l’île de ''Crète''. Les nymphes, disait-on, lui avaient donné un aliment miraculeux, qu’il conservait dans une corne de bœuf, et dont une très petite quantité suffisait pour le nourrir. ''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Pittacus_NdT_DR_back|<span id="Pittacus_NdT_DR"><sup>2</sup></span>]] Pittacus, au rapport de différents historiens, s’exerçait à moudre du blé. Il faisait un grand éloge de l’utilité des moulins, et insistait sur l’avantage qu’a le moulin de fournir, dans un très petit espace, le moyen de prendre différents exercices. ''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' p.351, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe XV.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage d’une doctrine de '''Thalès''' sur l’importance vitale de l’agriculture.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§15. [...] « Οὐδαμῶς, » ὁ '''Κλεόδωρος''', « ἔμοιγ´, » εἶπεν, « εἰ δεῖ τὸ φαινόμενον εἰπεῖν, καὶ μάλιστα παρακειμένης τραπέζης, ἣν ἀναιροῦσιν αἰρομένης τροφῆς φιλίων θεῶν βωμὸν οὖσαν καὶ ξενίων. ὡς δὲ '''Θαλῆς''' λέγει τῆς γῆς ἀναιρεθείσης σύγχυσιν τὸν ὅλον ἕξειν κόσμον, οὕτως οἴκου διάλυσις ἐστι· συναναιρεῖται γὰρ αὐτῇ πῦρ ἑστιοῦχον ἑστία κρατῆρες ὑποδοχαὶ ξενισμοί, φιλανθρωπότατα καὶ πρῶτα κοινωνήματα πρὸς ἀλλήλους, μᾶλλον δὲ σύμπας ὁ βίος, εἴ γε διαγωγή τίς ἐστιν ἀνθρώπου πράξεων ἔχουσα διέξοδον, ὧν ἡ τῆς τροφῆς χρεία καὶ παρασκευὴ τὰς πλείστας παρακαλεῖ. [...] »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §15'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§15. [...] « S’il faut dire ce que je pense », reprit '''Cléodème''', « ce n’est nullement mon avis, et surtout quand est dressée la table, que l’on supprime si la nourriture est supprimée et qui est l’autel des dieux amis et hospitaliers. Et s’il est vrai, comme dit '''Thalès''', que la suppression de la terre dût entraîner le désordre et la ruine du monde entier, de même anéantir la table ce serait anéantir la maison. Avec la table disparaîtraient le feu qui consacre le foyer, le foyer lui-même, les coupes, les réceptions, les hospitalités, qui sont les plus affectueux et les premiers rapports de communauté entre les hommes; ou plutôt disparaîtrait la vie entière, s’il est vrai que la vie soit une sorte de courant formé par la série des actes de l’homme, actes dont le plus grand nombre est commandé par le besoin et la préparation de la nourriture.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §15'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">S’il faut, reprit '''Cléodème''', que je dise mon sentiment, je ne suis point du tout de cet avis-là, surtout quand la table est dressée. Nous ôter le besoin de nourriture, c’est détruire cet autel des dieux hospitaliers. Et comme la destruction de la terre, selon '''Thalès''', entraînerait la ruine de l’univers, ainsi la chute de la table causerait celle de la maison. Avec elle, on détruirait le feu sacré de nos foyers, les dieux pénates, les libations, le plaisir si touchant de recevoir et de traiter ses amis, tous ces usages respectables qui sont les premiers fondements et les plus doux liens de la société ; disons mieux, on détruirait la vie entière, puisqu’elle est remplie par des occupations et des soins successifs, dont la plupart ont pour objet la nourriture et sa préparation.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' pp.353, 354, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe XVII.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage d’une parole sage de '''Thalès''' : Ne croire ni ses ennemis sur les choses croyables, ni ses amis sur les choses incroyables.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§17. τέλος δὲ γελάσας πρὸς ἡμᾶς « βούλομαι μέν, » ἔφη, « πρὸς τὸ παρὸν φράσαι τὸ προσηγγελμένον· ὀκνῶ δ´ ἀκούσας '''Θαλέω''' ποτ´ εἰπόντος ὅτι δεῖ τὰ μὲν εἰκότα λέγειν, τὰ δ´ ἀμήχανα σιωπᾶν. » Ὑπολαβὼν οὖν ὁ '''Βίας''' « ἀλλὰ καὶ τοῦτ´, » ἔφη, « '''Θαλέω''' τὸ σοφόν ἐστιν, ὅτι δεῖ τοῖς μὲν ἐχθροῖς καὶ περὶ τῶν πιστῶν ἀπιστεῖν, τοῖς δὲ φίλοις καὶ τὰ ἄπιστα πιστεύειν, ἐχθροὺς μέν, ἔγωγ´ ἡγοῦμαι, τοὺς πονηροὺς καὶ ἀνοήτους, φίλους δὲ τοὺς χρηστοὺς καὶ φρονίμους αὐτοῦ καλοῦντος. οὐκοῦν, »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §17'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§17. [...] A la fin il s’adressa à nous en éclatant de rire : « Je voudrais vous faire connaître, sans plus attendre, ce que '''Gorgias''' vient de me conter; et pourtant j’hésite, parce que j’ai autrefois entendu dire à '''Thalès''' qu’il faut dire les choses vraisemblables et taire les impossibles. « Mais, reprit '''Bias''', « c’est à '''Thalès''' aussi qu’appartient cette sage parole : qu’il faut ne pas croire ses ennemis même sur les choses croyables, et croire ses amis même sur celles qui ne le sont pas : par ennemis il entendait, je suppose, les méchants et les sots, par amis, les gens vertueux et sensés. »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §17'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Mais quand '''Gorgias''' [[#Gorgias_NdT_DR|<span id="Gorgias_NdT_DR_back"><sup>1</sup></span>]] eut achevé, il nous dit en riant : « Je voudrais vous répéter ce que je viens d’entendre ; mais je n’ose le faire après ce mot de '''Thalès''' : qu’il faut dire les choses vraisemblables, et taire celles qui paraissent impossibles. - Mais, repartit '''Bias''' , n’est-ce pas aussi '''Thalès''' qui a dit cette autre maxime si sage, qu’il faut ne pas croire ses ennemis même sur les choses croyables, et croire ses amis sur les choses même les moins vraisemblables. Par les ennemis, il entend, sans doute, les méchants et les insensés ; par les amis, les bons et les sages.</div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Gorgias_NdT_DR_back|<span id="Gorgias_NdT_DR"><sup>1</sup></span>]] Tout ce qu’on sait de ce frère de Périandre, c’est qu’il fonda une colonie dans l’''[[w:Ambracie|Ambracie]]'', et qu’il mourut vraisemblablement avant son frère, puisque son fils [[w:Psammétique_(Corinthe)|Psammétique]] succéda à Périandre, et fut le dernier tyran de ''Corinthe'' de la race de [[w:Cypsélos|Cypsèle]]. ''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' p.358, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe XXI.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage d’une doctrine de '''Thalès''' sur la résidence de l'âme dans toutes les parties du monde les plus essentielles.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§21. Μετὰ δὲ τοῦτον ὁ '''Ἀνάχαρσις''' εἶπεν ὅτι τοῦ '''Θαλέω''' καλῶς ὑπολαμβάνοντος ἐν πᾶσιν εἶναι τοῖς κυριωτάτοις μέρεσι τοῦ κόσμου καὶ μεγίστοις ψυχήν, [...].</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §21'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§21. Après '''Pittacus''', '''Anacharsis''' prit la parole : « Puisque, comme '''Thalès''' l’a magnifiquement établi, une âme réside dans toutes les parties du monde les plus essentielles, [...].</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §21'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">'''Pittacus''' ayant cessé de parler, '''Anacharsis''' prit la parole : « S’il est vrai, dit-il, comme '''Thalès''' le croit avec raison, que les plus grandes et les principales parties du monde ont une ame, [...].</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' p.365, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto; color: #3366BB">― ✳ ―</div> ==== Du démon de '''Socrate''' ==== <div style="text-align: center; margin: 0 1em;">Discussion autour de la libération de [[w:Thèbes (Grèce)|''Thèbes'']] de ''[[w:Sparte|Sparte]]'' grâce à une conjuration de '''[[w:Pélopidas|Pélopidas]]''' [[#Pélopidas|<span id="Pélopidas_back"><sup>'''I'''</sup></span>]] en [[w:-379|-379]]. Le récit est ici plus ample que lors de la biographie de Pélopidas dans les ''[[w:Vies parallèles|Vies parallèles]]''. La source de '''Plutarque''' est d’origine ''thébaine'', la même que '''[[w:Cornélius Népos|Cornélius Népos]]''' [[#Cornélius_Népos|<span id="Cornélius_Népos_back"><sup>'''II'''</sup></span>]]. Le traité porte sur la ''[[w:démonologie|démonologie]]'', le démon de '''Socrate''' peut-être une voix intérieure ou ses capacités [[w:divinatoires|divinatoires]]'', la légende étant d’origine [[w:pythagoricienne|pythagoricienne]] et évoque l’oracle '''[[w:Trophonios|Trophonios]]'''.</div> {{Boîte déroulante début|titre=NdA du Démon de Socrate|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Pélopidas_back|<span id="Pélopidas"><sup>I</sup></span>]] Du nom propre grec ancien Πελοπῐ́δᾱς / Pelopĭ́dās [[wikt:en:Πελοπίδας#Ancient_Greek|(en)]] ;<br /><p style="margin: 0 2em; text-indent: 15px;">Stratège [[w:Thèbes (Grèce)|''thébain'']]. Chassé en [[w:-382|-382]] de ''Thèbes'' après la prise de la [[w:Cadmée_(Thèbes)|Cadmée]], la citadelle située au sommet de son ''[[w:acropole|acropole]]'', par [[w:Phébidas|Phébidas]] avec l’aide des ''[[w:Sparte|Spartiates]]'', il renverse le gouvernement pro-spartiate d’[[w:Archias de Thèbes|Archias]] et de Léontidas en [[w:-379|-379]], qu’il tue, et rétablit la ''[[w:démocratie|démocratie]]''.<br /><p style="text-align: right; margin: 0 2em;">(date de naissance inconnue, à ''Thèbes'' — [[w:364_av._J.-C.|-364]]<sup>[[w:IVe_siècle_av._J.-C.|⏳]]</sup>, mort lors de la [[w:Bataille_de_Cynoscéphales_(364_av._J.-C.)|''bataille de Cynoscéphales'']], dans le cadre d’une vengeance pour sa captivité par le ''tyran'' de [[w:Thessalie|''Thessalie'']], [[w:Alexandre_de_Phères|Alexandre]] de [[w:Phères|''Phères'']], alors qu’il était en ambassade chez lui)<br /><br /><p style="margin: 0 2em; text-indent: 15px;">[[#Cornélius_Népos|<span id="Cornélius_Népos"><sup>II</sup></span>]] [[w:Nom_romain|Tria Nomina]] en latin ''{{Info|<nowiki>[praenomen inconnu]</nowiki>|praenomen, nom individuel du citoyen romain}}'' {{Info|Cornélius|nomen, nom de famille}} {{Info|Népos|cognomen, surnom héréditaire, servant à distinguer les diverses branches d’une même gens}}<br /><p style="margin: 0 2em; text-indent: 15px;">Auteur ''latin''. On sait par les lettres de Cicéron que Cornelius Népos n’aimait pas les écrits moraux, leur préférant la description de la nature et l’étude de l’histoire. Aucun des ouvrages qu’il avait composés dans ce genre n’est parvenu en entier jusqu’à nous. Les « Vies des grands capitaines de l’antiquité » qui subsistent aujourd’hui, et qui ont connu de multiples éditions, lui ont été attribuées jusqu'au XVIIIe siècle ; mais l'analyse de ce court recueil montre qu'il ne serait qu'un abrégé (attribué à Æmilius Probus), de l’ouvrage original de Cornelius Népos.<br /><p style="text-align: right; margin: 0 2em;">(vers [[w:-100|-100]], au pays des [[w:Insubres|Insubres]] à [[w:Mantoue|Mantoue]] ou à [[w:Pavie|''Ticinum'']], dans le nord de l’''Italie'' — vers [[w:-29|-29]]/[[w:-25|-25]], à ''Rome'')<sup>[[w:Ier_siècle_av._J.-C.|⏳]]</sup>'''<br /><br /> </div>{{Boîte déroulante fin}} ===== <div style="text-align: center;">Paragraphe VI.</div> ===== <div style="text-align: center; margin: 0 1em;">Témoignage de l’aversion de '''Thalès''' pour les [[w:Tyran|''tyrans'']].</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid;"><br /><div style="text-align: justify; margin: 0 2em; text-indent: 15px">§6. Ταῦτα τοῦ '''Θεοκρίτου''' λέγοντος ὁ '''Λεοντίδης''' ἐξῄει μετὰ τῶν φίλων, ἡμεῖς δ´ εἰσελθόντες ἠσπαζόμεθα τὸν '''Σιμμίαν''' ἐπὶ τῆς κλίνης καθεζόμενον οὐ κατατετευχότα τῆς δεήσεως, οἶμαι, μάλα σύννουν καὶ διαλελυπημένον· ἀποβλέψας δὲ πρὸς ἅπαντας ἡμᾶς ‘ὦ '''Ἡράκλεις''',’ εἶπεν ‘ἀγρίων καὶ βαρβάρων ἠθῶν· εἶτ´ οὐχ ὑπέρευ '''Θαλῆς''' ὁ παλαιὸς ἀπὸ ξένης ἐλθὼν διὰ χρόνου τῶν φίλων ἐρωτώντων ὅ τι καινότατον ἱστορήκοι ’τύραννον‘ ἔφη ’γέροντα.‘ καὶ γὰρ ᾧ μηδὲν ἰδίᾳ συμβέβηκεν ἀδικεῖσθαι, τὸ βάρος αὐτὸ καὶ τὴν σκληρότητα τῆς ὁμιλίας δυσχεραίνων ἐχθρός ἐστι τῶν ἀνόμων καὶ ἀνυπευθύνων δυναστειῶν.[...]</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome II, [https://remacle.org/bloodwolf/historiens/Plutarque/demonsocrategr.htm Περι του Σωκρατους Δαιμονιου - Le Démon de Socrate], §6'', traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§6. Pendant que [[w:Théocrite|'''Théocritos''']] [[#Théocrite|<span id="Théocrite_back"><sup>'''I'''</sup></span>]] parlait, '''Léontidas''' sortit avec ses amis, et nous entrâmes chez [[w:Simmias_de_Thèbes|'''Simmias''']] [[#Simmias_de_Thèbes|<span id="Simmias_de_Thèbes_back"><sup>'''II'''</sup></span>]], que nous saluâmes affectueusement. Il était assis sur son lit, et j’attribuai à l’insuccès de sa demande son air pensif et affligé. Après nous avoir regardés tous : « Par '''Hercule''' ! s’écria-t-il, quelles mœurs sauvages et barbares ! Eh bien ! n’avait-il pas cent fois raison le '''Thalès''' des anciens jours ? Comme il était revenu d’un long voyage à l’étranger, ses amis lui demandaient ce qu’il avait vu de plus curieux : « Un tyran parvenu à la vieillesse », répondit-il. Car ceux même qui n’ont pas éprouvé de la part d’un despote une injustice personnelle, supportent avec peine le poids et la dureté d’un semblable régime. On déteste tout pouvoir qui est en dehors de la loi et qui ne veut rendre de comptes à personne. [...]</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome III, [[s:Page:Plutarque_-_Œuvres_complètes_de_Plutarque_-_Œuvres_morales_et_œuvres_diverses,_tome_3,_1870.djvu/74|Περι του Σωκρατους Δαιμονιου - Le Démon de Socrate]], [[s:Page:Plutarque_-_Œuvres_complètes_de_Plutarque_-_Œuvres_morales_et_œuvres_diverses,_tome_3,_1870.djvu/83|§6]]'', traduites par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> {{Boîte déroulante début|titre=NdA de trad. Victor Bétolaud de 1870|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Théocrite_back|<span id="Théocrite"><sup>I</sup></span>]] Du nom propre [[w:Nom_théophore|''théophore'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_période_Grèce_Classique#théophore_back|<sup>🔄</sup>]] grec ancien Θεόκριτος / Theókritos [[wikt:en:Θεόκριτος#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;">➥ de l’adjectif et du nom commun θεός / theós [[wikt:en:θεός#Ancient_Greek|(en)]], « divin, dieu, divinité »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ +‎ du verbe κρίνω / krínō, « 1. (transitif) Séparer, diviser, distinguer entre deux choses ou personnes ou parmi un groupe de choses ou de personnes. 2. (transitif) Commander, organiser. 3. S’enquérir, enquêter. 4. Sélectionner, choisir, préférer. 5. (transitif) Trancher un différend ou un concours ; (intransitif) Porter un jugement, prendre une décision : • (voix moyenne, voix passive) Décider d’un concours ; (voix moyenne et voix passive) Se disputer, se disputer, se quereller. 6. Décider ou juger [+accusatif et infinitif = que quelque chose fait quelque chose], [+accusatif et accusatif = que quelque chose est quelque chose]. 7. Discerner entre le bien et le mal. 8. Juger, prononcer. 9. Traduire en justice, accuser. 10. Condamner, critiquer. 11. Sécréter, cacher, dissimuler. »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ + le suffixe adjectival récessif‎ -τος / -tos [[wikt:en:-τος#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;">''Poète'', auteur de [[w:Mime|''mimes'']] (imitations comiques du langage ou des gestes), d’[[w:Poésie_pastorale|''idylles pastorales'']] et de [[w:Épopée|''contes épiques'']].<br /><p style="text-align: right; margin: 0 2em;">([[w:Circa|{{Info|''ca.''|Circa, locution latine que l’on emploie pour indiquer l’approximation d’une date}}]] [[w:310_av._J.-C.|-310]]<sup>[[w:IVe_siècle_av._J.-C.|⏳]]</sup>, à [[w:Théocrite#cite_ref-2|''Syracuse'']] — {{Info|''ca.''|Circa, locution latine que l’on emploie pour indiquer l’approximation d’une date}} [[w:250_av._J.-C.|-250]]<sup>[[w:IIIe_siècle_av._J.-C.|⏳]]</sup>) <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Simmias_de_Thèbes_back|<span id="Simmias_de_Thèbes"><sup>II</sup></span>]] Du grec ancien Σιμμίας ο Θηβαίος / Simmías o Thēbaíos ;<br /><p style="margin: 0 2em; text-indent: 15px;">Philosophe grec et disciple de [[w:Socrate|Socrate]] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Socrate_back|<sup>🔄</sup>]].<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:Ve_siècle_av._J.-C.|V<sup>ème</sup>]] et [[w:IVe_siècle_av._J.-C.|IV<sup>ème</sup>]] siècles {{Info|AEC|Avant l’Ère Commune}}, ''Thèbes'')'''<br /><br /> </div>{{Boîte déroulante fin}} <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">§6. Pendant que '''Théocritos''' discourait ainsi, '''Léontidas''' sortit avec ses amis ; nous entrâmes et saluâmes '''Simmias''', qui était assis sur son lit, tout soucieux et triste, parce que sa demande avait été rejetée sans doute. En nous regardant tous, il s’écria : « '''Héraclès''' ! les moeurs sauvages et barbares ! Ah ! que '''Thalès''' l’ancien avait raison de répondre, lorsqu’après un long voyage à l’étranger ses amis lui demandaient ce qu’il avait remarqué de plus extraordinaire : « Un tyran âgé ». Même un homme qui a eu la chance de n’être pour son compte victime d’aucune injustice exècre déjà le poids et la dureté de ce commerce et est ennemi des dictatures, des dominations arbitraires.[...]</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome II, [https://remacle.org/bloodwolf/historiens/Plutarque/demonsocrate.htm Περι του Σωκρατους Δαιμονιου - Le Démon de Socrate], §6'', traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto; color: #3366BB">― ✳ ―</div> ==== Les [[w:Alimentation_en_Grèce_antique#Banquets|''Symposiaques'']] [[#Symposiaques|<span id="Symposiaques_back"><sup>'''I'''</sup></span>]], ou questions de table ==== <div style="text-align: center; margin: 0 1em;"></div> {{Boîte déroulante début|titre=NdA Les Symposiaques|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Symposiaques_back|<span id="Symposiaques"><sup>I</sup></span>]] Du nom commun grec ancien συμπόσιον / sympósion [[wikt:en:συμπόσιον#Ancient_Greek|(en)]], « Seconde partie d’un repas pendant laquelle un groupe restreint de convives buvaient et discutaient sur un sujet. » ; <br /><p style="margin: 0 2em; text-indent: 15px;">➥ du nom commun σῠμπότης / sŭmpótēs [[wikt:en:συμπότης#Ancient_Greek|(en)]], « compagnon de boisson » ; <br /><p style="margin: 0 4em; text-indent: 15px;">➥ du préfixe σῠν- / sŭn- [[wikt:en:συν-#Ancient_Greek|(en)]], « avec, ensemble » ;<br /><p style="margin: 0 4em; text-indent: 15px;">➥ +‎ du nom commun ποτής / potḗs [[wikt:en:ποτής#Ancient_Greek|(en)]], « boisson » ;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ +‎ du suffixe -ῐον / -ĭon [[wikt:en:-ιον#Ancient_Greek|(en)]] ;<br /><p style="margin: 0 2em; text-indent: 15px;">Entretiens dans un banquet, propos de table. '''<br /><br /> </div>{{Boîte déroulante fin}} ===== <div style="text-align: center;">Livre III</div> ===== <div style="text-align: center; margin: 0 1em;"></div> ====== <div style="text-align: center;">Question VI. Sur le temps où il est à propos de se rapprocher d’une femme.</div> ====== <div style="text-align: center; margin: 0 1em;">Témoignage du statut marital de '''Thalès''' et de sa relation avec sa mère</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid;"><br /><div style="text-align: justify; margin: 0 2em; text-indent: 15px">Καθάπερ οὖν '''Θαλῆς''' ὁ σοφὸς ὑπὸ τῆς μητρὸς ἐνοχλούμενος γῆμαι κελευούσης πῶς ὑπεξέφυγε παρήγαγε λέγων πρὸς αὐτὴν ἐν ἀρχῇ μέν « οὔπω καιρὸς ὦ μῆτερ, » ὕστερον δ´ « οὐκέτι καιρὸς ὦ μῆτερ », οὕτως ἄρα καὶ πρὸς ἀφροδίσια κράτιστον {ἔσται} ἔχειν ἕκαστον, ὥστε κατακλινόμενον λέγειν «οὔπω καιρός», ἀνιστάμενον δ´ « οὐκέτι καιρός ».</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome III, [https://remacle.org/bloodwolf/historiens/Plutarque/sympos3.htm#VI Προβλημα Ϛ. Περὶ καιροῦ συνουσίας. - Question VI. Quel est le temps le plus propre à l'amour?]'', traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div></div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§3. Ainsi donc, comme le sage '''Thalès''', fatigué par sa mère qui l’engageait à se marier, trouva le moyen de lui échapper et de lui donner le change en lui disant une première fois : « Il n’est pas encore temps, ma mère », et, lorsqu’elle insistait encore après qu’il avait passé l’âge : « Il n’est plus temps » ; de même, pour ce qui regarde les plaisirs de l’amour, le mieux sera que chacun se détermine à dire, en se mettant au lit : « Il n’est pas temps encore », et, en sortant du lit : « il n’est plus temps ».</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome III, [[s:Page:Plutarque_-_Œuvres_complètes_de_Plutarque_-_Œuvres_morales_et_œuvres_diverses,_tome_3,_1870.djvu/268|Question VI. Sur le temps où il est à propos de se rapprocher d’une femme]], [[s:Page:Plutarque_-_Œuvres_complètes_de_Plutarque_-_Œuvres_morales_et_œuvres_diverses,_tome_3,_1870.djvu/271|§3]]'', traduites par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Le sage '''Thalès''', pressé par sa mère de se marier, lui répondit avec beaucoup d’adresse. Au commencement, il lui dit : Ma mère, il n’est pas encore temps. Quand il eut passé la fleur de son âge, et qu’elle lui fit de nouvelles instances, il lui répondit : Il n’est plus temps. De même, par rapport à la question proposée, le mieux serait que chacun pût se dire le soir en se couchant : Il n’est pas encore temps ; et le matin, quand il se lève : Il n’est plus temps. »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome III, [https://remacle.org/bloodwolf/historiens/Plutarque/sympos3.htm#VI Προβλημα Ϛ. Περὶ καιροῦ συνουσίας. - Question VI. Quel est le temps le plus propre à l’amour?]'', traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto; color: #3366BB">― ✳ ―</div> ==== De la malignité d’[[w:Hérodote|'''Hérodote''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Chapitre_XX|<sup>🔄</sup>]] ==== <div style="text-align: center; margin: 0 1em;">Ouvrage critique contre l’impartialité d’'''Hérodote''', ses contre-vérités face à la dévaluation des héros et peuples ''grecs''. Le ton critique surprend de la part de '''Plutarque''' au point que l’on contesta l’authenticité du traité, sans succès.</div> ===== Paragraphe XV ===== <div style="text-align: center; margin: 0 1em;">Remise en question de l’origine phénicienne de '''Thalès''' donnée par '''Hérodote'''.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid;"><br /><div style="text-align: justify; margin: 0 2em; text-indent: 15px">Καὶ μὴν τῶν ἑπτὰ σοφῶν, οὓς αὐτὸς σοφιστὰς προσεῖπε, τὸν μὲν '''Θάλητα''' Φοίνικα τῷ γένει τὸ ἀνέκαθεν ἀποφαίνεται βάρβαρον·</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome IV, [https://remacle.org/bloodwolf/historiens/Plutarque/malignhero.htm Περι της Ηροδοτου κακοηθειας]'' traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§15. Quand il parle des sept sages, il les appelle des ''sophistes''. Il prétend démontrer que '''Thalès''' est d’origine ''phénicienne''[[#phénicienne_NdT_DR|<span id="phénicienne_NdT_DR_back"><sup>1</sup></span>]], et qu’à remonter en arrière ce personnage appartient aux Barbares.</div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#phénicienne_NdT_DR_back|<span id="phénicienne_NdT_DR"><sup>1</sup></span>]] I, 170.''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome III, [[s:Page:Plutarque_-_Œuvres_complètes_de_Plutarque_-_Œuvres_morales_et_œuvres_diverses,_tome_3,_1870.djvu/773|De la malignité d’Hérodote]], [[s:Page:Plutarque_-_Œuvres_complètes_de_Plutarque_-_Œuvres_morales_et_œuvres_diverses,_tome_3,_1870.djvu/782|§15]]'', traduites par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Entre les sept sages qu’il appelle ''sophistes'', il enlève '''Thalès''' à la ''Grèce'' pour le donner aux Barbares, en le faisant descendre d’une famille ''phénicienne''.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome IV, [https://remacle.org/bloodwolf/historiens/Plutarque/malignhero.htm De la malignité d’Hérodote]'' traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto; color: #3366BB">― ✳ ―</div> ==== Les opinions des Philosophes ==== <div style="text-align: center; margin: 0 1em;">Ouvrage [[w:doxographe|'''doxographe''']], à la manière de [[w:Diogène Laërce|'''Diogène Laërce''']] [[#Diogène_Laërce_back|<sup>⤵️</sup>]] et [[w:Alcinoos_(philosophe)|'''Alcinoos''']] [[#Alcinoos|<span id="Alcinoos_back"><sup>'''I'''</sup></span>]], qui cite un nombre important de [[w:présocratiques|''présocratiques'']].</div> {{Boîte déroulante début|titre=NdA Les opinions des Philosophes|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Alcinoos_back|<span id="Alcinoos"><sup>I</sup></span>]] Du grec ancien Ἀλκίνοος / Alkínoos [[wikt:en:Ἀλκίνοος#Ancient_Greek|(en)]] ; <br /><p style="margin: 0 2em; text-indent: 15px;">➥ du nom commun ἀλκή / alkḗ [[wikt:en:ἀλκή#Ancient_Greek|(en)]], « 1. Prouesse; force. 2. Défense; garde. 3. Bataille; combat. » ;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ +‎ du nom commun νόος / nóos [[wikt:en:νόος#Ancient_Greek|(en)]], « 1. Esprit : • Perception, sens ; • L’esprit en tant que siège des sentiments, le cœur, l’âme ; • L’esprit en tant que faculté de décision et d’intention, la volonté. 2. Un acte de l’esprit : • Pensée ; • Intention, dessein. 3. Le sens ou la signification d’un mot. 4. (philosophie) Intelligence, intellect, raison. 5. (métaphysique) Le principe agissant sur les particules élémentaires de la matière (tel que décrit par [[w:Anaxagore|Anaxagore]] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Anaxagore_back|<sup>🔄</sup>]]) » ;<br /><p style="margin: 0 2em; text-indent: 15px;">Philosophe de l’époque [[w:Moyen-platonisme|''médio-platonicienne'']] [[#moyen-platonisme|<span id="moyen-platonisme_back"><sup>II</sup></span>]], auteur du Διδασκαλικὸς τῶν Πλάτωνος δογμάτων / Didaskalikòs tō̃n Plátōnos dogmátōn, « Enseignement des doctrines de Platon » [[#Didaskalikos|<span id="Didaskalikos_back"><sup>III</sup></span>]].<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:IIe_siècle|II<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]])<br /><br /><p style="margin: 0 2em; text-indent: 15px;">[[#moyen-platonisme_back|<span id="moyen-platonisme"><sup>II</sup></span>]] Le ''moyen-platonisme'' ou ''médio-platonisme'' est un courant philosophique regroupant des penseurs qui se réclament de Platon, depuis le [[w:Ier_siècle_av._J.-C.|I<sup>er</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]] jusqu'au [[w:IIe_siècle|II<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]].<br /><br /><p style="margin: 0 2em; text-indent: 15px;">[[#Didaskalikos_back|<span id="Didaskalikos"><sup>III</sup></span>]] Le ''Didaskalikos'' se rattache étroitement à la branche du ''moyen-platonisme'' qui interprétait Platon à la lumière surtout d’Aristote. On constate en plus une certaine influence du ''stoïcisme'', en particulier l’emprunt d’un extrait conséquent au ''stoïcien'' Arius Didyme [[#Arius_Didyme|<span id="Arius_Didyme_back"><sup>'''IV'''</sup></span>]]. Souvent pourtant les doctrines du ''stoïcisme'' sont combattues, avant tout, mais pas exclusivement, en ce qui concerne la morale : il est donc impossible que l’auteur du ''Didaskalikos'' fût ''stoïcien orthodoxe'', dont la persistance au [[w:IIe_siècle|II<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]] est sujet à débat. Pour autant, l’auteur veut maintenir une certaine réserve à l’égard des doctrines dont il fait l’exposé : d’où l’emploi de la troisième personne à propos des ''platoniciens''. Enfin, il ne se comptait pas non plus parmi les grands du ''moyen-platonisme''.<br /><p style="margin: 0 2em; text-indent: 15px;">Le Didaskalikos ne peut donc pas être antérieur à Arius Didyme, contemporain de l’empereur Auguste. Il est impossible d’établir un [[wikt:terminus_ad_quem|''terminus ante quem'']] précis. L’ouvrage présente en effet des coïncidences frappantes avec une gamme d’auteurs s’échelonnant de Philon d’Alexandrie jusqu’à Plotin. Depuis fin [[w:XIXe_siècle|XIX<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]], l’habitude a été prise de dater le ''Didaskalikos'' des environs de l’an [[w:150|150]] EC ; et même si cela semble raisonnable, il y a d’autres possibilités à prendre en considération, en l’absence de tout renseignement biographique.<br /><br /><p style="margin: 0 2em; text-indent: 15px;">[[#Arius_Didyme_back|<span id="Arius_Didyme"><sup>IV</sup></span>]] Du nom propre grec ancien Ἄρειος Δίδυμος / Areios Didymos ;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ du nom propre [[w:Nom_théophore|''théophore'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#théophore_back|<sup>🔄</sup>]] Ἄρειος / Áreios [[wikt:en:Ἄρειος#Ancient_Greek|(en)]], « Relatif à Ares »; <br /><p style="margin: 0 2em; text-indent: 30px;">➥ du nom propre Ἄρης / Árēs [[wikt:Ἄρης#Ancient_Greek|(en)]], « 1. (mythologie grecque) La divinité Arès. 2. (par transfert) La planète Mars. 3. (par antonomase) Rencontre ou situation hostile entre groupes de personnes : bataille, affrontement, combat, escarmouche, guerre. 4. (par antonomase) Événements ou conséquences liés aux hostilités : boucherie, carnage, embrasement, massacre, tuerie. 5. (par antonomase, avec synecdoque comme substantif désignant une qualité) Esprit guerrier ou esprit combatif. 6. Épithète de Zeus, « le vengeur » »;<br /><p style="margin: 0 2em; text-indent: 30px;">➥ +‎ du suffixe adjectival -ιος / -ios [[wikt:en:-ιος#Ancient_Greek|(en)]], « Relatif à, appartenant à : "de" » ;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ de l’adjectif δῐ́δῠμος / dĭ́dŭmos [[wikt:en:δίδυμος#Ancient_Greek|(en)]], « 1. Double. 2. Jumeaux. » ;<br /><p style="margin: 0 2em; text-indent: 30px;">➥ [[wikt:en:réduplication|''Réduplication'']] de δύο / dúo [[wikt:en:δύο#Ancient_Greek|(en)]], « deux » ; <br /><p style="margin: 0 2em; text-indent: 30px;">➥ + du suffixe -μος / -mos [[wikt:en:-μος#Ancient_Greek|(en)]] ; forme alternative du suffixe adjectival -ιμος / -imos [[wikt:en:-ιμος#Ancient_Greek|(en)]] de possibilité ou de capacité, « -able » ;<br /><p style="margin: 0 2em; text-indent: 15px;">Philosophe ''alexandrin'' et doxographe de tendance éclectique, il est ami et conseiller d’Auguste, au moins de [[w:-30|-30]] (date fondée sur des références à Auguste et à Arius dans le contexte de la prise d’Alexandrie, épargnée par Auguste - entre autres raisons – grâce à Arius) à [[w:9|9]]. Bien que nous ne connaissions pas de façon certaine l’école à laquelle il se rattachait, il était probablement ''stoïcien'' : il manifeste des affinités avec la ''philosophie académicienne'' telle qu’elle est présentée par Antiochus d’''Ascalon'', de la sympathie pour l’''académicien'' Eudore, une grande précision dans le traitement du matériel ''stoïcien'' et une ouverture à la pensée ''péripatéticienne''.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:Ier_siècle_av._J.-C.|I<sup>er</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]]) [https://books.google.fr/books?id=crnWAAAAMAAJ&newbks=1&newbks_redir=0&lpg=PA3&dq=Richard%20Goulet%20dictionnaire%20des%20auteurs%20antiques&hl=fr&pg=PA345#v=onepage&q&f=false {{Info|<sup>🔍</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume I, §324 - Areios Didymos}}]'''<br/><br/></div> {{Boîte déroulante fin}} ===== <div style="text-align: center;">Livre I</div> ===== <div style="text-align: center; margin: 0 1em;"></div> <div style="text-align: center; margin: 0 auto;">― ● ―</div> ===== <div style="text-align: center;">Livre II</div> ===== <div style="text-align: center; margin: 0 1em;"></div> <div style="text-align: center; margin: 0 auto;">― ● ―</div> ===== <div style="text-align: center;">Livre III</div> ===== <div style="text-align: center; margin: 0 1em;"></div> <div style="text-align: center; margin: 0 auto;">― ● ―</div> ===== <div style="text-align: center;">Livre IV</div> ===== <div style="text-align: center; margin: 0 1em;"></div> <div style="text-align: center; margin: 0 auto; color: #3366BB">― ✳ ―</div> ==== Les animaux de terre ont-ils plus d'adresse que ceux de mer? ==== <div style="text-align: center; margin: 0 1em;"></div> <div style="text-align: center; margin: 0 auto; color: #3366BB">― ✳ ―</div> ==== D’'''Isis''' et d’'''Osiris'''==== <div style="text-align: center; margin: 0 1em;">[[w:Diatribe|Diatribe]] ''[[w:Isis|Isiaque]]'', avec une interprétation ''platonique'' pour intéresser '''Cléa''', admiratrice du mystère d’'''Isis''' à la [[w:Religion_%C3%A9gyptienne|religion ''égyptienne'']]. C’est un plaidoyer, exégèse, avec '''[[w:Osiris|Osiris]]''' qui évoque '''[[w:Dionysos|Dionysos]]''' et '''[[w:Hadès|Hadès]]''', ainsi que des notions de ''[[w:démonologie|démonologie]]'', ''[[w:Dualisme (philosophie)|dualisme]]'' et ''[[w:didactique|didactique]]''. Il contient le premier récit suivi et cohérent du [[w:Mythe_d'Osiris|mythe d’'''Osiris''']]. L’une de ses sources est probablement '''[[w:Hérodote|Hérodote]]'''. mais on croit qu’il s’est rendu lui-même à ''Alexandrie'' pour suivre des cours de médecine.</div> ===== <div style="text-align: center;">Paragraphe IX.</div> ===== <div style="text-align: center; margin: 0 1em;">Témoignage d’un voyage de '''Thalès''' en ''Égypte'', de rencontres avec des prêtres et de récit sur leur divinités.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid;"><br /><div style="text-align: justify; margin: 0 2em; text-indent: 15px">§9. [...] '''Ἑκαταῖος''' δ´ ὁ ''Ἀβδηρίτης'' φησὶ τούτῳ καὶ πρὸς ἀλλήλους τῷ ῥήματι χρῆσθαι τοὺς ''Αἰγυπτίους'', ὅταν τινὰ προσκαλῶνται· προσκλητικὴν γὰρ εἶναι τὴν φωνήν. Διὸ τὸν πρῶτον θεόν, ὃν τῷ παντὶ τὸν αὐτὸν νομίζουσιν, ὡς ἀφανῆ καὶ κεκρυμμένον ὄντα προσκαλούμενοι καὶ παρακαλοῦντες ἐμφανῆ γενέσθαι καὶ δῆλον αὐτοῖς ''Ἀμοῦν'' λέγουσιν.<br /><p style="text-indent: 15px">§10. Ἡ μὲν οὖν εὐλάβεια τῆς περὶ τὰ θεῖα σοφίας '''Αἰγυπτίων''' τοσαύτη {ἦν}, μαρτυροῦσι δὲ καὶ τῶν ''Ἑλλήνων'' οἱ σοφώτατοι, '''Σόλων''' '''Θαλῆς''' '''Πλάτων''' '''Εὔδοξος''' '''Πυθαγόρας''', ὡς δ´ ἔνιοί φασι, καὶ '''Λυκοῦργος''' εἰς ''Αἴγυπτον'' ἀφικόμενοι καὶ συγγενόμενοι τοῖς ἱερεῦσιν.[...]</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome V, [https://remacle.org/bloodwolf/historiens/Plutarque/isisetosiris.htm Περι Ισιδος και Οσιριδος - Traité d’Isis et d’Osiris], §34'', traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1870<br />(également disponible une édition de 1844 [https://remacle.org/bloodwolf/historiens/Plutarque/isisetosiris1.htm ici])</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§9. [...] '''Hécatée''' d’''Abdère'' dit que les ''Égyptiens'' emploient ce mot pour s’appeler les uns les autres, attendu qu’il est essentiellement appellatif. C’est pourquoi, s’adressant au premier Dieu, le même, selon eux, que l’Univers, comme à un être invisible et caché, ils l’exhortent avec supplications, en l’appelant "Amoun", à se faire voir et à se découvrir à eux. Voilà jusqu’à quel point était grande la réserve qui caractérisait la philosophie religieuse des ''Égyptiens''.<br /><p style="text-indent: 15px">§10. C’est ce que témoignent les plus éclairés d’entre les ''Grecs'': '''Solon''', '''Thalès''', '''Platon''', '''Eudoxe''', '''Pythagore''', et aussi, d’après quelques-uns, '''Lycurgue'''. Ils étaient allés en ''Égypte'' et avaient eu des conférences avec les prêtres. [...]</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome V, [https://remacle.org/bloodwolf/historiens/Plutarque/isisetosiris.htm Περι Ισιδος και Οσιριδος - Traité d’Isis et d’Osiris], §§9, 10'', traduites par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870<br/>(également disponible [[s:Sur_Isis_et_Osiris|ici]])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">§9. [...] '''Hécatée''' d’''Abdère'' dit que les ''Egyptiens'' s’en servent pour s’appeler les uns les autres; que ce nom est de sa nature appellatif ; que ce peuple , qui croit que le premier des dieux, qu’il confond avec l’univers, est un dieu caché et inconnu, l’invoque et le prie de se découvrir à eux, en lui disant ''Amoun'' ;<br /><p style="text-indent: 15px">§10. tant ce peuple portait de retenue et de réserve dans sa philosophie religieuse ! C’est ce qu'attestent unanimement les plus sages d’entre les ''Grecs'', '''Solon''', '''Thalès''', '''Platon''', '''Eudoxe''', '''Pythagore''', et, suivant quelques uns, '''Lycurgue''' lui-même, qui tous voyagèrent en ''Egypte'', et y conférèrent avec les prêtres du pays.[...]</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome V, [https://remacle.org/bloodwolf/historiens/Plutarque/isisetosiris1.htm Περι Ισιδος και Οσιριδος - Traité d’Isis et d’Osiris], §§9, 10'', traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe XXXIV.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage de la théorie de '''Thalès''' de l’eau principe de tous les êtres.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§34. Ἥλιον δὲ καὶ Σελήνην οὐχ ἅρμασιν ἀλλὰ πλοίοις ὀχήμασι χρωμένους περιπολεῖν φασιν αἰνιττόμενοι τὴν ἀφ´ ὑγροῦ τροφὴν αὐτῶν καὶ γένεσιν. Οἴονται δὲ καὶ '''Ὅμηρον''' ὥσπερ '''Θαλῆν''' μαθόντα παρ´ ''Αἰγυπτίων'' ὕδωρ ἀρχὴν ἁπάντων καὶ γένεσιν τίθεσθαι· τὸν γὰρ '''Ὠκεανὸν''' '''Ὄσιριν''' εἶναι, τὴν δὲ '''Τηθὺν''' '''Ἶσιν''' ὡς τιθηνουμένην πάντα καὶ συνεκτρέφουσαν. [...]</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome V, [https://remacle.org/bloodwolf/historiens/Plutarque/isisetosiris.htm Περι Ισιδος και Οσιριδος - Traité d’Isis et d’Osiris], §34'', traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1870<br />(également disponible une édition de 1844 [https://remacle.org/bloodwolf/historiens/Plutarque/isisetosiris1.htm ici])</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§34. Ils disent que le soleil et la lune parcourent leur route perpétuelle non pas sur des chars, mais sur des bâtiments de navigation: signifiant par là, que c’est le principe humide qui les entretient et qui leur a donné naissance. Ils croient aussi que c’est des ''Egyptiens'' qu’'''Homère''', et après lui '''Thalès''', ont appris à établir l’eau comme principe générateur de tous les êtres. Ils veulent qu’'''Osiris''' soit l’'''Océan''', qu’'''Isis''' soit '''Téthys''', laquelle nourrit et entretient tout ce qui existe.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome V, [https://remacle.org/bloodwolf/historiens/Plutarque/isisetosiris1.htm Περι Ισιδος και Οσιριδος - Traité d’Isis et d’Osiris], §34'', traduites par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870<br/>(également disponible [[s:Sur_Isis_et_Osiris|ici]])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">§34. Ils disent que le soleil et la lune parcourent les cieux, portés, non sur des chars, mais sur des vaisseaux, pour signifier que tout est nourri et mis en mouvement par l’eau. Ils pensent que c’est des ''Egyptiens'' qu’'''Homère''' et '''Thalès''' avaient pris cette opinion, que l’eau est le principe de tous les êtres, qu’'''Osiris''' est l’'''Océan''', et qu’'''Isis''' est '''Thétis''', qui nourrit et alimente toutes les substances.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome V, [https://remacle.org/bloodwolf/historiens/Plutarque/isisetosiris1.htm Περι Ισιδος και Οσιριδος - Traité d’Isis et d’Osiris], §34'', traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Valère_Maxime|'''Valère Maxime''']] ''([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l'on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:Ier_siècle|I<sup>er</sup> siècle {{Info|EC|de l’Ère Commune}}]])'' [[s:Auteur:Valère_Maxime|<sup>📚</sup>]] == === Actions et paroles mémorables, VII, § 2 === :8. Il y a aussi un mot admirable de Thalès. On lui demandait si les actions des hommes échappaient à la connaissance des dieux. "Leurs pensées non plus", répondit-il. Aussi faut-il nous appliquer à avoir, je ne dis pas seulement les mains, mais encore le cœur pur, dans la persuasion que la divinité est témoin des mouvements les plus secrets de nos âmes. <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Tatien_le_Syrien|'''Tatien''']] le [[w:Assyrie_(province_romaine)|''Syrien'']] ''(vers [[w:120|120]], en [[w:Halicarnasse|''Halicarnasse'']] en [[w:Assyrie_(province_romaine)|Assyrie]] — vers [[w:173|173]], en Assyrie)'' <sup>[[w:IIe_siècle|⏳]]</sup> [[s:Auteur:Tatien_le_Syrien|<sup>📚</sup>]] == === Discours aux Grecs, 41 === == [[w:Lucien_de_Samosate|'''Lucien de Samosate''']] ''(vers [[w:120|120]], à [[w:Samosate|Samosate]] — vers [[w:180|180]], en [[w:Égypte_romaine_et_byzantine|Égypte]])'' <sup>[[w:IIe_siècle|⏳]]</sup> [[s:Auteur:Lucien_de_Samosate|<sup>📚</sup>]] == === Dialogues des morts === https://gallica.bnf.fr/ark:/12148/bpt6k6227866x/f7.item https://gallica.bnf.fr/ark:/12148/bpt6k6227866x/f103.double === Hippias ou le bain === :(2) Mon but est de prouver que les constructeurs de machines qui méritent le plus notre admiration sont ceux qui, distingués par leur science théorique, ont laissé en outre à la postérité des monuments de leur art et des œuvres de leur génie, tandis que les hommes, qui se sont seulement exercés dans la parole méritent plutôt le nom de sophistes que celui de savants. C'est sur la liste traditionnelle de ces artistes que nous voyons figurer Archimède et Socrate de Cnide, qui inventèrent, l'un les moyens de soumettre à Ptolémée la ville de Memphis, sans recourir à un siège, mais en détournant et en divisant le cours du Nil ; l'autre, ceux d'incendier les galères des ennemis. Avant eux, Thalès de Milet, ayant promis à Crésus de faire passer à pied sec à son armée les eaux du fleuve Halys, imagina de les détourner en une seule nuit derrière le camp ; et pourtant ce n'était pas un mécanicien de profession, mais un sage d'un esprit inventif et à l'intelligence duquel on pouvait s'en rapporter. === Exemples de longévité === :(18) Solon, Thalès et Pittacus, que l'on compte au nombre des Sept sages, vécurent chacun cent années. <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Athénée_de_Naucratis|'''Athénée''' de ''Naucratis'']] == [[w:https://remacle.org/bloodwolf/erudits/athenee/livre11.htm|''Le Livre XI des Deipnosophistes'']] [781d] « Alcmène reçoit le vase d'or, et le contemple aussitôt avec admiration. » Stésichore dit qu'Hercule traverse l'Océan dans son vase à boire (poteerioo) ; qu'il s'en servit même pour le franchir et aller enlever les bœufs de Géryon. Nous connaissons aussi par l'histoire le vase à boire (poteerion) de l'arcadien Bathyclès, qui le laissa pour présent à celui qui fut appelé le sage par excellence entre les Sept de la Grèce; mais nombre de potiers de terre font le vase de Nestor, car plusieurs écrivains en ont donné des détails. <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Clément_d%27Alexandrie|'''Clément''']] d'[[w:Histoire_d%27Alexandrie#Annexion|''Alexandrie'']] ''(vers [[w:150|150]]'' <sup>[[w:IIe_siècle|⏳]]</sup>'', à [[w:Athènes#Antiquité|Athènes]] — vers [[w:215|215]]'' <sup>[[w:IIIe_siècle|⏳]]</sup>'', à [[w:Kayseri|Kayseri]])'' [[s:Auteur:Clément_d’Alexandrie|<sup>📚</sup>]] == === Stromates, I, 65 === <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Claude_Élien|'''Claude Élien''']] ''(vers [[w:175|175]]''<sup>[[w:IIe_siècle|⏳]]</sup>'', à [[w:Préneste|Préneste]] — vers [[w:235|235]]''<sup>[[w:IIIe_siècle|⏳]]</sup>'', en [[w:Rome_antique|Rome]])'' [[s:Auteur:Élien_le_sophiste|<sup>📚</sup>]] == === Histoires diverses === :On a vu des philosophes à la tête des affaires publiques : d'autres, se bornant à cultiver leur raison, ont passé leur vie dans le repos. Entre les premiers sont Zaleucus et Charondas qui réformèrent, l'un, le gouvernement des Locriens, l'autre, d'abord celui des Catanéens, puis, après qu'il eut été exilé de Catane, celui des Rhéginiens. Archytas servit utilement les Tarentins. Les Athéniens durent tout à Solon. Bias et Thalès rendirent les mêmes services à l'Ionie, Chilon à Lacédémone, Pittacus à Mitylène, Cléobule à Rhodes. <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Sextus_Empiricus|'''Sextus Empiricus''']] ''([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l'on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:IIe_siècle|II<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]])'' [[s:Auteur:Sextus_Empiricus|<sup>📚</sup>]] == Hypot III, 30, et Liv I contre les phys., sect. 319 https://gallica.bnf.fr/ark:/12148/bpt6k9796311p/f305.item.r=thales <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Lactance|'''Lactance''']] ''(vers [[w:250|250]]''<sup>[[w:IIIe_siècle|⏳]]</sup>'', à [[w:Henchir_Kssiba#Histoire|Civitas Popthensis]] — vers [[w:325|325]]''<sup>[[w:IVe_siècle|⏳]]</sup>'', en [[w:Gaule#La_Gaule_dans_l'Antiquité_tardive|Gaule]])'' == Épit. 4 (https://gallica.bnf.fr/ark:/12148/bpt6k282068z/f300.image.r=thales) Inst. 111, 16 (https://gallica.bnf.fr/ark:/12148/bpt6k282068z/f621.item.r=thales) <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Jamblique|'''Jamblique''']] ''(vers [[w:250|250]]''<sup>[[w:IIIe_siècle|⏳]]</sup>'', à [[w:Qinnasrīn|Chalcis ad Belum]] — vers [[w:333|333]]''<sup>[[w:IVe_siècle|⏳]]</sup>'')'' == === Vie de Pythagore === ==== chap. II ==== (https://web.archive.org/web/20110721184914/http://www.aurumsolis.info/index.php?option=com_phocadownload&view=category&download=1%3Aiamblichus-the-pythagorean-life&id=19%3Awritings-from-the-founders&Itemid=143&lang=en) <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Eusèbe_de_Césarée|'''Eusèbe''']] de [[w:Césarée#Césarée_au_début_du_christianisme|''Césarée'']] ''(vers [[w:265|265]]'' <sup>[[w:IIIe_siècle|⏳]]</sup>'', à Césarée — [[w:340|340]]'' <sup>[[w:IVe_siècle|⏳]]</sup>'', à Césarée)'' [[s:Auteur:Eusèbe_de_Césarée|<sup>📚</sup>]] == Preparation Évangélique, XI, 2 Prepar. évang. I, 8, page 22-25 https://gallica.bnf.fr/ark:/12148/bpt6k9796311p/f310.image.r=thales <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Diogène_Laërce|'''Diogène Laërce''']] ''([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l'on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:IIIe_siècle|III<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]])'' [[s:Auteur:Diogène_Laërce|<sup>📚</sup>]] == ''Ce texte est un extrait de la traduction de Robert Genaille (1933)'' Thalès[1], au dire d’Hérodote, de Douris et de Démocrite, était fils d’Examios et de Cléobuline, et membre de la famille des Thélides, Phéniciens descendant en droite ligne d’Agénor[2] et de Cadmus[3], s’il faut en croire Platon. Le premier, il porta le nom de sage, au temps où Damasias était archonte à Athènes[4]. C’est sous le même archontat que fut créée l’expression : « les sept sages » (cf. Démocrite de Phalère, Registre des Archontes). Thalès fut inscrit comme citoyen de Milet quand il vint dans cette ville avec Nélée chassé de Phénicie. Une autre tradition très courante veut qu’il soit natif de Milet et qu’il descende d’une bonne famille. Il s’occupa de politique avant d’étudier la nature. On croit qu’il ne laissa aucun écrit, car l’Astrologie nautique qu’on lui attribue est de Phocos de Samos. Callimaque[5] croit qu’il découvrit la Petite Ourse et le raconte en vers iambiques : Il mesura, dit-on, les étoiles du Chariot Sur quoi les Phéniciens règlent leur navigation. D’autres auteurs disent qu’il écrivit seulement deux ouvrages, un sur le solstice et un sur l’équinoxe, car il pensait le reste inaccessible. Il passe pour avoir le premier étudié l’astrologie et prédit les éclipses de soleil et les solstices (cf. Eudème, Histoire de l’astrologie)[6]. Xénophane et Hérodote le louent à ce propos, et leur témoignage est confirmé par celui d’Héraclite et de Démocrite. On dit encore (cf. le poète Choirilos) qu’il fut le premier à affirmer l’immortalité des âmes. Le premier il dessina la course du soleil d’un solstice à l’autre, et démontra que comparée au soleil, la lune en est la cent vingtième partie. C’est encore lui qui fixa à trente jours la durée du mois, et qui écrivit le premier traité sur la Nature. Aristote et Hippias disent aussi qu’il accordait une âme aux choses qu’on croit inanimées ; il en donnait pour preuve l’ambre et la pierre de Magnésie. Selon Pamphile[7], il apprit des Égyptiens la géométrie, inscrivit dans un cercle le triangle rectangle, et pour cette découverte immola un bœuf. D’autres, comme Apollodore le calculateur, attribuent cette invention à Pythagore. Thalès a encore développé et précisé l’invention du Phrygien Euphorbe citée par Callimaque dans ses Iambes et concernant le triangle scalène, et tout ce qui touche aux considérations sur les lignes. Il semble encore avoir été en politique un homme de bon conseil. Ainsi, quand Crésus[8] envoya une ambassade aux Milésiens pour demander leur alliance, il s’y opposa, et son intervention sauva la ville, puisque Cyrus l’emporta. Héraclite cite une opinion de Clytos selon laquelle Thalès aurait eu une vie retirée et solitaire. Les uns disent qu’il se maria et eut un fils nommé Kibissos. D’autres prétendent qu’il resta célibataire et adopta le fils de sa sœur, qu’on lui demanda un jour pourquoi il ne cherchait pas à avoir des enfants, et qu’il répondit : « Par amour pour les enfants. » Sa mère l’exhortait à se marier, il lui répondit : « Non, par Zeus, il n’est pas encore temps. » Elle l’y invita une nouvelle fois quand il eut pris de l’âge, mais il lui dit : « Il n’est plus temps. » D’après Hiéronyme de Rhodes (Notes, livre II), il voulut montrer combien il était facile de s’enrichir ayant prévu pour l’année une abondante récolte d’huile, il prit à loyer une oliveraie et gagna beaucoup d’argent[9]. Il soupçonna que l’eau était le principe des choses, que le monde était animé et rempli de démons. On dit qu’il découvrit les saisons de l’année, et qu’il la divisa en trois cent soixante-cinq jours. Il ne suivit les leçons d’aucun maître, sauf en Égypte, où il fréquenta les prêtres du pays. A ce propos, Hiéronyme dit qu’il mesura les Pyramides en calculant le rapport entre leur ombre et celle de notre corps. Si l’on en croit Minuès, il vivait au temps de Thrasybule, qui fut tyran de Milet[10]. L’histoire du trépied trouvé par des pêcheurs et dédié aux sages par le peuple de Milet est bien connue. Des jeunes gens d’Ionie achetèrent à des pêcheurs milésiens leur coup de filet. Ils tirèrent de l’eau un trépied. On se querella et les Milésiens envoyèrent une ambassade à Delphes. Voici quel fut l’oracle de la divinité : Race de Milet, tu interroges Phébus au sujet d’un trépied ? Au plus sage de tous, je donne ce trépied[11]. Ils le donnent alors à Thalès, qui le donne à un autre, et cet autre à un autre, et ainsi de suite jusqu’à Solon, qui, déclarant que seul le dieu était le plus sage de tous, rendit le trépied à Delphes. Callimaque, dans ses Iambes, rapporte cette histoire autrement ; il la tient de Léandre de Milet. Il dit qu’un certain Bathyclès d’Arcadie laissa en mourant une coupe pour qu’elle fût donnée à l’homme le plus sage. Elle fut donc donnée à Thalès, et après être passée de main en main et avoir fait le tour des sages, elle revint à Thalès. Celui-ci en fit don alors à Apollon de Didyme, en ces termes selon le poème de Callimaque : Thalès me donne au protecteur du peuple du Nil, Thalès qui a reçu deux fois ce présent, ce qui, en prose, se dit ainsi : « Thalès de Milet, fils d’Examios, à Apollon delphien, ce présent qu’il a reçu deux fois des Grecs. » Celui qui portait la coupe de sage en sage, le fils de Bathyclès, s’appelait Thyrion (cf. Éleusis, Livre sur Achille, et Alexon de Mynde, Fables, livre IX). Eudoxe de Cnide et Évanthès de Milet disent de leur côté qu’un ami de Crésus reçut du roi un vase d’or, pour le donner au plus sage des Grecs, qu’il le donna à Thalès et que ce vase parvint jusqu’à Chilon. Celui-ci consulta la Pythie, pour savoir qui était plus sage que lui. Elle répondit que c’était Myson (je parlerai de lui : Eudoxe le met parmi les sages à la place de Cléobule et Platon à la place de Périandre.) Voici la réponse que lui fit la Pythie : Il y a un habitant de l’Oeta, Myson, né à Chénée, Qui plus que toi est riche de sages pensées. L’homme qui consulta l’oracle pour Chilon s’appelait Anacharsis. Dédale le Platonicien et Cléarque disent que la coupe fut envoyée par Crésus à Pittacos, et que c’est ainsi qu’elle passa de main en main. D’après Andron, d’autre part (Livre du trépied), les Argiens décidèrent que le trépied serait attribué comme prix de vertu au plus sage des Grecs. Aristodème de Sparte fut choisi et c’est lui qui donna le trépied à Chilon. Alcée est aussi partisan d’Aristodème dont il parle dans les vers suivants : :Comme jadis Aristodème, dit-on, :Prononça à Sparte cette parole bien juste : :C’est de l’argent, un homme, oui de l’argent, :Car l’homme vertueux n’est jamais pauvre. D’autres disent encore que Périandre envoya à Thrasybule, tyran de Milet, un navire chargé, que ce navire fit naufrage dans la mer de Cos, et que quelque temps après le trépied fut trouvé par des pêcheurs. Phanodicos dit que le trépied fut trouvé dans la mer Attique, porté à la ville, et que l’assemblée du peuple s’étant réunie le fit porter à Bias. Pourquoi cela, je le dirai quand je parlerai de Bias. Selon d’autres auteurs, le trépied avait été fabriqué par Héphaïstos et donné en présent de la part de ce dieu à Pélops lors de son mariage. Il vint ensuite à Ménélas, fut enlevé avec Hélène par Alexandre, jeté dans la mer de Cos à l’instigation de la Spartiate qui prévoyait qu’il serait un sujet de querelle. Plus tard, en ce lieu, des Lébédiens achetèrent le produit d’un coup de filet et c’est le trépied qui fut tiré de l’eau. Il y eut querelle avec les pêcheurs, on vint jusqu’à Cos, et comme on ne s’accordait pas, on s’adressa à Milet, qui était la capitale. Les Milésiens envoyèrent des députés qui ne furent pas écoutés, aussi firent-ils la guerre aux gens de Cos. Comme de chaque côté il mourait beaucoup de gens, l’oracle déclara qu’il fallait donner le trépied au plus sage. Les deux camps s’entendirent alors pour l’attribuer à Thalès, qui par la suite le consacra à Apollon de Didyme. Pour en revenir à la réponse de l’oracle aux gens de Cos, elle disait ceci : La querelle entre Ioniens et Méropes ne cessera pas Avant que le trépied d’or qu’Héphaïstos jeta dans la mer N’ait quitté votre ville pour la maison de l’homme Qui connaît le présent, l’avenir et le passé. La réponse aux Milésiens fut la suivante : Race de Milet, tu interroges Phoebus au sujet d’un trépied... comme il a été dit plus haut. En voilà assez sur ce sujet[12]. Hermippe, dans ses Vies, rapporte à Thalès ce qui est dit par d’autres de Socrate : il aimait à dire qu’il remerciait la fortune de trois choses : d’être un humain et non une bête, d’être un homme et non une femme, enfin d’être un Grec, et non un barbare. On raconte encore qu’étant sorti de chez lui pour contempler les astres, il tomba dans un puits[13]. Une vieille femme survenant se moqua de lui en ces mots : « Comment, Thalès, toi qui n’es pas capable de voir ce qui est à tes pieds, t’imagines-tu pouvoir connaître ce qui est dans le ciel ? » Timon[14] a bien connu aussi la science de Thalès en astronomie, et dans ses Silles, il le loue en ces termes : Comme Thalès, un des sept sages, qui fut savant astronome. L’Argien Lobon dit que ses écrits font un total de quelque deux cents vers, et que sous sa statue on écrivit : Thalès de Milet repose ici dans le sol qui l’a nourri, Il fut un sage, et le premier des astrologues. Voici un de ses poèmes : Le trop parler n’est pas marque d’esprit. Trouvez une seule chose sage, Choisissez une seule chose belle, Et vous clouerez le bec à bien des bavards. On lui attribue encore les sentences suivantes : de tous les êtres, le plus ancien, c’est Dieu, car il n’a pas été engendré ; le plus beau, c’est le monde, car il est l’ouvrage du dieu ; le plus grand, c’est l’espace, car il contient tout ; le plus rapide, c’est l’esprit, car il court partout ; le plus fort, c’est la nécessité, car elle vient à bout de tout ; le plus sage, c’est le temps, parce qu’il découvre tout. La mort, dit-il, ne diffère en rien de la vie. On lui répond : « Pourquoi, alors, ne te donnes-tu pas la mort ? » ; « Parce que vie ou mort, c’est tout un », réplique-t-il. Quelqu’un lui demande ce qui du jour ou de la nuit fut créé d’abord ; il répond : « La nuit est en avance d’un jour. » On lui demande si les mauvaises actions d’un homme échappent au regard des dieux. Il répond : « Ils voient même les mauvaises pensées. » Un homme adultère lui demandait s’il pouvait jurer qu’il n’avait pas commis d’adultère. Il répondit : « Le parjure n’est pas pire que l’adultère. » On lui demandait ce qui était difficile : « Se connaître » dit-il ; ce qui était facile : donner un conseil à autrui ; ce qui était le plus doux : jouir ; ce que c’était que la divinité : un être sans commencement ni fin ; encore une chose difficile : voir un tyran âgé ; comment supporter aisément l’infortune : en voyant ses ennemis plus malheureux encore ; comment vivre vertueusement : en ne faisant pas ce que nous reprochons à autrui ; qui est heureux : l’homme bien portant, riche, courageux et instruit. Il disait encore que l’on doit penser à ses amis aussi bien en leur absence qu’en leur présence, que la beauté ne vient pas d’un beau visage, mais de belles actions. « Ne t’enrichis pas injustement, conseillait-il, et veille à ne pas être cité en justice pour de mauvaises paroles contre tes proches et tes amis. Comme tu traites tes parents, tes enfants te traiteront. » Du Nil[15] il disait qu’il débordait quand ses eaux étaient repoussées par les vents étésiens qui soufflent contre son cours. Apollodore dans ses Chroniques dit que Thalès naquit la première année de la trente-cinquième olympiade[16]. Il mourut dans sa soixante-dix-huitième année ou, comme le dit Sosicrate, dans sa quatre-vingt-dixième année, car ce fut dans la cinquante-huitième olympiade. Il vécut du temps de Crésus, auquel il promit de faire traverser l’Hallys[17] sans pont, en détournant le cours du fleuve. Il y eut cinq autres personnages du nom de Thalès (cf. Démétrios de Magnésie, Homonymes) : un rhéteur de Callatie, au style prétentieux, un peintre de Sicyone, de noble origine, un troisième, très ancien, du temps d’Hésiode, d’Homère et de Lycurgue, un quatrième, mentionné par Douris dans son traité de la peinture, un cinquième, plus jeune et peu connu, cité par Denys dans ses Critiques. Pour en revenir à notre sage, il mourut en regardant les jeux gymniques, pour avoir eu trop chaud et trop soif et par suite de sa fatigue et de son grand âge. Voici son épitaphe : :Ce tombeau, certes, est bien petit, :Mais la renommée de l’homme est allée au ciel. :C’est celui de Thalès le très sage. J’ai écrit sur lui les vers suivants dans le premier livre de mes épigrammes ou « vers de mètres divers[18] : :Tandis qu’il regardait les jeux, ô Zeus Hélios, :Tu as ravi du stade le sage Thalès. :Je te loue de l’avoir rapproché du ciel. Il était si vieux :Que de la terre il ne pouvait plus voir les astres. Thalès est l’auteur du fameux « connais-toi toi-même » qu’Antisthène (Livre des Filiations) attribue à Phémonoé, en déclarant que Chilon se l’appropria mensongèrement. Sur les sept sages, qu’il est juste de citer maintenant l’un après l’autre, voici la tradition. Damon de Cyrène, qui blâme tous les philosophes dans ses écrits, s’attaque surtout aux sept sages. Anaximène dit que tous étaient poètes. Dicéarque dit qu’ils n’étaient ni sages ni philosophes, mais hommes d’esprit et législateurs. Archétimos de Syracuse a décrit leurs assemblées chez Cypsélos[19] et dit qu’il y assista personnellement. Euphoros dit que tous, sauf Thalès, fréquentèrent Crésus. D’autres disent qu’ils se réunirent à Panionium, à Corinthe et à Delphes. On rapporte même leurs paroles, et qui a prononcé telle ou telle. Exemple : Le Spartiate Chilon fut sage, Lui qui dit : Rien de trop, Tout est bien qui vient en son temps ! On n’est pas d’accord sur leur nombre. Léandre, au lieu de Cléobule et de Myson, met Léophante, fils de Gorsias, ou Lébédios d’Éphèse et Épiménide de Crète. Platon, dans le Protagoras[20], met Myson à la place de Périandre. Éphoros met Anacharsis à la place de Myson et d’autres ajoutent Pythagore. Selon Dicéarque, il y en a quatre sur qui tout le monde est d’accord : Thalès, Bias, Pittacos et Solon. Le même auteur en nomme six autres, parmi lesquels il en choisit trois : Aristodème, Pamphile, le Lacédémonien Chilon, Cléobule, Anacharsis et Périandre. D’autres ajoutent Acousilaos, Caba ou Scala, un Argien. Hermippe, dans son livre sur les sages, dit qu’ils furent dix-sept et que chacun en choisit sept selon ses préférences. Ce sont Solon, Thalès, Pittacos, Bias, Chilon, Cléobule, Périandre, Anacharsis, Acousilaos, Épiménide, Léophante, Phérécyde, Aristodème, Pythagore, Lasos, fils de Charmantidas ou de Sisambrinos ou, selon Aristoxène, de Chabrinus, Hermonée, Anaxagore. Hippobotos (Catalogue des Philosophes) les inscrit ainsi : Orphée, Linos, Solon, Périandre, Anacharsis, Cléobule, Myson, Thalès, Bias, Pittacos, Épicharme et Pythagore. Voici des lettres attribuées à Thalès[21] : ==== Thalès à Phérécyde ==== « J’apprends que vous vous disposez à présenter aux Grecs le premier traité ionien des choses divines. Vous agiriez peut-être plus sagement en lisant votre ouvrage à vos amis, qu’en communiquant à n’importe quelles gens des écrits qui ne peuvent guère leur être utiles. « Si cela vous plaît, j’aimerais profiter de vos recherches et, si vous m’y invitez, je viendrai vous trouver au plus tôt. Car Solon d’Athènes et moi, qui avons déjà traversé deux fois la mer pour aller visiter la Crète, et pour aller en Égypte nous entretenir avec les prêtres et les astronomes du lieu, nous sommes assez sages pour ne pas hésiter à la traverser de nouveau pour aller vous voir. « Je parle de Solon, parce qu’il viendra avec moi si vous le permettez. Vous êtes un sédentaire, vous allez rarement en Ionie, vous n’aimez guère aller voir les étrangers, et vous ne songez, j’imagine, qu’à écrire. « Mais nous qui n’écrivons pas, nous parcourons volontiers la Grèce et l’Italie. » ==== Thalès à Solon ==== « Si vous quittez Athènes, vous aurez, je crois, tout avantage à venir vous établir à Milet, parmi les colons athéniens. Il n’y a là pour vous aucun danger. Si vous hésitez, sous prétexte que nous, Milésiens, sommes gouvernés par un tyran (je sais que vous haïssez tout pouvoir absolu), songez du moins que vous aurez plaisir à vivre avec nous qui sommes vos amis. Je sais que Bias vous a écrit et vous invite à aller à Priène. Si vous trouvez préférable d’habiter la ville de Priène, j’irai vivre là-bas avec vous. » <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Ausone|'''Ausone''']] ''([[w:309|309]]/[[w:310|310]], à [[w:Bazas|Bazas]] ou à [[w:Bordeaux#Burdigala,_cité_romaine_(Ier_siècle_-_Ve_siècle)|Bordeaux]] — [[w:394|394]]/[[w:395|395]], entre [[w:Langon_(Gironde)|Langon]] et [[w:La_Réole|La Réole]])'' <sup>[[w:IVe_siècle|⏳]]</sup> [[s:Auteur:Ausone|<sup>📚</sup>]] == === Le Jeu des Sept Sages === :Thalès a trouvé [texte grec] pour nous défendre de nous porter cautions, parce qu'il y a du danger à répondre ainsi pour d'autres[iv]. Nous donnons-là un avis qui ne plaira pas beaucoup aux emprunteurs. :THALÈS : Je suis Thalès de Milet ; j'ai dit, comme le poète Pindare, que l'eau est, le principe de toute chose. C'est à moi que des pêcheurs donnèrent autrefois [un trépied d'or] qu'ils avaient tiré de la mer : ils m'avaient choisi pour obéir au dieu de Délos, qui envoyait ce présent à un sage. Je refusai de le recevoir, je le leur rendis pour le porter à d'autres que je croyais plus dignes. Envoyé à tous les sept Sages, et renvoyé par eux, il nie fut rapporté. Je le reçus alors pour le consacrer à Apollon : car si Phébus a voulu qu'on choisit un sage, ce n'était pas d'un homme, mais d'un dieu qu'il fallait l'entendre. Je suis donc ce Thalès : mais un motif m'amène sur la scène. Comme les deux sages qui m'ont précédé, je viens défendre la sentence dont je suis l'auteur. Elle déplaira, mais non certes aux esprits prudents que l'expérience a instruits et rendus plus avisés. Nous avons dit : [texte grec], ou, en latin : Cautionne, mais tu t'en trouveras mal. Je pourrais parcourir mille exemples pour vous montrer des cautions et des répondants bien et dûment convaincus de repentir. Mais je ne veux nommer personne. Que chacun de, vous ré-fléchisse, et compte en lui-même combien de gens ont perdu ou souffert de s'être ainsi portés cautions pour d'autres. Toutefois, si un pareil service a du charme pour vous, n'y renoncez ni les uns ni les autres. :Alors que les uns applaudissent, et que les autres, si je les blesse, me sifflent. :THALÈS DE MILET. :AVANT d'oser une mauvaise action, à défaut de Témoin redoute ta conscience. La vie s'éteint, mais la gloire de la mort ne meurt point. Ce que tu veux faire, abstiens-toi de le dire. C'est un supplice de craindre ce qu'on ne peut empêcher. Si tu blâmes avec raison, ton hostilité même est profitable ; si tu loues mal à propos, ton amitié même est nuisible. Rien de trop. - Arrêtons-nous, et qu'ici même il n'y ait rien de trop. <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Proclus|'''Proclus''']] ''(le 7 ou 8 février [[w:412|412]], à [[w:Constantinople|Constantinople]] — le 17 avril [[w:485|485]], à [[w:Histoire_d%27Athènes#Antiquité_tardive|Athènes]])''<sup>[[w:Ve_siècle|⏳]]</sup> [[s:Auteur:Proclus|<sup>📚</sup>]] == === Commentaire sur le premier livre d'Euclide, 65, 3 === ὥσπερ οὖν παρὰ τοῖς Φοίνιξιν διὰ τὰς ἐμπορείας καὶ τὰ συναλλάγματα τὴν ἀρχὴν ἔλαβεν ἡ τῶν ἀριθμῶν ἀκριβὴς γνῶσις, οὕτω δὴ καὶ παρ' Αἰγυπτίοις ἡ γεωμετρία διὰ τὴν εἰρημένην αἰτίαν εὕρηται. Θαλῆς δὲ πρῶτον εἰς Αἴγυπτον ἐλθὼν μετήγαγεν εἰς τὴν Ἑλλάδα τὴν θεωρίαν ταύτην καὶ πολλὰ μὲν αὐτὸς εὗρεν, πολλῶν δὲ τὰς ἀρχὰς τοῖς μετ' αὐτὸν ὑφηγήσατο τοῖς μὲν καθολικώτερον ἐπιβάλλων, τοῖς δὲ αἰσθητικώτερον. <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == « [[w:Souda|'''Suidas''']] » ''([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l'on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] fin du [[w:IXe_siècle|IX<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]])'' [[s:Auteur:Suidas|<sup>📚</sup>]] == === La Souda === Θαλῆς, Ἐξαμύου καὶ Κλεοβουλίνης, Μιλήσιος, ὡς δὲ Ἡρόδοτος Φοῖνιξ: γεγονὼς πρὸ Κροίσου, ἐπὶ τῆς λε# ὀλυμπιάδος, κατὰ δὲ Φλέγοντα γνωριζόμενος ἤδη ἐπὶ τῆς ζ#. ἔγραψε περὶ μετεώρων ἐν ἔπεσι, Περὶ ἰσημερίας, καὶ ἄλλα πολλά. ἐτελεύτησε δὲ γηραιός, θεώμενος γυμνικὸν ἀγῶνα, πιληθεὶς δὲ ὑπὸ τοῦ ὄχλου καὶ ἐκλυθεὶς ὑπὸ τοῦ καύματος. πρῶτος δὲ Θαλῆς τὸ τοῦ σοφοῦ ἔσχεν ὄνομα καὶ πρῶτος τὴν ψυχὴν εἶπεν ἀθάνατον ἐκλείψεις τε καὶ ἰσημερίας κατείληφεν. ἀποφθέγματα δὲ αὐτοῦ πλεῖστα: καὶ τὸ θρυλλούμενον: γνῶθι σαυτόν. τὸ γάρ, ἐγγύα, πάρα δ' ἄτα, Χίλωνός ἐστι μᾶλλον, ἰδιοποιησαμένου αὐτό: καὶ τό, μηδὲν ἄγαν. ssw3625md4o9nh63a9is9p0snaxh4q4 773689 773688 2026-09-30T07:02:21Z Alex Mtlr 103840 /* Chapitre XVII. */ 773689 wikitext text/x-wiki {| border="0" cellpadding="0" width="100%" style="background: #f9f9f9" | colspan="3" height="25"|<div style="text-align: center;">[[Philosophie/Thalès de Milet|'''Thalès de Milet''']]</div> |- | width="33%"|'''[[Philosophie/Thalès de Milet/Textes_et_traductions_période_République_Romaine|Période République Romaine]]''' |- | width="33%"|'''[[Philosophie/Thalès de Milet/Textes_et_traductions_période_Grèce_Hellénistique|Période de la Grèce Hellénistique]]''' |- | width="33%"|'''[[Philosophie/Thalès de Milet/Textes_et_traductions_Ier_millénaire_AEC|Période de la Grèce Classique]]''' |} {{EnTravaux}} <span style="font-size:18pt;">Période du Principat de l’[[w:Empire_romain|''Empire'']] [[#Empire|<span id="Empire_back"><sup>'''I'''</sup></span>]] [[w:Rome_antique|''Romain'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Rome_back|<sup>🔄</sup>]]</span> <p style="text-align: right;">(16 janvier [[w:27_av._J.-C.|-27]] <sup>[[w:Ier_siècle_av._J.-C.|⏳]]</sup>, nomination de [[w:Auguste|'''Caius Iulius Caesar Octavianus''']] aux titres d’[[w:Auguste_(titre)|''Augustus'']] et de [[w:Princeps_senatus|''Princeps'']] par le [[w:Sénat_romain|''Sénat romain'']] — fin du [[w:IIIe_siècle|III<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]], création du système [[w:Tétrarchie|''tétrarchique'']] [[#tétrarchie|<span id="tétrarchie_back"><sup>'''II'''</sup></span>]] par [[w:Dioclétien|'''Dioclétien''']] [[#Dioclétien|<span id="Dioclétien_back"><sup>'''III'''</sup></span>]] pour faire face aux [[w:Invasions_barbares#Première_période_:_les_mouvements_migratoires_germaniques_du_IIIe_siècle|''incursions barbares'']]) {{Boîte déroulante début|titre=NdA Empire|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Empire_back|<span id="Empire"><sup>I</sup></span>]] Du nom commun latin imperium [[wikt:en:imperium#Latin|(en)]], « 1. L’empire, l’État, le gouvernement impérial, le royaume, la domination. 2. Le droit ou le pouvoir de commander ou d’avoir le contrôle ; domination. 3. Commandement ou autorité absolue sur l’empire (ou un autre régime politique) ; souveraineté ; domination. 4. (militaire) Autorité militaire, commandement (d’une armée). 5. L’exercice de l’autorité, de la règle, de la loi, du contrôle, de la souveraineté. 6. Un commandement, un ordre, une direction, une injonction.) »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ du verbe imperō, « 1. (avec datif) Commander, donner des ordres à, imposer, exiger. 2. Gouverner. »;<br /><p style="margin: 0 2em; text-indent: 30px;">➥ du préfixe prépositionnal in-, « 1. Dans, à l’intérieur. 2. Contre; dans; sur; vers. 3. (utiliser comme un intensifieur). 4. Attaché à des [[w:Aspect_inchoatif|''verbes inchoatifs'']], il peut exprimer le sens d’un changement en cours ou d’un achèvement partiel. »;<br /><p style="margin: 0 2em; text-indent: 30px;">➥ +‎ du verbe parō [[wikt:en:paro#Latin|(en)]], « 1. Arranger, ordonner, concevoir. 2. Fournir, meubler, préparer. 3. Résoudre, viser, décider. 4. Obtenir, acquérir, se procurer, se faire. »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ + du suffixe nominal abstractif‎ -ium [[wikt:en:-ium#Latin|(en)]], désignant parfois des offices et des groupes. »;<br /><p style="margin: 0 2em; text-indent: 15px;">L’historien spécialiste de l’[[w:Grèce_antique|''antiquité grecque'']] [[w:Moses_Finley|Moses Finley]] définit un empire par tout {{Info|''« exercice durable par un État d’une autorité, d’un pouvoir, ou d’un contrôle sur un ou plusieurs États, communautés ou peuples »''|Moses Finley, Économie et société en Grèce antique, La Découverte, 2007.}}. L’historien [[w:Jean_Tulard|Jean Tulard]], précise cette définition par {{Info|''cinq traits suivants''|Jean Tulard, Les Empires occidentaux de Rome à Berlin, PUF, 1997.}} : :::* '''Une volonté expansionniste ; :::* '''Une organisation centralisée ; :::* '''Des peuples encadrés par une armature politique et fiscale commune ; :::* '''La croyance en une supériorité d’essence ; :::* '''Un début et une fin clairement identifiés. <br /><p style="margin: 0 2em; text-indent: 15px;">'''[[#tétrarchie_back|<span id="tétrarchie"><sup>II</sup></span>]] Du nom commun grec ancien τετραρχία / tetrarkhía;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ du préfixe τετρα- / tétra- [[wikt:en:τετρα-#Ancient_Greek|(en)]], « quatre »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ + du suffixe -αρχία / -arkhía [[wikt:en:-αρχία#Ancient_Greek|(en)]], « -archie (forme de gouvernement ou de règle) »;<br /><p style="margin: 0 2em; text-indent: 15px;"> Système de gouvernement de l’Empire ''romain'' mis en place par Dioclétien à la fin du [[w:IIIe_siècle|III<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]], pour faire face aux invasions barbares. Il consiste en la division de la direction de l’empire entre, d’une part deux [[w:Empereur_romain|''empereurs'']] — les [[w:Auguste_(titre)|''augustes'']] —, d’autre part deux ''lieutenants'' (successeurs désignés des ''augustes'') — les [[w:C%C3%A9sar_(titre)|''césars'']]. <br /><br /><p style="margin: 0 2em; text-indent: 15px;">'''[[#Dioclétien_back|<span id="Dioclétien"><sup>III</sup></span>]] [[w:Nom_romain|Tria Nomina]] en latin {{Info|Gaius|praenomen, nom individuel du citoyen romain}} {{Info|Aurelius|nomen, nom de famille}} {{Info|Valerius|cognomen, surnom héréditaire, servant à distinguer les diverses branches d’une même gens}}, surnommé Dioclētiānus [[wikt:en:Diocletian#English|(en)]] lorsqu’il a été proclamé empereur par ses troupes;<br /><p style="margin: 0 2em; text-indent: 15px;"> Militaire et empereur, connu pour avoir séparé et élargi les services civils et militaires de l’empire, et réorganisé les divisions provinciales de l’empire, établissant le gouvernement le plus vaste et le plus bureaucratique de l’histoire de l’empire. En [[w:286|286]], il nomme son ''césar'', ou adjoint et successeur, [[w:Maximien_Hercule|Maximien]] ''Auguste'', co-empereur, et partage l’Empire entre l’Orient et l’Occident, puis en 293, y nomme respectivement [[w:Galère_(empereur_romain)|Maximien Galère]] et [[w:Constance_Chlore|Constance Chlore]] comme ''césar''.<br/><br/></div> ''' {{Boîte déroulante fin}} == [[w:Sénèque|'''Sénèque''']] [[#Sénèque|<span id="Sénèque_back"><sup>'''I'''</sup></span>]] == <p style="text-align: right;">([[w:5_av._J.-C.|-5]] <sup>[[w:Ier_siècle_av._J.-C.|⏳]]</sup> / [[w:1|1]] <sup>[[w:Ier_siècle|⏳]]</sup>, à [[w:Corduba|Corduba]] — 12 avril [[w:65|65]], à [[w:Rome_antique|''Rome'']], dans une maison de plaisance, la « quatrième pierre milliaire », contraint au [[w:Suicide_forcé|''suicide forcé'']] par l’empereur [[w:Néron|'''Néron''']] après avoir été dénoncé dans la [[w:Conjuration_de_Pison|''Conjuration de Pison'']], sans preuve selon [[w:Tacite|'''Tacite''']] [https://remacle.org/bloodwolf/historiens/tacite/annales15.htm <sup>Annales, l.V, §§LX-LXVI.</sup>]) [[s:Auteur:Sénèque_le_Jeune|<sup>📚</sup>]] [https://books.google.fr/books?id=_HZTvAxN7CIC&newbks=1&newbks_redir=0&lpg=PA3&dq=bibliogroup%3A%22Dictionnaire%20des%20philosophes%20antiques%22&hl=fr&pg=PA177#v=onepage&q&f=true {{Info|<sup>🔍</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume VI, §43 - Seneca (Lucius Annaeus –)}}] [[Fichier:Duble_herma_of_Socrates_and_Seneca_Antikensammlung_Berlin_03_.jpg|vignette|<p style="text-align: justify; text-indent: 15px;">Double-hermès du [[w:IIIe_siècle|III<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]], unique portrait de '''Sénèque''' nommé et authentifié, et associé à celui de '''Socrate''', dont le point commun est celui d’avoir été contraint de se donner la mort. Copie ''romaine'' d’un modèle fait du vivant même du philosophe [https://books.google.fr/books?id=_HZTvAxN7CIC&newbks=1&newbks_redir=0&lpg=PA3&dq=bibliogroup%3A%22Dictionnaire%20des%20philosophes%20antiques%22&hl=fr&pg=PA180#v=onepage&q&f=true {{Info|<sup>➕</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume VI, §43 - Seneca (Lucius Annaeus –), Iconographie}}] [https://books.google.fr/books?id=_HZTvAxN7CIC&newbks=1&newbks_redir=0&lpg=PA3&dq=bibliogroup%3A%22Dictionnaire%20des%20philosophes%20antiques%22&hl=fr&pg=PA201#v=onepage&q&f=true {{Info|<sup>➕➕</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume VI, §43 - Seneca (Lucius Annaeus –), Iconographie - contribution de J. Lang}}].<br /><p style="text-align: justify; text-indent: 15px;">Matériau : Marbre blanc-brunâtre, légèrement veiné, finement cristallin.<br /><p style="text-indent: 15px;">Provenance : ''Rome'', 1813.<br /><p style="text-align: justify; text-indent: 15px;">Exposition : Staatliche Museen zu Berlin, Antikensammlung, SK. 391 [https://recherche.smb.museum/detail/698814/doppelherme-des-sokrates-und-seneca-mit-namensbeischriften-der-dargestellten <sup>🔍</sup>].]] <div style="text-align: justify; margin: 0 1em; text-indent: 15px">Homme politique romain, philosophe stoïcien et dramaturge, il devient tour à tour conseiller à la cour impériale sous '''Caligula''' puis '''Claude''', est exilé en 41 en ''Corse'', où il écrit ses premiers traités philosophiques avant d’être rappelé comme tuteur du jeune '''Néron''' en 49, et enfin, lorsque ce dernier accède au pouvoir, en devient le conseiller et l’un des personnages les plus influents de l’Empire.</div> {{Boîte déroulante début|titre=NdA Sénèque|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Sénèque_back|<span id="Sénèque"><sup>I</sup></span>]] [[w:Nom_romain|Tria Nomina]] en latin {{Info|Lucius|praenomen, nom individuel du citoyen romain}} {{Info|Annaeus|nomen, nom de famille}} {{Info|Seneca|cognomen, surnom héréditaire, servant à distinguer les diverses branches d’une même gens}}'''<br/><br/></div> {{Boîte déroulante fin}} === [[w:Sénèque#Physique|Questions naturelles]] === <p style="text-align: right;">[[s:Questions_naturelles|📚]] <div style="text-align: justify; margin: 0 1em; text-indent: 15px">Ouvrage de philosophie naturelle écrit vers 65. Il ne s’agit pas d’une [[w:Encyclopédie|encyclopédie]] [[#encyclopédie|<span id="encyclopédie_back"><sup>'''I'''</sup></span>]] systématique comme l’[[w:Histoire_naturelle_(Pline_l'Ancien)|''Histoire naturelle'']] [[#Histoire_naturelle|<sup>⤵️</sup>]] de [[w:Pline_l'Ancien|'''Pline l’Ancien''']] [[#Pline_l’Ancien_I|<sup>⤵️</sup>]], bien que ces 2 œuvres représentent les rares ouvrages romains consacrés à l’étude du monde naturel. L’investigation de '''Sénèque''' se déroule principalement à travers la prise en compte des points de vue d’autres penseurs, ''grecs'' et ''romains'', bien qu’elle ne soit pas dénuée de pensées originales, dont éthiques conforment à la pensée ''stoïcienne''.</div> {{Boîte déroulante début|titre=NdA Questions naturelles|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#encyclopédie_back|<span id="encyclopédie"><sup>I</sup></span>]] Du nom commun [[w:Latin#Latin_humaniste|latin Renaissance]] encyclopaedīa [[wikt:en:encyclopaedia#Latin|(en)]]; de l’expression grec ancien ἐγκύκλῐος παιδείᾱ / enkúklios paideíā [https://dumas.ccsd.cnrs.fr/dumas-03927443/file/DONNADILLE-MR2-Pline-VERS-FINALE.pdf {{Info|<sup>🔍</sup>|Lisa Donnadille. Merveilles animalières dans les livres VIII à XI de l’Histoire naturelle de Pline l’Ancien. Littératures. 2020. ffdumas-03927443, p.21}}], « cercle de l’éducation ou des sciences, l’ensemble des sciences qui constituent une éducation complète »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ de l’adjectif ἐγκύκλιος / enkúklios, littéralement « qui est rond ou tourne en rond, circulaire », ou au sens figuré « qui revient en cercle sur soi-même, périodique », « qui embrasse un cercle entier »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ du nom commun παιδεία / paideía, « l’éducation »;'''<br /><p style="margin: 0 2em; text-align: center;">« ''Si à première vue la signification de cette expression semble être sans ambiguïté, sa portée réelle et la compréhension qu’en avaient les auteurs grecs puis latins font l’objet de débats parmi les spécialistes. En effet, deux interprétations sont possibles lorsqu’un auteur de l’Antiquité a recours à cette expression dans l’un de ses textes. Dans le premier cas, cela équivaudrait à parler d’une éducation ordinaire, commune à tous ; et dans le second cas, cela ferait référence à la quantité de connaissances et de sciences qu’il faudrait maîtriser au préalable avant de commencer l’étude d’un sujet précis, qui serait dans ce cas placé en haut d’une hiérarchie dans les savoirs.'' »<br /><p style="margin: 0 2em; text-align: right;">''' Lisa Donnadille. [https://dumas.ccsd.cnrs.fr/dumas-03927443/file/DONNADILLE-MR2-Pline-VERS-FINALE.pdf Merveilles animalières dans les livres VIII à XI de l’Histoire naturelle de Pline l’Ancien. Littératures. 2020. ffdumas-03927443], p.21'''<br/><br/></div> {{Boîte déroulante fin}} ==== Livre III — De l’eau ==== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">En prologue, Sénèque explique pourquoi il est plus important de s’intéresser à l’observation du monde, à sa connaissance et à sa compréhension plutôt qu’à sa conquête. Puis, il développe diverses théories sur la formation des rivières, les eaux souterraines et les propriétés de l’eau. Dans une critique morale aux chapitres XVII à XIX, il fustige la mauvaise pratique consistant à amener à table des poissons, notamment des rougets, vivants et à se délecter de leurs couleurs changeantes à l’agonie avant de les préparer devant les convives. En épilogue, il énonce son [[w:Eschatologie|''eschatologie'']], sa vision de la fin du monde où les êtres vivants seront anéantis par des raz-de-marée, marquant la fin d’un cycle du vivant et le début d’un autre.</div> ===== <div style="text-align: center;">Chapitre XIII.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage de la doctrine de '''Thalès''' faisant de l’eau l’élément à l’origine de la vie et critique d’une autre de la terre flottant dessus.</div> :'''Texte latin''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''13.''' Adiciam, ut '''Thales''' ait, «ualentissimum elementum est». Hoc fuisse primum putat, ex hoc surrexisse omnia. Sed nos quoque aut in eadem sententia, aut in uicinia eius sumus. Dicimus enim ignem esse qui occupet mundum et in se cuncta conuertat; hunc euanidum languentemque considere et nihil relinqui aliud in rerum natura igne restincto quam umoren; in hoc futuri mundi spem latere. Ita ignis exitus mundi est, umor primordium. Miraris ex hoc posse amnes semper exire qui pro omnibus fuit et ex quo sunt omnia? Hic umor in diductione rerum ad quartas redactus est, sic positus ut sufficere fluminibus edendis, ut riuis, ut fontibus posset.<br /><p style="text-indent: 15px;">'''14.''' Quae sequitur '''Thaletis''' inepta sententia est. Ait enim terrarum orbem aqua sustineri et uehi more nauigii mobilitateque eius fluctuare tunc cum dicitur tremere; non est ergo mirum si abundat umor ad flumina profundenda, cum in umore sit totus. Hanc ueterem et rudem sententiam explode. Nec est quod credas in hunc orbem aquam subire per rimas et facere sentinam.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/seneca.-cuestiones-naturales.-naturales-quaestiones.-vol.-i-1979/page/n1/mode/2up <u>L. Annaei Senecae, Natvrales Qvaestiones</u>], [https://archive.org/details/seneca.-cuestiones-naturales.-naturales-quaestiones.-vol.-i-1979/page/n261/mode/2up ''Liber Tertivs.''], [https://archive.org/details/seneca.-cuestiones-naturales.-naturales-quaestiones.-vol.-i-1979/page/n293/mode/2up ''chap. 13.-14.''], texte établi par Carmen Codoñer Merino [[w:es:Carmen_Codoñer_Merino|(es)]], Consejo Superior de Investigaciones Científicas, Madrid, 1979</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: justify; margin: 0 2em;">'''XIII.''' Aqua, ait '''Thales''', valentissimum elementum est : hoc fuisse primum putat, et hoc surrexisse omnia. Sed et nos quoque aut in eadem sententia, aut in ultima sumus. Dicimus enim ignem esse, qui occupet mundum, et in se cuncta convertat ; hunc evanidum considere, et nihil relinqui aliud in rerum natura, igne restincto, quam humorem : in hoc futuri mundi spem latere. Ita ignis exitus mundi est, humor primordium. Miraris amnes ex hoc posse exire semper, qui pro omnibus fuit, et ex quo sunt omnia? Hic humor in diductione rerum ad quartas redactus est, sic positus, ut fluminibus edendis sufficere, ut rivis, ut fontibus posset. Quæ sequitur, '''Thaletis''' inepta sententia est : ait enim , terrarum orbem aqua sustineri, et vehi more navigii, mobilitateque ejus fluctuare, tum quum dicitur tremere. Non est ergo mirum, si abundat humor ad flumina fundenda, quum mundus in humore sit totus. Hanc veterem et rudem sententiam explode : nec est quod credas, in hunc orbem aquam subire per rimas et facere sentiuam.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PP9#v=onepage&q&f=true <u>Œuvres Complètes de Sénèque, Tome Quatrième</u>], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA327#v=onepage&q&f=true ''Questions Naturelles, De Sénèque à Lucilius - Livre Troisième.''], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA342#v=onepage&q&f=true ''chap. XIII.''], traduction française de la collection Panckoucke, nouvelle édition très soigneusement revue par M. Charpentier et M. Félix Lemaistre, 1860</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''XIII.''' L’eau, dit '''Thalès''', est le plus puissant des éléments, le premier en date, celui par qui tout a pris vie. Nous pensons comme '''Thalès''', au moins sur le dernier point. En effet, nous prétendons que le feu doit s’emparer du monde entier et convertir tout en sa propre substance, puis s’évaporer, s’affaisser, s’éteindre et ne rien laisser autre chose dans la nature que l’eau ; qu’enfin l’eau recèle l’espoir du monde futur. Ainsi périra par le feu cette création dont l’eau fut le principe. Es-tu surpris que des fleuves sortent incessamment d’un élément qui a tenu lieu de tout, et duquel tout est sorti ? Quand les éléments furent séparés les uns des autres, l’eau fut réduite au quart de l’univers, et placée de manière à suffire à l’écoulement des fleuves, des ruisseaux, des fontaines. Mais voici une idée absurde de ce même '''Thalès'''. Il dit que la terre est soutenue par l’eau sur laquelle elle vogue comme un navire ; qu’à la mobilité d’un tel support sont dues les fluctuations qu’on appelle tremblements de terre. Ce ne sera donc pas merveille qu’il y ait assez d’eau pour entretenir les fleuves, si tout le globe est dans l’eau. Ce système grossier et suranné n’est que risible ; tu ne saurais admettre que l’eau pénètre notre globe par ses interstices, et que la cale est entr’ouverte.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[[s:Questions_naturelles_(trad._Baillard)|<u>Sénèque le Jeune</u>]], [[s:Questions_naturelles_(trad._Baillard)/Livre_3|''Livre III. chap. 13.'']], traduction par [[s:Auteur:Joseph_Baillard|Joseph Baillard]], Hachette, 1914<br />(également disponible [https://remacle.org/bloodwolf/philosophes/seneque/questionsnaturelles3.htm ici])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: justify; margin: 0 2em;">'''XIII.''' L’eau, dit '''Thalès''', est le plus puissant des éléments : elle existait avant tout, elle est le principe de tout. Nous pensons comme '''Thalès''', au moins sur le dernier point. En effet, nous croyons que le feu, s’emparant du monde entier, convertira tout en sa propre substance : mais il finira par cesser ses ravages, et quand il sera éteint, dans toute la nature il ne restera que l’eau, et cette eau renfermera le germe et l’espérance d’un monde futur. Ainsi par le feu s’accomplira la destruction de l’univers, et par l’eau sa réorganisation. Êtes-vous surpris, maintenant, qu’après avoir tenu lieu de tous les éléments, et les avoir produits tous, l’eau suffise à l’entretien perpétuel des fleuves ? Quand les éléments furent séparés les uns des autres, l’eau fut réduite au quart de l’univers, et dans une proportion convenable pour suffire à l’alimentation des fontaines, des ruisseaux et des rivières. Mais voici une idée absurde du même '''Thalès''' : il dit que la terre est soutenue par l’eau, et qu’elle flotte sur elle comme un navire ; que les tremblements de terre sont causés par les oscillations et les mouvements du fluide qui la soutient. Il n’est donc pas étonnant qu’il y ait assez d’eau pour alimenter les fleuves, puisque tout le globe est dans l’eau. Mais rejetons cette vieille et informe hypothèse, qui assimile les sources aux flots que la cale entr’ouverte laisse pénétrer dans le vaisseau.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PP9#v=onepage&q&f=true <u>Œuvres Complètes de Sénèque, Tome Quatrième</u>], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA327#v=onepage&q&f=true ''Questions Naturelles, De Sénèque à Lucilius - Livre Troisième.''], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA342#v=onepage&q&f=true ''chap. XIII.''], traduction française de la collection Panckoucke, nouvelle édition très soigneusement revue par M. Charpentier et M. Félix Lemaistre, 1860</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: justify; margin: 0 2em;">'''Chap. III.'''<br />''Opiniõ de Thales touchant l’eau.''<br /><p style="text-align: justify; text-indent: 15px;">L’eau , comme dit '''Thales''' , e[[w:S_long|{{Info|ſ|forme ancienne longue de la lettre s minuscule}}]]<nowiki>t</nowiki> le plus fort des Elemens. Il croit me{{Info|ſ|forme ancienne longue de la lettre s minuscule}}me qu’elle e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t le premier , & que toutes cho{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es en ont pris nai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ance. Pour moy ie {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uis de cette opinion , ou du moins de la derniere partie de cette opinion. Car nous [[#nous_stoiciens_NdT_dR|<span id="nous_stoiciens_NdT_dR_back"><sup>1</sup></span>]] di{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ons que c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t le feu qui enueloppera tout le monde , & qui conuertira en {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oy toutes cho{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es; qu’il deuiendra {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ans force quand il n’aura plus de nourriture , qu’apres que le feu {{Info|ſ|forme ancienne longue de la lettre s minuscule}}era e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}teint il ne demeurera rien de re{{Info|ſ|forme ancienne longue de la lettre s minuscule}}te à la nature que l’eau {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eulement , & que c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t en elle {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eule que con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i{{Info|ſ|forme ancienne longue de la lettre s minuscule}}te l’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}perance d’vn monde futur. Ain{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i le feu e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t la fin du monde , & l’eau en e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t le commencement. Vous e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tonnez-vous donc que les fleuues pui{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ent tou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iours {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ortir d’vn Element , qui e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t fait pour toutes cho{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es & dont toutes cho{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e font ? Lors que la nature fit le departement des Elemens , l’eau fut placée de telle {{Info|ſ|forme ancienne longue de la lettre s minuscule}}orte , qu’elle peut {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uffire pour les fleuues , pour les rui{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}eaux , pour les fontaines. Mais ce que '''Thales''' dit en {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uitte e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t ridicule , car il dit que le Globe de la terre e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tenu par les eaux ; qu’elles le portent comme vn vai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}eau , & qu’elles l’agitent de la me{{Info|ſ|forme ancienne longue de la lettre s minuscule}}me {{Info|ſ|forme ancienne longue de la lettre s minuscule}}orte , lors que nous croyons qu’il tremble. Il ne faut donc pas s’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tonner , s’il ya tou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iours a{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ez d’eau pour former de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i grands fleuues , puis que tout le monde nage fur l’eau. Mais me{{Info|ſ|forme ancienne longue de la lettre s minuscule}}pri{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ez cette vieille , & cette gro{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}iere opinion , & ne croyez pas que l’eau vienne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur la terre , comme par des fentes & par des creua{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}es , & qu’elle y {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oit {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eulement comme dans le fond d’vn vai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}eau.</div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#nous_stoiciens_NdT_dR_back|<span id="nous_stoiciens_NdT_dR"><sup>1.</sup></span>]] Les Stoïciens.''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=ktOcOg9lr54C&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles%20iii&hl=fr&pg=PA1#v=onepage&q&f=true <u>Seneque Des Qvestions Natvrelles</u>], [https://books.google.fr/books?id=ktOcOg9lr54C&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles%20iii&hl=fr&pg=PA202#v=onepage&q&f=true ''Livre Troisiesme. Des eaux.''], [https://books.google.fr/books?id=ktOcOg9lr54C&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles%20iii&hl=fr&pg=PA234#v=onepage&q&f=true ''chap. XIII.''], traduction par [[w:Pierre_Du_Ryer|Pierre Du Ryer]], A Lyon, Chez Christofle Fovrmy, 1663</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div> </div> <div style="text-align: center; margin: 0 auto;">― ● ―</div> ==== Livre IV — Du Nil ==== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">En prologue, '''Sénèque''' fait l’éloge de [[w:Lucilius_le_Jeune|'''Lucilius''']] [[#Lucilius|<span id="Lucilius_back"><sup>'''I'''</sup></span>]] avant de lui expliquer les dangers de la flatterie. Puis, il décrit la crue du [[w:Nil|''Nil'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Nil_back|<sup>🔄</sup>]], expose les théories tentant de l’expliquer et les réfute. En épilogue, il fait le procès du luxe, et plus particulièrement celui d’acheter de la neige, et donc de marchandiser l’eau, regrettant qu’on ne puisse faire de même avec l’air et le soleil.</div> {{Boîte déroulante début|titre=NdA Lucilius|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Lucilius_back|<span id="Lucilius"><sup>I</sup></span>]] Du nom propre latin Lucilius [[wikt:en:Lucilius#Latin|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;">Gouverneur ''romain'' de Sicile durant le règne de [[w:Néron|Néron]], ainsi qu’un ami et un correspondant de Sénèque.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:Ier_siècle_av._J.-C.|I<sup>er</sup> siècle {{Info|EC|de l’Ère Commune}}]], [[w:Campanie#Histoire|''Campanie'']], [[w:Quatorze_régions_de_la_Rome_augustéenne#Regio_I_:_Porte_Capène|''Regio I'']])'''<br/><br/></div> {{Boîte déroulante fin}} ===== <div style="text-align: center;">Chapitre II.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Réfutation par '''Sénèque''' d’une théorie explicite de '''Thalès''' sur la crue du ''Nil'' (théorie identique mais supposément implicite rapportée par [[w:Hérodote|'''Hérodote''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Chapitre_XX|<sup>🔄</sup>]]).</div> :'''Texte latin''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''2.''' [...] Si '''Thaleti''' credis, etesiae descendenti ''Nilo'' resistunt et cursum eius acto contra ostia mari sustinent. Ita reuerberatus in se recurrit, nec crescit, sed exitu prohibitus resistit et quacumque mox potuit ui congestus erumpit. '''Euthymenes''' ''Massiliensis'' testimonium dicit: «Nauigaui, inquit, ''Atlanticum'' mare. Inde ''Nilus'' fluit, maior, quamdiu etesiae tempus obseruant; tunc enim eicitur mare instantibus uentis. Cum resederunt, et pelagus conquiescit minorque descendenti inde uis ''Nilo'' est. Ceterum dulcis mari sapor est et similes ''Niloticis'' beluae». Quare ergo, si ''Nilum'' etesiae prouocant, et ante illos incipit incrementum eius et post eos durat? Praeterea non fit maior quo illi flauere uehementius, nec remittitur incitaturque, prout illis impetus fuit; quod fieret, si illorum uiribus cresceret. Quid quod etesiae litus ''Aegyptium'' uerberant et contra illos ''Nilus'' descendit, inde uenturus unde illi, si origo ab illis esset? Praeterea ex mari purus et caeruleus efflueret, non, ut nunc, turbidus ueniret. Adde quod testimonium eius testium turba coarguitur. Tunc erat mendacio locus; cum ignota essent externa, licebat illis fabulas mittere. Nunc uero tota exteri maris ora mercatorum nauibus stringitur, quorum nemo narrat initium ''Nili'' aut mare saporis alterius: quae natura credi uetat, quia dulcissimum quodque et leuissimum sol trahit. Praeterea quare hieme non crescit? Et tunc potest uentis concitari mare, aliquanto quidem majoribus; nam etesiae temperati sunt. Quod si e mari ferretur ''Atlantico'', semel oppleret ''Aegyptum''. At nunc per gradus crescit.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/seneca.-cuestiones-naturales.-naturales-quaestiones.-vol.-ii-1979/page/n1/mode/2up <u>L. Annaei Senecae, Natvrales Qvaestiones</u>], [https://archive.org/details/seneca.-cuestiones-naturales.-naturales-quaestiones.-vol.-ii-1979/page/n7/mode/2up ''Liber Qvartvs A.''], [https://archive.org/details/seneca.-cuestiones-naturales.-naturales-quaestiones.-vol.-ii-1979/page/n41/mode/2up ''chap. 2.''], texte établi par Carmen Codoñer Merino [[w:es:Carmen_Codoñer_Merino|(es)]], Consejo Superior de Investigaciones Científicas, Madrid, 1979</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: justify; margin: 0 2em;">'''II.''' [...] Si '''Thaleti''' credis, Etesiæ descendenti ''Nilo'' resistunt, et cursus ejus acto contra ostia mari sustinent : ita reverberatus in se recurrit : nec crescit, sed exitu prohibitus resistit, et quacumque mox potuit, inconcessus erumpit.<br /><p style="text-align: justify; text-indent: 15px;">'''Euthymenes''' ''Massiliensis'' testimonium dicit : « Navigavi, inquit, ''Atlanticum'' mare. Inde ''Nilus'' fluit major, quamdiu Etesiæ tempus observant : tunc enim ejicitur mare instantibus ventis. Quum resederint, et pelagus conquiescit, minorque descendenti inde vis ''Nilo'' est. Ceterum dulcis maris sapor est, et similes ''Niloticis'' belluæ. » Quare ergo, si ''Nilum'' Etesiæ provocant, et ante illos incipit incrementum ejus, et post eos durat ? Præterea non fit major, quo illi flavere vehementius. Nec remittitur, incitaturque, prout illis impetus fuit : quod fieret, si illorum viribus cresceret. Quid, quod Etesiæ littus ''ægyptium'' verberant, et contra illos ''Nilus'' descendit, inde venturus, unde illi, si origo ab illis esset ? Præterea ex mari purus et cæruleus efflueret, non ut nunc turbidus venit. Adde, quod testimonium ejus testium turba coarguitur. Tunc erat mendacio locus, quum ignota essent externa. Licebat illis fabulas mittere. Nunc vero tota exteri maris ora mercatorum navibus stringitur : quorum nemo narrat nunc cæruleum ''Nilum'', aut mare saporis alterius ; quod et natura credi vetat, quia dulcissimum quodque et levissimum sol trahit. Præterea quare hieme non crescit ? et tunc potest ventis concitari mare, aliquando quidem majoribus ; nam Etesiæ temperati sunt. Quod si e mari ferretur ''Atlantico'', semel oppleret ''Ægyptum''. At nunc per gradus crescit.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PP9#v=onepage&q&f=true <u>Œuvres Complètes de Sénèque, Tome Quatrième</u>], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA371#v=onepage&q&f=true ''Questions Naturelles, De Sénèque à Lucilius - Livre Quatrième.''], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA385#v=onepage&q&f=true ''chap. II.''], traduction française de la collection Panckoucke, nouvelle édition très soigneusement revue par M. Charpentier et M. Félix Lemaistre, 1860</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''II.''' [...] À en croire '''Thalès''', les vents étésiens repoussent le ''Nil'' à sa descente dans la mer, et suspendent son cours en poussant la mer contre ses embouchures. Ainsi refoulé, il revient sur lui-même, sans pour cela grossir ; mais l’issue lui étant barrée, il s’arrête, et bientôt, partout où il le peut, force le passage qui lui est refusé. [[w:Euthymènes|'''Euthymène''']] [[#Euthymènes|<span id="Euthymènes_back"><sup>'''I'''</sup></span>]], de ''Marseille'', en parle comme témoin : « J’ai navigué, dit-il, sur la mer ''Atlantique''. Elle cause le débordement du ''Nil'', tant que les vents étésiens se soutiennent ; car c’est leur souffle qui alors pousse cette mer hors de son lit. Dès qu’ils tombent, la mer aussi redevient calme, et le ''Nil'' à sa descente déploie moins de puissance. Du reste, l’eau de cette mer est douce, et nourrit des animaux semblables à ceux du ''Nil''. » Mais pourquoi, si les vents étésiens font gonfler le ''Nil'', la crue commence-t-elle avant la saison de ces vents, et dure-t-elle encore après ? D’ailleurs le fleuve ne grossit pas à mesure qu’ils soufflent plus violemment. Son plus ou moins de fougue n’est point réglé sur celle des vents étésiens, ce qui aurait lieu, si leur action le faisait hausser. Et puis ils battent la côte ''égyptienne'', le ''Nil'' descend à leur encontre : il faudrait qu’il vînt du même point qu’eux, si son accroissement était leur ouvrage. De plus, il sortirait pur et azuré de la mer, et non pas trouble comme il est. Ajoute que le témoignage d’'''Euthymène''' est réfuté par une foule d’autres. Le mensonge avait libre carrière, quand les plages étrangères étaient inconnues ; on pouvait de là nous envoyer des fables, À présent, la mer extérieure est côtoyée sur tous ses bords par des trafiquants dont pas un ne raconte qu’aujourd’hui le ''Nil'' soit azuré ou que l’eau de la mer soit douce. La nature elle-même repousse cette idée ; car les parties les plus douces et les plus légères sont pompées par le soleil. Et encore pourquoi le ''Nil'' ne croît-il pas en hiver ? Alors aussi la mer peut être agitée par des vents quelque peu plus forts que les étésiens, qui sont modérés. Si le mouvement venait de l’Atlantique, il couvrirait tout d’un coup l’Égypte : or l’inondation est graduelle.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[[s:Questions_naturelles_(trad._Baillard)|<u>Sénèque le Jeune</u>]], [[s:Questions_naturelles_(trad._Baillard)/Livre_4|''Livre IV.'']] ''chap. 2.'', traduction par [[s:Auteur:Joseph_Baillard|Joseph Baillard]], Hachette, 1914<br />(également disponible [https://remacle.org/bloodwolf/philosophes/seneque/questionsnaturelles4.htm ici])</div> {{Boîte déroulante début|titre=NdA trad. par Joseph Baillard de 1914|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Euthymènes_back|<span id="Euthymènes"><sup>I</sup></span>]] Du nom propre grec ancien Εὐθυμένης / Euthuménēs [[wikt:en:Εὐθυμένης#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;"> ➥ de l’adjectif εὐθύς / euthús, « 1. Droit, direct : (au sens moral) direct, ouvert, franc. »;<br /><p style="margin: 0 2em; text-indent: 15px;"> ➥ + du nom commun μενος / ménos, « 1. Esprit. 2. Désir, ardeur, souhait, but. 3. Colère. 4. Courage, esprit, vigueur. 5. Pouvoir, force. 6. Violence. »;<br /><p style="margin: 0 2em; text-indent: 15px;"> ➥ + du suffixe nominal‎ propre -ης / -ēs [[wikt:en:-ης#Suffix_2|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;"> Navigateur et explorateur de la mer Extérieure le long des côtes africaines (actuelle Atlantique sud).<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:VIeme_siècle_av._J.-C.|VI<sup>ème</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]], [[w:Marseille_antique#Massalia,_une_cité_grecque|''Massalia'']], actuelle Marseille)'''<br/><br/></div> {{Boîte déroulante fin}} <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: justify; margin: 0 2em;">'''II.''' [...] Selon '''Thalès''', le phénomène a pour cause les vents Étésiens, qui s’opposent au cours du ''Nil'' et font rebrousser ses eaux en sens inverse du mouvement qui le porte vers la mer. Refoulés sur eux-mêmes, les flots refluent sans pour cela grossir ; mais l’issue leur étant fermée, ils s’arrêtent, et bientôt ils s’ouvrent partout où ils peuvent le passage qui leur est refusé.<br /><p style="text-align: justify; text-indent: 15px;">'''Euthymène''' de ''Marseille'' en parle comme témoin : « J’ai navigué, dit-il, sur la mer ''Atlantique''. Le ''Nil'' roule des eaux plus abondantes, tant que durent les vents Étésiens ; car alors ils refoulent la mer sur le fleuve. Dès qu’ils se sont abattus et que la mer est devenue calme, le ''Nil'', qui peut redescendre vers celle-ci, diminue. Au reste, les eaux de cette mer sont douces et contiennent des animaux semblables à ceux du ''Nil''. » Dans cette hypothèse, qui donne les vents Étésiens pour cause des crues du ''Nil'', qu’on me dise pourquoi ces crues précèdent les vents, persistent quand les vents ne sont plus, enfin n’augmentent plus d’intensité et de violence, et ne diminuent pas selon la violence et l’impétuosité du vent même ; c’est pourtant ce qui devrait arriver, si les vents déterminaient la hausse des eaux. De plus, les vents Étésiens battent directement la côte ''égyptienne'' : pourquoi donc le ''Nil'' descend-il contre le souffle de ces vents, tandis qu’il devrait couler dans la même direction, s’il leur devait ses débordements ? Enfin, pourquoi, au lieu d’être diaphanes et azurés, ces flots, qu’on fait venir de la mer, sont-ils chargés de limon ? Ajoutez qu’une foule de témoignages réfutent '''Euthymène'''. On pouvait mentir, quand les plages étrangères étaient inconnues : c’était alors le temps des fables ; mais aujourd’hui mille vaisseaux marchands côtoient la mer extérieure ; personne ne dit que le ''Nil'' ait des flots d’azur ; personne ne donne à la mer une saveur douce, que la nature refuse à ses eaux : car le soleil en pompe sans cesse la partie la plus douce et la plus légère ; ensuite pourquoi le ''Nil'' ne croîtrait-il point pendant l’hiver ? la mer alors peut être battue par les vents, par des vents plus violents que les Étésiens, qui sont modérés. Enfin, si le mouvement venait de l’Atlantique, l’Égypte entière serait inondée tout d’un coup : or, l’inondation est graduelle.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PP9#v=onepage&q&f=true <u>Œuvres Complètes de Sénèque, Tome Quatrième</u>], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA371#v=onepage&q&f=true ''Questions Naturelles, De Sénèque à Lucilius - Livre Quatrième.''], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA385#v=onepage&q&f=true ''chap. II.''], traduction française de la collection Panckoucke, nouvelle édition très soigneusement revue par M. Charpentier et M. Félix Lemaistre, 1860</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: justify; margin: 0 2em;">'''Chap. II.'''<br />''En quelle fai[[w:S_long|{{Info|ſ|forme ancienne longue de la lettre s minuscule}}]]<nowiki>ó</nowiki> {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e fait l’accroi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ement du Nil.''<br /><p style="text-align: justify; text-indent: 15px;">[...] Si vous en croyez '''Thales''' , les vents Ethe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iens re{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tent au ''Nil'' en de{{Info|ſ|forme ancienne longue de la lettre s minuscule}}cendant dans la mer; & arre{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tent {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on cours, en pou{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ant la mer contre {{Info|ſ|forme ancienne longue de la lettre s minuscule}}es {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ept emboucheures. Si bien qu’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es {{Info|ſ|forme ancienne longue de la lettre s minuscule}}tant repou{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}é de la {{Info|ſ|forme ancienne longue de la lettre s minuscule}}orte il retourne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oy-me{{Info|ſ|forme ancienne longue de la lettre s minuscule}}me , & ne croi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t pas comme l’on pen{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e , mais par ce qu’il trouue vn ob{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tacle qui l’empe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}che de pa{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}er outre , il e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t contraint de s’arre{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ter , & ne pouuant plus pour{{Info|ſ|forme ancienne longue de la lettre s minuscule}}uiure {{Info|ſ|forme ancienne longue de la lettre s minuscule}}a cour{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e , il {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e re{{Info|ſ|forme ancienne longue de la lettre s minuscule}}pand par où il peut {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e répandre. '''Euthimenes''' de ''Mar{{Info|ſ|forme ancienne longue de la lettre s minuscule}}eille'' en rend ce te{{Info|ſ|forme ancienne longue de la lettre s minuscule}}moignage. I’ay nauigé, dit il, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur la mer ''Atlantique'' , & c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t par elle que le ''Nil'' deuient plus grand, lors que les vents Ethe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iens {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oufflent ; car alors cette mer {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ort pour ain{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i dire d’elle-me{{Info|ſ|forme ancienne longue de la lettre s minuscule}}me par la force & par la violence de ces vents. Mais lors qu’ils ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oufflent plus la mer demeure tranquille, & le Nil ne trouue plus rien qui l’empe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}che de de{{Info|ſ|forme ancienne longue de la lettre s minuscule}}cendre , Au re{{Info|ſ|forme ancienne longue de la lettre s minuscule}}te l’eau de la mer e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t douce en ce temps-là , & l’on y void des be{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tes {{Info|ſ|forme ancienne longue de la lettre s minuscule}}emblables à celles du Nil. Mais {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i les Ethe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iens {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont enfler le Nil, pourquoy {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on débordement commence il auant qu’ils {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oufflent & pourquoy dure - il encore lors qu’ils ont ce{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}é de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ouffler. Dauantage ils ne s’enfle pas plus que de cou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tume , quand ces vents {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oufflent auecque plus de violence qu’ils ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont ordinairement. Enfim il ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e hau{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}e & ne s’abai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}e pas {{Info|ſ|forme ancienne longue de la lettre s minuscule}}elon que leur impetuo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ité e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t plus ou moins grande , ce qui arriveroit {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ans doute s’il s’enfloit par la force de ces véts. Mais comme les Ete{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iens battent directement les bords de l’Egypte, & que le Nil de{{Info|ſ|forme ancienne longue de la lettre s minuscule}}cend contre eux ; il faudroit s’ils e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}toient cau{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on accroi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ement , qu’il commença{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t par l’endroit d’où ils viennent. Outre cela il {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ortiroit tout pur de la mer, & de la couleur de la mer, & ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eroit pas trouble & limonneux , comme il e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t. Et apres tout le te{{Info|ſ|forme ancienne longue de la lettre s minuscule}}moignage d’'''Euthimene''' , e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t condamné par le plus grand nombre. Il e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}toit permis de mentir quand on n’auoit point de connoi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ance des pays e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}trangers ; & alors on pouuoit facilement nous en enuoyer des fables. Mais aujourd’huy tous les riuages des mers les plus e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}loignées {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont remplis de vai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}eaux de marchands, & pas vn ne nous apporte que le ''Nil'' {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oit de la couleur de la mer, ou que la mer ait vn autre gou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t. Quand nous aurions des rai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ons pour nous la per{{Info|ſ|forme ancienne longue de la lettre s minuscule}}uader , la nature nous empe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}cheroit de le croire par ce que le Soleil en attire ce qu’il y a de plus leger & de plus doux. Dauantage pourquoy ne croi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t-il pas en Hyuer , puis que la met en ce temps là peut e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tre agitée par des vents plus violents, que les Ethe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iens qui {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont tou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iours moderez. Que {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i le ''Nil'' venoit de la mer ''Atlantique'' , il couuriroit l’Egypte tout d’vn coup, & neantmoins il ne la couure que peu à peu.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=gEzVYlz3c3cC&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles%20iii%20volume%202&hl=fr&pg=PA1#v=onepage&q&f=true <u>Seneque Des Qvestions Natvrelles</u>], [https://books.google.fr/books?id=gEzVYlz3c3cC&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles%20iii%20volume%202&hl=fr&pg=PA3#v=onepage&q&f=true ''Livre Qvatriesme. De la Nege, de la Greſle, & de la Pluye.''], [https://books.google.fr/books?id=gEzVYlz3c3cC&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles%20iii%20volume%202&hl=fr&pg=PA37#v=onepage&q&f=true ''chap. II.''], traduction par [[w:Pierre_Du_Ryer|Pierre Du Ryer]], A Lyon, Chez Christofle Fovrmy, 1663</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div> </div> <div style="text-align: center; margin: 0 auto;">― ● ―</div> ==== Livre VI — Des tremblements de terre ==== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">En prologue, '''Sénèque''' énonce le plan du livre, des causes des tremblements de terre et des peurs qu’ils provoquent, en s’appuyant sur celui de ''Campanie'' qui a récemment causé d’importants dégâts à ''Pompéi'' et à ''Herculanum''. Des chapitres IV à XX, de nombreuses théories sismiques sont présentées, la plupart liées au nom d’un philosophe qui les prône. Le feu, l’eau et l’air sont cités comme causes, et plusieurs d’entre-elles les combinent. À partir du chapitre XXIV, '''Sénèque''' développe sa propre opinion : l’air pénétrant, qui remplit complètement les cavités souterraines sous une forte pression, en est la cause. En épilogue, il explique à '''Lucilius''' quel comportement adopté en de telles situations, à savoir être courageux en ne craignant pas la mort</div> ===== <div style="text-align: center;">Chapitre VI.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Réfutation d’une théorie de '''Thalès''' de la Terre flottant sur l’eau, et témoignage d’une de ses preuves portant sur les tremblements de terre.</div> :'''Texte latin''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''6.''' In aqua causam esse nec ab uno dictum est nec uno modo. '''Thales''' ''Milesius'' totam terram subiecto iudicat umore portari et innare, siue illud oceanum uocas, siue magnum mare, siue alterius naturae simplicem adhuc aquam et umidum elementum. Hac, inquit, unda sustinetur orbis uelut aliquod grande nauigium et graue his aquis quas premit. Superuacuum est reddere causas propter quas existimat grauissimam partem mundi non posse spiritu tam tenui fugacique gestari; non enim nunc de situ terrarum sed de motu agitur. Illud argumenti loco ponit aquas esse in causa quibus hic orbis agitetur, quod in omni maiore motu erumpunt fere noui fontes, sicut in nauigiis quoque euenit ut, si inclinata sunt et abierunt in latus, aquam sorbeant, quae in omni eorum onere quae uehit, si immodice depressa sunt, aut superfunditur aut certe dextra sinistraque solito magis surgit. Hanc opinionem falsam esse non est diu colligendum. Nam, si terra aqua sustineretur et ea aliquando concuteretur, semper moueretur, nec agitari illam miraremur sed manere; deinde tota concuteretur, non ex parte; numquam enim nauis dimidia iactatur. Nunc uero terrarum non uniuersarum sed ex parte motus est. Quomodo ergo fieri potest ut, quod totum uehitur, totum non agitetur, si eo quo uehitur agitatum est? — At quare aquae erumpunt? — Primum omnium saepe tremuit terra et nihil umoris noui fluxit. Deinde, si ex hac causa unda prorumperet, a lateribus terrae circumfunderetur, sicut in fluminibus ac mari uidemus incidere ut incrementum aquarum, quotiens nauigia desidunt, in lateribus maxime appareat. Ad ultimum non tam exigua fieret quam tu dicis eruptio nec uelut per rimam sentina subreperet, sed fieret ingens inundatio ut ex infinito liquore et ferente uniuersa.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/seneca.-cuestiones-naturales.-naturales-quaestiones.-vol.-ii-1979/page/n1/mode/2up <u>L. Annaei Senecae, Natvrales Qvaestiones</u>], [https://archive.org/details/seneca.-cuestiones-naturales.-naturales-quaestiones.-vol.-ii-1979/page/n135/mode/2up ''Liber Qvintvs - De terrae motv''], [https://archive.org/details/seneca.-cuestiones-naturales.-naturales-quaestiones.-vol.-ii-1979/page/n155/mode/2up ''chap. 6.''], texte établi par Carmen Codoñer Merino [[w:es:Carmen_Codoñer_Merino|(es)]], Consejo Superior de Investigaciones Científicas, Madrid, 1979</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: justify; margin: 0 2em;">'''VI.''' In aqua causam esse, nec ab uno dictum est, nec uno modo. '''Thales''' ''Milesius'' totam terram subjecto judicat humore portari et innatare : sive illud Oceanum vocas, sive magnum mare, sive alterius naturæ simplicem adhuc aquam et humidum elementum. Hac, inquit, unda sustinetur orbis, velut aliquod grande navigium et grave his aquis, quas premit. Supervacuum est reddere causas, propter quas existimat, gravissimam partem mundi non posse spiritu tam tenui fugacique gestari ; non enim nunc de situ terrarum, sed de motu agitur. Illud argumenti loco ponit, aquas esse in causa, quibus hic orbis agitatur, quod in omui majore motu erumpunt fere novi fontes : sicut in navigiis quoque evenit, ut, si inclinata sunt et abiere in latus, aquam sorbeant, quæ in omni onere eorum quæ vehit, si immodice depressa sunt, aut superfunditur, aut certe dextra sinistraque solito magis surgit. Hanc opinionem falsam esse, non est diu colligendum ; nam, si terram aqua sustineret, et ea aliquando concuteretur : semper moveretur, nec agitari illam miraremur, sed manere. Tum tota concuteretur, non ex parte : nunquam enim navis dimidia jactatur. Nunc vero non terrarum universarum, sed ex parte motus est. Quomodo ergo fieri potest, ut quod totum vehitur, totum non agitetur, si eo quo vehitur, agitatum est ? At quare aquæ erumpunt ? Primum omnium sæpe tremuit terra, et nihil humoris novi fluxit. Deinde si ex hac causa unda prorumperet, a lateribus terræ circumfunderetur : sicut in fluminibus ac mari videmus accidere, ut incrementum aquarum, quoties navigia desidunt, in lateribus maxime appareat. Ad ultimum non tam exigua fieret quam dicit eruptio, nec velut per rimam sentina subreperet, sed fieret ingens inundatio, ut ex infinito liquore, et ferente universa.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PP9#v=onepage&q&f=true <u>Œuvres Complètes de Sénèque, Tome Quatrième</u>], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA420#v=onepage&q&f=true ''Questions Naturelles, De Sénèque à Lucilius - Livre Sixième.''], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA429#v=onepage&q&f=true ''chap. VI.''], traduction française de la collection Panckoucke, nouvelle édition très soigneusement revue par M. Charpentier et M. Félix Lemaistre, 1860</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''VI.''' Que l’eau soit cause des tremblements de terre, c’est ce qu’affirment divers auteurs et avec divers arguments. '''Thalès''' de ''Milet'' estime que le globe entier a pour support une masse d’eaux sur laquelle il flotte, et qu’on peut appeler Océan ou grande mer, ou élément jusqu’ici de nature simple, l’élément humide. Cette eau, dit-il, soutient la terre ; et l’immense navire pèse sur le liquide qu’il comprime. Il est superflu d’exposer les motifs qui font croire à '''Thalès''' que la partie de l’univers la plus pesante ne saurait porter sur une substance aussi ténue, aussi fugace que l’air : il ne s’agit pas maintenant de l’assiette du globe, mais de ses secousses. '''Thalès''' apporte en preuve de son système, que presque toujours les grandes secousses font jaillir des sources nouvelles, comme il arrive dans les navires qui, lorsqu’ils penchent et s’inclinent sur le flanc, sont envahis par l’eau ; toujours, s’il y a surcharge, l’eau vient couvrir le bâtiment, ou du moins s’élève à droite et à gauche plus que de coutume. La fausseté de cette opinion se démontre sans longs raisonnements. Si la terre était soutenue par l’eau, elle tremblerait quelquefois dans toute sa masse et toujours serait en mouvement ; ce ne serait pas son agitation qui étonnerait, mais son repos. Elle s’ébranlerait tout entière, non partiellement ; car ce n’est jamais la moitié seulement d’un navire qui est battue des flots. Or, les tremblements de notre terre ne sont pas universels, mais partiels. Comment serait-il possible qu’un corps porté tout entier par l’eau ne fût pas agité tout entier, quand ce fluide est agité ? « Mais d’où viennent les eaux qu’on a vues jaillir ? » D’abord, souvent la terre tremble, sans qu’il en sorte de nouvelles eaux. Ensuite, si telle était la cause de ces éruptions, elles n’auraient lieu qu’autour des flancs du globe ; ce que nous voyons arriver sur les fleuves et en mer : l’exhaussement de l’onde, à mesure que s’enfonce le navire, se remarque surtout aux flancs du bâtiment. Enfin l’éruption dont on parle ne serait pas si minime, et comme une voie d’eau qui s’infiltre par une fente légère ; l’inondation serait immense en raison de l’abîme infini sur lequel flotterait le monde.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[[s:Questions_naturelles_(trad._Baillard)|<u>Sénèque le Jeune</u>]], [[s:Questions_naturelles_(trad._Baillard)/Livre_6|''Livre VI.'']] ''chap. 6.'', traduction par [[s:Auteur:Joseph_Baillard|Joseph Baillard]], Hachette, 1914<br />(également disponible [https://remacle.org/bloodwolf/philosophes/seneque/questionsnaturelles6.htm ici])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: justify; margin: 0 2em;">'''VI.''' Plusieurs philosophes ont prétendu que l’eau est la cause de ces secousses : ce que chacun explique à sa manière. '''Thalès''' de ''Milet'' prétend que le globe entier a pour support une masse d’eau sur laquelle il flotte ; peu importe qu’on donne à cet amas le nom d’Océan, de grande mer ou d’eau élémentaire, eau simple. Cette eau, dit-il, soutient la terre comme un grand vaisseau pesant sur le liquide qu’il comprime. Il est inutile d’exposer les raisons qui font croire à '''Thalès''' que le corps le plus pesant de la nature ne peut être soutenu par un fluide aussi délié et aussi rare que l’air : car il s’agit ici des tremblements de terre et non de l’assiette du globe. La grande raison de '''Thales''' pour faire de l’eau la cause des secousses de la terre, c’est que, dans tout tremblement considérable, jaillissent des eaux nouvelles ainsi les vaisseaux se remplissent d’eau quand ils penchent d’un côté ; chargés à l’excès, ou ils sont submergés, ou ils s’enfoncent à droite et à gauche plus profondément dans la mer. Il ne faut pas longtemps discuter pour voir la fausseté de cette opinion. Si la terre était soutenue par les eaux, elle serait quelquefois fortement ébranlée, mais de plus elle serait toujours flottante, et il faudrait s’étonner non de son agitation , mais de son repos ; enfin, au lieu d’être ébranlée en partie, elle le serait tout entière : car jamais la moitié d’un vaisseau n’est battue des flots. Or, on sait que les secousses de la terre sont partielles et non universelles : comment se ferait-il donc que ce qui est entièrement porté par les eaux ne fût pas entièrement agité, tandis que les eaux mêmes le sont en totalité ? Mais, dit-on, qui fait jaillir les eaux ? D'abord, souvent la terre tremble sans qu’il se produise des eaux nouvelles ; ensuite, si telle était la cause de ces éruptions, les eaux se répandraient latéralement autour de la terre. Ainsi, par exemple, quand un vaisseau s’enfonce ou dans la mer ou dans les fleuves, c’est vers les bords surtout que l’accroissement devient sensible. Enfin les sources qui jaillissent ne seraient pas si peu considérables ; on ne pourrait pas les comparer à une voie d’eau qui pénètre par les fentes du fond de cale : ce serait une inondation immense comme l’abîme infini sur lequel flotterait le monde.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PP9#v=onepage&q&f=true <u>Œuvres Complètes de Sénèque, Tome Quatrième</u>], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA420#v=onepage&q&f=true ''Questions Naturelles, De Sénèque à Lucilius - Livre Sixième.''], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA429#v=onepage&q&f=true ''chap. VI.''], traduction française de la collection Panckoucke, nouvelle édition très soigneusement revue par M. Charpentier et M. Félix Lemaistre, 1860</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: justify; margin: 0 2em;">'''Chap. VI.'''<br />''Si l’eau e[[w:S_long|{{Info|ſ|forme ancienne longue de la lettre s minuscule}}]]<nowiki>t</nowiki> la cau{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e des tréblemés de terre.''<br /><p style="text-align: justify; text-indent: 15px;">Ce n'e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t pas vn homme {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eul qui a dit , que l’eau e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}toit cau{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e du tremblement de la terre ; & l’on ne l’a pas dit d’vne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eule façó. '''Thales''' ''Mile{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ien'' a crû que toute la terre e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}toit portée {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur l’eau , & qu’elle y nageoit, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oit que vous appelliez cette eau Ocean, ou que vous l’appelliez grade mer, ou vne eau d’vne autre nature , eau {{Info|ſ|forme ancienne longue de la lettre s minuscule}}imple , element humide. C’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur cette eau, dit-il, que le monde e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tenu, comme quelque vai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}eau d’vne grandeur deme{{Info|ſ|forme ancienne longue de la lettre s minuscule}}urée , qui charge les eaux qui le {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tiennent. Il {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eroit inutile de rapporter les rai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ons qui luy {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont croire que la plus pe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ante partie du móde ne peut e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tre {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tenuë par l’air qui e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ubtil, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i fluide & {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i delié ; & d’ailleurs, il ne s’agit pas icy de l’a{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}iete de la terre , mais du tremblement de la terre. Ain{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i pour preuue que les eaux {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont cau{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e que la terre tremble , il dit qu’il ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e fait pre{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que point de grands tremblemens de terre, qu’on n’en voye {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ortir en{{Info|ſ|forme ancienne longue de la lettre s minuscule}}uitte de nouuelles {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ources; que la terre re{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}emble en cela aux vai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}eaux qui ne peuuent pancher d’vn co{{Info|ſ|forme ancienne longue de la lettre s minuscule}}té, qu’ils ne pui{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ent de l’eau, qui {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e re{{Info|ſ|forme ancienne longue de la lettre s minuscule}}pand {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur toutes les cho{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es qu’ils portent , {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i elles {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont trop enfoncées; ou qui s’éleue de part & d’autre à la gauche , & à la droite. Il n’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t pas besoin d’vn long di{{Info|ſ|forme ancienne longue de la lettre s minuscule}}cours pour montrer la fau{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}eté de cette opinion ; car {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i l’eau {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tenoit la terre, quelquesfois elle trembleroit toute entiere, & {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eroit tou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iours en mouuement; & nous ne nous e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tonnerions point de la voir remuer, mais de la voir ferme & inébranlable. Elle trembleroit toute entiere , & non pas en partie , car vn vai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}eau n’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t iamais agité par vne moitié {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eulement ; & apres tout nous voyons que le tremblement ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e fait pas de toute la terre , mais {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eulement d’vne partie. Comment donc {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e peut-il faire que ce qui e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t porté tout entier ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oit pas entierement agité , {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i la cho{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e me{{Info|ſ|forme ancienne longue de la lettre s minuscule}}me qui porte e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}meuë & agitée ? Mais pourquoy {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ort-il de l’eau apres vn tremblement de terre ? Premierement la terre a {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ouuent tremblé {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ans qu’on en ayt veu {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ortir de nouuelles {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ources. D’ailleurs {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i l’eau {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ortoit par cette rai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}on elle {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e re{{Info|ſ|forme ancienne longue de la lettre s minuscule}}pandroit par les co{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tez de la terre , comme nous voyons dans les fleuues & dans la mer , où lors que le vai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}eau s’enfonce on remarque que l’eau s'éleue , principalement par les co{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tez. Enfin ces eaux ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ortiroient pas en {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i petite quantité, ny par vne fi petite ouuerture , mais il {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eroit vne grande inondation, comme procedant de cette abondance d’eaux qui {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tiennent tout l’vniuers.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=gEzVYlz3c3cC&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles%20iii%20volume%202&hl=fr&pg=PA1#v=onepage&q&f=true <u>Seneque Des Qvestions Natvrelles</u>], [https://books.google.fr/books?id=gEzVYlz3c3cC&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles%20iii%20volume%202&hl=fr&pg=PA141#v=onepage&q&f=true ''Livre Sixiesme. Des tremblemens de terre.''], [https://books.google.fr/books?id=gEzVYlz3c3cC&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles%20iii%20volume%202&hl=fr&pg=PA164#v=onepage&q&f=true ''chap. VI.''], traduction par [[w:Pierre_Du_Ryer|Pierre Du Ryer]], A Lyon, Chez Christofle Fovrmy, 1663</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Pline_l%27Ancien|'''Pline l’Ancien''']] [[#Pline|<span id="Pline_back"><sup>'''I'''</sup></span>]] == <p style="text-align: right;">([[w:23|23]]/[[w:24|24]], à [[w:Côme|''Novum Comum'']] ou [[w:Vérone|Vérone]] — [[w:79|79]], à [[w:Stabies|Stabies]], [[w:Mort_de_Pline_l%27Ancien|mort]] par asphyxie près de [[w:Pompéi|Pompéi]], lors de l’éruption du [[w:Vésuve|Vésuve]], en voulant observer le phénomène au plus près et en désirant porter secours aux victimes, alors en poste à [[w:Misène|''Misène'']] en tant que Préfet commandant la flotte militaire ''romaine'') <sup>[[w:Ier_siècle|⏳]]</sup> [[s:Auteur:Pline_l’Ancien|<sup>📚</sup>]] [https://books.google.fr/books?id=tRsuD3WJT-UC&newbks=1&newbks_redir=0&lpg=PA3&dq=bibliogroup%3A%22Dictionnaire%20des%20philosophes%20antiques%22&hl=fr&pg=PA876#v=onepage&q&f=true {{Info|<sup>🔍</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume Va, §204 - Plinius Secundus (Caius —)}}] <div style="text-align: justify; margin: 0 1em; text-indent: 15px">Haut fonctionnaire militaire et civique, issu de l’[[w:Chevalier_romain|''orde équestre'']], et écrivain prolifique dans de très nombreux domaines.</div> {{Boîte déroulante début|titre=NdA Pline l’Ancien|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Pline_back|<span id="Pline"><sup>I</sup></span>]] [[w:Nom_romain|Tria Nomina]] en latin {{Info|Caius|praenomen, nom individuel du citoyen romain}} {{Info|Plinius|nomen, nom de famille}} {{Info|Secundus|cognomen, surnom héréditaire, servant à distinguer les diverses branches d’une même gens}}'''<br/><br/></div> {{Boîte déroulante fin}} === [[w:Histoire_naturelle_(Pline_l'Ancien)|Histoire naturelle]] === <p style="text-align: right;">[[s:Histoire_naturelle_(Pline)|📚]] <div style="text-align: justify; margin: 0 1em; text-indent: 15px">Ouvrage de 37 livres dédié à l’empereur [[w:Titus_(empereur_romain)|'''Titus''']] [[#Titus|<span id="Titus_back"><sup>'''I'''</sup></span>]], dont il a été le ''{{Lang|la|contubernium}}'' pendant son service en tant que commandant des armées du ''Rhin'' en ''Germanie'' en [[w:47|47]]. '''Pline''' définit lui-même son enquête [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Histoire/Enquête_I|<sup>🔄</sup>]] sur la nature comme une reproduction de la vie — ''{{Lang|la|rerum natura, hoc est uita narratur}}'' (Livre I, Préface, 10), qu’il inscrit dans la tradition encyclopédique [[#encyclopédie_back|<sup>⤴️</sup>]] grecque mais s’en différencie par son exhaustivité : ''{{Lang|la|Jam omnia attingenda, quæ Græci}}'' ''{{Lang|grc|τάς έγχυχλοπαιδείας}}'' ''{{Lang|la|vocant : et tamen ignota aut incerta ingeniis facta; alia vero ita multis prodita, ut in fastidium sint adducta}}'' (Préface, 11). Il a, dans ce but, compilé « vingt mille faits dignes d’intérêt, tirés de la lecture d’environ deux mille volumes, [...] provenant de cent auteurs de choix » — ''{{Lang|la|Viginti millia rerum dignarum cura ex lectione voluminum circiter duum millium, [...] ex exquisitis auctoribus centum}}'' (Préface, 13).</div> {{Boîte déroulante début|titre=NdA Titus|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Titus_back|<span id="Titus"><sup>I</sup></span>]] Du nom propre latin Titus [[wikt:en:Titus#Latin|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;">Commandant militaire, notamment pendant la [[w:Premi%C3%A8re_guerre_jud%C3%A9o-romaine|''première guerre judéo-romaine'']], au cours de laquelle il prend ''Jérusalem'' que ses troupes mettent à sac et fait détruire le [[w:Second_temple_de_Jérusalem#Destruction|''Second Temple'']], et empereur ''romain'', de la dynastie des [[w:Flaviens|''Flaviens'']], de [[w:79|79]] à [[w:81|81]].<br /><p style="text-align: right; margin: 0 2em;">(30 décembre [[w:39|39]] , ''Rome'' — 13 septembre [[w:81|81]], mort par fièvre selon [[w:Suétone|Suétone]] [http://remacle.org/bloodwolf/historiens/suetone/titus.htm <sup>VdDC, Titus</sup>] ou par empoisonnement avec du venin de [[w:Aplysia|''lièvre marin'']] par son propre frère [[w:Domitien|Domitien]] selon [[w:Philostrate_d%27Ath%C3%A8nes|Philostrate]] [https://remacle.org/bloodwolf/roman/philiostrate/apollonius6.htm <sup>AdT, l. VI, chap. 32</sup>])<sup>[[w:Ier_siècle|⏳]]</sup>'''<br/><br/></div> {{Boîte déroulante fin}} ==== Livre II ==== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Enquête sur l’astronomie et la physique du monde, basée sur les quatre éléments : air, terre, eau et feu.</div> ===== <div style="text-align: center;">Chapitre IX.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage de la première prédiction grecque d’une éclipse solaire (ou lunaire selon les traductions) par '''Thalès'''.</div> :'''Texte latin''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''IX.''' Et rationem quidem defectus utriusque primus ''Romani'' generis in vulgus extulit '''Sulpicius Gallus''', qui consul cum '''Marcello''' fuit, sed tum tribunus militum, sollicitudine exercitu liberato, pridie quam '''Perseus''' rex superatus a '''Paulo''' est, in concionem ab imperatore productus ad prædicendam eclipsim, mox et composito volumine. Apud Græcos autem investigavit primus omnium '''Thales''' ''Milesius'', Olympiadis XLVIII anno quarto, prædicto solis defectu, qui '''Alyatte''' rege factus est, Urbis conditæ; anno CLXX. Post eos utriusque sideris cursum in sexcentos annos præcinuit '''Hipparchus''', menses gentium, diesque et horas, ac situs locorum, et visus populorum complexus, ævo teste, haud alio modo, quam consiliorum naturæ particeps. Viri ingentes supraque mortalium naturam, tantorum numinum lege deprehensa, et misera hominum mente absoluta, in defectibus scelera aut mortem aliquam siderum pavente (quo in metu fuisse '''Stesichori''' et '''Pindari''' vatum sublimia ora palam est deliquio Solis), et in Luna veneficia arguente mortalitate, et ob id crepitu dissono auxiliante. Quo pavore, ignarus causæ, '''Nicias''' ''Atheniensium'' imperator, veritus classem portu educere, opes eorum afflixit. Macti ingenio este, cæli interpretes, rerumque naturæ capaces, argumenti repertores, quo deos hominesque vinxistis. Quis enim hæc cernens, et statos siderum (quoniam ita placuit appellare) labores, non suæ necessitati mortalis genitus ignoscat ? Nunc confessa de iisdem breviter atque capitulatim attingam, ratione admodum necessariis locis strictimque reddita : nam neque instituti operis talis argumentatio est : neque omnium rerum afferri posse causas, minus mirum est, quam consfare in aliquibus.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/b24875958_0001/page/n7/mode/2up <u>Histoire Naturelle de Pline.</u>], [https://archive.org/details/b24875958_0001/page/98/mode/2up ''Livre II.''], [https://archive.org/details/b24875958_0001/page/106/mode/2up ''chap. IX.''], texte corrigé par [[w:Émile_Littré|M. É. Littré]], à partir de celui de [[w:Jean_Hardouin|Hardouin]], Librairie de Firmin-Didot et C<sup>ie</sup>, Paris, 1883<br />(également disponible une édition 1848 [[s:Page:Pline_l'ancien_-_Histoire_naturelle,_Littré,_T1_-_1848.djvu/130|ici]] et 1829 [https://gallica.bnf.fr/ark:/12148/bpt6k5773334c/f45.item là])</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''IX.''' Le premier ''Romain'' qui exposa publiquement la théorie des éclipses du soleil et de la lune est [[w:Caius_Sulpicius_Gallus|'''Sulpicius Gallus''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Caius_Sulpicius_Gallus_back|<sup>🔄</sup>]], qui fut consul avec [[w:Marcus_Claudius_Marcellus_(consul_en_-166)|'''Marcellus''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Marcellus-166_back|<sup>🔄</sup>]], mais qui alors était tribun militaire. La veille du jour où [[w:Persée_(roi)|'''Persée''']] [[#Persée_(roi)|<span id="Persée_(roi)_back"><sup>'''I'''</sup></span>]] fut défait par [[w:Lucius_Æmilius_Paullus_Macedonicus|'''Paul-Emile''']] [[#Lucius_Æmilius_Paullus_Macedonicus|<span id="Lucius_Æmilius_Paullus_Macedonicus_back"><sup>'''II'''</sup></span>]] il parut par ordre du général, afin de prévenir les alarmes de l’armée, devant les troupes assemblées pour annoncer l’éclipse qui allait survenir; peu de temps après, il composa un livre sur ce sujet. Le premier qui s’en occupa chez les ''Grecs'' fut '''Thalès''' de ''Milet'', dans la quatrième année de la quarante-huitième olympiade (an 585 av. J. C. [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#éclipse_back|<sup>🔄</sup>]]), l’an 170 de la fondation de ''Rome'', et prédit une éclipse de lune qui arriva sous le roi [[w:Alyatte_II|'''Alyatte''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Alyatte_back|<sup>🔄</sup>]]. Après eux, [[w:Hipparque_(astronome)|'''Hipparque''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Hipparque_back|<sup>🔄</sup>]] dressa pour six cents ans la table du cours du soleil et de la lune, déterminant les mois des divers calendriers, les jours, les heures, les localités et les aspects, suivant les contrées. Le cours des ans ne lui a donné aucun démenti, et il semble avoir été admis aux conseils de la nature. Génies puissants et élevés au dessus de l’humanité, ils ont découvert la loi qui régit ces grandes divinités, et ils ont délivré de ses craintes l’esprit misérable des hommes, qui dans les éclipses, tantôt croyaient voir une influence malfaisante ou une espèce de mort des astres, crainte qui, comme on sait, a, pour l’éclipse du soleil, troublé [[w:Stésichore|'''Stésichore''']] [[#Stésichore|<span id="Stésichore_back"><sup>'''III'''</sup></span>]] et [[w:Pindare|'''Pindare''']] [[#Pindare|<span id="Pindare_back"><sup>'''IV'''</sup></span>]], poètes sublimes, et tantôt attribuaient l’obscurcissement de la lune à des maléfices, et lui venaient en aide par un bruit dissonnant. Redoutant ce phénomène, dont il ignorait la cause, [[w:Nicias|'''Nicias''']] [[#Nicias|<span id="Nicias_back"><sup>'''V'''</sup></span>]], général des ''Athéniens'', n’osa pas faire sortir la flotte du port de [[w:Syracuse#Antiquité|''Syracuse'']], et ruina la puissance de sa patrie. Redoublez de génie, interprètes du ciel, vous dont l’intelligence, embrassant la nature, a inventé des théories qui ont créé un lien entre les dieux et les hommes [[#Vicistis_JH|<span id="Vicistis_JH_back"><sup>'''1'''</sup></span>]] ! A la vue de ce spectacle, à la vue des labeurs (puisque c’est le nom qu’on a voulu donner aux éclipses), des labeurs réguliers auxquels les astres sont soumis, quel mortel ne pardonnerait à la nécessité sous laquelle il est né ? Maintenant je vais parler, d’une manière brève et sommaire, des points sur lesquels on est d’accord en cette matière. Je ne donnerai que de courtes explications, et là où il sera tout à fait nécessaire; car les explications n’entrent pas dans le plan de cet ouvrage, et il n’y a pas moins de mérite à énumérer les causes de toutes choses qu’à s’appesantir sur quelques-unes.</div> <table cellspacing=15 align=center style="margin: 0 4em; font-size:85%;"> <tr> <td style="text-align: justify; margin: 0 4em;">'''[[#Vicistis_JH_back|<span id="Vicistis_JH"><sup>1</sup></span>]] Vicistis Vulg. — Vinxistis cod. Dalech. — Vinxistis me parait meilleur. Comp. ce que dit Pline plus loin, ch. 24, sur l’affinité de l’esprit humain avec les astres.'''</td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/b24875958_0001/page/n7/mode/2up <u>Histoire Naturelle de Pline.</u>], [https://archive.org/details/b24875958_0001/page/98/mode/2up ''Livre II.''], [https://archive.org/details/b24875958_0001/page/106/mode/2up ''chap. IX.''], texte corrigé par [[w:Émile_Littré|M. É. Littré]], à partir de celui de [[w:Jean_Hardouin|Hardouin]], Librairie de Firmin-Didot et C<sup>ie</sup>, Paris, 1883<br />(édition 1848 également disponible [[s:Page:Pline_l'ancien_-_Histoire_naturelle,_Littré,_T1_-_1848.djvu/130|ici]])</div> {{Boîte déroulante début|titre=NdA de trad. Jean Hardouin 1883|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Persée_(roi)_back|<span id="Persée_(roi)"><sup>I</sup></span>]] Du nom propre grec ancien Περσεύς / Perseús[[wikt:en:Περσεύς#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px">Dernier roi de [[w:Royaume_de_Mac%C3%A9doine|''Macédoine'']] de la dynastie des [[w:Antigonides|''Antigonides'']], vaincu en [[w:-168|-168]] à la [[w:bataille de Pydna|bataille de ''Pydna'']] à l’issue de la [[w:troisième guerre macédonienne|''troisième guerre macédonienne'']], causant la disparition du ''Royaume de Macédoine''.<br /><p style="text-align: right; margin: 0 2em;">([[w:Années_212_av._J.-C.|-212]]<sup>[[w:IIIe_siècle_av._J.-C.|⏳]]</sup>, [[w:Pella_(cité_antique)|''Pella'']], au nord de l’actuelle ''Grèce'' — [[w:Années_166_av._J.-C.|-166]]<sup>[[w:IIe_siècle_av._J.-C.|⏳]]</sup>, [[w:Alba_Fucens|''Alba Fucens'']], au centre de l’actuelle ''Italie'') <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Lucius_Æmilius_Paullus_Macedonicus_back|<span id="Lucius_Æmilius_Paullus_Macedonicus"><sup>II</sup></span>]] [[w:Nom_romain|Tria Nomina]] en latin {{Info|Lucius|praenomen, nom individuel du citoyen romain}} {{Info|Æmilius|nomen, nom de famille}} {{Info|Paullus|cognomen, surnom héréditaire, servant à distinguer les diverses branches d’une même gens}}, surnommé [[wikt:Macedonicus#Latin|Macedonicus]] par le [[w:Sénat_romain|''Sénat'']] à la suite de sa victoire;<br /><p style="margin: 0 2em; text-indent: 15px">Homme politique ''romain'', consul à 2 reprises en [[w:Années_182_av._J.-C.|-182]] et [[w:Années_169_av._J.-C.|-169]]. Il remporta la victoire contre le ''royaume de Macédoine'' à ''Pydna'' en battant le roi Persée [[#Persée_(roi)|<sup>I</sup>]], ce qui mit fin à la dynastie des ''Antigonides''.<br /><p style="text-align: right; margin: 0 2em;">([[w:Circa|{{Info|''ca.''|Circa, locution latine que l’on emploie pour indiquer l’approximation d’une date}}]] [[w:Années_230_av._J.-C.|-230]]<sup>[[w:IIIe_siècle_av._J.-C.|⏳]]</sup>, ''Rome'' — ''ca.'' [[w:Années_160_av._J.-C.|-160]]<sup>[[w:IIe_siècle_av._J.-C.|⏳]]</sup>, ''Rome'') <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Stésichore_back|<span id="Stésichore"><sup>III</sup></span>]] Du nom propre grec ancien Στησίχορος /Stēsíkhoros [[wikt:en:Στησίχορος#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;">➥ du verbe ἵστημι /hístēmi, « 1. (voix transitive, active des temps présent, imparfait, futur et 1er aoriste) : • Faire se tenir debout, se tenir debout; • Arrêter, rester, vérifier; • Mettre en place : - Faire monter, élever, réveiller, remuer; - Nommer, désigner; - Établir, instituer; • Mettre dans la balance, peser. 2. (voix intransitive, moyenne et passive, voix active du 2e aoriste, parfait et plus-que-parfait) : • Se tenir debout; • Se tenir immobile : (au sens figuré) Rester ferme; • Être dressé ou debout, se lever, s’élever : - (en général) Se lever, commencer; - (en marquant le pas) Être; - Être désigné. »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ +‎ du nom commun χορός / khorós, « 1. Danse en rond. 2. Danse accompagnée de chant, danse chorale. 3. Chœur, chorale, groupe de chanteurs et de danseurs. 4. Groupe, troupe. 5. Rangée. 6. Lieu de danse. 7. (théâtre) Chœur »;<br /><p style="margin: 0 2em; text-indent: 15px">Poète lyrique grec, considéré comme l’un des [[w:Neuf_lyriques_grecs|''neuf poètes lyriques'']] de la Grèce antique.<br /><p style="text-align: right; margin: 0 2em;">([[w:Circa|{{Info|''ca.''|Circa, locution latine que l’on emploie pour indiquer l’approximation d’une date}}]] [[w:Années_630_av._J.-C.|-630]]<sup>[[w:VIIe_siècle_av._J.-C.|⏳]]</sup>, [[w:Metauria|''Metauria'']], colonie de la [[w:Grande-Grèce|''Grande-Grèce'']], au sud de la région de [[w:Calabre|''Calabre'']], au sud de l’Italie — ''ca.'' [[w:Années_555_av._J.-C.|-555]]<sup>[[w:VIe_siècle_av._J.-C.|⏳]]</sup>, [[w:Catane|''Catane'']], colonie de la ''Grande-Grèce'', à l’est de la [[w:Sicile|''Sicile'']]) <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Pindare_back|<span id="Pindare"><sup>IV</sup></span>]] Du nom propre grec ancien Πίνδᾰρος /Píndaros [[wikt:en:Πίνδαρος#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px">Poète lyrique grec, considéré comme l’un des [[w:Neuf_lyriques_grecs|''neuf poètes lyriques'']] de la Grèce antique.<br /><p style="text-align: right; margin: 0 2em;">([[w:Années_518_av._J.-C.|-518]]<sup>[[w:VIe_siècle_av._J.-C.|⏳]]</sup>, [[w:Cynocéphales|''Cynocéphales'']], cité grecque située près de [[w:Thèbes_(Grèce)|''Thèbes'']], en [[w:Béotie|''Béotie'']] — [[w:Années_438_av._J.-C.|-438]]<sup>[[w:Ve_siècle_av._J.-C.|⏳]]</sup>, [[w:Árgos|''Árgos'']], cité grecque de la région de l’[[w:Argolide|''Argolide'']], à l’est de la [[w:Péloponnèse|''péninsule du Péloponnèse'']]) <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Nicias_back|<span id="Nicias"><sup>V</sup></span>]] Du nom propre grec ancien Νῑκίᾱς /Nīkíās [[wikt:en:Νικίας#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;">➥ du nom commun νίκη / níkē [[wikt:en:νίκη#Ancient_Greek|(en)]], « 1. Le fait de gagner : la victoire, le succès [avec le génitif "sur, dans quelque chose"] : • Les choses gagnées dans la victoire, les fruits de la victoire; • La supériorité, l’avantage. »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ + du suffixe nominal masculin -ίας / -ías [[wikt:en:-ίας#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px">Homme politique et général ''athénien'' durant la [[w:Guerre_du_Péloponnèse|''guerre du Péloponnèse'']], qui oppose la [[w:Ligue_de_Délos|''ligue de Délos'']], menée par ''Athènes'', et la [[w:Ligue_du_Péloponnèse|''ligue du Péloponnèse'']], sous l’[[w:Hégémonie|hégémonie]] de ''Sparte'' de [[w:Années_431_av._J.-C.|-431]] à [[w:Années_404_av._J.-C.|-404]]. Sa supersition liée à une éclipse lunaire, s’étant produite lors de l’[[w:Expédition_de_Sicile|''expédition de Sicile'']], est également relatée par [[w:Thucydide|Thucydide]] [http://remacle.org/bloodwolf/historiens/thucydide/livre7.htm#L <sup>{{Info|HdlgdP|Histoire de la guerre du Péloponnèse}} l.VII, §.L</sup>] et [[w:Plutarque|Plutarque]] [[#Plutarque_back|<sup>⤵️</sup>]] [http://remacle.org/bloodwolf/historiens/Plutarque/supestition.htm#23 <sup>{{Info|DlS|De la Superstition}} l.I</sup>].<br /><p style="text-align: right; margin: 0 2em;">([[w:Circa|{{Info|''ca.''|Circa, locution latine que l’on emploie pour indiquer l’approximation d’une date}}]] [[w:Années_470_av._J.-C.|-470]], ''Athènes'' — ''ca.'' [[w:Années_413_av._J.-C.|-413]], ''Syracuse'')<sup>[[w:Ve_siècle_av._J.-C.|⏳]]</sup>'''<br/><br/></div> {{Boîte déroulante fin}} <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: center; margin: 0 2em;">Des découvertes astronomiques : part de chaque observateur dans la science.<br /><p style="text-align: justify; text-indent: 15px;">'''IX.''' '''Sulpicius Gallus''' [[#Sulpicius_Gallus_AdG|<span id="Sulpicius_Gallus_AdG_back"><sup>'''1'''</sup></span>]] fut le premier ''Romain'' qui expliqua au vulgaire la raison des éclipses de soleil et de lune. Il fut consul avec '''Marcus Marcellus''' ; mais il n’était que tribun militaire lorsque la veille de la victoire que '''Paul Emile''' remporta sur '''Persée''' [[#Pridie_quam_Perses_rex_AdG|<span id="Pridie_quam_Perses_rex_AdG_back"><sup>'''2'''</sup></span>]], son général le fit paraître devant l’armée assemblée, pour lui annoncer l’éclipse qui allait arriver, et la délivrer de l’alarme qu’elle aurait pu en concevoir. Il composa bientôt après un volume sur ce sujet. Parmi les ''Grecs'', '''Thalès''' de ''Milet'' [[#Primus_omnium_Thales_AdG|<span id="Primus_omnium_Thales_AdG_back"><sup>'''3'''</sup></span>]] dirigea le premier ses recherches sur ce phénomène, et la quatrième année de la 48e olympiade, qui répond à l’an 170 [[#Anno_CLXX_AdG|<span id="Anno_CLXX_AdG_back"><sup>'''4'''</sup></span>]] de ''Rome'', il prédit l’éclipse de soleil qui eut lieu sous le règne d’'''Alyatte''' [[#Alyatte_rege_AdG|<span id="Alyatte_rege_AdG_back"><sup>'''5'''</sup></span>]]. Après eux, '''Hipparque''' dressa des tables du cours de ces deux astres pour six cents ans [[#In_sexcentos_annos_AdG|<span id="In_sexcentos_annos_AdG_back"><sup>'''6'''</sup></span>]] : mois, heures, jours, situations respectives des lieux, aspects du ciel selon les diverses nations [[#Menses_gentium_etc_AdG|<span id="Menses_gentium_etc_AdG_back"><sup>'''7'''</sup></span>]], tout y est compris, tout a été vérifié par le temps [[#Aevo_teste_AdG|<span id="Aevo_teste_AdG_back"><sup>'''8'''</sup></span>]]; on croirait l’astronome admis au conseil de la nature. Génies vastes et plus qu’humains, d’avoir ainsi surpris la loi de ces deux grandes divinités [[#Numinum_AdG|<span id="Numinum_AdG_back"><sup>'''9'''</sup></span>]], et affranchi d’effroi la malheureuse espèce humaine, qui tremblait en voyant dans chaque éclipse l’annonce de quelque grand crime, ou craignait la mort des astres [[#In_defectibus_scelera_etc_AdG|<span id="In_defectibus_scelera_etc_AdG_back"><sup>'''10'''</sup></span>]] (effroi dont '''Stésichore''' et '''Pindare''' [[#Pindari_AdG|<span id="Pindari_AdG_back"><sup>'''11'''</sup></span>]], ces poètes sublimes, ne furent point exempts dans les éclipses de soleil), ou qui attribuait à des enchantemens celles de la lune, et venait à son secours en faisant un bruit discordant [[#Crepitu_dissono_AdG|<span id="Crepitu_dissono_AdG_back"><sup>'''12'''</sup></span>]]. C’est pour en avoir ignoré la cause, que, frappé de cette même terreur, '''Nicias''' [[#Nicias_AdG|<span id="Nicias_AdG_back"><sup>'''13'''</sup></span>]], général des ''Athéniens'', n’osa pas faire sortir sa flotte du port, et causa la ruine de leur puissance. Gloire à vous, interprètes du ciel, génies aussi étendus que la nature, inventeurs d’une science qui enchaîne à une même destinée les dieux et les mortels ! Quel est donc l’homme qui, voyant les astres en travail (pour me servir du nom qu’il a plu de donner aux crises qu’ils, subissent périodiquement), ne se soumettra pas à sa destinée?<br /><p style="text-align: justify; text-indent: 15px;">Je vais maintenant toucher brièvement et sommairement les points sur lesquels on est d’accord dans cette matière, et j’en rendrai raison en passant, lorsque cela sera tout-à-fait nécessaire; car un développement de preuves n’est pas le but de l’ouvrage que j’ai entrepris, et il n’y a pas, je pense, moins de mérite à pouvoir rendre raison de toutes choses, qu’à s’arrêter à en prouver quelques-unes.</div> {{Boîte déroulante début|titre=Notes du traducteur|alignT=center}} <div style="text-align: justify; border: 2px; border-radius:15px; font-size:85%;"><br/> <table cellspacing=15 align=center style="margin: 0 4em;"> <tr> <td style="text-align: justify; margin: 0 4em; text-indent: 15px">'''[[#Sulpicius_Gallus_AdG_back|<span id="Sulpicius_Gallus_AdG"><sup>1</sup></span>]] [[w:Tite-Live|Tite-Live]], XLIV, 37, [[w:Quintilien|Quintilien]], I, 10, [[w:Plutarque|Plutarque]] [[#Plutarque_back|<sup>⤵️</sup>]], [[w:Vies_parallèles|''Vie de Paul Emile'']], [[w:Frontin|Frontin]], I, etc., prétendent, comme Pline, que Sulpicius Gallus prédit l’éclipse anx soldats romains. [[w:Cicéron|'''Cicéron''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Cicéron_back|<sup>🔄</sup>]] ([[w:De_Republica|''Répub.'']], I, 15 , page 44, ''édit. Maj.'') dit au contraire que l’éclipse était déjà arrivée lorsque Sulpicius Gailus commençait à s’efforcer d’ôter aux soldats romains la terreur qu’ils avaient conçue de cet événement, en leur expliquant les causes des éclipses.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Pridie_quam_Perses_rex_AdG_back|<span id="Pridie_quam_Perses_rex_AdG"><sup>2</sup></span>]] Selon Tite-Live (XLIV, 37), l’éclipse eut lieu dans la soirée du 3 septembre, cent huit ans avant J.-C., entre sept et dix heures (''ab hora secunda usque ad quartam noctis, quam pridie nonas sept, secula est dies''). M. [[w:Christian_Ludwig_Ideler|Ideler]] (''Chronologie'', II, 104) a calculé cette éclipse. Il a trouvé, comme M. de Nauze, que, selon le calendrier Julien, elle arriva dans la soirée du 21 juin de l’an 168 avant J.-C. à Rome, la lune commença à s’éclipser vers 5h.44’ du soir ; depuis 6h.51’ jusqu’à 8h.18’, la lune fut totalement éclipsée, ; à 9h.,24’, la lune ne fut plus obscurcie du tout. En Macédoine, tous ces phénomènes arrivèrent 39 minutes plus tard. Le 21 juin, le soleil se coucha à Rome et en Macédoine vers 7h.33’, et s’y montra alors à 44 1/2’ h. équatoriales. Ainsi, la première heure de la nuit finissait vers 8h.17’, la seconde vers 9h.2’, la troisième vers 9h.46’, la quatrième vers 10h.31’. La lune fut donc éclipsée totalement au moment où elle se leva dans la Macédoine, et cette éclipse totale y finit dans la seconde heure de la nuit ; au milieu de la quatrième, la lune ne fut plus obscurcie du tout. S’il est vrai, que cette éclipse lunaire, comme Pline, Tite-Live et d’autres le disent, fut prédite par Sulpicius Gallus, l’on devrait avouer que ce Romain s’entendait très-bien au calcul des éclipses lunaires. Mais les récits de Cicéron et de [[w:Valère_Maxime|Valère-Maxime]] ne seraient-ils pas plus vrais que ceux de Pline et de Tite-Live ?''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Primus_omnium_Thales_AdG_back|<span id="Primus_omnium_Thales_AdG"><sup>3</sup></span>]] Le même fait est rapporté par [[w:Hérodote|Hérodote]] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Hérodote_back|<sup>🔄</sup>]], I, 74, par [[w:Diogène_Laërce|Diogène Laërce]] [[#Diogène_Laërce_back|<sup>⤵️</sup>]], I, 6 , par [[w:Clément_d'Alexandrie|Clément d’Alexandrie]] [[#Clément_d'Alexandrie_back|<sup>⤵️</sup>]], ''Strom.'', I, page 302 , par Plutarque, ''Opinions des Philosophes'', II, 24, par [[w:Jean_Tzétzès|Tzetzès]], ''Chil.'' II, v. 869, et par Hardouin.<br /><p style="text-align: justify; text-indent: 15px;">Oltmann a publié une dissertation dans laquelle, à l’aide des tables astronomiques les plus modernes, il est arrivé à ce résultat, que l’éclipse solaire dont il est question ici eut lieu le 3o septembre 610 ans avant J.-C. L’éclipse était totale pour les environs de la ville d’[[w:Erzurum|Érzerum]] sur le [[w:Kızılırmak_(fleuve)|Halys]] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Halys_back|<sup>🔄</sup>]], où [[w:Volney|Volney]] place le champ de bataille des rois [[w:Alyatte_II|Halyattes]] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Alyatte_back|<sup>🔄</sup>]] et [[w:Cyaxare|Cyaxare]] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Cyaxare_back|<sup>🔄</sup>]]. La quatre-vingtième partie du disque solaire seule ne fut pas éclipsée pour le lieu de la terre où Oltmann place le champ de bataille, qui est situé, selon lui, sous 36° long. à l’est de Terro et sous 40° lat. sept. Dans le pays des Ioniens où Thalès prédit l’éclipse, selon Hérodote, l’éclipse se monta à 11 1/2’. M. [[w:Alphonse_Des_Vignoles|Desvignolles]] (''Chronologie de l’histoire sainte'', t. II, pag. 245 et suiv.) fixe l’éclipsé prédite par Thales au 38 mai de l’an 585 avant J.-C. ; son opinion a été adoptée depuis par presque tous les chronologistes et historiens, et par [[w:Gabriel_Brotier|Brotier]] et M. Alexandre. Elle a été réfutée avec succès par Oltmann, qui s’est servi de tables astronomiques bien plus exactes que celles de M. Desvignolles ; en effet, celui-ci a démontré par ses calculs que l’éclipse totale du soleil du 28 mai de l’an 585 avant J.-C., ne fut pas totale dans les lieux où les troupes du roi lydien Halyatte combattirent contre celles du roi Cyaxare ; que, dans ces régions, elle ne se monta pas à plus de 7 1/2 pouces, et que, d’ailleurs, le soleil ne s’était pas encore levé lorsque Féclipse était le plus forte pour les habitans des pays nommés. Mais Hérodote dit positivement que l’éclipse prédite par Thalès fut totale dans ces contrées, et qu’elle eut lieu en plein jour. (Voyez IDELER, ''Chronologie'', t. I, pag. 209 et 210.) Nous remarquerons pourtant avant de finir cette note que la date de Desvignolles est plus conforme que celle d’Oltmann à l’année dans laquelle l’éclipse prédite par Thalès, arriva selon Pline. En effet, le naturaliste romain dit que cette année est la six cent quatre-vingt-cinquième avant J.—C., et c’est justement le 28 mai de cette année que l’éclipse prédite par Thalès arriva, selon M. Desvignolles.<br /><p style="text-align: justify; text-indent: 15px;">Volney pense que l’éclipse en question arriva le 3 février de de l’an 626. Oltman a démontré, dans son Mémoire sur l’éclipse de Thalès, que celle de Volney était déjà passée lorsque le soleil se leva sur le champ de bataille des rois Halyattes et Cyaxare.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Anno_CLXX_AdG_back|<span id="Anno_CLXX_AdG"><sup>4</sup></span>]] L’an 170. C’est ainsi que l’on doit lire, et non CLX, comme l’ont fait Hardouin et Poinsinet; la quatrième année de la quarante-huitième olympiade, correspondant à l’an 170 de Rome, si l’on suppose avec [[w:Varron_(écrivain)|Varron]] que cette ville a été fondée dans la deuxième année de la 6e olympiade.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Alyatte_rege_AdG_back|<span id="Alyatte_rege_AdG"><sup>5</sup></span>]] Le nom de ce roi est écrit avec un esprit rude dans Hérodote, ce qui a donné lieu à [[w:Louis_Poinsinet_de_Sivry|Poinsinet]] et à d’autres traducteurs de Pline de substituer le mot Halyatte à celui d’Alyatte.<br /><p style="text-align: justify; text-indent: 15px;">Alyatte ou Halyatte fut roi de la Lydie et père de Crésus. Il faisait la guerre à Cyaxare, roi des Mèdes, lorsque l’éclipse solaire en question interrompit le combat.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#In_sexcentos_annos_AdG_back|<span id="In_sexcentos_annos_AdG"><sup>6</sup></span>]] On lit dans [[w:Georges_le_Syncelle|le Syncelle]] (''Chronolog.'', pag. 17) que les Chaldéens ont connu une période de six cents années solaires. [[w:Flavius_Josèphe|Josèphe]] [[#Flavius_Josèphe_back|<sup>⤵️</sup>]] ([[w:Antiquités_judaïques|''Ant. jud.'']], I, page 17 et 18, édit. Havercamp) dit que Dieu donna une longue vie aux patriarches pour qu’ils pussent cultiver avec succès les sciences astronomiques et géométriques, ce qu’ils n’auraient pu faire s’ils n’avaient pas vécu au moins six cents ans ; car la grande année ne finit pas plus tôt. Ainsi, il est certain qu’avant Hipparque les Chaldéens et d’autres peuples asiatiques ont connu une période de six cents années solaires. Mais [[w:Jean-Dominique_Cassini|Cassini]] ([[w:Jean-Dominique_Cassini#Mémoires_de_l’Académie_royale_des_sciences|''Anciens mém. de l’Acad.'']], t. VIII, pag. 4 et 5) et [[w:Jean_Sylvain_Bailly|Bailly]] (''Hist. de l’astr. ancienne'', t. II, liv. 3, Eclairciss.) ont prouvé que tous les six cents ans les nouvelles et pleines lunes n’arrivent pas seulement au même jour et à la même heure qu’auparavant, mais encore à la même minute. Ne serait-il donc pas probable qu’Hipparque, comme le dit Ideler (''Historische untersuchungen uber die astronomischen beobachtungen der alten'', Berlin 1806, page 417) a connu cette période chaldéenne, et que delà résulte l’étendue de six cents ans donnée à son calendrier selon Pline.<br /><p style="text-align: justify; text-indent: 15px;">[[w:Abel_Burja|Abel-Burja]] de Leipzig a tâché d’expliquer d’une autre manière la durée du calendrier d’Hipparque (''Astronomisches Jahrbuch'', 1797, pag. 233 et 234). [[w:Claude_Ptolémée|Ptolémée]] et [[w:Censorin_(grammairien)|Censorin]] racontent qu’Hipparque est auteur d’une période soli-lunaire de trois cent quatre années solaires. En la prenant deux fois, on obtient une période de six cent huit ans. Celle-ci fut abrégée par Hipparque de huit ans, afin d’obtenir un nombre entier de siècles pour son calendrier. Ideler a fait une objection très-juste contre cette opinion de Burja ; c’est que la période de six cent huit ans n’a aucun avantage sur celle de trois cent quatre ans. On ne voit donc pas ce qui a pu engager Hipparque à préférer le nombre de six cents ans à celui de trois cents, lorsqu’il composait son calendrier.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Menses_gentium_etc_AdG_back|<span id="Menses_gentium_etc_AdG"><sup>7</sup></span>]] C’est-à-dire il écrivit des éphémérides dans lesquelles il avait calculé d’avance les néomenies et les pleines lunes. Il fit aussi entrer dans son calendrier les longueurs des jours et des heures variables, [[w:ὧραι|ὧραι]] καιρικαι, ainsi que les aspects du ciel, ''visus populorum'', tels qu’ils eurent lieu chez les habitans de différentes contrées de la terre. Il ajouta une table des longitudes et des latitudes des principaux pays et villes du globe. Ptolémée (''Géogr.'', I, ch. 4) en dit autant d’Hipparque.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Aevo_teste_AdG_back|<span id="Aevo_teste_AdG"><sup>8</sup></span>]] Les tables d’Hipparque étaient dressées pour six cents ans. Cet astronome florissait vers cent cinquante ans avant J.-C. Ainsi, du temps de Pline, on avait encore à jouir de ces tables pour quatre cents ans environ. POINSINET.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Numinum_AdG_back|<span id="Numinum_AdG"><sup>9</sup></span>]] Pline donne souvent l’épithète de divinités aux planètes, à la lune, au soleil, à la terre et aux étoiles fixes.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#In_defectibus_scelera_etc_AdG_back|<span id="In_defectibus_scelera_etc_AdG"><sup>10</sup></span>]] Nous transcrivons ici ce beau passage de l’Uranographie de M. [[w:Louis-Benjamin_Francœur|Francoeur]], qui mérite d’être mis en parallèle avec celui de Pline pour l’élégance du style et les pensées, et qui renferme le meilleur commentaire que nous puissions donner de tout ce que Pline dit des terreurs que les éclipses causaient autrefois aux hommes ignorans. « L’histoire, dit M. Francoeur (page 93), est pleine des exemples de l’effroi causé par les éclipses, et des dangers que produisent l’ignorance et la superstition. Nicias avait résolu de quitter la Sicile avec son armée ; effrayé par une éclipse de lune, et voulant temporiser plusieurs jours pour s’assurer si l’astre n’avait rien perdu après cet évènenement, il manqua ainsi l’occasion de sa retraite; son armée fut détruite ; Nicias périt, et ce malheur commença la ruine d’Athènes.<br /><p style="text-align: justify; text-indent: 15px;">« Souvent on a vu des hommes adroits tirer parti de la frayeur du peuple pour l’amener à remplir leurs desseins. Christophe Colomb, réduit à faire subsister ses soldats des dons volontaires d’une nation sauvage et indigente, était prêt à voir tarir cette ressource et à périr de faim ; il annonce qu’il va priver le monde de la lumière de la lune. L’éclipse commence et la terreur s’empare des Indiens, qui reviennent apporter aux pieds de Colomb les tributs accoutumés.<br /><p style="text-align: justify; text-indent: 15px;">« Drusus (TACITE , Annales, I, 28) apaisa une sédition dans son armée, en prédisant une éclipse de lune, et, selon Tite-Live, Sulpicius Gallus, dans la guerre de Paul-Emile contre Persée, usa du même stratagème. Periclès, [[w:Agathocle_de_Syracuse|Agathocles de Syracuse]], [[w:Dion_de_Syracuse|Dion]], roi de Sicile, ont failli être victimes de l’ignorance de leurs soldats. [[w:Alexandre_le_Grand|Alexandre]], près d’[[w:Bataille_de_Gaugamèles|Arbelles]], est réduit à user de toute son adresse pour calmer la terreur qu’une éclipse avait jetée parmi ses troupes. Les hommes supérieurs, plutôt que de plier sous les circonstances qui les maîtrisent, mettent leur art à les tourner à leur profit.<br /><p style="text-align: justify; text-indent: 15px;">« Combien de fables établies d’après l’opinion que les éclipses sont l’effet du courroux céleste qui se venge des iniquités de l’homme en le privant de la lumière! Tantôt [[w:Diane_(mythologie)|Diane]] va trouver [[w:Endymion|Endymion]] dans les montagnes de Carie; tantôt les magiciennes de Thessalie font descendre la lune sur les herbes qu’elles destinent aux enchantemens. »<br /><br /><p style="text-align: center;">''Carmina vel cælo possunt deducere lunam.''<br /><p style="text-align: right; text-indent: 15px;">Virg., ''Eclog.'' VIII.<br /><br /><p style="text-align: justify; text-indent: 15px;">« Ici c’est un dragon qui dévore l’astre, et qu’on cherche à épouvanter par des cris ; le dieu tient le soleil enfermé dans un tuyau, et nous ôte ou nous rend la vue de cet astre à l’aide d’un volet, etc. Les progrès des sciences ont fait connaître le ridicule de ces opinions et de ces craintes, depuis qu’on a vu qu’il était possible de calculer par les tables astronomiques, et de prévoir long-temps d’avance l’instant où la colère du ciel devait éclater.<br /><p style="text-align: justify; text-indent: 15px;">« Cependant, naguère encore, l’épouvante a causé les revers des armées de Louis XIV, près de Barcelone, lors de l’éclipse totale de l’an 1706 [[w:en:Solar_eclipse_of_May_12,_1706|(en)]], et la devise, ''nec pluribus impar'', a prêté aux allusions injurieuses ! »''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Pindari_AdG_back|<span id="Pindari_AdG"><sup>11</sup></span>]] Pindare était le plus fameux poète de la Grèce après Homère. Il vint au monde l’an 134 avant l’ère chrétienne. POINSINET.<br /><p style="text-align: justify; text-indent: 15px;">Plutarque (''De la face de la lune'', pag. 931) dit aussi que Stésichore et Pindare craignaient beaucoup les éclipses. Le dernier poète a peint les terreurs que lui causaient ces phénomènes dans son poëme sur le soleil. HARDOUIN et DALECHAMP.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Crepitu_dissono_AdG_back|<span id="Crepitu_dissono_AdG"><sup>12</sup></span>]] Cet usage superstitieux dont Plutarque parle au long dans sa vie de Paul-Émile, a fourni un vers fort plaisant à Juvénal, lorsqu’après avoir épuisé toute sorte d’exagération pour représenter le bruit qu’une femme fait en criant, il finit par dire :<br /><br /><p style="text-align: center;">''Una laboranti poterit succurrere lunæ.''<br /><br /><p style="text-align: justify; text-indent: 15px;">« Elle seule, au besoin, décharmerait la lune. » POINSINET.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Nicias_AdG_back|<span id="Nicias_AdG"><sup>13</sup></span>]] Le même fait est raconté par Plutarque dans la vie de Nicias, par Quintilien, I, 10, et par d’autres écrivains anciens. HARDOUIN.''' </td> </tr> </table><br/><br/></div>{{Boîte déroulante fin}} <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k5773334c/f10.item <u>Histoire Naturelle de Pline. Tome Second</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k5773334c/f14.item ''Livre II.''], [https://gallica.bnf.fr/ark:/12148/bpt6k5773334c/f46.item ''chap. IX.''], traduction nouvelle par M. [[w:Stéphane_Ajasson_de_Grandsagne|Ajasson de Grandsagne]] [https://gallica.bnf.fr/ark:/12148/bpt6k5773334c/f311.item <sup>NOTES</sup>], C. L. F. Panckoucke, Paris, 1829</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: center; margin: 0 2em;">''Des inventions a[[w:S_long|{{Info|ſ|forme ancienne longue de la lettre s minuscule}}]]<nowiki />tronomiques, & de leurs Auteurs.''<br /><p style="text-align: justify; text-indent: 15px;">'''L'''E PREMIER d’entre les ''Romains'' qui rendit publique la théorie des éclip{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oleil & de lune, fut '''Sulpicius Gallus''' [[#Sulpicius_Gallus_LPdS|<span id="Sulpicius_Gallus_LPdS_back"><sup>'''1'''</sup></span>]], celui que '''Marcus Marcellus''' eut pour Collegue au Con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ulat : mais il n’étoit que Tribun Militaire [[#Tribun_Militaire_LPdS|<span id="Tribun_Militaire_LPdS_back"><sup>'''2'''</sup></span>]], lor{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’il di{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ipa l’allarme qu’auroient pu prendre nos troupes la veille de la victoire remportée {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur '''Per{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ée''' par '''Paul Emile''' ; car ce Général l’ayant produit devant les {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oldats a{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}emblés, il leur prédit une éclip{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e qui devoit arriver [[#éclipse_LPdS|<span id="éclipse_LPdS_back"><sup>'''3'''</sup></span>]] ; il compo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}a même en{{Info|ſ|forme ancienne longue de la lettre s minuscule}}uite un Ouvrage {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur ce {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ujet. Parmi les ''Grecs'', '''Thalès''' de ''Milet'' prédit l’an quatrieme de la quarante-huitieme olympiade l’éclip{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oleil qui arriva {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous le regne de '''Halyattes''' [[#Halyattes_LPdS|<span id="Halyattes_LPdS_back"><sup>'''4'''</sup></span>]], l’an cent {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oixante de la fondation de [[#cent_soixante_LPdS|<span id="cent_soixante_LPdS_back"><sup>'''5'''</sup></span>]] ''Rome''. Après eux, Hipparque [[#Hipparque_LPdS|<span id="Hipparque_LPdS_back"><sup>'''6'''</sup></span>]] dre{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}a des Tables en vers [[#En_vers_LPdS|<span id="En_vers_LPdS_back"><sup>'''7'''</sup></span>]] du cours de ces deux aftres pour fix cents ans. Dans ces Tables , de l’exactitude deſquelles notre âge rend encore témoignage [[#témoignage_LPdS|<span id="témoignage_LPdS_back"><sup>'''8'''</sup></span>]], il embra{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}e les éphémérides propres à chaque nation [[#chaque_nation_LPdS|<span id="chaque_nation_LPdS_back"><sup>'''9'''</sup></span>]], les jours, les heures, le {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ite re{{Info|ſ|forme ancienne longue de la lettre s minuscule}}pectif de chaque lieu, & les divers a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}pects du ciel relativement aux divers peuples, comme {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i la Nature l’eût admis à {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}eil intime. Per{{Info|ſ|forme ancienne longue de la lettre s minuscule}}onnages vraiment grands! génies plus qu’humains, d’avoir ain{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i {{Info|ſ|forme ancienne longue de la lettre s minuscule}}urpris les loix qui font mouvoir ces va{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tes pui{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ances du ciel ; & d’avoir guéri de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}es allarmes l’imagination malade des hommes, qui ju{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’alors, ou avoient toujours vu dans les éclip{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es l’annonce effrayante de quelque grand crime & de quelque mort (terreur dont Sté{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ikhore [[#Stésikhore_LPdS|<span id="Stésikhore_LPdS_back"><sup>'''10'''</sup></span>]] & Pindare [[#Pindare_LPdS|<span id="Pindare_LPdS_back"><sup>'''11'''</sup></span>]], ces Poètes {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ublimes, ne furent point exempts à l’égard des éclip{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es {{Info|ſ|forme ancienne longue de la lettre s minuscule}}olaires), ou attribuoient les ténebres dont {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e couvre la lune à des maléfices opérés par le mêlange de certaines herbes magiques ; & croyoient devoir la {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ecourir par un bruit di{{Info|ſ|forme ancienne longue de la lettre s minuscule}}cordant [[#bruit_discordant_LPdS|<span id="bruit_discordant_LPdS_back"><sup>'''12'''</sup></span>]]. Cette même terreur fut cau{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e que le Général Nicias [[#Nicias_LPdS|<span id="Nicias_LPdS_back"><sup>'''13'''</sup></span>]], peu au fait des cau{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es phy{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iques, & n’o{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ant pas, par {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uper{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tition, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ortir {{Info|ſ|forme ancienne longue de la lettre s minuscule}}a flotte du Port, mit Athenes à deux doigts de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}a perte. Honneur [[#Honneur_LPdS|<span id="Honneur_LPdS_back"><sup>'''14'''</sup></span>]] à vous, Interpretes du Ciel ! E{{Info|ſ|forme ancienne longue de la lettre s minuscule}}prits [[#Esprits_LPdS|<span id="Esprits_LPdS_back"><sup>'''15'''</sup></span>]] dont l’étendue {{Info|ſ|forme ancienne longue de la lettre s minuscule}}urpa{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}e celle de la Nature ; Inventeurs d’une méthode qui a{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ujettit les dieux comme les hommes, à une même de{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tinée ! Eh! qui pourroit, en voyant les a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tres même ''en cri{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e'' (pour me {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ervir de l’expre{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ion commune), ne pas {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oumettre à la néce{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ité où {{Info|ſ|forme ancienne longue de la lettre s minuscule}}a condition mortelle l’enchaîne.<br /><p style="text-align: justify; text-indent: 15px;">Pré{{Info|ſ|forme ancienne longue de la lettre s minuscule}}entement je vais toucher par articles fort courts & fort précis les points {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur le{{Info|ſ|forme ancienne longue de la lettre s minuscule}}quels on s’accorde le plus. Je ré{{Info|ſ|forme ancienne longue de la lettre s minuscule}}oudrai, chemin fai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ant, quelques que{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tions, lor{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que le cas l’exigera, mais toujours d’une maniere très {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ommaire ; car une analy{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e en forme d’arguments {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uivis excéderoit le but de cet Ouvrage : & puis, je pen{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e qu’il n’y a pas moins de mérite à rendre une rai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}on plau{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ible de toutes cho{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es, qu’à rendre une rai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}on bien {{Info|ſ|forme ancienne longue de la lettre s minuscule}}olide de deux ou trois cho{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eulement.</div> {{Boîte déroulante début|titre=Notes du traducteur|alignT=center}} <div style="text-align: justify; border: 2px; border-radius:15px; font-size:85%;"><br/> <table cellspacing=15 align=center style="margin: 0 4em;"> <tr> <td style="text-align: justify; margin: 0 4em; text-indent: 15px">'''[[#Sulpicius_Gallus_LPdS_back|<span id="Sulpicius_Gallus_LPdS"><sup>1</sup></span>]] Son premier prénom étoit Caïus. Voyez à {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ujet Tite-Live, l. 44. Valere maxime, l. 8. Quintilien, l. I. ch. 10. Plutarque, vie de Paul-Emile, &c.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Tribun_Militaire_LPdS_back|<span id="Tribun_Militaire_LPdS"><sup>2</sup></span>]] Ce grade répond à celui de Major-général des Troupes.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#éclipse_LPdS_back|<span id="éclipse_LPdS"><sup>3</sup></span>]] Cette éclip{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}elon Tite-Live, fut annoncée aux {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oldats pour la nuit {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uivante. Sulpicius Gallus leur prédit que la lune s’éclip{{Info|ſ|forme ancienne longue de la lettre s minuscule}}eroit entre la {{Info|ſ|forme ancienne longue de la lettre s minuscule}}econde heure de la nuit & la quatrieme. Plutarque ajoute qu’on étoit alors à l’i{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ue de l’été (''{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ub exitum a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tatis''). [[w:Paulin_II_d'Aquilée|Paul d’Aquilée]] écrit que cette éclip{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e arriva aux nones de Septembre (''nonas Septembris''), c’est-à-dire au 4 Septembre : c’étoit l’an 168 avant J.C. {{Info|ſ|forme ancienne longue de la lettre s minuscule}}elon le calcul d’[[w:James_Ussher|U{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}erius]].''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Halyattes_LPdS_back|<span id="Halyattes_LPdS"><sup>4</sup></span>]] Il paroît que Ciceron & Eu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ebe {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e trompent lor{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’ils placent cet événement {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous ''A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tiages'' : [[w:Hermolaos_(Macédoine)|Hermolaüs]] s’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t trompé d’après eux, en {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ub{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tituant ''A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tiages'' à ''Halyattes'' dans le texte de Pline, contre la foi des manu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}crits, & contre le témoignage d’Herodote qui place cet événement dans une guerre entre Halyattes, Roi de Sardes, & Cyaxare, Roi des Medes, pere d’A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tiages.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#cent_soixante_LPdS_back|<span id="cent_soixante_LPdS"><sup>5</sup></span>]] Les deux manu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}crits royaux portent ''anno CLX'' : c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t la leçon qu’il faut {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uivre. En effet, Rome, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}elon Varron, fut fondée l’an 2 de la {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ixieme olympiade, c’est-à-dire, dans l’année olympiadique 22. Mais comme chaque olympiade, depuis leur premiere in{{Info|ſ|forme ancienne longue de la lettre s minuscule}}titution, commençoit après le {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ol{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tice d’été, & comme l’année Romaine avoit toujours commencé au plus tard en Mars {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous Romulus, & depuis en Janvier {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous Numa, il s’en{{Info|ſ|forme ancienne longue de la lettre s minuscule}}uit que la premiere année de Rome, qui répondoit à l’année olympiadique 22, répondoit en même-tems, de quatre mois au moins, à l’année olympíadique 23. Selon ce calcul, la quatrieme année de la quarante-huitieme olympiade, répond en partie à l’an 160, & en partie à l’an 161 de la fondation de Rome, pui{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que 48 olympiades font cent quatre-vingt-douze années, de{{Info|ſ|forme ancienne longue de la lettre s minuscule}}quelles {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i vous ôtez 22 ans écoulés, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}elon Varron, entre la premiere olympiade & la fondation de Rome, il re{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tera 160 ans, & 161 ans {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i l’on a égard à l’enjambement réciproque des années olympiadiques {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur les années Romaines, & des années Romaines {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur les années olympiadiques. Il e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t donc évident que le calcul de Pline (''anno CLX'') e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t ju{{Info|ſ|forme ancienne longue de la lettre s minuscule}}te, en admettant l’hypothe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e chronologique de Varron, à laquelle on voit bien que notre Auteur s’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t conformé en cette occa{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ion particuliere encore qu’en plu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ieurs autres rencontres il paroi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}e affecter de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uivre le {{Info|ſ|forme ancienne longue de la lettre s minuscule}}y{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tême de Caton : vici{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}itude pardonnable dans un ouvrage de compilation où Pline a dû, comme malgré lui, adopter tantôt le {{Info|ſ|forme ancienne longue de la lettre s minuscule}}tyle d’un Auteur, tantôt celui d’un autre, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}elon la {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ource où il pui{{Info|ſ|forme ancienne longue de la lettre s minuscule}}oit pour l’heure. Si Pline eût {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uivi l’hypothe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e de Caton qui place la fondation de Rome deux ans plus tard que Varron, il eût fait tomber le rapport {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur l’année 157 ou 158 de la fondation de Rome. C’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t le parti que prend le Pere Hardouin, & c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t de là qu’il part pour propo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}er une correction dans le texte. Mais encore une fois, c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t commettre {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oi-même une faute que d’en trouver une chez Pline en cette occa{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ion ; pui{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que cet Auteur a été en droit de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ervir du {{Info|ſ|forme ancienne longue de la lettre s minuscule}}y{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tème Varronien, ou ce qui revient au même, de con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}erver la date Varronienne dont s’étoit {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ervi l’Auteur de qui il emprunte le fait hi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}torique en que{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tion.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Hipparque_LPdS_back|<span id="Hipparque_LPdS"><sup>6</sup></span>]] Voyez les notes {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur le premier livre au mot ''Hipparque'' : HIPPARCHUS (de Nicée, en Bithinie comme l’ob{{Info|ſ|forme ancienne longue de la lettre s minuscule}}erve [[w:Souda|Suidas]]), flori{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}oit dans la quatre-vingt-quatorzieme olympiade. Nous avons {{Info|ſ|forme ancienne longue de la lettre s minuscule}}es trois livres d’Enarrations {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur les Phénomenes d’[[w:Aratos_de_Soles|Aratus]] & d’[[w:Eudoxe_de_Cnide|Eudoxe]], traduits par le [[w:Paul_Petau|P. Petau]]. Il avoit compo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}é un autre livre ''De {{Info|ſ|forme ancienne longue de la lettre s minuscule}}tellarum inerrantium Con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}titutione'', {{Info|ſ|forme ancienne longue de la lettre s minuscule}}elon Suidas. Son livre du mois lunaire e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t cité par [[w:Claude_Galien|Galien]].''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#En_vers_LPdS_back|<span id="En_vers_LPdS"><sup>7</sup></span>]] ''En Vers.'' Je préfume que c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t-là le {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ens de ''præcinere'', qui ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ignifie pas {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eulement prédire, mais prédire en chant, c’est-à-dire en Vers. Sur ce pied-là, ce {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eroit d’un Poëme dans le genre de celui d’[[w:Aratos_de_Soles|Aratus]], dont il {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eroit ici que{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tion. Si par hazard Pline n’a point prétendu parler d’un Poëme, au-moins s’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t-il {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ervi d’une expre{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ion propre à dé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}igner ce genre d’écrire. Pour décider la que{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tion, il faudroit avoir tous les ouvrages d’Hipparque, & {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur-tout celui-ci.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#témoignage_LPdS_back|<span id="témoignage_LPdS"><sup>8</sup></span>]] Ces tables étoient dre{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ées pour {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ix cents ans. Or Hipparque flori{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}oit 150 ans avant J.C. Ain{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i du tems de Pline, on avoit encore à jouir de ces tables pour quatre cents ans ou environ.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#chaque_nation_LPdS_back|<span id="chaque_nation_LPdS"><sup>9</sup></span>]] La lune ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e levant pas & ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e couchant pas à la même heure pour toutes les nations, les diver{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es époques & pha{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es qu’elle forme n’appartiennent pas non plus au même point de tems pour tous les peuples, pui{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que les uns ont la nuit quand les autres ont le jour; & que même lor{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que la lune s’éclip{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e, la partie de l’heure où ce phénomene e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t {{Info|ſ|forme ancienne longue de la lettre s minuscule}}en{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ible, n’a pas la même évaluation pour tous les climats qui l’apperçoivent. Hipparque avoit donc eu égard à cette différence d’époques, relativement aux diver{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es longitudes, &par-con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}équent aux diver{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es nations, tellement que les tables de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}es éphémérides étoient accommodées à l’u{{Info|ſ|forme ancienne longue de la lettre s minuscule}}age de tous les peuples : ouvrage dont on ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}auroit trop regretter la perte, & qui jetteroit le plus grand jour {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur l’ancienne géographie.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Stésikhore_LPdS_back|<span id="Stésikhore_LPdS"><sup>10</sup></span>]] Ste{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ikhore, l’un des plus fameux Poètes de la Grece, dont, par malheur, nous avons perdu tous les ouvrages, à l’exception d’une vingtaine de lignes décou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ues. Il vivoit dans la quarante-deuxieme olympiade, c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t-à-dire, vers l’an {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ix cents dix avant J.C.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Pindare_LPdS_back|<span id="Pindare_LPdS"><sup>11</sup></span>]] Pindare, le plus fameux Poète de la Grece après Homere. Il vint au monde l’an 134 avant l’ere chrétienne.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#bruit_discordant_LPdS_back|<span id="bruit_discordant_LPdS"><sup>12</sup></span>]] Cet u{{Info|ſ|forme ancienne longue de la lettre s minuscule}}age {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uper{{Info|ſ|forme ancienne longue de la lettre s minuscule}}titieux a fourni un Vers fort plai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ant à Juvenal, lor{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’après avoir épui{{Info|ſ|forme ancienne longue de la lettre s minuscule}}é toute {{Info|ſ|forme ancienne longue de la lettre s minuscule}}orte d’exagération pour repré{{Info|ſ|forme ancienne longue de la lettre s minuscule}}enter le bruit qu’une femme fait en criant, il finit par dire :<br /><p style="text-align: justify; text-indent: 15px;">''Una laboranti poterit {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uccurrere luna.''<br /><p style="text-align: justify; text-indent: 15px;">Elle {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eule au be{{Info|ſ|forme ancienne longue de la lettre s minuscule}}oin décharmeroit la lune.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Nicias_LPdS_back|<span id="Nicias_LPdS"><sup>13</sup></span>]] C’étoit un Général Athénien, qui fut malheureux dans pre{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que toutes {{Info|ſ|forme ancienne longue de la lettre s minuscule}}es expéditions. Les Athéniens finirent par le condamner à mort. Il étoit contemporain d’[[w:Alcibiade|Alcibiade]] & de [[w:Lamachos|Lamachus]], & leur collegue dans le commandement. Voyez {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur le fait dont parle ici Pline, Quintilien, l. I. ch. 10, & Plutarque à l’article Nicias.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Honneur_LPdS_back|<span id="Honneur_LPdS"><sup>14</sup></span>]] Au lieu de ''macte ingenio'', le Pere Hardouin lit ''macti'' ; mais {{Info|ſ|forme ancienne longue de la lettre s minuscule}}elon les meilleurs Latini{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tes ''macte'' e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t indéclinable, ou pour mieux dire, c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t un adverbe qui répond au ''bravò'' des Italiens. Fe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tus prétend que ''macte'' e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t un compo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}é de ''magis auctus''.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Esprits_LPdS_back|<span id="Esprits_LPdS"><sup>15</sup></span>]] Cette apo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}trophe de Pline aux A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tronomes rappelle ces beaux Vers d'Ovide {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur le même {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ujet :<br />Felices animos quibus hæc cogno{{Info|ſ|forme ancienne longue de la lettre s minuscule}}cere primise<br /><p style="text-align: justify; text-indent: 15px;">Inque Domos {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uperas {{Info|ſ|forme ancienne longue de la lettre s minuscule}}candere cura fuit!<br />Credibile e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t illos pariter vitli{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que joci{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que<br /><p style="text-align: justify; text-indent: 15px;">Altius humanis ex{{Info|ſ|forme ancienne longue de la lettre s minuscule}}eruifle caput,<br />Non Venus aut Vinum {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ublimia pectora fregit<br /><p style="text-align: justify; text-indent: 15px;">Officiumve {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ori, militiæve labor :<br />Nec levis ambitio, perfu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}aque gloria fuco,<br /><p style="text-align: justify; text-indent: 15px;">Magnarumve fames {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ollicitavit opum.<br />Admovere oculis di{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tantia {{Info|ſ|forme ancienne longue de la lettre s minuscule}}idera no{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tris,<br /><p style="text-align: justify; text-indent: 15px;">Ætheraque ingenio {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uppo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}uere {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uo.<br />Sic petitur cœlum: non ut ferat O{{Info|ſ|forme ancienne longue de la lettre s minuscule}}lan Olympus<br /><p style="text-align: justify; text-indent: 15px;">Summaque Peliacus {{Info|ſ|forme ancienne longue de la lettre s minuscule}}idera tangat apex, &c.<br /><p style="text-align: right; text-indent: 15px;">Ovid. {{Info|ſ|forme ancienne longue de la lettre s minuscule}}a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t. l. I.''' </td> </tr> </table><br/><br/></div> {{Boîte déroulante fin}} <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=UnhluychtF8C&newbks=1&newbks_redir=0&dq=Histoire%20naturelle%20Pline&hl=fr&pg=PP7#v=onepage&q&f=true <u>Histoire Naturelle de Pline. Tome Premier</u>], [https://books.google.fr/books?id=UnhluychtF8C&newbks=1&newbks_redir=0&dq=Histoire%20naturelle%20Pline&hl=fr&pg=RA1-PA3#v=onepage&q&f=true ''Livre Second.''], [https://books.google.fr/books?id=UnhluychtF8C&newbks=1&newbks_redir=0&dq=Histoire%20naturelle%20Pline&hl=fr&pg=RA1-PA59#v=onepage&q&f=true ''Des inventions astronomiques, & de leurs Auteurs.''], traduction en françois, avec le texte latin rétabli d’après les meilleures leçons manu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}crites ; accompagnée de Notes critiques pour l’éclairci{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ement du texte, & d’Ob{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ervations {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur les connoi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ances des Anciens comparées avec les découvertes des Modernes, par M. [[w:Louis_Poinsinet_de_Sivry|Louis Poinsinet de Sivry]], Chez la veuve Desaint, Paris, 1771</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div> </div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ==== Livre XVIII ==== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Enquête sur l’agriculture</div> ===== <div style="text-align: center;">Chapitre LVII.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage d’une théorie astronomique de '''Thalès''', du [[w:Lever_héliaque|''coucher matinal'']] des [[w:Pléiades_(astronomie)|''Pléiades'']] 25 jours après l’[[w:Équinoxe_de_septembre|''équinoxe d’automne'']].</div> :'''Texte latin''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''LVII.''' Primum omnium dierum ipsorum anni solisque motus prope inexplicabilis ratio est. Ad CCCLXV adjiciunt etiamnum intercalarios diei noctisque quadrantes. Ita fit, ut tradi non possint certa siderum tempora. Accedit confessa rerum obscuritas, nunc præcurrenle, nec paucis diebus, tempestatum significatu, quod προϰειμασιν Græci vocant : nunc postveniente, quod ἐπιϰεἰμασιν : et plerumque alias citius, alias tardius cæli effectu ad terram deciduo : vulgo serenitate reddita, confectum sidus audimus. Præterea quum omnia hæc statis sideribus cæloque affixis constent, interveniunt motu stellarum grandines, imbres, et ipsi non levi effectu, ut docuimus, turbantque conceptæ spei ordinem. ldque ne nobis tantum putemus accidere, et reliqua fallit animalia sagaciora circa hoc, ut quo vita eorum constet : æstivasque alites præposteri aut præproperi rigores necant, hibernas æstus. Ideo '''Virgilius''' errantium quoque siderum rationem ediscendam præcipit, admonens observandum frigidæ Saturni stellæ transitum. Sunt qui certissimum veris indicium arbitrentur ob infirmitatem animalis, papilionis proventum. Id eo ipso anno, quum commentaremur hæc, notatum est, proventum eorum ter repetito frigore exstinctum, advenasque volucres a. d. VI kalendas februarii spem veris attulisse, mox sævissima hieme conflictatas. Res anceps : primum omnium a cælo peti legem : deinde eam argumentis esse quærendam. Super omnia est mundi convexitas, terrarumque globi differentia, eodem sidere alio tempore aliis aperiente se gentibus : quo fit ut causa ejus non lisdem diebus ubique valeat. Addidere difficultatem et auclores diversis in locis observando, mox etiam in iisdem diversa prodendo. Très autem fuere sectæ : ''Chaldæa'', ''Ægyptia'', ''Græca''. His addidit apud nos quartam Cæsar dictator, annos ad solis cursum redigens singulos, '''Sosigene''' perito scientiæ ejus adhibito. Et ea ipsa ratio postea comperto errore correcta est : ita ut XII annis continuis non intercalaretur, quia cœperat sidera annus morari, qui prius antecedebat. Et '''Sosigenes''' ipse trinis commentationibus, quanquam diligentior cæteris, non cessavit tamen addubitare, ipse semet corrigendo. Auctores prodidere ea, quos prætexuimus volumini huic, raro ullius sententia cum alio congruente. Minus hoc in reliquis mirum, quos diversi excusaverint tractus. Eorum qui in eadem regione dissedere, unam discordiam ponemus exempli gratia : occasum matutinum Vergiliarum '''Hesiodus''' (nam hujus quoque nomine exstat Astrologia) tradidit fieri, quum æquinoctium autumni conficeretur, '''Thales''' vigesimo quinto die ab æquinoctio, '''Anaximander''' vigesimo nono, '''Euctemon''' XLVIII. Nos sequemur observationem Cæsaris : maximeque hæc erit ''Italiæ'' ratio. Dicemus tamen et aliorum placita : quoniam non unius terræ, sed totius naturæ interpretes sumus, non auctoribus positis (id enim verbosum est), sed regionibus : legentes tantum meminerint, brevitatis gratia, quum ''Altica'' nominata fuerit, simul intelligere ''Cycladas'' insulas ; quum ''Macedonia'', ''Magnesiam'', ''Thraciam'' ; quum ''Ægyptus'', ''Phœnicen'', ''Cyprum'', ''Ciliciam'' ; quum ''Bœotia'', ''Locridem'', ''Phocidem'', et finitimos semper tractus ; quum ''Hellespontus'', ''Cherronesum'', et continentia usque ''Atho'' montem ; quum ''Ionia'', ''Asiam'', et insulas ''Asiæ'' ; quum ''Peloponnesus'', ''Achaiam'', et ad ''Hesperum'' jacentes terras. ''Chaldæi Assyriam'' et ''Babyloniam'' demonstrabunt. ''Africam'', ''Hispanias'', ''Gallias'' sileri non erit mirum. Nemo enim observavit in iis, qui siderum proderet exortus. Non tamen difficili ratione dignoscentur in illis quoque terris digestione circulorum, quam in sexto volumine fecimus : qua cognatio cæli, non gentium modo, verum urbium quoque singularum intelligitur, nota ex his terris, quas nominavimus, sumta convexitate circuli, pertinentis ad quas quisque quæret terras, et ad earum siderum exortus, per omnium circulorum pares umbras. Indicandum et illud, tempestates ipsas ardores suos habere quadrinis annis : et easdem non magna differentia reverti ratione solis : octonis vero augeri easdem, centesima revolvente se luna.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/b24875958_0001/page/n7/mode/2up <u>Histoire Naturelle de Pline.</u>], [https://archive.org/details/b24875958_0001/page/652/mode/2up ''Livre XVIII.''], [https://archive.org/details/b24875958_0001/page/684/mode/2up ''Chap. LVII.''], texte corrigé par [[w:Émile_Littré|M. É. Littré]], à partir de celui de [[w:Jean_Hardouin|Hardouin]], Librairie de Firmin-Didot et C<sup>ie</sup>, Paris, 1883<br />(également disponible une édition de 1831 [https://gallica.bnf.fr/ark:/12148/bpt6k5804072n/f339.item ici] et de 1848 [[s:Page:Pline_l'ancien_-_Histoire_naturelle,_Littré,_T1_-_1848.djvu/708|là]])</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''LVII.''' Avant tout, le calcul des jours même de l’année et du mouvement solaire est d’une difficulté presque insurmontable. Aux trois cent soixante-cinq jours on ajoute des jours intercalaires, produits de quarts de jour et de nuit ; de là vient qu’on ne peut indiquer des époques fixes pour les astres. Ajoutez une obscurité des choses avouée de tous : tantôt en effet la mauvaise saison, s’annonçant, anticipe même de plusieurs jours, ce que les Grecs appellent προϰεἰμασις (avant-hiver), et la belle saison retarde, ce qui est nommé ἐπιϰεἰμασις (arriere-hiver) : l’effet du ciel tombe sur la terre tantôt plus vite, tantôt plus tardivement ; et d’ordinaire c’est quand la sérénité est rétablie que nous entendons dire que l’action de l’astre est accomplie. En outre, car tous ces phénomènes dépendent d’astres réglés et fixés au ciel, le mouvement des étoiles amène intercurremment des grêles, des pluies qui ne sont pas non plus d’une faible action, comme nous l’avons enseigné (XVII, 2), et qui troublent l’ordre espéré. Et ne pensons pas que ces méprises n’arrivent qu’à nous; les autres animaux s’y trompent, bien que plus sagaces que nous sur ce point, vu que leur vie en dépend : l’on voit les oiseaux d’été tués par des froids hâtifs ou tardifs, et les oiseaux d’hiver par des chaleurs hâtives ou tardives. Aussi [[w:Virgile|'''Virgile''']] [[#Virgile|<span id="Virgile_back"><sup>'''I'''</sup></span>]] ([[w:Géorgiques|''Georg.'']], I, 335) recommande-t-il d’étudier encore le cours des astres errants, avertissant d’observer le passage de Saturne, planète froide. Il en est qui regardent comme l’indice le plus sûr du printemps l’apparition des papillons, à cause de la délicatesse de cet insecte. Or, l’année même où nous écrivions ceci (an 830 de ''Rome''), il a été noté que les papillons, ayant éclos, furent détruits à trois reprises par le froid, et que les oiseaux étrangers, ayant apporté l’espérance du printemps avant le 6 des calendes de février (27 janvier), eurent bientôt après à essuyer un hiver très-rigoureux. La double difficulté est d’abord d’avoir à demander au ciel la règle de toute chose, puis d’être obligé de contrôler cette règle par des faits apparents. Avant tout signalons la convexité du monde et les différences du globe terrestre, qui font que le même astre se montre à des temps divers suivant les nations, de sorte que l’influence ne s’en fait pas sentir partout aux mêmes jours. La difficulté a été encore accrue par les auteurs qui ont observé en des lieux différents, ou même qui, ayant observé dans les mêmes lieux, ont publié des résultats divergents. Il y a eu trois écoles, la ''Chaldéenne'', l’Égyptienne, la ''Grecque''. Une quatrième a été formée chez nous par le dictateur [[w:Jules_César|'''César''']], qui ramena l’année à la révolution solaire avec l’aide de [[w:Sosigène_d'Alexandrie|'''Sosigène''']] [[#Sosigène|<span id="Sosigène_back"><sup>'''II'''</sup></span>]], astronome habile. Et ce calcul même, où l’on découvrit une erreur, a été corrigé : pendant douze années consécutives on ne fit pas d’intercalation, attendu que l’année, qui auparavant anticipait, maintenant retardait sur les astres. '''Sosigène''' lui-même, quoique plus exact que les autres, n’a pas cessé, dans trois mémoires, de témoigner de ses doutes en se corrigeant lui-même. Les auteurs que nous avons indiqués au commencement de ce livre [[#auteurs_JH|<span id="auteurs_JH_back"><sup>'''1'''</sup></span>]] ont révélé ces discordances, l’avis de l’un s’accordant rarement avec l’avis de l’autre. Cela est moins étonnant dans ceux qui s’excuseront par la différence des lieux. Parmi ceux qui dans le même pays sont en désaccord, nous choisirons un exemple de dissidence : [[w:Hésiode|'''Hésiode''']] [[#Hésiode|<span id="Hésiode_back"><sup>'''III'''</sup></span>]] (car nous avons aussi sous son nom un livre sur les astres) a rapporté que le [[w:Lever_héliaque|''coucher matinal'']] des [[w:Pléiades_(astronomie)|''Pléiades'']] se faisait au moment de l’[[w:Équinoxe_de_septembre|''équinoxe d’automne'']] ; '''Thalès''', qu’il se faisait vingt-cinq jours après cet équinoxe; [[w:Anaximandre|'''Anaximandre''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Anaximandre_back|<sup>🔄</sup>]], vingt-neuf; [[w:Euctémon|'''Euctémon''']] [[#Euctémon|<span id="Euctémon_back"><sup>'''IV'''</sup></span>]], quarante-huit. Quant à nous, nous suivrons les calculs de '''César''' : ils se rapportent spécialement à l’Italie. Toutefois, nous relaterons aussi les opinions des autres ; car nous sommes les interprètes, non d’un seul pays, mais de la nature entière. Nous nommerons, non pas les auteurs, ce qui serait trop long, mais les pays. Les lecteurs auront seulement à se souvenir que, pour abréger, sous le nom d’[[w:Attique|''Attique'']] nous entendons aussi les [[w:Cyclades|''Cyclades'']]; sous celui de [[w:Macédoine_(province_romaine)|''Macédoine'']], la [[w:Magnésie_antique|''Magnésie'']] et la [[w:Thrace_(province_romaine)|''Thrace'']]; sous celui d’[[w:Égypte_romaine_et_byzantine|''Égypte'']], la [[w:Syrie-Phénicie_(province_romaine)|''Phénicie'']], [[w:Chypre_(province_romaine)|''Chypre'']] et la [[w:Cilicie|''Cilicie'']]; sous celui de [[w:Béotie#Antiquité|''Béotie'']], la [[w:Locride_(Grèce)|''Locride'']], la [[w:Phocide#Antiquité_et_période_byzantine|''Phocide'']] et les contrées limitrophes ; sous celui d’[[w:Hellespontique|''Hellespont'']], la [[w:Chersonèse_(cité_grecque)|''Chersonèse'']] et le continent jusqu’au [[w:Mont_Athos|''mont Athos'']]; sous celui d’[[w:Ionie|''Ionie'']], l’Asie et les îles ''Asiatiques'' ; sous celui de [[w:Péloponnèse#Antiquité|''Péloponnèse'']], l’[[w:Achaïe|''Achaïe'']] et les terres situées à l’occident; la [[w:Chaldée|''Chaldée'']] indiquera la [[w:Histoire_de_la_Syrie#Antiquité|''Syrie'']] et la [[w:Babylone_(civilisation)|''Babylonie'']]. On ne s’étonnera pas que je passe sous silence l’[[w:Afrique_romaine|''Afrique'']], l’[[w:Hispanie_romaine|''Espagne'']] et les [[w:Gaule|''Gaules'']], car personne dans ces contrées n’a laissé d’observations sur le lever des astres. Toutefois, il ne sera pas difficile de le calculer, même dans ces contrées, en étudiant la disposition des cercles que nous avons présentés dans le sixième livre (VI, 39). Grâce à cette étude, on connaît les relations astronomiques nou-seulement des nations, mais encore des villes en particulier : étant donnés les cercles déterminés par l’égalité des ombres, on choisit, dans les terres que nous avons nommées, le cercle qui a rapport à la localité objet du problème, et qui détermine en même temps le lever des astres pour cette localité. Il faut encore remarquer (II, 48) que tous les quatre ans les saisons ont leurs excès, et qu’elles reviennent les mêmes sans grande différence, en raison du soleil ; mais que tous les huit ans elles ont un redoublement, à la révolution de la centième lune.</div> <table cellspacing=15 align=center style="margin: 0 4em; font-size:85%;"> <tr> <td style="text-align: justify; margin: 0 4em;">'''[[#auteurs_JH_back|<span id="auteurs_JH"><sup>1</sup></span>]] Ce passage porte à croire que les auteurs dont Pline s’était servi pour composer chacun des livres de son ouvrage avaient été placés en tête du livre auquel ils se rapportaient. Les éditions mettent cette liste d’auteurs à la suite de la table de chaque livre, dans la table générale dressée par Pline lui-même.'''</td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/b24875958_0001/page/n7/mode/2up <u>Histoire Naturelle de Pline.</u>], [https://archive.org/details/b24875958_0001/page/652/mode/2up ''Livre XVIII.''], [https://archive.org/details/b24875958_0001/page/684/mode/2up ''Chap. LVII.''], texte corrigé par [[w:Émile_Littré|M. É. Littré]], à partir de celui de [[w:Jean_Hardouin|Hardouin]] [https://archive.org/details/b24875958_0001/page/708/mode/2up <sup>NOTES</sup>], Librairie de Firmin-Didot et C<sup>ie</sup>, Paris, 1883<br />(également disponible une édition 1848 [[s:Page:Pline_l'ancien_-_Histoire_naturelle,_Littré,_T1_-_1848.djvu/708|ici]])</div> {{Boîte déroulante début|titre=NdA de trad. Jean Hardouin 1883|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Virgile_back|<span id="Virgile"><sup>I</sup></span>]] [[w:Nom_romain|Tria Nomina]] en latin {{Info|Publius|praenomen, nom individuel du citoyen romain}} {{Info|Vergilius|nomen, nom de famille}} {{Info|Maro|cognomen, surnom héréditaire, servant à distinguer les diverses branches d’une même gens}};<br /><p style="margin: 0 2em; text-indent: 15px">Poète latin renommé dans les styles [[w:Épopée|''épique'']] (l’[[w:Énéide|''Énéide'']]), [[w:Poésie_pastorale|''pastorale'']] (les [[w:Bucoliques|''Bucoliques'']]) et [[w:Poésie_didactique|''didactique'']] (les [[w:Géorgiques|''Géorgiques'']]).<br /><p style="text-align: right; margin: 0 2em;">(15 octobre [[w:Années_70_av._J.-C.|-70]], [[w:Virgilio_(Lombardie)#Histoire|''Andes'']], au sud-est de l’actuelle [[w:Lombardie#Histoire|''Lombardie'']], au nord de l’Italie — 21 septembre [[w:Années_19_av._J.-C.|-19]], [[w:Brindisi#Histoire|''Brundisium'']], au sud-est des actuelles [[w:Pouilles#Domination_romaine|''Pouilles'']], au sud-est de l’Italie)<sup>[[w:Ier_siècle_av._J.-C.|⏳]]</sup> <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Sosigène_back|<span id="Sosigène"><sup>II</sup></span>]] Du nom propre grec ancien Σωσῐγένης / Sōsigénēs [[wikt:en:Σωσιγένης#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;">➥ du verbe σῴζω / sṓizō, « 1. Sauver : • Guérir ; • (rare chez Homère) Garder en sécurité, préserver ; • Garder, observer, maintenir ; • (généralement au milieu) Garder à l’esprit, se souvenir ; • Conduire en toute sécurité (à) ; • Secourir ; • Conserver pour. »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ + du nom commun‎ γένος / génos [[wikt:en:γένος#Ancient_Greek|(en)]], « 1. Race, souche, parenté : Descendance directe, par opposition à une relation collatérale. 2. Progéniture, descendant : (collectif) progéniture, postérité. 3. (en général) Race d’êtres : • Famille, clan, maison ; • Tribu, nation, race, en tant que subdivision de ἔθνος / éthnos [[wikt:en:ἔθνος#Ancient_Greek|(en)]] ; • Caste ; • Race d’animaux. 4. Âge, génération, période de la vie. 5. Sexe, genre : (grammaire) Genre grammatical. 6. Classe, sorte, genre : • (logique) L’opposé de εἶδος / eîdos [[wikt:en:εἶδος#Ancient_Greek|(en)]] ; • (taxonomie) Classe : • (taxonomie) Genre ; • Espèce de plante ; culture, produit ; matériau ; • Élément. »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ +‎ du suffixe nominal propre -ης / -ēs [[wikt:en:-ης#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;"> Astronome grec, connu pour avoir participer à la conception du [[w:Calendrier_julien|''calendrier julien'']] (instauré par Jules César en [[w:Années_46_av._J.-C.|-46]]/[[w:Années_45_av._J.-C.|-45]], lorsqu’il était [[w:Pontifex_maximus|''pontifex maximus'']]), avec une année commune de 365 jours divisée en 12 mois, et un jour intercalaire ajouté tous les 4 ans, lors des années bissextiles.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:Ier_siècle_av._J.-C.|I<sup>er</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]]) <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Hésiode_back|<span id="Hésiode"><sup>III</sup></span>]] Du nom propre grec ancien Ἡσῐ́οδος / Hēsíodos;<br /><p style="margin: 0 2em; text-indent: 15px">Poète ''grec'', renommé pour 2 ouvrages :<br /><p style="margin: 0 2em; text-indent: 15px;">• [[w:Théogonie_(Hésiode)|''la Théogonie'']], une généalogie des dieux (dans laquelle il présente la multitude des dieux célébrés par les mythes grecs où trois générations divines se succèdent : celle d’Ouranos, celle de Cronos, celle de Zeus qui sort triomphant) et une cosmogonie (qui retrace la création du monde à partir du Chaos) ;<br /><p style="margin: 0 2em; text-indent: 15px;">• et [[w:Les_Travaux_et_les_Jours|''les Travaux et les Jours'']], un almanac sur l’agriculture à destination de son frère Perses.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:VIIIe_siècle_av._J.-C.|VIII<sup>ème</sup>]] — [[w:VIIe_siècle_av._J.-C.|VII<sup>ème</sup>]] siècles {{Info|AEC|Avant l’Ère Commune}}) <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Euctémon_back|<span id="Euctémon"><sup>IV</sup></span>]] Du nom propre grec ancien Ευκτήμων / Euktémōn;<br /><p style="margin: 0 2em; text-indent: 15px;">Astronome ''athénien'', contemporain et collègue de l’astronome [[w:Méton|Méton]], avec qui, il a fait une série d’observations des [[w:Solstice|''solstices'']] afin de déterminer la durée de l’[[w:Année_tropique|''année tropique'']] [https://ecliptiqc.ca/Almageste_Livre3.php#III1 <sup>Ptolémée, Almageste, liv. III, chap. 1</sup>].<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:Ve_siècle_av._J.-C.|V<sup>ème</sup>]] siècle {{Info|AEC|Avant l’Ère Commune}})'''<br/><br/></div> {{Boîte déroulante fin}} <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: center; margin: 0 2em;">Des découvertes astronomiques : part de chaque observateur dans la science.<br /><p style="text-align: justify; text-indent: 15px;">'''LVII.''' D’abord, il est presque impossible de déterminer d’une manière précise le nombre des jours de l’année et le cours du soleil [[#Primum_omnium_dierum_AdG|<span id="Primum_omnium_dierum_AdG_back"><sup>'''1'''</sup></span>]]. Aux trois cent soixante-cinq jours qui composent l’année, on ajoute le quart d’un jour et d’une nuit, pour en faire ensuite un jour intercalaire ; de là il suit qu’on ne saurait indiquer avec précision le moment du lever et du coucher des astres. On convient qu’il y a encore dans cette théorie beaucoup d’obscurité ; en effet, les saisons quelquefois commencent plusieurs jours avant le terme qui leur a été fixé, ce que les ''Grecs'' appellent ''procheimasis'' ; d’autres fois, plusieurs jours après, ce qu’ils appellent ''épicheimasis'' [[#Accedit_confessa_rerum_obscuritas_AdG|<span id="Accedit_confessa_rerum_obscuritas_AdG_back"><sup>'''2'''</sup></span>]]. Presque toujours l’action des astres se fait sentir sur la terre ou plus tôt ou plus tard qu’il ne devrait ; aussi dit-on communément, lorsque le beau temps est revenu, que tel astre a produit son effet. Ces phénomènes dépendent des astres fixés à la voûte des cieux, ainsi que des étoiles, dont les mouvemens particuliers excitent des grêles et des pluies qui sont d’une très-grande conséquence pour les biens de la terre, comme nous l’avons observé, et amènent dans la température des changemens sur lesquels le laboureur ne pouvait compter. Non-seulement les hommes y sont trompés, mais aussi les animaux, bien plus habiles que nous à prévoir ces vicissitudes, puisque d’ailleurs leur vie en dépend ; en effet, on a vu des oiseaux d’été périr par des froids arrivés trop tôt ou trop tard, et des oiseaux d’hiver par des chaleurs également imprévues. Aussi '''Virgile''' veut-il qu’on étudie aussi le cours des ''planètes'', et qu’on observe avec soin le passage du froid ''Saturne'' [[#Ideo_Virgilius_errantium_quoque_siderum_rationem_ediscendam_prœcipit_AdG|<span id="Ideo_Virgilius_errantium_quoque_siderum_rationem_ediscendam_prœcipit_AdG_back"><sup>'''3'''</sup></span>]].<br /><p style="text-align: justify; text-indent: 15px;">Quelques-uns fixent le commencement du printemps à l’apparition des papillons, parce que ces insectes sont fort délicats. Néanmoins on a observé, dans l’année même où j’écris cette partie de mon ouvrage, que le froid, ayant repris trois fois, a fait périr autant de fois les papillons, et que les hirondelles qui, s’étaient montrées dès le 6 des [[w:Calendes|''kalendes'']] de février, et semblaient annoncer le retour du printemps, ont eu à essuyer un rigoureux hiver.<br /><p style="text-align: justify; text-indent: 15px;">C’est donc une science très-problématique que celle de l’influence des astres, et les inductions qu’elle fournit sont fort douteuses [[#Res_anceps_AdG|<span id="Res_anceps_AdG_back"><sup>'''4'''</sup></span>]]. Ce qui augmente la difficulté, c’est la convexité du ciel et la différence des climats de la terre : le même astre se montre ici dans un temps, et là dans un autre ; d’où il suit que son influence ne se fait pas sentir en même temps partout. Pour surcroît d’embarras, les observations recueillies par les auteurs ont été faites dans des lieux différens, et ceux du même pays ne s’accordent pas même entre eux. On compte trois écoles astronomiques, la ''chaldéenne'', l’égyptienne et la ''grecque''. Le dictateur '''César''' en a fondé, chez les ''Romains'', une quatrième, lorsqu’aidé de '''Sosigène''', habile astronome, il fixa la longueur de l’année à une révolution du soleil. On trouva dans la suite que son calendrier était défectueux, parce que l’année, auparavant plus courte, se trouvait alors plus longue que le cours du soleil. Pour y remédier, il fallut, pour douze années consécutives, supprimer les jours intercalaires. '''Sosigène''' lui-même, le mathématicien le plus exact de son temps, après avoir revu jusqu’à trois fois ses calculs, sembla toujours douter de leur justesse, et ne cessa jamais de se corriger lui-même. De tous les auteurs qui ont traité ce sujet, et que nous avons cités au commencement de ce livre, il en est rarement deux qui soient de même avis. Cette divergence d’opinions est moins surprenante et plus excusable chez ceux qui écrivaient en des pays différens. Mais que dire de ceux qui, habitant le même pays, sont néanmoins d’avis différens ? En voici un exemple : '''Hésiode''', qui nous a laissé aussi un ouvrage sur le cours des astres, fixe le coucher matutinal des ''Pléiades'' au moment de l’équinoxe d’automne ; '''Thales''' prétend qu’il n’arrive que vingt-cinq jours après ; '''Anaximandre''' en met vingt-neuf ; '''Euctémon''', quarante-huit.<br /><p style="text-align: justify; text-indent: 15px;">Quant à nous, nous suivrons les calculs de '''César''', qui se rapportent spécialement à l’Italie ; mais nous rapporterons aussi les observations étrangères, car notre plan n’est pas de traiter d’un seul pays, mais de la nature entière. Pour être moins longs, nous citerons les pays, et non les auteurs ; et, pour abréger davantage encore, les lecteurs se souviendront que, sous le nom d’Attique, il faut aussi entendre les ''Cyclades'' ; sous le nom de ''Macédoine'', la ''Magnésie'' et la ''Thrace'' ; sous le nom d’Égypte , la ''Phénicie'', l’île de ''Cypre'' et la ''Cilicie'' ; sous celui de ''Béotie'', la ''Locride'', la ''Phocide'' et les contrées voisines ; sous le nom d’Hellespont, la ''Chersonèse'' et partie du continent jusqu’au mont ''Athos'' ; sous le nom de l’Ionie, l’Asie et les îles ''Asiatiques'' ; sous le nom du ''Péloponnèse'', l’Achaïe et les pays adjacens au couchant ; enfin sous le nom de ''Chaldée'', l’Assyrie et la ''Babylonie''. On ne sera pas étonné que nous ne parlions ni de l’Afrique, ni de l’Espagne, ni des ''Gaules''. Aucun auteur dans ces contrées n’a laissé d’observations sur le lever ou le coucher des astres. Il ne sera pas difficile néanmoins de déterminer l’époque de ces phénomènes dans ces contrées, en étudiant la disposition des cercles, telle que nous l’avons présentée dans le sixième livre. Par ce moyen, on déterminera la position astronomique, non-seulement de chaque pays, mais encore de chaque ville dont nous avons pu parler, en prenant par les ombres égales de tous les cercles, une portion du cercle de telle contrée qu’on voudra choisir, et en calculant son rapport avec le lever des astres. Il faut faire observer encore que tous les quatre ans les chaleurs reviennent à peu près les mêmes pour chaque saison, en raison du mouvement du soleil, et que toutes les huitièmes années elles sont plus fortes, à cause de la centième lunaison.</div> <table cellspacing=15 align=center style="margin: 0 4em; font-size:85%;"> <tr> <td style="text-align: justify; margin: 0 4em;">'''[[#Primum_omnium_dierum_AdG_back|<span id="Primum_omnium_dierum_AdG"><sup>1</sup></span>]] Cf. sur la plupart des difficultés que le texte de notre auteur révèle, les notes relatives à l’astronomie, au livre II. L’année romaine fut d’abord celle des [[w:Albe_la_Longue|''Albains'']], c’est-à-dire lunaire ; dix mois la composaient, mars en était le premier : elle avait cinquante jours de moins que l’année lunaire réelle, et soixante-un de moins que l’année solaire, c’est-à-dire trois cent quatre jours seulement ; c’était là l’[[w:Calendrier_romain|{{Info|''année de Romulus''|le calendrier dit romuléen}}]]. [[w:Calendrier_romain|{{Info|''Numa''|le calendrier dit pompilien}}]] ajouta deux mois à cette année, janvier et février, et elle se trouva être composée de trois cent cinquante-cinq jours. Elle demeura ainsi jusqu’à Jules César, où commence l’[[w:Calendrier_julien|''année julienne'']], qui se compose de trois cent soixante-cinq jours, huit heures, auxquels [[w:Calendrier_grégorien|''Grégoire le Grand'']] ajouta onze minutes, pour arriver à la plus grande exactitude possible.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Accedit_confessa_rerum_obscuritas_AdG_back|<span id="Accedit_confessa_rerum_obscuritas_AdG"><sup>2</sup></span>]] L’entrée du soleil dans tel ou tel signe du zodiaque, son passage à l’équateur, etc., ne sont pas toujours le signal d’un changement dans la température. [[w:Végèce|Végèce]] a parlé des jours prokéimasiques et épikéiniasiques :''' {{Info|''Aut enim circa diem statutum, aut ante, vel postea, tempestates fieri, compertum est : unde præcedentes, ωροϰεἰμασιν : nascentes die solenni, επιϰεἰμασιν : subsequentes, μεταϰεἰμασιν, græco vocabulo nuncuperaverunt''|Car on a constaté que les tempêtes se produisent soit vers le jour fixé, soit avant, soit après : d’où les précédents, ωροϰεἰμασιν : nés le jour solennel, επιϰεἰμασιν : les suivants, μεταϰεἰμασιν, étaient appelés par le mot grec. TdA.}} '''(IV, 40).''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Ideo_Virgilius_errantium_quoque_siderum_rationem_ediscendam_prœcipit_AdG_back|<span id="Ideo_Virgilius_errantium_quoque_siderum_rationem_ediscendam_prœcipit_AdG"><sup>3</sup></span>]] <p style="margin: 0 6em; text-indent: 0px">'''{{Info|Hoc metuens, cæli menses et sidera serva,<br />Frigida Saturni sese quo stella receptet.|Craignant cela, gardez les lunes et les étoiles du ciel, le froid de Saturne lui-même, où l’étoile les recevra. TdA.}}'''<p style="text-align: right; margin: 0 6em; text-indent: 0px">''Georg.'', I, 335.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Res_anceps_AdG_back|<span id="Res_anceps_AdG"><sup>4</sup></span>]] Voici enfin quelques idées philosophiques qui se trouvent sous la plume de Pline ; malheureusement la cause par laquelle notre auteur explique l’influence des astres est problématique, et montre que les sciences astronomiques des anciens laissaient beaucoup à désirer. Les Grecs croyaient qu’il y avait autant de cieux que de planètes ; le huitième ciel, ou le firmament, était celui dès étoiles fixés.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Occasum_matutinum_Vergiliarum_Hesiodus_AdG_back|<span id="Occasum_matutinum_Vergiliarum_Hesiodus_AdG"><sup>5</sup></span>]] L’ouvrage auquel Pline fait allusion a été mentionné par [[w:Théon_d'Alexandrie|Théon]] qui le nomme Αστριϰὴ βίϐλος [[w:en:Astronomia_(poem)|(en)]]. Cet ouvrage est perdu.'''</td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k5804072n <u>Histoire Naturelle de Pline. Tome Onzième</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k5804072n/f196.item ''Livre XVIII.''], [https://gallica.bnf.fr/ark:/12148/bpt6k5804072n/f340.item ''chap. LVII.''], traduction nouvelle par M. [[w:Stéphane_Ajasson_de_Grandsagne|Ajasson de Grandsagne]] [https://gallica.bnf.fr/ark:/12148/bpt6k5804072n/f453.item <sup>NOTES</sup>], C. L. F. Panckoucke, Paris, 1829</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: center; margin: 0 2em;">''Divi[[w:S_long|{{Info|ſ|forme ancienne longue de la lettre s minuscule}}]]<nowiki />ion des jours & des nuits [[w:S_long|{{Info|ſ|forme ancienne longue de la lettre s minuscule}}]]<nowiki />uivant le cours du Soleil ; lever & coucher des étoiles ; ordre des [[w:S_long|{{Info|ſ|forme ancienne longue de la lettre s minuscule}}]]<nowiki />ai[[w:S_long|{{Info|ſ|forme ancienne longue de la lettre s minuscule}}]]<nowiki />ons ; tems où l’on [[w:S_long|{{Info|ſ|forme ancienne longue de la lettre s minuscule}}]]<nowiki />eme les bleds d’hiver.''<br /><p style="text-align: justify; text-indent: 15px;">'''D'''’ABORD il e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t pre{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que impo{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ible de déterminer au ju{{Info|ſ|forme ancienne longue de la lettre s minuscule}}te le nombre des jours de l’année, & le cours du Soleil ; car comme aux trois cents {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oixante & cinq jours dont l’année e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t compo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ée, on ajoute le quart d’un jour & d’une nuit, autrement {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ix heures, qui, au bout de quatre ans, font un jour intercalaire [[#jour_intercalaire_LPdS|<span id="jour_intercalaire_LPdS_back"><sup>'''1'''</sup></span>]], il arrive qu’on ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}auroit a{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}igner avec certitude le tems du lever & du coucher des a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tres. En {{Info|ſ|forme ancienne longue de la lettre s minuscule}}econd lieu, l’on convient qu’il y a dans cette théorie beaucoup d’ob{{Info|ſ|forme ancienne longue de la lettre s minuscule}}curité ; car quelquefois les {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ons [[#quelques_les_saisons_LPdS|<span id="quelques_les_saisons_LPdS_back"><sup>'''2'''</sup></span>]] commencent plu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ieurs jours avant le terme qui leur a été fixé, ce que les Grecs appellent ''prokheïma{{Info|ſ|forme ancienne longue de la lettre s minuscule}}is'' ; & d’autres fois plu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ieurs jours après, ce que ces mêmes Grecs expriment par le mot ''epikheïma{{Info|ſ|forme ancienne longue de la lettre s minuscule}}is'' : & l’on éprouve très {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ouvent que l’action des a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tres {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ait {{Info|ſ|forme ancienne longue de la lettre s minuscule}}entir {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur la terre, tantôt plutôt, tantôt plus tard. Au{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}i dit-on communément, lor{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que le beau tems e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t revenu, que tel a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tre a produit {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on effet. D’ailleurs comme tout cela dépend des globes céle{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tes, leur mouvement relatif excite quelquefois des grêles & des pluies, qui, comme nous l’avons déja [[#déjà_fait_observer_LPdS|<span id="déjà_fait_observer_LPdS_back"><sup>'''3'''</sup></span>]] fait ob{{Info|ſ|forme ancienne longue de la lettre s minuscule}}erver, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont de la plus grande con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}équence pour les biens de la terre, & qui renver{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ent l’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}pérance qu’on avoit du beau tems. Et non {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eulement les hommes y {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont trompés, mais au{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}i les animaux, quoiqu’ils aient bien plus de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}agacité que nous pour pre{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}entir ces vici{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}itudes du ciel, d’autant que leur vie en dépend. En effet, on voit quelquefois les oi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}eaux d’été mourir par des froids qui viennent trop tard ou trop tôt, & les oi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}eaux d’hiver par des chaleurs qui arrivent de même. C’est pourquoi '''Virgile''' veut qu’on étudie au{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}i le cours des planetes, & qu’on ob{{Info|ſ|forme ancienne longue de la lettre s minuscule}}erve à quelle partie du zodiaque répond la planete du froid Saturne [[#Saturne_LPdS|<span id="Saturne_LPdS_back"><sup>'''4'''</sup></span>]]. Quelques-uns croient que le {{Info|ſ|forme ancienne longue de la lettre s minuscule}}igne le plus certain du printems commencé, c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t lor{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’on voit des papillons, & cela parceque ces in{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ectes {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont fort délicats. Néanmoins on a remarqué que dans l’année même [[#lAnnée_dÉcriture_LPdS|<span id="lAnnée_dÉcriture_LPdS_back"><sup>'''5'''</sup></span>]] où j’écris ceci, le froid ayant recommencé ju{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’à trois fois, a fait mourir autant de fois les papillons ; & que les hirondelles, qui, s’étant montrées dès le vingt-{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ept de Janvier, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}embloient annoncer le retour du printems, ont en{{Info|ſ|forme ancienne longue de la lettre s minuscule}}uite e{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}uyé un très cruel hiver.<br /><p style="text-align: justify; text-indent: 15px;">C’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t donc une {{Info|ſ|forme ancienne longue de la lettre s minuscule}}cience très problématique que celle de l’influence des a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tres, & les inductions que l’on en tire {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont fort douteuses. Mais ce qui cau{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e le plus d’incertitude, c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t cette convexité du ciel & la différence des climats de la terre, parceque le même a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tre {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e montre ici dans un tems, & là dans un autre, d’où il ré{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ulte que {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on influence ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e fait pas {{Info|ſ|forme ancienne longue de la lettre s minuscule}}entir en même tems par-tout. Un autre {{Info|ſ|forme ancienne longue de la lettre s minuscule}}urcroît de difficulté, c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t que les ob{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ervations recueillies par les Auteurs ont été faites en différents lieux, & que ceux même qui ont écrit dans le même endroit ne s’accordent nullement entre eux dans ce qu’ils écrivent. On compte ju{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’à trois différentes {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ortes de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ectes en A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tronomie ; {{Info|ſ|forme ancienne longue de la lettre s minuscule}}avoir, celle des Chaldéens [[#secte_des_Chaldéens_LPdS|<span id="secte_des_Chaldéens_LPdS_back"><sup>'''5*'''</sup></span>]], celle des Egyptiens & celle des Grecs. On peut même dire que le Dictateur Cé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ar [[#Dictateur_César_LPdS|<span id="Dictateur_César_LPdS_back"><sup>'''6'''</sup></span>]] en produi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}it, chez les Romains, une quatrieme, lor{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’il rédui{{Info|ſ|forme ancienne longue de la lettre s minuscule}}it chaque année au cours du {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oleil, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ervant à cet effet du travail de So{{Info|ſ|forme ancienne longue de la lettre s minuscule}}igene, très habile A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tronome. Néanmoins on découvrit en{{Info|ſ|forme ancienne longue de la lettre s minuscule}}uite que le calendrier de Cé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ar étoit défectueux [[#calendrier_César_défectueux_LPdS|<span id="calendrier_César_défectueux_LPdS_back"><sup>'''7'''</sup></span>]], parceque l’année qui auparavant étoit plus courte que le cours du {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oleil, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e trouvoit alors plus longue : & pour corriger cette erreur, on ordonna que pendant douze années de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uite, il n’y auroit point de jour intercalaire [[#correction_erreur_LPdS|<span id="correction_erreur_LPdS_back"><sup>'''8'''</sup></span>]]. So{{Info|ſ|forme ancienne longue de la lettre s minuscule}}igene lui-même, quoique Mathématicien plus exact que les autres, ne lai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}a pas de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e conduire con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tamment en homme qui doutoit de la ju{{Info|ſ|forme ancienne longue de la lettre s minuscule}}te{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}e de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on propre calcul, pui{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’il en fit ju{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’à trois différentes corrections. De tous les Auteurs [[#Auteurs_calendrier_LPdS|<span id="Auteurs_calendrier_LPdS_back"><sup>'''9'''</sup></span>]] qui ont écrit {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur cette matiere, & que nous avons allégués au commencement de ce livre, il s’en trouve rarement deux qui {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oient de même {{Info|ſ|forme ancienne longue de la lettre s minuscule}}entiment. Cette variété e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t moins {{Info|ſ|forme ancienne longue de la lettre s minuscule}}urprenante, comme au{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}i plus excu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}able, chez ceux qui écrivoient en des pays différents. Mais que dire de ceux qui, écrivant dans le même pays, n’ont pas lai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}é d’être partagés d’opinion ? En voici un exemple. '''Hé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iode''', dont il y a au{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}i un ouvrage [[#ouvrage_astronomique_Hésiode_LPdS|<span id="ouvrage_astronomique_Hésiode_LPdS_back"><sup>'''10'''</sup></span>]] {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur le cours des a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tres, dit que les Pléiades {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e couchent le matin dans le tems même de l’équinoxe d’automne. '''Thalès''' [[#opinion_Thalès_Hésiode_Anaximandre_LPdS|<span id="opinion_Thalès_Hésiode_Anaximandre_LPdS_back"><sup>'''11'''</sup></span>]] dit que cela arrive vingt-cinq jours après. '''Anaximandre''' en met vingt-neuf ; '''Euctémon''' [[#Euctémon_LPdS|<span id="Euctémon_LPdS_back"><sup>'''12'''</sup></span>]] quarante-huit.<br /><p style="text-align: justify; text-indent: 15px;">Quant à nous, nous {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uivrons le calcul de Cé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ar, ayant principalement égard à l’Italie. Nous ne lai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}erons néanmoins de rapporter les opinions étrangeres, parceque notre objet n’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t pas de traiter d’un {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eul pays, mais de la Nature entiere. Seulement, pour éviter les longueurs, nous n’indiquerons que les pays où chaque opinion a lieu, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ans faire mention des auteurs de ces a{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ertions : & pour abréger encore davantage, les Lecteurs voudront bien {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ouvenir que quand il e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t parlé de l’Attique, il faut, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous ce nom, entendre au{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}i les Cyclades ; que {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous le nom de Macédoine, il faut entendre au{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}i la Magné{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ie & la Thrace ; {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous le nom de l’Egypte, la Phénicie, l’i{{Info|ſ|forme ancienne longue de la lettre s minuscule}}le de Chypre & la Cilicie; {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous celui de la Béotie, la Locride, la Phocide & les contrées voi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ines ; {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous le nom de l’Hel le{{Info|ſ|forme ancienne longue de la lettre s minuscule}}pont, la pre{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’i{{Info|ſ|forme ancienne longue de la lettre s minuscule}}le de Thrace & le pays de terre ferme, ju{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’au mont Athos ; {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous le nom de l’Ionie, l’A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ie & les i{{Info|ſ|forme ancienne longue de la lettre s minuscule}}les A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iatiques ; {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous le nom du Péloponne{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e, l’Achaïe & les contrées [[#contrées_adjacentes_ouest_Péloponnese_LPdS|<span id="contrées_adjacentes_ouest_Péloponnese_LPdS_back"><sup>'''13'''</sup></span>]] adjacentes qu’elle a à {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on couchant ; {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous le nom des Chaldéens, l’Assyrie & la Babylonie. Il ne faudra pas s’étonner {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i je ne parle ici ni de l’Afrique, ni de l’Espagne, ni des Gaules, pui{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que ces pays n’ont eu aucun Auteur qui ait écrit du cours des a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tres, ni de leur lever. Toutefois il ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}era pas difficile de connoître le tems où ils {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e levent dans ces pays-là même, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i l’on e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t in{{Info|ſ|forme ancienne longue de la lettre s minuscule}}truit de l’arrangement des cercles céle{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tes, tel que nous l’avons expliqué au {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ixieme livre de cet ouvrage ; car, par ce moyen, & par les {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eules notions que nous avons expo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ées en donnant une nomenclature des lieux, on {{Info|ſ|forme ancienne longue de la lettre s minuscule}}aura la po{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ition, non {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eulement de chaque pays, mais encore de chaque ville, en prenant par les ombres égales de tous les cercles, un {{Info|ſ|forme ancienne longue de la lettre s minuscule}}egment du cercle de tel pays qu’on voudra choi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ir, & en cherchant {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on rapport avec le lever des a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tres. Il faut remarquer au{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}i que de quatre [[#Columelle_LPdS|<span id="Columelle_LPdS_back"><sup>'''14'''</sup></span>]] en quatre ans les {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ons & les chaleurs reviennent à peu près les mêmes, & cela à cau{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e du mouvement du Soleil ; & que de huit en huit ans ces mêmes chaleurs reviennent plus con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}idérables, en vertu de la centieme lunai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}on.</div> {{Boîte déroulante début|titre=Notes du traducteur|alignT=center}} <div style="text-align: justify; border: 2px; border-radius:15px; font-size:85%;"><br/> <table cellspacing=15 align=center style="margin: 0 4em;"> <tr> <td style="text-align: justify; margin: 0 4em; text-indent: 15px">'''[[#jour_intercalaire_LPdS_back|<span id="jour_intercalaire_LPdS"><sup>1</sup></span>]] Con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ultez, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur toute cette que{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tion, nos notes 13 & 14 {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur le huitieme chapitre du {{Info|ſ|forme ancienne longue de la lettre s minuscule}}econd livre de Pline, tome 1, p. 41 & 42 :<br /><p style="text-align: justify; text-indent: 15px; margin: 0 5em;">(13) [[w:Suétone|Suétone]] s’exprime mieux, lor{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’il écrit : chaque quatrieme année ''quarto quoque anno''. Il est vrai que, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}elon le [[w:Jean_Hardouin|Pere Hardouin]], il faut comprendre dans la période de cinq ans, dont parle Pline, la premiere & la cinquieme année comme Bi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}extiles ; ce qui revient aux quatre années de Suétone, dont la quatrieme avoit un ''bi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ex'' ; mais en vérité cette explication est des plus forcées. Je {{Info|ſ|forme ancienne longue de la lettre s minuscule}}erois donc d’avis qu’il faudroit lire dans Pline comme dans Suétone, ''quarto anno'', {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i nous n’apprenions d’ailleurs de cet Hi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}torien, que dès le regne d’Augu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}te il s’étoit déja gli{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}é plu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ieurs abus & altérations dans l’année Julienne. On voit du moins qu’il y réforma plu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ieurs cho{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es, sous prétexte de la remettre {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur le pied où Cé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ar l’avoit in{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tituée. Cela me donneroit à pen{{Info|ſ|forme ancienne longue de la lettre s minuscule}}er qu’on fit dès-lors attention à la fau{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}eté & à l’excédence du calcul Julien ; mais qu’Augu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}te, par respect pour la mémoire de Cé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ar, affecta d’imputer la faute à la négligence des Prêtres chargés à Rome de l’in{{Info|ſ|forme ancienne longue de la lettre s minuscule}}pection du Calendrier ; qu’au demeurant, on découvrit l’abus, & qu’on e{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}aya d’y remédier, en n’ajoûtant un jour entier à l’année ordinaire que chaque ''cinquieme année'' comme Pline paroît l’articuler ici expre{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ement. Mais d’ailleurs il e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t évident qu’à la longue le période bi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}extile de quatre années en quatre années prévalut {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur celui de chaque cinquieme année, dont parle Pline ; & même il paroît que ceux qui, par la {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uite, voulurent {{Info|ſ|forme ancienne longue de la lettre s minuscule}}upputer les tems, récapitulerent, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ans exception, toutes les bi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}extiles quartenaires écoulées depuis l’in{{Info|ſ|forme ancienne longue de la lettre s minuscule}}titution Julienne ; car en 1582, on trouva par ce moyen que l’année étoit reculée de dix jours & plus; d’autant que l’excédence du calcul Julien, qui {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uppo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e à l’année révolue 365 jours & {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ix heures, au lieu de 365 jours 5 heures 49 minutes, 8 {{Info|ſ|forme ancienne longue de la lettre s minuscule}}econdes 17 tierces & 13 quarts qu’elle a réellement, forme tous les ans environ 11 minutes de trop, & tous les cent trente-quatre ans un jour entier d’excès. Le Pape Grégoire XIII trouvant donc l’année reculée de plus de dix jours ; ce qui dérangeoit l’économie annuelle des {{Info|ſ|forme ancienne longue de la lettre s minuscule}}olemnités, remédia à cet inconvénient en retranchant de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on autorité dix jours au mois d’Octobre de l’année 1582, où l’on étoit alors ; & en réglant qu’à l’avenir tous les quatre cents ans on omettroit trois années bi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}extiles. Ce réglement devint une loi pour pre{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que toute l’Europe chrétienne. L’autre maniere de compter fut appellée l’ancien {{Info|ſ|forme ancienne longue de la lettre s minuscule}}tyle. La Grande-Bretagne a long-tems per{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i{{Info|ſ|forme ancienne longue de la lettre s minuscule}}té à s’en {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ervir malgré {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on abus manife{{Info|ſ|forme ancienne longue de la lettre s minuscule}}te. Enfin le Parlement d’Angleterre, par acte du mois de Septembre 1752, a adopté la réforme Grégorienne.<br /><p style="text-align: justify; text-indent: 15px; margin: 0 4em;">(14) Le {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oleil, en fai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ant le tour du cercle oblique, parcourt réellement 360 degrés ou {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ections ; pui{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que tout cercle {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e divi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e en 360 parties appellées degrés : mais la me{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ure de chaque degré du cercle parcouru annuellement par le {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oleil, excede tant {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oit peu, c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t-à-dire de quelques légeres fractions de tems, la durée de chacun de nos jours révolus ; durée qui n’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t, comme on {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ait, que de 24 heures préci{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es ; le{{Info|ſ|forme ancienne longue de la lettre s minuscule}}quelles, comparées à un degré, en produi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ent, au bout de l’année, 365 & plus pour le cercle, au lieu de 360 {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eulement que le cercle requerroit. D’après une connoi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ance con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}u{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e de ces principes, Jules Cé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ar {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e voyant Dictateur, Grand-Pontife, & maître du monde, entreprit, l’an 140 avant J. C. de réformer les abus qui s’étoient gli{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}és, tant dans l’année Pompilienne, ou de Numa, que dans celle des Pontifes, encore plus irréguliere que celle de Numa. A cet effet, il fit venir d’Alexandrie le Philo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ophe So{{Info|ſ|forme ancienne longue de la lettre s minuscule}}igenes. Celui-ci décida fau{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ement que le cercle des jours de l’année révolue excédoit du nombres 5 joint au quart de 1 les 360 degrés du cercle oblique parcouru par le {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oleil : expo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}é faux, auquel le Dictateur, occupé d’autres {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oins, déféra {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ans autre examen. Jules Cé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ar régla donc, de l’avis de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tronome, que l’année {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eroit divisée en 365 jours ; & quant au quart de jour re{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tant, qui produit {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ix heures, il ordonna qu’on n’y auroit aucun égard pour chaque année particuliere ; mais que chaque quatrieme année on réuniroit la totalité de quatre fois {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ix heures, qui en font vingt-quatre, pour en compo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}er un jour entier; & qu’ain{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i cette quatrieme année auroit 366 jours. Il régla de plus, que ce jour intercalaire, ou ajoûté à chaque quatrieme année, seroit le 24 Février. Les Romains nommoient ce jour-là ''bis {{Info|ſ|forme ancienne longue de la lettre s minuscule}}exto calendas Martii'', c’est-à-dire, le ''{{Info|ſ|forme ancienne longue de la lettre s minuscule}}econd {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ixieme avant les calendes de Mars'' ; d’où il arriva que l’année où tomboit ce jour intercalaire fut appellée bis-{{Info|ſ|forme ancienne longue de la lettre s minuscule}}extile.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#quelques_les_saisons_LPdS_back|<span id="quelques_les_saisons_LPdS"><sup>2</sup></span>]] Végece dit pareillement, liv. 4, chap. 40 : ''Aut enim circa diem {{Info|ſ|forme ancienne longue de la lettre s minuscule}}tatutum, aut ante, vel po{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tea, tempe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tates fieri compertum e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t : unde præcedentes, ωροϰεἰμασιν : na{{Info|ſ|forme ancienne longue de la lettre s minuscule}}centes die {{Info|ſ|forme ancienne longue de la lettre s minuscule}}olenni, επιϰεἰμασιν : {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ub{{Info|ſ|forme ancienne longue de la lettre s minuscule}}equentes, μεταϰεἰμασιν, Græco vocabulo nuncuperaverunt'' [[#Accedit_confessa_rerum_obscuritas_AdG_back|<sup>⤴️</sup>]]. On lit au{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}i chez [[w:Columelle|Columelle]], dans {{Info|ſ|forme ancienne longue de la lettre s minuscule}}a Préface :''' {{Info|''Neque enim ſemper eumdem, cælum & annus, velut ex præſcripto habitum gerunt : nec omnibus annis eodem vultu venit aſtas, aut hyems, &c.''|Car le ciel et l’année ne portent pas toujours le même habit, comme par un précepte : ni l’automne n’arrive chaque année avec la même apparence, ni l’hiver, etc. TdA}} </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#déjà_fait_observer_LPdS_back|<span id="déjà_fait_observer_LPdS"><sup>3</sup></span>]] Au liv. 17, chap. 2.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Saturne_LPdS_back|<span id="Saturne_LPdS"><sup>4</sup></span>]] Ain{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i qu’il l’in{{Info|ſ|forme ancienne longue de la lettre s minuscule}}inue dans {{Info|ſ|forme ancienne longue de la lettre s minuscule}}es ''Géorg.'' liv. I, v. 335 :'''<br /><p style="margin: 0 6em; text-indent: 0px">{{Info|Hoc metuens, cæli menses et sidera serva,<br />Frigida Saturni sese quo stella receptet.|Craignant cela, gardez les lunes et les étoiles du ciel, le froid de Saturne lui-même, où l’étoile les recevra. TdA.}} </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#lAnnée_dÉcriture_LPdS_back|<span id="lAnnée_dÉcriture_LPdS"><sup>5</sup></span>]] Pline, au quatorzieme livre, chap. 4, comptoit deux cents trente ans depuis la mort de [[w:Cicéron|Cicéron]] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Cicéron_I|<sup>🔄</sup>]], arrivée l’an de Rome 600. L’année qu’il indique ici, & où il {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e trouvoit avoir compo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}é quatre livres de plus, e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t probablement la {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uivante, c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t-à-dire l’année 831 de la fondation de Rome.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#secte_des_Chaldéens_LPdS_back|<span id="secte_des_Chaldéens_LPdS"><sup>5*</sup></span>]] Sur l’année Chaldéenne, qui étoit la même que la Judaïque, con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ultez [[w:Eusèbe_de_Césarée|Eu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ebe]], ''Præpar. Evang.'' liv. 9, chap. 17, où il fait Abraham inventeur de l’a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tronomie chez les Chaldéens. Les A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}trologues Chaldéens étoient ordinairement des Prêtres des Dieux, tels que [[w:Bérose|Béro{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e]], auquel les Athéniens éleverent dans leur Gymna{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e une {{Info|ſ|forme ancienne longue de la lettre s minuscule}}tatue à langue dorée. Sur quoi voyez Pline, liv. 7, chap. 37. Ce Béro{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e étoit un Prêtre de [[w:Bēl|Belus]] ; il e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t cité par [[w:Clément_d'Alexandrie|Clément d’Alexandrie]], & par [[w:Flavius_Josèphe|Jo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}eph]] [[#Flavius_Josèphe_I|<sup>⤵️</sup>]], contre Apion, liv. 1. Sur l’année Egyptienne, & {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur l’ancienne année Grecque, con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ultez [[w:Hérodote|Hérodote]] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Hérodote_I|<sup>🔄</sup>]] liv. 2, n°. 4. Cicéron rend ju{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tice à l’étude que firent des a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tres les Egyptiens & les Babyloniens, liv. 1, de ''Divinat.'' n°. 16 :''' {{Info|''Ægyptii, & Babylonii, in camporum patentium aquoribus habitantes, cùm ex terra nihil emineret, quod contemplationi cæli officere poſſet, omnem curam in ſiderum cognitione poſuerunt''|Les Égyptiens et les Babyloniens, vivant dans les eaux des plaines découvertes, alors que rien ne dépassait de la terre qui pût gêner la contemplation du ciel, mettaient tous leurs soins dans la connaissance des étoiles. TdA}}. </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Dictateur_César_LPdS_back|<span id="Dictateur_César_LPdS"><sup>6</sup></span>]] Voyez les notes 13 & 14 {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur le chap. 8 du liv. 2, tome 1, p. 41 & 42.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#calendrier_César_défectueux_LPdS_back|<span id="calendrier_César_défectueux_LPdS"><sup>7</sup></span>]] Voyez les notes indiquées dans la note précédente ; & joignez-y les ob{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ervations {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uivantes, qui {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont de M. De{{Info|ſ|forme ancienne longue de la lettre s minuscule}}places, p. 339 : « Le calendrier chrétien, ayant {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uivi la réformation de Jules Cé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ar, il {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e trouva qu’en l’année 1582, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous le Pape Grégoire XIII, l’équinoxe étoit remontée ju{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’au 11 de Mars, au lieu du 21, où elle devoit être. Ce Pape, après avoir con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ulté Clavius & Ciaconius, les plus habiles A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tronomes du tems, ordonna qu’en cette même année 1582, on compteroit le 5 du mois d’Octobre, au lieu du 15, afin de retrancher les dix jours qui s’étoient gli{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}és de trop, en {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uivant la {{Info|ſ|forme ancienne longue de la lettre s minuscule}}upputation Julienne, depuis le Concile de Nicée, tenu en 325 : on convint encore de continuer l’intercalation d’un jour tous les quatre ans ; & qu’en outre, pour éviter dans la {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uite pareille erreur, il {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eroit fait un retranchement de trois jours intercalaires, dans l’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}pace de quatre {{Info|ſ|forme ancienne longue de la lettre s minuscule}}iecles, à cau{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e des onze minutes qui manquent aux {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ix heures des années, dont on compo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e l’année intercalaire, ou bi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}extile ; ces trois jours {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e retranchent en l’année qui finit les trois premiers {{Info|ſ|forme ancienne longue de la lettre s minuscule}}iecles. De célebres A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tronomes modernes ont fait voir que, malgré cette précaution, il y auroit encore, au bout de quatre cents ans, plu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ieurs jours de variation dans l’équinoxe ».''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#correction_erreur_LPdS_back|<span id="correction_erreur_LPdS"><sup>8</sup></span>]] Etabli par Jules Cé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ar, & qui revenoit tous les quatre ans. Ecoutons Suétone, vie de ce Dictateur, chap. 40 : {{Info|''Faſtos correxit, jampridem vitio Pontiſicum, per intercalandi licentiam adeo turbatos, ut neque meſſium feria aſtati, neque vindemiarum autumno competerent, annumque ad curſum ſolis accommodevit, ut CCCLXV dierum eſſet, & intercalario menſe ſublato, unus dies quarto quoque anno intercalaretur, &c''|Il corrigea les jeûnes, qui avaient toujours été une faute pontique, si perturbés par la permission de l’intercalation, que ni les fêtes du mois ne tenaient, ni les récoltes ne correspondaient à l’automne, et il ajusta l’année à la course du soleil, de sorte que c’était 365 jours, et après le mois intercalaire, un jour était intercalé tous les quatre ans, etc. TdA}}. On s’apperçut que cette correction de Jules Cé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ar étoit elle-même fautive. On tenta de nouveau de remédier au vice du calendrier ; {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur quoi con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ultez Solin, chapitre 1, p. 5 ; le P. Petau, ''de Doctr. temp.'' chap. 3 ; mais {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur-tout [[w:Macrobe|Macrobe]], qui s’exprime ain{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i, liv. 1, ''Saturn.'' chap. 14, p. 255 :''' {{Info|''Sacerdotes ſibi errorem novum ex ipſa emendatione ſecerunt. Nam cùm oporteret diem, qui ex quadrantibus conſit, quarto quoque anno conſecto, antequam quintus inciperet, intercalare, illi quarto non peracto ſed incipiente, intercalabant. Hic error ſex & triginta annis permanſit : quibus annis intercalati ſunt dies duodecim, cùm deberent intercalari novem. Sed hunc quoque errorem ſerò deprehenſum correxit Auguſtus, qui annos duodecim ſine intercalari die tranſigi juſſit : ut illi tres dies, qui per annos triginta & ſex vitio ſacerdotalis ſeſtinationis excreverant, ſequentibus annis duodecim, nullo die intercalato, devorarentur. Poſt hoc unum diem, ſecundùm ordinationem Caſaris, quinto quoque incipiente anno intercalari juſſit : & omnem hunc ordinem area tabula ad aternam cuſtodiam inciſione mandavit.''|Les prêtres retranchèrent une nouvelle erreur de leur correction. Car lorsqu’il fallait intercaler le jour qui est composé de quadrants, la quatrième année consécutive, avant que la cinquième ne commence, on intercalait ceux lorsque la quatrième n’était pas terminée mais commençait. Cette erreur a duré trente-six ans : années au cours desquelles douze jours ont été intercalés, alors qu’il aurait fallu en intercaler neuf. Mais cette erreur fut également détectée par Auguste, qui ordonna que douze années s’écoulèrent sans jour intercalaire : afin que ces trois jours, qui avaient été excrétés pendant les trente-six années du vice sacerdotal de cessation, soient dévorés dans le douze années suivantes, sans jour intercalaire. Après ce jour, selon l’ordonnance de César, il décréta que la cinquième année serait également intercalée : et tout l’ordre fut ordonné d’être gravé par le conseil du domaine pour la garde éternelle. TdA}}. </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Auteurs_calendrier_LPdS_back|<span id="Auteurs_calendrier_LPdS"><sup>9</sup></span>]] Ces Auteurs {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont Hiéron, Philomêtor, Attale, Archelaüs, Xénophon, Magon, Caton, Silanus, Varron, &c. dont Pline a fait mention {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur la fin du chapitre 3.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#ouvrage_astronomique_Hésiode_LPdS_back|<span id="ouvrage_astronomique_Hésiode_LPdS"><sup>10</sup></span>]] Nous apprenons de Théon que cet ouvrage {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e nommoit l’A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}trique, Ἀςριϰὴ ϐίϐλος. Voyez au{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}i {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur ce même ouvrage, une Epigramme de [[w:Callimaque_de_Cyr%C3%A8ne|Callimaque]] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Callimaque_I_de_Cyrène_II|<sup>🔄</sup>]], citée dans la vie d’Aratus, qui fait partie de l’Uranologie de [[w:Denis_Pétau|Petau]], liv. 2, ''Var. Di{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ert.'' chap. 9, p. 97.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#opinion_Thalès_Hésiode_Anaximandre_LPdS_back|<span id="opinion_Thalès_Hésiode_Anaximandre_LPdS"><sup>11</sup></span>]] Con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ultez, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur cette opinion de Thalès, ain{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i que {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur celles d’Hé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iode & d’Anaximandre, l’Uranologie citée note précédente.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Euctémon_LPdS_back|<span id="Euctémon_LPdS"><sup>12</sup></span>]] ''Euctemon'' ; ain{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i portent les manu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}crits, & non pas ''Eudemon''. J’ai traité d’Euctêmon (en Grec Εὐϰτημον) dans les notes alphabétiques du premier livre, & plus récemment dans la note 21 du chapitre précédent.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#contrées_adjacentes_ouest_Péloponnese_LPdS_back|<span id="contrées_adjacentes_ouest_Péloponnese_LPdS"><sup>13</sup></span>]] Telles que l’Elide, l’Arcadie, la Me{{Info|ſ|forme ancienne longue de la lettre s minuscule}}lénie.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Columelle_LPdS_back|<span id="Columelle_LPdS"><sup>14</sup></span>]] Columelle, liv. 3, chap. 6 :''' {{Info|''Quo tempore ſol in eamdem partem ſigniſeri per eoſdem numeros redit, per quos cursus ſui principium cæperat : quem circuitum meatus dierum integrorum mille quadringentorum ſexaginta unius [[w:Apocatastase|ὰ τοκατάςασιν]] vocant ſtudioſi rerum cæleſtium''|A ce moment-là, le soleil revient dans la même direction au moyen des mêmes nombres par lesquels il a commencé sa course : laquelle course de mille quatre cent soixante et un jours entiers est appelée ὰ τοκατάςασιν par ceux qui étudient les choses célestes. TdA}}.</td> </tr> </table><br/><br/></div> {{Boîte déroulante fin}} <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=JeyFTzG771cC&newbks=1&newbks_redir=0&dq=Louis%20Poinsinet%20de%20Sivry%20Pline%20l'ancien&hl=fr&pg=PP9#v=onepage&q&f=true <u>Histoire Naturelle de Pline. Tome Sixieme</u>], [https://books.google.fr/books?id=JeyFTzG771cC&newbks=1&newbks_redir=0&dq=Louis%20Poinsinet%20de%20Sivry%20Pline%20l'ancien&hl=fr&pg=PA257#v=onepage&q&f=true ''Livre Dix-huitieme.''], [https://books.google.fr/books?id=JeyFTzG771cC&newbks=1&newbks_redir=0&dq=Louis%20Poinsinet%20de%20Sivry%20Pline%20l'ancien&hl=fr&pg=PA455#v=onepage&q&f=true ''Diviſion des jours & des nuits ſuivant le cours du Soleil ; lever & coucher des étoiles ; ordre des ſaiſons ; tems où l’on ſeme les bleds d’hiver.''], traduction en françois, avec le texte latin rétabli d’après les meilleures leçons manu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}crites ; accompagnée de Notes critiques pour l’éclairci{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ement du texte, & d’Ob{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ervations {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur les connoi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ances des Anciens comparées avec les découvertes des Modernes, par M. [[w:Louis_Poinsinet_de_Sivry|Louis Poinsinet de Sivry]], Chez la veuve Desaint, Paris, 1771</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div> </div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ==== Livre XXXVI ==== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Enquête sur la nature des pierres.</div> ===== <div style="text-align: center;">Chapitre XVII.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage de la mesure de la hauteur des pyramides et autres édifices semblables par comparaison des longueurs d'ombre, par '''Thalès'''.</div> :'''Texte latin''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''XVII.''' [...] Mensuram altitudinis earum omniumque similium deprehendere, invenit '''Thales''' ''Milesius'' umbram metiendo, qua hora par esse corpori solet.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=L249AAAAcAAJ&hl=fr&pg=PP11#v=onepage&q&f=false <u>Histoire Naturelle de Pline ― Tome Second</u>], [https://books.google.fr/books?id=L249AAAAcAAJ&hl=fr&pg=PA500#v=onepage&q&f=false ''Livre XXXVI.''], [https://books.google.fr/books?id=L249AAAAcAAJ&hl=fr&pg=PA513#v=onepage&q&f=false ''Chap. XVII.''], texte corrigé par [[w:Émile_Littré|M. É. Littré]], à partir de celui de [[w:Jean_Hardouin|Hardouin]], Librairie de Firmin-Didot et C<sup>ie</sup>, Paris, 1850<br />(également disponible une édition de 1877 sur [https://gallica.bnf.fr/ark:/12148/bpt6k282082c/f517.image ''Gallica''], ainsi qu’une édition de [[w:Stéphane_Ajasson_de_Grandsagne|Ajasson de Grandsagne]] également sur [https://gallica.bnf.fr/ark:/12148/bpt6k1522394n/f179.item ''Gallica''])</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''XVII.''' [...] Le moyen de mesurer la hauteur des pyramides et autres édifices semblables, fut trouvé par '''Thalès''' de ''Milet'' : il mesura l’ombre à l’heure où elle est égale aux corps.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=L249AAAAcAAJ&hl=fr&pg=PP11#v=onepage&q&f=false <u>Histoire Naturelle de Pline ― Tome Second</u>], [https://books.google.fr/books?id=L249AAAAcAAJ&hl=fr&pg=PA500#v=onepage&q&f=false ''Livre XXXVI.''], [https://books.google.fr/books?id=L249AAAAcAAJ&hl=fr&pg=PA513#v=onepage&q&f=false ''Chap. XVII.''], texte corrigé par [[w:Émile_Littré|M. É. Littré]], à partir de celui de [[w:Jean_Hardouin|Hardouin]], Librairie de Firmin-Didot et C<sup>ie</sup>, Paris, 1850<br />(également disponible une édition de 1848 sur [https://remacle.org/bloodwolf/erudits/plineancien/livre36.htm ''Remacle''], sur [[s:Histoire_naturelle_(trad._Littré)/XXXVI|''wikisource'']] et une édition de 1877 sur [https://gallica.bnf.fr/ark:/12148/bpt6k282082c/f517.image ''Gallica''])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: center; margin: 0 2em;">Des découvertes astronomiques : part de chaque observateur dans la science.<br /><p style="text-align: justify; text-indent: 15px;">'''XVII.''' [...] '''Thalès''' découvrit le moyen de mesurer et les pyramides et toutes les hauteurs semblables par la mesure de l’ombre à l’instant où elle est égale au corps.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k5804072n <u>Histoire Naturelle de Pline. Tome Onzième</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k5804072n/f196.item ''Livre XXXVI.''], [https://gallica.bnf.fr/ark:/12148/bpt6k1522394n/f179.item ''chap. XVII.''], traduction nouvelle par M. [[w:Stéphane_Ajasson_de_Grandsagne|Ajasson de Grandsagne]], C. L. F. Panckoucke, Paris, 1829</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Flavius_Josèphe|'''Flavius Josèphe''']] [[#Flavius_Josèphe|<span id="Flavius_Josèphe_back"><sup>'''I'''</sup></span>]] == <p style="text-align: right;">([[w:37|37]]/[[w:38|38]], à [[w:Histoire_de_Jérusalem#Période_romaine_et_byzantine_(63_av._J.-C._-_638)|''Jérusalem'']] — vers [[w:100|100]], à [[w:Rome_antique|''Rome'']]) [[w:Ier_siècle|<sup>⏳</sup>]] [[s:Auteur:Flavius_Josèphe|<sup>📚</sup>]] <div style="text-align: justify; margin: 0 1em; text-indent: 15px">[[w:historiographe|Historiographe]] ''romain'' [[w:Juifs|''juif'']] d’origine [[w:Judée_(province romaine)|''judéenne'']], il participe activement au début de la ''première guerre judéo-romaine'' en tant que commandant militaire de ''Galilée'' contre les Romains, avant de se rendre à [[w:Vespasien|'''Vespasien''']] [[#Vespasien|<span id="Vespasien_back"><sup>'''II'''</sup></span>]] lors de la prise de la garnison juive de la forteresse de [[w:Jotapata|''Jotapata'']] en juillet 67, et de devenir intermédiaire, interprète et négociateur entre les ''romains'' et les ''Juifs'' lors du siège de ''Jérusalem'' conduit par '''Titus''' [[#Titus_back|<sup>⤴️</sup>]] en 70. Après la fin de la grande révolte ''judéenne'', en 71, il s’établit auprès de son protecteur à ''Rome'' où il obtient la [[w:citoyenneté_romaine|''citoyenneté romaine'']].</div> {{Boîte déroulante début|titre=NdA Flavius Josèphe|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Flavius_Josèphe_back|<span id="Flavius_Josèphe"><sup>I</sup></span>]] De son nom de naissance Joseph ben (fils de) Matthatias, de l’hébreu יוסף בן מתתיהו / Yossef [[wikt:en:יוסף#Hebrew|(en)]] ben [[wikt:en:בן#Noun|(en)]] Matityahou [[wikt:en:מתתיהו#Hebrew|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;">• de la troisième personne du singulier [[w:Jussif|''jussive'']], signifiant ainsi « peut-il ajouter », du verbe הוֹסִיף / hosíf [[wikt:en:הוסיף#Hebrew|(en)]], « 1. Ajouter (quelque chose) à (quelque chose d'autre). 2. (littéraire) Continuer (à faire quelque chose). 3. (archaïque) Coordonné avec un autre verbe pour indiquer que l’action de ce verbe "ajoute" d’une manière ou d’une autre. »;<br /><p style="margin: 0 2em; text-indent: 15px;">• du nom commun בֵּן / bén, « 1. Fils. 2. (ne produit plus de mot ou d’expression) Un descendant mâle direct. 3. Un mec, un garçon. 4. (n’est plus productif, état de construction) Possesseur de (connaissance, capacité, etc.). 5. (État construit) Utilisé pour exprimer l’âge d’un homme, d’un garçon ou le référent d’un nom masculin : âge, âgé. »;<br /><p style="margin: 0 2em; text-indent: 15px;">• de la contraction du nom commun מַתָּנַת / mataná [[wikt:en:מתנה#Hebrew|(en)]], « cadeau, présent, don »;<br /><p style="margin: 0 2em; text-indent: 30px;">➥ du verbe נתן / natán [[wikt:en:נתן#Verb|(en)]], « 1. Donner. 2. Autoriser, permettre, laisser. 3. (archaïque) Mettre, placer. 4. (archaïque, hébreu biblique) Se transformer en. »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ et du nom propre יהוה / YHWH [[wikt:en:יהוה#Hebrew|(en)]], « (Judaïsme) Tétragramme : mot en quatre lettres hébraïques utilisé comme nom [[wikt:ineffable#Français|''ineffable'']] de Dieu dans la Bible hébraïque, diversement rendu par Yahweh ou Jéhovah. »;<br /><p style="margin: 0 2em; text-indent: 15px;">Son tria nomina à l’obtention de sa ''citoyenneté romaine'' est {{Info|Titus|praenomen, nom individuel du citoyen romain}} {{Info|Flavius|nomen, nom de famille}} {{Info|Josephus|cognomen, surnom héréditaire, servant à distinguer les diverses branches d’une même gens}}, prenant ainsi le nom de son bienfaiteur :<br /><br /><p style="margin: 0 2em; text-indent: 15px;">[[#Vespasien_back|<span id="Vespasien"><sup>II</sup></span>]] [[w:Nom_romain|Tria Nomina]] en latin {{Info|Titus|praenomen, nom individuel du citoyen romain}} {{Info|Flavius|nomen, nom de famille}} {{Info|Vespasianus|cognomen, surnom héréditaire, servant à distinguer les diverses branches d’une même gens}};<br /><p style="margin: 0 2em; text-indent: 15px;">[[w:L%C3%A9gat_(Rome_antique)|''Légat'']] lors de la [[w:Conqu%C3%AAte_romaine_de_la_Grande-Bretagne|''conquête de la Bretagne en 43'']] et lors de la [[w:Premi%C3%A8re_guerre_jud%C3%A9o-romaine|''rébellion juive de 66'']] en [[w:Jud%C3%A9e_(province_romaine)|''Judée'']]. Fin décembre 69, il est couronné empereur par le [[w:S%C3%A9nat_romain|''Sénat'']] après la guerre civile de l’[[w:Ann%C3%A9e_des_quatre_empereurs|''année des quatre empereurs'']], et fonde la dynastie des [[w:Flaviens|''Flaviens'']].<br /><p style="text-align: right; margin: 0 2em;">(17 novembre [[w:9|9]], près de [[w:Reate|''Reate'']] dans la région centrale italienne du [[w:Latium|''Latium'']] — 23/24 juin [[w:79|79]], à la station thermale de [[w:Aquae_Cutiliae|''Aquae Cutiliae'']], à l’est de ''Reate'')<sup>[[w:Ier_siècle|⏳]]</sup><br/><br/></div> ''' {{Boîte déroulante fin}} === [[w:Contre_Apion|Contre Apion]] === <p style="text-align: right;">[[s:Contre_Apion|📚]] {| cellpadding="0" align="{{{align|right}}}" style="margin-left: 2em; width:40%; border-spacing:3px; text-align:center; background-color:#F8F9FA; border:2px solid #C8CCD1" |- | style="border:solid 1px #F8F9FA" | [https://archive.org/details/contreapiontexte0000jose/page/n156/mode/1up {{Info|'''Éditions & Manuscrits'''|Flavius Josèphe Contre Apion, Théodore Reinach & Léon Blum, 1930}}] |- style="font-size:8pt; line-height:10pt; vertical-align:middle" | align="center" | <div style="margin-right: 1em; padding:0 0 4px 0; text-align:justify;">{{{légende| * La traduction ''latine'' a été imprimée dès 1480 à [[w:Vérone#Époque_moderne|''Vérone'']] par '''Pierre Maufer''' [[w:en:Petrus_Maufer|(en)]]. L’édition de cette traduction, due à [[w:Sigismund_Gelenius|'''Sigismond Gelenius''']] (''Paris'', 1535), qui constitue la « [[w:Vulgate|Vulgate]] », présente un texte souvent « amélioré » de façon arbitraire. La seule édition critique est celle de '''Ch. Boysen''' (''Vienne'', 1898) qui fait partie du [[w:Corpus_scriptorum_ecclesiasticorum_latinorum|{{Info|''Corpus scriptorum ecclesiasticorum latinorum''|Le corpus des écrits ecclésiastiques latins}}]]. Elle repose principalement sur les manuscrits L(aurentianus LXVI, 2), B(odleianus Canonicianus 148), R(egius Parisinus 5049) de la I<sup>re</sup> classe, C(heltenhamensis Phillipicus 12311), P(arisinus 1615), Pa(rsinus 5054) de la seconde. * Le texte grec est édité pour la première fois dans l’édition complète de '''Josèphe''' à [[w:Bâle#XVIe_siècle|''Bâle'']], chez [[w:Johann_Froben|''Froben'']], en 1544 par [[w:Arnoldus_Arlenius|'''Arlenius''']] qui a peut-être fait usage du ''Schleusingensis'' (un des fils du Laurentianus), mais a introduit grand nombre de corrections tantôt heureuses, et tantôt arbitraires. Par la suite notre traité n’a guère été imprimé que comme partie intégrante d’éditions complètes des œuvres de '''Josèphe'''. Les plus importantes sont celles de '''E. Bernard''' (1700), de [[w:John_Hudson_(classiciste)|'''Hudson''']] (1720) — le premier qui ait utilisé L —, de [[w:Sigebert_Havercamp|'''Havercamp''']] (1726), simple compilateur, de [[w:Karl_Wilhelm_Dindorf|'''L. Dindorf''']] (1847), de [[w:Immanuel_Bekker|'''Imm. Bekker''']] (1856), tout à fait manquée. L’édition critique de '''Niese''' [[w:en:Benedikt_Niese|(en)]] (1889) est la base de tous les travaux ultérieurs, notamment des éditions de '''Naber''' (1896) et de [[w:Henry_St._John_Thackeray|'''H. St. J. Thackeray''']] (coll. Loeb, 1926 : il n’a encore paru que le ''C. Apion'', la ''Vita'' et le commencement de la ''Guerre'') qui ont pu profiter aussi des conjectures de '''Cobet''', de '''Holwerda''', et de '''Herwerden'''.}}}</div> |} <div style="text-align: justify; margin: 0 1em; text-indent: 15px">Dernière œuvre écrite par '''Flavius Josèphe''', vers [[w:93|93]], dont l’objectif est de répondre aux critiques qu’ont soulevées ses [[w:Antiquit%C3%A9s_juda%C3%AFques|''Antiquités judaïques'']], de défendre l’ancienneté du peuple ''juif'' et du [[w:Judaïsme#Judaïsme_antique|''judaïsme'']] (Livre I) et les accusations d’[[w:Apion_(grammairien)|'''Apion''']] [[#Apion|<span id="Apion_back"><sup>'''I'''</sup></span>]] (Livre II).</div> {{Boîte déroulante début|titre=NdA Apion|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Apion_back|<span id="Apion"><sup>I</sup></span>]] Du nom propre grec ancien [[wikt:Apion#Latin|Ἀπίων / Apíôn]]; <br/><br /><p style="margin: 0 2em; text-indent: 15px;">'''[[w:Grammaticus|''Grammairien'']] [[#grammairien|<span id="grammairien_back"><sup>II</sup></span>]] et [[w:Polygraphe_(auteur)|''polygraphe'']] [[#polygraphe|<span id="Grammairien_back"><sup>III</sup></span>]] ''grec'' d’Alexandrie.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] seconde moitié du [[w:Ier_siècle_av._J.-C.|I<sup>er</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]] — première moitié du [[w:Ier_siècle|I<sup>er</sup> siècle {{Info|EC|de l’Ère Commune}}]]) <br /><br /><p style="margin: 0 2em; text-indent: 15px;">'''[[#grammairien_back|<span id="grammairien"><sup>II</sup></span>]] Du nom commun latin grammaticus [[wikt:en:grammaticus#Latin|(en)]]; du nom commun grec ancien γραμματικός / grammatikós [[wikt:en:γραμματικός#Noun|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px">➥ du nom commun γρᾰ́μμᾰ / grámma [[wikt:en:γράμμα#Noun|(en)]], « 1. Ce qui est écrit, ce qui est dessiné. 2. Lettre. 3. (au pluriel) Alphabet. 4. Écriture, livre. »;<br /><p style="margin: 0 2em; text-indent: 30px">➥ du verbe γράφω / gráphō [[wikt:en:γράφω#Ancient_Greek|(en)]], « 1. (Homérique) égratigner, couper en dedans. 2. Dessiner, esquisser, peindre. 3. Écrire. 4. Écrire, proposer une loi. 5. ([[w:Diathèse#Moyen|''voix moyenne'']]) : • (''[[w:Réflexivité_(grammaire)|réflexif]] indirect'') Écrire pour soi, noter ; • Accuser, poursuivre. 6. ([[w:Conjugaison_latine|''passif parfait'']]) Être écrit, être sous forme écrite. »;<br /><p style="margin: 0 2em; text-indent: 30px">➥ + du suffixe nominal de résultat‎ -μα / -ma [[wikt:en:-μα#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px">➥ +‎ du suffixe adjectival -ῐκός / -ikós, de ou se rapportant à, de la manière de ; « -ique »;<br /><p style="margin: 0 2em; text-indent: 15px">Enseignant responsable de la deuxième étape du système éducatif traditionnel, après l’apprentissage de l’alphabet, la lecture et l’écriture, et l’initiation au calcul avec un abaque chez un ''magister ludi'' [[w:en:Ludi_magister|(en)]] et avant celle de l’art du discours chez un [[w:Rhétorique#Rhétorique_dans_l'Antiquité_grecque|''rhéteur'']]. Le travail du grammairien était d’enseigner la lecture, l’analyse de textes des poètes antiques tels qu’Homère, Tite-Live et Virgile, et la grammaire [https://archive.wikiwix.com/cache/index2.php?url=http%3A%2F%2Fwww.antiquite.ac-versailles.fr%2Feducatio%2Fedrom2.htm#federation=archive.wikiwix.com&tab=url {{Info|<sup>➕</sup>|« L’école du grammaticus », ac-Versailles}}] [https://philo-lettres.fr/latin/rome_vie-quotidienne/ecole-romaine/ {{Info|<sup>➕➕</sup>|« L’École dans l’antiquité romaine, philo-lettres}}]. <br /><br /><p style="margin: 0 2em; text-indent: 15px;">'''[[#polygraphe_back|<span id="polygraphe"><sup>III</sup></span>]] Du nom commun grec ancien [[wikt:polygraphe|πολύγραφος / polýgraphos]], « qui écrit beaucoup de sujets »;<br /><p style="margin: 0 2em; text-indent: 15px">➥ de l’adjectif πολῠ́ς / polús [[wikt:en:πολύς#Ancient_Greek|(en)]], « (de nombre, au pluriel) Beaucoup de : • (avec des noms de multitude) Grand ; • (de quantité, avec des noms de masse) beaucoup de ; • (rare, d'une personne) Grand, puissant ; • (de son) Fort ; • (attributivement, adverbial) Fortement, pleinement ; • (d'espace) Large, grand ; • (de distance) Loin ; • (de temps) Long, en retard. »;<br /><p style="margin: 0 2em; text-indent: 15px">➥ +‎ du verbe γράφω / gráphō [[wikt:en:γράφω#Ancient_Greek|(en)]], « 1. (Homérique) égratigner, couper en dedans. 2. Dessiner, esquisser, peindre. 3. Écrire. 4. Écrire, proposer une loi. 5. (''voix moyenne'') : • (''réflexif indirect'') Écrire pour soi, noter ; • Accuser, poursuivre. 6. (''passif parfait'') Être écrit, être sous forme écrite. »;<br /><p style="margin: 0 2em; text-indent: 15px;">Le terme semble avoir été employé au cours de l’Antiquité dans un sens différent de celui que nous l’entendons aujourd’hui, pas dans le sens de diversité mais, de façon restreinte, le fait de composer un grand nombre de textes [https://eriac.univ-rouen.fr/la-polygraphie-comme-norme/ {{Info|<sup>➕</sup>|Isabelle Gassino, Université de Rouen et Dimitri Kasprzyk, université de Brest, « Colloque "La polygraphie comme norme" », 16 et 17 novembre 2017.}}].'''<br/><br/></div> {{Boîte déroulante fin}} ==== Livre I ==== ===== <div style="text-align: center;">Chapitre II.</div> ===== <div style="text-align: justify; margin: 0 1em;">Témoignage de '''Thales''' comme : * l’un des premiers ''philosophes grecs'' ayant traité des choses célestes et divines ; * disciple des ''Égyptiens'' et des ''Chaldéens'' (premier témoignage) ; * auteur de court(s)/rare(s) ouvrages (supposément unanimement admis), que les ''Grecs'' considéreraient comme les plus anciens, et douteraient, selon '''Flavius Josèphe''', de leur authenticité.</div> :'''Texte latin''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">qui autem historias apud eos conscribere temptauerunt, id est hi, qui circa '''Cadmum''' ''Milesium'', et '''Acusilaus''' ''Argiuus'' et post hunc quicumque alii fuisse referuntur, paululum tempus ''Persicam'' apud ''Helladium'' militiam praecesserunt. sed etiam eos, qui de caelestibus et diuinis primitus apud ''Graecos philosophati'' sund, id est '''Pherecydem''' ''Syrum'' et '''Pythagoram''' et '''Thaletem''' omnes concorditer confidentur ''Aegyptiorum'' et ''Chaldaeorum'' fuisse discipulos et breuiter conscripsisse quae a ''Graecis'' omnium antiquissima iudicantur ita ut uix ea credant ab illis fuisse conscripta.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[[w:Corpus_scriptorum_ecclesiasticorum_latinorum|<u>Corpus scriptorum ecclesiasticorum latinorum</u>]], [https://verlag.oeaw.ac.at/produkt/flavii-iosephi-opera-ex-versione-latina-antiqua-pars-vi-de-iudaeorum-vetustate-sive-contra-apionem-libri-ii/601067?name=flavii-iosephi-opera-ex-versione-latina-antiqua-pars-vi-de-iudaeorum-vetustate-sive-contra-apionem-libri-ii&product_form=5107 <u>Tome XXXVII, Flavius Iosephus, Contra Apionem</u>], ''Livre I'', ''chap. II.'', ''l.13, 14'', p.64, 1898</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">Οἱ μέντοι τὰς ἱστορίας ἐπιχειρήσαντες συγγράφειν παρ' αὐτοῖς, λέγω δὲ τοὺς περὶ '''Κάδμον''' τε τὸν ''Μιλήσιον'' καὶ τὸν ''Ἀργεῖον'' '''Ἀκουσίλαον''' καὶ μετὰ τοῦτον εἴ τινες ἄλλοι λέγονται γενέσθαι, βραχὺ τῆς ''Περσῶν'' ἐπὶ τὴν ''Ἑλλάδα'' στρατείας τῷ χρόνῳ προύλαβον. Ἀλλὰ μὴν καὶ τοὺς περὶ τῶν οὐρανίων τε καὶ θείων πρώτους παρ' ''Ἕλλησι φιλοσοφήσαντας'', οἷον '''Φερεκύδην''' τε τὸν ''Σύριον'' καὶ '''Πυθαγόραν''' καὶ '''Θάλητα''', πάντες συμφώνως ὁμολογοῦσιν ''Αἰγυπτίων'' καὶ ''Χαλδαίων'' γενομένους μαθητὰς ὀλίγα συγγράψαι, καὶ ταῦτα τοῖς ''Ἕλλησιν'' εἶναι δοκεῖ πάντων ἀρχαιότατα καὶ μόλις αὐτὰ πιστεύουσιν ὑπ' ἐκείνων γεγράφθαι.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://remacle.org/bloodwolf/historiens/Flajose/Apion1gr.htm <u>Φλαίίου Ἰωσήπου, περὶ ἀρχαιότητος Ἰουδαίων</u>, ''λόγος α''], ''chap. II.'', ''l.13, 14'', 1898</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">Quant aux Grecs qui ont entrepris d’écrire l’histoire, comme [[w:Cadmos_de_Milet|'''Cadmos''' de ''Milet'']], [[w:Acousilaos|'''Acousilaos''' d’Argos]] et ceux qu’on cite après lui, ils n’ont vécu que peu de temps [[#Cadmos_NdT_LB|<span id="Cadmos_NdT_LB_back"><sup>1</sup></span>]] avant [[w:Guerres_médiques|''l’expédition des Perses contre la Grèce'']]. Mais bien certainement les premiers ''philosophes grecs'' qui aient traité des choses célestes et divines, comme [[w:Phérécyde_de_Syros|'''Phérécyde''' de ''Syros'']] [[#Phérécyde_de_Syros_NdT_LB|<span id="Phérécyde_de_Syros_NdT_LB_back"><sup>2</sup></span>]], '''Pythagore''' et '''Thalès'''[[#Thales_NdT_LB|<span id="Thales_NdT_LB_back"><sup>3</sup></span>]] furent, tout le monde s’accorde là-dessus, les disciples des ''Égyptiens'' et des ''Chaldéens'' avant de composer leurs courts ouvrages, et ces écrits sont aux yeux des ''Grecs'' les plus anciens de tous ; à peine même les croient-ils authentiques.</div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Cadmos_NdT_LB_back|<span id="Cadmos_NdT_LB"><sup>1.</sup></span>]] En réalité, Cadmos paraît avoir fleuri vers le milieu [[w:VIe_siècle_av._J.-C.|VI<sup>ème</sup> siècle]] [{{Info|AEC|Avant l’Ère Commune}}].''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Phérécyde_de_Syros_NdT_LB_back|<span id="Phérécyde_de_Syros_NdT_LB"><sup>2</sup></span>]] Seul texte qui attribue une origine égyptienne ou chaldéenne aux doctrines de Phérécyde de Syros. Cependant [[w:Theodor_Gomperz|Gompers]], [https://archive.org/details/bub_gb_QrfVAAAAMAAJ/page/n434/mode/1up Griechische Denker, I, 430], identifie ᾿Ογηνός avec l’Ouginna babylonien.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Thales_NdT_LB_back|<span id="Thales_NdT_LB"><sup>3</sup></span>]] On retrouve chez [[w:Apollonios_de_Tyane|Apollonios de Tyane]] ([[w:Jamblique|Jamblique]] [[#Jamblique_back|<sup>⤵️</sup>]], Vit. Pyth. [[#Vie_de_Pythagore_back|<sup>⤵️</sup>]], 12) et [[w:Plutarque|Plutarque]] [[#Plutarque_back|<sup>⤵️</sup>]] l’idée que Thalès de Milet fut disciple des Égyptiens ; l’adjonction des Chaldéens est propre Josèphe.''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/contreapiontexte0000jose/page/n6/mode/1up?view=theater <u>Flavius Josèphe, Contre Apion</u>], ''Livre I'', [https://archive.org/details/contreapiontexte0000jose/page/n49/mode/1up?view=theater&q=Thales ''chap. 2''], traduction du grec ancien par Léon Blum, agrégé des Lettres, professeur au lycée Janson-de-Sailly, texte établi et annotée par [[w:Théodore_Reinach|Théodore Reinach]] Membre de l’[[w:Institut_de_France|Institut]], professeur au Collège de France, 1930<br />(édition bilingue de 1911 également disponible [https://remacle.org/bloodwolf/historiens/Flajose/Apion1.htm ici])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: justify; margin: 0 2em;">Quant aux Grecs qui ont entrepris d’écrire l’histoire, comme '''Cadmos''' de ''Milet'', '''Acousilaos''' d’''Argos'' et ceux qu’on nomme après lui, ils n’ont vécu que peu de temps[2] avant l’expédition des ''Perses'' contre la ''Grèce''. [14]. De même, les premiers ''philosophes grecs'' qui aient traité des choses célestes et divines, comme '''Phérécyde''' de ''Syros''[3], '''Pythagore''' et '''Thalès'''[4] furent, tout le monde s’accorde là dessus, les disciples des ''Égyptiens'' et des ''Chaldéens'' avant de composer leurs rares ouvrages, et ces écrits sont aux yeux des ''Grecs'' les plus anciens de tous ; à peine même les croient-ils authentiques.</div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Cadmos_NdT_LB_back|<span id="Cadmos_NdT_LB"><sup>1.</sup></span>]] En réalité, Cadmos paraît avoir fleuri vers le milieu [[w:VIe_siècle_av._J.-C.|VI<sup>ème</sup> siècle]] [{{Info|AEC|Avant l’Ère Commune}}].''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Phérécyde_de_Syros_NdT_LB_back|<span id="Phérécyde_de_Syros_NdT_LB"><sup>2</sup></span>]] Seul texte qui attribue une origine égyptienne ou chaldéenne aux doctrines de Phérécyde de Syros. Cependant [[w:Theodor_Gomperz|Gompers]], [https://archive.org/details/bub_gb_QrfVAAAAMAAJ/page/n434/mode/1up Griechische Denker, I, 430], identifie ᾿Ογηνός avec l’Ouginna babylonien.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Thales_NdT_LB_back|<span id="Thales_NdT_LB"><sup>3</sup></span>]] On retrouve chez [[w:Apollonios_de_Tyane|Apollonios de Tyane]] ([[w:Jamblique|Jamblique]] [[#Jamblique_back|<sup>⤵️</sup>]], Vit. Pyth. [[#Vie_de_Pythagore_back|<sup>⤵️</sup>]], 12) et [[w:Plutarque|Plutarque]] [[#Plutarque_back|<sup>⤵️</sup>]] l’idée que Thalès de Milet fut disciple des Égyptiens ; l’adjonction des Chaldéens est propre Josèphe.''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Flavius Josèphe, De l’ancienneté du peuple juif (Contre Apion)</u>, ''Livre I'', [[s:Page:Flavius_Josephe_-_Leon_Blum_-_Contre_Apion,_Leroux,_Paris,_1902.djvu/17|''Chap. 2'']], traduction de Léon Blum, agrégé des lettres, professeur au lycée du Havre, sous la direction de [[w:Théodore_Reinach|Théodore Reinach]], 1902.</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div> </div> <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Plutarque|'''Plutarque''']] [[#Plutarque|<span id="Plutarque_back"><sup>'''I'''</sup></span>]] == <p style="text-align: right;">([[w:Circa|{{Info|''ca.''|Circa, locution latine que l’on emploie pour indiquer l’approximation d’une date}}]] [[w:45|45]]'' <sup>[[w:Ier_siècle|⏳]]</sup>'', à [[w:Chéronée|''Chéronée'']] en [[w:Béotie|''Béotie'']] — {{Info|''ca.''|Circa, locution latine que l’on emploie pour indiquer l’approximation d’une date}} [[w:125|125]]'' <sup>[[w:IIe_siècle|⏳]]</sup>)[[s:Auteur:Plutarque|<sup>📚</sup>]] [https://books.google.fr/books?id=qfl1xwEACAAJ&lpg=PA1067&hl=fr&pg=PA1097#v=onepage&q&f=false {{Info|<sup>🔍</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume Vb, §210 - Plutarque de Chéronée}}] [[Fichier:Plutarch at Delphi.jpg|vignette|<p style="text-align: justify; text-indent: 15px;">Buste probable de Plutarque du [[w:IIe_siècle|II<sup>ème</sup>]] ou [[w:IIIe_siècle|III<sup>ème</sup>]] siècles {{Info|EC|de l’Ère Commune}}, en marbre de [[w:Marbre_de_Paros|''Paros'']].<br /><p style="text-align: justify; text-indent: 15px;">Provenance : découvert lors de fouilles près de l’angle sud-est du [[w:Temple d'Apollon (Delphes)|''temple d’Apollon'']] de [[w:Delphes|''Delphes'']], au côté d'une [[w:Fichier:Plutarch_stele_inscription_100_AD,_AM_of_Delphi_4070060092.jpg|''stèle'']] portant une inscription gravée : ΔΕΛΦΟΙ ΧΑΙΡΩΝΕΥΣΙΝ ΟΜΟΥ ΠΛΟΥΤΑΡΧΟΝ ΕΘΗΚΑΝ ΤΟΙΣ ΑΜΦΙΚΤΥΟΝΩΝ ΔΟΓΜΑΣΙ ΠΕΙΘΟΜΕΝΟΙ — Les ''Delphiens'', avec les ''Chéronéens'', dédièrent ce(tte image de) Plutarque, suivant les préceptes de l’[[w:Amphictyonie|''Amphictyonie'']].<br /><p style="text-align: justify; text-indent: 15px;">Exposition : Salle XIV, [[w:Mus%C3%A9e_arch%C3%A9ologique_de_Delphes|''Musée archéologique de Delphes'']].]] <div style="text-align: justify; margin: 0 1em; text-indent: 15px">Biographe, philosophe et moraliste grec, auteur d’une œuvre importante, comportant un ensemble varié de traités et de dialogues consacrés à des questions de philosophie morale, mais abordant aussi des sujets littéraires, politiques, scientifiques, religieux.</div> {{Boîte déroulante début|titre=NdA Plutarque|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Plutarque_back|<span id="Plutarque"><sup>I</sup></span>]] Du nom propre grec ancien πλούταρχος / ploútarkhos [[wikt:en:Πλούταρχος#Ancient_Greek|(en)]], « maître des richesses » ; <br /><p style="margin: 0 2em; text-indent: 15px">➥ du nom commun πλοῦτος / ploûtos [[wikt:en:πλοῦτος#Ancient_Greek|(en)]], « richesses » ;<br /><p style="margin: 0 2em; text-indent: 15px">➥ +‎ du nom commun ἀρχός / arkhós, « souverain, chef, prince »)'''<br/><br/></div> {{Boîte déroulante fin}} {{Boîte déroulante début|titre=Remarque|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>''' Dans la ''Vie de [[w:Lycurgue_(législateur)|Lycurgue]]'' et la ''Vie d’Agis et Cléomène'' (''Vies parallèles''), et le traité ''Un philosophe doit surtout converser avec les princes'' (''Œuvres morales''), il est fait mention d’un Thalès : il s’agit de [[w:Thalétas|Thalétas]], aussi appelé Thalès de [[w:Crète|''Crète'']], un musicien et poète, originaire de la cité de [[w:Gortyne|''Gortyne'']] en ''Crète'', et actif à la fin du [[w:VIIIe_siècle_av._J.-C.|VIII<sup>ème</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]] et au début du siècle suivant.'''<br/><br/></div> {{Boîte déroulante fin}} === [[w:Vies_parallèles|Vies parallèles]] [[#Vies_parallèles|<span id="Vies_parallèles_back"><sup>'''I'''</sup></span>]] === <div style="text-align: center; margin: 0 1em;">Recueil de 50 biographies de grands hommes de l’histoire, dont 46 présentées par paires : un ''Grec'' mis en parallèle avec un ''Romain'' [https://books.google.fr/books?id=qfl1xwEACAAJ&lpg=PA1059&hl=fr&pg=PA1115#v=onepage&f=false {{info|<sup>🔍</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume Vb, §210 - Plutarque de Chéronée, pp.1115 - 1119, (7) Le Moraliste et l’entreprise des Vies Parallèles}}]. {{Boîte déroulante début|titre=NdA Vies parallèles|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Vies_parallèles_back|<span id="Vies_parallèles"><sup>I</sup></span>]] En grec ancien Βίοι Παράλληλοι / Bíoi Parállêloi :<br /><p style="margin: 0 2em; text-indent: 15px;">➥ Du nom commun βῐ́ος / bĭ́os [[wikt:en:βίος#Ancient_Greek|(en)]], « Vie (souvent avec une connotation positive : la vie heureuse) » ;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ De l’adjectif πᾰρᾰ́λληλος / părắllēlos [[wikt:en:παράλληλος#Ancient_Greek|(en)]], « 1. À côté l’un de l’autre, côte à côte. 2. Parallèle à ou avec. 3. Pléonastique, redondant.<br /><p style="margin: 0 2em; text-indent: 30px;">➥ du préfixe παρα- / para- [[wikt:en:παρα-#Ancient_Greek|(en)]], « 1. À côté. 2. Contrairement à. » ;<br /><p style="margin: 0 2em; text-indent: 45px;">➥ de la préposition πᾰρᾰ́ / părắ [[wikt:en:παρά#Ancient_Greek|(en)]], « 1. [avec génitif] : • De ; • À cause de. 2. [avec datif] : • À, à côté de, près de. 3. [avec accusatif] : • Contraire à ; • À côté de, près de (avec les verbes de venir ou d’aller ; avec les verbes de mouvement passé ; avec les verbes de frapper ou de blesser) » ;<br /><p style="margin: 0 2em; text-indent: 30px;">➥ +‎ du pronom ᾰ̓λλήλων / ăllḗlōn [[wikt:en:ἀλλήλων#Ancient_Greek|(en)]], « Se rapportant à un sujet pluriel et exprimant une action bilatérale : l’un de l’autre, l’un à l’autre, l’un l’autre, l’un l’autre, mutuellement, réciproquement. » ;<br /><p style="margin: 0 2em; text-indent: 45px;">➥ À partir d’expressions telles que ᾰ̓́λλος ᾰ̓́λλον / ắllos ắllon, ᾰ̓́λλοι ᾰ̓́λλους / ắlloi ắllous, « les uns les autres », avec perte de λ soit par dissimilation, soit par allongement de α, ainsi que restauration de la deuxième voyelle initiale ή / ḗ.'''<br/><br/></div> {{Boîte déroulante fin}} ==== Vie de [[w:Solon|'''Solon''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Solon|<sup>🔄</sup>]] ==== <div style="text-align: center; margin: 0 1em;">Biographie de '''Solon''', qui précède celle de [[w:Publius_Valerius_Publicola_(consul_en_-509)|'''Publicola''']] [[#Publicola|<span id="Publicola_back"><sup>'''I'''</sup></span>]], et avec laquelle '''Plutarque''' la compare.</div> {{Boîte déroulante début|titre=NdA Vie de Solon|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Publicola_back|<span id="Publicola"><sup>I</sup></span>]] [[w:Nom_romain|Tria Nomina]] en latin {{Info|Publius|praenomen, nom individuel du citoyen romain}} {{Info|Valerius|nomen, nom de famille}} {{Info|Publicola ou Poplicola|cognomen, surnom héréditaire, servant à distinguer les diverses branches d’une même gens}}, « celui qui prend soin de l’armée. »[https://academic.oup.com/bics/advance-article/doi/10.1093/bics/qbaf002/8117642?login=false {{Info|<sup>🔍</sup>|M. Gallo, « Misinterpreting a compound name. The origin of the agnomen Publicola in Dionysius of Halicarnassus and Plutarch », Bulletin of the Institute of Classical Studies,‎ 22 avril 2025}}].<br /><p style="margin: 0 2em; text-indent: 15px">[[w:Consul_(Rome_antique)|Consul]] de la [[w:république_romaine|''République Romaine'']], à quatre reprises : en [[w:-509|-509]], [[w:-508|-508]], [[w:-507|-507]] et [[w:-504|-504]], et l’un des instaurateurs légendaires de la ''République Romaine'' en -509, suite au viol et au suicide de [[w:Lucrèce_(dame_romaine)|Lucrèce]], une femme aristocratique ''romaine'', par [[w:Sextus_Tarquin|Sextus Tarquin]], le fils du dernier [[w:Roi_de_Rome|roi de ''Rome'']] [[w:Tarquin_le_Superbe|Tarquin le Superbe]].<br /><p style="text-align: right; margin: 0 2em;">(date et lieu de naissance inconnu.e.s — [[w:-503|-503]], soit sur le champ de bataille pendant les [[w:Guerres_romano-sabelliennes|''guerres romano-sabelliennes'']], soit de maladie)<sup>[[w:VIe_siècle_av._J.-C.|⏳]]</sup> '''<br/><br/></div> {{Boîte déroulante fin}} ===== <div style="text-align: center;">Chapitre II.</div> ===== ====== <div style="text-align: center;">Paragraphe III.</div> ====== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage de '''Thalès''' ''commerçant''.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''III.''' Κωλύει δὲ οὐδὲν τὸν ἀγαθὸν καὶ πολιτικὸν ἄνδρα μήτε τῶν περιττῶν τὴν κτῆσιν ἐν σπουδῇ τίθεσθαι μήτε τῆς χρείας τῶν ἀναγκαίων καὶ ἱκανῶν καταφρονεῖν. Ἐν δὲ τοῖς τότε χρόνοις, καθ' Ἡσίοδον, ἔργον οὐδὲν ἦν ὄνειδος, οὐδὲ τέχνη διαφορὰν ἔφερεν, ἐμπορία δὲ καὶ δόξαν εἶχεν οἰκειουμένη τὰ βαρβαρικὰ καὶ προξενοῦσα φιλίας βασιλέων καὶ πραγμάτων ἐμπείρους ποιοῦσα πολλῶν. Ἔνιοι δὲ καὶ πόλεων οἰκισταὶ γεγόνασι μεγάλων, ὡς καὶ Μασσαλίας Πρῶτις ὑπὸ Κελτῶν τῶν περὶ τὸν Ῥοδανὸν ἀγαπηθείς. Καὶ Θαλῆν δέ φασιν ἐμπορίᾳ χρήσασθαι καὶ Ἱπποκράτην τὸν μαθηματικόν, καὶ Πλάτωνι τῆς ἀποδημίας ἐφόδιον ἐλαίου τινὸς ἐν Αἰγύπτῳ διάθεσιν γενέσθαι.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://remacle.org/bloodwolf/historiens/Plutarque/solon.htm <u>Plutarque, Vie de Solon</u>], ''chap. II'', ''§3'', traduction par [[w:Dominique_Ricard|Dominique Ricard]], 1844<br />(également disponible une édition de 1853 [https://remacle.org/bloodwolf/historiens/Plutarque/solonpierrron.htm ici] et de 1862 [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f16.item là])</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 390px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''III.''' Mais rien n’empêche l’homme de bien, le citoyen dévoué à son pays, de garder un juste milieu : il peut ne point s’attacher à la poursuite du superflu, sans pour cela mépriser le nécessaire et ce qui suffit à ses besoins.<br />Dans ce temps-là, pour parler comme [[w:Hésiode|'''Hésiode''']] [[#Hésiode|<span id="Hésiode_back"><sup>'''I'''</sup></span>]] [[#Hésiode_NdT_AP|<span id="Hésiode_NdT_AP_back"><sup>1</sup></span>]], il n’y avait pas de travail qui fût honteux; aucun art ne mettait de différence entre les hommes : le négoce surtout était honoré, qui met en possession des avantages dont jouissent les étrangers, gagne l’amitié des rois, et donne une grande expérience. On a même vu des trafiquants fonder de grandes villes : ainsi [[w:Mythe_fondateur_de_Marseille|'''Protis''']] bâtit [[w:Marseille_antique|''Marseille'']], après s'être concilié l’amitié des ''Gaulois'' qui habitent les bords du [[w:Rhône#Histoire|''Rhône'']]. '''Thales''' se livra, dit-on, au négoce, ainsi qu’[[w:Hippocrate_de_Chios|'''Hippocrate''']] [[#Hippocrate|<span id="Hippocrate_back"><sup>'''II'''</sup></span>]] le mathématicien[[#Hippocrate_NdT_AP|<span id="Hippocrate_NdT_AP_back"><sup>2</sup></span>]] ; et [[w:Platon|'''Platon''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Platon|<sup>🔄</sup>]] vendit de l’huile en [[w:Basse_Époque|''Égypte'']] , pour fournir aux frais de son voyage.</div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Hésiode_NdT_AP_back|<span id="Hésiode_NdT_AP"><sup>1.</sup></span>]] Œuvres et Jours, vers 309.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Hippocrate_NdT_AP_back|<span id="Hippocrate_NdT_AP"><sup>2</sup></span>]] Cet Hippocrate n’est point connu d’ailleurs.''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/viesdeshommesill01plut/page/n6/mode/1up?view=theater <u>Vie des Hommes Illustres de Plutarque</u>], [https://archive.org/details/viesdeshommesill01plut/page/182/mode/1up?view=theater ''Solon''], ''Chap. II'', ''§3'', [https://archive.org/details/viesdeshommesill01plut/page/184/mode/1up?view=theater p.184], traduit par [[w:Alexis_Pierron|Alexis Pierron]], professeur au lycée Louis-le-Grand, 1877<br />(également disponible une édition de 1853 [[s:Vies_des_hommes_illustres/Solon|ici]])</div> {{Boîte déroulante début|titre=NdA trad. par Alexis Pierron de 1877|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Hésiode_back|<span id="Hésiode"><sup>I</sup></span>]] Du nom propre grec ancien Ἡσῐ́οδος / Hēsĭ́odos [[wikt:en:Ἡσίοδος#Ancient_Greek|(en)]].<br /><p style="margin: 0 2em; text-indent: 15px">Berger sur les pentes du Mont [[w:Mont_Hélicon|Hélicon]] et un des plus grands poètes grecs. Il s’agit plus précisément d’un ''aède'' (il « chante » ses vers avec sa lyre) et un ''rhapsode'' (il « coud » des chants entre eux)[https://odysseum.eduscol.education.fr/hesiode-un-des-premiers-poetes-grecs {{Info|<sup>🔍</sup>|Hésiode, un des premiers poètes grecs - Odysseum, la maison numérique des Humanités}}]. <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Hippocrate_back|<span id="Hippocrate"><sup>II</sup></span>]] Du nom propre grec ancien Ῐ̔πποκρᾰ́της / Hĭppokrắtēs [[wikt:en:Ἱπποκράτης#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px">➥ du nom commun ῐ̔́ππος / hĭ́ppos [[wikt:en:ἵππος#Ancient_Greek|(en)]], « cheval »;<br /><p style="margin: 0 2em; text-indent: 15px">➥ + du nom commun‎ κρᾰ́τος / krắtos [[wikt:en:κράτος#Ancient_Greek|(en)]], « 1. Puissance, force. 2. Acte de force, acte de bravoure. 3. (au pluriel) Actes de violence. 4. Domination, pouvoir. »;<br /><p style="margin: 0 2em; text-indent: 15px">➥ +‎ du suffixe nominal -ης / -ēs.<br /><p style="margin: 0 2em; text-indent: 15px"> Mathématicien (géomètre) et astronome « para-pythagoricien », dont l’œuvre ne nous est pas parvenue.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] milieu du [[w:Ve_siècle_av._J.-C.|V<sup>ème</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]]) [https://books.google.fr/books?id=DrvWAAAAMAAJ&newbks=1&newbks_redir=0&lpg=PA764&vq=Hippocrate&dq=bibliogroup%3A%22Dictionnaire%20des%20philosophes%20antiques%22&hl=fr&pg=PA764#v=onepage&q&f=true {{Info|<sup>🔍</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume III, §151 - Hippocrate de Chios}}]'''<br/><br/></div> {{Boîte déroulante fin}} <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: center; margin: 0 2em;">'''II. Dans sa jeunesse il se livre au commerce maritime; la modicité de sa fortune et son goût pour la sagesse l’y décident. Faveur du commerce à cette époque ; grands noms qui l’ont illustré.'''<br /><br /><p style="text-align: justify; text-indent: 15px;">Mais rien n’empêche qu’un homme de bien, un sage politique tienne à cet égard un juste milieu, et que sans rechercher des richesses superflues, il ne méprise pas celles qui sont nécessaires et qui suffisent. Dans ce temps-là, comme dit [[w:Hésiode|'''Hésiode''']], aucun travail n’était regardé comme honteux; aucun art ne mettait de différence entre les hommes. Le commerce maritime surtout était honorable; il ouvrait des communications utiles avec les nations étrangères, procurait des alliances avec les rois, et donnait une grande expérience. On a même vu des commerçants fonder de grandes villes. Ainsi '''Protus''' gagna l’amitié des Gaulois qui habitaient les bords du ''Rhône'', et bâtit ''Marseille''. '''Thalès''' et '''Hippocrate''' le mathématicien firent aussi le commerce ; et '''Platon''' vendit de l’huile en ''Égypte'' pour fournir aux frais de son voyage.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f7.item <u>Plutarque, Vie de Solon</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f16.item ''chap. II''], traduction correcte et précédée du texte grec, par une société de professeurs et d’helléniste, 1862<br />(également disponible une édition de 1844 [https://remacle.org/bloodwolf/historiens/Plutarque/solon.htm#1a ici] et de 1829 [[s:Les_Vies_des_hommes_illustres/Vie_de_Solon|là]])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Mais rien n’empêche l’homme de-bien et l’homme politique ni se mettre en souci (rechercher) l’acquisition des choses superflues, ni mépriser l’usage des choses nécessaires et suffisantes. Or dans les temps d’alors, selon '''Hésiode''', aucun travail n’était sujet-de-honte, ni aucun métier n’apportait de différence entre les citoyens mais même le commerce-maritime avait de la gloire, rendant-amies les nations-barbares, et procurant des amitiés de rois, et faisant les hommes expérimentés d’affaires nombreuses. Et quelques-uns aussi sont devenus fondateurs de grandes villes, comme aussi le '''Protus''' de ''Marseille'' ayant été aimé par les ''Celtes'' ceux autour du ''Rhône''. Et on dit aussi '''Thalès''', avoir fait-usage du commerce-maritime et '''Hippocrate''' le mathématicien, et la vente d'une certaine huile en ''Égypte'' avoir été pour '''Platon''' ressource du voyage.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f7.item <u>Plutarque, Vie de Solon</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f16.item ''chap. II''], traduction littérale et juxtalinéaire présentant le mot à mot français en regard des mots grecs correspondants, par une société de professeurs et d’helléniste, 1862</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ====== <div style="text-align: center;">Paragraphe IV.</div> ====== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage de la sagesse de '''Thalès''' en ''philosophie naturelle''</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''IV.''' Φιλοσοφίας δὲ τοῦ ἠθικοῦ μάλιστα τὸ πολιτικόν, ὥσπερ οἱ πλεῖστοι τῶν σοφῶν, ἠγάπησεν. Ἐν δὲ τοῖς φυσικοῖς ἁπλοῦς ἐστι λίαν καὶ ἀρχαῖος, ὡς δῆλον ἐκ τούτων· [...].<br /><p style="text-indent: 15px">Καὶ ὅλως ἔοικεν ἡ Θάλεω μόνου σοφία τότε περαιτέρω τῆς χρείας ἐξικέσθαι τῇ θεωρίᾳ· τοῖς δὲ ἄλλοις ἀπὸ τῆς πολιτικῆς ἀρετῆς τοὔνομα τῆς σοφίας ὑπῆρξε.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://remacle.org/bloodwolf/historiens/Plutarque/solon.htm <u>Plutarque, Vie de Solon</u>], ''chap. II'', ''§4'', traduction par [[w:Dominique_Ricard|Dominique Ricard]], 1844<br />(également disponible une édition de 1853 [https://remacle.org/bloodwolf/historiens/Plutarque/solonpierrron.htm ici] et de 1862 [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f20.item là])</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 390px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''IV.''' Il s’attacha, comme presque tous les sages d’alors, à cette partie de la philosophie morale qui traite de la politique. Pour la philosophie naturelle, il en était aux rudiments, et aux notions du vieux temps sans plus; [...].<br /><p style="text-indent: 15px;">Aussi bien n’y eut-il, en somme, que '''Thalès''' dont la science dépassât alors les notions d’un usage vulgaire : tous les autres ne durent qu’à leurs connaissances politiques leur réputation de sagesse.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/viesdeshommesill01plut/page/n6/mode/1up?view=theater <u>Vie des Hommes Illustres de Plutarque</u>], [https://archive.org/details/viesdeshommesill01plut/page/182/mode/1up?view=theater ''Solon''], ''Chap. II'', ''§4'', [https://archive.org/details/viesdeshommesill01plut/page/185/mode/1up?view=theater p.185], traduit par [[w:Alexis_Pierron|Alexis Pierron]], professeur au lycée Louis-le-Grand, 1877<br />(également disponible une édition de 1853 [[s:Vies_des_hommes_illustres/Solon|ici]])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">A l’exemple des sages de son temps, il cultiva principalement cette partie de la morale qui traite de la politique. Il n’avait en physique que des connaissances très-superficielles, et en était aux premiers éléments de cette science, [...].<br/><p style="text-indent: 15px">En général '''Thalès''' fut, de tous les sages d’alors, le seul qui porta au delà des besoins de la vie la théorie des sciences ; tous les autres ne durent qu’à leurs connaissances politiques leur réputation de sagesse.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f7.item <u>Plutarque, Vie de Solon</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f20.item ''chap. II''], traduction correcte et précédée du texte grec, par une société de professeurs et d’helléniste, 1862<br />(également disponible une édition de 1844 [https://remacle.org/bloodwolf/historiens/Plutarque/solon.htm#1a ici] et de 1829 [[s:Les_Vies_des_hommes_illustres/Vie_de_Solon|là]])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Mais de la partie morale de la philosophie il embrassa surtout la partie politique, comme la plupart des sages d’alors. Mais dans les sciences physiques il est extrêmement simple (ignorant) et primitif, [...]. Et en-un-mot la science de '''Thalès''' seul paraît s’être avancée alors par la théorie plus loin que le besoin ; et le nom de la science a appartenu aux autres par-suite des qualités politiques.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f7.item <u>Plutarque, Vie de Solon</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f21.item ''chap. II''], traduction littérale et juxtalinéaire présentant le mot à mot français en regard des mots grecs correspondants, par une société de professeurs et d’helléniste, 1862</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ====== <div style="text-align: center;">Paragraphe V.</div> ====== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Version alternative du récit de la coupe de [[w:Bathyclès_de_Magnésie|'''Bathyclès''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Bathyclès_back|<sup>🔄</sup>]] par [[w:Callimaque_de_Cyrène|'''Callimaque''']] de [[w:Cyrène|''Cyrène'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Callimaque_back|<sup>🔄</sup>]].</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''V.''' Γενέσθαι δὲ μετ' ἀλλήλων ἔν τε Δελφοῖς ὁμοῦ λέγονται καὶ πάλιν ἐν Κορίνθῳ, Περιάνδρου σύλλογόν τινα κοινὸν αὐτῶν καὶ συμπόσιον κατασκευάσαντος. Ἔτι δὲ μᾶλλον εἰς ἀξίωμα καὶ δόξαν αὐτοὺς κατέστησεν ἡ τοῦ [[w:τρίπους#Grec_ancien|'''τρίποδος''']] περίοδος καὶ διὰ πάντων ἀνακύκλησις καὶ ἀνθύπειξις μετ' εὐμενείας φιλοτίμου γενομένη. Κῴων γάρ, ὥς φασι, καταγόντων σαγήνην, καὶ ξένων ἐκ Μιλήτου πριαμένων τὸν βόλον οὔπω φανερὸν ὄντα, χρυσοῦς ἐφάνη τρίπους ἑλκόμενος, ὃν λέγουσιν Ἑλένην πλέουσαν ἐκ Τροίας αὐτόθι καθεῖναι χρησμοῦ τινος ἀναμνησθεῖσαν παλαιοῦ. Γενομένης δὲ τοῖς ξένοις πρῶτον ἀντιλογίας πρὸς τοὺς ἁλιέας περὶ τοῦ τρίποδος, εἶτα τῶν πόλεων ἀναδεξαμένων τὴν διαφορὰν ἄχρι πολέμου προελθοῦσαν, ἀνεῖλεν ἀμφοτέροις ἡ Πυθία τῷ σοφωτάτῳ τὸν τρίποδα ἀποδοῦναι. Καὶ πρῶτον μὲν ἀπεστάλη πρὸς Θαλῆν εἰς Μίλητον, ἑκουσίως τῶν Κῴων ἑνὶ δωρουμένων ἐκείνῳ περὶ οὗ πρὸς ἅπαντας ὁμοῦ Μιλησίους ἐπολέμησαν. Θάλεω δὲ Βίαντα σοφώτερον ἀποφαίνοντος αὑτοῦ πρὸς ἐκεῖνον ἧκεν· ἀπ' ἐκείνου δ' αὖθις ἀπεστάλη πρὸς ἄλλον ὡς σοφώτερον. Εἶτα περιϊὼν καὶ ἀναπεμπόμενος οὕτως ἐπὶ Θαλῆν τὸ δεύτερον ἀφίκετο, καὶ τέλος εἰς Θήβας ἐκ Μιλήτου κομισθεὶς τῷ Ἰσμηνίῳ Ἀπόλλωνι καθιερώθη. Θεόφραστος δέ φησι,πρῶτον μὲν εἰς Πριήνην Βίαντι τὸν τρίποδα πεμφθῆναι, δεύτερον δ' εἰς Μίλητον Θαλῇ Βίαντος ἀποπέμψαντος· οὕτω δὲ διὰ πάντων πάλιν εἰς Βίαντα περιελθεῖν, τέλος δὲ εἰς Δελφοὺς ἀποσταλῆναι. Ταῦτα μὲν οὖν ὑπὸ πλειόνων τεθρύληται, πλὴν ὅτι τὸ δῶρον ἀντὶ τοῦ τρίποδος οἱ μὲν φιάλην ὑπὸ Κροίσου πεμφθεῖσαν, οἱ δὲ ποτήριον Βαθυκλέους ἀπολιπόντος εἶναι λέγουσιν.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://remacle.org/bloodwolf/historiens/Plutarque/solon.htm <u>Plutarque, Vie de Solon</u>], ''chap. II'', ''§5'', traduction par [[w:Dominique_Ricard|Dominique Ricard]], 1844<br />(également disponible une édition de 1853 [https://remacle.org/bloodwolf/historiens/Plutarque/solonpierrron.htm ici] et de 1862 [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f22.item là])</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 390px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''V.''' On raconte que les sept sages se réunirent une fois à [[w:Delphes|''Delphes'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Delphes_back|<sup>🔄</sup>]], et une autre fois à [[w:Histoire_de_Corinthe_dans_l%27Antiquité|''Corinthe'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Corinthe_back|<sup>🔄</sup>]], où [[w:Périandre|'''Périandre''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Périandre_back|<sup>🔄</sup>]] les avait convoqués pour leur offrir un banquet. Rien ne contribua tant à leur réputation et à leur gloire, que le renvoi qu’ils se firent successivement l’un à l’autre du trépied d’or, et l’honorable humilité avec laquelle ils refusèrent le prix tour à tour. Des hommes de [[w:Kos_(Dodécanèse)#Kos_à_l'époque_hellénistique|''Cos'']] [[#Cos|<span id="Cos_back"><sup>'''I'''</sup></span>]] venaient, dit-on, de jeter leur filet en mer : des étrangers de ''Milet'' achetèrent le coup, avant que les pêcheurs y eussent regardé. Il se trouva, dans le filet, un trépied d’or qu’[[w:Hélène_(mythologie)|'''Hélène''']] [[#Hélène|<span id="Hélène_back"><sup>'''II'''</sup></span>]], à ce qu’on prétend, pour obéir à un ancien oracle, avait jeté dans la mer à son retour de [[w:Troie|''Troie'']] [[#Troie|<span id="Troie_back"><sup>'''III'''</sup></span>]]. Ce fut un sujet de débat, d’abord entre les pêcheurs et les étrangers, ensuite entre les deux villes, qui prirent parti dans la querelle : la guerre allait s’allumer, lorsque la [[w:Pythie|''Pythie'']] [[#Pythie|<span id="Pythie_back"><sup>'''IV'''</sup></span>]], que les deux partis avaient consultée, commanda de donner le trépied au plus sage. On l’envoya d’abord à ''Milet'', pour '''Thalès''', et ceux de ''Cos'' cédèrent sans peine à un seul particulier ce qu’ils allaient disputer par les armes à tous les ''Milésiens'' ensemble. '''Thalès''' déclara que [[w:Bias_de_Priène|'''Bias''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Bias_back|<sup>🔄</sup>]] était plus sage que lui, et le lui fit passer. '''Bias''', avec la même modestie, le fit passer à un autre; et le trépied, après avoir été envoyé successivement à tous les sept, revint une seconde fois à '''Thalès'''. Enfin, il fut transporté de ''Milet'' à [[w:Thèbes_(Grèce)|''Thèbes'']] [[#Thèbes|<span id="Thèbes_back"><sup>'''V'''</sup></span>]], et consacré à Apollon [[w:en:Ismenus|''Isménien'']]. Cependant [[w:Théophaste|'''Théophaste''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Théophaste_back|<sup>🔄</sup>]] dit qu’on envoya le trépied d’abord à '''Bias''', dans ''Priène'' ; que '''Bias''' le fit porter à '''Thalès''' ; qu’après avoir passé alternativement chez tous les sages, il revint à '''Bias''', et qu’il finit par être envoyé à ''Delphes''. Telle est la tradition commune : seulement quelques-uns prétendent qu’il s’agissait de décerner non point un trépied, mais un vase que [[w:Crésus|'''Crésus''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Crésus_back|<sup>🔄</sup>]] avait envoyé ; et, suivant d’autres, c’était une coupe, héritage de '''Bathyclès'''.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/viesdeshommesill01plut/page/n6/mode/1up?view=theater <u>Vie des Hommes Illustres de Plutarque</u>], [https://archive.org/details/viesdeshommesill01plut/page/182/mode/1up?view=theater ''Solon''], ''Chap. II'', ''§5'', [https://archive.org/details/viesdeshommesill01plut/page/185/mode/1up?view=theater p.185], traduit par [[w:Alexis_Pierron|Alexis Pierron]], professeur au lycée Louis-le-Grand, 1877<br />(également disponible une édition de 1853 [[s:Vies_des_hommes_illustres/Solon|ici]])</div> {{Boîte déroulante début|titre=NdA trad. par Alexis Pierron de 1877|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Cos_back|<span id="Cos"><sup>I</sup></span>]] Du nom propre grec ancien Κῶς / Kôs [[wikt:en:Κῶς#Ancient_Greek|(en)]] ;<br /><p style="margin: 0 2em; text-indent: 15px">Île grecque l’archipel du [[w:Dodécanèse|''Dodécanèse'']], au Sud-Est de la [[w:Mer_Égée|''mer Égée'']], au large des côtes ''turques''. <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Hélène_back|<span id="Hélène"><sup>II</sup></span>]] Du nom propre grec ancien Ἑλένη / Helénē [[wikt:en:Ἑλένη#Ancient_Greek|(en)]] ;<br /><p style="margin: 0 2em; text-indent: 15px">Fille de [[w:Zeus|Zeus]] et de [[w:Léda (mythologie)|Léda]], considérée comme la plus belle femme du monde, uniquement surpassée par la déesse [[w:Aphrodite|Aphrodite]]. Elle est mariée à [[w:Ménélas|Ménélas]], roi de [[w:Sparte|Sparte]], et est enlevée par [[w:Pâris|Pâris]], prince [[w:Troie|''troyen'']] [[#Troie|<sup>'''III'''</sup>]], ce qui déclencha la [[w:guerre de Troie|guerre de Troie]] qui opposa ''Grecs'' et ''Troyens''. <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Troie_back|<span id="Troie"><sup>III</sup></span>]] Du nom propre grec ancien Τροίᾱ / Troíā [[wikt:en:Τροία#Ancient_Greek|(en)]] ; [[w:Troie#Toponymie|''toponymie incertaine'']] ;<br /><p style="margin: 0 2em; text-indent: 15px"> Cité semi-légendaire, située sur la colline d’''[[w:site archéologique de Troie|{{lang|tr|Hisarlık}}]]'', à l’entrée de l’''[[w:Hellespont|Hellespont]]'', non loin de la ''[[w:mer Égée|mer Égée]]'', au nord-ouest de la ''péninsule anatolienne'', dans la région ''[[w:Troade|Troade]]'' en ''[[w:Asie Mineure|Asie Mineure]]''.<br /><p style="margin: 0 2em; text-indent: 15px"> Le site a fait l’objet de nombreuses campagnes de fouilles, à la suite de celles entreprises par [[w:Heinrich Schliemann|Heinrich Schliemann]] en 1870, ponctuées par des découvertes fortement médiatisées, qui ont popularisé son identification avec la Troie homérique (qui reste un sujet de débat en l’absence de preuve décisive), le lieu principal des événements du ''[[w:cycle troyen|cycle troyen]]'' rapportés dans les ''[[w:Épopée|poèmes épiques]]'' ''[[w:Homère|homériques]]'' l’''[[w:Iliade|Iliade]]'' et l’''[[w:Odyssée|Odyssée]]''. <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Pythie_back|<span id="Pythie"><sup>IV</sup></span>]] Du nom commun grec ancien Πῡθῐ́ᾱ / Pūthĭ́ā,<br /><p style="margin: 0 2em; text-indent: 15px">➥ du nom propre Πῡθώ / Pūthṓ, « [[w:Delphes#Histoire_du_site|''Pythô'']], ancien nom de ''Delphes'' » ;<br /><p style="margin: 0 2em; text-indent: 15px">➥ +‎ du suffixe adjectival féminin -ῐος / -ĭos [[wikt:en:-ιος#Ancient_Greek|(en)]], « relatif à, appartenant à (de) ».<br /><p style="margin: 0 2em; text-indent: 15px">[[w:Divination_dans_la_Grèce_antique|''Oracle'']] du [[w:Temple_d%27Apollon_(Delphes)|''temple d’Apollon'']] à ''Delphes''.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:XIVe_siècle_av._J.-C.|XIV<sup>ème</sup>]]/[[w:VIIIe_siècle_av._J.-C.|VIII<sup>ème</sup>]] siècles {{Info|AEC|Avant l’Ère Commune}} — [[w:IVe_siècle_av._J.-C.|IV<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]]) <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Thèbes_back|<span id="Thèbes"><sup>V</sup></span>]] Du nom propre grec ancien Θῆβαι / Thêbai [[wikt:en:Θῆβαι#Ancient_Greek|(en)]], désigne indistinctement la cité ''grecque'' comme [[w:Thèbes_(Égypte)|celle ''égyptienne'']] ; mais leur étymologie diffère :<br /><p style="margin: 0 2em; text-indent: 15px;">➥ pour celle de la cité grecque, de l’[[w:Ionien-attique|''ionien-attique'']] Θήβη / Thḗbē ; du grec mycénien 𐀳𐀣 / te-qa (/Tʰēgʷā/) ;<br /><p style="margin: 0 2em; text-indent: 15px;">(➥ pour celle de la cité égyptienne, de l’égyptien démotique tꜣ-jpy, « Thèbes, littéralement "le temple" » ;<br /><p style="margin: 0 2em; text-indent: 30px;">➥ de l’article défini tꜣ [[wikt:en:tꜣ#Demotic_Egyptian|(en)]], « le/la » ;<br /><p style="margin: 0 2em; text-indent: 30px;">➥ + du nom propre et commun jpt [[wikt:en:jpt#Etymology_3|(en)]], « Louxor, littéralement "sanctuaire intérieur" »).<br /><p style="margin: 0 2em; text-indent: 15px">Cité grecque de la région de [[w:Béotie#Antiquité|''Béotie'']], au centre de la ''Grèce''.'''<br/><br/></div> {{Boîte déroulante fin}} <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">On raconte que les sept sages se trouvèrent un jour ensemble à ''Delphes'', et une autre fois à ''Corinthe'', chez '''Périandre''', qui les avait réunis pour un banquet. Rien ne contribua autant à leur réputation et à leur gloire, que la modestie empressée avec laquelle ils se renvoyèrent l’un à l’autre le trépied d’or. Des ''Milésiens'' qui se trouvaient à l’île de ''Cos'', avaient acheté d’avance de quelques pêcheurs ce que retirerait de l’eau le filet qu’ils allaient y jeter. Quand on l’eut tiré, il s’y trouva un trépied d’or qu’'''Hélène''', à ce qu’on prétend, pour obéir à un oracle, avait jeté dans la mer, à son retour de ''Troie''. Cet incident donna lieu à une vive dispute d’abord entre les pêcheurs et les étrangers, ensuite entre les deux villes, qui prirent parti dans la querelle et étaient près d’en venir aux mains, lorsque la ''Pythie'' consultée leur ordonna de porter ce trépied au plus sage. On l’envoya d’abord à '''Thalès''', et ceux de ''Cos'' cédèrent sans peine à un seul particulier ce qu’ils allaient disputer par les armes à tous les ''Milésiens'' ensemble. '''Thalès''' le renvoya à '''Bias''', qui, disait-il, était plus sage que lui ; '''Bias''', avec la même modestie, le fit passer à un autre ; et après avoir été envoyé successivement à tous les sept, il revint une seconde fois à '''Thalès''' : enfin il fut porté à ''Thèbes'', et consacré à ''Apollon Isménien''. '''Théophraste''' dit qu’on l’envoya d’abord à '''Bias''', qui demeurait à ''Priène'' ; que '''Bias''' le fit porter à '''Thalès''' ; qu’après avoir été envoyé alternativement à tous les sages, il revint à '''Bias''', et qu’enfin il fut porté à ''Delphes''. Telle est la tradition la plus commune sur ce fait ; seulement quelques auteurs disent que ce n’était pas un trépied, mais un vase que '''Crésus''' envoyait à ''Delphes''; suivant d’autres, c’était une coupe que '''Bathyclès''' avait laissée.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f7.item <u>Plutarque, Vie de Solon</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f22.item ''chap. II''], traduction correcte et précédée du texte grec, par une société de professeurs et d’helléniste, 1862<br />(également disponible une édition de 1844 [https://remacle.org/bloodwolf/historiens/Plutarque/solon.htm#1a ici] et de 1829 [[s:Les_Vies_des_hommes_illustres/Vie_de_Solon|là]])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Or ils (les sept sages) sont dits s’être trouvés aussi ensemble les uns avec les autres et à ''Delphes'' et de nouveau à ''Corinthe'', '''Périandre''' ayant préparé une certaine réunion commune d’eux et un banquet. Or le tour du trépied, et sa circulation à travers tous et sa cession se faisant avec une bienveillance pleine-d’émulation mit eux encore davantage en considération et renommée. Car des ''habitants-de-Cos'', comme on dit, jetant le filet, et des hôtes venus de ''Milet'' ayant acheté le coup qui n’était pas encore apparent, un trépied d’-or apparut étant retiré, lequel on dit '''Hélène''' naviguant pour revenir de ''Troie'' avoir jeté là, s’étant souvenue d’un certain oracle ancien. Mais une contestation ayant eu lieu d’abord aux hôtes vis-à-vis des pécheurs au sujet du trépied, ensuite les villes ayant pris-sur-elles le différend qui alla jusqu'à une guerre, la ''Pythie'' répondit aux-uns-et-aux-autres de donner le trépied au plus sage des hommes. Et d’abord il fut envoyé à '''Thalès''' à ''Milet'', les ''habitants-de-Cos'' donnant volontairement à celui-là seul le trépied, au sujet duquel ils avaient fait-la-guerre contre tous les ''Milésiens'' à-la-fois. Mais '''Thalès''' déclarant '''Bias''' plus sage que lui-même, il renvoya vers celui-là. Et de nouveau il fut envoyé par celui-là vers un autre, comme plus sage. Ensuite faisant-le-tour et étant envoyé-successivement ainsi il arriva pour la seconde fois à '''Thalès''' ; et à la fin transporté de ''Milet'' à ''Thèbes'', il fut consacré à ''Apollon Isménien''. Mais '''Théophraste''' dit le trépied avoir été envoyé d’abord à la vérité à ''Priène'' à '''Bias''', mais en-second-lieu à ''Milet'' à '''Thalès''', '''Bias''' l’ayant renvoyé ; et ainsi à travers tous (de l’un à l’autre) être venu-en-faisant-le-tour de nouveau à '''Bias''', et à la fin avoir été envoyé à ''Delphes''. Ces choses donc ont été répandues par plusieurs, excepté qu’ils disent le présent au lieu du trépied les uns être un vase à boire envoyé par '''Crésus''', les autres une coupe. '''Bathyclès''' rayant laissée (laissée par '''Bathyclès'''). </div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f7.item <u>Plutarque, Vie de Solon</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f23.item ''chap. II''], traduction littérale et juxtalinéaire présentant le mot à mot français en regard des mots grecs correspondants, par une société de professeurs et d’helléniste, 1862</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Chapitre VI.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;"> Récit d’une entrevue de '''Thalès''' avec '''Solon''', de son stoïcisme, de son célibat et de l’adoption du fils de sa sœur, '''Cybistus'''.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;"> '''VI.''' Ἰδίᾳ δ' Ἀναχάρσεώς τε πρὸς Σόλωνα καὶ πάλιν Θάλεω συνουσίαν τινὰ καὶ λόγους ἀναγράφουσι τοιούτους. [...]<br /><p style="text-indent: 15px"> '''VII.''' Πρὸς Θαλῆν δ' εἰς Μίλητον ἐλθόντα τὸν Σόλωνα θαυμάζειν ὅτι γάμου καὶ παιδοποιΐας τὸ παράπαν ἠμέληκε. Καὶ τὸν Θαλῆν τότε μὲν σιωπῆσαι, διαλιπόντα δ' ὀλίγας ἡμέρας ἄνδρα παρασκευάσαι ξένον, ἀρτίως ἥκειν φάσκοντα δεκαταῖον ἐξ Ἀθηνῶν. Πυθομένου δὲ τοῦ Σόλωνος εἰ δή τι καινὸν ἐν ταῖς Ἀθήναις, δεδιδαγμένον ἃ χρὴ λέγειν τὸν ἄνθρωπον, « οὐδέν,» εἰπεῖν, « ἕτερον, εἰ μὴ νὴ Δία νεανίσκου τινὸς ἦν ἐκφορὰ καὶ προὔπεμπεν ἡ πόλις. Ἦν γὰρ υἱός, ὡς ἔφασαν, ἀνδρὸς ἐνδόξου καὶ πρωτεύοντος ἀρετῇ τῶν πολιτῶν· οὐ παρῆν δέ, ἀλλ' ἀποδημεῖν ἔφασαν αὐτὸν ἤδη πολὺν χρόνον.» « Ὡς δυστυχὴς ἐκεῖνος,» φάναι τὸν Σόλωνα. « Τίνα δὲ ὠνόμαζον αὐτόν;» « ἤκουσα,» φάναι, « τοὔνομα,» τὸν ἄνθρωπον, « ἀλλ' οὐ μνημονεύω· πλὴν ὅτι πολὺς λόγος ἦν αὐτοῦ σοφίας καὶ δικαιοσύνης.» Οὕτω δὴ καθ' ἑκάστην ἀπόκρισιν τῷ φόβῳ προσαγόμενον τὸν Σόλωνα καὶ τέλος ἤδη συντεταραγμένον αὐτὸν ὑποβάλλειν τοὔνομα τῷ ξένῳ, πυνθανόμενον μὴ Σόλωνος ὁ τεθνηκὼς υἱὸς ὠνομάζετο. Φήσαντος δὲ τοῦ ἀνθρώπου, τὸν μὲν ὁρμῆσαι παίειν τὴν κεφαλὴν καὶ τἆλλα ποιεῖν καὶ λέγειν ἃ συμβαίνει τοῖς περιπαθοῦσι, τὸν δὲ Θαλῆν ἐπιλαβόμενον αὐτοῦ καὶ γελάσαντα, « ταῦτά τοι,» φάναι, « ὦ Σόλων, ἐμὲ γάμου καὶ παιδοποιΐας ἀφίστησιν, ἃ καὶ σὲ κατερείπει τὸν ἐρρωμενέστατον. Ἀλλὰ θάρρει τῶν λόγων ἕνεκα τούτων· οὐ γάρ εἰσιν ἀληθεῖς.» ταῦτα μὲν οὖν Ἕρμιππος ἱστορεῖν φησι Πάταικον, ὃς ἔφασκε τὴν Αἰσώπου ψυχὴν ἔχειν.<br /><p style="text-indent: 15px">'''VIII.''' Ἄτοπος δὲ καὶ ἀγεννὴς ὁ τῷ φόβῳ τῆς ἀποβολῆς τὴν κτῆσιν ὧν χρὴ προϊέμενος· οὕτω γὰρ ἄν τις οὐ πλοῦτον, οὐ δόξαν, οὐ σοφίαν ἀγαπήσειε παραγενομένην, δεδιὼς στέρεσθαι. Καὶ γὰρ ἀρετήν, ἧς κτῆμα μεῖζον οὐδὲν οὐδ' ἥδιον, ἐξισταμένην ὑπὸ νόσων καὶ φαρμάκων ὁρῶμεν· αὐτῷ τε '''Θαλῇ''' μὴ γήμαντι πλέον οὐδὲν εἰς ἀφοβίαν, εἰ μὴ καὶ φίλων κτῆσιν ἔφυγε καὶ οἰκείων καὶ πατρίδος. Ἀλλὰ καὶ παῖδα θετὸν ἔσχε ποιησάμενος αὐτὸς τὸν τῆς ἀδελφῆς, ὥς φασι, '''Κύβισθον'''.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://remacle.org/bloodwolf/historiens/Plutarque/solon.htm <u>Plutarque, Vie de Solon</u>], ''chap. II'', ''§§6-8'', traduction par [[w:Dominique_Ricard|Dominique Ricard]], 1844<br />(également disponible une édition de 1853 [https://remacle.org/bloodwolf/historiens/Plutarque/solonpierrron.htm ici] et de 1862 [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f26.item là])</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 390px; border: 2px solid; text-indent: 15px"><br /><div style="margin: 0 2em; text-align: justify; direction: ltr;">'''VI.''' '''Solon''' connut [[w:Anacharsis|'''Anacharsis''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Anacharsis_back|<sup>🔄</sup>]] et '''Thalès''', et l’on cite des mots qui s’étaient dits dans leurs entrevues. <br /><p style="text-align: center"> [...]<br /><p style="text-indent: 15px; text-align: justify;">'''Solon''' alla à ''Milet'', pour voir '''Thalès''' : là, il lui témoigna sa surprise dans ce qu’il n’avait jamais voulu se marier et avoir des enfants. '''Thalès''' ne répondit rien sur l’heure; mais, quelques jours après, il fit paraître un étranger, qui disait arriver d’''Athènes'', et qu’il n’en était parti que depuis dix jours. '''Solon''' demanda à cet homme s’il n’y avait rien de nouveau à ''Athènes''. Celui-ci, à qui '''Thalès''' avait fait la leçon, répondit qu’il n’y avait rien de nouveau , sinon la mort d’un jeune homme dont toute la ville menait les funérailles. C’était, en effet, à ce qu’on disait, le fils d’un personnage considérable, d’une vertu éprouvée : le père n’était pas alors à ''Athènes'', et il voyageait depuis longtemps. « L’infortuné père! s’écria '''Solon'''. Mais comment s’appelait-il? — Je l’ai entendu nommer, répondit l’étranger, mais j’ai oublié son nom ; je me souviens seulement qu’on ne parlait que de sa sagesse et de sa justice. » A chacune de ces réponses, '''Solon''' sentait augmenter ses craintes; enfin, ne se possédant plus , il suggéra le nom à l’étranger, et lui demanda si le mort n’était pas le fils de '''Solon'''. « Oui. » répondit l’étranger. A cette parole, '''Solon''' se frappa la tête, et il se mit à faire et à dire tout ce qu’inspire une douleur violente. Alors '''Thalès''' lui prit la main, et lui dit en riant : « Voilà, '''Solon''', ce qui m’éloigne de me marier et d’avoir des enfants. J’ai redouté le coup sous lequel tu fléchis, toi le plus ferme des hommes. Mais rassure-toi; car il n’y a rien de vrai dans tout ce qu’on vient de te dire. » [[w:Hermippe_de_Smyrne|'''Hermippus''']] [[#Hermippe|<span id="Hermippe_back"><sup>'''I'''</sup></span>]] rapporte cette histoire d’après '''Patécus''', celui qui prétendait avoir hérité de l’âme d’[[w:Ésope|'''Ésope''']] [[#Ésope|<span id="Ésope_back"><sup>'''II'''</sup></span>]].<br /><p style="text-indent: 15px">Pourtant il y a faute de sens et de cœur à refuser d’acquérir les choses nécessaires, par la crainte de les perdre. A ce compte, on devra n’aimer ni la richesse, ni la gloire, ni la sagesse, quand on les possède, de peur d’en être privé. En effet, la vertu, le plus grand des biens et le plus doux, nous quitte quelquefois par l’action de certaines maladies ou de certains breuvages. '''Thalès''' lui-même, en ne se mariant point, n’était pas pour cela à l’abri de la crainte, à moins qu’il n'eût renoncé aussi à ses parents, à ses amis, à sa patrie. Mais il n’en était rien : il avait adopté, dit-on, '''Cybisthus''', le fils de sa sœur. </div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/viesdeshommesill01plut/page/n6/mode/1up?view=theater <u>Vie des Hommes Illustres de Plutarque</u>], [https://archive.org/details/viesdeshommesill01plut/page/182/mode/1up?view=theater ''Solon''], ''Chap. II'', ''§6'', [https://archive.org/details/viesdeshommesill01plut/page/185/mode/1up?view=theater p.185], traduit par [[w:Alexis_Pierron|Alexis Pierron]], professeur au lycée Louis-le-Grand, 1877<br />(également disponible une édition de 1853 [[s:Vies_des_hommes_illustres/Solon|ici]])</div> {{Boîte déroulante début|titre=NdA trad. par Alexis Pierron de 1877|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Hermippe_back|<span id="Hermippe"><sup>I</sup></span>]] Du nom propre [[w:Nom_théophore|''théophore'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#théophore_back|<sup>🔄</sup>]] grec ancien Ἕρμιππος / Hérmippos [[wikt:en:Ἕρμιππος#Ancient_Greek|(en)]] ;<br /><p style="margin: 0 2em; text-indent: 15px">➥ du nom propre Ἑρμῆς / Hermês [[wikt:en:Ἑρμῆς#Ancient_Greek|(en)]], « Hermès » ;<br /><p style="margin: 0 2em; text-indent: 15px">➥ +‎ du nom commun ἵππος / híppos [[wikt:en:ἵππος#Ancient_Greek|(en)]], « cheval » ;<br /><p style="margin: 0 2em; text-indent: 15px">« Péripatéticien » grec, disciple de [[w:Callimaque_de_Cyr%C3%A8ne|Callimaque de ''Cyrène'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Callimaque_back|<sup>🔄</sup>]], auteur de nombreuses biographies toutes perdues, mais listées par plusieurs auteurs.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] seconde moitié du [[w:IIIe_siècle_av._J.-C.|III<sup>ème</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]]) [https://books.google.fr/books?id=DrvWAAAAMAAJ&newbks=1&newbks_redir=0&lpg=PA497&dq=bibliogroup%3A%22Dictionnaire%20des%20philosophes%20antiques%22&hl=fr&pg=PA655#v=onepage&q&f=false {{Info|<sup>🔍</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume III, §86 - Hermippe de Smyrne}}] <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Ésope_back|<span id="Ésope"><sup>II</sup></span>]] Du nom propre grec ancien Αἴσωπος / Aísōpos [[wikt:en:Αἴσωπος#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px">➥ du nom commun αἶσα / aîsa, « destin »;<br /><p style="margin: 0 2em; text-indent: 15px">➥ +‎ du nom commun ὄψ / óps, « voix »;<br /><br /><p style="margin: 0 2em; text-indent: 15px">Auteur grec de fable.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] seconde moitié du [[w:VIe_siècle_av._J.-C.|VI<sup>ème</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]]) [https://books.google.fr/books?id=DrvWAAAAMAAJ&newbks=1&newbks_redir=0&lpg=PA497&dq=bibliogroup%3A%22Dictionnaire%20des%20philosophes%20antiques%22&hl=fr&pg=PA240#v=onepage&q&f=false {{Info|<sup>🔍</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume III, §60 - Ésope(Αἴσωπος)}}]'''<br/><br/></div> {{Boîte déroulante fin}} <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">'''V.''' Voici les particularités qu’on raconte d’une entrevue de '''Solon''' avec '''Anacharsis''', et d’un entretien qu’il eut avec '''Thalès'''.<br /><p style="text-align: center"> [...]<br /><p style="text-indent: 15px; text-align: justify;">'''VI.''' '''Solon''', étant allé à ''Milet'' pour voir '''Thalès''', lui témoigna sa surprise de ce qu’il n’avait jamais voulu se marier et avoir des enfants. '''Thalès''' ne lui répondit rien dans le moment; mais ayant laissé passer quelques jours, il fit paraître un étranger qui disait arriver d’''Athènes'', d’où il était parti depuis dix jours. '''Solon''' lui demanda s’il n’y avait rien de nouveau, lorsqu’il en était parti. Cet homme, à qui '''Thalès''' avait fait la leçon, lui répondit qu’il n’y avait autre chose que la mort d’un jeune homme dont toute la ville accompagnait le convoi. C’était, disait-on, le fils d’un des premiers et des plus vertueux citoyens, qui n'’était pas alors à ''Athènes'' et qui voyageait depuis longtemps, « Le malheureux père! s’écria Solon. Comment s’appelle-t-il? ― Je l’ai entendu nommer, répondit l’étranger; mais j’ai oublié son nom; je me souviens seulement qu’on ne parlait que de sa sagesse et de sa justice. » A chacune de ces réponses, les craintes de '''Solon''' augmentaient; enfin, troublé, hors de lui-même, il suggéra le nom à l’étranger, et lui demanda si ce jeune homme n’était pas le fils de '''Solon'''. « C’est lui-même, » dit l’autre. A cette parole, '''Solon''', se frappant la tête, se mit à faire et à dire tout ce que la douleur la plus violente peut inspirer. Alors '''Thalès''' l’arrêta et lui dit en souriant : « Voilà, '''Solon''', ce qui m’a éloigné de me marier et d’avoir des enfants; j’ai redouté le coup qui vous accable aujourd’hui, et contre lequel toute votre fermeté est impuissante. Mais rassurez-vous ; il n’y a rien de vrai dans tout ce qu’on vient de vous dire. » '''Hermippus''' rapporte cette histoire d’après le récit qu’en fait '''Patécus''', qui prétendait avoir hérité de l’âme d’'''Ésope'''.<br /><p style="text-indent: 15px; text-align: justify;">'''VII.''' Cependant c’est manquer de sens et de courage que de renoncer à acquérir des choses nécessaires par la crainte de les perdre. A ce compte, il ne faudrait aimer ni la richesse, ni la gloire, ni la sagesse, quand on les possède, de peur d’en être privé. La vertu même, le plus grand et le plus agréable des biens, se perd souvent par l’effet. de quelques maladies ou de certains breuvages. '''Thalès''' lui-même, en ne se mariant point, n’était pas à l’abri de toute crainte, à moins qu’il ne renonçât aussi à ses parents, à ses amis et à sa patrie. Mais au contraire, il avait adopté '''Cybistus''', le fils de sa sœur. </div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f7.item <u>Plutarque, Vie de Solon</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f26.item ''chap. II''], traduction correcte et précédée du texte grec, par une société de professeurs et d’helléniste, 1862<br />(également disponible une édition de 1844 [https://remacle.org/bloodwolf/historiens/Plutarque/solon.htm#1a ici] et de 1829 [[s:Les_Vies_des_hommes_illustres/Vie_de_Solon|là]])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">'''V.''' Mais en particulier on rapporte une certaine entrevue et de tels discours et d’'''Anacharsis''' à '''Solon''' et une-autre-fois de '''Thalès'''.<br /><p style="text-align: center"> [...]<br /><p style="text-indent: 15px; text-align: justify;">'''VI.''' Et on raconte '''Solon''' étant venu vers '''Thalès''' à ''Milet'' s’étonner de ce qu’il avait négligé absolument le mariage et la création-d’enfants. Et '''Thalès''' alors à la vérité s’être tu, mais ayant laissé-d’intervalle peu-de jours, avoir aposté un homme étranger, disant être arrivé récemment parti-depuis-dix-jours d’''Athènes''. Et '''Solon''' s’étant informé si donc il y a quelque chose de nouveau à ''Athènes'', l’homme instruit des choses qu’il faut dire n’avoir dit aucune autre chose, si ce n’est :<br /><p style="text-indent: 15px"> « Par '''Jupiter''', il y avait le convoi d’un certain jeune-homme, et la ville l’accompagnait. Car il était fils, comme on disait, d’un homme illustre et étant-le-premier des citoyens par la vertu; mais il n’était-pas-présent, mais on disait lui être-en-voyage depuis un temps déjà long.<br /><p style="text-align: left; text-indent: 15px">― Combien cet homme-là est malheureux! avoir dit '''Solon'''. Mais quel (comment) appelaient-ils lui ?<br /><p style="text-align: left; text-indent: 15px">― J’ai entendu le nom, avoir dit l’homme (répondit l’étranger), mais je ne me le rappelle pas; excepté qu’un discours fréquent était de la sagesse et de la justice de lui. »<br /><p style="text-indent: 15px">'''Solon''' donc étant-approché ainsi de-la crainte à chaque réponse, et à la fin déjà étant tout-troublé, lui-même avoir suggéré le nom à l’étranger, demandant si le mort n’était pas nommé fils de '''Solon'''. Et l’homme ayant dit-oui, celui-ci ('''Solon''') avoir commencé à frapper sa tête, et à faire et à dire les autres choses, qu’il arrive de faire et de dire à ceux affligés-à-l’excès. Mais '''Thalès''' ayant arrêté lui, et ayant ri, avoir dit :<br /><p style="text-indent: 15px">« Ces choses donc, ô '''Solon''', écartent moi du mariage et de la création-d’enfants, lesquelles abattent même toi le très-fort. Mais aie-confiance quant-à ces discours: car ils ne sont pas vrais. »<br /><p style="text-indent: 15px">'''Hermippe''' donc dit '''Patécus''', qui disait-souvent avoir l’âme d’'''Ésope''', raconter ces choses. <br /><p style="text-indent: 15px">'''VII.''' Or il est absurde et dépourvu de courage celui rejetant par la crainte de la perte l’acquisition des choses qu’il faut; car ainsi quelqu’un n’aimerait pas la richesse, n’aimerait pas la gloire, n’aimerait pas la sagesse étant survenue à lui, craignant (par crainte) d’en être privé. Et en effet nous voyons la vertu, au prix de laquelle aucune possession n’est plus grande, ni plus agréable, déplacée (chassée) par des maladies et des breuvages; et rien de plus n’être pour l’exemption-de-crainte à '''Thalès''' lui-même ne s’étant pas marié, s’il n’avait pas évité la possession et d’amis et de parents et de patrie. Mais même il eut un fils adoptif se l’étant fait tel lui-même, celui de sa sœur, comme on dit '''Cybisthe'''.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f7.item <u>Plutarque, Vie de Solon</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f27.item ''chap. II''], traduction littérale et juxtalinéaire présentant le mot à mot français en regard des mots grecs correspondants, par une société de professeurs et d’helléniste, 1862</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ====== <div style="text-align: center;">Paragraphe XV.</div> ====== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;"> Testament d’inhumation de '''Thalès'''.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''XV.''' Καὶ φόβοι τινὲς ἐκ δεισιδαιμονίας ἅμα καὶ φάσματα κατεῖχε τὴν πόλιν, οἵ τε μάντεις ἄγη καὶ μιασμοὺς δεομένους καθαρμῶν προφαίνεσθαι διὰ τῶν ἱερῶν ἠγόρευον. Οὕτω δὴ μετάπεμπτος αὐτοῖς ἧκεν ἐκ Κρήτης Ἐπιμενίδης ὁ Φαίστιος, ὃν ἕβδομον ἐν τοῖς σοφοῖς καταριθμοῦσιν ἔνιοι τῶν οὐ προσιεμένων τὸν Περίανδρον. Ἐδόκει δέ τις εἶναι θεοφιλὴς καὶ σοφὸς περὶ τὰ θεῖα τὴν ἐνθουσιαστικὴν καὶ τελεστικὴν σοφίαν, διὸ καὶ παῖδα νύμφης ὄνομα Βάλτης καὶ Κούρητα νέον αὐτὸν οἱ τότε ἄνθρωποι προσηγόρευον. <br /><p style="text-align: center">[...]<br /><p style="text-indent: 15px; text-align: justify;">Τὸ δὲ μέγιστον, ἱλασμοῖς τισι καὶ καθαρμοῖς καὶ ἱδρύσεσι κατοργιάσας καὶ καθοσιώσας τὴν πόλιν ὑπήκοον τοῦ δικαίου καὶ μᾶλλον εὐπειθῆ πρὸς ὁμόνοιαν κατέστησε. Λέγεται δὲ τὴν Μουνυχίαν ἰδὼν καὶ καταμαθὼν πολὺν χρόνον, εἰπεῖν πρὸς τοὺς παρόντας ὡς τυφλόν ἐστι τοῦ μέλλοντος ἄνθρωπος· ἐκφαγεῖν γὰρ ἂν Ἀθηναίους τοῖς αὑτῶν ὀδοῦσιν, εἰ προῄδεσαν ὅσα τὴν πόλιν ἀνιάσει τὸ χωρίον· ὅμοιον δέ τι καὶ Θαλῆν εἰκάσαι λέγουσι· κελεῦσαι γὰρ αὐτὸν ἔν τινι τόπῳ τῆς Μιλησίας φαύλῳ καὶ παρορωμένῳ τελευτήσαντα θεῖναι, προειπὼν ὡς ἀγορά ποτε τοῦτο Μιλησίων ἔσται τὸ χωρίον. Ἐπιμενίδης μὲν οὖν μάλιστα θαυμασθείς, καὶ χρήματα διδόντων πολλὰ καὶ τιμὰς μεγάλας τῶν Ἀθηναίων, οὐδὲν ἢ θαλλὸν ἀπὸ τῆς ἱερᾶς ἐλαίας αἰτησάμενος καὶ λαβὼν ἀπῆλθεν. </div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://remacle.org/bloodwolf/historiens/Plutarque/solon.htm <u>Plutarque, Vie de Solon</u>], ''chap. II'', ''§15'', traduction par [[w:Dominique_Ricard|Dominique Ricard]], 1844<br />(également disponible une édition de 1853 [https://remacle.org/bloodwolf/historiens/Plutarque/solonpierrron.htm ici] et de 1862 [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f26.item là])</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 390px; border: 2px solid; text-indent: 15px"><br /><div style="margin: 0 2em; text-align: justify; direction: ltr;">'''XV.''' Au chagrin que ces pertes causèrent à ceux-ci [les ''Athéniens''], se joignirent des craintes superstitieuses dont la ville [''Athènes''] fut frappée, et qui venaient d’apparitions de spectres et de fantômes. Les devins déclarèrent aussi que l’état des victimes qu’ils avaient offertes annonçait des crimes et des profanations qu’il fallait expier. On fit donc venir de ''Crète'' [[w:Épiménide|'''Épiménide''']] [[#Épiménide|<span id="Épiménide_back"><sup>'''I'''</sup></span>]] le [[w:Phaistos|''Phestien'']] [[#Phaistos|<span id="Phaistos_back"><sup>'''II'''</sup></span>]], qui est mis au nombre des sept sages par ceux qui n’y comptent pas '''Périandre'''. Il passait pour un homme chéri des dieux, doué d’une grande sagesse, fort instruit des choses divines, surtout versé dans la science des inspirations et dans la connaissance des mystères; on l’appelait, même de son vivant, le nouveau [[w:Curètes|'''Curète''']], le fils de la nymphe '''Balté'''.<br /><p style="text-align: center">[...]<br /><p style="text-indent: 15px; text-align: justify;">Mais ce qui était plus important, il fit un grand nombre d’expiations et de sacrifices, il fonda plusieurs temples; et par ces différentes cérémonies il purifia entièrement la ville, en bannit l’impiété et l’injustice, et la rendit plus soumise, plus disposée à l’union et à la paix. On rapporte aussi que lorsqu’il vit le fort de [[w:Munichie|''Munychium'']] [[#Munichie|<span id="Munichie_back"><sup>'''III'''</sup></span>]], il le considéra longtemps, et dit à ceux qui l’accompagnaient : Que les hommes sont aveugles sur l’avenir ! Si les ''Athéniens'' pouvaient prévoir tous les maux que ce lieu doit un jour causer à leur ville, ils l’emporteraient à belles dents ». '''Thalès''' eut aussi, dit-on, un pressentiment à peu près semblable. Il ordonna qu’on l’enterrât dans le lieu le plus sauvage et le plus désert du territoire de ''Milet''; et il prédit aux ''Milésiens'' qu’un jour leur marché public y serait transporté. Les ''Athéniens'', pleins de reconnaissance et d’admiration pour '''Épiménide''', voulurent le combler d’honneurs et de présents; mais il ne demanda qu’une branche de l’olivier sacré, qui lui fut accordée, et il s’en retourna en ''Crète''.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/viesdeshommesill01plut/page/n6/mode/1up?view=theater <u>Vie des Hommes Illustres de Plutarque</u>], [https://archive.org/details/viesdeshommesill01plut/page/182/mode/1up?view=theater ''Solon''], ''Chap. II'', ''§15'',[https://archive.org/details/viesdeshommesill01plut/page/185/mode/1up?view=theater p.185], traduit par [[w:Alexis_Pierron|Alexis Pierron]], professeur au lycée Louis-le-Grand, 1877<br />(également disponible une édition de 1853 [[s:Vies_des_hommes_illustres/Solon|ici]])</div> {{Boîte déroulante début|titre=NdA trad. par Alexis Pierron de 1877|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Épiménide_back|<span id="Épiménide"><sup>I</sup></span>]] Du nom propre grec ancien Ἐπιμενίδης / Epimenídēs [[wikt:en:Ἐπιμενίδης#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px">Poète, philosophe et [[w:Iatromante|''iatromante'']] crétois.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] milieu du [[w:VIe_siècle_av._J.-C.|VI<sup>ème</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]]) <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Phaistos_back|<span id="Phaistos"><sup>II</sup></span>]] Du nom propre grec ancien Φαιστός / Phaistós [[wikt:en:Φαιστός#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px">Ancienne ville du Sud de la [[w:Histoire_de_la_Crète#Antiquité|''Crète'']].<br /><br /><p style="margin: 0 2em; text-indent: 15px">[[#Munichie_back|<span id="Munichie"><sup>III</sup></span>]] Du nom propre grec ancien Μουνιχία / Mounikhia [[wikt:en:Μουνυχία#Grec_ancien|(en)]] ;<br /><p style="margin: 0 2em; text-indent: 15px">Nom d’une colline du [[w:Le_Pirée|''Pirée'']] et de l’[[w:Port_de_Munichie|un des ports du ''Pirée'']].'''<br/><br/></div> {{Boîte déroulante fin}} <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">'''XII.''' Au chagrin que ces pertes causèrent à ceux-ci, se joignirent des craintes superstitieuses dont la ville fut frappée, et qui venaient d’apparitions de spectres et de fantômes. Les devins déclarèrent aussi que l’état des victimes annonçait des crimes et des profanations qu’il fallait expier. On fit donc venir de ''Crète'' '''Épiménide''' le ''Phestien'' qui est mis au nombre des sept sages par ceux qui n’y comptent pas '''Périandre'''. Il passait pour un homme chéri des dieux, doué d’une grande sagesse, fort instruit des choses divines, surtout versé dans la science des inspirations et dans la connaissance des mystères; on l’appelait, même de son vivant, le nouveau '''Curète''', le fils de la nymphe '''Balté'''.<br /><p style="text-align: center">[...]<br /><p style="text-indent: 15px; text-align: justify;">Mais ce qui était plus important, il fit un grand nombre d’expiations et de sacrifices; il fonda plusieurs temples; et par ces différentes cérémonies, il purifia entièrement la ville, en bannit l’impiété et l’injustice, et la rendit plus soumise, plus disposée à l’union et à la paix. On rapporte aussi que lorsqu’il vit ''Munychie'', il la considéra longtemps, et dit à ceux qui l’accompagnaient :<br /><p style="text-align: justify; text-indent: 15px"> « Que les hommes sont aveugles sur l’avenir! Si les ''Athéniens'' pouvaient prévoir tous les maux que ce lieu doit un jour causer à leur ville, il l’emporteraient à belles dents. »<br /><p style="text-align: justify; text-indent: 15px"> '''Thalès''' eut aussi, dit-on, un pressentiment à peu près semblable. Il ordonna qu’on l’enterrât dans le lieu le plus sauvage et le plus désert du territoire de ''Milet''; et il prédit aux ''Milésiens'' qu’un jour leur marché public y serait transporté. Les ''Athéniens'', pleins de reconnaissance et d’admiration pour '''Épiménide''', voulurent le combler d’honneurs et de présents; mais il ne demanda qu’une branche de l’olivier sacré, qui lui fut accordée, et il s’en retourna en ''Crète''.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f7.item <u>Plutarque, Vie de Solon</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f58.item ''chap. II''], traduction correcte et précédée du texte grec, par une société de professeurs et d’helléniste, 1862<br />(également disponible une édition de 1844 [https://remacle.org/bloodwolf/historiens/Plutarque/solon.htm#1a ici] et de 1829 [[s:Les_Vies_des_hommes_illustres/Vie_de_Solon|là]])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Et certaines craintes nées de la superstition en-même-temps aussi des apparitions occupaient la ville; et les devins disaient des impiétés et des souillures ayant-besoin de purifications être indiquées par les victimes. Et ainsi vint à eux mandé (ils firent venir) de ''Crète'' '''Épiménide''' le ''Phestien'', que quelques-uns de ceux n’admettant pas '''Périandre''' comptent le septième parmi les sages. Or il avait-la-réputation d’être un homme ami-des-dieux, et habile dans la science de-l’inspiration et des-mystères. C’est-pourquoi les hommes d’alors appelaient lui et fils de la nymphe de nom (nommée) '''Balté''', et nouveau '''Curète'''.<br /><p style="text-align: center">[...]<br /><p style="text-indent: 15px; text-align: justify;">Mais le plus grand (le plus important), ayant initié-aux-mystères et ayant purifié la ville par certaines expiations et purifications et fondations, il la rendit prêtant-l’oreille à la justice et plus obéissante pour la concorde. Et il est dit, ayant vu ''Munychie'' et l’ayant examinée un temps long, avoir dit à ceux présents, que l’homme est un être aveugle sur l’avenir ; car les ''Athéniens'' avoir dû manger ''Munychie'' avec les dents d’eux-mêmes, s’ils avaient prévu en combien de choses cette place affligera la ville. Et on dit aussi '''Thalès''' avoir conjecturé quelque chose de semblable; lui avoir ordonné en effet de placer lui ayant cessé de vivre dans un certain lieu de la ''Milésie'' méprisé et dédaigné, ayant prédit que cet endroit sera (serait) un jour le marché des ''Milésiens''. '''Épiménide''' donc ayant été admiré très-grandement, et les ''Athéniens'' lui donnant des sommes nombreuses et des honneurs grands, n’ayant demandé rien qu’un rameau détaché de l’olivier sacré et l’ayant pris (reçu) s’en alla.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f7.item <u>Plutarque, Vie de Solon</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f59.item ''chap. II''], traduction littérale et juxtalinéaire présentant le mot à mot français en regard des mots grecs correspondants, par une société de professeurs et d’helléniste, 1862</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto; color: #3366BB">═✳═</div> === [[w:Œuvres_morales|Œuvres morales]] [[#Œuvres_morales|<span id="Œuvres_morales_back"><sup>'''I'''</sup></span>]] === <div style="text-align: center; margin: 0 1em;">Ensemble de 78 textes de traitant de sujets extrêmement variés (religieux, éthiques, politiques, philosophiques, littéraires, historiques), et s'inscrivant dans des genres littéraires également divers (traité, différentes sortes de dialogues, lettres, réponses à des Questions ([[wikt:ζήτημα#Grec_ancien|''zetemata'']]), « dits » ([[w:Apophtegme|''apophtegmes'']])).</div> {{Boîte déroulante début|titre=NdA Le Banquet des Septs Sages|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Cléobuline_back|<span id="Cléobuline"><sup>I</sup></span>]] En grec ancien Ἠθικὰ / Ethikà [[wikt:en:ἠθικός#Ancient_Greek|(en)]], «1. Relatif au caractère ou au tempérament : • (d’une personne) Qui exprime ou manifeste sa nature ; • (théâtre) Conforme au personnage. 2. Éthique moral (relatif à la moralité) : (philosophie) Relatif à l’éthique (l’étude des principes régissant la conduite juste ou injuste) ; (d’un texte) qui traite de la conduite et de la vertu. 3. (rhétorique) Empreint de tact. » ; <br /><p style="margin: 0 2em; text-indent: 15px;">➥ du nom commun ἦθος / êthos [[wikt:en:ἦθος#Ancient_Greek|(en)]], « 1. Le lieu habituel ou coutumier (de quelque chose) : • Le domicile ou le lieu de résidence (d’une personne) ; • Le territoire (d’un animal). 2. Le caractère ; le tempérament : • (théâtre) Personnage (dramatique). 3. La coutume ; l’habitude : • (au pluriel) Les manières ; l’étiquette. » ;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ +‎ du suffixe adjectival -ῐκός/-ĭkós, « relatif à, à la manière de ; -ique ».<br /><br /><p style="margin: 0 2em; text-indent: 15px;">En latin Moralia ; de l’adjectif mōrālis [[wikt:en:moralis#Latin|(en)]], « Qui a trait aux mœurs ou à l'éthique ; moral. » ;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ du nom commun mōs [[wikt:en:mos#Latin|(en)]], « 1. Manière d’agir ; comportement ; conduite. 2. Coutume ; habitude ; pratique ; usage. 3. (surtout au pluriel) Caractère ; disposition ; inclination ; tempérament. 4. Volonté ; obstination ; humeur ; caprice. 5. (sens dérivé) Qualité ; nature ; mode ; façon. 6. (sens dérivé) Précepte ; loi ; règle. 7. (au pluriel uniquement) mœurs ; principes »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ + du suffixe adjectival -ālis [[wikt:en:-alis#Latin|(en)]]. Utilisé pour la première fois par Cicéron pour traduire le terme grec ancien ēthikós, « moral ». <br /><br /><p style="margin: 0 2em; text-indent: 15px;">En retraçant l’usage de l’adjectif ἠθικός à partir de la Rhétorique d’Aristote, le professeur de littérature latine [https://cv.hal.science/charles-guerin Charles Guérin] démontre que Cicéron l’utilise dans son dernier traité rhétorique non comme un équivalent du style moyen, mais comme une catégorie nouvelle permettant d’opposer éloquence du ''mouere'' [[wikt:en:movere#Latin|(en)]] et éloquence du ''conciliare'' [[wikt:en:conciliare#Latin|(en)]]. Cicéron réintroduit ainsi dans son traité la notion de conciliation du public qu’il avait tout d’abord éliminée de son architecture théorique (au profit de la notion de ''delectare'' [[wikt:en:delectare#Latin|(en)]]) afin de garantir la cohérence conceptuelle de sa doctrine. L’ἠθικόν correspond ainsi à l’idée d’une adaptation du style à l’orateur, non sur le mode pragmatique défendu par Aristote (chez qui la λέξις ἠθική désigne l’adaptation du style aux caractéristiques concrètes de l’orateur), mais sur un mode idéalisant : l’ἠθικόν est une catégorie stylistique prescriptive, celle du style de l’orateur accompli [https://hal.science/hal-03189440 {{Info|<sup>🔍</sup>|Charles Guérin. Orator 128: Cicéron et la catégorie rhétorique de l’ethikon. Pierre Chiron; Carlos Lévy. Les noms du style, Peeters, pp.143-164, 2010. ⟨hal-03189440⟩}}].<br /><br /></div> {{Boîte déroulante fin}} ==== Le Banquet des Sept Sages ==== {| cellpadding="0" align="{{{align|right}}}" style="margin-left: 2em; width:40%; border-spacing:3px; text-align:center; background-color:#F8F9FA; border:2px solid #C8CCD1" |- | style="border:solid 1px #F8F9FA" | '''Manuscrit''' [https://archive.org/details/p.-oxy.-16/Oxyrhynchus%20Papyri/P.%20Oxy.%2052/page/n66/mode/1up {{info|<sup>➕</sup>|The Oxyrhynchus Papyri, Volume LII, 1984}}] [https://books.google.fr/books?id=qfl1xwEACAAJ&lpg=PA1059&hl=fr&pg=PA1171#v=onepage&q=Plutarque&f=false {{info|<sup>➕➕</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume Vb, §210 - Plutarque de Chéronée, p.1171}}] |- style="font-size:8pt; line-height:10pt; vertical-align:middle" | align="center" | <div style="margin-right: 1em; padding:0 0 4px 0; text-align:justify;">{{{légende| Le P. Oxy. 3685 conserve les vestiges assez détériorés de deux colonnes du Banquet des Sept Sages, datant de la première moitié du [[w:IIe_siècle|II<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]], c’est-à-dire presque contemporain de '''Plutarque'''. Ce petit fragment de papyrus (9,6 x 8 cm) présente un intérêt à deux titres : * d’une part, sa datation étant proche de l’époque de '''Plutarque''', il apporte des éléments sur l’authenticité de l’œuvre ; * d’autre part, une partie du texte se retrouve également chez '''Stobée'''. Les doutes quant à l'attribution du Banquet des Sept Sages à Plutarque ne semblent être apparus qu'à une époque relativement récente ; en effet, l'ouvrage figure dans ce que l'on appelle le « Catalogue de Lamprias », une liste des œuvres de Plutarque dressée au [[w:IIIe_siècle|III<sup>ème</sup>]] ou au [[w:IVe_siècle|IV<sup>ème</sup>]] siècle {{Info|EC|de l’Ère Commune}}. Toutefois, ces réserves ont désormais été levées de manière convaincante par J. Defradas pp.7-12 de l’édition de la Budé de 1985. NB : Les [[w:Papyrus_d%27Oxyrhynque|''papyrus d’Oxyrhynque'']] constituent un ensemble de manuscrits découverts à la fin du [[w:XIXe_siècle|XIX<sup>ème</sup>]] et au début du [[w:XXe_siècle|XX<sup>ème</sup>]] siècles {{Info|EC|de l’Ère Commune}} par les papyrologues [[w:Bernard_Pyne_Grenfell|'''Bernard Pyne Grenfell''']] et [[w:Arthur_Surridge_Hunt|'''Arthur Surridge Hunt''']], dans une ancienne décharge située près d’[[w:Oxyrhynque|''Oxyrhynque'']], en ''Égypte''.}}}</div> |} <div style="text-align: center; margin: 0 1em;">Dialogue faisant intervenir 20 personnages, dont une liste des sept sages : '''Thalès''', [[w:Solon|'''Solon''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Solon_back|<sup>🔄</sup>]], [[w:Bias_de_Priène|'''Bias''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Bias_back|<sup>🔄</sup>]], [[w:Chilon|'''Chilon''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Chilon_back|<sup>🔄</sup>]], [[w:Cléobule|'''Cléobule''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Cléobule_back|<sup>🔄</sup>]], [[w:Pittacos_de_Mytil%C3%A8ne|'''Pittacos''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Pittacos_back|<sup>🔄</sup>]], [[w:Périandre|'''Périandre''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Périandre_back|<sup>🔄</sup>]].</div> <div style="text-align: left; margin: 0 1em;">À ceux-ci se rajoutent : * [[w:Anacharsis|'''Anacharsis''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Anacharsis_back|<sup>🔄</sup>]], * '''[[w:Ésope|Ésope]]''' [[#Ésope|<span id="Ésope_back"><sup>'''I'''</sup></span>]], * '''Dioclès''' le ''devin'' et narrateur (possiblement fictif) [[#Dioclès_Cléodème_Chersias|<span id="Dioclès_Cléodème_Chersias_back"><sup>'''II'''</sup></span>]], * '''Nicarque''' le destinataire du récit (possiblement fictif), * [[w:Cléobuline|'''Cléobuline''']] [[#Cléobuline|<span id="Cléobuline_back"><sup>'''III'''</sup></span>]], * '''Mélissa''' la conjointe de '''Périandre''', * '''Niloxène''', * '''Alexidème''' un bâtard du ''tyran'' [[w:Thrasybule_de_Milet|'''Thrasybule''' de ''Milet'']], * '''Ardalus''' le joueur de flûte [[w:Trézène_(ville)|''trézénien'']] [[#Trézène|<span id="Trézène_back"><sup>'''IV'''</sup></span>]], * '''Cléodème''' le ''médecin'' (possiblement fictif) [[#Dioclès_Cléodème_Chersias|<sup>'''II'''</sup>]], * '''Mnésiphile''' un disciple de '''Solon''', * '''Chersias''' le ''poète'' (possiblement fictif) [[#Dioclès_Cléodème_Chersias|<sup>'''II'''</sup>]], * [[w:Gorgias|'''Gorgias''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Gorgias_back|<sup>🔄</sup>]].</div> {{Boîte déroulante début|titre=NdA Le Banquet des Septs Sages|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Ésope_back|<span id="Ésope"><sup>I</sup></span>]] Du nom propre grec ancien Αἴσωπος / Aísōpos ;<br /><p style="margin: 0 2em; text-indent: 15px;">Sous le nom d’Ésope ont circulé dans l’antiquité différents recueils de fables qui ont connu un succès universel et ont été traduites et imitées dans toute la tradition littéraire postérieure. On peut y voir l’expression d’une éthique populaire, rationaliste et cosmopolite, qui n’est pas sans intérêt pour l’histoire de la philosophie. Selon Hérodote, (livre II, chap. 134), il serait un ancien esclave d’Iadmon de ''Samos''.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] seconde moitié du [[w:VIe_siècle_av._J.-C.|VI<sup>ème</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]], selon la Souda, ({{Info|s.v.|Abréviation du latin sub verbo, « À l’article, à l’entrée, au mot. »}} Αἴσωπος, Αι 334), il aurait été précipité du haut des [[w:Phédriades|''Roches Phédriades'']] à ''Delphes'' en la 54<sup>ème</sup> Olympiade (564/561))[https://books.google.fr/books?id=DrvWAAAAMAAJ&newbks=1&newbks_redir=0&lpg=PA5&dq=bibliogroup%3A%22Dictionnaire%20des%20philosophes%20antiques%22&hl=fr&pg=PA240#v=onepage&q&f=false {{Info|<sup>🔍</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume III, §60 - Ésope (Αἴσωπος)}}] <br /><br /><p style="margin: 0 2em; text-indent: 15px;">'''[[#Dioclès_Cléodème_Chersias_back|<span id="Dioclès_Cléodème_Chersias"><sup>II</sup></span>]] D’après l’historienne [https://research-bulletin.chs.harvard.edu/authors/zoe-stamatopoulou/ Zoe Stamatopoulou] [https://research-bulletin.chs.harvard.edu/2017/04/17/periander-plutarch-symposium/ {{info|<sup>🔍</sup>|Stamatopoulou, Zoe. “Constructing Periander in Plutarch’s Symposium of the Seven Sages.” CHS Research Bulletin 5, no. 1 (2016). http://nrs.harvard.edu/urn-3:hlnc.essay:StamatopoulouZ.Constructing_Periander.2016.}}], il s’agit de non-Sages individualisés par leur profession. <br /><br /><p style="margin: 0 2em; text-indent: 15px;">'''[[#Cléobuline_back|<span id="Cléobuline"><sup>III</sup></span>]] Du nom propre grec ancien Κλεοβουλίνη / Kleoboulinè ;<br /><p style="margin: 0 2em; text-indent: 15px">➥ de Κλεόβουλος / Kleóboulos [[wikt:en:Κλεόβουλος#Ancient_Greek|(en)]], « Cléobule, le père de Cléobuline » <br /><p style="margin: 0 2em; text-indent: 15px">➥ du suffixe adjectival féminin -ῑ́νη / -ī́nē [[wikt:en:-ίνη#Ancient_Greek|(en)]], relatif à la matière, au temps, etc. : « fait de, pendant la durée de » ;<br /><p style="margin: 0 2em; text-indent: 15px">Philosophe et poétesse grecque, célèbre pour ses énigmes, fille du [[w:Tyran|''tyran'']] de [[w:Rhodes|''Rhodes'']], Cléobule, qui la surnommerait Εὔμητις / Eúmētis, « la Prudente » selon Plutarque.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:VIe_siècle_av._J.-C.|VI<sup>ème</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]], originaire de [[w:Lindos|''Lindos'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Lindos_back|<sup>🔄</sup>]] sur l’île de ''Rhodes'') <br /><br /><p style="margin: 0 2em; text-indent: 15px;">'''[[#Trézène_back|<span id="Trézène"><sup>IV</sup></span>]] Du nom propre grec ancien Τροιζήν / Troizḗn [[wikt:en:Τροιζήν#Ancient_Greek|(en)]] ;<br /><p style="margin: 0 2em; text-indent: 15px">[[w:polis|Cité grecque]] du [[w:Péloponnèse|''Péloponnèse'']], sur la côte nord de l’[[w:Argolide|''Argolide'']]. '''<br/><br/></div> {{Boîte déroulante fin}} ===== <div style="text-align: center;">Paragraphe I.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">'''Dioclès''' raconte le Banquet des Sept Sages organisé par '''Périandre''', pendant lequel il fût l’hôte de '''Thalès'''.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§1. Ἦ που προϊὼν ὁ χρόνος, ὦ '''Νίκαρχε''', πολὺ σκότος ἐπάξει τοῖς πράγμασι καὶ πᾶσαν ἀσάφειαν, εἰ νῦν ἐπὶ προσφάτοις οὕτω καὶ νεαροῖς λόγοι ψευδεῖς συντεθέντες ἔχουσι πίστιν. οὔτε γὰρ μόνων, ὡς ὑμεῖς ἀκηκόατε, τῶν ἑπτὰ γέγονε τὸ συμπόσιον, ἀλλὰ πλειόνων ἢ δὶς τοσούτων (ἐν οἷς καὶ αὐτὸς ἤμην, συνήθης μὲν ὢν '''Περιάνδρῳ''' διὰ τὴν τέχνην, ξένος δὲ '''Θάλεω'''· παρ´ ἐμοὶ γὰρ κατέλυσεν ὁ ἀνὴρ '''Περιάνδρου''' κελεύσαντος), οὔτε τοὺς λόγους ὀρθῶς ἀπεμνημόνευσεν ὅστις ἦν ὑμῖν ὁ διηγούμενος· ἦν δ´ ὡς ἔοικεν οὐδεὶς τῶν παραγεγονότων. ἀλλ´ ἐπεὶ σχολή τε πάρεστι πολλὴ καὶ τὸ γῆρας οὐκ ἀξιόπιστον ἐγγυήσασθαι τὴν ἀναβολὴν τοῦ λόγου, προθυμουμένοις ὑμῖν ἀπ´ ἀρχῆς ἅπαντα διηγήσομαι. </div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §1'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§1. '''D<span style ="font-size:85%;">IOCLÈS</span>'''. Certainement le long cours des âges, mon cher '''Nicarque''', jettera sur les faits d’épaisses ténèbres et une complète incertitude, puisque dès aujourd’hui, à propos de choses si récentes et si nouvelles, des relations mensongères et controuvées obtiennent crédit. Car d’abord le banquet en question ne se composait pas seulement des sept sages, comme vous autres l’avez ouï dire. Les convives étaient plus du double de ce nombre. J’en faisais moi-même partie, comme familier de '''Périandre''' en raison de notre profession commune, et comme hôte de '''Thalès''' : ce dernier était en effet descendu chez moi sur la recommandation de '''Périandre'''. Ensuite, on ne vous en a pas rapporté fidèlement les entretiens lorsqu’on vous a fait ce récit. Il faut que celui de qui vous le tenez n’ait pas été un des convives. Mais puisque nous avons un ample loisir et que la vieillesse est un garant trop peu sûr pour nous autoriser à remettre cet entretien, je vais, suivant votre désir unanime, vous en raconter tous les détails à partir du commencement. </div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §1'', traduction par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870<br/>(également disponible [[s:Page:Plutarque_-_Œuvres_complètes_de_Plutarque_-_Œuvres_morales_et_œuvres_diverses,_tome_1,_1870.djvu/424|ici]])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">'''D<span style ="font-size:85%;">IOCLÈS</span>'''. Quelle incertitude et quelle obscurité la succession des temps ne doit-elle pas répandre sur l’histoire, mon cher '''Nicarque''', puisque, dans des faits récents, et qui se sont passés presque sous nos yeux, le faux prend la place du vrai ? Ce banquet n’était pas, comme on vous l’a dit, composé seulement des sept sages ; les convives étaient plus du double de ce nombre. J’y assistai moi-même, et comme ami de '''Périandre''', avec qui ma profession ma lié depuis longtemps [[#Dioclès_NdT_DR|<span id="Dioclès_NdT_DR_back"><sup>1</sup></span>]], et comme hôte de '''Thalès''', à qui '''Périandre''' avait fait marquer son logement chez moi. Celui qui vous a fait le récit de ce qui s’y est passé n’en était sûrement pas, et vous a trompé sur presque tous les points. Mais, puisque nous en avons le loisir, et que notre âge avancé ne nous permet guère de différer, je vais vous satisfaire et vous en raconter tous les détails.</div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Dioclès_NdT_DR_back|<span id="Dioclès_NdT_DR"><sup>1.</sup></span>]] Dioclès était devin.''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' pp.325, 326, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe II.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage de la simplicité de '''Thalès''', de sa mesure de la pyramide d’''Égypte'' [[#mesure_pyramide|<span id="mesure_pyramide_back"><sup>'''I'''</sup></span>]], et de son aversion des [[w:Tyran|''tyrans'']] et des rois.</div> {{Boîte déroulante début|titre=NdA Mesure de la Pyramide d’Égypte|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#mesure_pyramide_back|<span id="mesure_pyramide"><sup>I</sup></span>]]'''<br/><br/></div> {{Boîte déroulante fin}} :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§2. Παρεσκευάκει μὲν γὰρ οὐκ ἐν τῇ πόλει τὴν ὑποδοχὴν ὁ Περίανδρος, ἀλλ´ ἐν τῷ περὶ τὸ Λέχαιον ἑστιατορίῳ παρὰ τὸ τῆς Ἀφροδίτης ἱερόν, ἧς ἦν καὶ ἡ θυσία. μετὰ γὰρ τὸν ἔρωτα τῆς μητρὸς αὐτοῦ προεμένης τὸν βίον ἑκουσίως οὐ τεθυκὼς τῇ Ἀφροδίτῃ, τότε πρῶτον ἔκ τινων ἐνυπνίων τῆς Μελίσσης ὥρμησε τιμᾶν καὶ θεραπεύειν τὴν θεόν. Τῶν δὲ κεκλημένων ἑκάστῳ συνωρὶς ἱκανῶς κεκοσμημένη προσήχθη· καὶ γὰρ ὥρα θέρους ἦν, καὶ τὴν ὁδὸν ἅπασαν ὑπὸ πλήθους ἁμαξῶν καὶ ἀνθρώπων ἄχρι θαλάττης κονιορτὸς καὶ θόρυβος κατεῖχεν. ὁ μέντοι Θαλῆς τὸ ζεῦγος ἐπὶ ταῖς θύραις ἰδὼν καὶ μειδιάσας ἀφῆκεν. ἐβαδίζομεν οὖν ἐκτραπόμενοι διὰ τῶν χωρίων, καθ´ ἡσυχίαν, καὶ μεθ´ ἡμῶν τρίτος ὁ Ναυκρατίτης Νειλόξενος, ἀνὴρ ἐπιεικὴς καὶ τοῖς περὶ Σόλωνα καὶ Θαλῆν γεγονὼς ἐν Αἰγύπτῳ συνήθης. ἐτύγχανε δὲ πρὸς Βίαντα πάλιν ἀπεσταλμένος· ὧν δὲ χάριν οὐδ´ αὐτὸς ᾔδει, πλὴν ὑπενόει πρόβλημα δεύτερον αὐτῷ κομίζειν ἐν βιβλίῳ κατασεσημασμένον· εἴρητο γάρ, εἰ Βίας ἀπαγορεύσειεν, ἐπιδεῖξαι τοῖς σοφωτάτοις Ἑλλήνων τὸ βιβλίον. « Ἕρμαιον » ὁ Νειλόξενος ἔφη « μοι γέγονεν ἐνταῦθα λαβεῖν ἅπαντας ὑμᾶς, καὶ κομίζω τὸ βιβλίον ὡς ὁρᾷς ἐπὶ τὸ δεῖπνον. » ἅμα δ´ ἡμῖν ἐπεδείκνυε. Καὶ ὁ Θαλῆς γελάσας « εἴ τι κακόν, » εἶπεν, « αὖθις εἰς Πριήνην· διαλύσει γὰρ ὁ Βίας, ὡς διέλυσεν αὐτὸς τὸ πρῶτον. » « Τί δ´ ἦν, » ἔφην ἐγώ, « τὸ πρῶτον; » « Ἱερεῖον, » εἶπεν, « ἔπεμψεν αὐτῷ, κελεύσας τὸ πονηρότατον ἐξελόντα καὶ χρηστότατον ἀποπέμψαι κρέας. ὁ δ´ ἡμέτερος εὖ καὶ καλῶς τὴν γλῶτταν ἐξελὼν ἔπεμψεν· ὅθεν εὐδοκιμῶν δῆλός ἐστι καὶ θαυμαζόμενος. » « Οὐ διὰ ταῦτ´ » ἔφη « μόνον » ὁ Νειλόξενος, « ἀλλ´ οὐ φεύγει τὸ φίλος εἶναι καὶ λέγεσθαι βασιλέων καθάπερ ὑμεῖς, ἐπεὶ σοῦ γε καὶ τἄλλα θαυμάζει, καὶ τῆς [[wikt:en:πυραμίδος#Ancient_Greek|πυραμίδος]] τὴν μέτρησιν ὑπερφυῶς ἠγάπησεν, ὅτι πάσης ἄνευ πραγματείας καὶ μηδενὸς ὀργάνου δεηθεὶς ἀλλὰ τὴν βακτηρίαν στήσας ἐπὶ τῷ πέρατι τῆς σκιᾶς ἣν ἡ πυραμὶς ἐποίει, γενομένων τῇ ἐπαφῇ τῆς ἀκτῖνος δυεῖν τριγώνων, ἔδειξας ὃν ἡ σκιὰ πρὸς τὴν σκιὰν λόγον εἶχε τὴν πυραμίδα πρὸς τὴν βακτηρίαν ἔχουσαν. ἀλλ´, ὅπερ ἔφην, διεβλήθης μισοβασιλεὺς εἶναι, καί τινες ὑβριστικαί σου περὶ τυράννων ἀποφάσεις ἀνεφέροντο πρὸς αὐτόν, ὡς ἐρωτηθεὶς ὑπὸ Μολπαγόρου τοῦ Ἴωνος τί παραδοξότατον εἴης ἑωρακώς, ἀποκρίναιο ‘τύραννον γέροντα,’ καὶ πάλιν ἔν τινι πότῳ, περὶ τῶν θηρίων λόγου γενομένου, φαίης κάκιστον εἶναι τῶν μὲν ἀγρίων θηρίων τὸν τύραννον, τῶν δ´ ἡμέρων τὸν κόλακα· ταῦτα γάρ, εἰ καὶ πάνυ προσποιοῦνται διαφέρειν οἱ βασιλεῖς τῶν τυράννων, οὐκ εὐμενῶς ἀκούουσιν. » « Ἀλλὰ τοῦτο μέν, » εἶπεν ὁ Θαλῆς, « Πιττακοῦ ἐστιν, εἰρημένον ἐν παιδιᾷ ποτε πρὸς Μυρσίλον· ἐγὼ δὲ θαυμάσαιμ´ ἄν, » ἔφη, « οὐ τύραννον ἀλλὰ [[wikt:κυβερνήτης#Grec_ancien|'''κυβερνήτην''']] γέροντα θεασάμενος. πρὸς δὲ τὴν μετάθεσιν τὸ τοῦ νεανίσκου πέπονθα τοῦ βαλόντος μὲν ἐπὶ τὴν κύνα πατάξαντος δὲ τὴν μητρυιὰν καὶ εἰπόντος ‘οὐδ´ οὕτω κακῶς.’ διὸ καὶ Σόλωνα σοφώτατον ἡγησάμην οὐ δεξάμενον τυραννεῖν. καὶ Πιττακὸς οὗτος εἰ μοναρχίᾳ μὴ προσῆλθεν, οὐκ ἂν εἶπεν ὡς ‘χαλεπὸν ἐσθλὸν ἔμμεναι.’ Περίανδρος δ´ ἔοικεν ὥσπερ ἐν νοσήματι πατρῴῳ τῇ τυραννίδι κατειλημμένος οὐ φαύλως ἐξαναφέρειν, χρώμενος ὁμιλίαις ὑγιειναῖς ἄχρι γε νῦν καὶ συνουσίας ἀνδρῶν νοῦν ἐχόντων ἐπαγόμενος, ἃς δὲ '''Θρασύβουλος''' αὐτῷ κολούσεις τῶν ἄκρων οὑμὸς πολίτης ὑφηγεῖται μὴ προσιέμενος. γεωργοῦ γὰρ [[wikt:en:αἶρα#Ancient_Greek|αἴρας]] καὶ [[wikt:ononis|ὀνώνιδας]] ἀντὶ [[wikt:πυρός#Grec_ancien|πυρῶν]] καὶ [[wikt:κριθή#Grec_ancien|κριθῶν]] συγκομίζειν ἐθέλοντος οὐδὲν διαφέρει τύραννος ἀνδραπόδων μᾶλλον ἄρχειν ἢ ἀνδρῶν βουλόμενος· ἓν γὰρ ἀντὶ πολλῶν κακῶν ἀγαθὸν αἱ δυναστεῖαι τὴν τιμὴν ἔχουσι καὶ τὴν δόξαν, ἄνπερ ἀγαθῶν ὡς κρείττονες ἄρχωσι καὶ μεγάλων μείζονες εἶναι δοκῶσι· τὴν δ´ ἀσφάλειαν ἀγαπῶντας ἄνευ τοῦ καλοῦ προβάτων ἔδει πολλῶν καὶ ἵππων καὶ βοῶν ἄρχειν, μὴ ἀνθρώπων. ἀλλὰ γὰρ εἰς οὐδὲν προσήκοντας ἐμβέβληκεν ἡμᾶς, » ἔφη, « ὁ ξένος οὑτοσὶ λόγους, ἀμελήσας λέγειν τε καὶ ζητεῖν ἃ ἁρμόττει ἐπὶ δεῖπνον βαδίζουσιν. ἦ γὰρ οὐκ οἴει, καθάπερ ἑστιάσοντος ἔστι τις παρασκευή, καὶ δειπνήσοντος εἶναι; Συβαρῖται μὲν γὰρ ὡς ἔοικε πρὸ ἐνιαυτοῦ τὰς κλήσεις ποιοῦνται τῶν γυναικῶν, ὅπως ἐκγένοιτο κατὰ σχολὴν παρασκευασαμέναις ἐσθῆτι καὶ χρυσῷ φοιτᾶν ἐπὶ τὸ δεῖπνον· ἐγὼ δὲ πλείονος οἶμαι χρόνου δεῖσθαι τὴν ἀληθινὴν τοῦ δειπνήσοντος ὀρθῶς παρασκευήν, ὅσῳ χαλεπώτερόν ἐστιν ἤθει τὸν πρέποντα κόσμον ἢ σώματι τὸν περιττὸν ἐξευρεῖν καὶ ἄχρηστον. οὐ γὰρ ὡς ἀγγεῖον ἥκει κομίζων ἑαυτὸν ἐμπλῆσαι πρὸς τὸ δεῖπνον ὁ νοῦν ἔχων, ἀλλὰ καὶ σπουδάσαι τι καὶ παῖξαι καὶ ἀκοῦσαι καὶ εἰπεῖν ὡς ὁ καιρὸς παρακαλεῖ τοὺς συνόντας, εἰ μέλλουσι μετ´ ἀλλήλων ἡδέως ἔσεσθαι. καὶ γὰρ καὶ ὄψον πονηρὸν ἔστι παρώσασθαι, κἂν οἶνος ᾖ φαῦλος, ἐπὶ τὰς νύμφας καταφυγεῖν· σύνδειπνος δὲ κεφαλαλγὴς καὶ βαρὺς καὶ ἀνάγωγος παντὸς μὲν οἴνου καὶ ὄψου πάσης δὲ μουσουργοῦ χάριν ἀπόλλυσι καὶ λυμαίνεται, καὶ οὐδ´ ἀπεμέσαι τὴν τοιαύτην ἀηδίαν ἕτοιμόν ἐστιν, ἀλλ´ ἐνίοις εἰς ἅπαντα τὸν βίον ἐμμένει τὸ πρὸς ἀλλήλους δυσάρεστον, ὥσπερ ἑωλοκρασία τις ὕβρεως ἢ ὀργῆς ἐν οἴνῳ γενομένης. ὅθεν ἄριστα Χίλων, καλούμενος ἐχθές, οὐ πρότερον ὡμολόγησεν ἢ πυθέσθαι τῶν κεκλημένων ἕκαστον. ἔφη γὰρ ὅτι σύμπλουν ἀγνώμονα δεῖ φέρειν καὶ σύσκηνον οἷς πλεῖν ἀνάγκη καὶ στρατεύεσθαι· τὸ δὲ συμπόταις ἑαυτὸν ὡς ἔτυχε καταμιγνύειν οὐ νοῦν ἔχοντος ἀνδρός ἐστιν. ὁ δ´ Αἰγύπτιος σκελετός, ὃν ἐπιεικῶς εἰσφέροντες εἰς τὰ συμπόσια προτίθενται καὶ παρακαλοῦσι μεμνῆσθαι τάχα δὴ τοιούτους ἐσομένους, καίπερ ἄχαρις καὶ ἄωρος ἐπίκωμος ἥκων, ὅμως ἔχει τινὰ καιρόν, καὶ εἰ μὴ πρὸς τὸ πίνειν καὶ ἡδυπαθεῖν ἀλλὰ πρὸς φιλίαν καὶ ἀγάπησιν ἀλλήλων προτρέπεται, καὶ παρακαλεῖ τὸν βίον μὴ τῷ χρόνῳ βραχὺν ὄντα πράγμασι κακοῖς μακρὸν ποιεῖν. » </div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §2'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§2. La réception avait été préparée par '''Périandre''', non pas dans la ville même, mais dans son [[w:Cénacle|''cénacle'']] du port de [[w:Léchaion|''Léchée'']], près du temple de '''Vénus''' en l’honneur de laquelle il y avait même un sacrifice. Car depuis l’incestueux amour à la suite duquel sa mère avait volontairement abandonné la vie, '''Périandre''' n’avait pas sacrifié à '''Vénus''' ; et c’était alors la première fois que, d’après certains songes de '''Mélissa''' il s’était décidé à honorer la déesse et à lui rendre des hommages. Pour chacun des invités on avait amené un attelage approprié convenablement. Nous étions en été, et tout le long de la route, en raison du grand nombre de chariots et de piétons, ce n’était jusqu’à la mer que poussière et que bruit. Pourtant '''Thalès''', ayant vu l’attelage à notre porte, se mit à sourire et le renvoya. Nous partîmes donc à pied en faisant un détour, et à travers champs nous cheminâmes à loisir. Un troisième compagnon s’était joint à nous, '''Niloxène''' de ''Naucratie'', homme plein de mérite, que '''Thalès''' et '''Solon''' avaient autrefois beaucoup connu en ''Égypte''. Il se trouvait envoyé de nouveau vers '''Bias''' ; mais pour quelle mission ? Il n’en savait rien lui-même, hormis qu’il se soupçonnait porteur d’une seconde question à résoudre, contenue dans un pli cacheté; et il lui avait été dit, au cas où '''Bias''' renoncerait, de la présenter aux plus sages d’entre les Grecs. « C’est », dit '''Niloxène''', « une chance heureuse que de vous trouver ici tous, et j’apporte, comme vous voyez, cette lettre pour le banquet. » En même temps, il nous la faisait voir. '''Thalès''' se mit à rire : « Si c’est une question épineuse », dit-il, « qu’on aille encore à ''Priène'' : '''Bias''' la résoudra comme il a résolu la première. » — « Quelle était donc cette première question ? » lui demandai-je. — « Le roi d’Égypte », dit '''Thalès''', « avait envoyé à '''Bias''' une victime, en lui faisant dire d’en couper ce qu’il y avait de plus mauvais et de meilleur, et de le lui renvoyer. Notre sage, avec un discernement merveilleux, en ôta la langue et la fit porter au Roi. Voilà ce qui lui a valu une estime et une admiration si déclarée ». — « Cette raison n’est pas la seule », ajouta '''Niloxène''' ; « c’est encore, que '''Bias''' ne fuit pas, comme vous autres, l’amitié des rois eux-mêmes. Ainsi, vous, '''Thalès''', le roi d’Égypte vous admire beaucoup, et, entre autres choses, il a été, au-delà de ce qu’on peut dire, ravi de la manière dont vous avez mesuré la pyramide sans le moindre embarras et sans avoir eu besoin d’aucun instrument. Après avoir dressé votre bâton à l’extrémité de l’ombre que projetait la pyramide, vous construisîtes deux triangles par la tangence d’un rayon, et vous démontrâtes qu’il y avait la même proportion entre la hauteur du bâton et la hauteur de la pyramide qu’entre la longueur des deux ombres. Mais, comme j’ai dit, on vous accuse de détester les rois ; quelques boutades injurieuses prononcées par vous contre des ''tyrans'' ont été rapportées à [[w:Ahmôsis_II|'''Amasis''']]. Par exemple, l’Ionien '''Molpagore''' vous ayant demandé ce que vous aviez jamais vu de plus extraordinaire, vous lui auriez répondu : « C’est un tyran parvenu à la vieillesse. » Une autre fois, dans un festin, la conversation étant venue à tomber sur les bêtes féroces, vous auriez dit : « La plus méchante bête parmi les animaux sauvages, c’est le tyran, et parmi les animaux apprivoisés le flatteur. » De tels propos ne sont pas de ceux que les rois entendent avec plaisir, lors même qu’ils affectent de n’avoir rien de commun avec les tyrans. » Pour cette dernière réponse, dit '''Thalès''', elle est de '''Pittacus''' : il l’avait adressée un jour en plaisantant à '''Myrsile'''. Quant au premier propos, ce n’était pas « un tyran » que j’avais dit, mais « un [[wikt:κυβερνήτης#Grec_ancien|''pilote'']] », qui soit parvenu à la vieillesse. Toutefois, puisqu’on a changé la destination du mot, je fais comme le jeune homme qui, ayant jeté une pierre à un chien, atteignit sa belle-mère et s’écria : Même ainsi, ce n’est pas mal. » C’est pourquoi je regardai '''Solon''' comme éminemment sage lorsqu’il n’accepta pas la tyrannie ; et '''Pittacus''', s’il n’eût approché de la monarchie, n’aurait pas eu à dire : « Il est difficile d’être homme de bien. » Quant à '''Périandre''', il semble qu’ayant été saisi par le souverain pouvoir comme par une maladie de famille, il ne s’en tire pas trop mal. Il use, au moins jusqu’à présent, de sociétés salutaires. Il réunit, pour entretenir commerce avec eux, ses hommes remplis de sens ; et le conseil que lui a donné mon compatriote [[w:Thrasybule_de_Milet|'''Thrasybule''']] [[#Thrasybule|<span id="Thrasybule_back"><sup>'''I'''</sup></span>]], de décapiter l’aristocratie, il ne l’a pas accepté. Entre un laboureur qui aimerait mieux voir dans son champ de l’[[w:Ivraie|''ivraie'']] ou de l’[[w:Orobanche|''orobanche'']] que de l’orge ou du blé, et un tyran qui veut régner sur des esclaves plutôt que sur des hommes de coeur, je ne vois aucune différence. Un seul bien compense les maux nombreux attachés au pouvoir des tyrans : c’est la gloire et l’honneur qui leur sont réservés lorsque, commandant à des hommes vertueux, ils sont plus vertueux eux-mêmes, et qu’au milieu de grands ils se montrent plus grands. Ceux qui préfèrent leur sûreté en renonçant à ce beau rôle, étaient faits pour réunir sous leur main beaucoup de moutons, de chevaux et de boeufs, mais non des hommes. » « Du reste », continua '''Thalès''', « ce sont propos sans portée aucune que ceux où nous a jetés cet étranger, et nous avons omis de dire et de chercher les choses qui conviennent bien à des gens partis pour un banquet. Ne croyez-vous pas, '''Nicarque''', qu’il y ait des préparatifs à faire quand on vient prendre place à un festin, comme il y en a pour celui qui doit le donner ? Les [[w:Sybaris|''Sybarites'']] [[#Sybaris|<span id="Sybaris_back"><sup>'''II'''</sup></span>]], à ce qu’il paraît, s’y prennent un an d’avance pour adresser leurs invitations aux femmes, afin qu’elles puissent à loisir préparer leur toilette et leurs bijoux en or avant de se rendre au festin; et, selon moi, il faut plus de temps encore à un convive pour les préparatifs vraiment nécessaires, parce qu’il est plus difficile de trouver un ajustement convenable pour son moral que la vaine et inutile parure dont on s’inquiète pour son corps. Un homme sensé ne se transporte pas à un festin comme un bocal qu’il s’agit d’y remplir. Il songe à trouver là une occasion de passer tour à tour du sérieux au badinage, d’entendre et de tenir lui-même ces propos auxquels la circonstance invite les convives s’ils veulent se rendre la réunion agréable les uns aux autres. En effet on est libre de repousser un mauvais ragoût, et si le vin ne vaut rien on peut « recourir aux [[w:Naïades|''Naïades'']] »; mais un convive qui vous donne mal à la tête, qui est lourd, qui ne sait pas se conduire, vous fait perdre et vous gâte le plaisir de tout vin, de toute bonne chère, de toute musique. On n’est même pas le maître de se débarrasser aussi complétement qu’on le voudrait d’un tel désagrément. Quelques-uns en gardent tant qu’ils vivent du mécontentement les uns contre les autres : il leur semble qu’il leur reste comme un arrière-goût de viandes mal digérées, parce qu’ils conservent le souvenir d’injures ou de colères échangées dans le vin. C’est pour cela que '''Chilon''', invité hier, n’a pas voulu promettre avant d’avoir su le nom de chacun des convives : « Car on est bien obligé, a-t-il dit, de supporter un désagréable compagnon de traversée, de tente, quand il faut être sur terre ou à l’armée ; mais se mêler indifféremment à table avec les premiers venus, n’est pas le propre d’un homme sensé. » Le squelette des ''Égyptiens'', qu’ils ont la sage coutume de produire et de placer dans la salle du festin afin d’engager à se souvenir que l’on sera bientôt comme lui, survient là comme un convive assez désagréable et intempestif, mais enfin la présence s’en explique. Si cette vue n’excite pas à boire et à se réjouir, elle engage du moins à s’aimer, à se chérir les uns les autres, et elle exhorte à ne pas allonger par des tracas pénibles une existence dont la durée est si courte. </div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §2'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> {{Boîte déroulante début|titre=NdA trad. par Victor Bétolaud de 1870|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Thrasybule_back|<span id="Thrasybule"><sup>I</sup></span>]] Du nom propre grec ancien Θρᾰσῠ́βουλος / Thrăsŭ́boulos [[wikt:en:Θρασύβουλος#Ancient_Greek|(en)]] ;<br /><p style="margin: 0 2em; text-indent: 15px">➥ de l’adjectif [[wikt:θρασύς#Grec_ancien|θρᾰσύς / thrăsús]], « confiant, audacieux » ;<br /><p style="margin: 0 2em; text-indent: 15px">➥ +‎ du nom commun [[wikt:βουλή#Grec_ancien|βουλή / boulế]], « Volonté. Décision, conseil. Conseil, sénat athénien. »; du verbe [[wikt:βούλομαι#Grec_ancien|βούλομαι / boúlomai]], « Vouloir, désirer, souhaiter. Vouloir bien, consentir à. » ;<br /><p style="margin: 0 2em; text-indent: 15px">➥ +‎ -ος (-os).<br /><br /><p style="margin: 0 2em; text-indent: 15px">[[#Sybaris_back|<span id="Sybaris"><sup>II</sup></span>]] Du nom propre grec ancien Σῠ́βᾰρῐς / Sŭ́bărĭs [[wikt:en:Σύβαρις#Ancient_Greek|(en)]] ;<br /><p style="margin: 0 2em; text-indent: 15px">[[w:Colonisation grecque|Colonie grecque]] du sud de l’Italie (en [[w:Calabre|Calabre]] actuelle), fondée au [[w:VIIIe_siècle_av._J.-C.|VIII<sup>ème</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]] dans le cadre du mouvement d’établissement et d’[[w:Colonisation_grecque|''essaimage'']] des Grecs vers l’Occident, particulièrement en [[w:Grande-Grèce|''Grande-Grèce'']]. Réputée dès l’Antiquité pour sa richesse devenue proverbiale, ainsi que pour son emprise sur les peuples voisins et différentes cités grecques de son voisinage, elle est détruite à l’issue d’une [[w:Guerre entre Sybaris et Crotone|guerre]] qui l’oppose à [[w:Crotone|''Crotone'']] à la fin du [[w:VIe_siècle_av._J.-C.|VI<sup>ème</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]], et enfouie sous les eaux du fleuve ''Crathis'' (aujourd’hui [[Crati]]), avant de voir son site réoccupé, soixante ans plus tard, par la colonie [[w:Panhellénisme|''panhellénique'']] de [[w:Thourioï|''Thourioï'']].'''<br/><br/></div> {{Boîte déroulante fin}} <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">'''Périandre''' avait fait préparer le banquet, non à la ville même, mais au ''port de Léchée'' [[#Léchée_NdT_DR|<span id="Léchée_NdT_DR_back"><sup>1</sup></span>]], dans une salle voisine du ''temple de Vénus'', à qui l’on devait offrir un sacrifice. Depuis que sa mère, victime d’un malheureux amour [[#Cratée_NdT_DR|<span id="Cratée_NdT_DR_back"><sup>2</sup></span>]], s’était donné la mort, il n’avait pas encore sacrifié à cette déesse, et c’était la première fois qu’il y pensait, d’après un songe de '''Mélisse''' [[#Mélisse_NdT_DR|<span id="Mélisse_NdT_DR_back"><sup>3</sup></span>]]. Nous étions dans les plus grandes chaleurs de l’été. Le grand nombre des voitures et des gens de pied qui fréquentaient le chemin qui conduit à la mer, l’avaient couvert de poussière et le rendaient fort incommode pour les voyageurs. On avait amené, pour chaque convive, un char commode et proprement orné. '''Thalès''', en voyant le sien à ma porte, se mit à sourire et le refusa. Nous primes donc, à travers les champs, un sentier détourné, et nous allâmes, en nous promenant, suivis de '''Niloxène''' de ''Naucrate'' [[#Niloxène_NdT_DR|<span id="Niloxène_NdT_DR_back"><sup>4</sup></span>]], homme du plus grand mérite, que '''Thalès''' et '''Solon''' avaient autrefois beaucoup connu en ''Égypte''. Il était envoyé, pour la seconde fois, vers '''Bias''', sans savoir lui-même quel était l’objet de sa mission. Il se doutait seulement que la lettre dont '''Amasis''' l’avait chargé contenait une seconde question à résoudre. Il avait ordre, en cas que '''Bias''' refusât d’y répondre, de la proposer aux plus sages d’entre les ''Grecs''. Dès qu’il m’eut aperçu, il me dit en me montrant sa lettre : « J’ai du bonheur aujourd’hui. Cette lettre vous trouve tous réunis. Je la porte au banquet, comme vous voyez. - Si c’est une question épineuse, dit '''Thalès''' en souriant, retournez à ''Priene'' [[#Priene_NdT_DR|<span id="Priene_NdT_DR_back"><sup>5</sup></span>]], '''Bias''' la résoudra, comme il a résolu la première. - Quelle était cette première question, demandai-je à '''Thalès''' ? - Le roi d’Égypte, me répondit-il, avait envoyé une victime à '''Bias''', en lui faisant dire d’en couper ce qu’il y avait de meilleur et de plus mauvais, et de le lui renvoyer. Notre sage, fort habilement en ôta la langue, qu’il lui fit porter. Voilà ce qui lui a mérité l’estime et l’admiration de ce prince. - Ajoutez encore à cette première raison, dit '''Niloxène''', que '''Bias''' ne dédaigne pas, comme vous, l’amitié des rois ; car '''Amasis''' n’a pas moins d’estime pour vous ; il admire surtout la manière dont vous mesurâtes, avec la plus grande facilité et sans aucun instrument mathématique, la hauteur de la pyramide. En dressant votre bâton à l’extrémité de l’ombre qu’elle faisait sur la terre, le rayon solaire qui touchait le sommet de la pyramide et l’extrémité du bâton forma deux triangles ; et vous démontrâtes qu’il y avait la même proportion entre la hauteur du bâton et celle de la pyramide qu’entre la longueur des ombres projetées par l’une et par l’autre. Mais, comme je viens de le dire, on vous accuse, auprès de lui, d’être l’ennemi des rois, et on lui a rapporté plusieurs propos injurieux que vous avez tenus contre les tyrans [[#tyrans_NdT_DR|<span id="tyrans_NdT_DR_back"><sup>6</sup></span>]] ; entre autres que l’''Ionien'' '''Molpagore''' [[#Molpagore_NdT_DR|<span id="Molpagore_NdT_DR_back"><sup>7</sup></span>]] vous ayant demandé ce qui vous paraîtrait plus extraordinaire dans la vie, vous lui répondîtes : de voir vieillir un tyran. Une autre fois, comme on vint à parler, dans un repas, du naturel des animaux, vous dîtes que le plus méchant des animaux sauvages était le tyran, et des animaux domestiques, le flatteur. Les rois, quoiqu’ils affectent de ne rien avoir de commun avec les tyrans, n’aiment pas cependant ces sortes de discours. Cette dernière réponse, dit '''Thalès''', est de '''Pittacus''' ; il la fit un jour, en plaisantant, à ''Myrsile'' [[#Myrsile_NdT_DR|<span id="Myrsile_NdT_DR_back"><sup>8</sup></span>]]. Dans la première, je parlais d’un pilote, et non pas d’un tyran. Mais puisqu’on en a fait application au tyran, je dirai comme ce jeune homme qui, jetant une pierre à son chien, en avait atteint sa belle-mère : « Le coup n’est pas perdu. » Aussi jamais '''Solon''' ne montra-t-il plus de sagesse, à mon gré, que lorsqu’il refusa la tyrannie ; et si '''Pittacus''' n’eût pas été contraint de l’accepter, il n’eût point dit qu’il est à charge d’être vertueux [[#Pittacus_NdT_DR|<span id="Pittacus_NdT_DR_back"><sup>9</sup></span>]]. Il est vrai que '''Périandre''', qui a succédé à l’autorité des tyrans, paraît jusqu’ici opposer à ce mal héréditaire un remède puissant, par le soin qu’il a de rechercher les entretiens et les avis salutaires des hommes vertueux , et par l’horreur qu’il a témoignée pour le conseil barbare que notre compatriote '''Thrasybule''' lui donnait de faire mourir les grands. Un tyran qui veut commander à des esclaves, plutôt qu’à des hommes, ressemble à un laboureur qui aimerait mieux voir son champ couvert de passereaux et de sauterelles que d’orge et de froment. Le seul bien qui puisse compenser tant de maux attachés au pouvoir des tyrans, c’est d’avoir, même sur les plus grands et les plus vertueux de leurs sujets, la supériorité de l’honneur et de la vertu. Ceux qui préfèrent la sûreté à la gloire sont faits pour commander à des troupeaux, et non pour gouverner des hommes. « Mais '''Niloxène''' nous a jetés dans une conversation absolument étrangère à notre objet, et nous a fait négliger ce qui devait nous occuper en allant au banquet. Ne pensez-vous pas que les conviés ont, aussi bien que leur hôte, des apprêts à faire. Les ''Sybarites'', dit-on, prient les femmes à souper un an d’avance, afin qu’elles puissent préparer à loisir leurs habits et leurs bijoux [[#Sybarites_NdT_DR|<span id="Sybarites_NdT_DR_back"><sup>10</sup></span>]]. Pour moi, je pense qu’il faut encore plus de temps à un convive pour faire tous les préparatifs convenables, parcequ’il est bien plus difficile d’orner son esprit comme il faut, que de donner à son corps une parure vaine et superflue. Un homme sensé doit aller à un festin, non pour y remplir son estomac, comme un vase, mais pour écouter et tenir à son tour des propos utiles ou amusants, suivant les circonstances. C’est le seul moyen de rendre le repas agréable aux convives. En effet, on peut laisser un mauvais ragoût, et recourir à l’eau quand le vin n’est pas bon ; mais un convive désagréable, importun et fatigant, fait perdre tout le plaisir de la bonne chère et de la musique. On ne peut se délivrer de l’ennui qu’il cause, et souvent même une parole vive ou offensante qu’il se sera permise dans la liberté de la table, fait naître des aversions et des ressentiments qui ne finissent qu’avec la vie. Aussi '''Chilon''', invité hier à ce banquet, ne voulut-il accepter qu’après qu’on lui eut nommé tous les convives. Il disait avec raison, que quand on est sur mer ou dans un camp, il faut nécessairement supporter les compagnons qui nous sont associés, quelque fâcheux qu’ils soient ; mais dans un festin, il n’est pas d’un homme sensé de se mêler indifféremment avec toutes sortes de personnes. Le squelette que les ''Égyptiens'' placent ordinairement à côté d’eux dans leurs repas, en s’exhortant à penser qu’ils seront bientôt dans le même état, est, à la vérité, un compagnon de table assez triste et assez déplacé. Il est néanmoins utile, sinon pour les exciter au plaisir, du moins pour les porter à la bienveillance et à l’amitié réciproque, et pour les avertir de ne pas remplir d’aigreur et de querelles le temps si court de la vie [[#squelette_NdT_DR|<span id="squelette_NdT_DR_back"><sup>11</sup></span>]]. » </div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Léchée_NdT_DR_back|<span id="Léchée_NdT_DR"><sup>1</sup></span>]] L’isthme de ''Corinthe'' avait deux ports, l’un sur la côte orientale, appelé ''Cenchrées'' ; et l’autre sur la côte occidentale, nommé ''Léchée''. Pausanias, qui a donné une description si détaillée de la ''Grèce'', parle d’un ''temple de Vénus'', bâti sur le port de ''Cenchrées'', et dont la statue était de marbre ; mais il ne fait pas mention de celui que cite Plutarque, et qu’il place près du port occidental. ''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Cratée_NdT_DR_back|<span id="Cratée_NdT_DR"><sup>2</sup></span>]] La mère de Périandre se nommait Cratée. On peut voir dans Parthenius la manière dont elle conçut et nourrit une passion incestueuse pour son fils, les moyens qu'elle prit pour la satisfaire sans être connue, et comment elle fut découverte. Les remords qu’elle en eut l’obligèrent de se donner la mort.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Mélisse_NdT_DR_back|<span id="Mélisse_NdT_DR"><sup>3</sup></span>]] Mélisse était fille de Proclès, roi d’[[w:Épidaure_(cité_antique)|''Épidaure'']]. On prétend que Périandre en devint éperdument amoureux pour l’avoir vue dans l’habillement ordinaire aux femmes du ''Péloponnèse''. Cette passion toutefois ne l’empêcha pas de partager son cœur entre elle et plusieurs concubines. Elles parvinrent à l’irriter contre elle au point qu’un jour, par un mouvement de jalousie, il la frappa d’un coup de pied, sans songer qu’elle était enceinte, et la fit mourir.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Niloxène_NdT_DR_back|<span id="Niloxène_NdT_DR"><sup>4</sup></span>]] Niloxène signifie hôte du ''Nil'' : ce nom semble indiquer que c’est un personnage supposé.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Priene_NdT_DR_back|<span id="Priene_NdT_DR"><sup>5</sup></span>]] Ville d’''Ionie'', colonie des ''Thébains'' et patrie de Bias.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#tyrans_NdT_DR_back|<span id="tyrans_NdT_DR"><sup>6</sup></span>]] Par le mot [[wikt:τύραννος#Grec_ancien|τύραννος]], que nous ne pouvons rendre en français que par celui de tyran, les ''Grecs'' entendaient, non pas seulement, comme nous, un prince injuste et cruel ; mais, en général, tout homme qui s’était emparé de l’autorité monarchique dans un état libre, sans qu’elle lui fût légitimement acquise.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Molpagore_NdT_DR_back|<span id="Molpagore_NdT_DR"><sup>7</sup></span>]] Ce Molpagore est peut-être le père d’Aristagore, que Darius établit tyran à ''Milet''.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Myrsile_NdT_DR_back|<span id="Myrsile_NdT_DR"><sup>8</sup></span>]] Myrsile n’est guère mieux connu que Molpagore. Strabon le met au nombre de ces ''Lesbiens'' ambitieux, qui, du temps de Pittacus, s’étaient emparés de l’autorité souveraine à ''Lesbos'', et dont le poète [[w:Alcée_de_Mytilène|Alcée]] avait flétri la mémoire.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Pittacus_NdT_DR_back|<span id="Pittacus_NdT_DR"><sup>9</sup></span>]] Pittacus en se voyant forcé, dans sa vieillesse, de reprendre le gouvernement des affaires, prononça cette maxime.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Sybarites_NdT_DR_back|<span id="Sybarites_NdT_DR"><sup>10</sup></span>]] Cet usage des ''Sybarites'' n’avait lieu que dans les festins publics.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#squelette_NdT_DR_back|<span id="squelette_NdT_DR"><sup>11</sup></span>]] Cet usage, d’abord particulier aux ''Egyptiens'', avait ensuite passé chez les ''Grecs'', de qui les ''Romains'' l’empruntèrent. ''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' pp.326-330, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe III.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage de la reconnaissance de la sagesse de '''Cléobuline''' ''« Eumétis »'' par '''Thalès''', de l’humilité de ce dernier et de son [[w:Cynisme|''cynisme'']], en particulier à la vue d’un ''centaure'' [[#centaure|<span id="centaure_back"><sup>'''I'''</sup></span>]]. </div> {{Boîte déroulante début|titre=NdA centaure|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#centaure_back|<span id="centaure"><sup>I</sup></span>]] Il s’agit d’une adaptation d’une fable de [[w:Phèdre_(fabuliste)|Phèdre]] [[#Phèdre|<span id="Phèdre_back"><sup>II</sup></span>]], où Ésope [[#Ésope_back|<sup>⤴️</sup>]] remplace Thalès [https://books.openedition.org/pur/12177 {{info|<sup>🔍</sup>|Gourmelen, Laurent. « Imposture ou dualité : que faut-il penser de la naissance d’un centaure ? Sur un curieux passage du Banquet des Sept Sages (Plutarque, Moralia, 149 C-F) ». L’imposture dans la littérature, édité par Arlette Bouloumié, Presses universitaires de Rennes, 2011, https://doi.org/10.4000/books.pur.12177.}}] :'''<br /><br /><p style="margin: 0 2em; text-align: center;">« Un homme d’expérience en sait plus long qu’un devin. C’est un proverbe; d’où vient-il? on ne le dit pas. Ma fable, la première, va l’apprendre.<br /><br />Un fermier avait des brebis qui lui donnaient des agneaux à tête humaine. Épouvanté d’une monstruosité pareille, il court tout affligé consulter les devins. L’un répond que la vie du maître est menacée, et qu’il faut conjurer le péril par une victime. L’autre assure au fermier que sa femme lui est infidèle, et que cela signifie l’illégitimité des enfants; mais qu’un sacrifice important peut tout expier. Enfin, tous diffèrent d’opinion et ne font qu’aggraver le souci du paysan. '''Ésope''', vieillard plein de finesse et de sagacité, et que la nature ne put jamais tromper, se trouvait là par hasard : "Villageois, lui dit-il, si tu veux faire cesser ce prodige, donne des femmes tes bergers." » <br /><br /><p style="text-align: right; margin: 0 2em 0 1em;">'''[https://remacle.org/bloodwolf/fabulistes/phedre/livre3.htm <u>Fables de Phèdre</u>, livre III], §3 - Ésope et le paysan, traduites par M. E. Panckoucke, 1864.<br /><br /><p style="margin: 0 2em; text-indent: 15px;">[[#Phèdre_back|<span id="Phèdre"><sup>II</sup></span>]] [[w:Nom_romain|Tria Nomina]] en latin {{Info|Caius|praenomen, nom individuel du citoyen romain}} {{Info|Iulius|nomen, nom de famille}} {{Info|Phaedrus ou Phaeder|cognomen, surnom héréditaire, servant à distinguer les diverses branches d’une même gens}} ;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ du grec ancien Φαῖδρος / Phaîdros [[wikt:en:Φαῖδρος#Ancient_Greek|(en)]] ; de l’adjectif phaidrós / phaidrós [[wikt:en:φαιδρός#Ancient_Greek|(en)]], « 1. Lumineux, rayonnant. 2. (au sens figuré) Rayonnant de joie, brillant, joyeux. » ;<br /><p style="margin: 0 2em; text-indent: 15px;">Fabuliste latin d’origine ''[[w:thrace|thrace]]'', esclave à son arrivée à ''Rome'' et affranchi par un décret d’[[w:Auguste|Auguste]]. Près d’un tiers de son œuvre est repris d’Ésope dont il adapte les fables ; les deux autres tiers sont issus de son imagination. Tout comme son prédécesseur, Phèdre raconte des histoires d’animaux, mais il met en scène aussi des personnages humains et parmi ceux-ci Ésope :'''<br /><br /><p style="margin: 0 2em; text-align: center;">« C’est '''Ésope''' qui, le premier, a trouvé la matière : moi, je l’ai polie en vers [[w:Sénaire iambique|''sénaires'']]. Ce petit livre a un double mérite : il fait rire et il donne de sages conseils pour la conduite de la vie. À celui qui viendrait me reprocher injustement de faire parler non seulement les animaux, mais même les arbres, je rappellerai que je m’amuse ici à de pures fictions. »<br /><p style="margin: 0 2em; text-align: right;">'''Phèdre, ''Fables'', I, prologue'''<br /><br /><p style="margin: 0 2em; text-align: center;">« Le genre d’'''Ésope''' est tout en exemples, et on ne doit y chercher que le but de ses fables : corriger les erreurs des hommes, et exciter en eux une vive émulation. Quelle que soit donc la nature d’un récit, s’il captive, et remplit son objet, il se recommande de lui-même, sans aucun nom d’auteur. Aussi suivrai-je scrupuleusement les traces du vieillard. »<br /><p style="margin: 0 2em; text-align: right;">'''Phèdre, ''Fables'', II, prologue'''<br /><br /><p style="margin: 0 2em; text-indent: 15px;">'''Au total, il composera cent-vingt-trois fables, divisées en cinq livres.<br /><p style="text-align: right; margin: 0 2em;">(vers [[w:-14|-14]] <sup>[[w:Ier_siècle_av._J.-C.|⏳]]</sup>, en ''Thrace'' ― vers [[w:50|50]] <sup>[[w:Ier_siècle|⏳]]</sup>, lieu de décès inconnu)'''<br /><br /> </div>{{Boîte déroulante fin}} :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§3. Ἐν τοιούτοις λόγοις γενόμενοι κατὰ τὴν ὁδὸν ἀφικόμεθα πρὸς τὴν οἰκίαν, καὶ λούσασθαι μὲν ὁ Θαλῆς οὐκ ἠθέλησεν, ἀληλιμμένοι γὰρ ἦμεν· ἐπιὼν δὲ τούς τε δρόμους ἐθεᾶτο καὶ τὰς παλαίστρας καὶ τὸ ἄλσος τὸ παρὰ τὴν θάλατταν ἱκανῶς διακεκοσμημένον, ὑπ´ οὐδενὸς ἐκπληττόμενος τῶν τοιούτων, ἀλλ´ ὅπως μὴ καταφρονεῖν δοκοίη μηδ´ ὑπερορᾶν τοῦ Περιάνδρου τῆς φιλοτιμίας. τῶν δ´ ἄλλων τὸν ἀλειψάμενον ἢ λουσάμενον οἱ θεράποντες εἰσῆγον εἰς τὸν ἀνδρῶνα διὰ τῆς στοᾶς. Ὁ δ´ Ἀνάχαρσις ἐν τῇ στοᾷ καθῆστο, καὶ παιδίσκη προειστήκει τὴν κόμην ταῖς χερσὶ διακρίνουσα. ταύτην ὁ Θαλῆς ἐλευθεριώτατά πως αὐτῷ προσδραμοῦσαν ἐφίλησε καὶ γελάσας « οὕτως, » ἔφη, « ποίει καλὸν τὸν ξένον, ὅπως ἡμερώτατος ὢν μὴ φοβερὸς ᾖ τὴν ὄψιν ἡμῖν μηδ´ ἄγριος. » Ἐμοῦ δ´ ἐρομένου περὶ τῆς παιδὸς ἥτις εἴη, « τὴν σοφήν, » ἔφη, « καὶ περιβόητον ἀγνοεῖς Εὔμητιν; οὕτω γὰρ ταύτην ὁ πατὴρ αὐτός, οἱ δὲ πολλοὶ πατρόθεν ὀνομάζουσι Κλεοβουλίνην. » Καὶ ὁ Νειλόξενος εἶπεν « ἦ που τὴν περὶ τὰ αἰνίγματα δεινότητα καὶ σοφίαν, » ἔφη, « τῆς κόρης ἐπαινεῖς· καὶ γὰρ εἰς Αἴγυπτον ἔνια τῶν προβαλλομένων ὑπ´ αὐτῆς διῖκται. » « Οὐκ ἔγωγ´, » εἶπεν ὁ Θαλῆς· « τούτοις γὰρ ὥσπερ ἀστραγάλοις, ὅταν τύχῃ, παίζουσα χρῆται καὶ διαβάλλεται πρὸς τοὺς ἐντυχόντας. ἀλλὰ καὶ φρόνημα θαυμαστὸν καὶ νοῦς ἔνεστι πολιτικὸς καὶ φιλάνθρωπον ἦθος, καὶ τὸν πατέρα τοῖς πολίταις πραότερον ἄρχοντα παρέχει καὶ δημοτικώτερον. » « Εἶεν, » ὁ Νειλόξενος ἔφη, « καὶ φαίνεται βλέποντι πρὸς τὴν λιτότητα καὶ ἀφέλειαν αὐτῆς· Ἀνάχαρσιν δὲ πόθεν οὕτω τημελεῖ φιλοστόργως; » « Ὅτι, » ἔφη, « σώφρων ἀνήρ ἐστι καὶ πολυμαθής, καὶ τὴν δίαιταν αὐτῇ καὶ τὸν καθαρμόν, ᾧ χρῶνται Σκύθαι περὶ τοὺς κάμνοντας, ἀφθόνως καὶ προθύμως παραδέδωκε. καὶ νῦν οἶμαι περιέπειν αὐτὴν τὸν ἄνδρα καὶ φιλοφρονεῖσθαι, μανθάνουσάν τι καὶ προσδιαλεγομένην. » Ἤδη δὲ πλησίον οὖσιν ἡμῖν τοῦ ἀνδρῶνος ἀπήντησεν Ἀλεξίδημος ὁ Μιλήσιος (ἦν δὲ Θρασυβούλου τοῦ τυράννου νόθος) καὶ ἐξῄει τεταραγμένος καὶ σὺν ὀργῇ τινι πρὸς αὑτὸν οὐδὲν ἡμῖν γε σαφὲς διαλεγόμενος. ὡς δὲ τὸν Θαλῆν εἶδε, μικρὸν ἀνενεγκὼν καὶ καταστάς « οἵαν ὕβριν, » εἶπεν, « εἰς ἡμᾶς Περίανδρος ὕβρικεν, ἐκπλεῦσαι μὲν οὐκ ἐάσας ὡρμημένον ἀλλὰ προσμεῖναι δεηθεὶς τὸ δεῖπνον, ἐλθόντι δὲ νέμων κλισίαν ἄτιμον, Αἰολεῖς δὲ καὶ νησιώτας (καὶ τίνας γὰρ οὐχί;) Θρασυβούλου προτιμῶν· Θρασύβουλον γὰρ ἐν ἐμοὶ τὸν πέμψαντα προπηλακίσαι βουλόμενος καὶ καταβαλεῖν ὡς δὴ περιορῶν δῆλός ἐστιν. » « Εἶτ´, » ἔφη, « σὺ δέδιας μὴ καθάπερ Αἰγύπτιοι τοὺς ἀστέρας ὑψώματα καὶ ταπεινώματα λαμβάνοντας ἐν τοῖς τόποις οὓς διεξίασι γίγνεσθαι βελτίονας ἢ χείρονας ἑαυτῶν λέγουσιν, οὕτως ἡ περὶ σὲ διὰ τὸν τόπον ἀμαύρωσις ἢ ταπείνωσις γένηται; καὶ τοῦ Λάκωνος ἔσῃ φαυλότερος, ὃς ἐν χορῷ τινι κατασταθεὶς εἰς τὴν ἐσχάτην χώραν ὑπὸ τοῦ ἄρχοντος ‘εὖ γ´,’ εἶπεν, ‘ἐξεῦρες, ὡς καὶ αὕτα ἔντιμος γένηται.’ οὐ καταλαβόντας, » ἔφη, « τόπον μετὰ τίνας κατακείμεθα δεῖ ζητεῖν, μᾶλλον δ´ ὅπως εὐάρμοστοι τοῖς συγκατακειμένοις ὦμεν, ἀρχὴν καὶ λαβὴν φιλίας εὐθὺς ἐν αὐτοῖς ζητοῦντες, μᾶλλον δ´ ἔχοντες τὸ μὴ δυσκολαίνειν ἀλλ´ ἐπαινεῖν ὅτι τοιούτοις συγκατεκλίθημεν· ὡς ὅ γε τόπῳ κλισίας δυσχεραίνων δυσχεραίνει τῷ συγκλίτῃ μᾶλλον ἢ τῷ κεκληκότι, καὶ πρὸς ἀμφοτέρους ἀπεχθάνεται. » « Λόγος, » ἔφη, « ταῦτ´ ἄλλως ἐστίν » ὁ Ἀλεξίδημος, « ἔργῳ δὲ καὶ τοὺς σοφοὺς ὑμᾶς ὁρῶ τὸ τιμᾶσθαι διώκοντας, » καὶ ἅμα παραμειψάμενος ἡμᾶς ἀπῆλθε. Καὶ ὁ Θαλῆς πρὸς ἡμᾶς τὴν ἀτοπίαν τοῦ ἀνθρώπου θαυμάζοντας, « ἔμπληκτος, » ἔφη, « καὶ ἀλλόκοτος φύσει, ἐπεὶ καὶ μειράκιον ὢν ἔτι, μύρου σπουδαίου Θρασυβούλῳ κομισθέντος, εἰς ψυκτῆρα κατεράσας μέγαν καὶ προσεγχέας ἄκρατον ἐξέπιεν, ἔχθραν ἀντὶ φιλίας Θρασυβούλῳ διαπεπραγμένος. » Ἐκ τούτου περιελθὼν ὑπηρέτης « κελεύει σε Περίανδρος, » ἔφη, « καὶ Θαλῆν παραλαβόντα τοῦτον ἐπισκέψασθαι τὸ κεκομισμένον ἀρτίως αὐτῷ πότερον ἄλλως γέγονεν ἤ τι σημεῖόν ἐστι καὶ τέρας· αὐτὸς μὲν γὰρ ἔοικε τεταράχθαι σφόδρα, μίασμα καὶ κηλῖδα τῆς θυσίας ἡγούμενος. » ἅμα δ´ ἀπῆγεν ἡμᾶς εἴς τι οἴκημα τῶν περὶ τὸν κῆπον. ἐνταῦθα νεανίσκος ὡς ἐφαίνετο νομευτικός, οὔπω γενειῶν ἄλλως τε τὸ εἶδος οὐκ ἀγεννής, ἀναπτύξας τινὰ διφθέραν ἔδειξεν ἡμῖν βρέφος ὡς ἔφη γεγονὸς ἐξ ἵππου, τὰ μὲν ἄνω μέχρι τοῦ τραχήλου καὶ τῶν χειρῶν ἀνθρωπόμορφον, τὰ λοιπὰ δ´ ἔχον ἵππου, τῇ δὲ φωνῇ καθάπερ τὰ νεογνὰ παιδάρια κλαυθμυριζόμενον. ὁ μὲν οὖν Νειλόξενος, « Ἀλεξίκακε » εἰπών, ἀπεστράφη τὴν ὄψιν, ὁ δὲ Θαλῆς προσέβλεπε τῷ νεανίσκῳ πολὺν χρόνον, εἶτα μειδιάσας (εἰώθει δ´ ἀεὶ παίζειν πρὸς ἐμὲ περὶ τῆς τέχνης) « ἦ που τὸν καθαρμόν, ὦ Διόκλεις, » ἔφη, « κινεῖν διανοῇ καὶ παρέχειν πράγματα τοῖς ἀποτροπαίοις, ὥς τινος δεινοῦ καὶ μεγάλου συμβάντος; » « Τί δ´, » εἶπον, « οὐ μέλλω; στάσεως γάρ, ὦ Θαλῆ, καὶ διαφορᾶς τὸ σημεῖόν ἐστι, καὶ δέδια μὴ μέχρι γάμου καὶ γενεᾶς ἐξίκηται, πρὶν ἢ τὸ πρῶτον ἐξιλάσασθαι μήνιμα, τῆς θεοῦ δεύτερον ὡς ὁρᾷς προφαινούσης. » Πρὸς τοῦτο μηδὲν ἀποκρινάμενος ὁ Θαλῆς ἀλλὰ γελῶν ἀπηλλάττετο. καὶ τοῦ Περιάνδρου πρὸς τὰς θύρας ἀπαντήσαντος ἡμῖν καὶ διαπυθομένου περὶ ὧν εἴδομεν, ἀφεὶς ὁ Θαλῆς με καὶ λαβόμενος τῆς ἐκείνου χειρὸς ἔφη, « ἃ μὲν Διοκλῆς κελεύει δράσεις καθ´ ἡσυχίαν· ἐγὼ δέ σοι παραινῶ νέοις οὕτω μὴ χρῆσθαι νομεῦσιν ἵππων, ἢ διδόναι γυναῖκας αὐτοῖς. » Ἔδοξε μὲν οὖν μοι τῶν λόγων ἀκούσας ὁ Περίανδρος ἡσθῆναι σφόδρα· καὶ γὰρ ἐξεγέλασε καὶ τὸν Θαλῆν περιβαλὼν κατησπάσατο. κἀκεῖνος « οἶμαι δ´, » εἶπεν, « ὦ Διόκλεις, καὶ πέρας ἔσχε τὸ σημεῖον· ὁρᾷς γὰρ ἡλίκον κακὸν γέγονεν ἡμῖν, Ἀλεξιδήμου συνδειπνεῖν μὴ θελήσαντος. » </div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §3'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§3. Ce fut en tenant de tels propos chemin faisant, que nous arrivâmes à la maison. '''Thalès''' ne voulut pas se baigner : « Je me suis frotté d’huile. » dit-il. Il se promena donc de côté et d’autre, regardant les champs de course, les palestres, et le bois sacré, voisin de la mer, que l’on avait bien convenablement disposé. Ce n’était pas qu’il fût frappé par aucun de ces préparatifs, mais il voulait ne pas avoir l’air de mépriser '''Périandre''' et de faire peu de cas de l’empressement avec lequel celui-ci honorait ses hôtes. Pour les autres convives, à mesure qu’ils s’étaient parfumés ou baignés, les serviteurs les introduisaient par la galerie dans la salle du banquet. Or '''Anacharsis''' s’était installé dans cette galerie, et devant lui une jeune fille se tenait, lui séparant les cheveux avec ses mains. Lorsqu’entra '''Thalès''', elle s’élança très librement à sa rencontre, et '''Thalès''', après l’avoir embrassée, lui dit en riant : « Continue à rendre bien beau notre étranger, afin qu’étant devenu la douceur même il ne conserve pas au milieu de nous une mine à faire peur et un aspect sauvage. » Je lui demandai quelle était cette jeune enfant : « Quoi ! » me dit-il, « vous ne connaissez pas la savante et célèbre '''Eumétis''' ! car c’est ainsi que son père la nomme : le plus communément on l’appelle '''Cléobuline''', du nom paternel. » Et '''Niloxène''' : « C’est sans doute à cause de son talent et de son habileté pour les énigmes, que vous faites l’éloge de cette jeune fille : car quelques-unes de celles qu’elle a proposées sont parvenues jusqu’en ''Égypte''. » — « Ce n’est pas à cause de cela », répondit '''Thalès''' : « les énigmes sont pour elle des joujoux dont elle s’amuse à l’occasion pour faire sa partie avec ceux qui se rencontrent. Mais ce qui est admirable en elle c’est sa profondeur d’esprit, son sens politique, l’aménité de son caractère, et le talent qu’elle a de rendre plus douce l’autorité de son père et d’inspirer à celui-ci des sentiments plus humains à l’égard du peuple. » — « Soit », dit '''Niloxène''' ; « et cela se reconnaît à voir sa modestie et sa simplicité. Mais d’où vient qu’elle prend un soin si amoureux de la toilette d’'''Anacharsis''' ? » — Parce que c’est, répondit '''Thalès''', « un sage, un homme des plus instruits, et parce qu’il lui a communiqué, avec de nombreux détails et de grand coeur, l’ensemble des pratiques sanitaires et des purifications que les ''Scythes'' appliquent au traitement des malades. Et dans ce moment je suppose qu’elle l’entoure de soins et d’amitiés parce qu’elle s’instruit de quelque chose en conversant avec lui. » Comme nous étions déjà près de la salle, '''Alexidème''' le ''Milésien'' vint à notre rencontre. C’était un bâtard du tyran '''Thrasybule'''. Il était sorti tout troublé, et avec une sorte de fureur il se parlait à lui-même, mais ses paroles n’avaient rien de clair pour nous. Quand il eut vu '''Thalès''', il se remit un peu ; puis, s’arrêtant tout court : « Quel affront '''Périandre''' vient de nous faire ! Je voulais mettre à la voile : il ne l’a pas permis ; il m’a supplié de rester à son festin, et quand j’arrive, il me donne une des dernières places, faisant passer des [[w:Éoliens|''Éoliens'']], des insulaires (je ne sais qui il ne me préfère pas), les faisant passer, dis je, avant '''Thrasybule''', car c’est '''Thrasybule''' en ma personne, c’est celui par lequel je suis envoyé qu’il a l’intention de traîner dans la boue et de ravaler comme le méprisant : la chose est bien claire. » — « Eh quoi ! » lui dit '''Thalès''', « êtes-vous comme les ''Égyptiens'', qui prétendent que les astres, suivant qu’ils prennent une position élevée ou basse en parcourant leur orbite, ont une condition meilleure ou pire qu’ils ne l’avaient ? Craignez-vous, pareillement, qu’autour de vous, en raison de la place où vous serez, il ne se produise obscurité ou dépression ? Serez-vous moins résigné que certain ''Spartiate'' ? À je ne sais quelle représentation il avait été placé au dernier rang par le maître des cérémonies : « Voilà qui va bien », lui dit-il : « tu as trouvé moyen de rendre honorable ce lieu même. Quand nous avons pris une place nous ne devons pas chercher au-dessous de qui nous sommes installés, mais plutôt comment nous nous mettrons en bon accord avec nos voisins. À leur occasion nous ferons voir tout d’abord, ou plutôt nous l’éprouverons réellement, un désir d’initiative et de prise de possession en matière d’amitié, et nous manifesterons ce désir en nous félicitant, loin d’en montrer du dépit, de ce que l’on nous a placés en une telle compagnie. Mais celui qui se plaint du rang qu’on lui donne à table montre plus de mécontentement contre son commensal que contre son hôte, et il se rend odieux à l’un et à l’autre. » — « Paroles que tout cela, » dit '''Alexidème''', « et paroles sans portée ! Mais je vois que de fait, vous autres sages, vous recherchez aussi les honneurs. » En même temps il s’éloigna de nous et disparut. Une conduite si étrange nous semblait étonnante. « C’est », nous dit '''Thalès''', « un homme écervelé et naturellement bizarre. Vous allez en juger. Il était encore tout jeune ; on avait apporté à '''Thrasybule''' un parfum d’un très haut prix. '''Alexidème''' le versa dans un grand vase à rafraîchir, y mêla du vin pur, et avala le tout, rendant son père odieux au lieu de le faire aimer. » Au même moment parut un serviteur : « Vous êtes invité par '''Périandre''' », me dit-il, « à venir, en vous faisant accompagner de '''Thalès''' que voici, examiner l’objet qu’on lui a récemment apporté, afin que vous disiez si c’est une création toute fortuite, ou bien un présage et une monstruosité; car, pour ce qui est de '''Périandre''', il a l’air grandement troublé, pensant que c’est une souillure et une profanation pour son sacrifice. » En même temps, il nous emmena vers une des salles qui donnaient sur le jardin. Là un jeune homme paraissant appartenir à la classe des bergers, qui n’avait pas encore de barbe et dont la physionomie ne manquait pas de noblesse, déploya une espèce de couverture en cuir, et nous montra un petit enfant né, disait-il, d’une cavale. Par le haut, jusqu’au cou et aux mains, cette créature était de forme humaine ; mais le reste était d’un cheval, et sa voix avait quelque chose des vagissements poussés par les petits enfants qui viennent de naître. « Dieu préservateur ! » s’écria '''Niloxène''', et il détourna les yeux. Mais '''Thalès''' fixa longtemps son regard sur le jeune pâtre; puis s’étant mis à sourire, (car il avait l’habitude de plaisanter toujours avec moi sur ma profession) : « Eh bien, '''Dioclès''', » dit-il, « songez-vous à préparer quelque expiation, et à donner de la besogne aux dieux préservateurs, comme vous trouvant en présence de quelque événement grave et considérable ? » — « Pourquoi non ? » répondis-je : « j’y vois le présage de troubles et de discordes qui s’étendront, j’en ai peur, jusqu’à un mariage et une génération avant que le courroux de la déesse ait été apaisé, puisqu’elle fait, vous le savez, une seconde manifestation ». À ces paroles '''Thalès''' ne répondit rien : il se contenta de rire et de s’en aller. Et comme '''Périandre''' était à la porte, s’avançant pour nous interroger sur ce que nous venions de voir, '''Thalès''' me quitta et le prit par la main : « Ce que '''Dioclès''' prescrira, vous l’exécuterez à loisir », lui dit-il ; « mais moi j’ai un conseil à vous donner : pour faire paître vos juments ne prenez pas de jeunes garçons, ou bien à ceux-ci donnez des femmes. » Ces paroles me semblèrent causer, des qu’il les eut entendues, une vive satisfaction à '''Périandre''', car il éclata de rire et serra très affectueusement '''Thalès''' dans ses bras. '''Thalès''' alors : « '''Dioclès''' », me dit-il, « si je conjecture bien, le prodige reçoit déjà son accomplissement. Car vous voyez quel grand malheur nous est arrivé, '''Alexidème''' n’ayant pas voulu souper avec nous. »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §3'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Après avoir ainsi conversé pendant le chemin, nous arrivâmes au lieu destiné pour le banquet. '''Thalès''' ne voulut point entrer dans le bain, parcequ’il s’était déja parfumé, mais il se promena dans les dehors, s’arrêta à voir les luttes et les courses ; il alla voir le bocage voisin de la mer, qu’on avait décoré avec beaucoup de soin, non qu’il fût frappé de tout cet appareil, mais pour ne point paraître mépriser '''Périandre''' et dédaigner sa magnificence. Tous les autres convives, à mesure qu’ils sortaient du bain, étaient introduits par des esclaves dans la salle du banquet. '''Anacharsis''' seul était assis sous le portique, une jeune fille, debout, lui arrangeait les cheveux. Dès qu’elle vit '''Thalès''', elle accourut très librement au-devant de lui ; ce philosophe l’embrassa, et lui dit en riant : « Parez cet hôte du mieux que vous pourrez, afin que le plus doux des hommes n'’ait plus un extérieur sauvage et effrayant. » Je lui demandai quelle était cette jeune personne : « Eh quoi ! me répondit-il, vous ne connaissez pas la sage et fameuse '''Eumétis''' ? C’est le nom que '''Cléobule''' lui donne, mais les autres l’appellent '''Cléobuline''', du nom de son père. - Est-ce, dit '''Niloxène''', à cause de sa subtilité et de son adresse à composer des énigmes, que vous faites ainsi son éloge ? Quelques unes de celles qu’on lui attribue ont pénétré jusqu’en ''Egypte''. - Non, répliqua '''Thalès''' ; ces énigmes ne sont que des jouets dont elle s’amuse dans l’occasion pour éprouver la perspicacité de ceux qu’elle rencontre. Ce qu’elle a de vraiment admirable, c’est sa grande prudence, sa capacité pour les affaires, son humanité, et l’attention qu’elle a de rendre le gouvernement de son père doux et bienfaisant. - Il est vrai, reprit '''Niloxène''', que sa modestie et sa simplicité annoncent combien elle est populaire. Mais d’où viennent ces soins et cet intérêt pour '''Anacharsis''' ? - Parceque c’est un homme sensé et très instruit, répondit '''Thalès''', qu’il s’est fait un plaisir de lui apprendre en détail le régime et le traitement que les ''Scythes'' emploient dans les maladies. Je suis sûr que dans ce moment même où elle le pare avec tant de soin, elle s’entretient utilement avec lui, et cherche à s’instruire. » Nous approchions de la salle, lorsque nous rencontrâmes '''Alexidème''' de ''Milet'', fils naturel du tyran '''Thrasybule'''. Il sortait tout troublé, et d’un ton de colère murmurait quelques mots que nous ne pûmes entendre. Dès qu’il vit '''Thalès''', il se remit un peu ; et en lui adressant la parole, il lui dit : « Quel indigne affront '''Périandre''' vient de nous faire ! J’allais partir, il me retient, il me prie de rester à son festin ; et quand j’arrive, il m’y donne la dernière place : il préfère un ''éolien'', un insulaire, enfin je ne sais qui, à '''Thrasybule''', car il est évident que c’est '''Thrasybule''' que '''Périandre''' méprise, et brave ouvertement dans la personne de son envoyé [[#Thrasybule_NdT_DR|<span id="Thrasybule_NdT_DR_back"><sup>1</sup></span>]]. - Eh quoi ! lui dit '''Thalès''', craignez-vous que la place que vous occuperez à table ne vous rende plus grand ou plus petit, comme les ''Égyptiens'' disent que les astres brillent plus ou moins, suivant que le cercle qu’ils parcourent est plus ou moins élevé ? Et vous estimeriez-vous moins que ce ''Lacédémonien'', qui, dans une assemblée publique, placé par le magistrat au dernier rang, lui dit : Vous avez trouvé le moyen de rendre cette place honorable [[#place_honorable_NdT_DR|<span id="place_honorable_NdT_DR_back"><sup>2</sup></span>]] ? Doit-on en effet examiner après qui l’on est placé ? Ne faut-il pas plutôt s’accommoder de ceux qu’on a pour voisins, afin d’avoir une occasion naturelle de se lier avec eux, et loin de se fâcher du rang qu’on occupe, témoigner sa satisfaction de se trouver auprès d’eux ? Celui qui se plaint de la place qu’on lui assigne semble plus mécontent de son voisin que de son hôte, et se rend odieux à l’un et à l’autre . - Belles paroles que cela, repartit '''Alexidème'''. Mais, dans le fait, je vois que vous autres sages, vous recherchez les honneurs aussi bien que nous. » En même temps, il nous quitte brusquement, et s’en va. Une conduite si étrange nous étonna tous : « Ce jeune et homme, nous dit '''Thalès''', a montré dès l’enfance un caractère dur et emporté. Un jour qu’on avait fait présent à '''Thrasybule''' d’un parfum de grand prix, il le versa dans une coupe mêlé avec du vin, et l’avala, payant ainsi d’ingratitude la tendresse de son père. » Au même instant, un des gens de '''Périandre''' vint me prier d’aller avec '''Thalès''' voir quelque chose d’extraordinaire qu’on venait de lui apporter, afin de juger si c’était un jeu de la nature ou un prodige menaçant ; il nous dit qu’il en était tout troublé, et qu’il craignait que son sacrifice n’en fût souillé. En même temps, il nous conduit dans une salle qui donnait sur le jardin. Nous y trouvâmes un jeune homme sans barbe, d’une figure intéressante, qui avait l’air d’un berger. Il lève une espèce de peau, et nous fait voir un enfant qu’il disait être né d’une cavale, qui avait la tête, le cou et les mains d’un homme, et dans tout le reste, était fait comme un cheval. Sa voix ressemblait à celle d’un enfant qui vient de naître : « Dieu préservateur ! s’écria '''Niloxène''', en détournant la vue. » Mais '''Thalès''', qui a coutume de plaisanter avec moi sur mon art, après avoir longtemps considéré ce jeune homme, me dit en souriant : « Ne pensez-vous pas déja, '''Dioclès''', à faire des expiations ? Et pour détourner un présage si terrible, n’allez-vous pas donner bien de l’ouvrage aux dieux préservateurs ? - Pourquoi non ? lui répondis-je. Ce prodige, '''Thalès''', est un signe menaçant de troubles et de discorde ; et je crains bien que l’épouse et les enfants de '''Périandre''' n’en éprouvent les tristes suites, puisque enfin, comme vous voyez, avant que la déesse soit apaisée, elle donne une nouvelle marque de son courroux. » A ces mots, '''Thalès''' sourit et sortit sans rien répondre. Il vit, à la porte de la salle, '''Périandre''' venir au-devant de nous, pour savoir notre sentiment. Il me quitta, lui prit la main, et lui dit : « '''Dioclès''' vous parlera ; vous ferez à loisir ce qu’il vous dira. Pour moi, je pense que vous ne devez pas avoir, pour garder vos juments, des bergers aussi jeunes, ou que vous devez les marier. » Ce discours parut faire grand plaisir à '''Périandre''', car il en rit beaucoup, et embrassa affectueusement '''Thalès'''. Celui-ci s’adressant à moi : « Je crois, '''Dioclès''', me dit-il, que le prodige a déja eu son accomplissement. Vous voyez le malheur qui vient de nous arriver ; '''Alexidème''' a refusé de souper avec nous. » </div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Thrasybule_NdT_DR_back|<span id="Thrasybule_NdT_DR"><sup>1</sup></span>]]Dans les ''Propos de table'', on trouve une aventure pareille, arrivée chez Timon, frère de Plutarque ; mais le personnage n’est pas nommé. ''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#place_honorable_NdT_DR_back|<span id="place_honorable_NdT_DR"><sup>2</sup></span>]] Plutarque, dans les ''apophthegmes des Lacédémoniens'', nomme ce ''Spartiate'' Dæmonidas, et attribue un mot semblable au fameux Agésilas. ''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' pp.330-334, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe IV.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage du caractère désinvolte de '''Thalès'''.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§4. Ἐπεὶ δ´ εἰσήλθομεν, ἤδη μεῖζον ὁ Θαλῆς φθεγξάμενος « ποῦ δ´ » εἶπεν « ὁ ἀνὴρ κατακλινάμενος ἐδυσχέρανεν; » ἀποδειχθείσης δὲ τῆς χώρας περιελθὼν ἐκεῖ κατέκλινεν ἑαυτὸν καὶ ἡμᾶς « ἀλλὰ κἂν ἐπριάμην » εἰπών « Ἀρδάλῳ κοινωνεῖν μιᾶς τραπέζης. » ἦν δὲ Τροιζήνιος ὁ Ἄρδαλος, αὐλῳδὸς καὶ ἱερεὺς τῶν Ἀρδαλείων Μουσῶν, ἃς ὁ παλαιὸς Ἄρδαλος ἱδρύσατο ὁ Τροιζήνιος.<br /><p style="text-align: centre">[...]<br /><p style="text-align: justify; text-indent: 15px">καὶ ὁ Θαλῆς ἐμὲ προσαγορεύσας ἐπάνω τοῦ Βίαντος κατακείμενον « τί οὐκ ἔφρασας, » εἶπεν, « ὦ Διόκλεις, Βίαντι τὸν Ναυκρατίτην ξένον ἥκοντα μετὰ προβλημάτων βασιλικῶν αὖθις ἐπ´ αὐτόν, ὅπως νήφων καὶ προσέχων ἑαυτῷ τὸν λόγον δέχηται; » Καὶ ὁ Βίας « ἀλλ´ οὗτος μέν, » ἔφη, « πάλαι δεδίττεται ταῦτα παρακελευόμενος, ἐγὼ δὲ τὸν Διόνυσον οἶδα τά τ´ ἄλλα δεινὸν ὄντα καὶ Λύσιον ἀπὸ σοφίας προσαγορευόμενον, ὥστ´ οὐ δέδια τοῦ θεοῦ μεστὸς γενόμενος μὴ ἀθαρσέστερον ἀγωνίσωμαι. » Τοιαῦτα μὲν ἐκεῖνοι πρὸς ἀλλήλους ἅμα δειπνοῦντες ἔπαιζον·</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §4'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§4. Après que nous fûmes entrés, '''Thalès''' ayant déjà élevé plus haut la voix: « Où donc », dit-il, « l’avait-on placé, cet homme qui s’en est formalisé ? » Quand on lui eut montré l’endroit il fit le tour de la salle, et ce fut là-même qu’il se plaça et nous installa. « En vérité », ajouta-t-il, « j’aurais payé pour partager la même table qu’'''Ardalus'''. » Cet '''Ardalus''' était un joueur de flûte ''Trézénien'', prêtre des ''muses Ardalides'' auxquelles l’antique [[w:Ardalos|'''Ardalus''']] de ''Trézène'' avait dressé des statues.<br /><p style="text-align: center">[...]<br /><p style="text-indent: 15px">Moi, j’étais au-dessus de '''Bias''', et '''Thalès''' m’ayant interpellé : « '''Dioclès''' », me dit-il, « pourquoi n’avez-vous pas dit à '''Bias''' que l’étranger de ''Naucratie'' est venu une seconde fois le trouver avec des questions de la part de son prince, afin que ce soit à jeun qu’il reçoive ces communications et qu’il y applique son esprit ? » Et '''Bias''' : « Il y a longtemps », dit-il, « que '''Dioclès''' me menace de m’y contraindre ; mais je sais que '''Bacchus''', entre autres attributions merveilleuses, possède une sagacité qui l’a fait surnommer le dieu qui délie, de sorte que je ne crains pas, étant rempli de la divinité, que la confiance m’abandonne au moment de la lutte. » C’est ainsi que, pendant le repas, ils échangeaient entre eux des plaisanteries.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §4'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Quand nous fûmes dans la salle, il demanda, en élevant la voix : « Où est donc cette place qui a tant fâché notre homme ? » Quand on la lui eut montrée, il alla s’y placer avec nous : « Certes, ajouta-t-il, j’aurais payé pour être à la même table qu’'''Ardalus'''. » Cet '''Ardalus''' était un joueur de flûte ''træzenien'', prêtre du temple des muses ''Ardalides'', que l’ancien '''Ardalus''' avait fait bâtir à ''Træzène'' [[#Ardalus_NdT_DR|<span id="Ardalus_NdT_DR_back"><sup>1</sup></span>]].<br /><p style="text-align: center">[...]<br /><p style="text-indent: 15px">Comme j’étais au-dessus de '''Bias''', '''Thalès''' m’adressant la parole : « Pourquoi, me dit-il, ne pas avertir '''Bias''' que '''Niloxène''' vient une seconde fois de la part de son prince lui proposer des problèmes à résoudre ? Il y penserait plus librement, tandis qu’il est à jeun. - Il y a longtemps, répondit '''Bias''', que '''Dioclès''' me menace de le faire. Mais je connais la puissance de '''Bacchus''', et surtout cette sagesse qui lui a fait donner le surnom de [[wikt:λύσις#Grec_ancien|''Lysien'']] ou Dieu qui délie. Ainsi, quand je serai plein de ce dieu, je ne crains pas de combattre avec moins d'avantage. ». Ce ton de gaieté régna pendant le repas. </div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Ardalus_NdT_DR_back|<span id="Ardalus_NdT_DR"><sup>1</sup></span>]] Plutarque, dans son traité de la musique, dit qu’Ardalus, fils de Vulcain, selon la Fable, passait pour l’inventeur de la flûte.''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' pp.334, 335, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe VII.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Réflexions de '''Thalès''' sur le défi de sagacité posé par le roi des ''Éthiopiens'' au roi d’''Égypte'', [[w:Ahmôsis_II|'''Amasis''']], consistant à boire la mer. Ce dernier fait appel à '''Bias''' pour la résoudre, et celui-ci souhaite l’examiner en commun avec les sages. '''Chilon''' explique qu’il ne s’agit pas de faire disparaître tant d’eau salée, mais de rendre la domination d’'''Amasis''' potable et douce à ses sujets (§6).</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§7. [...] Ἐπὶ τούτῳ δ´ ὁ '''Θαλῆς''' ἔφησεν, εὐδαιμονίαν ἄρχοντος νομίζειν, εἰ τελευτήσειε γηράσας κατὰ φύσιν.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §7'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§7. [...] Après lui '''Thalès''' prit la parole : « J’estime que le bonheur pour un souverain, c’est s’il meurt de vieillesse et naturellement. ».</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §7'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Après lui, '''Thalès''' dit que le plus grand bonheur d’un prince serait ''de mourir de vieillesse''.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' p.339, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe IX.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Réflexions de '''Thalès''' sur le défi de sagacité posé par le roi d’''Égypte'', [[w:Ahmôsis_II|'''Amasis''']], au roi des ''Éthiopiens'', consistant en une série de questions : « Qu’y a-t-il de plus ancien ? Le temps. — De plus grand ? Le monde. — De plus habile/sage ? La vérité. — De plus beau ? La lumière. — De plus commun ? La mort. — De plus utile ? Dieu. — De plus nuisible ? Le mauvais Génie/démon. — De plus puissant/fort ? La Fortune. — De plus facile ? Le plaisir. ». '''Amasis''' fait encore appel à '''Bias''' pour analyser les réponses du roi des ''Éthiopiens'', qui les examinent également en commun avec les sages.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§9. Τούτων πάλιν ἀναγνωσθέντων, ὦ Νίκαρχε, γενομένης σιωπῆς Θαλῆς ἠρώτησε τὸν Νειλόξενον εἰ προσήκατο τὰς λύσεις ὁ Ἄμασις. ἐκείνου δ´ εἰπόντος ὅτι τὰς μὲν ἀπεδέξατο ταῖς δ´ ἐδυσκόλαινε, « καὶ μὴν οὐδέν, » εἶπεν ὁ Θαλῆς, « ἀνεπίληπτόν ἐστιν, ἀλλ´ ἔχει πάντα διαμαρτίας μεγάλας καὶ ἀγνοίας. οἷον εὐθὺς ὁ χρόνος πῶς ἂν εἴη πρεσβύτατον, εἰ τὸ μὲν αὐτοῦ γεγονὸς τὸ δ´ ἐνεστώς ἐστι τὸ δὲ μέλλον; ὁ γὰρ μεθ´ ἡμᾶς ἐσόμενος χρόνος καὶ πραγμάτων τῶν νῦν καὶ ἀνθρώπων νεώτερος ἂν φανείη. τὸ δὲ τὴν ἀλήθειαν ἡγεῖσθαι σοφίαν οὐδὲν ἐμοὶ δοκεῖ διαφέρειν τοῦ τὸ φῶς ὀφθαλμὸν ἀποφαίνειν. εἰ δὲ τὸ φῶς καλόν, ὥσπερ ἐστὶν, ἐνόμιζε, πῶς τὸν ἥλιον αὐτὸν παρεῖδε; τῶν δ´ ἄλλων ἡ μὲν περὶ θεῶν καὶ δαιμόνων ἀπόκρισις θράσος ἔχει καὶ κίνδυνον, ἀλογίαν δὲ καὶ πολλὴν ἡ περὶ τῆς τύχης· οὐ γὰρ ἂν μετέπιπτε ῥᾳδίως οὕτως, ἰσχυρότατον οὖσα τῶν ὄντων καὶ ῥωμαλεώτατον. οὐ μὴν οὐδ´ ὁ θάνατος κοινότατόν ἐστιν· οὐ γάρ ἐστι πρὸς τοὺς ζῶντας. ἀλλ´ ἵνα μὴ δοκῶμεν εὐθύνειν τὰς τῶν ἑτέρων ἀποφάσεις, ἰδίας ταῖς ἐκείνου παραβάλωμεν· ἐμαυτὸν δὲ παρέχω πρῶτον, εἰ βούλεται Νειλόξενος, ἐρωτᾶν καθ´ ἕκαστον. ὡς οὖν ἐγένοντο τότε, κἀγὼ νῦν διηγήσομαι τὰς ἐρωτήσεις καὶ τὰς ἀποκρίσεις· ‘Τί πρεσβύτατον;’ [[wikt:en:θεός#Ancient_Greek|‘θεός,’]] » ἔφη Θαλῆς· « ‘ἀγέν νητον γάρ ἐστι.’ ‘Τί μέγιστον;’ ‘τόπος· τἄλλα μὲν γὰρ ὁ κόσμος, τὸν δὲ κόσμον οὗτος περιέχει.’ ‘Τί κάλλιστον;’ ‘κόσμος· πᾶν γὰρ τὸ κατὰ τάξιν τούτου μέρος ἐστί.’ ‘Τί σοφώτατον;’ ‘χρόνος· τὰ μὲν γὰρ εὕρηκεν οὗτος ἤδη, τὰ δ´ εὑρήσει.’ ‘Τί κοινότατον;’ ‘ἐλπίς· καὶ γὰρ οἷς ἄλλο μηδέν, αὕτη πάρεστι.’ ‘Τί ὠφελιμώτατον;’ ‘ἀρετή· καὶ γὰρ τἄλλα τῷ χρῆσθαι καλῶς ὠφέλιμα ποιεῖ.’ ‘Τί βλαβερώτατον;’ ‘κακία· καὶ γὰρ τὰ πλεῖστα βλάπτει παραγενομένη.’ ‘Τί ἰσχυρότατον;’ ‘ἀνάγκη· μόνον γὰρ ἀνίκητον.’ ‘Τί ῥᾷστον;’ ‘τὸ κατὰ φύσιν, ἐπεὶ πρὸς ἡδονάς γε πολλάκις ἀπαγορεύουσιν.’ » <br /><br /><p style="text-indent: 15px;">§10. Ἀποδεξαμένων δὲ πάντων τὸν Θαλῆν, ὁ Κλεόδωρος εἶπε, « τοιαῦτ´ ἐρωτᾶν καὶ ἀποκρίνεσθαι βασιλεῦσιν, ὦ Νειλόξενε, προσῆκόν ἐστιν· ὁ δὲ προπίνων τὴν θάλατταν Ἀμάσιδι βάρβαρος ἐδεῖτο τῆς Πιττακοῦ βραχυλογίας, ᾗ πρὸς Ἀλυάττην ἐχρήσατο προστάττοντά τι καὶ γράφοντα Λεσβίοις ὑπερήφανον, ἀποκρινάμενος οὐδὲν ἀλλ´ ἢ μόνον κελεύσας κρόμμυα καὶ θερμὸν ἄρτον ἐσθίειν. »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §9'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§9. Cette lecture ainsi reproduite, mon cher '''Nicarque''', il se fit un moment de silence. Après quoi '''Thalès''' demanda à '''Niloxène''' si '''Amasis''' avait accepté de telles solutions. Il répondit que ce monarque avait accepté les unes et qu’il avait été mécontent des autres. « C’est qu’en effet », dit '''Thalès''', « il n’en est aucune qui soit irréprochable, et toutes sont grandement entachées d’erreur et d’ignorance. Ainsi, d’abord, comment le temps pourrait-il être ce qu’il y a de plus ancien, puisque, une partie étant écoulée, je le veux bien, une autre est le présent, une autre est l’avenir ? Le temps qui doit venir après nous est évidemment plus jeune que les hommes d’aujourd’hui, que les événements actuels. Croire que ce qu’il y a de plus habile, ce soit la vérité, c’est, à mon avis, ne pas émettre une autre opinion que celle-ci : l’oeil et la lumière sont tout un. Si du reste l’''Éthiopien'' a cru, ce qui est réel, la lumière plus belle que tout, pourquoi a-t-il négligé de nommer le soleil lui-même ? Des autres réponses, celle qui concerne la Divinité et le Génie est aussi téméraire que dangereuse ; et ce qu’il dit de la Fortune est tout à fait déraisonnable : car elle ne changerait pas avec tant de facilité, si elle était ce qu’il y a de plus puissant et de plus fort au monde. De même, la mort n’est pas ce qu’il y a de plus commun, puisqu’elle n’est pas commune aux vivants. Mais pour que nous ne semblions pas nous borner à redresser les réponses des autres, il faut y opposer nos propres solutions. Je m’y offre le premier, si '''Niloxène''' veut reprendre chaque question ». Telles que furent faites alors et les demandes et les réponses, je vais vous les reproduire aujourd’hui : Qu’y a-t-il de plus ancien ? C’est dieu, répondit '''Thalès''', attendu qu’il est incréé. — De plus grand ? L’espace : car si le monde contient le reste, à son tour il est contenu dans l’espace. — De plus beau ? Le monde : car tout ce qui est bien ordonné en fait partie. ― De plus habile ? Le temps : car c’est lui qui a découvert et qui découvrira tout. — De plus commun ? L’espérance : car ceux même qui n’ont rien autre chose la possèdent. — De plus utile ? La vertu : car elle rend toutes les autres choses utiles par le bon usage qu’elle en fait. — De plus nuisible ? Le vice : car il corrompt tout par sa présence. — De plus puissant ? La nécessité : car elle est seule invincible. De plus facile ? Ce qui est selon la nature : car, pour ce qui est du plaisir, il amène souvent la lassitude.<br /><br /><p style="text-indent: 15px;">§10. Tout le monde ayant accueilli ces réponses de '''Thalès''', '''Cléodème''' prit la parole : « Voilà », dit-il, « ô '''Niloxène''', les questions et les réponses qu’il est convenable de faire à des rois. Mais le barbare qui veut faire boire la mer à '''Amasis''' aurait besoin de la concision employée par '''Pittacus''' à l’égard d’[[w:Alyatte_II|'''Alyatte''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Alyatte_back|<sup>🔄</sup>]], quand celui-ci enjoignait aux ''Lesbiens'' un ordre des plus insolents. Il se contenta, pour toute réponse, de l’engager « à manger des oignons et du pain chaud. »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §9'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Cette lecture étant finie, il se fit un moment de silence ; après quoi, '''Thalès''' demanda si le roi d’''Égypte'' avait approuvé toutes ces solutions. '''Niloxène''' lui répondit qu’il avait adopté les unes et rejeté les autres : « Mais, reprit '''Thalès''', il n’en est aucune d’admissible, et qui ne soit marquée au coin de l’erreur et de l’ignorance. D'abord, comment le temps peut-il être ce qu’il y a de plus ancien, puisqu’on le divise en passé, présent et avenir ? Ce dernier est certainement moins ancien que les hommes et que les événements actuels. Dire que la vérité est la sagesse, c’est, ce me semble, confondre l’œil avec la lumière. Si d’ailleurs la lumière est, selon lui, ce qu'’il y a de plus beau, pourquoi ne pas nommer le soleil lui-même ? Quant aux autres réponses, celles qu’il a faites sur les dieux et les démons sont aussi hardies que dangereuses. Ce qu’il dit de la fortune est tout à fait déraisonnable. Si elle est réellement si forte et si puissante, comment change-t-elle avec tant de facilité ? Enfin la mort n’est pas ce qu’il y a de plus commun, puisqu’elle n’existe point parmi les vivants. Mais pour qu’on ne croie pas que nous voulons seulement critiquer, opposons à ces réponses nos solutions. Je m’offre le premier pour répondre , si '''Niloxène''' veut reprendre les questions . »<br /><br /><p style="text-indent: 15px;">'''Niloxène''' le fit, et '''Thalès''' donna ses réponses, que je vais vous répéter. Qu’y a-t-il de plus ancien ? Dieu ; car il est éternel. De plus grand ? l’espace ; il contient le monde, qui lui-même renferme tout le reste. De plus beau ? le monde ; tout ce qui est dans l’ordre en fait partie. De plus sage ? le temps ; il a découvert ou découvrira tout. De plus commun ? l’espérance ; elle reste à ceux mêmes qui n’ont rien. De plus utile ? la vertu; elle fait bien user de tout. De plus nuisible ? le vice ; il corrompt tout par sa présence. De plus fort ? la nécessité ; elle seule est invincible. De plus facile ? ce qui est selon la nature ; on se lasse souvent du plaisir même.<br /><br /><p style="text-indent: 15px;">Tout le monde applaudit aux solutions de '''Thalès''' : « Voilà, dit '''Cléodème''', les questions et les réponses qu’il convient à des rois de faire. Pour ce barbare, qui propose à votre prince de boire toute la mer, il lui fallait une réponse aussi courte que celle de '''Pittacus''' au roi de ''Lydie'' '''Alyatte''', qui , dans une lettre, donnait aux ''Lesbiens'' un ordre très impérieux. '''Pittacus''' se contenta de lui récrire : ''Mangez des ognons et du pain chaud'' [[#expression_proverbiale_mépris_NdT_DR|<span id="expression_proverbiale_mépris_NdT_DR_back"><sup>1</sup></span>]].</div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#expression_proverbiale_mépris_NdT_DR_back|<span id="expression_proverbiale_mépris_NdT_DR"><sup>1</sup></span>]] C’est-à-dire : pleurez ; expression proverbiale, pour témoigner du mépris à quelqu’un.''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' pp.341, 342, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe XI.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Réflexion de '''Thalès''' sur les gouvernements où la loi est égale pour tous.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§11. Ἐπὶ τούτῳ '''Θαλῆς''' τὴν μήτε πλουσίους ἄγαν μήτε πένητας ἔχουσαν πολίτας.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §11'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§11. Après lui '''Thalès''' : « que c’est celle qui n’a ni des citoyens trop riches, ni des citoyens trop pauvres. »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §11'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">'''Thalès''' : ''celle dont les citoyens ne sont ni trop riches ni trop pauvres''.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' p.345, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe XII.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Réflexion de '''Thalès''' sur la maison la mieux réglée.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§12. Ὁ δὲ '''Θαλῆς''' ἐν ᾧ πλείστην ἄγειν τῷ δεσπότῃ σχολὴν ἔξεστιν.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §12'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§12. '''Thalès''' : « celle où le maître peut avoir un très grand loisir. »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §12'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">'''Thalès''' : ''celle qui donne le moins d’affaires à son maître''.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' p.346, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe XIII.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Référence à l’anecdote de la coupe de [[w:Bathyclès_de_Magnésie|'''Bathyclès''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_période_Grèce_Hellénistique#Bathyclès_back|<sup>🔄</sup>]] par [[w:Callimaque_de_Cyrène|'''Callimaque''']] de [[w:Cyrène|''Cyrène'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_période_Grèce_Hellénistique#Callimaque_back|<sup>🔄</sup>]].</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§13. Ἐπεὶ δὲ καὶ οὗτος ἔσχεν ὁ λόγος τέλος, ἡ μὲν Εὔμητις ἐξῆλθε μετὰ τῆς Μελίσσης, τοῦ δὲ Περιάνδρου τῷ Χίλωνι προπιόντος εὐμεγέθη κύλικα, τῷ δὲ Βίαντι τοῦ Χίλωνος, Ἄρδαλος ἐπαναστὰς καὶ προσαγορεύσας τὸν Αἴσωπον, « σὺ δ´ οὐκ ἄν, » ἔφη, « διαπέμψαιο δεῦρο τὸ ποτήριον πρὸς ἡμᾶς, ὁρῶν τούτους ὥσπερ τὴν Βαθυκλέους κύλικα διαπεμπομένους ἀλλήλοις, ἑτέρῳ δὲ μὴ μεταδιδόντας; » Καὶ ὁ Αἴσωπος, « ἀλλ´ οὐδὲ τοῦτ´, » ἔφη, « τὸ ποτήριον δημοτικόν ἐστι· Σόλωνι γὰρ ἔκπαλαι παράκειται μόνῳ. »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §13'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§13. Ce texte de conversation se trouvant à son tour épuisé, et '''Eumétis''' étant sortie avec '''Mélissa''', '''Périandre''' but une grande coupe à '''Chilon''', et '''Chilon''', à '''Bias'''. '''Ardalus''' alors se leva, et interpellant '''Ésope''' : « Ne feras-tu pas, dit-il, circuler la coupe jusqu’à nous, quand tu vois qu’ils se la passent mutuellement comme s’il s’agissait de celle de '''Bathycle''' et qu’ils ne la partagent pas avec un autre ? » Et '''Esope''' : « Mais ce vase non plus, dit-il, n’est pas une propriété populaire : car voilà longtemps qu’il reste devant '''Solon''' tout seul ».</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §13'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Après tous ces propos, '''Mélisse''' sortit avec '''Eumétis'''. '''Périandre''' alors boit le premier dans une grande coupe, la présente à '''Chilon''' [[#Chilon_NdT_DR|<span id="Chilon_NdT_DR_back"><sup>1</sup></span>]], et celui-ci à '''Bias''', qui la remit à '''Solon'''. Comme ce dernier la gardait, '''Ardalus''' se lève , et s’adressant à '''Esope''' : « Ne nous ferez-vous point, lui dit-il, passer ce vase, que nos sages, comme vous voyez, se renvoient l’un à l’autre, ainsi que la coupe de '''Bathycle''', sans le faire parvenir jusqu’à nous [[#Bathycle_NdT_DR|<span id="Bathycle_NdT_DR_back"><sup>2</sup></span>]] ? ― Ce vase, lui répondit '''Esope''', n’est sûrement pas populaire, puisqu’il reste si longtemps devant '''Solon'''. »</div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Chilon_NdT_DR_back|<span id="Chilon_NdT_DR"><sup>1</sup></span>]] Cet usage était constant chez les anciens. A la fin du repas, on remplissait de vin une grande coupe. Le principal personnage de l’assemblée en buvait le premier, et la coupe passait ainsi de main en main.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Bathycle_NdT_DR_back|<span id="Bathycle_NdT_DR"><sup>2</sup></span>]] Tout le monde sait l’histoire du fameux trépied d’or, trouvé par des pêcheurs, qui, pour terminer leurs débats, ayant eu recours à l’oracle de ''Delphes'', reçurent ordre d’en faire présent au plus sage, et l’envoyèrent à Thalès. Après avoir passé successivement par les mains des sept sages, il revint à Thalès, qui le consacra dans un temple d’Apollon. Selon Léandre de ''Milet'', cité par Diogène Laërce, c’était une coupe d’or que l’''Arcadien'' Bathycle avait laissée, par son testament, au plus sage, et c’est ce dernier récit que Plutarque semble préférer.''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' p.347, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe XIV.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage de l’''espièglerie'' de '''Thalès'''.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§14. [...] '''Ἐπιστήσαντος''' δὲ τοῦ λόγου τὸ συμπόσιον ὁ μὲν '''Θαλῆς''' ἐπισκώπτων εὖ φρονεῖν ἔφη τὸν '''Ἐπιμενίδην''' ὅτι μὴ βούλεται πράγματα ἔχειν ἀλῶν τὰ σιτία καὶ πέττων ἑαυτῷ, καθάπερ '''Πιττακός'''. « ἐγὼ γάρ, » εἶπε, « τῆς ξένης ἤκουον ᾀδούσης πρὸς τὴν μύλην, ἐν [[w:Eresós|''Ἐρέσῳ'']] γενόμενος, ἄλει, μύλα, ἄλει· καὶ γὰρ '''Πιττακὸς''' ἄλει μεγάλας ''Μυτιλάνας'' βασιλεύων. »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §14'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§14. [...] Ces paroles ayant mis en arrêt les convives, '''Thalès''' dit en raillant qu’'''Epiménide''' avait bien raison de ne pas vouloir se donner l’embarras de moudre et de cuire lui-même son manger, comme faisait '''Pittacus''' : « Car je me souviens », ajouta-t-il, « qu’étant à ''Lesbos'', j’entendis mon hôtesse chanter à sa meule : Va ton train, meule, va ton train, puisque '''Pittacus''', le roi de la grande ''Mitylène'', s’occupe bien à moudre. »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §14'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Ce discours ayant frappé tout le monde, '''Thalès''' dit en plaisantant qu’il approuvait '''Epiménides''' [[#Epiménides_NdT_DR|<span id="Epiménides_NdT_DR_back"><sup>1</sup></span>]] de s’épargner la peine de moudre et de cuire lui-même son pain, comme faisait '''Pittacus'''. « Je me souviens , ajouta-t-il, qu’étant à ''Lesbos'', j’ai entendu une meunière qui chantait : ''Moulez, meule, moulez ; '''Pittacus''', qui règne dans la superbe Mitylène, s’occupe aussi à moudre'' [[#Pittacus_NdT_DR|<span id="Pittacus_NdT_DR_back"><sup>2</sup></span>]]. »</div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Epiménides_NdT_DR_back|<span id="Epiménides_NdT_DR"><sup>1</sup></span>]] Epiménides était un poète de l’île de ''Crète''. Les nymphes, disait-on, lui avaient donné un aliment miraculeux, qu’il conservait dans une corne de bœuf, et dont une très petite quantité suffisait pour le nourrir. ''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Pittacus_NdT_DR_back|<span id="Pittacus_NdT_DR"><sup>2</sup></span>]] Pittacus, au rapport de différents historiens, s’exerçait à moudre du blé. Il faisait un grand éloge de l’utilité des moulins, et insistait sur l’avantage qu’a le moulin de fournir, dans un très petit espace, le moyen de prendre différents exercices. ''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' p.351, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe XV.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage d’une doctrine de '''Thalès''' sur l’importance vitale de l’agriculture.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§15. [...] « Οὐδαμῶς, » ὁ '''Κλεόδωρος''', « ἔμοιγ´, » εἶπεν, « εἰ δεῖ τὸ φαινόμενον εἰπεῖν, καὶ μάλιστα παρακειμένης τραπέζης, ἣν ἀναιροῦσιν αἰρομένης τροφῆς φιλίων θεῶν βωμὸν οὖσαν καὶ ξενίων. ὡς δὲ '''Θαλῆς''' λέγει τῆς γῆς ἀναιρεθείσης σύγχυσιν τὸν ὅλον ἕξειν κόσμον, οὕτως οἴκου διάλυσις ἐστι· συναναιρεῖται γὰρ αὐτῇ πῦρ ἑστιοῦχον ἑστία κρατῆρες ὑποδοχαὶ ξενισμοί, φιλανθρωπότατα καὶ πρῶτα κοινωνήματα πρὸς ἀλλήλους, μᾶλλον δὲ σύμπας ὁ βίος, εἴ γε διαγωγή τίς ἐστιν ἀνθρώπου πράξεων ἔχουσα διέξοδον, ὧν ἡ τῆς τροφῆς χρεία καὶ παρασκευὴ τὰς πλείστας παρακαλεῖ. [...] »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §15'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§15. [...] « S’il faut dire ce que je pense », reprit '''Cléodème''', « ce n’est nullement mon avis, et surtout quand est dressée la table, que l’on supprime si la nourriture est supprimée et qui est l’autel des dieux amis et hospitaliers. Et s’il est vrai, comme dit '''Thalès''', que la suppression de la terre dût entraîner le désordre et la ruine du monde entier, de même anéantir la table ce serait anéantir la maison. Avec la table disparaîtraient le feu qui consacre le foyer, le foyer lui-même, les coupes, les réceptions, les hospitalités, qui sont les plus affectueux et les premiers rapports de communauté entre les hommes; ou plutôt disparaîtrait la vie entière, s’il est vrai que la vie soit une sorte de courant formé par la série des actes de l’homme, actes dont le plus grand nombre est commandé par le besoin et la préparation de la nourriture.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §15'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">S’il faut, reprit '''Cléodème''', que je dise mon sentiment, je ne suis point du tout de cet avis-là, surtout quand la table est dressée. Nous ôter le besoin de nourriture, c’est détruire cet autel des dieux hospitaliers. Et comme la destruction de la terre, selon '''Thalès''', entraînerait la ruine de l’univers, ainsi la chute de la table causerait celle de la maison. Avec elle, on détruirait le feu sacré de nos foyers, les dieux pénates, les libations, le plaisir si touchant de recevoir et de traiter ses amis, tous ces usages respectables qui sont les premiers fondements et les plus doux liens de la société ; disons mieux, on détruirait la vie entière, puisqu’elle est remplie par des occupations et des soins successifs, dont la plupart ont pour objet la nourriture et sa préparation.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' pp.353, 354, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe XVII.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage d’une parole sage de '''Thalès''' : Ne croire ni ses ennemis sur les choses croyables, ni ses amis sur les choses incroyables.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§17. τέλος δὲ γελάσας πρὸς ἡμᾶς « βούλομαι μέν, » ἔφη, « πρὸς τὸ παρὸν φράσαι τὸ προσηγγελμένον· ὀκνῶ δ´ ἀκούσας '''Θαλέω''' ποτ´ εἰπόντος ὅτι δεῖ τὰ μὲν εἰκότα λέγειν, τὰ δ´ ἀμήχανα σιωπᾶν. » Ὑπολαβὼν οὖν ὁ '''Βίας''' « ἀλλὰ καὶ τοῦτ´, » ἔφη, « '''Θαλέω''' τὸ σοφόν ἐστιν, ὅτι δεῖ τοῖς μὲν ἐχθροῖς καὶ περὶ τῶν πιστῶν ἀπιστεῖν, τοῖς δὲ φίλοις καὶ τὰ ἄπιστα πιστεύειν, ἐχθροὺς μέν, ἔγωγ´ ἡγοῦμαι, τοὺς πονηροὺς καὶ ἀνοήτους, φίλους δὲ τοὺς χρηστοὺς καὶ φρονίμους αὐτοῦ καλοῦντος. οὐκοῦν, »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §17'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§17. [...] A la fin il s’adressa à nous en éclatant de rire : « Je voudrais vous faire connaître, sans plus attendre, ce que '''Gorgias''' vient de me conter; et pourtant j’hésite, parce que j’ai autrefois entendu dire à '''Thalès''' qu’il faut dire les choses vraisemblables et taire les impossibles. « Mais, reprit '''Bias''', « c’est à '''Thalès''' aussi qu’appartient cette sage parole : qu’il faut ne pas croire ses ennemis même sur les choses croyables, et croire ses amis même sur celles qui ne le sont pas : par ennemis il entendait, je suppose, les méchants et les sots, par amis, les gens vertueux et sensés. »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §17'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Mais quand '''Gorgias''' [[#Gorgias_NdT_DR|<span id="Gorgias_NdT_DR_back"><sup>1</sup></span>]] eut achevé, il nous dit en riant : « Je voudrais vous répéter ce que je viens d’entendre ; mais je n’ose le faire après ce mot de '''Thalès''' : qu’il faut dire les choses vraisemblables, et taire celles qui paraissent impossibles. - Mais, repartit '''Bias''' , n’est-ce pas aussi '''Thalès''' qui a dit cette autre maxime si sage, qu’il faut ne pas croire ses ennemis même sur les choses croyables, et croire ses amis sur les choses même les moins vraisemblables. Par les ennemis, il entend, sans doute, les méchants et les insensés ; par les amis, les bons et les sages.</div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Gorgias_NdT_DR_back|<span id="Gorgias_NdT_DR"><sup>1</sup></span>]] Tout ce qu’on sait de ce frère de Périandre, c’est qu’il fonda une colonie dans l’''[[w:Ambracie|Ambracie]]'', et qu’il mourut vraisemblablement avant son frère, puisque son fils [[w:Psammétique_(Corinthe)|Psammétique]] succéda à Périandre, et fut le dernier tyran de ''Corinthe'' de la race de [[w:Cypsélos|Cypsèle]]. ''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' p.358, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe XXI.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage d’une doctrine de '''Thalès''' sur la résidence de l'âme dans toutes les parties du monde les plus essentielles.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§21. Μετὰ δὲ τοῦτον ὁ '''Ἀνάχαρσις''' εἶπεν ὅτι τοῦ '''Θαλέω''' καλῶς ὑπολαμβάνοντος ἐν πᾶσιν εἶναι τοῖς κυριωτάτοις μέρεσι τοῦ κόσμου καὶ μεγίστοις ψυχήν, [...].</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §21'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§21. Après '''Pittacus''', '''Anacharsis''' prit la parole : « Puisque, comme '''Thalès''' l’a magnifiquement établi, une âme réside dans toutes les parties du monde les plus essentielles, [...].</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §21'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">'''Pittacus''' ayant cessé de parler, '''Anacharsis''' prit la parole : « S’il est vrai, dit-il, comme '''Thalès''' le croit avec raison, que les plus grandes et les principales parties du monde ont une ame, [...].</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' p.365, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto; color: #3366BB">― ✳ ―</div> ==== Du démon de '''Socrate''' ==== <div style="text-align: center; margin: 0 1em;">Discussion autour de la libération de [[w:Thèbes (Grèce)|''Thèbes'']] de ''[[w:Sparte|Sparte]]'' grâce à une conjuration de '''[[w:Pélopidas|Pélopidas]]''' [[#Pélopidas|<span id="Pélopidas_back"><sup>'''I'''</sup></span>]] en [[w:-379|-379]]. Le récit est ici plus ample que lors de la biographie de Pélopidas dans les ''[[w:Vies parallèles|Vies parallèles]]''. La source de '''Plutarque''' est d’origine ''thébaine'', la même que '''[[w:Cornélius Népos|Cornélius Népos]]''' [[#Cornélius_Népos|<span id="Cornélius_Népos_back"><sup>'''II'''</sup></span>]]. Le traité porte sur la ''[[w:démonologie|démonologie]]'', le démon de '''Socrate''' peut-être une voix intérieure ou ses capacités [[w:divinatoires|divinatoires]]'', la légende étant d’origine [[w:pythagoricienne|pythagoricienne]] et évoque l’oracle '''[[w:Trophonios|Trophonios]]'''.</div> {{Boîte déroulante début|titre=NdA du Démon de Socrate|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Pélopidas_back|<span id="Pélopidas"><sup>I</sup></span>]] Du nom propre grec ancien Πελοπῐ́δᾱς / Pelopĭ́dās [[wikt:en:Πελοπίδας#Ancient_Greek|(en)]] ;<br /><p style="margin: 0 2em; text-indent: 15px;">Stratège [[w:Thèbes (Grèce)|''thébain'']]. Chassé en [[w:-382|-382]] de ''Thèbes'' après la prise de la [[w:Cadmée_(Thèbes)|Cadmée]], la citadelle située au sommet de son ''[[w:acropole|acropole]]'', par [[w:Phébidas|Phébidas]] avec l’aide des ''[[w:Sparte|Spartiates]]'', il renverse le gouvernement pro-spartiate d’[[w:Archias de Thèbes|Archias]] et de Léontidas en [[w:-379|-379]], qu’il tue, et rétablit la ''[[w:démocratie|démocratie]]''.<br /><p style="text-align: right; margin: 0 2em;">(date de naissance inconnue, à ''Thèbes'' — [[w:364_av._J.-C.|-364]]<sup>[[w:IVe_siècle_av._J.-C.|⏳]]</sup>, mort lors de la [[w:Bataille_de_Cynoscéphales_(364_av._J.-C.)|''bataille de Cynoscéphales'']], dans le cadre d’une vengeance pour sa captivité par le ''tyran'' de [[w:Thessalie|''Thessalie'']], [[w:Alexandre_de_Phères|Alexandre]] de [[w:Phères|''Phères'']], alors qu’il était en ambassade chez lui)<br /><br /><p style="margin: 0 2em; text-indent: 15px;">[[#Cornélius_Népos|<span id="Cornélius_Népos"><sup>II</sup></span>]] [[w:Nom_romain|Tria Nomina]] en latin ''{{Info|<nowiki>[praenomen inconnu]</nowiki>|praenomen, nom individuel du citoyen romain}}'' {{Info|Cornélius|nomen, nom de famille}} {{Info|Népos|cognomen, surnom héréditaire, servant à distinguer les diverses branches d’une même gens}}<br /><p style="margin: 0 2em; text-indent: 15px;">Auteur ''latin''. On sait par les lettres de Cicéron que Cornelius Népos n’aimait pas les écrits moraux, leur préférant la description de la nature et l’étude de l’histoire. Aucun des ouvrages qu’il avait composés dans ce genre n’est parvenu en entier jusqu’à nous. Les « Vies des grands capitaines de l’antiquité » qui subsistent aujourd’hui, et qui ont connu de multiples éditions, lui ont été attribuées jusqu'au XVIIIe siècle ; mais l'analyse de ce court recueil montre qu'il ne serait qu'un abrégé (attribué à Æmilius Probus), de l’ouvrage original de Cornelius Népos.<br /><p style="text-align: right; margin: 0 2em;">(vers [[w:-100|-100]], au pays des [[w:Insubres|Insubres]] à [[w:Mantoue|Mantoue]] ou à [[w:Pavie|''Ticinum'']], dans le nord de l’''Italie'' — vers [[w:-29|-29]]/[[w:-25|-25]], à ''Rome'')<sup>[[w:Ier_siècle_av._J.-C.|⏳]]</sup>'''<br /><br /> </div>{{Boîte déroulante fin}} ===== <div style="text-align: center;">Paragraphe VI.</div> ===== <div style="text-align: center; margin: 0 1em;">Témoignage de l’aversion de '''Thalès''' pour les [[w:Tyran|''tyrans'']].</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid;"><br /><div style="text-align: justify; margin: 0 2em; text-indent: 15px">§6. Ταῦτα τοῦ '''Θεοκρίτου''' λέγοντος ὁ '''Λεοντίδης''' ἐξῄει μετὰ τῶν φίλων, ἡμεῖς δ´ εἰσελθόντες ἠσπαζόμεθα τὸν '''Σιμμίαν''' ἐπὶ τῆς κλίνης καθεζόμενον οὐ κατατετευχότα τῆς δεήσεως, οἶμαι, μάλα σύννουν καὶ διαλελυπημένον· ἀποβλέψας δὲ πρὸς ἅπαντας ἡμᾶς ‘ὦ '''Ἡράκλεις''',’ εἶπεν ‘ἀγρίων καὶ βαρβάρων ἠθῶν· εἶτ´ οὐχ ὑπέρευ '''Θαλῆς''' ὁ παλαιὸς ἀπὸ ξένης ἐλθὼν διὰ χρόνου τῶν φίλων ἐρωτώντων ὅ τι καινότατον ἱστορήκοι ’τύραννον‘ ἔφη ’γέροντα.‘ καὶ γὰρ ᾧ μηδὲν ἰδίᾳ συμβέβηκεν ἀδικεῖσθαι, τὸ βάρος αὐτὸ καὶ τὴν σκληρότητα τῆς ὁμιλίας δυσχεραίνων ἐχθρός ἐστι τῶν ἀνόμων καὶ ἀνυπευθύνων δυναστειῶν.[...]</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome II, [https://remacle.org/bloodwolf/historiens/Plutarque/demonsocrategr.htm Περι του Σωκρατους Δαιμονιου - Le Démon de Socrate], §6'', traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§6. Pendant que [[w:Théocrite|'''Théocritos''']] [[#Théocrite|<span id="Théocrite_back"><sup>'''I'''</sup></span>]] parlait, '''Léontidas''' sortit avec ses amis, et nous entrâmes chez [[w:Simmias_de_Thèbes|'''Simmias''']] [[#Simmias_de_Thèbes|<span id="Simmias_de_Thèbes_back"><sup>'''II'''</sup></span>]], que nous saluâmes affectueusement. Il était assis sur son lit, et j’attribuai à l’insuccès de sa demande son air pensif et affligé. Après nous avoir regardés tous : « Par '''Hercule''' ! s’écria-t-il, quelles mœurs sauvages et barbares ! Eh bien ! n’avait-il pas cent fois raison le '''Thalès''' des anciens jours ? Comme il était revenu d’un long voyage à l’étranger, ses amis lui demandaient ce qu’il avait vu de plus curieux : « Un tyran parvenu à la vieillesse », répondit-il. Car ceux même qui n’ont pas éprouvé de la part d’un despote une injustice personnelle, supportent avec peine le poids et la dureté d’un semblable régime. On déteste tout pouvoir qui est en dehors de la loi et qui ne veut rendre de comptes à personne. [...]</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome III, [[s:Page:Plutarque_-_Œuvres_complètes_de_Plutarque_-_Œuvres_morales_et_œuvres_diverses,_tome_3,_1870.djvu/74|Περι του Σωκρατους Δαιμονιου - Le Démon de Socrate]], [[s:Page:Plutarque_-_Œuvres_complètes_de_Plutarque_-_Œuvres_morales_et_œuvres_diverses,_tome_3,_1870.djvu/83|§6]]'', traduites par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> {{Boîte déroulante début|titre=NdA de trad. Victor Bétolaud de 1870|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Théocrite_back|<span id="Théocrite"><sup>I</sup></span>]] Du nom propre [[w:Nom_théophore|''théophore'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_période_Grèce_Classique#théophore_back|<sup>🔄</sup>]] grec ancien Θεόκριτος / Theókritos [[wikt:en:Θεόκριτος#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;">➥ de l’adjectif et du nom commun θεός / theós [[wikt:en:θεός#Ancient_Greek|(en)]], « divin, dieu, divinité »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ +‎ du verbe κρίνω / krínō, « 1. (transitif) Séparer, diviser, distinguer entre deux choses ou personnes ou parmi un groupe de choses ou de personnes. 2. (transitif) Commander, organiser. 3. S’enquérir, enquêter. 4. Sélectionner, choisir, préférer. 5. (transitif) Trancher un différend ou un concours ; (intransitif) Porter un jugement, prendre une décision : • (voix moyenne, voix passive) Décider d’un concours ; (voix moyenne et voix passive) Se disputer, se disputer, se quereller. 6. Décider ou juger [+accusatif et infinitif = que quelque chose fait quelque chose], [+accusatif et accusatif = que quelque chose est quelque chose]. 7. Discerner entre le bien et le mal. 8. Juger, prononcer. 9. Traduire en justice, accuser. 10. Condamner, critiquer. 11. Sécréter, cacher, dissimuler. »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ + le suffixe adjectival récessif‎ -τος / -tos [[wikt:en:-τος#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;">''Poète'', auteur de [[w:Mime|''mimes'']] (imitations comiques du langage ou des gestes), d’[[w:Poésie_pastorale|''idylles pastorales'']] et de [[w:Épopée|''contes épiques'']].<br /><p style="text-align: right; margin: 0 2em;">([[w:Circa|{{Info|''ca.''|Circa, locution latine que l’on emploie pour indiquer l’approximation d’une date}}]] [[w:310_av._J.-C.|-310]]<sup>[[w:IVe_siècle_av._J.-C.|⏳]]</sup>, à [[w:Théocrite#cite_ref-2|''Syracuse'']] — {{Info|''ca.''|Circa, locution latine que l’on emploie pour indiquer l’approximation d’une date}} [[w:250_av._J.-C.|-250]]<sup>[[w:IIIe_siècle_av._J.-C.|⏳]]</sup>) <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Simmias_de_Thèbes_back|<span id="Simmias_de_Thèbes"><sup>II</sup></span>]] Du grec ancien Σιμμίας ο Θηβαίος / Simmías o Thēbaíos ;<br /><p style="margin: 0 2em; text-indent: 15px;">Philosophe grec et disciple de [[w:Socrate|Socrate]] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Socrate_back|<sup>🔄</sup>]].<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:Ve_siècle_av._J.-C.|V<sup>ème</sup>]] et [[w:IVe_siècle_av._J.-C.|IV<sup>ème</sup>]] siècles {{Info|AEC|Avant l’Ère Commune}}, ''Thèbes'')'''<br /><br /> </div>{{Boîte déroulante fin}} <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">§6. Pendant que '''Théocritos''' discourait ainsi, '''Léontidas''' sortit avec ses amis ; nous entrâmes et saluâmes '''Simmias''', qui était assis sur son lit, tout soucieux et triste, parce que sa demande avait été rejetée sans doute. En nous regardant tous, il s’écria : « '''Héraclès''' ! les moeurs sauvages et barbares ! Ah ! que '''Thalès''' l’ancien avait raison de répondre, lorsqu’après un long voyage à l’étranger ses amis lui demandaient ce qu’il avait remarqué de plus extraordinaire : « Un tyran âgé ». Même un homme qui a eu la chance de n’être pour son compte victime d’aucune injustice exècre déjà le poids et la dureté de ce commerce et est ennemi des dictatures, des dominations arbitraires.[...]</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome II, [https://remacle.org/bloodwolf/historiens/Plutarque/demonsocrate.htm Περι του Σωκρατους Δαιμονιου - Le Démon de Socrate], §6'', traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto; color: #3366BB">― ✳ ―</div> ==== Les [[w:Alimentation_en_Grèce_antique#Banquets|''Symposiaques'']] [[#Symposiaques|<span id="Symposiaques_back"><sup>'''I'''</sup></span>]], ou questions de table ==== <div style="text-align: center; margin: 0 1em;"></div> {{Boîte déroulante début|titre=NdA Les Symposiaques|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Symposiaques_back|<span id="Symposiaques"><sup>I</sup></span>]] Du nom commun grec ancien συμπόσιον / sympósion [[wikt:en:συμπόσιον#Ancient_Greek|(en)]], « Seconde partie d’un repas pendant laquelle un groupe restreint de convives buvaient et discutaient sur un sujet. » ; <br /><p style="margin: 0 2em; text-indent: 15px;">➥ du nom commun σῠμπότης / sŭmpótēs [[wikt:en:συμπότης#Ancient_Greek|(en)]], « compagnon de boisson » ; <br /><p style="margin: 0 4em; text-indent: 15px;">➥ du préfixe σῠν- / sŭn- [[wikt:en:συν-#Ancient_Greek|(en)]], « avec, ensemble » ;<br /><p style="margin: 0 4em; text-indent: 15px;">➥ +‎ du nom commun ποτής / potḗs [[wikt:en:ποτής#Ancient_Greek|(en)]], « boisson » ;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ +‎ du suffixe -ῐον / -ĭon [[wikt:en:-ιον#Ancient_Greek|(en)]] ;<br /><p style="margin: 0 2em; text-indent: 15px;">Entretiens dans un banquet, propos de table. '''<br /><br /> </div>{{Boîte déroulante fin}} ===== <div style="text-align: center;">Livre III</div> ===== <div style="text-align: center; margin: 0 1em;"></div> ====== <div style="text-align: center;">Question VI. Sur le temps où il est à propos de se rapprocher d’une femme.</div> ====== <div style="text-align: center; margin: 0 1em;">Témoignage du statut marital de '''Thalès''' et de sa relation avec sa mère</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid;"><br /><div style="text-align: justify; margin: 0 2em; text-indent: 15px">Καθάπερ οὖν '''Θαλῆς''' ὁ σοφὸς ὑπὸ τῆς μητρὸς ἐνοχλούμενος γῆμαι κελευούσης πῶς ὑπεξέφυγε παρήγαγε λέγων πρὸς αὐτὴν ἐν ἀρχῇ μέν « οὔπω καιρὸς ὦ μῆτερ, » ὕστερον δ´ « οὐκέτι καιρὸς ὦ μῆτερ », οὕτως ἄρα καὶ πρὸς ἀφροδίσια κράτιστον {ἔσται} ἔχειν ἕκαστον, ὥστε κατακλινόμενον λέγειν «οὔπω καιρός», ἀνιστάμενον δ´ « οὐκέτι καιρός ».</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome III, [https://remacle.org/bloodwolf/historiens/Plutarque/sympos3.htm#VI Προβλημα Ϛ. Περὶ καιροῦ συνουσίας. - Question VI. Quel est le temps le plus propre à l'amour?]'', traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div></div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§3. Ainsi donc, comme le sage '''Thalès''', fatigué par sa mère qui l’engageait à se marier, trouva le moyen de lui échapper et de lui donner le change en lui disant une première fois : « Il n’est pas encore temps, ma mère », et, lorsqu’elle insistait encore après qu’il avait passé l’âge : « Il n’est plus temps » ; de même, pour ce qui regarde les plaisirs de l’amour, le mieux sera que chacun se détermine à dire, en se mettant au lit : « Il n’est pas temps encore », et, en sortant du lit : « il n’est plus temps ».</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome III, [[s:Page:Plutarque_-_Œuvres_complètes_de_Plutarque_-_Œuvres_morales_et_œuvres_diverses,_tome_3,_1870.djvu/268|Question VI. Sur le temps où il est à propos de se rapprocher d’une femme]], [[s:Page:Plutarque_-_Œuvres_complètes_de_Plutarque_-_Œuvres_morales_et_œuvres_diverses,_tome_3,_1870.djvu/271|§3]]'', traduites par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Le sage '''Thalès''', pressé par sa mère de se marier, lui répondit avec beaucoup d’adresse. Au commencement, il lui dit : Ma mère, il n’est pas encore temps. Quand il eut passé la fleur de son âge, et qu’elle lui fit de nouvelles instances, il lui répondit : Il n’est plus temps. De même, par rapport à la question proposée, le mieux serait que chacun pût se dire le soir en se couchant : Il n’est pas encore temps ; et le matin, quand il se lève : Il n’est plus temps. »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome III, [https://remacle.org/bloodwolf/historiens/Plutarque/sympos3.htm#VI Προβλημα Ϛ. Περὶ καιροῦ συνουσίας. - Question VI. Quel est le temps le plus propre à l’amour?]'', traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto; color: #3366BB">― ✳ ―</div> ==== De la malignité d’[[w:Hérodote|'''Hérodote''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Chapitre_XX|<sup>🔄</sup>]] ==== <div style="text-align: center; margin: 0 1em;">Ouvrage critique contre l’impartialité d’'''Hérodote''', ses contre-vérités face à la dévaluation des héros et peuples ''grecs''. Le ton critique surprend de la part de '''Plutarque''' au point que l’on contesta l’authenticité du traité, sans succès.</div> ===== Paragraphe XV ===== <div style="text-align: center; margin: 0 1em;">Remise en question de l’origine phénicienne de '''Thalès''' donnée par '''Hérodote'''.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid;"><br /><div style="text-align: justify; margin: 0 2em; text-indent: 15px">Καὶ μὴν τῶν ἑπτὰ σοφῶν, οὓς αὐτὸς σοφιστὰς προσεῖπε, τὸν μὲν '''Θάλητα''' Φοίνικα τῷ γένει τὸ ἀνέκαθεν ἀποφαίνεται βάρβαρον·</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome IV, [https://remacle.org/bloodwolf/historiens/Plutarque/malignhero.htm Περι της Ηροδοτου κακοηθειας]'' traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§15. Quand il parle des sept sages, il les appelle des ''sophistes''. Il prétend démontrer que '''Thalès''' est d’origine ''phénicienne''[[#phénicienne_NdT_DR|<span id="phénicienne_NdT_DR_back"><sup>1</sup></span>]], et qu’à remonter en arrière ce personnage appartient aux Barbares.</div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#phénicienne_NdT_DR_back|<span id="phénicienne_NdT_DR"><sup>1</sup></span>]] I, 170.''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome III, [[s:Page:Plutarque_-_Œuvres_complètes_de_Plutarque_-_Œuvres_morales_et_œuvres_diverses,_tome_3,_1870.djvu/773|De la malignité d’Hérodote]], [[s:Page:Plutarque_-_Œuvres_complètes_de_Plutarque_-_Œuvres_morales_et_œuvres_diverses,_tome_3,_1870.djvu/782|§15]]'', traduites par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Entre les sept sages qu’il appelle ''sophistes'', il enlève '''Thalès''' à la ''Grèce'' pour le donner aux Barbares, en le faisant descendre d’une famille ''phénicienne''.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome IV, [https://remacle.org/bloodwolf/historiens/Plutarque/malignhero.htm De la malignité d’Hérodote]'' traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto; color: #3366BB">― ✳ ―</div> ==== Les opinions des Philosophes ==== <div style="text-align: center; margin: 0 1em;">Ouvrage [[w:doxographe|'''doxographe''']], à la manière de [[w:Diogène Laërce|'''Diogène Laërce''']] [[#Diogène_Laërce_back|<sup>⤵️</sup>]] et [[w:Alcinoos_(philosophe)|'''Alcinoos''']] [[#Alcinoos|<span id="Alcinoos_back"><sup>'''I'''</sup></span>]], qui cite un nombre important de [[w:présocratiques|''présocratiques'']].</div> {{Boîte déroulante début|titre=NdA Les opinions des Philosophes|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Alcinoos_back|<span id="Alcinoos"><sup>I</sup></span>]] Du grec ancien Ἀλκίνοος / Alkínoos [[wikt:en:Ἀλκίνοος#Ancient_Greek|(en)]] ; <br /><p style="margin: 0 2em; text-indent: 15px;">➥ du nom commun ἀλκή / alkḗ [[wikt:en:ἀλκή#Ancient_Greek|(en)]], « 1. Prouesse; force. 2. Défense; garde. 3. Bataille; combat. » ;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ +‎ du nom commun νόος / nóos [[wikt:en:νόος#Ancient_Greek|(en)]], « 1. Esprit : • Perception, sens ; • L’esprit en tant que siège des sentiments, le cœur, l’âme ; • L’esprit en tant que faculté de décision et d’intention, la volonté. 2. Un acte de l’esprit : • Pensée ; • Intention, dessein. 3. Le sens ou la signification d’un mot. 4. (philosophie) Intelligence, intellect, raison. 5. (métaphysique) Le principe agissant sur les particules élémentaires de la matière (tel que décrit par [[w:Anaxagore|Anaxagore]] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Anaxagore_back|<sup>🔄</sup>]]) » ;<br /><p style="margin: 0 2em; text-indent: 15px;">Philosophe de l’époque [[w:Moyen-platonisme|''médio-platonicienne'']] [[#moyen-platonisme|<span id="moyen-platonisme_back"><sup>II</sup></span>]], auteur du Διδασκαλικὸς τῶν Πλάτωνος δογμάτων / Didaskalikòs tō̃n Plátōnos dogmátōn, « Enseignement des doctrines de Platon » [[#Didaskalikos|<span id="Didaskalikos_back"><sup>III</sup></span>]].<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:IIe_siècle|II<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]])<br /><br /><p style="margin: 0 2em; text-indent: 15px;">[[#moyen-platonisme_back|<span id="moyen-platonisme"><sup>II</sup></span>]] Le ''moyen-platonisme'' ou ''médio-platonisme'' est un courant philosophique regroupant des penseurs qui se réclament de Platon, depuis le [[w:Ier_siècle_av._J.-C.|I<sup>er</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]] jusqu'au [[w:IIe_siècle|II<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]].<br /><br /><p style="margin: 0 2em; text-indent: 15px;">[[#Didaskalikos_back|<span id="Didaskalikos"><sup>III</sup></span>]] Le ''Didaskalikos'' se rattache étroitement à la branche du ''moyen-platonisme'' qui interprétait Platon à la lumière surtout d’Aristote. On constate en plus une certaine influence du ''stoïcisme'', en particulier l’emprunt d’un extrait conséquent au ''stoïcien'' Arius Didyme [[#Arius_Didyme|<span id="Arius_Didyme_back"><sup>'''IV'''</sup></span>]]. Souvent pourtant les doctrines du ''stoïcisme'' sont combattues, avant tout, mais pas exclusivement, en ce qui concerne la morale : il est donc impossible que l’auteur du ''Didaskalikos'' fût ''stoïcien orthodoxe'', dont la persistance au [[w:IIe_siècle|II<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]] est sujet à débat. Pour autant, l’auteur veut maintenir une certaine réserve à l’égard des doctrines dont il fait l’exposé : d’où l’emploi de la troisième personne à propos des ''platoniciens''. Enfin, il ne se comptait pas non plus parmi les grands du ''moyen-platonisme''.<br /><p style="margin: 0 2em; text-indent: 15px;">Le Didaskalikos ne peut donc pas être antérieur à Arius Didyme, contemporain de l’empereur Auguste. Il est impossible d’établir un [[wikt:terminus_ad_quem|''terminus ante quem'']] précis. L’ouvrage présente en effet des coïncidences frappantes avec une gamme d’auteurs s’échelonnant de Philon d’Alexandrie jusqu’à Plotin. Depuis fin [[w:XIXe_siècle|XIX<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]], l’habitude a été prise de dater le ''Didaskalikos'' des environs de l’an [[w:150|150]] EC ; et même si cela semble raisonnable, il y a d’autres possibilités à prendre en considération, en l’absence de tout renseignement biographique.<br /><br /><p style="margin: 0 2em; text-indent: 15px;">[[#Arius_Didyme_back|<span id="Arius_Didyme"><sup>IV</sup></span>]] Du nom propre grec ancien Ἄρειος Δίδυμος / Areios Didymos ;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ du nom propre [[w:Nom_théophore|''théophore'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#théophore_back|<sup>🔄</sup>]] Ἄρειος / Áreios [[wikt:en:Ἄρειος#Ancient_Greek|(en)]], « Relatif à Ares »; <br /><p style="margin: 0 2em; text-indent: 30px;">➥ du nom propre Ἄρης / Árēs [[wikt:Ἄρης#Ancient_Greek|(en)]], « 1. (mythologie grecque) La divinité Arès. 2. (par transfert) La planète Mars. 3. (par antonomase) Rencontre ou situation hostile entre groupes de personnes : bataille, affrontement, combat, escarmouche, guerre. 4. (par antonomase) Événements ou conséquences liés aux hostilités : boucherie, carnage, embrasement, massacre, tuerie. 5. (par antonomase, avec synecdoque comme substantif désignant une qualité) Esprit guerrier ou esprit combatif. 6. Épithète de Zeus, « le vengeur » »;<br /><p style="margin: 0 2em; text-indent: 30px;">➥ +‎ du suffixe adjectival -ιος / -ios [[wikt:en:-ιος#Ancient_Greek|(en)]], « Relatif à, appartenant à : "de" » ;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ de l’adjectif δῐ́δῠμος / dĭ́dŭmos [[wikt:en:δίδυμος#Ancient_Greek|(en)]], « 1. Double. 2. Jumeaux. » ;<br /><p style="margin: 0 2em; text-indent: 30px;">➥ [[wikt:en:réduplication|''Réduplication'']] de δύο / dúo [[wikt:en:δύο#Ancient_Greek|(en)]], « deux » ; <br /><p style="margin: 0 2em; text-indent: 30px;">➥ + du suffixe -μος / -mos [[wikt:en:-μος#Ancient_Greek|(en)]] ; forme alternative du suffixe adjectival -ιμος / -imos [[wikt:en:-ιμος#Ancient_Greek|(en)]] de possibilité ou de capacité, « -able » ;<br /><p style="margin: 0 2em; text-indent: 15px;">Philosophe ''alexandrin'' et doxographe de tendance éclectique, il est ami et conseiller d’Auguste, au moins de [[w:-30|-30]] (date fondée sur des références à Auguste et à Arius dans le contexte de la prise d’Alexandrie, épargnée par Auguste - entre autres raisons – grâce à Arius) à [[w:9|9]]. Bien que nous ne connaissions pas de façon certaine l’école à laquelle il se rattachait, il était probablement ''stoïcien'' : il manifeste des affinités avec la ''philosophie académicienne'' telle qu’elle est présentée par Antiochus d’''Ascalon'', de la sympathie pour l’''académicien'' Eudore, une grande précision dans le traitement du matériel ''stoïcien'' et une ouverture à la pensée ''péripatéticienne''.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:Ier_siècle_av._J.-C.|I<sup>er</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]]) [https://books.google.fr/books?id=crnWAAAAMAAJ&newbks=1&newbks_redir=0&lpg=PA3&dq=Richard%20Goulet%20dictionnaire%20des%20auteurs%20antiques&hl=fr&pg=PA345#v=onepage&q&f=false {{Info|<sup>🔍</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume I, §324 - Areios Didymos}}]'''<br/><br/></div> {{Boîte déroulante fin}} ===== <div style="text-align: center;">Livre I</div> ===== <div style="text-align: center; margin: 0 1em;"></div> <div style="text-align: center; margin: 0 auto;">― ● ―</div> ===== <div style="text-align: center;">Livre II</div> ===== <div style="text-align: center; margin: 0 1em;"></div> <div style="text-align: center; margin: 0 auto;">― ● ―</div> ===== <div style="text-align: center;">Livre III</div> ===== <div style="text-align: center; margin: 0 1em;"></div> <div style="text-align: center; margin: 0 auto;">― ● ―</div> ===== <div style="text-align: center;">Livre IV</div> ===== <div style="text-align: center; margin: 0 1em;"></div> <div style="text-align: center; margin: 0 auto; color: #3366BB">― ✳ ―</div> ==== Les animaux de terre ont-ils plus d'adresse que ceux de mer? ==== <div style="text-align: center; margin: 0 1em;"></div> <div style="text-align: center; margin: 0 auto; color: #3366BB">― ✳ ―</div> ==== D’'''Isis''' et d’'''Osiris'''==== <div style="text-align: center; margin: 0 1em;">[[w:Diatribe|Diatribe]] ''[[w:Isis|Isiaque]]'', avec une interprétation ''platonique'' pour intéresser '''Cléa''', admiratrice du mystère d’'''Isis''' à la [[w:Religion_%C3%A9gyptienne|religion ''égyptienne'']]. C’est un plaidoyer, exégèse, avec '''[[w:Osiris|Osiris]]''' qui évoque '''[[w:Dionysos|Dionysos]]''' et '''[[w:Hadès|Hadès]]''', ainsi que des notions de ''[[w:démonologie|démonologie]]'', ''[[w:Dualisme (philosophie)|dualisme]]'' et ''[[w:didactique|didactique]]''. Il contient le premier récit suivi et cohérent du [[w:Mythe_d'Osiris|mythe d’'''Osiris''']]. L’une de ses sources est probablement '''[[w:Hérodote|Hérodote]]'''. mais on croit qu’il s’est rendu lui-même à ''Alexandrie'' pour suivre des cours de médecine.</div> ===== <div style="text-align: center;">Paragraphe IX.</div> ===== <div style="text-align: center; margin: 0 1em;">Témoignage d’un voyage de '''Thalès''' en ''Égypte'', de rencontres avec des prêtres et de récit sur leur divinités.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid;"><br /><div style="text-align: justify; margin: 0 2em; text-indent: 15px">§9. [...] '''Ἑκαταῖος''' δ´ ὁ ''Ἀβδηρίτης'' φησὶ τούτῳ καὶ πρὸς ἀλλήλους τῷ ῥήματι χρῆσθαι τοὺς ''Αἰγυπτίους'', ὅταν τινὰ προσκαλῶνται· προσκλητικὴν γὰρ εἶναι τὴν φωνήν. Διὸ τὸν πρῶτον θεόν, ὃν τῷ παντὶ τὸν αὐτὸν νομίζουσιν, ὡς ἀφανῆ καὶ κεκρυμμένον ὄντα προσκαλούμενοι καὶ παρακαλοῦντες ἐμφανῆ γενέσθαι καὶ δῆλον αὐτοῖς ''Ἀμοῦν'' λέγουσιν.<br /><p style="text-indent: 15px">§10. Ἡ μὲν οὖν εὐλάβεια τῆς περὶ τὰ θεῖα σοφίας '''Αἰγυπτίων''' τοσαύτη {ἦν}, μαρτυροῦσι δὲ καὶ τῶν ''Ἑλλήνων'' οἱ σοφώτατοι, '''Σόλων''' '''Θαλῆς''' '''Πλάτων''' '''Εὔδοξος''' '''Πυθαγόρας''', ὡς δ´ ἔνιοί φασι, καὶ '''Λυκοῦργος''' εἰς ''Αἴγυπτον'' ἀφικόμενοι καὶ συγγενόμενοι τοῖς ἱερεῦσιν.[...]</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome V, [https://remacle.org/bloodwolf/historiens/Plutarque/isisetosiris.htm Περι Ισιδος και Οσιριδος - Traité d’Isis et d’Osiris], §34'', traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1870<br />(également disponible une édition de 1844 [https://remacle.org/bloodwolf/historiens/Plutarque/isisetosiris1.htm ici])</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§9. [...] '''Hécatée''' d’''Abdère'' dit que les ''Égyptiens'' emploient ce mot pour s’appeler les uns les autres, attendu qu’il est essentiellement appellatif. C’est pourquoi, s’adressant au premier Dieu, le même, selon eux, que l’Univers, comme à un être invisible et caché, ils l’exhortent avec supplications, en l’appelant "Amoun", à se faire voir et à se découvrir à eux. Voilà jusqu’à quel point était grande la réserve qui caractérisait la philosophie religieuse des ''Égyptiens''.<br /><p style="text-indent: 15px">§10. C’est ce que témoignent les plus éclairés d’entre les ''Grecs'': '''Solon''', '''Thalès''', '''Platon''', '''Eudoxe''', '''Pythagore''', et aussi, d’après quelques-uns, '''Lycurgue'''. Ils étaient allés en ''Égypte'' et avaient eu des conférences avec les prêtres. [...]</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome V, [https://remacle.org/bloodwolf/historiens/Plutarque/isisetosiris.htm Περι Ισιδος και Οσιριδος - Traité d’Isis et d’Osiris], §§9, 10'', traduites par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870<br/>(également disponible [[s:Sur_Isis_et_Osiris|ici]])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">§9. [...] '''Hécatée''' d’''Abdère'' dit que les ''Egyptiens'' s’en servent pour s’appeler les uns les autres; que ce nom est de sa nature appellatif ; que ce peuple , qui croit que le premier des dieux, qu’il confond avec l’univers, est un dieu caché et inconnu, l’invoque et le prie de se découvrir à eux, en lui disant ''Amoun'' ;<br /><p style="text-indent: 15px">§10. tant ce peuple portait de retenue et de réserve dans sa philosophie religieuse ! C’est ce qu'attestent unanimement les plus sages d’entre les ''Grecs'', '''Solon''', '''Thalès''', '''Platon''', '''Eudoxe''', '''Pythagore''', et, suivant quelques uns, '''Lycurgue''' lui-même, qui tous voyagèrent en ''Egypte'', et y conférèrent avec les prêtres du pays.[...]</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome V, [https://remacle.org/bloodwolf/historiens/Plutarque/isisetosiris1.htm Περι Ισιδος και Οσιριδος - Traité d’Isis et d’Osiris], §§9, 10'', traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe XXXIV.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage de la théorie de '''Thalès''' de l’eau principe de tous les êtres.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§34. Ἥλιον δὲ καὶ Σελήνην οὐχ ἅρμασιν ἀλλὰ πλοίοις ὀχήμασι χρωμένους περιπολεῖν φασιν αἰνιττόμενοι τὴν ἀφ´ ὑγροῦ τροφὴν αὐτῶν καὶ γένεσιν. Οἴονται δὲ καὶ '''Ὅμηρον''' ὥσπερ '''Θαλῆν''' μαθόντα παρ´ ''Αἰγυπτίων'' ὕδωρ ἀρχὴν ἁπάντων καὶ γένεσιν τίθεσθαι· τὸν γὰρ '''Ὠκεανὸν''' '''Ὄσιριν''' εἶναι, τὴν δὲ '''Τηθὺν''' '''Ἶσιν''' ὡς τιθηνουμένην πάντα καὶ συνεκτρέφουσαν. [...]</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome V, [https://remacle.org/bloodwolf/historiens/Plutarque/isisetosiris.htm Περι Ισιδος και Οσιριδος - Traité d’Isis et d’Osiris], §34'', traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1870<br />(également disponible une édition de 1844 [https://remacle.org/bloodwolf/historiens/Plutarque/isisetosiris1.htm ici])</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§34. Ils disent que le soleil et la lune parcourent leur route perpétuelle non pas sur des chars, mais sur des bâtiments de navigation: signifiant par là, que c’est le principe humide qui les entretient et qui leur a donné naissance. Ils croient aussi que c’est des ''Egyptiens'' qu’'''Homère''', et après lui '''Thalès''', ont appris à établir l’eau comme principe générateur de tous les êtres. Ils veulent qu’'''Osiris''' soit l’'''Océan''', qu’'''Isis''' soit '''Téthys''', laquelle nourrit et entretient tout ce qui existe.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome V, [https://remacle.org/bloodwolf/historiens/Plutarque/isisetosiris1.htm Περι Ισιδος και Οσιριδος - Traité d’Isis et d’Osiris], §34'', traduites par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870<br/>(également disponible [[s:Sur_Isis_et_Osiris|ici]])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">§34. Ils disent que le soleil et la lune parcourent les cieux, portés, non sur des chars, mais sur des vaisseaux, pour signifier que tout est nourri et mis en mouvement par l’eau. Ils pensent que c’est des ''Egyptiens'' qu’'''Homère''' et '''Thalès''' avaient pris cette opinion, que l’eau est le principe de tous les êtres, qu’'''Osiris''' est l’'''Océan''', et qu’'''Isis''' est '''Thétis''', qui nourrit et alimente toutes les substances.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome V, [https://remacle.org/bloodwolf/historiens/Plutarque/isisetosiris1.htm Περι Ισιδος και Οσιριδος - Traité d’Isis et d’Osiris], §34'', traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Valère_Maxime|'''Valère Maxime''']] ''([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l'on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:Ier_siècle|I<sup>er</sup> siècle {{Info|EC|de l’Ère Commune}}]])'' [[s:Auteur:Valère_Maxime|<sup>📚</sup>]] == === Actions et paroles mémorables, VII, § 2 === :8. Il y a aussi un mot admirable de Thalès. On lui demandait si les actions des hommes échappaient à la connaissance des dieux. "Leurs pensées non plus", répondit-il. Aussi faut-il nous appliquer à avoir, je ne dis pas seulement les mains, mais encore le cœur pur, dans la persuasion que la divinité est témoin des mouvements les plus secrets de nos âmes. <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Tatien_le_Syrien|'''Tatien''']] le [[w:Assyrie_(province_romaine)|''Syrien'']] ''(vers [[w:120|120]], en [[w:Halicarnasse|''Halicarnasse'']] en [[w:Assyrie_(province_romaine)|Assyrie]] — vers [[w:173|173]], en Assyrie)'' <sup>[[w:IIe_siècle|⏳]]</sup> [[s:Auteur:Tatien_le_Syrien|<sup>📚</sup>]] == === Discours aux Grecs, 41 === == [[w:Lucien_de_Samosate|'''Lucien de Samosate''']] ''(vers [[w:120|120]], à [[w:Samosate|Samosate]] — vers [[w:180|180]], en [[w:Égypte_romaine_et_byzantine|Égypte]])'' <sup>[[w:IIe_siècle|⏳]]</sup> [[s:Auteur:Lucien_de_Samosate|<sup>📚</sup>]] == === Dialogues des morts === https://gallica.bnf.fr/ark:/12148/bpt6k6227866x/f7.item https://gallica.bnf.fr/ark:/12148/bpt6k6227866x/f103.double === Hippias ou le bain === :(2) Mon but est de prouver que les constructeurs de machines qui méritent le plus notre admiration sont ceux qui, distingués par leur science théorique, ont laissé en outre à la postérité des monuments de leur art et des œuvres de leur génie, tandis que les hommes, qui se sont seulement exercés dans la parole méritent plutôt le nom de sophistes que celui de savants. C'est sur la liste traditionnelle de ces artistes que nous voyons figurer Archimède et Socrate de Cnide, qui inventèrent, l'un les moyens de soumettre à Ptolémée la ville de Memphis, sans recourir à un siège, mais en détournant et en divisant le cours du Nil ; l'autre, ceux d'incendier les galères des ennemis. Avant eux, Thalès de Milet, ayant promis à Crésus de faire passer à pied sec à son armée les eaux du fleuve Halys, imagina de les détourner en une seule nuit derrière le camp ; et pourtant ce n'était pas un mécanicien de profession, mais un sage d'un esprit inventif et à l'intelligence duquel on pouvait s'en rapporter. === Exemples de longévité === :(18) Solon, Thalès et Pittacus, que l'on compte au nombre des Sept sages, vécurent chacun cent années. <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Athénée_de_Naucratis|'''Athénée''' de ''Naucratis'']] == [[w:https://remacle.org/bloodwolf/erudits/athenee/livre11.htm|''Le Livre XI des Deipnosophistes'']] [781d] « Alcmène reçoit le vase d'or, et le contemple aussitôt avec admiration. » Stésichore dit qu'Hercule traverse l'Océan dans son vase à boire (poteerioo) ; qu'il s'en servit même pour le franchir et aller enlever les bœufs de Géryon. Nous connaissons aussi par l'histoire le vase à boire (poteerion) de l'arcadien Bathyclès, qui le laissa pour présent à celui qui fut appelé le sage par excellence entre les Sept de la Grèce; mais nombre de potiers de terre font le vase de Nestor, car plusieurs écrivains en ont donné des détails. <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Clément_d%27Alexandrie|'''Clément''']] d'[[w:Histoire_d%27Alexandrie#Annexion|''Alexandrie'']] ''(vers [[w:150|150]]'' <sup>[[w:IIe_siècle|⏳]]</sup>'', à [[w:Athènes#Antiquité|Athènes]] — vers [[w:215|215]]'' <sup>[[w:IIIe_siècle|⏳]]</sup>'', à [[w:Kayseri|Kayseri]])'' [[s:Auteur:Clément_d’Alexandrie|<sup>📚</sup>]] == === Stromates, I, 65 === <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Claude_Élien|'''Claude Élien''']] ''(vers [[w:175|175]]''<sup>[[w:IIe_siècle|⏳]]</sup>'', à [[w:Préneste|Préneste]] — vers [[w:235|235]]''<sup>[[w:IIIe_siècle|⏳]]</sup>'', en [[w:Rome_antique|Rome]])'' [[s:Auteur:Élien_le_sophiste|<sup>📚</sup>]] == === Histoires diverses === :On a vu des philosophes à la tête des affaires publiques : d'autres, se bornant à cultiver leur raison, ont passé leur vie dans le repos. Entre les premiers sont Zaleucus et Charondas qui réformèrent, l'un, le gouvernement des Locriens, l'autre, d'abord celui des Catanéens, puis, après qu'il eut été exilé de Catane, celui des Rhéginiens. Archytas servit utilement les Tarentins. Les Athéniens durent tout à Solon. Bias et Thalès rendirent les mêmes services à l'Ionie, Chilon à Lacédémone, Pittacus à Mitylène, Cléobule à Rhodes. <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Sextus_Empiricus|'''Sextus Empiricus''']] ''([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l'on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:IIe_siècle|II<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]])'' [[s:Auteur:Sextus_Empiricus|<sup>📚</sup>]] == Hypot III, 30, et Liv I contre les phys., sect. 319 https://gallica.bnf.fr/ark:/12148/bpt6k9796311p/f305.item.r=thales <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Lactance|'''Lactance''']] ''(vers [[w:250|250]]''<sup>[[w:IIIe_siècle|⏳]]</sup>'', à [[w:Henchir_Kssiba#Histoire|Civitas Popthensis]] — vers [[w:325|325]]''<sup>[[w:IVe_siècle|⏳]]</sup>'', en [[w:Gaule#La_Gaule_dans_l'Antiquité_tardive|Gaule]])'' == Épit. 4 (https://gallica.bnf.fr/ark:/12148/bpt6k282068z/f300.image.r=thales) Inst. 111, 16 (https://gallica.bnf.fr/ark:/12148/bpt6k282068z/f621.item.r=thales) <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Jamblique|'''Jamblique''']] ''(vers [[w:250|250]]''<sup>[[w:IIIe_siècle|⏳]]</sup>'', à [[w:Qinnasrīn|Chalcis ad Belum]] — vers [[w:333|333]]''<sup>[[w:IVe_siècle|⏳]]</sup>'')'' == === Vie de Pythagore === ==== chap. II ==== (https://web.archive.org/web/20110721184914/http://www.aurumsolis.info/index.php?option=com_phocadownload&view=category&download=1%3Aiamblichus-the-pythagorean-life&id=19%3Awritings-from-the-founders&Itemid=143&lang=en) <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Eusèbe_de_Césarée|'''Eusèbe''']] de [[w:Césarée#Césarée_au_début_du_christianisme|''Césarée'']] ''(vers [[w:265|265]]'' <sup>[[w:IIIe_siècle|⏳]]</sup>'', à Césarée — [[w:340|340]]'' <sup>[[w:IVe_siècle|⏳]]</sup>'', à Césarée)'' [[s:Auteur:Eusèbe_de_Césarée|<sup>📚</sup>]] == Preparation Évangélique, XI, 2 Prepar. évang. I, 8, page 22-25 https://gallica.bnf.fr/ark:/12148/bpt6k9796311p/f310.image.r=thales <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Diogène_Laërce|'''Diogène Laërce''']] ''([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l'on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:IIIe_siècle|III<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]])'' [[s:Auteur:Diogène_Laërce|<sup>📚</sup>]] == ''Ce texte est un extrait de la traduction de Robert Genaille (1933)'' Thalès[1], au dire d’Hérodote, de Douris et de Démocrite, était fils d’Examios et de Cléobuline, et membre de la famille des Thélides, Phéniciens descendant en droite ligne d’Agénor[2] et de Cadmus[3], s’il faut en croire Platon. Le premier, il porta le nom de sage, au temps où Damasias était archonte à Athènes[4]. C’est sous le même archontat que fut créée l’expression : « les sept sages » (cf. Démocrite de Phalère, Registre des Archontes). Thalès fut inscrit comme citoyen de Milet quand il vint dans cette ville avec Nélée chassé de Phénicie. Une autre tradition très courante veut qu’il soit natif de Milet et qu’il descende d’une bonne famille. Il s’occupa de politique avant d’étudier la nature. On croit qu’il ne laissa aucun écrit, car l’Astrologie nautique qu’on lui attribue est de Phocos de Samos. Callimaque[5] croit qu’il découvrit la Petite Ourse et le raconte en vers iambiques : Il mesura, dit-on, les étoiles du Chariot Sur quoi les Phéniciens règlent leur navigation. D’autres auteurs disent qu’il écrivit seulement deux ouvrages, un sur le solstice et un sur l’équinoxe, car il pensait le reste inaccessible. Il passe pour avoir le premier étudié l’astrologie et prédit les éclipses de soleil et les solstices (cf. Eudème, Histoire de l’astrologie)[6]. Xénophane et Hérodote le louent à ce propos, et leur témoignage est confirmé par celui d’Héraclite et de Démocrite. On dit encore (cf. le poète Choirilos) qu’il fut le premier à affirmer l’immortalité des âmes. Le premier il dessina la course du soleil d’un solstice à l’autre, et démontra que comparée au soleil, la lune en est la cent vingtième partie. C’est encore lui qui fixa à trente jours la durée du mois, et qui écrivit le premier traité sur la Nature. Aristote et Hippias disent aussi qu’il accordait une âme aux choses qu’on croit inanimées ; il en donnait pour preuve l’ambre et la pierre de Magnésie. Selon Pamphile[7], il apprit des Égyptiens la géométrie, inscrivit dans un cercle le triangle rectangle, et pour cette découverte immola un bœuf. D’autres, comme Apollodore le calculateur, attribuent cette invention à Pythagore. Thalès a encore développé et précisé l’invention du Phrygien Euphorbe citée par Callimaque dans ses Iambes et concernant le triangle scalène, et tout ce qui touche aux considérations sur les lignes. Il semble encore avoir été en politique un homme de bon conseil. Ainsi, quand Crésus[8] envoya une ambassade aux Milésiens pour demander leur alliance, il s’y opposa, et son intervention sauva la ville, puisque Cyrus l’emporta. Héraclite cite une opinion de Clytos selon laquelle Thalès aurait eu une vie retirée et solitaire. Les uns disent qu’il se maria et eut un fils nommé Kibissos. D’autres prétendent qu’il resta célibataire et adopta le fils de sa sœur, qu’on lui demanda un jour pourquoi il ne cherchait pas à avoir des enfants, et qu’il répondit : « Par amour pour les enfants. » Sa mère l’exhortait à se marier, il lui répondit : « Non, par Zeus, il n’est pas encore temps. » Elle l’y invita une nouvelle fois quand il eut pris de l’âge, mais il lui dit : « Il n’est plus temps. » D’après Hiéronyme de Rhodes (Notes, livre II), il voulut montrer combien il était facile de s’enrichir ayant prévu pour l’année une abondante récolte d’huile, il prit à loyer une oliveraie et gagna beaucoup d’argent[9]. Il soupçonna que l’eau était le principe des choses, que le monde était animé et rempli de démons. On dit qu’il découvrit les saisons de l’année, et qu’il la divisa en trois cent soixante-cinq jours. Il ne suivit les leçons d’aucun maître, sauf en Égypte, où il fréquenta les prêtres du pays. A ce propos, Hiéronyme dit qu’il mesura les Pyramides en calculant le rapport entre leur ombre et celle de notre corps. Si l’on en croit Minuès, il vivait au temps de Thrasybule, qui fut tyran de Milet[10]. L’histoire du trépied trouvé par des pêcheurs et dédié aux sages par le peuple de Milet est bien connue. Des jeunes gens d’Ionie achetèrent à des pêcheurs milésiens leur coup de filet. Ils tirèrent de l’eau un trépied. On se querella et les Milésiens envoyèrent une ambassade à Delphes. Voici quel fut l’oracle de la divinité : Race de Milet, tu interroges Phébus au sujet d’un trépied ? Au plus sage de tous, je donne ce trépied[11]. Ils le donnent alors à Thalès, qui le donne à un autre, et cet autre à un autre, et ainsi de suite jusqu’à Solon, qui, déclarant que seul le dieu était le plus sage de tous, rendit le trépied à Delphes. Callimaque, dans ses Iambes, rapporte cette histoire autrement ; il la tient de Léandre de Milet. Il dit qu’un certain Bathyclès d’Arcadie laissa en mourant une coupe pour qu’elle fût donnée à l’homme le plus sage. Elle fut donc donnée à Thalès, et après être passée de main en main et avoir fait le tour des sages, elle revint à Thalès. Celui-ci en fit don alors à Apollon de Didyme, en ces termes selon le poème de Callimaque : Thalès me donne au protecteur du peuple du Nil, Thalès qui a reçu deux fois ce présent, ce qui, en prose, se dit ainsi : « Thalès de Milet, fils d’Examios, à Apollon delphien, ce présent qu’il a reçu deux fois des Grecs. » Celui qui portait la coupe de sage en sage, le fils de Bathyclès, s’appelait Thyrion (cf. Éleusis, Livre sur Achille, et Alexon de Mynde, Fables, livre IX). Eudoxe de Cnide et Évanthès de Milet disent de leur côté qu’un ami de Crésus reçut du roi un vase d’or, pour le donner au plus sage des Grecs, qu’il le donna à Thalès et que ce vase parvint jusqu’à Chilon. Celui-ci consulta la Pythie, pour savoir qui était plus sage que lui. Elle répondit que c’était Myson (je parlerai de lui : Eudoxe le met parmi les sages à la place de Cléobule et Platon à la place de Périandre.) Voici la réponse que lui fit la Pythie : Il y a un habitant de l’Oeta, Myson, né à Chénée, Qui plus que toi est riche de sages pensées. L’homme qui consulta l’oracle pour Chilon s’appelait Anacharsis. Dédale le Platonicien et Cléarque disent que la coupe fut envoyée par Crésus à Pittacos, et que c’est ainsi qu’elle passa de main en main. D’après Andron, d’autre part (Livre du trépied), les Argiens décidèrent que le trépied serait attribué comme prix de vertu au plus sage des Grecs. Aristodème de Sparte fut choisi et c’est lui qui donna le trépied à Chilon. Alcée est aussi partisan d’Aristodème dont il parle dans les vers suivants : :Comme jadis Aristodème, dit-on, :Prononça à Sparte cette parole bien juste : :C’est de l’argent, un homme, oui de l’argent, :Car l’homme vertueux n’est jamais pauvre. D’autres disent encore que Périandre envoya à Thrasybule, tyran de Milet, un navire chargé, que ce navire fit naufrage dans la mer de Cos, et que quelque temps après le trépied fut trouvé par des pêcheurs. Phanodicos dit que le trépied fut trouvé dans la mer Attique, porté à la ville, et que l’assemblée du peuple s’étant réunie le fit porter à Bias. Pourquoi cela, je le dirai quand je parlerai de Bias. Selon d’autres auteurs, le trépied avait été fabriqué par Héphaïstos et donné en présent de la part de ce dieu à Pélops lors de son mariage. Il vint ensuite à Ménélas, fut enlevé avec Hélène par Alexandre, jeté dans la mer de Cos à l’instigation de la Spartiate qui prévoyait qu’il serait un sujet de querelle. Plus tard, en ce lieu, des Lébédiens achetèrent le produit d’un coup de filet et c’est le trépied qui fut tiré de l’eau. Il y eut querelle avec les pêcheurs, on vint jusqu’à Cos, et comme on ne s’accordait pas, on s’adressa à Milet, qui était la capitale. Les Milésiens envoyèrent des députés qui ne furent pas écoutés, aussi firent-ils la guerre aux gens de Cos. Comme de chaque côté il mourait beaucoup de gens, l’oracle déclara qu’il fallait donner le trépied au plus sage. Les deux camps s’entendirent alors pour l’attribuer à Thalès, qui par la suite le consacra à Apollon de Didyme. Pour en revenir à la réponse de l’oracle aux gens de Cos, elle disait ceci : La querelle entre Ioniens et Méropes ne cessera pas Avant que le trépied d’or qu’Héphaïstos jeta dans la mer N’ait quitté votre ville pour la maison de l’homme Qui connaît le présent, l’avenir et le passé. La réponse aux Milésiens fut la suivante : Race de Milet, tu interroges Phoebus au sujet d’un trépied... comme il a été dit plus haut. En voilà assez sur ce sujet[12]. Hermippe, dans ses Vies, rapporte à Thalès ce qui est dit par d’autres de Socrate : il aimait à dire qu’il remerciait la fortune de trois choses : d’être un humain et non une bête, d’être un homme et non une femme, enfin d’être un Grec, et non un barbare. On raconte encore qu’étant sorti de chez lui pour contempler les astres, il tomba dans un puits[13]. Une vieille femme survenant se moqua de lui en ces mots : « Comment, Thalès, toi qui n’es pas capable de voir ce qui est à tes pieds, t’imagines-tu pouvoir connaître ce qui est dans le ciel ? » Timon[14] a bien connu aussi la science de Thalès en astronomie, et dans ses Silles, il le loue en ces termes : Comme Thalès, un des sept sages, qui fut savant astronome. L’Argien Lobon dit que ses écrits font un total de quelque deux cents vers, et que sous sa statue on écrivit : Thalès de Milet repose ici dans le sol qui l’a nourri, Il fut un sage, et le premier des astrologues. Voici un de ses poèmes : Le trop parler n’est pas marque d’esprit. Trouvez une seule chose sage, Choisissez une seule chose belle, Et vous clouerez le bec à bien des bavards. On lui attribue encore les sentences suivantes : de tous les êtres, le plus ancien, c’est Dieu, car il n’a pas été engendré ; le plus beau, c’est le monde, car il est l’ouvrage du dieu ; le plus grand, c’est l’espace, car il contient tout ; le plus rapide, c’est l’esprit, car il court partout ; le plus fort, c’est la nécessité, car elle vient à bout de tout ; le plus sage, c’est le temps, parce qu’il découvre tout. La mort, dit-il, ne diffère en rien de la vie. On lui répond : « Pourquoi, alors, ne te donnes-tu pas la mort ? » ; « Parce que vie ou mort, c’est tout un », réplique-t-il. Quelqu’un lui demande ce qui du jour ou de la nuit fut créé d’abord ; il répond : « La nuit est en avance d’un jour. » On lui demande si les mauvaises actions d’un homme échappent au regard des dieux. Il répond : « Ils voient même les mauvaises pensées. » Un homme adultère lui demandait s’il pouvait jurer qu’il n’avait pas commis d’adultère. Il répondit : « Le parjure n’est pas pire que l’adultère. » On lui demandait ce qui était difficile : « Se connaître » dit-il ; ce qui était facile : donner un conseil à autrui ; ce qui était le plus doux : jouir ; ce que c’était que la divinité : un être sans commencement ni fin ; encore une chose difficile : voir un tyran âgé ; comment supporter aisément l’infortune : en voyant ses ennemis plus malheureux encore ; comment vivre vertueusement : en ne faisant pas ce que nous reprochons à autrui ; qui est heureux : l’homme bien portant, riche, courageux et instruit. Il disait encore que l’on doit penser à ses amis aussi bien en leur absence qu’en leur présence, que la beauté ne vient pas d’un beau visage, mais de belles actions. « Ne t’enrichis pas injustement, conseillait-il, et veille à ne pas être cité en justice pour de mauvaises paroles contre tes proches et tes amis. Comme tu traites tes parents, tes enfants te traiteront. » Du Nil[15] il disait qu’il débordait quand ses eaux étaient repoussées par les vents étésiens qui soufflent contre son cours. Apollodore dans ses Chroniques dit que Thalès naquit la première année de la trente-cinquième olympiade[16]. Il mourut dans sa soixante-dix-huitième année ou, comme le dit Sosicrate, dans sa quatre-vingt-dixième année, car ce fut dans la cinquante-huitième olympiade. Il vécut du temps de Crésus, auquel il promit de faire traverser l’Hallys[17] sans pont, en détournant le cours du fleuve. Il y eut cinq autres personnages du nom de Thalès (cf. Démétrios de Magnésie, Homonymes) : un rhéteur de Callatie, au style prétentieux, un peintre de Sicyone, de noble origine, un troisième, très ancien, du temps d’Hésiode, d’Homère et de Lycurgue, un quatrième, mentionné par Douris dans son traité de la peinture, un cinquième, plus jeune et peu connu, cité par Denys dans ses Critiques. Pour en revenir à notre sage, il mourut en regardant les jeux gymniques, pour avoir eu trop chaud et trop soif et par suite de sa fatigue et de son grand âge. Voici son épitaphe : :Ce tombeau, certes, est bien petit, :Mais la renommée de l’homme est allée au ciel. :C’est celui de Thalès le très sage. J’ai écrit sur lui les vers suivants dans le premier livre de mes épigrammes ou « vers de mètres divers[18] : :Tandis qu’il regardait les jeux, ô Zeus Hélios, :Tu as ravi du stade le sage Thalès. :Je te loue de l’avoir rapproché du ciel. Il était si vieux :Que de la terre il ne pouvait plus voir les astres. Thalès est l’auteur du fameux « connais-toi toi-même » qu’Antisthène (Livre des Filiations) attribue à Phémonoé, en déclarant que Chilon se l’appropria mensongèrement. Sur les sept sages, qu’il est juste de citer maintenant l’un après l’autre, voici la tradition. Damon de Cyrène, qui blâme tous les philosophes dans ses écrits, s’attaque surtout aux sept sages. Anaximène dit que tous étaient poètes. Dicéarque dit qu’ils n’étaient ni sages ni philosophes, mais hommes d’esprit et législateurs. Archétimos de Syracuse a décrit leurs assemblées chez Cypsélos[19] et dit qu’il y assista personnellement. Euphoros dit que tous, sauf Thalès, fréquentèrent Crésus. D’autres disent qu’ils se réunirent à Panionium, à Corinthe et à Delphes. On rapporte même leurs paroles, et qui a prononcé telle ou telle. Exemple : Le Spartiate Chilon fut sage, Lui qui dit : Rien de trop, Tout est bien qui vient en son temps ! On n’est pas d’accord sur leur nombre. Léandre, au lieu de Cléobule et de Myson, met Léophante, fils de Gorsias, ou Lébédios d’Éphèse et Épiménide de Crète. Platon, dans le Protagoras[20], met Myson à la place de Périandre. Éphoros met Anacharsis à la place de Myson et d’autres ajoutent Pythagore. Selon Dicéarque, il y en a quatre sur qui tout le monde est d’accord : Thalès, Bias, Pittacos et Solon. Le même auteur en nomme six autres, parmi lesquels il en choisit trois : Aristodème, Pamphile, le Lacédémonien Chilon, Cléobule, Anacharsis et Périandre. D’autres ajoutent Acousilaos, Caba ou Scala, un Argien. Hermippe, dans son livre sur les sages, dit qu’ils furent dix-sept et que chacun en choisit sept selon ses préférences. Ce sont Solon, Thalès, Pittacos, Bias, Chilon, Cléobule, Périandre, Anacharsis, Acousilaos, Épiménide, Léophante, Phérécyde, Aristodème, Pythagore, Lasos, fils de Charmantidas ou de Sisambrinos ou, selon Aristoxène, de Chabrinus, Hermonée, Anaxagore. Hippobotos (Catalogue des Philosophes) les inscrit ainsi : Orphée, Linos, Solon, Périandre, Anacharsis, Cléobule, Myson, Thalès, Bias, Pittacos, Épicharme et Pythagore. Voici des lettres attribuées à Thalès[21] : ==== Thalès à Phérécyde ==== « J’apprends que vous vous disposez à présenter aux Grecs le premier traité ionien des choses divines. Vous agiriez peut-être plus sagement en lisant votre ouvrage à vos amis, qu’en communiquant à n’importe quelles gens des écrits qui ne peuvent guère leur être utiles. « Si cela vous plaît, j’aimerais profiter de vos recherches et, si vous m’y invitez, je viendrai vous trouver au plus tôt. Car Solon d’Athènes et moi, qui avons déjà traversé deux fois la mer pour aller visiter la Crète, et pour aller en Égypte nous entretenir avec les prêtres et les astronomes du lieu, nous sommes assez sages pour ne pas hésiter à la traverser de nouveau pour aller vous voir. « Je parle de Solon, parce qu’il viendra avec moi si vous le permettez. Vous êtes un sédentaire, vous allez rarement en Ionie, vous n’aimez guère aller voir les étrangers, et vous ne songez, j’imagine, qu’à écrire. « Mais nous qui n’écrivons pas, nous parcourons volontiers la Grèce et l’Italie. » ==== Thalès à Solon ==== « Si vous quittez Athènes, vous aurez, je crois, tout avantage à venir vous établir à Milet, parmi les colons athéniens. Il n’y a là pour vous aucun danger. Si vous hésitez, sous prétexte que nous, Milésiens, sommes gouvernés par un tyran (je sais que vous haïssez tout pouvoir absolu), songez du moins que vous aurez plaisir à vivre avec nous qui sommes vos amis. Je sais que Bias vous a écrit et vous invite à aller à Priène. Si vous trouvez préférable d’habiter la ville de Priène, j’irai vivre là-bas avec vous. » <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Ausone|'''Ausone''']] ''([[w:309|309]]/[[w:310|310]], à [[w:Bazas|Bazas]] ou à [[w:Bordeaux#Burdigala,_cité_romaine_(Ier_siècle_-_Ve_siècle)|Bordeaux]] — [[w:394|394]]/[[w:395|395]], entre [[w:Langon_(Gironde)|Langon]] et [[w:La_Réole|La Réole]])'' <sup>[[w:IVe_siècle|⏳]]</sup> [[s:Auteur:Ausone|<sup>📚</sup>]] == === Le Jeu des Sept Sages === :Thalès a trouvé [texte grec] pour nous défendre de nous porter cautions, parce qu'il y a du danger à répondre ainsi pour d'autres[iv]. Nous donnons-là un avis qui ne plaira pas beaucoup aux emprunteurs. :THALÈS : Je suis Thalès de Milet ; j'ai dit, comme le poète Pindare, que l'eau est, le principe de toute chose. C'est à moi que des pêcheurs donnèrent autrefois [un trépied d'or] qu'ils avaient tiré de la mer : ils m'avaient choisi pour obéir au dieu de Délos, qui envoyait ce présent à un sage. Je refusai de le recevoir, je le leur rendis pour le porter à d'autres que je croyais plus dignes. Envoyé à tous les sept Sages, et renvoyé par eux, il nie fut rapporté. Je le reçus alors pour le consacrer à Apollon : car si Phébus a voulu qu'on choisit un sage, ce n'était pas d'un homme, mais d'un dieu qu'il fallait l'entendre. Je suis donc ce Thalès : mais un motif m'amène sur la scène. Comme les deux sages qui m'ont précédé, je viens défendre la sentence dont je suis l'auteur. Elle déplaira, mais non certes aux esprits prudents que l'expérience a instruits et rendus plus avisés. Nous avons dit : [texte grec], ou, en latin : Cautionne, mais tu t'en trouveras mal. Je pourrais parcourir mille exemples pour vous montrer des cautions et des répondants bien et dûment convaincus de repentir. Mais je ne veux nommer personne. Que chacun de, vous ré-fléchisse, et compte en lui-même combien de gens ont perdu ou souffert de s'être ainsi portés cautions pour d'autres. Toutefois, si un pareil service a du charme pour vous, n'y renoncez ni les uns ni les autres. :Alors que les uns applaudissent, et que les autres, si je les blesse, me sifflent. :THALÈS DE MILET. :AVANT d'oser une mauvaise action, à défaut de Témoin redoute ta conscience. La vie s'éteint, mais la gloire de la mort ne meurt point. Ce que tu veux faire, abstiens-toi de le dire. C'est un supplice de craindre ce qu'on ne peut empêcher. Si tu blâmes avec raison, ton hostilité même est profitable ; si tu loues mal à propos, ton amitié même est nuisible. Rien de trop. - Arrêtons-nous, et qu'ici même il n'y ait rien de trop. <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Proclus|'''Proclus''']] ''(le 7 ou 8 février [[w:412|412]], à [[w:Constantinople|Constantinople]] — le 17 avril [[w:485|485]], à [[w:Histoire_d%27Athènes#Antiquité_tardive|Athènes]])''<sup>[[w:Ve_siècle|⏳]]</sup> [[s:Auteur:Proclus|<sup>📚</sup>]] == === Commentaire sur le premier livre d'Euclide, 65, 3 === ὥσπερ οὖν παρὰ τοῖς Φοίνιξιν διὰ τὰς ἐμπορείας καὶ τὰ συναλλάγματα τὴν ἀρχὴν ἔλαβεν ἡ τῶν ἀριθμῶν ἀκριβὴς γνῶσις, οὕτω δὴ καὶ παρ' Αἰγυπτίοις ἡ γεωμετρία διὰ τὴν εἰρημένην αἰτίαν εὕρηται. Θαλῆς δὲ πρῶτον εἰς Αἴγυπτον ἐλθὼν μετήγαγεν εἰς τὴν Ἑλλάδα τὴν θεωρίαν ταύτην καὶ πολλὰ μὲν αὐτὸς εὗρεν, πολλῶν δὲ τὰς ἀρχὰς τοῖς μετ' αὐτὸν ὑφηγήσατο τοῖς μὲν καθολικώτερον ἐπιβάλλων, τοῖς δὲ αἰσθητικώτερον. <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == « [[w:Souda|'''Suidas''']] » ''([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l'on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] fin du [[w:IXe_siècle|IX<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]])'' [[s:Auteur:Suidas|<sup>📚</sup>]] == === La Souda === Θαλῆς, Ἐξαμύου καὶ Κλεοβουλίνης, Μιλήσιος, ὡς δὲ Ἡρόδοτος Φοῖνιξ: γεγονὼς πρὸ Κροίσου, ἐπὶ τῆς λε# ὀλυμπιάδος, κατὰ δὲ Φλέγοντα γνωριζόμενος ἤδη ἐπὶ τῆς ζ#. ἔγραψε περὶ μετεώρων ἐν ἔπεσι, Περὶ ἰσημερίας, καὶ ἄλλα πολλά. ἐτελεύτησε δὲ γηραιός, θεώμενος γυμνικὸν ἀγῶνα, πιληθεὶς δὲ ὑπὸ τοῦ ὄχλου καὶ ἐκλυθεὶς ὑπὸ τοῦ καύματος. πρῶτος δὲ Θαλῆς τὸ τοῦ σοφοῦ ἔσχεν ὄνομα καὶ πρῶτος τὴν ψυχὴν εἶπεν ἀθάνατον ἐκλείψεις τε καὶ ἰσημερίας κατείληφεν. ἀποφθέγματα δὲ αὐτοῦ πλεῖστα: καὶ τὸ θρυλλούμενον: γνῶθι σαυτόν. τὸ γάρ, ἐγγύα, πάρα δ' ἄτα, Χίλωνός ἐστι μᾶλλον, ἰδιοποιησαμένου αὐτό: καὶ τό, μηδὲν ἄγαν. julphkn8s5rr04mqtlgmkqf4kf9krht 773690 773689 2026-09-30T07:09:30Z Alex Mtlr 103840 /* Chapitre XVII. */ 773690 wikitext text/x-wiki {| border="0" cellpadding="0" width="100%" style="background: #f9f9f9" | colspan="3" height="25"|<div style="text-align: center;">[[Philosophie/Thalès de Milet|'''Thalès de Milet''']]</div> |- | width="33%"|'''[[Philosophie/Thalès de Milet/Textes_et_traductions_période_République_Romaine|Période République Romaine]]''' |- | width="33%"|'''[[Philosophie/Thalès de Milet/Textes_et_traductions_période_Grèce_Hellénistique|Période de la Grèce Hellénistique]]''' |- | width="33%"|'''[[Philosophie/Thalès de Milet/Textes_et_traductions_Ier_millénaire_AEC|Période de la Grèce Classique]]''' |} {{EnTravaux}} <span style="font-size:18pt;">Période du Principat de l’[[w:Empire_romain|''Empire'']] [[#Empire|<span id="Empire_back"><sup>'''I'''</sup></span>]] [[w:Rome_antique|''Romain'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Rome_back|<sup>🔄</sup>]]</span> <p style="text-align: right;">(16 janvier [[w:27_av._J.-C.|-27]] <sup>[[w:Ier_siècle_av._J.-C.|⏳]]</sup>, nomination de [[w:Auguste|'''Caius Iulius Caesar Octavianus''']] aux titres d’[[w:Auguste_(titre)|''Augustus'']] et de [[w:Princeps_senatus|''Princeps'']] par le [[w:Sénat_romain|''Sénat romain'']] — fin du [[w:IIIe_siècle|III<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]], création du système [[w:Tétrarchie|''tétrarchique'']] [[#tétrarchie|<span id="tétrarchie_back"><sup>'''II'''</sup></span>]] par [[w:Dioclétien|'''Dioclétien''']] [[#Dioclétien|<span id="Dioclétien_back"><sup>'''III'''</sup></span>]] pour faire face aux [[w:Invasions_barbares#Première_période_:_les_mouvements_migratoires_germaniques_du_IIIe_siècle|''incursions barbares'']]) {{Boîte déroulante début|titre=NdA Empire|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Empire_back|<span id="Empire"><sup>I</sup></span>]] Du nom commun latin imperium [[wikt:en:imperium#Latin|(en)]], « 1. L’empire, l’État, le gouvernement impérial, le royaume, la domination. 2. Le droit ou le pouvoir de commander ou d’avoir le contrôle ; domination. 3. Commandement ou autorité absolue sur l’empire (ou un autre régime politique) ; souveraineté ; domination. 4. (militaire) Autorité militaire, commandement (d’une armée). 5. L’exercice de l’autorité, de la règle, de la loi, du contrôle, de la souveraineté. 6. Un commandement, un ordre, une direction, une injonction.) »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ du verbe imperō, « 1. (avec datif) Commander, donner des ordres à, imposer, exiger. 2. Gouverner. »;<br /><p style="margin: 0 2em; text-indent: 30px;">➥ du préfixe prépositionnal in-, « 1. Dans, à l’intérieur. 2. Contre; dans; sur; vers. 3. (utiliser comme un intensifieur). 4. Attaché à des [[w:Aspect_inchoatif|''verbes inchoatifs'']], il peut exprimer le sens d’un changement en cours ou d’un achèvement partiel. »;<br /><p style="margin: 0 2em; text-indent: 30px;">➥ +‎ du verbe parō [[wikt:en:paro#Latin|(en)]], « 1. Arranger, ordonner, concevoir. 2. Fournir, meubler, préparer. 3. Résoudre, viser, décider. 4. Obtenir, acquérir, se procurer, se faire. »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ + du suffixe nominal abstractif‎ -ium [[wikt:en:-ium#Latin|(en)]], désignant parfois des offices et des groupes. »;<br /><p style="margin: 0 2em; text-indent: 15px;">L’historien spécialiste de l’[[w:Grèce_antique|''antiquité grecque'']] [[w:Moses_Finley|Moses Finley]] définit un empire par tout {{Info|''« exercice durable par un État d’une autorité, d’un pouvoir, ou d’un contrôle sur un ou plusieurs États, communautés ou peuples »''|Moses Finley, Économie et société en Grèce antique, La Découverte, 2007.}}. L’historien [[w:Jean_Tulard|Jean Tulard]], précise cette définition par {{Info|''cinq traits suivants''|Jean Tulard, Les Empires occidentaux de Rome à Berlin, PUF, 1997.}} : :::* '''Une volonté expansionniste ; :::* '''Une organisation centralisée ; :::* '''Des peuples encadrés par une armature politique et fiscale commune ; :::* '''La croyance en une supériorité d’essence ; :::* '''Un début et une fin clairement identifiés. <br /><p style="margin: 0 2em; text-indent: 15px;">'''[[#tétrarchie_back|<span id="tétrarchie"><sup>II</sup></span>]] Du nom commun grec ancien τετραρχία / tetrarkhía;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ du préfixe τετρα- / tétra- [[wikt:en:τετρα-#Ancient_Greek|(en)]], « quatre »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ + du suffixe -αρχία / -arkhía [[wikt:en:-αρχία#Ancient_Greek|(en)]], « -archie (forme de gouvernement ou de règle) »;<br /><p style="margin: 0 2em; text-indent: 15px;"> Système de gouvernement de l’Empire ''romain'' mis en place par Dioclétien à la fin du [[w:IIIe_siècle|III<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]], pour faire face aux invasions barbares. Il consiste en la division de la direction de l’empire entre, d’une part deux [[w:Empereur_romain|''empereurs'']] — les [[w:Auguste_(titre)|''augustes'']] —, d’autre part deux ''lieutenants'' (successeurs désignés des ''augustes'') — les [[w:C%C3%A9sar_(titre)|''césars'']]. <br /><br /><p style="margin: 0 2em; text-indent: 15px;">'''[[#Dioclétien_back|<span id="Dioclétien"><sup>III</sup></span>]] [[w:Nom_romain|Tria Nomina]] en latin {{Info|Gaius|praenomen, nom individuel du citoyen romain}} {{Info|Aurelius|nomen, nom de famille}} {{Info|Valerius|cognomen, surnom héréditaire, servant à distinguer les diverses branches d’une même gens}}, surnommé Dioclētiānus [[wikt:en:Diocletian#English|(en)]] lorsqu’il a été proclamé empereur par ses troupes;<br /><p style="margin: 0 2em; text-indent: 15px;"> Militaire et empereur, connu pour avoir séparé et élargi les services civils et militaires de l’empire, et réorganisé les divisions provinciales de l’empire, établissant le gouvernement le plus vaste et le plus bureaucratique de l’histoire de l’empire. En [[w:286|286]], il nomme son ''césar'', ou adjoint et successeur, [[w:Maximien_Hercule|Maximien]] ''Auguste'', co-empereur, et partage l’Empire entre l’Orient et l’Occident, puis en 293, y nomme respectivement [[w:Galère_(empereur_romain)|Maximien Galère]] et [[w:Constance_Chlore|Constance Chlore]] comme ''césar''.<br/><br/></div> ''' {{Boîte déroulante fin}} == [[w:Sénèque|'''Sénèque''']] [[#Sénèque|<span id="Sénèque_back"><sup>'''I'''</sup></span>]] == <p style="text-align: right;">([[w:5_av._J.-C.|-5]] <sup>[[w:Ier_siècle_av._J.-C.|⏳]]</sup> / [[w:1|1]] <sup>[[w:Ier_siècle|⏳]]</sup>, à [[w:Corduba|Corduba]] — 12 avril [[w:65|65]], à [[w:Rome_antique|''Rome'']], dans une maison de plaisance, la « quatrième pierre milliaire », contraint au [[w:Suicide_forcé|''suicide forcé'']] par l’empereur [[w:Néron|'''Néron''']] après avoir été dénoncé dans la [[w:Conjuration_de_Pison|''Conjuration de Pison'']], sans preuve selon [[w:Tacite|'''Tacite''']] [https://remacle.org/bloodwolf/historiens/tacite/annales15.htm <sup>Annales, l.V, §§LX-LXVI.</sup>]) [[s:Auteur:Sénèque_le_Jeune|<sup>📚</sup>]] [https://books.google.fr/books?id=_HZTvAxN7CIC&newbks=1&newbks_redir=0&lpg=PA3&dq=bibliogroup%3A%22Dictionnaire%20des%20philosophes%20antiques%22&hl=fr&pg=PA177#v=onepage&q&f=true {{Info|<sup>🔍</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume VI, §43 - Seneca (Lucius Annaeus –)}}] [[Fichier:Duble_herma_of_Socrates_and_Seneca_Antikensammlung_Berlin_03_.jpg|vignette|<p style="text-align: justify; text-indent: 15px;">Double-hermès du [[w:IIIe_siècle|III<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]], unique portrait de '''Sénèque''' nommé et authentifié, et associé à celui de '''Socrate''', dont le point commun est celui d’avoir été contraint de se donner la mort. Copie ''romaine'' d’un modèle fait du vivant même du philosophe [https://books.google.fr/books?id=_HZTvAxN7CIC&newbks=1&newbks_redir=0&lpg=PA3&dq=bibliogroup%3A%22Dictionnaire%20des%20philosophes%20antiques%22&hl=fr&pg=PA180#v=onepage&q&f=true {{Info|<sup>➕</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume VI, §43 - Seneca (Lucius Annaeus –), Iconographie}}] [https://books.google.fr/books?id=_HZTvAxN7CIC&newbks=1&newbks_redir=0&lpg=PA3&dq=bibliogroup%3A%22Dictionnaire%20des%20philosophes%20antiques%22&hl=fr&pg=PA201#v=onepage&q&f=true {{Info|<sup>➕➕</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume VI, §43 - Seneca (Lucius Annaeus –), Iconographie - contribution de J. Lang}}].<br /><p style="text-align: justify; text-indent: 15px;">Matériau : Marbre blanc-brunâtre, légèrement veiné, finement cristallin.<br /><p style="text-indent: 15px;">Provenance : ''Rome'', 1813.<br /><p style="text-align: justify; text-indent: 15px;">Exposition : Staatliche Museen zu Berlin, Antikensammlung, SK. 391 [https://recherche.smb.museum/detail/698814/doppelherme-des-sokrates-und-seneca-mit-namensbeischriften-der-dargestellten <sup>🔍</sup>].]] <div style="text-align: justify; margin: 0 1em; text-indent: 15px">Homme politique romain, philosophe stoïcien et dramaturge, il devient tour à tour conseiller à la cour impériale sous '''Caligula''' puis '''Claude''', est exilé en 41 en ''Corse'', où il écrit ses premiers traités philosophiques avant d’être rappelé comme tuteur du jeune '''Néron''' en 49, et enfin, lorsque ce dernier accède au pouvoir, en devient le conseiller et l’un des personnages les plus influents de l’Empire.</div> {{Boîte déroulante début|titre=NdA Sénèque|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Sénèque_back|<span id="Sénèque"><sup>I</sup></span>]] [[w:Nom_romain|Tria Nomina]] en latin {{Info|Lucius|praenomen, nom individuel du citoyen romain}} {{Info|Annaeus|nomen, nom de famille}} {{Info|Seneca|cognomen, surnom héréditaire, servant à distinguer les diverses branches d’une même gens}}'''<br/><br/></div> {{Boîte déroulante fin}} === [[w:Sénèque#Physique|Questions naturelles]] === <p style="text-align: right;">[[s:Questions_naturelles|📚]] <div style="text-align: justify; margin: 0 1em; text-indent: 15px">Ouvrage de philosophie naturelle écrit vers 65. Il ne s’agit pas d’une [[w:Encyclopédie|encyclopédie]] [[#encyclopédie|<span id="encyclopédie_back"><sup>'''I'''</sup></span>]] systématique comme l’[[w:Histoire_naturelle_(Pline_l'Ancien)|''Histoire naturelle'']] [[#Histoire_naturelle|<sup>⤵️</sup>]] de [[w:Pline_l'Ancien|'''Pline l’Ancien''']] [[#Pline_l’Ancien_I|<sup>⤵️</sup>]], bien que ces 2 œuvres représentent les rares ouvrages romains consacrés à l’étude du monde naturel. L’investigation de '''Sénèque''' se déroule principalement à travers la prise en compte des points de vue d’autres penseurs, ''grecs'' et ''romains'', bien qu’elle ne soit pas dénuée de pensées originales, dont éthiques conforment à la pensée ''stoïcienne''.</div> {{Boîte déroulante début|titre=NdA Questions naturelles|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#encyclopédie_back|<span id="encyclopédie"><sup>I</sup></span>]] Du nom commun [[w:Latin#Latin_humaniste|latin Renaissance]] encyclopaedīa [[wikt:en:encyclopaedia#Latin|(en)]]; de l’expression grec ancien ἐγκύκλῐος παιδείᾱ / enkúklios paideíā [https://dumas.ccsd.cnrs.fr/dumas-03927443/file/DONNADILLE-MR2-Pline-VERS-FINALE.pdf {{Info|<sup>🔍</sup>|Lisa Donnadille. Merveilles animalières dans les livres VIII à XI de l’Histoire naturelle de Pline l’Ancien. Littératures. 2020. ffdumas-03927443, p.21}}], « cercle de l’éducation ou des sciences, l’ensemble des sciences qui constituent une éducation complète »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ de l’adjectif ἐγκύκλιος / enkúklios, littéralement « qui est rond ou tourne en rond, circulaire », ou au sens figuré « qui revient en cercle sur soi-même, périodique », « qui embrasse un cercle entier »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ du nom commun παιδεία / paideía, « l’éducation »;'''<br /><p style="margin: 0 2em; text-align: center;">« ''Si à première vue la signification de cette expression semble être sans ambiguïté, sa portée réelle et la compréhension qu’en avaient les auteurs grecs puis latins font l’objet de débats parmi les spécialistes. En effet, deux interprétations sont possibles lorsqu’un auteur de l’Antiquité a recours à cette expression dans l’un de ses textes. Dans le premier cas, cela équivaudrait à parler d’une éducation ordinaire, commune à tous ; et dans le second cas, cela ferait référence à la quantité de connaissances et de sciences qu’il faudrait maîtriser au préalable avant de commencer l’étude d’un sujet précis, qui serait dans ce cas placé en haut d’une hiérarchie dans les savoirs.'' »<br /><p style="margin: 0 2em; text-align: right;">''' Lisa Donnadille. [https://dumas.ccsd.cnrs.fr/dumas-03927443/file/DONNADILLE-MR2-Pline-VERS-FINALE.pdf Merveilles animalières dans les livres VIII à XI de l’Histoire naturelle de Pline l’Ancien. Littératures. 2020. ffdumas-03927443], p.21'''<br/><br/></div> {{Boîte déroulante fin}} ==== Livre III — De l’eau ==== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">En prologue, Sénèque explique pourquoi il est plus important de s’intéresser à l’observation du monde, à sa connaissance et à sa compréhension plutôt qu’à sa conquête. Puis, il développe diverses théories sur la formation des rivières, les eaux souterraines et les propriétés de l’eau. Dans une critique morale aux chapitres XVII à XIX, il fustige la mauvaise pratique consistant à amener à table des poissons, notamment des rougets, vivants et à se délecter de leurs couleurs changeantes à l’agonie avant de les préparer devant les convives. En épilogue, il énonce son [[w:Eschatologie|''eschatologie'']], sa vision de la fin du monde où les êtres vivants seront anéantis par des raz-de-marée, marquant la fin d’un cycle du vivant et le début d’un autre.</div> ===== <div style="text-align: center;">Chapitre XIII.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage de la doctrine de '''Thalès''' faisant de l’eau l’élément à l’origine de la vie et critique d’une autre de la terre flottant dessus.</div> :'''Texte latin''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''13.''' Adiciam, ut '''Thales''' ait, «ualentissimum elementum est». Hoc fuisse primum putat, ex hoc surrexisse omnia. Sed nos quoque aut in eadem sententia, aut in uicinia eius sumus. Dicimus enim ignem esse qui occupet mundum et in se cuncta conuertat; hunc euanidum languentemque considere et nihil relinqui aliud in rerum natura igne restincto quam umoren; in hoc futuri mundi spem latere. Ita ignis exitus mundi est, umor primordium. Miraris ex hoc posse amnes semper exire qui pro omnibus fuit et ex quo sunt omnia? Hic umor in diductione rerum ad quartas redactus est, sic positus ut sufficere fluminibus edendis, ut riuis, ut fontibus posset.<br /><p style="text-indent: 15px;">'''14.''' Quae sequitur '''Thaletis''' inepta sententia est. Ait enim terrarum orbem aqua sustineri et uehi more nauigii mobilitateque eius fluctuare tunc cum dicitur tremere; non est ergo mirum si abundat umor ad flumina profundenda, cum in umore sit totus. Hanc ueterem et rudem sententiam explode. Nec est quod credas in hunc orbem aquam subire per rimas et facere sentinam.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/seneca.-cuestiones-naturales.-naturales-quaestiones.-vol.-i-1979/page/n1/mode/2up <u>L. Annaei Senecae, Natvrales Qvaestiones</u>], [https://archive.org/details/seneca.-cuestiones-naturales.-naturales-quaestiones.-vol.-i-1979/page/n261/mode/2up ''Liber Tertivs.''], [https://archive.org/details/seneca.-cuestiones-naturales.-naturales-quaestiones.-vol.-i-1979/page/n293/mode/2up ''chap. 13.-14.''], texte établi par Carmen Codoñer Merino [[w:es:Carmen_Codoñer_Merino|(es)]], Consejo Superior de Investigaciones Científicas, Madrid, 1979</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: justify; margin: 0 2em;">'''XIII.''' Aqua, ait '''Thales''', valentissimum elementum est : hoc fuisse primum putat, et hoc surrexisse omnia. Sed et nos quoque aut in eadem sententia, aut in ultima sumus. Dicimus enim ignem esse, qui occupet mundum, et in se cuncta convertat ; hunc evanidum considere, et nihil relinqui aliud in rerum natura, igne restincto, quam humorem : in hoc futuri mundi spem latere. Ita ignis exitus mundi est, humor primordium. Miraris amnes ex hoc posse exire semper, qui pro omnibus fuit, et ex quo sunt omnia? Hic humor in diductione rerum ad quartas redactus est, sic positus, ut fluminibus edendis sufficere, ut rivis, ut fontibus posset. Quæ sequitur, '''Thaletis''' inepta sententia est : ait enim , terrarum orbem aqua sustineri, et vehi more navigii, mobilitateque ejus fluctuare, tum quum dicitur tremere. Non est ergo mirum, si abundat humor ad flumina fundenda, quum mundus in humore sit totus. Hanc veterem et rudem sententiam explode : nec est quod credas, in hunc orbem aquam subire per rimas et facere sentiuam.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PP9#v=onepage&q&f=true <u>Œuvres Complètes de Sénèque, Tome Quatrième</u>], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA327#v=onepage&q&f=true ''Questions Naturelles, De Sénèque à Lucilius - Livre Troisième.''], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA342#v=onepage&q&f=true ''chap. XIII.''], traduction française de la collection Panckoucke, nouvelle édition très soigneusement revue par M. Charpentier et M. Félix Lemaistre, 1860</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''XIII.''' L’eau, dit '''Thalès''', est le plus puissant des éléments, le premier en date, celui par qui tout a pris vie. Nous pensons comme '''Thalès''', au moins sur le dernier point. En effet, nous prétendons que le feu doit s’emparer du monde entier et convertir tout en sa propre substance, puis s’évaporer, s’affaisser, s’éteindre et ne rien laisser autre chose dans la nature que l’eau ; qu’enfin l’eau recèle l’espoir du monde futur. Ainsi périra par le feu cette création dont l’eau fut le principe. Es-tu surpris que des fleuves sortent incessamment d’un élément qui a tenu lieu de tout, et duquel tout est sorti ? Quand les éléments furent séparés les uns des autres, l’eau fut réduite au quart de l’univers, et placée de manière à suffire à l’écoulement des fleuves, des ruisseaux, des fontaines. Mais voici une idée absurde de ce même '''Thalès'''. Il dit que la terre est soutenue par l’eau sur laquelle elle vogue comme un navire ; qu’à la mobilité d’un tel support sont dues les fluctuations qu’on appelle tremblements de terre. Ce ne sera donc pas merveille qu’il y ait assez d’eau pour entretenir les fleuves, si tout le globe est dans l’eau. Ce système grossier et suranné n’est que risible ; tu ne saurais admettre que l’eau pénètre notre globe par ses interstices, et que la cale est entr’ouverte.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[[s:Questions_naturelles_(trad._Baillard)|<u>Sénèque le Jeune</u>]], [[s:Questions_naturelles_(trad._Baillard)/Livre_3|''Livre III. chap. 13.'']], traduction par [[s:Auteur:Joseph_Baillard|Joseph Baillard]], Hachette, 1914<br />(également disponible [https://remacle.org/bloodwolf/philosophes/seneque/questionsnaturelles3.htm ici])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: justify; margin: 0 2em;">'''XIII.''' L’eau, dit '''Thalès''', est le plus puissant des éléments : elle existait avant tout, elle est le principe de tout. Nous pensons comme '''Thalès''', au moins sur le dernier point. En effet, nous croyons que le feu, s’emparant du monde entier, convertira tout en sa propre substance : mais il finira par cesser ses ravages, et quand il sera éteint, dans toute la nature il ne restera que l’eau, et cette eau renfermera le germe et l’espérance d’un monde futur. Ainsi par le feu s’accomplira la destruction de l’univers, et par l’eau sa réorganisation. Êtes-vous surpris, maintenant, qu’après avoir tenu lieu de tous les éléments, et les avoir produits tous, l’eau suffise à l’entretien perpétuel des fleuves ? Quand les éléments furent séparés les uns des autres, l’eau fut réduite au quart de l’univers, et dans une proportion convenable pour suffire à l’alimentation des fontaines, des ruisseaux et des rivières. Mais voici une idée absurde du même '''Thalès''' : il dit que la terre est soutenue par l’eau, et qu’elle flotte sur elle comme un navire ; que les tremblements de terre sont causés par les oscillations et les mouvements du fluide qui la soutient. Il n’est donc pas étonnant qu’il y ait assez d’eau pour alimenter les fleuves, puisque tout le globe est dans l’eau. Mais rejetons cette vieille et informe hypothèse, qui assimile les sources aux flots que la cale entr’ouverte laisse pénétrer dans le vaisseau.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PP9#v=onepage&q&f=true <u>Œuvres Complètes de Sénèque, Tome Quatrième</u>], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA327#v=onepage&q&f=true ''Questions Naturelles, De Sénèque à Lucilius - Livre Troisième.''], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA342#v=onepage&q&f=true ''chap. XIII.''], traduction française de la collection Panckoucke, nouvelle édition très soigneusement revue par M. Charpentier et M. Félix Lemaistre, 1860</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: justify; margin: 0 2em;">'''Chap. III.'''<br />''Opiniõ de Thales touchant l’eau.''<br /><p style="text-align: justify; text-indent: 15px;">L’eau , comme dit '''Thales''' , e[[w:S_long|{{Info|ſ|forme ancienne longue de la lettre s minuscule}}]]<nowiki>t</nowiki> le plus fort des Elemens. Il croit me{{Info|ſ|forme ancienne longue de la lettre s minuscule}}me qu’elle e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t le premier , & que toutes cho{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es en ont pris nai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ance. Pour moy ie {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uis de cette opinion , ou du moins de la derniere partie de cette opinion. Car nous [[#nous_stoiciens_NdT_dR|<span id="nous_stoiciens_NdT_dR_back"><sup>1</sup></span>]] di{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ons que c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t le feu qui enueloppera tout le monde , & qui conuertira en {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oy toutes cho{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es; qu’il deuiendra {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ans force quand il n’aura plus de nourriture , qu’apres que le feu {{Info|ſ|forme ancienne longue de la lettre s minuscule}}era e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}teint il ne demeurera rien de re{{Info|ſ|forme ancienne longue de la lettre s minuscule}}te à la nature que l’eau {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eulement , & que c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t en elle {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eule que con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i{{Info|ſ|forme ancienne longue de la lettre s minuscule}}te l’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}perance d’vn monde futur. Ain{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i le feu e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t la fin du monde , & l’eau en e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t le commencement. Vous e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tonnez-vous donc que les fleuues pui{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ent tou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iours {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ortir d’vn Element , qui e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t fait pour toutes cho{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es & dont toutes cho{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e font ? Lors que la nature fit le departement des Elemens , l’eau fut placée de telle {{Info|ſ|forme ancienne longue de la lettre s minuscule}}orte , qu’elle peut {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uffire pour les fleuues , pour les rui{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}eaux , pour les fontaines. Mais ce que '''Thales''' dit en {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uitte e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t ridicule , car il dit que le Globe de la terre e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tenu par les eaux ; qu’elles le portent comme vn vai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}eau , & qu’elles l’agitent de la me{{Info|ſ|forme ancienne longue de la lettre s minuscule}}me {{Info|ſ|forme ancienne longue de la lettre s minuscule}}orte , lors que nous croyons qu’il tremble. Il ne faut donc pas s’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tonner , s’il ya tou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iours a{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ez d’eau pour former de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i grands fleuues , puis que tout le monde nage fur l’eau. Mais me{{Info|ſ|forme ancienne longue de la lettre s minuscule}}pri{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ez cette vieille , & cette gro{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}iere opinion , & ne croyez pas que l’eau vienne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur la terre , comme par des fentes & par des creua{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}es , & qu’elle y {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oit {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eulement comme dans le fond d’vn vai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}eau.</div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#nous_stoiciens_NdT_dR_back|<span id="nous_stoiciens_NdT_dR"><sup>1.</sup></span>]] Les Stoïciens.''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=ktOcOg9lr54C&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles%20iii&hl=fr&pg=PA1#v=onepage&q&f=true <u>Seneque Des Qvestions Natvrelles</u>], [https://books.google.fr/books?id=ktOcOg9lr54C&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles%20iii&hl=fr&pg=PA202#v=onepage&q&f=true ''Livre Troisiesme. Des eaux.''], [https://books.google.fr/books?id=ktOcOg9lr54C&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles%20iii&hl=fr&pg=PA234#v=onepage&q&f=true ''chap. XIII.''], traduction par [[w:Pierre_Du_Ryer|Pierre Du Ryer]], A Lyon, Chez Christofle Fovrmy, 1663</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div> </div> <div style="text-align: center; margin: 0 auto;">― ● ―</div> ==== Livre IV — Du Nil ==== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">En prologue, '''Sénèque''' fait l’éloge de [[w:Lucilius_le_Jeune|'''Lucilius''']] [[#Lucilius|<span id="Lucilius_back"><sup>'''I'''</sup></span>]] avant de lui expliquer les dangers de la flatterie. Puis, il décrit la crue du [[w:Nil|''Nil'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Nil_back|<sup>🔄</sup>]], expose les théories tentant de l’expliquer et les réfute. En épilogue, il fait le procès du luxe, et plus particulièrement celui d’acheter de la neige, et donc de marchandiser l’eau, regrettant qu’on ne puisse faire de même avec l’air et le soleil.</div> {{Boîte déroulante début|titre=NdA Lucilius|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Lucilius_back|<span id="Lucilius"><sup>I</sup></span>]] Du nom propre latin Lucilius [[wikt:en:Lucilius#Latin|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;">Gouverneur ''romain'' de Sicile durant le règne de [[w:Néron|Néron]], ainsi qu’un ami et un correspondant de Sénèque.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:Ier_siècle_av._J.-C.|I<sup>er</sup> siècle {{Info|EC|de l’Ère Commune}}]], [[w:Campanie#Histoire|''Campanie'']], [[w:Quatorze_régions_de_la_Rome_augustéenne#Regio_I_:_Porte_Capène|''Regio I'']])'''<br/><br/></div> {{Boîte déroulante fin}} ===== <div style="text-align: center;">Chapitre II.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Réfutation par '''Sénèque''' d’une théorie explicite de '''Thalès''' sur la crue du ''Nil'' (théorie identique mais supposément implicite rapportée par [[w:Hérodote|'''Hérodote''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Chapitre_XX|<sup>🔄</sup>]]).</div> :'''Texte latin''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''2.''' [...] Si '''Thaleti''' credis, etesiae descendenti ''Nilo'' resistunt et cursum eius acto contra ostia mari sustinent. Ita reuerberatus in se recurrit, nec crescit, sed exitu prohibitus resistit et quacumque mox potuit ui congestus erumpit. '''Euthymenes''' ''Massiliensis'' testimonium dicit: «Nauigaui, inquit, ''Atlanticum'' mare. Inde ''Nilus'' fluit, maior, quamdiu etesiae tempus obseruant; tunc enim eicitur mare instantibus uentis. Cum resederunt, et pelagus conquiescit minorque descendenti inde uis ''Nilo'' est. Ceterum dulcis mari sapor est et similes ''Niloticis'' beluae». Quare ergo, si ''Nilum'' etesiae prouocant, et ante illos incipit incrementum eius et post eos durat? Praeterea non fit maior quo illi flauere uehementius, nec remittitur incitaturque, prout illis impetus fuit; quod fieret, si illorum uiribus cresceret. Quid quod etesiae litus ''Aegyptium'' uerberant et contra illos ''Nilus'' descendit, inde uenturus unde illi, si origo ab illis esset? Praeterea ex mari purus et caeruleus efflueret, non, ut nunc, turbidus ueniret. Adde quod testimonium eius testium turba coarguitur. Tunc erat mendacio locus; cum ignota essent externa, licebat illis fabulas mittere. Nunc uero tota exteri maris ora mercatorum nauibus stringitur, quorum nemo narrat initium ''Nili'' aut mare saporis alterius: quae natura credi uetat, quia dulcissimum quodque et leuissimum sol trahit. Praeterea quare hieme non crescit? Et tunc potest uentis concitari mare, aliquanto quidem majoribus; nam etesiae temperati sunt. Quod si e mari ferretur ''Atlantico'', semel oppleret ''Aegyptum''. At nunc per gradus crescit.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/seneca.-cuestiones-naturales.-naturales-quaestiones.-vol.-ii-1979/page/n1/mode/2up <u>L. Annaei Senecae, Natvrales Qvaestiones</u>], [https://archive.org/details/seneca.-cuestiones-naturales.-naturales-quaestiones.-vol.-ii-1979/page/n7/mode/2up ''Liber Qvartvs A.''], [https://archive.org/details/seneca.-cuestiones-naturales.-naturales-quaestiones.-vol.-ii-1979/page/n41/mode/2up ''chap. 2.''], texte établi par Carmen Codoñer Merino [[w:es:Carmen_Codoñer_Merino|(es)]], Consejo Superior de Investigaciones Científicas, Madrid, 1979</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: justify; margin: 0 2em;">'''II.''' [...] Si '''Thaleti''' credis, Etesiæ descendenti ''Nilo'' resistunt, et cursus ejus acto contra ostia mari sustinent : ita reverberatus in se recurrit : nec crescit, sed exitu prohibitus resistit, et quacumque mox potuit, inconcessus erumpit.<br /><p style="text-align: justify; text-indent: 15px;">'''Euthymenes''' ''Massiliensis'' testimonium dicit : « Navigavi, inquit, ''Atlanticum'' mare. Inde ''Nilus'' fluit major, quamdiu Etesiæ tempus observant : tunc enim ejicitur mare instantibus ventis. Quum resederint, et pelagus conquiescit, minorque descendenti inde vis ''Nilo'' est. Ceterum dulcis maris sapor est, et similes ''Niloticis'' belluæ. » Quare ergo, si ''Nilum'' Etesiæ provocant, et ante illos incipit incrementum ejus, et post eos durat ? Præterea non fit major, quo illi flavere vehementius. Nec remittitur, incitaturque, prout illis impetus fuit : quod fieret, si illorum viribus cresceret. Quid, quod Etesiæ littus ''ægyptium'' verberant, et contra illos ''Nilus'' descendit, inde venturus, unde illi, si origo ab illis esset ? Præterea ex mari purus et cæruleus efflueret, non ut nunc turbidus venit. Adde, quod testimonium ejus testium turba coarguitur. Tunc erat mendacio locus, quum ignota essent externa. Licebat illis fabulas mittere. Nunc vero tota exteri maris ora mercatorum navibus stringitur : quorum nemo narrat nunc cæruleum ''Nilum'', aut mare saporis alterius ; quod et natura credi vetat, quia dulcissimum quodque et levissimum sol trahit. Præterea quare hieme non crescit ? et tunc potest ventis concitari mare, aliquando quidem majoribus ; nam Etesiæ temperati sunt. Quod si e mari ferretur ''Atlantico'', semel oppleret ''Ægyptum''. At nunc per gradus crescit.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PP9#v=onepage&q&f=true <u>Œuvres Complètes de Sénèque, Tome Quatrième</u>], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA371#v=onepage&q&f=true ''Questions Naturelles, De Sénèque à Lucilius - Livre Quatrième.''], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA385#v=onepage&q&f=true ''chap. II.''], traduction française de la collection Panckoucke, nouvelle édition très soigneusement revue par M. Charpentier et M. Félix Lemaistre, 1860</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''II.''' [...] À en croire '''Thalès''', les vents étésiens repoussent le ''Nil'' à sa descente dans la mer, et suspendent son cours en poussant la mer contre ses embouchures. Ainsi refoulé, il revient sur lui-même, sans pour cela grossir ; mais l’issue lui étant barrée, il s’arrête, et bientôt, partout où il le peut, force le passage qui lui est refusé. [[w:Euthymènes|'''Euthymène''']] [[#Euthymènes|<span id="Euthymènes_back"><sup>'''I'''</sup></span>]], de ''Marseille'', en parle comme témoin : « J’ai navigué, dit-il, sur la mer ''Atlantique''. Elle cause le débordement du ''Nil'', tant que les vents étésiens se soutiennent ; car c’est leur souffle qui alors pousse cette mer hors de son lit. Dès qu’ils tombent, la mer aussi redevient calme, et le ''Nil'' à sa descente déploie moins de puissance. Du reste, l’eau de cette mer est douce, et nourrit des animaux semblables à ceux du ''Nil''. » Mais pourquoi, si les vents étésiens font gonfler le ''Nil'', la crue commence-t-elle avant la saison de ces vents, et dure-t-elle encore après ? D’ailleurs le fleuve ne grossit pas à mesure qu’ils soufflent plus violemment. Son plus ou moins de fougue n’est point réglé sur celle des vents étésiens, ce qui aurait lieu, si leur action le faisait hausser. Et puis ils battent la côte ''égyptienne'', le ''Nil'' descend à leur encontre : il faudrait qu’il vînt du même point qu’eux, si son accroissement était leur ouvrage. De plus, il sortirait pur et azuré de la mer, et non pas trouble comme il est. Ajoute que le témoignage d’'''Euthymène''' est réfuté par une foule d’autres. Le mensonge avait libre carrière, quand les plages étrangères étaient inconnues ; on pouvait de là nous envoyer des fables, À présent, la mer extérieure est côtoyée sur tous ses bords par des trafiquants dont pas un ne raconte qu’aujourd’hui le ''Nil'' soit azuré ou que l’eau de la mer soit douce. La nature elle-même repousse cette idée ; car les parties les plus douces et les plus légères sont pompées par le soleil. Et encore pourquoi le ''Nil'' ne croît-il pas en hiver ? Alors aussi la mer peut être agitée par des vents quelque peu plus forts que les étésiens, qui sont modérés. Si le mouvement venait de l’Atlantique, il couvrirait tout d’un coup l’Égypte : or l’inondation est graduelle.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[[s:Questions_naturelles_(trad._Baillard)|<u>Sénèque le Jeune</u>]], [[s:Questions_naturelles_(trad._Baillard)/Livre_4|''Livre IV.'']] ''chap. 2.'', traduction par [[s:Auteur:Joseph_Baillard|Joseph Baillard]], Hachette, 1914<br />(également disponible [https://remacle.org/bloodwolf/philosophes/seneque/questionsnaturelles4.htm ici])</div> {{Boîte déroulante début|titre=NdA trad. par Joseph Baillard de 1914|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Euthymènes_back|<span id="Euthymènes"><sup>I</sup></span>]] Du nom propre grec ancien Εὐθυμένης / Euthuménēs [[wikt:en:Εὐθυμένης#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;"> ➥ de l’adjectif εὐθύς / euthús, « 1. Droit, direct : (au sens moral) direct, ouvert, franc. »;<br /><p style="margin: 0 2em; text-indent: 15px;"> ➥ + du nom commun μενος / ménos, « 1. Esprit. 2. Désir, ardeur, souhait, but. 3. Colère. 4. Courage, esprit, vigueur. 5. Pouvoir, force. 6. Violence. »;<br /><p style="margin: 0 2em; text-indent: 15px;"> ➥ + du suffixe nominal‎ propre -ης / -ēs [[wikt:en:-ης#Suffix_2|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;"> Navigateur et explorateur de la mer Extérieure le long des côtes africaines (actuelle Atlantique sud).<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:VIeme_siècle_av._J.-C.|VI<sup>ème</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]], [[w:Marseille_antique#Massalia,_une_cité_grecque|''Massalia'']], actuelle Marseille)'''<br/><br/></div> {{Boîte déroulante fin}} <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: justify; margin: 0 2em;">'''II.''' [...] Selon '''Thalès''', le phénomène a pour cause les vents Étésiens, qui s’opposent au cours du ''Nil'' et font rebrousser ses eaux en sens inverse du mouvement qui le porte vers la mer. Refoulés sur eux-mêmes, les flots refluent sans pour cela grossir ; mais l’issue leur étant fermée, ils s’arrêtent, et bientôt ils s’ouvrent partout où ils peuvent le passage qui leur est refusé.<br /><p style="text-align: justify; text-indent: 15px;">'''Euthymène''' de ''Marseille'' en parle comme témoin : « J’ai navigué, dit-il, sur la mer ''Atlantique''. Le ''Nil'' roule des eaux plus abondantes, tant que durent les vents Étésiens ; car alors ils refoulent la mer sur le fleuve. Dès qu’ils se sont abattus et que la mer est devenue calme, le ''Nil'', qui peut redescendre vers celle-ci, diminue. Au reste, les eaux de cette mer sont douces et contiennent des animaux semblables à ceux du ''Nil''. » Dans cette hypothèse, qui donne les vents Étésiens pour cause des crues du ''Nil'', qu’on me dise pourquoi ces crues précèdent les vents, persistent quand les vents ne sont plus, enfin n’augmentent plus d’intensité et de violence, et ne diminuent pas selon la violence et l’impétuosité du vent même ; c’est pourtant ce qui devrait arriver, si les vents déterminaient la hausse des eaux. De plus, les vents Étésiens battent directement la côte ''égyptienne'' : pourquoi donc le ''Nil'' descend-il contre le souffle de ces vents, tandis qu’il devrait couler dans la même direction, s’il leur devait ses débordements ? Enfin, pourquoi, au lieu d’être diaphanes et azurés, ces flots, qu’on fait venir de la mer, sont-ils chargés de limon ? Ajoutez qu’une foule de témoignages réfutent '''Euthymène'''. On pouvait mentir, quand les plages étrangères étaient inconnues : c’était alors le temps des fables ; mais aujourd’hui mille vaisseaux marchands côtoient la mer extérieure ; personne ne dit que le ''Nil'' ait des flots d’azur ; personne ne donne à la mer une saveur douce, que la nature refuse à ses eaux : car le soleil en pompe sans cesse la partie la plus douce et la plus légère ; ensuite pourquoi le ''Nil'' ne croîtrait-il point pendant l’hiver ? la mer alors peut être battue par les vents, par des vents plus violents que les Étésiens, qui sont modérés. Enfin, si le mouvement venait de l’Atlantique, l’Égypte entière serait inondée tout d’un coup : or, l’inondation est graduelle.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PP9#v=onepage&q&f=true <u>Œuvres Complètes de Sénèque, Tome Quatrième</u>], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA371#v=onepage&q&f=true ''Questions Naturelles, De Sénèque à Lucilius - Livre Quatrième.''], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA385#v=onepage&q&f=true ''chap. II.''], traduction française de la collection Panckoucke, nouvelle édition très soigneusement revue par M. Charpentier et M. Félix Lemaistre, 1860</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: justify; margin: 0 2em;">'''Chap. II.'''<br />''En quelle fai[[w:S_long|{{Info|ſ|forme ancienne longue de la lettre s minuscule}}]]<nowiki>ó</nowiki> {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e fait l’accroi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ement du Nil.''<br /><p style="text-align: justify; text-indent: 15px;">[...] Si vous en croyez '''Thales''' , les vents Ethe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iens re{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tent au ''Nil'' en de{{Info|ſ|forme ancienne longue de la lettre s minuscule}}cendant dans la mer; & arre{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tent {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on cours, en pou{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ant la mer contre {{Info|ſ|forme ancienne longue de la lettre s minuscule}}es {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ept emboucheures. Si bien qu’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es {{Info|ſ|forme ancienne longue de la lettre s minuscule}}tant repou{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}é de la {{Info|ſ|forme ancienne longue de la lettre s minuscule}}orte il retourne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oy-me{{Info|ſ|forme ancienne longue de la lettre s minuscule}}me , & ne croi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t pas comme l’on pen{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e , mais par ce qu’il trouue vn ob{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tacle qui l’empe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}che de pa{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}er outre , il e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t contraint de s’arre{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ter , & ne pouuant plus pour{{Info|ſ|forme ancienne longue de la lettre s minuscule}}uiure {{Info|ſ|forme ancienne longue de la lettre s minuscule}}a cour{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e , il {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e re{{Info|ſ|forme ancienne longue de la lettre s minuscule}}pand par où il peut {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e répandre. '''Euthimenes''' de ''Mar{{Info|ſ|forme ancienne longue de la lettre s minuscule}}eille'' en rend ce te{{Info|ſ|forme ancienne longue de la lettre s minuscule}}moignage. I’ay nauigé, dit il, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur la mer ''Atlantique'' , & c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t par elle que le ''Nil'' deuient plus grand, lors que les vents Ethe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iens {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oufflent ; car alors cette mer {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ort pour ain{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i dire d’elle-me{{Info|ſ|forme ancienne longue de la lettre s minuscule}}me par la force & par la violence de ces vents. Mais lors qu’ils ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oufflent plus la mer demeure tranquille, & le Nil ne trouue plus rien qui l’empe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}che de de{{Info|ſ|forme ancienne longue de la lettre s minuscule}}cendre , Au re{{Info|ſ|forme ancienne longue de la lettre s minuscule}}te l’eau de la mer e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t douce en ce temps-là , & l’on y void des be{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tes {{Info|ſ|forme ancienne longue de la lettre s minuscule}}emblables à celles du Nil. Mais {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i les Ethe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iens {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont enfler le Nil, pourquoy {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on débordement commence il auant qu’ils {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oufflent & pourquoy dure - il encore lors qu’ils ont ce{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}é de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ouffler. Dauantage ils ne s’enfle pas plus que de cou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tume , quand ces vents {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oufflent auecque plus de violence qu’ils ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont ordinairement. Enfim il ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e hau{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}e & ne s’abai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}e pas {{Info|ſ|forme ancienne longue de la lettre s minuscule}}elon que leur impetuo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ité e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t plus ou moins grande , ce qui arriveroit {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ans doute s’il s’enfloit par la force de ces véts. Mais comme les Ete{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iens battent directement les bords de l’Egypte, & que le Nil de{{Info|ſ|forme ancienne longue de la lettre s minuscule}}cend contre eux ; il faudroit s’ils e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}toient cau{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on accroi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ement , qu’il commença{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t par l’endroit d’où ils viennent. Outre cela il {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ortiroit tout pur de la mer, & de la couleur de la mer, & ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eroit pas trouble & limonneux , comme il e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t. Et apres tout le te{{Info|ſ|forme ancienne longue de la lettre s minuscule}}moignage d’'''Euthimene''' , e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t condamné par le plus grand nombre. Il e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}toit permis de mentir quand on n’auoit point de connoi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ance des pays e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}trangers ; & alors on pouuoit facilement nous en enuoyer des fables. Mais aujourd’huy tous les riuages des mers les plus e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}loignées {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont remplis de vai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}eaux de marchands, & pas vn ne nous apporte que le ''Nil'' {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oit de la couleur de la mer, ou que la mer ait vn autre gou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t. Quand nous aurions des rai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ons pour nous la per{{Info|ſ|forme ancienne longue de la lettre s minuscule}}uader , la nature nous empe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}cheroit de le croire par ce que le Soleil en attire ce qu’il y a de plus leger & de plus doux. Dauantage pourquoy ne croi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t-il pas en Hyuer , puis que la met en ce temps là peut e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tre agitée par des vents plus violents, que les Ethe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iens qui {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont tou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iours moderez. Que {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i le ''Nil'' venoit de la mer ''Atlantique'' , il couuriroit l’Egypte tout d’vn coup, & neantmoins il ne la couure que peu à peu.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=gEzVYlz3c3cC&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles%20iii%20volume%202&hl=fr&pg=PA1#v=onepage&q&f=true <u>Seneque Des Qvestions Natvrelles</u>], [https://books.google.fr/books?id=gEzVYlz3c3cC&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles%20iii%20volume%202&hl=fr&pg=PA3#v=onepage&q&f=true ''Livre Qvatriesme. De la Nege, de la Greſle, & de la Pluye.''], [https://books.google.fr/books?id=gEzVYlz3c3cC&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles%20iii%20volume%202&hl=fr&pg=PA37#v=onepage&q&f=true ''chap. II.''], traduction par [[w:Pierre_Du_Ryer|Pierre Du Ryer]], A Lyon, Chez Christofle Fovrmy, 1663</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div> </div> <div style="text-align: center; margin: 0 auto;">― ● ―</div> ==== Livre VI — Des tremblements de terre ==== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">En prologue, '''Sénèque''' énonce le plan du livre, des causes des tremblements de terre et des peurs qu’ils provoquent, en s’appuyant sur celui de ''Campanie'' qui a récemment causé d’importants dégâts à ''Pompéi'' et à ''Herculanum''. Des chapitres IV à XX, de nombreuses théories sismiques sont présentées, la plupart liées au nom d’un philosophe qui les prône. Le feu, l’eau et l’air sont cités comme causes, et plusieurs d’entre-elles les combinent. À partir du chapitre XXIV, '''Sénèque''' développe sa propre opinion : l’air pénétrant, qui remplit complètement les cavités souterraines sous une forte pression, en est la cause. En épilogue, il explique à '''Lucilius''' quel comportement adopté en de telles situations, à savoir être courageux en ne craignant pas la mort</div> ===== <div style="text-align: center;">Chapitre VI.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Réfutation d’une théorie de '''Thalès''' de la Terre flottant sur l’eau, et témoignage d’une de ses preuves portant sur les tremblements de terre.</div> :'''Texte latin''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''6.''' In aqua causam esse nec ab uno dictum est nec uno modo. '''Thales''' ''Milesius'' totam terram subiecto iudicat umore portari et innare, siue illud oceanum uocas, siue magnum mare, siue alterius naturae simplicem adhuc aquam et umidum elementum. Hac, inquit, unda sustinetur orbis uelut aliquod grande nauigium et graue his aquis quas premit. Superuacuum est reddere causas propter quas existimat grauissimam partem mundi non posse spiritu tam tenui fugacique gestari; non enim nunc de situ terrarum sed de motu agitur. Illud argumenti loco ponit aquas esse in causa quibus hic orbis agitetur, quod in omni maiore motu erumpunt fere noui fontes, sicut in nauigiis quoque euenit ut, si inclinata sunt et abierunt in latus, aquam sorbeant, quae in omni eorum onere quae uehit, si immodice depressa sunt, aut superfunditur aut certe dextra sinistraque solito magis surgit. Hanc opinionem falsam esse non est diu colligendum. Nam, si terra aqua sustineretur et ea aliquando concuteretur, semper moueretur, nec agitari illam miraremur sed manere; deinde tota concuteretur, non ex parte; numquam enim nauis dimidia iactatur. Nunc uero terrarum non uniuersarum sed ex parte motus est. Quomodo ergo fieri potest ut, quod totum uehitur, totum non agitetur, si eo quo uehitur agitatum est? — At quare aquae erumpunt? — Primum omnium saepe tremuit terra et nihil umoris noui fluxit. Deinde, si ex hac causa unda prorumperet, a lateribus terrae circumfunderetur, sicut in fluminibus ac mari uidemus incidere ut incrementum aquarum, quotiens nauigia desidunt, in lateribus maxime appareat. Ad ultimum non tam exigua fieret quam tu dicis eruptio nec uelut per rimam sentina subreperet, sed fieret ingens inundatio ut ex infinito liquore et ferente uniuersa.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/seneca.-cuestiones-naturales.-naturales-quaestiones.-vol.-ii-1979/page/n1/mode/2up <u>L. Annaei Senecae, Natvrales Qvaestiones</u>], [https://archive.org/details/seneca.-cuestiones-naturales.-naturales-quaestiones.-vol.-ii-1979/page/n135/mode/2up ''Liber Qvintvs - De terrae motv''], [https://archive.org/details/seneca.-cuestiones-naturales.-naturales-quaestiones.-vol.-ii-1979/page/n155/mode/2up ''chap. 6.''], texte établi par Carmen Codoñer Merino [[w:es:Carmen_Codoñer_Merino|(es)]], Consejo Superior de Investigaciones Científicas, Madrid, 1979</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: justify; margin: 0 2em;">'''VI.''' In aqua causam esse, nec ab uno dictum est, nec uno modo. '''Thales''' ''Milesius'' totam terram subjecto judicat humore portari et innatare : sive illud Oceanum vocas, sive magnum mare, sive alterius naturæ simplicem adhuc aquam et humidum elementum. Hac, inquit, unda sustinetur orbis, velut aliquod grande navigium et grave his aquis, quas premit. Supervacuum est reddere causas, propter quas existimat, gravissimam partem mundi non posse spiritu tam tenui fugacique gestari ; non enim nunc de situ terrarum, sed de motu agitur. Illud argumenti loco ponit, aquas esse in causa, quibus hic orbis agitatur, quod in omui majore motu erumpunt fere novi fontes : sicut in navigiis quoque evenit, ut, si inclinata sunt et abiere in latus, aquam sorbeant, quæ in omni onere eorum quæ vehit, si immodice depressa sunt, aut superfunditur, aut certe dextra sinistraque solito magis surgit. Hanc opinionem falsam esse, non est diu colligendum ; nam, si terram aqua sustineret, et ea aliquando concuteretur : semper moveretur, nec agitari illam miraremur, sed manere. Tum tota concuteretur, non ex parte : nunquam enim navis dimidia jactatur. Nunc vero non terrarum universarum, sed ex parte motus est. Quomodo ergo fieri potest, ut quod totum vehitur, totum non agitetur, si eo quo vehitur, agitatum est ? At quare aquæ erumpunt ? Primum omnium sæpe tremuit terra, et nihil humoris novi fluxit. Deinde si ex hac causa unda prorumperet, a lateribus terræ circumfunderetur : sicut in fluminibus ac mari videmus accidere, ut incrementum aquarum, quoties navigia desidunt, in lateribus maxime appareat. Ad ultimum non tam exigua fieret quam dicit eruptio, nec velut per rimam sentina subreperet, sed fieret ingens inundatio, ut ex infinito liquore, et ferente universa.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PP9#v=onepage&q&f=true <u>Œuvres Complètes de Sénèque, Tome Quatrième</u>], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA420#v=onepage&q&f=true ''Questions Naturelles, De Sénèque à Lucilius - Livre Sixième.''], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA429#v=onepage&q&f=true ''chap. VI.''], traduction française de la collection Panckoucke, nouvelle édition très soigneusement revue par M. Charpentier et M. Félix Lemaistre, 1860</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''VI.''' Que l’eau soit cause des tremblements de terre, c’est ce qu’affirment divers auteurs et avec divers arguments. '''Thalès''' de ''Milet'' estime que le globe entier a pour support une masse d’eaux sur laquelle il flotte, et qu’on peut appeler Océan ou grande mer, ou élément jusqu’ici de nature simple, l’élément humide. Cette eau, dit-il, soutient la terre ; et l’immense navire pèse sur le liquide qu’il comprime. Il est superflu d’exposer les motifs qui font croire à '''Thalès''' que la partie de l’univers la plus pesante ne saurait porter sur une substance aussi ténue, aussi fugace que l’air : il ne s’agit pas maintenant de l’assiette du globe, mais de ses secousses. '''Thalès''' apporte en preuve de son système, que presque toujours les grandes secousses font jaillir des sources nouvelles, comme il arrive dans les navires qui, lorsqu’ils penchent et s’inclinent sur le flanc, sont envahis par l’eau ; toujours, s’il y a surcharge, l’eau vient couvrir le bâtiment, ou du moins s’élève à droite et à gauche plus que de coutume. La fausseté de cette opinion se démontre sans longs raisonnements. Si la terre était soutenue par l’eau, elle tremblerait quelquefois dans toute sa masse et toujours serait en mouvement ; ce ne serait pas son agitation qui étonnerait, mais son repos. Elle s’ébranlerait tout entière, non partiellement ; car ce n’est jamais la moitié seulement d’un navire qui est battue des flots. Or, les tremblements de notre terre ne sont pas universels, mais partiels. Comment serait-il possible qu’un corps porté tout entier par l’eau ne fût pas agité tout entier, quand ce fluide est agité ? « Mais d’où viennent les eaux qu’on a vues jaillir ? » D’abord, souvent la terre tremble, sans qu’il en sorte de nouvelles eaux. Ensuite, si telle était la cause de ces éruptions, elles n’auraient lieu qu’autour des flancs du globe ; ce que nous voyons arriver sur les fleuves et en mer : l’exhaussement de l’onde, à mesure que s’enfonce le navire, se remarque surtout aux flancs du bâtiment. Enfin l’éruption dont on parle ne serait pas si minime, et comme une voie d’eau qui s’infiltre par une fente légère ; l’inondation serait immense en raison de l’abîme infini sur lequel flotterait le monde.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[[s:Questions_naturelles_(trad._Baillard)|<u>Sénèque le Jeune</u>]], [[s:Questions_naturelles_(trad._Baillard)/Livre_6|''Livre VI.'']] ''chap. 6.'', traduction par [[s:Auteur:Joseph_Baillard|Joseph Baillard]], Hachette, 1914<br />(également disponible [https://remacle.org/bloodwolf/philosophes/seneque/questionsnaturelles6.htm ici])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: justify; margin: 0 2em;">'''VI.''' Plusieurs philosophes ont prétendu que l’eau est la cause de ces secousses : ce que chacun explique à sa manière. '''Thalès''' de ''Milet'' prétend que le globe entier a pour support une masse d’eau sur laquelle il flotte ; peu importe qu’on donne à cet amas le nom d’Océan, de grande mer ou d’eau élémentaire, eau simple. Cette eau, dit-il, soutient la terre comme un grand vaisseau pesant sur le liquide qu’il comprime. Il est inutile d’exposer les raisons qui font croire à '''Thalès''' que le corps le plus pesant de la nature ne peut être soutenu par un fluide aussi délié et aussi rare que l’air : car il s’agit ici des tremblements de terre et non de l’assiette du globe. La grande raison de '''Thales''' pour faire de l’eau la cause des secousses de la terre, c’est que, dans tout tremblement considérable, jaillissent des eaux nouvelles ainsi les vaisseaux se remplissent d’eau quand ils penchent d’un côté ; chargés à l’excès, ou ils sont submergés, ou ils s’enfoncent à droite et à gauche plus profondément dans la mer. Il ne faut pas longtemps discuter pour voir la fausseté de cette opinion. Si la terre était soutenue par les eaux, elle serait quelquefois fortement ébranlée, mais de plus elle serait toujours flottante, et il faudrait s’étonner non de son agitation , mais de son repos ; enfin, au lieu d’être ébranlée en partie, elle le serait tout entière : car jamais la moitié d’un vaisseau n’est battue des flots. Or, on sait que les secousses de la terre sont partielles et non universelles : comment se ferait-il donc que ce qui est entièrement porté par les eaux ne fût pas entièrement agité, tandis que les eaux mêmes le sont en totalité ? Mais, dit-on, qui fait jaillir les eaux ? D'abord, souvent la terre tremble sans qu’il se produise des eaux nouvelles ; ensuite, si telle était la cause de ces éruptions, les eaux se répandraient latéralement autour de la terre. Ainsi, par exemple, quand un vaisseau s’enfonce ou dans la mer ou dans les fleuves, c’est vers les bords surtout que l’accroissement devient sensible. Enfin les sources qui jaillissent ne seraient pas si peu considérables ; on ne pourrait pas les comparer à une voie d’eau qui pénètre par les fentes du fond de cale : ce serait une inondation immense comme l’abîme infini sur lequel flotterait le monde.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PP9#v=onepage&q&f=true <u>Œuvres Complètes de Sénèque, Tome Quatrième</u>], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA420#v=onepage&q&f=true ''Questions Naturelles, De Sénèque à Lucilius - Livre Sixième.''], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA429#v=onepage&q&f=true ''chap. VI.''], traduction française de la collection Panckoucke, nouvelle édition très soigneusement revue par M. Charpentier et M. Félix Lemaistre, 1860</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: justify; margin: 0 2em;">'''Chap. VI.'''<br />''Si l’eau e[[w:S_long|{{Info|ſ|forme ancienne longue de la lettre s minuscule}}]]<nowiki>t</nowiki> la cau{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e des tréblemés de terre.''<br /><p style="text-align: justify; text-indent: 15px;">Ce n'e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t pas vn homme {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eul qui a dit , que l’eau e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}toit cau{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e du tremblement de la terre ; & l’on ne l’a pas dit d’vne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eule façó. '''Thales''' ''Mile{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ien'' a crû que toute la terre e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}toit portée {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur l’eau , & qu’elle y nageoit, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oit que vous appelliez cette eau Ocean, ou que vous l’appelliez grade mer, ou vne eau d’vne autre nature , eau {{Info|ſ|forme ancienne longue de la lettre s minuscule}}imple , element humide. C’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur cette eau, dit-il, que le monde e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tenu, comme quelque vai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}eau d’vne grandeur deme{{Info|ſ|forme ancienne longue de la lettre s minuscule}}urée , qui charge les eaux qui le {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tiennent. Il {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eroit inutile de rapporter les rai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ons qui luy {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont croire que la plus pe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ante partie du móde ne peut e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tre {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tenuë par l’air qui e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ubtil, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i fluide & {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i delié ; & d’ailleurs, il ne s’agit pas icy de l’a{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}iete de la terre , mais du tremblement de la terre. Ain{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i pour preuue que les eaux {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont cau{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e que la terre tremble , il dit qu’il ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e fait pre{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que point de grands tremblemens de terre, qu’on n’en voye {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ortir en{{Info|ſ|forme ancienne longue de la lettre s minuscule}}uitte de nouuelles {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ources; que la terre re{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}emble en cela aux vai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}eaux qui ne peuuent pancher d’vn co{{Info|ſ|forme ancienne longue de la lettre s minuscule}}té, qu’ils ne pui{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ent de l’eau, qui {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e re{{Info|ſ|forme ancienne longue de la lettre s minuscule}}pand {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur toutes les cho{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es qu’ils portent , {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i elles {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont trop enfoncées; ou qui s’éleue de part & d’autre à la gauche , & à la droite. Il n’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t pas besoin d’vn long di{{Info|ſ|forme ancienne longue de la lettre s minuscule}}cours pour montrer la fau{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}eté de cette opinion ; car {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i l’eau {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tenoit la terre, quelquesfois elle trembleroit toute entiere, & {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eroit tou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iours en mouuement; & nous ne nous e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tonnerions point de la voir remuer, mais de la voir ferme & inébranlable. Elle trembleroit toute entiere , & non pas en partie , car vn vai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}eau n’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t iamais agité par vne moitié {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eulement ; & apres tout nous voyons que le tremblement ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e fait pas de toute la terre , mais {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eulement d’vne partie. Comment donc {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e peut-il faire que ce qui e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t porté tout entier ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oit pas entierement agité , {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i la cho{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e me{{Info|ſ|forme ancienne longue de la lettre s minuscule}}me qui porte e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}meuë & agitée ? Mais pourquoy {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ort-il de l’eau apres vn tremblement de terre ? Premierement la terre a {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ouuent tremblé {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ans qu’on en ayt veu {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ortir de nouuelles {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ources. D’ailleurs {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i l’eau {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ortoit par cette rai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}on elle {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e re{{Info|ſ|forme ancienne longue de la lettre s minuscule}}pandroit par les co{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tez de la terre , comme nous voyons dans les fleuues & dans la mer , où lors que le vai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}eau s’enfonce on remarque que l’eau s'éleue , principalement par les co{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tez. Enfin ces eaux ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ortiroient pas en {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i petite quantité, ny par vne fi petite ouuerture , mais il {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eroit vne grande inondation, comme procedant de cette abondance d’eaux qui {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tiennent tout l’vniuers.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=gEzVYlz3c3cC&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles%20iii%20volume%202&hl=fr&pg=PA1#v=onepage&q&f=true <u>Seneque Des Qvestions Natvrelles</u>], [https://books.google.fr/books?id=gEzVYlz3c3cC&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles%20iii%20volume%202&hl=fr&pg=PA141#v=onepage&q&f=true ''Livre Sixiesme. Des tremblemens de terre.''], [https://books.google.fr/books?id=gEzVYlz3c3cC&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles%20iii%20volume%202&hl=fr&pg=PA164#v=onepage&q&f=true ''chap. VI.''], traduction par [[w:Pierre_Du_Ryer|Pierre Du Ryer]], A Lyon, Chez Christofle Fovrmy, 1663</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Pline_l%27Ancien|'''Pline l’Ancien''']] [[#Pline|<span id="Pline_back"><sup>'''I'''</sup></span>]] == <p style="text-align: right;">([[w:23|23]]/[[w:24|24]], à [[w:Côme|''Novum Comum'']] ou [[w:Vérone|Vérone]] — [[w:79|79]], à [[w:Stabies|Stabies]], [[w:Mort_de_Pline_l%27Ancien|mort]] par asphyxie près de [[w:Pompéi|Pompéi]], lors de l’éruption du [[w:Vésuve|Vésuve]], en voulant observer le phénomène au plus près et en désirant porter secours aux victimes, alors en poste à [[w:Misène|''Misène'']] en tant que Préfet commandant la flotte militaire ''romaine'') <sup>[[w:Ier_siècle|⏳]]</sup> [[s:Auteur:Pline_l’Ancien|<sup>📚</sup>]] [https://books.google.fr/books?id=tRsuD3WJT-UC&newbks=1&newbks_redir=0&lpg=PA3&dq=bibliogroup%3A%22Dictionnaire%20des%20philosophes%20antiques%22&hl=fr&pg=PA876#v=onepage&q&f=true {{Info|<sup>🔍</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume Va, §204 - Plinius Secundus (Caius —)}}] <div style="text-align: justify; margin: 0 1em; text-indent: 15px">Haut fonctionnaire militaire et civique, issu de l’[[w:Chevalier_romain|''orde équestre'']], et écrivain prolifique dans de très nombreux domaines.</div> {{Boîte déroulante début|titre=NdA Pline l’Ancien|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Pline_back|<span id="Pline"><sup>I</sup></span>]] [[w:Nom_romain|Tria Nomina]] en latin {{Info|Caius|praenomen, nom individuel du citoyen romain}} {{Info|Plinius|nomen, nom de famille}} {{Info|Secundus|cognomen, surnom héréditaire, servant à distinguer les diverses branches d’une même gens}}'''<br/><br/></div> {{Boîte déroulante fin}} === [[w:Histoire_naturelle_(Pline_l'Ancien)|Histoire naturelle]] === <p style="text-align: right;">[[s:Histoire_naturelle_(Pline)|📚]] <div style="text-align: justify; margin: 0 1em; text-indent: 15px">Ouvrage de 37 livres dédié à l’empereur [[w:Titus_(empereur_romain)|'''Titus''']] [[#Titus|<span id="Titus_back"><sup>'''I'''</sup></span>]], dont il a été le ''{{Lang|la|contubernium}}'' pendant son service en tant que commandant des armées du ''Rhin'' en ''Germanie'' en [[w:47|47]]. '''Pline''' définit lui-même son enquête [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Histoire/Enquête_I|<sup>🔄</sup>]] sur la nature comme une reproduction de la vie — ''{{Lang|la|rerum natura, hoc est uita narratur}}'' (Livre I, Préface, 10), qu’il inscrit dans la tradition encyclopédique [[#encyclopédie_back|<sup>⤴️</sup>]] grecque mais s’en différencie par son exhaustivité : ''{{Lang|la|Jam omnia attingenda, quæ Græci}}'' ''{{Lang|grc|τάς έγχυχλοπαιδείας}}'' ''{{Lang|la|vocant : et tamen ignota aut incerta ingeniis facta; alia vero ita multis prodita, ut in fastidium sint adducta}}'' (Préface, 11). Il a, dans ce but, compilé « vingt mille faits dignes d’intérêt, tirés de la lecture d’environ deux mille volumes, [...] provenant de cent auteurs de choix » — ''{{Lang|la|Viginti millia rerum dignarum cura ex lectione voluminum circiter duum millium, [...] ex exquisitis auctoribus centum}}'' (Préface, 13).</div> {{Boîte déroulante début|titre=NdA Titus|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Titus_back|<span id="Titus"><sup>I</sup></span>]] Du nom propre latin Titus [[wikt:en:Titus#Latin|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;">Commandant militaire, notamment pendant la [[w:Premi%C3%A8re_guerre_jud%C3%A9o-romaine|''première guerre judéo-romaine'']], au cours de laquelle il prend ''Jérusalem'' que ses troupes mettent à sac et fait détruire le [[w:Second_temple_de_Jérusalem#Destruction|''Second Temple'']], et empereur ''romain'', de la dynastie des [[w:Flaviens|''Flaviens'']], de [[w:79|79]] à [[w:81|81]].<br /><p style="text-align: right; margin: 0 2em;">(30 décembre [[w:39|39]] , ''Rome'' — 13 septembre [[w:81|81]], mort par fièvre selon [[w:Suétone|Suétone]] [http://remacle.org/bloodwolf/historiens/suetone/titus.htm <sup>VdDC, Titus</sup>] ou par empoisonnement avec du venin de [[w:Aplysia|''lièvre marin'']] par son propre frère [[w:Domitien|Domitien]] selon [[w:Philostrate_d%27Ath%C3%A8nes|Philostrate]] [https://remacle.org/bloodwolf/roman/philiostrate/apollonius6.htm <sup>AdT, l. VI, chap. 32</sup>])<sup>[[w:Ier_siècle|⏳]]</sup>'''<br/><br/></div> {{Boîte déroulante fin}} ==== Livre II ==== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Enquête sur l’astronomie et la physique du monde, basée sur les quatre éléments : air, terre, eau et feu.</div> ===== <div style="text-align: center;">Chapitre IX.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage de la première prédiction grecque d’une éclipse solaire (ou lunaire selon les traductions) par '''Thalès'''.</div> :'''Texte latin''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''IX.''' Et rationem quidem defectus utriusque primus ''Romani'' generis in vulgus extulit '''Sulpicius Gallus''', qui consul cum '''Marcello''' fuit, sed tum tribunus militum, sollicitudine exercitu liberato, pridie quam '''Perseus''' rex superatus a '''Paulo''' est, in concionem ab imperatore productus ad prædicendam eclipsim, mox et composito volumine. Apud Græcos autem investigavit primus omnium '''Thales''' ''Milesius'', Olympiadis XLVIII anno quarto, prædicto solis defectu, qui '''Alyatte''' rege factus est, Urbis conditæ; anno CLXX. Post eos utriusque sideris cursum in sexcentos annos præcinuit '''Hipparchus''', menses gentium, diesque et horas, ac situs locorum, et visus populorum complexus, ævo teste, haud alio modo, quam consiliorum naturæ particeps. Viri ingentes supraque mortalium naturam, tantorum numinum lege deprehensa, et misera hominum mente absoluta, in defectibus scelera aut mortem aliquam siderum pavente (quo in metu fuisse '''Stesichori''' et '''Pindari''' vatum sublimia ora palam est deliquio Solis), et in Luna veneficia arguente mortalitate, et ob id crepitu dissono auxiliante. Quo pavore, ignarus causæ, '''Nicias''' ''Atheniensium'' imperator, veritus classem portu educere, opes eorum afflixit. Macti ingenio este, cæli interpretes, rerumque naturæ capaces, argumenti repertores, quo deos hominesque vinxistis. Quis enim hæc cernens, et statos siderum (quoniam ita placuit appellare) labores, non suæ necessitati mortalis genitus ignoscat ? Nunc confessa de iisdem breviter atque capitulatim attingam, ratione admodum necessariis locis strictimque reddita : nam neque instituti operis talis argumentatio est : neque omnium rerum afferri posse causas, minus mirum est, quam consfare in aliquibus.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/b24875958_0001/page/n7/mode/2up <u>Histoire Naturelle de Pline.</u>], [https://archive.org/details/b24875958_0001/page/98/mode/2up ''Livre II.''], [https://archive.org/details/b24875958_0001/page/106/mode/2up ''chap. IX.''], texte corrigé par [[w:Émile_Littré|M. É. Littré]], à partir de celui de [[w:Jean_Hardouin|Hardouin]], Librairie de Firmin-Didot et C<sup>ie</sup>, Paris, 1883<br />(également disponible une édition 1848 [[s:Page:Pline_l'ancien_-_Histoire_naturelle,_Littré,_T1_-_1848.djvu/130|ici]] et 1829 [https://gallica.bnf.fr/ark:/12148/bpt6k5773334c/f45.item là])</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''IX.''' Le premier ''Romain'' qui exposa publiquement la théorie des éclipses du soleil et de la lune est [[w:Caius_Sulpicius_Gallus|'''Sulpicius Gallus''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Caius_Sulpicius_Gallus_back|<sup>🔄</sup>]], qui fut consul avec [[w:Marcus_Claudius_Marcellus_(consul_en_-166)|'''Marcellus''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Marcellus-166_back|<sup>🔄</sup>]], mais qui alors était tribun militaire. La veille du jour où [[w:Persée_(roi)|'''Persée''']] [[#Persée_(roi)|<span id="Persée_(roi)_back"><sup>'''I'''</sup></span>]] fut défait par [[w:Lucius_Æmilius_Paullus_Macedonicus|'''Paul-Emile''']] [[#Lucius_Æmilius_Paullus_Macedonicus|<span id="Lucius_Æmilius_Paullus_Macedonicus_back"><sup>'''II'''</sup></span>]] il parut par ordre du général, afin de prévenir les alarmes de l’armée, devant les troupes assemblées pour annoncer l’éclipse qui allait survenir; peu de temps après, il composa un livre sur ce sujet. Le premier qui s’en occupa chez les ''Grecs'' fut '''Thalès''' de ''Milet'', dans la quatrième année de la quarante-huitième olympiade (an 585 av. J. C. [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#éclipse_back|<sup>🔄</sup>]]), l’an 170 de la fondation de ''Rome'', et prédit une éclipse de lune qui arriva sous le roi [[w:Alyatte_II|'''Alyatte''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Alyatte_back|<sup>🔄</sup>]]. Après eux, [[w:Hipparque_(astronome)|'''Hipparque''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Hipparque_back|<sup>🔄</sup>]] dressa pour six cents ans la table du cours du soleil et de la lune, déterminant les mois des divers calendriers, les jours, les heures, les localités et les aspects, suivant les contrées. Le cours des ans ne lui a donné aucun démenti, et il semble avoir été admis aux conseils de la nature. Génies puissants et élevés au dessus de l’humanité, ils ont découvert la loi qui régit ces grandes divinités, et ils ont délivré de ses craintes l’esprit misérable des hommes, qui dans les éclipses, tantôt croyaient voir une influence malfaisante ou une espèce de mort des astres, crainte qui, comme on sait, a, pour l’éclipse du soleil, troublé [[w:Stésichore|'''Stésichore''']] [[#Stésichore|<span id="Stésichore_back"><sup>'''III'''</sup></span>]] et [[w:Pindare|'''Pindare''']] [[#Pindare|<span id="Pindare_back"><sup>'''IV'''</sup></span>]], poètes sublimes, et tantôt attribuaient l’obscurcissement de la lune à des maléfices, et lui venaient en aide par un bruit dissonnant. Redoutant ce phénomène, dont il ignorait la cause, [[w:Nicias|'''Nicias''']] [[#Nicias|<span id="Nicias_back"><sup>'''V'''</sup></span>]], général des ''Athéniens'', n’osa pas faire sortir la flotte du port de [[w:Syracuse#Antiquité|''Syracuse'']], et ruina la puissance de sa patrie. Redoublez de génie, interprètes du ciel, vous dont l’intelligence, embrassant la nature, a inventé des théories qui ont créé un lien entre les dieux et les hommes [[#Vicistis_JH|<span id="Vicistis_JH_back"><sup>'''1'''</sup></span>]] ! A la vue de ce spectacle, à la vue des labeurs (puisque c’est le nom qu’on a voulu donner aux éclipses), des labeurs réguliers auxquels les astres sont soumis, quel mortel ne pardonnerait à la nécessité sous laquelle il est né ? Maintenant je vais parler, d’une manière brève et sommaire, des points sur lesquels on est d’accord en cette matière. Je ne donnerai que de courtes explications, et là où il sera tout à fait nécessaire; car les explications n’entrent pas dans le plan de cet ouvrage, et il n’y a pas moins de mérite à énumérer les causes de toutes choses qu’à s’appesantir sur quelques-unes.</div> <table cellspacing=15 align=center style="margin: 0 4em; font-size:85%;"> <tr> <td style="text-align: justify; margin: 0 4em;">'''[[#Vicistis_JH_back|<span id="Vicistis_JH"><sup>1</sup></span>]] Vicistis Vulg. — Vinxistis cod. Dalech. — Vinxistis me parait meilleur. Comp. ce que dit Pline plus loin, ch. 24, sur l’affinité de l’esprit humain avec les astres.'''</td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/b24875958_0001/page/n7/mode/2up <u>Histoire Naturelle de Pline.</u>], [https://archive.org/details/b24875958_0001/page/98/mode/2up ''Livre II.''], [https://archive.org/details/b24875958_0001/page/106/mode/2up ''chap. IX.''], texte corrigé par [[w:Émile_Littré|M. É. Littré]], à partir de celui de [[w:Jean_Hardouin|Hardouin]], Librairie de Firmin-Didot et C<sup>ie</sup>, Paris, 1883<br />(édition 1848 également disponible [[s:Page:Pline_l'ancien_-_Histoire_naturelle,_Littré,_T1_-_1848.djvu/130|ici]])</div> {{Boîte déroulante début|titre=NdA de trad. Jean Hardouin 1883|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Persée_(roi)_back|<span id="Persée_(roi)"><sup>I</sup></span>]] Du nom propre grec ancien Περσεύς / Perseús[[wikt:en:Περσεύς#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px">Dernier roi de [[w:Royaume_de_Mac%C3%A9doine|''Macédoine'']] de la dynastie des [[w:Antigonides|''Antigonides'']], vaincu en [[w:-168|-168]] à la [[w:bataille de Pydna|bataille de ''Pydna'']] à l’issue de la [[w:troisième guerre macédonienne|''troisième guerre macédonienne'']], causant la disparition du ''Royaume de Macédoine''.<br /><p style="text-align: right; margin: 0 2em;">([[w:Années_212_av._J.-C.|-212]]<sup>[[w:IIIe_siècle_av._J.-C.|⏳]]</sup>, [[w:Pella_(cité_antique)|''Pella'']], au nord de l’actuelle ''Grèce'' — [[w:Années_166_av._J.-C.|-166]]<sup>[[w:IIe_siècle_av._J.-C.|⏳]]</sup>, [[w:Alba_Fucens|''Alba Fucens'']], au centre de l’actuelle ''Italie'') <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Lucius_Æmilius_Paullus_Macedonicus_back|<span id="Lucius_Æmilius_Paullus_Macedonicus"><sup>II</sup></span>]] [[w:Nom_romain|Tria Nomina]] en latin {{Info|Lucius|praenomen, nom individuel du citoyen romain}} {{Info|Æmilius|nomen, nom de famille}} {{Info|Paullus|cognomen, surnom héréditaire, servant à distinguer les diverses branches d’une même gens}}, surnommé [[wikt:Macedonicus#Latin|Macedonicus]] par le [[w:Sénat_romain|''Sénat'']] à la suite de sa victoire;<br /><p style="margin: 0 2em; text-indent: 15px">Homme politique ''romain'', consul à 2 reprises en [[w:Années_182_av._J.-C.|-182]] et [[w:Années_169_av._J.-C.|-169]]. Il remporta la victoire contre le ''royaume de Macédoine'' à ''Pydna'' en battant le roi Persée [[#Persée_(roi)|<sup>I</sup>]], ce qui mit fin à la dynastie des ''Antigonides''.<br /><p style="text-align: right; margin: 0 2em;">([[w:Circa|{{Info|''ca.''|Circa, locution latine que l’on emploie pour indiquer l’approximation d’une date}}]] [[w:Années_230_av._J.-C.|-230]]<sup>[[w:IIIe_siècle_av._J.-C.|⏳]]</sup>, ''Rome'' — ''ca.'' [[w:Années_160_av._J.-C.|-160]]<sup>[[w:IIe_siècle_av._J.-C.|⏳]]</sup>, ''Rome'') <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Stésichore_back|<span id="Stésichore"><sup>III</sup></span>]] Du nom propre grec ancien Στησίχορος /Stēsíkhoros [[wikt:en:Στησίχορος#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;">➥ du verbe ἵστημι /hístēmi, « 1. (voix transitive, active des temps présent, imparfait, futur et 1er aoriste) : • Faire se tenir debout, se tenir debout; • Arrêter, rester, vérifier; • Mettre en place : - Faire monter, élever, réveiller, remuer; - Nommer, désigner; - Établir, instituer; • Mettre dans la balance, peser. 2. (voix intransitive, moyenne et passive, voix active du 2e aoriste, parfait et plus-que-parfait) : • Se tenir debout; • Se tenir immobile : (au sens figuré) Rester ferme; • Être dressé ou debout, se lever, s’élever : - (en général) Se lever, commencer; - (en marquant le pas) Être; - Être désigné. »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ +‎ du nom commun χορός / khorós, « 1. Danse en rond. 2. Danse accompagnée de chant, danse chorale. 3. Chœur, chorale, groupe de chanteurs et de danseurs. 4. Groupe, troupe. 5. Rangée. 6. Lieu de danse. 7. (théâtre) Chœur »;<br /><p style="margin: 0 2em; text-indent: 15px">Poète lyrique grec, considéré comme l’un des [[w:Neuf_lyriques_grecs|''neuf poètes lyriques'']] de la Grèce antique.<br /><p style="text-align: right; margin: 0 2em;">([[w:Circa|{{Info|''ca.''|Circa, locution latine que l’on emploie pour indiquer l’approximation d’une date}}]] [[w:Années_630_av._J.-C.|-630]]<sup>[[w:VIIe_siècle_av._J.-C.|⏳]]</sup>, [[w:Metauria|''Metauria'']], colonie de la [[w:Grande-Grèce|''Grande-Grèce'']], au sud de la région de [[w:Calabre|''Calabre'']], au sud de l’Italie — ''ca.'' [[w:Années_555_av._J.-C.|-555]]<sup>[[w:VIe_siècle_av._J.-C.|⏳]]</sup>, [[w:Catane|''Catane'']], colonie de la ''Grande-Grèce'', à l’est de la [[w:Sicile|''Sicile'']]) <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Pindare_back|<span id="Pindare"><sup>IV</sup></span>]] Du nom propre grec ancien Πίνδᾰρος /Píndaros [[wikt:en:Πίνδαρος#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px">Poète lyrique grec, considéré comme l’un des [[w:Neuf_lyriques_grecs|''neuf poètes lyriques'']] de la Grèce antique.<br /><p style="text-align: right; margin: 0 2em;">([[w:Années_518_av._J.-C.|-518]]<sup>[[w:VIe_siècle_av._J.-C.|⏳]]</sup>, [[w:Cynocéphales|''Cynocéphales'']], cité grecque située près de [[w:Thèbes_(Grèce)|''Thèbes'']], en [[w:Béotie|''Béotie'']] — [[w:Années_438_av._J.-C.|-438]]<sup>[[w:Ve_siècle_av._J.-C.|⏳]]</sup>, [[w:Árgos|''Árgos'']], cité grecque de la région de l’[[w:Argolide|''Argolide'']], à l’est de la [[w:Péloponnèse|''péninsule du Péloponnèse'']]) <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Nicias_back|<span id="Nicias"><sup>V</sup></span>]] Du nom propre grec ancien Νῑκίᾱς /Nīkíās [[wikt:en:Νικίας#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;">➥ du nom commun νίκη / níkē [[wikt:en:νίκη#Ancient_Greek|(en)]], « 1. Le fait de gagner : la victoire, le succès [avec le génitif "sur, dans quelque chose"] : • Les choses gagnées dans la victoire, les fruits de la victoire; • La supériorité, l’avantage. »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ + du suffixe nominal masculin -ίας / -ías [[wikt:en:-ίας#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px">Homme politique et général ''athénien'' durant la [[w:Guerre_du_Péloponnèse|''guerre du Péloponnèse'']], qui oppose la [[w:Ligue_de_Délos|''ligue de Délos'']], menée par ''Athènes'', et la [[w:Ligue_du_Péloponnèse|''ligue du Péloponnèse'']], sous l’[[w:Hégémonie|hégémonie]] de ''Sparte'' de [[w:Années_431_av._J.-C.|-431]] à [[w:Années_404_av._J.-C.|-404]]. Sa supersition liée à une éclipse lunaire, s’étant produite lors de l’[[w:Expédition_de_Sicile|''expédition de Sicile'']], est également relatée par [[w:Thucydide|Thucydide]] [http://remacle.org/bloodwolf/historiens/thucydide/livre7.htm#L <sup>{{Info|HdlgdP|Histoire de la guerre du Péloponnèse}} l.VII, §.L</sup>] et [[w:Plutarque|Plutarque]] [[#Plutarque_back|<sup>⤵️</sup>]] [http://remacle.org/bloodwolf/historiens/Plutarque/supestition.htm#23 <sup>{{Info|DlS|De la Superstition}} l.I</sup>].<br /><p style="text-align: right; margin: 0 2em;">([[w:Circa|{{Info|''ca.''|Circa, locution latine que l’on emploie pour indiquer l’approximation d’une date}}]] [[w:Années_470_av._J.-C.|-470]], ''Athènes'' — ''ca.'' [[w:Années_413_av._J.-C.|-413]], ''Syracuse'')<sup>[[w:Ve_siècle_av._J.-C.|⏳]]</sup>'''<br/><br/></div> {{Boîte déroulante fin}} <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: center; margin: 0 2em;">Des découvertes astronomiques : part de chaque observateur dans la science.<br /><p style="text-align: justify; text-indent: 15px;">'''IX.''' '''Sulpicius Gallus''' [[#Sulpicius_Gallus_AdG|<span id="Sulpicius_Gallus_AdG_back"><sup>'''1'''</sup></span>]] fut le premier ''Romain'' qui expliqua au vulgaire la raison des éclipses de soleil et de lune. Il fut consul avec '''Marcus Marcellus''' ; mais il n’était que tribun militaire lorsque la veille de la victoire que '''Paul Emile''' remporta sur '''Persée''' [[#Pridie_quam_Perses_rex_AdG|<span id="Pridie_quam_Perses_rex_AdG_back"><sup>'''2'''</sup></span>]], son général le fit paraître devant l’armée assemblée, pour lui annoncer l’éclipse qui allait arriver, et la délivrer de l’alarme qu’elle aurait pu en concevoir. Il composa bientôt après un volume sur ce sujet. Parmi les ''Grecs'', '''Thalès''' de ''Milet'' [[#Primus_omnium_Thales_AdG|<span id="Primus_omnium_Thales_AdG_back"><sup>'''3'''</sup></span>]] dirigea le premier ses recherches sur ce phénomène, et la quatrième année de la 48e olympiade, qui répond à l’an 170 [[#Anno_CLXX_AdG|<span id="Anno_CLXX_AdG_back"><sup>'''4'''</sup></span>]] de ''Rome'', il prédit l’éclipse de soleil qui eut lieu sous le règne d’'''Alyatte''' [[#Alyatte_rege_AdG|<span id="Alyatte_rege_AdG_back"><sup>'''5'''</sup></span>]]. Après eux, '''Hipparque''' dressa des tables du cours de ces deux astres pour six cents ans [[#In_sexcentos_annos_AdG|<span id="In_sexcentos_annos_AdG_back"><sup>'''6'''</sup></span>]] : mois, heures, jours, situations respectives des lieux, aspects du ciel selon les diverses nations [[#Menses_gentium_etc_AdG|<span id="Menses_gentium_etc_AdG_back"><sup>'''7'''</sup></span>]], tout y est compris, tout a été vérifié par le temps [[#Aevo_teste_AdG|<span id="Aevo_teste_AdG_back"><sup>'''8'''</sup></span>]]; on croirait l’astronome admis au conseil de la nature. Génies vastes et plus qu’humains, d’avoir ainsi surpris la loi de ces deux grandes divinités [[#Numinum_AdG|<span id="Numinum_AdG_back"><sup>'''9'''</sup></span>]], et affranchi d’effroi la malheureuse espèce humaine, qui tremblait en voyant dans chaque éclipse l’annonce de quelque grand crime, ou craignait la mort des astres [[#In_defectibus_scelera_etc_AdG|<span id="In_defectibus_scelera_etc_AdG_back"><sup>'''10'''</sup></span>]] (effroi dont '''Stésichore''' et '''Pindare''' [[#Pindari_AdG|<span id="Pindari_AdG_back"><sup>'''11'''</sup></span>]], ces poètes sublimes, ne furent point exempts dans les éclipses de soleil), ou qui attribuait à des enchantemens celles de la lune, et venait à son secours en faisant un bruit discordant [[#Crepitu_dissono_AdG|<span id="Crepitu_dissono_AdG_back"><sup>'''12'''</sup></span>]]. C’est pour en avoir ignoré la cause, que, frappé de cette même terreur, '''Nicias''' [[#Nicias_AdG|<span id="Nicias_AdG_back"><sup>'''13'''</sup></span>]], général des ''Athéniens'', n’osa pas faire sortir sa flotte du port, et causa la ruine de leur puissance. Gloire à vous, interprètes du ciel, génies aussi étendus que la nature, inventeurs d’une science qui enchaîne à une même destinée les dieux et les mortels ! Quel est donc l’homme qui, voyant les astres en travail (pour me servir du nom qu’il a plu de donner aux crises qu’ils, subissent périodiquement), ne se soumettra pas à sa destinée?<br /><p style="text-align: justify; text-indent: 15px;">Je vais maintenant toucher brièvement et sommairement les points sur lesquels on est d’accord dans cette matière, et j’en rendrai raison en passant, lorsque cela sera tout-à-fait nécessaire; car un développement de preuves n’est pas le but de l’ouvrage que j’ai entrepris, et il n’y a pas, je pense, moins de mérite à pouvoir rendre raison de toutes choses, qu’à s’arrêter à en prouver quelques-unes.</div> {{Boîte déroulante début|titre=Notes du traducteur|alignT=center}} <div style="text-align: justify; border: 2px; border-radius:15px; font-size:85%;"><br/> <table cellspacing=15 align=center style="margin: 0 4em;"> <tr> <td style="text-align: justify; margin: 0 4em; text-indent: 15px">'''[[#Sulpicius_Gallus_AdG_back|<span id="Sulpicius_Gallus_AdG"><sup>1</sup></span>]] [[w:Tite-Live|Tite-Live]], XLIV, 37, [[w:Quintilien|Quintilien]], I, 10, [[w:Plutarque|Plutarque]] [[#Plutarque_back|<sup>⤵️</sup>]], [[w:Vies_parallèles|''Vie de Paul Emile'']], [[w:Frontin|Frontin]], I, etc., prétendent, comme Pline, que Sulpicius Gallus prédit l’éclipse anx soldats romains. [[w:Cicéron|'''Cicéron''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Cicéron_back|<sup>🔄</sup>]] ([[w:De_Republica|''Répub.'']], I, 15 , page 44, ''édit. Maj.'') dit au contraire que l’éclipse était déjà arrivée lorsque Sulpicius Gailus commençait à s’efforcer d’ôter aux soldats romains la terreur qu’ils avaient conçue de cet événement, en leur expliquant les causes des éclipses.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Pridie_quam_Perses_rex_AdG_back|<span id="Pridie_quam_Perses_rex_AdG"><sup>2</sup></span>]] Selon Tite-Live (XLIV, 37), l’éclipse eut lieu dans la soirée du 3 septembre, cent huit ans avant J.-C., entre sept et dix heures (''ab hora secunda usque ad quartam noctis, quam pridie nonas sept, secula est dies''). M. [[w:Christian_Ludwig_Ideler|Ideler]] (''Chronologie'', II, 104) a calculé cette éclipse. Il a trouvé, comme M. de Nauze, que, selon le calendrier Julien, elle arriva dans la soirée du 21 juin de l’an 168 avant J.-C. à Rome, la lune commença à s’éclipser vers 5h.44’ du soir ; depuis 6h.51’ jusqu’à 8h.18’, la lune fut totalement éclipsée, ; à 9h.,24’, la lune ne fut plus obscurcie du tout. En Macédoine, tous ces phénomènes arrivèrent 39 minutes plus tard. Le 21 juin, le soleil se coucha à Rome et en Macédoine vers 7h.33’, et s’y montra alors à 44 1/2’ h. équatoriales. Ainsi, la première heure de la nuit finissait vers 8h.17’, la seconde vers 9h.2’, la troisième vers 9h.46’, la quatrième vers 10h.31’. La lune fut donc éclipsée totalement au moment où elle se leva dans la Macédoine, et cette éclipse totale y finit dans la seconde heure de la nuit ; au milieu de la quatrième, la lune ne fut plus obscurcie du tout. S’il est vrai, que cette éclipse lunaire, comme Pline, Tite-Live et d’autres le disent, fut prédite par Sulpicius Gallus, l’on devrait avouer que ce Romain s’entendait très-bien au calcul des éclipses lunaires. Mais les récits de Cicéron et de [[w:Valère_Maxime|Valère-Maxime]] ne seraient-ils pas plus vrais que ceux de Pline et de Tite-Live ?''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Primus_omnium_Thales_AdG_back|<span id="Primus_omnium_Thales_AdG"><sup>3</sup></span>]] Le même fait est rapporté par [[w:Hérodote|Hérodote]] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Hérodote_back|<sup>🔄</sup>]], I, 74, par [[w:Diogène_Laërce|Diogène Laërce]] [[#Diogène_Laërce_back|<sup>⤵️</sup>]], I, 6 , par [[w:Clément_d'Alexandrie|Clément d’Alexandrie]] [[#Clément_d'Alexandrie_back|<sup>⤵️</sup>]], ''Strom.'', I, page 302 , par Plutarque, ''Opinions des Philosophes'', II, 24, par [[w:Jean_Tzétzès|Tzetzès]], ''Chil.'' II, v. 869, et par Hardouin.<br /><p style="text-align: justify; text-indent: 15px;">Oltmann a publié une dissertation dans laquelle, à l’aide des tables astronomiques les plus modernes, il est arrivé à ce résultat, que l’éclipse solaire dont il est question ici eut lieu le 3o septembre 610 ans avant J.-C. L’éclipse était totale pour les environs de la ville d’[[w:Erzurum|Érzerum]] sur le [[w:Kızılırmak_(fleuve)|Halys]] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Halys_back|<sup>🔄</sup>]], où [[w:Volney|Volney]] place le champ de bataille des rois [[w:Alyatte_II|Halyattes]] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Alyatte_back|<sup>🔄</sup>]] et [[w:Cyaxare|Cyaxare]] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Cyaxare_back|<sup>🔄</sup>]]. La quatre-vingtième partie du disque solaire seule ne fut pas éclipsée pour le lieu de la terre où Oltmann place le champ de bataille, qui est situé, selon lui, sous 36° long. à l’est de Terro et sous 40° lat. sept. Dans le pays des Ioniens où Thalès prédit l’éclipse, selon Hérodote, l’éclipse se monta à 11 1/2’. M. [[w:Alphonse_Des_Vignoles|Desvignolles]] (''Chronologie de l’histoire sainte'', t. II, pag. 245 et suiv.) fixe l’éclipsé prédite par Thales au 38 mai de l’an 585 avant J.-C. ; son opinion a été adoptée depuis par presque tous les chronologistes et historiens, et par [[w:Gabriel_Brotier|Brotier]] et M. Alexandre. Elle a été réfutée avec succès par Oltmann, qui s’est servi de tables astronomiques bien plus exactes que celles de M. Desvignolles ; en effet, celui-ci a démontré par ses calculs que l’éclipse totale du soleil du 28 mai de l’an 585 avant J.-C., ne fut pas totale dans les lieux où les troupes du roi lydien Halyatte combattirent contre celles du roi Cyaxare ; que, dans ces régions, elle ne se monta pas à plus de 7 1/2 pouces, et que, d’ailleurs, le soleil ne s’était pas encore levé lorsque Féclipse était le plus forte pour les habitans des pays nommés. Mais Hérodote dit positivement que l’éclipse prédite par Thalès fut totale dans ces contrées, et qu’elle eut lieu en plein jour. (Voyez IDELER, ''Chronologie'', t. I, pag. 209 et 210.) Nous remarquerons pourtant avant de finir cette note que la date de Desvignolles est plus conforme que celle d’Oltmann à l’année dans laquelle l’éclipse prédite par Thalès, arriva selon Pline. En effet, le naturaliste romain dit que cette année est la six cent quatre-vingt-cinquième avant J.—C., et c’est justement le 28 mai de cette année que l’éclipse prédite par Thalès arriva, selon M. Desvignolles.<br /><p style="text-align: justify; text-indent: 15px;">Volney pense que l’éclipse en question arriva le 3 février de de l’an 626. Oltman a démontré, dans son Mémoire sur l’éclipse de Thalès, que celle de Volney était déjà passée lorsque le soleil se leva sur le champ de bataille des rois Halyattes et Cyaxare.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Anno_CLXX_AdG_back|<span id="Anno_CLXX_AdG"><sup>4</sup></span>]] L’an 170. C’est ainsi que l’on doit lire, et non CLX, comme l’ont fait Hardouin et Poinsinet; la quatrième année de la quarante-huitième olympiade, correspondant à l’an 170 de Rome, si l’on suppose avec [[w:Varron_(écrivain)|Varron]] que cette ville a été fondée dans la deuxième année de la 6e olympiade.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Alyatte_rege_AdG_back|<span id="Alyatte_rege_AdG"><sup>5</sup></span>]] Le nom de ce roi est écrit avec un esprit rude dans Hérodote, ce qui a donné lieu à [[w:Louis_Poinsinet_de_Sivry|Poinsinet]] et à d’autres traducteurs de Pline de substituer le mot Halyatte à celui d’Alyatte.<br /><p style="text-align: justify; text-indent: 15px;">Alyatte ou Halyatte fut roi de la Lydie et père de Crésus. Il faisait la guerre à Cyaxare, roi des Mèdes, lorsque l’éclipse solaire en question interrompit le combat.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#In_sexcentos_annos_AdG_back|<span id="In_sexcentos_annos_AdG"><sup>6</sup></span>]] On lit dans [[w:Georges_le_Syncelle|le Syncelle]] (''Chronolog.'', pag. 17) que les Chaldéens ont connu une période de six cents années solaires. [[w:Flavius_Josèphe|Josèphe]] [[#Flavius_Josèphe_back|<sup>⤵️</sup>]] ([[w:Antiquités_judaïques|''Ant. jud.'']], I, page 17 et 18, édit. Havercamp) dit que Dieu donna une longue vie aux patriarches pour qu’ils pussent cultiver avec succès les sciences astronomiques et géométriques, ce qu’ils n’auraient pu faire s’ils n’avaient pas vécu au moins six cents ans ; car la grande année ne finit pas plus tôt. Ainsi, il est certain qu’avant Hipparque les Chaldéens et d’autres peuples asiatiques ont connu une période de six cents années solaires. Mais [[w:Jean-Dominique_Cassini|Cassini]] ([[w:Jean-Dominique_Cassini#Mémoires_de_l’Académie_royale_des_sciences|''Anciens mém. de l’Acad.'']], t. VIII, pag. 4 et 5) et [[w:Jean_Sylvain_Bailly|Bailly]] (''Hist. de l’astr. ancienne'', t. II, liv. 3, Eclairciss.) ont prouvé que tous les six cents ans les nouvelles et pleines lunes n’arrivent pas seulement au même jour et à la même heure qu’auparavant, mais encore à la même minute. Ne serait-il donc pas probable qu’Hipparque, comme le dit Ideler (''Historische untersuchungen uber die astronomischen beobachtungen der alten'', Berlin 1806, page 417) a connu cette période chaldéenne, et que delà résulte l’étendue de six cents ans donnée à son calendrier selon Pline.<br /><p style="text-align: justify; text-indent: 15px;">[[w:Abel_Burja|Abel-Burja]] de Leipzig a tâché d’expliquer d’une autre manière la durée du calendrier d’Hipparque (''Astronomisches Jahrbuch'', 1797, pag. 233 et 234). [[w:Claude_Ptolémée|Ptolémée]] et [[w:Censorin_(grammairien)|Censorin]] racontent qu’Hipparque est auteur d’une période soli-lunaire de trois cent quatre années solaires. En la prenant deux fois, on obtient une période de six cent huit ans. Celle-ci fut abrégée par Hipparque de huit ans, afin d’obtenir un nombre entier de siècles pour son calendrier. Ideler a fait une objection très-juste contre cette opinion de Burja ; c’est que la période de six cent huit ans n’a aucun avantage sur celle de trois cent quatre ans. On ne voit donc pas ce qui a pu engager Hipparque à préférer le nombre de six cents ans à celui de trois cents, lorsqu’il composait son calendrier.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Menses_gentium_etc_AdG_back|<span id="Menses_gentium_etc_AdG"><sup>7</sup></span>]] C’est-à-dire il écrivit des éphémérides dans lesquelles il avait calculé d’avance les néomenies et les pleines lunes. Il fit aussi entrer dans son calendrier les longueurs des jours et des heures variables, [[w:ὧραι|ὧραι]] καιρικαι, ainsi que les aspects du ciel, ''visus populorum'', tels qu’ils eurent lieu chez les habitans de différentes contrées de la terre. Il ajouta une table des longitudes et des latitudes des principaux pays et villes du globe. Ptolémée (''Géogr.'', I, ch. 4) en dit autant d’Hipparque.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Aevo_teste_AdG_back|<span id="Aevo_teste_AdG"><sup>8</sup></span>]] Les tables d’Hipparque étaient dressées pour six cents ans. Cet astronome florissait vers cent cinquante ans avant J.-C. Ainsi, du temps de Pline, on avait encore à jouir de ces tables pour quatre cents ans environ. POINSINET.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Numinum_AdG_back|<span id="Numinum_AdG"><sup>9</sup></span>]] Pline donne souvent l’épithète de divinités aux planètes, à la lune, au soleil, à la terre et aux étoiles fixes.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#In_defectibus_scelera_etc_AdG_back|<span id="In_defectibus_scelera_etc_AdG"><sup>10</sup></span>]] Nous transcrivons ici ce beau passage de l’Uranographie de M. [[w:Louis-Benjamin_Francœur|Francoeur]], qui mérite d’être mis en parallèle avec celui de Pline pour l’élégance du style et les pensées, et qui renferme le meilleur commentaire que nous puissions donner de tout ce que Pline dit des terreurs que les éclipses causaient autrefois aux hommes ignorans. « L’histoire, dit M. Francoeur (page 93), est pleine des exemples de l’effroi causé par les éclipses, et des dangers que produisent l’ignorance et la superstition. Nicias avait résolu de quitter la Sicile avec son armée ; effrayé par une éclipse de lune, et voulant temporiser plusieurs jours pour s’assurer si l’astre n’avait rien perdu après cet évènenement, il manqua ainsi l’occasion de sa retraite; son armée fut détruite ; Nicias périt, et ce malheur commença la ruine d’Athènes.<br /><p style="text-align: justify; text-indent: 15px;">« Souvent on a vu des hommes adroits tirer parti de la frayeur du peuple pour l’amener à remplir leurs desseins. Christophe Colomb, réduit à faire subsister ses soldats des dons volontaires d’une nation sauvage et indigente, était prêt à voir tarir cette ressource et à périr de faim ; il annonce qu’il va priver le monde de la lumière de la lune. L’éclipse commence et la terreur s’empare des Indiens, qui reviennent apporter aux pieds de Colomb les tributs accoutumés.<br /><p style="text-align: justify; text-indent: 15px;">« Drusus (TACITE , Annales, I, 28) apaisa une sédition dans son armée, en prédisant une éclipse de lune, et, selon Tite-Live, Sulpicius Gallus, dans la guerre de Paul-Emile contre Persée, usa du même stratagème. Periclès, [[w:Agathocle_de_Syracuse|Agathocles de Syracuse]], [[w:Dion_de_Syracuse|Dion]], roi de Sicile, ont failli être victimes de l’ignorance de leurs soldats. [[w:Alexandre_le_Grand|Alexandre]], près d’[[w:Bataille_de_Gaugamèles|Arbelles]], est réduit à user de toute son adresse pour calmer la terreur qu’une éclipse avait jetée parmi ses troupes. Les hommes supérieurs, plutôt que de plier sous les circonstances qui les maîtrisent, mettent leur art à les tourner à leur profit.<br /><p style="text-align: justify; text-indent: 15px;">« Combien de fables établies d’après l’opinion que les éclipses sont l’effet du courroux céleste qui se venge des iniquités de l’homme en le privant de la lumière! Tantôt [[w:Diane_(mythologie)|Diane]] va trouver [[w:Endymion|Endymion]] dans les montagnes de Carie; tantôt les magiciennes de Thessalie font descendre la lune sur les herbes qu’elles destinent aux enchantemens. »<br /><br /><p style="text-align: center;">''Carmina vel cælo possunt deducere lunam.''<br /><p style="text-align: right; text-indent: 15px;">Virg., ''Eclog.'' VIII.<br /><br /><p style="text-align: justify; text-indent: 15px;">« Ici c’est un dragon qui dévore l’astre, et qu’on cherche à épouvanter par des cris ; le dieu tient le soleil enfermé dans un tuyau, et nous ôte ou nous rend la vue de cet astre à l’aide d’un volet, etc. Les progrès des sciences ont fait connaître le ridicule de ces opinions et de ces craintes, depuis qu’on a vu qu’il était possible de calculer par les tables astronomiques, et de prévoir long-temps d’avance l’instant où la colère du ciel devait éclater.<br /><p style="text-align: justify; text-indent: 15px;">« Cependant, naguère encore, l’épouvante a causé les revers des armées de Louis XIV, près de Barcelone, lors de l’éclipse totale de l’an 1706 [[w:en:Solar_eclipse_of_May_12,_1706|(en)]], et la devise, ''nec pluribus impar'', a prêté aux allusions injurieuses ! »''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Pindari_AdG_back|<span id="Pindari_AdG"><sup>11</sup></span>]] Pindare était le plus fameux poète de la Grèce après Homère. Il vint au monde l’an 134 avant l’ère chrétienne. POINSINET.<br /><p style="text-align: justify; text-indent: 15px;">Plutarque (''De la face de la lune'', pag. 931) dit aussi que Stésichore et Pindare craignaient beaucoup les éclipses. Le dernier poète a peint les terreurs que lui causaient ces phénomènes dans son poëme sur le soleil. HARDOUIN et DALECHAMP.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Crepitu_dissono_AdG_back|<span id="Crepitu_dissono_AdG"><sup>12</sup></span>]] Cet usage superstitieux dont Plutarque parle au long dans sa vie de Paul-Émile, a fourni un vers fort plaisant à Juvénal, lorsqu’après avoir épuisé toute sorte d’exagération pour représenter le bruit qu’une femme fait en criant, il finit par dire :<br /><br /><p style="text-align: center;">''Una laboranti poterit succurrere lunæ.''<br /><br /><p style="text-align: justify; text-indent: 15px;">« Elle seule, au besoin, décharmerait la lune. » POINSINET.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Nicias_AdG_back|<span id="Nicias_AdG"><sup>13</sup></span>]] Le même fait est raconté par Plutarque dans la vie de Nicias, par Quintilien, I, 10, et par d’autres écrivains anciens. HARDOUIN.''' </td> </tr> </table><br/><br/></div>{{Boîte déroulante fin}} <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k5773334c/f10.item <u>Histoire Naturelle de Pline. Tome Second</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k5773334c/f14.item ''Livre II.''], [https://gallica.bnf.fr/ark:/12148/bpt6k5773334c/f46.item ''chap. IX.''], traduction nouvelle par M. [[w:Stéphane_Ajasson_de_Grandsagne|Ajasson de Grandsagne]] [https://gallica.bnf.fr/ark:/12148/bpt6k5773334c/f311.item <sup>NOTES</sup>], C. L. F. Panckoucke, Paris, 1829</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: center; margin: 0 2em;">''Des inventions a[[w:S_long|{{Info|ſ|forme ancienne longue de la lettre s minuscule}}]]<nowiki />tronomiques, & de leurs Auteurs.''<br /><p style="text-align: justify; text-indent: 15px;">'''L'''E PREMIER d’entre les ''Romains'' qui rendit publique la théorie des éclip{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oleil & de lune, fut '''Sulpicius Gallus''' [[#Sulpicius_Gallus_LPdS|<span id="Sulpicius_Gallus_LPdS_back"><sup>'''1'''</sup></span>]], celui que '''Marcus Marcellus''' eut pour Collegue au Con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ulat : mais il n’étoit que Tribun Militaire [[#Tribun_Militaire_LPdS|<span id="Tribun_Militaire_LPdS_back"><sup>'''2'''</sup></span>]], lor{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’il di{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ipa l’allarme qu’auroient pu prendre nos troupes la veille de la victoire remportée {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur '''Per{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ée''' par '''Paul Emile''' ; car ce Général l’ayant produit devant les {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oldats a{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}emblés, il leur prédit une éclip{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e qui devoit arriver [[#éclipse_LPdS|<span id="éclipse_LPdS_back"><sup>'''3'''</sup></span>]] ; il compo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}a même en{{Info|ſ|forme ancienne longue de la lettre s minuscule}}uite un Ouvrage {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur ce {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ujet. Parmi les ''Grecs'', '''Thalès''' de ''Milet'' prédit l’an quatrieme de la quarante-huitieme olympiade l’éclip{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oleil qui arriva {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous le regne de '''Halyattes''' [[#Halyattes_LPdS|<span id="Halyattes_LPdS_back"><sup>'''4'''</sup></span>]], l’an cent {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oixante de la fondation de [[#cent_soixante_LPdS|<span id="cent_soixante_LPdS_back"><sup>'''5'''</sup></span>]] ''Rome''. Après eux, Hipparque [[#Hipparque_LPdS|<span id="Hipparque_LPdS_back"><sup>'''6'''</sup></span>]] dre{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}a des Tables en vers [[#En_vers_LPdS|<span id="En_vers_LPdS_back"><sup>'''7'''</sup></span>]] du cours de ces deux aftres pour fix cents ans. Dans ces Tables , de l’exactitude deſquelles notre âge rend encore témoignage [[#témoignage_LPdS|<span id="témoignage_LPdS_back"><sup>'''8'''</sup></span>]], il embra{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}e les éphémérides propres à chaque nation [[#chaque_nation_LPdS|<span id="chaque_nation_LPdS_back"><sup>'''9'''</sup></span>]], les jours, les heures, le {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ite re{{Info|ſ|forme ancienne longue de la lettre s minuscule}}pectif de chaque lieu, & les divers a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}pects du ciel relativement aux divers peuples, comme {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i la Nature l’eût admis à {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}eil intime. Per{{Info|ſ|forme ancienne longue de la lettre s minuscule}}onnages vraiment grands! génies plus qu’humains, d’avoir ain{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i {{Info|ſ|forme ancienne longue de la lettre s minuscule}}urpris les loix qui font mouvoir ces va{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tes pui{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ances du ciel ; & d’avoir guéri de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}es allarmes l’imagination malade des hommes, qui ju{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’alors, ou avoient toujours vu dans les éclip{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es l’annonce effrayante de quelque grand crime & de quelque mort (terreur dont Sté{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ikhore [[#Stésikhore_LPdS|<span id="Stésikhore_LPdS_back"><sup>'''10'''</sup></span>]] & Pindare [[#Pindare_LPdS|<span id="Pindare_LPdS_back"><sup>'''11'''</sup></span>]], ces Poètes {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ublimes, ne furent point exempts à l’égard des éclip{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es {{Info|ſ|forme ancienne longue de la lettre s minuscule}}olaires), ou attribuoient les ténebres dont {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e couvre la lune à des maléfices opérés par le mêlange de certaines herbes magiques ; & croyoient devoir la {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ecourir par un bruit di{{Info|ſ|forme ancienne longue de la lettre s minuscule}}cordant [[#bruit_discordant_LPdS|<span id="bruit_discordant_LPdS_back"><sup>'''12'''</sup></span>]]. Cette même terreur fut cau{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e que le Général Nicias [[#Nicias_LPdS|<span id="Nicias_LPdS_back"><sup>'''13'''</sup></span>]], peu au fait des cau{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es phy{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iques, & n’o{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ant pas, par {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uper{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tition, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ortir {{Info|ſ|forme ancienne longue de la lettre s minuscule}}a flotte du Port, mit Athenes à deux doigts de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}a perte. Honneur [[#Honneur_LPdS|<span id="Honneur_LPdS_back"><sup>'''14'''</sup></span>]] à vous, Interpretes du Ciel ! E{{Info|ſ|forme ancienne longue de la lettre s minuscule}}prits [[#Esprits_LPdS|<span id="Esprits_LPdS_back"><sup>'''15'''</sup></span>]] dont l’étendue {{Info|ſ|forme ancienne longue de la lettre s minuscule}}urpa{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}e celle de la Nature ; Inventeurs d’une méthode qui a{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ujettit les dieux comme les hommes, à une même de{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tinée ! Eh! qui pourroit, en voyant les a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tres même ''en cri{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e'' (pour me {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ervir de l’expre{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ion commune), ne pas {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oumettre à la néce{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ité où {{Info|ſ|forme ancienne longue de la lettre s minuscule}}a condition mortelle l’enchaîne.<br /><p style="text-align: justify; text-indent: 15px;">Pré{{Info|ſ|forme ancienne longue de la lettre s minuscule}}entement je vais toucher par articles fort courts & fort précis les points {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur le{{Info|ſ|forme ancienne longue de la lettre s minuscule}}quels on s’accorde le plus. Je ré{{Info|ſ|forme ancienne longue de la lettre s minuscule}}oudrai, chemin fai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ant, quelques que{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tions, lor{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que le cas l’exigera, mais toujours d’une maniere très {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ommaire ; car une analy{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e en forme d’arguments {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uivis excéderoit le but de cet Ouvrage : & puis, je pen{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e qu’il n’y a pas moins de mérite à rendre une rai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}on plau{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ible de toutes cho{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es, qu’à rendre une rai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}on bien {{Info|ſ|forme ancienne longue de la lettre s minuscule}}olide de deux ou trois cho{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eulement.</div> {{Boîte déroulante début|titre=Notes du traducteur|alignT=center}} <div style="text-align: justify; border: 2px; border-radius:15px; font-size:85%;"><br/> <table cellspacing=15 align=center style="margin: 0 4em;"> <tr> <td style="text-align: justify; margin: 0 4em; text-indent: 15px">'''[[#Sulpicius_Gallus_LPdS_back|<span id="Sulpicius_Gallus_LPdS"><sup>1</sup></span>]] Son premier prénom étoit Caïus. Voyez à {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ujet Tite-Live, l. 44. Valere maxime, l. 8. Quintilien, l. I. ch. 10. Plutarque, vie de Paul-Emile, &c.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Tribun_Militaire_LPdS_back|<span id="Tribun_Militaire_LPdS"><sup>2</sup></span>]] Ce grade répond à celui de Major-général des Troupes.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#éclipse_LPdS_back|<span id="éclipse_LPdS"><sup>3</sup></span>]] Cette éclip{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}elon Tite-Live, fut annoncée aux {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oldats pour la nuit {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uivante. Sulpicius Gallus leur prédit que la lune s’éclip{{Info|ſ|forme ancienne longue de la lettre s minuscule}}eroit entre la {{Info|ſ|forme ancienne longue de la lettre s minuscule}}econde heure de la nuit & la quatrieme. Plutarque ajoute qu’on étoit alors à l’i{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ue de l’été (''{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ub exitum a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tatis''). [[w:Paulin_II_d'Aquilée|Paul d’Aquilée]] écrit que cette éclip{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e arriva aux nones de Septembre (''nonas Septembris''), c’est-à-dire au 4 Septembre : c’étoit l’an 168 avant J.C. {{Info|ſ|forme ancienne longue de la lettre s minuscule}}elon le calcul d’[[w:James_Ussher|U{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}erius]].''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Halyattes_LPdS_back|<span id="Halyattes_LPdS"><sup>4</sup></span>]] Il paroît que Ciceron & Eu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ebe {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e trompent lor{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’ils placent cet événement {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous ''A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tiages'' : [[w:Hermolaos_(Macédoine)|Hermolaüs]] s’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t trompé d’après eux, en {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ub{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tituant ''A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tiages'' à ''Halyattes'' dans le texte de Pline, contre la foi des manu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}crits, & contre le témoignage d’Herodote qui place cet événement dans une guerre entre Halyattes, Roi de Sardes, & Cyaxare, Roi des Medes, pere d’A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tiages.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#cent_soixante_LPdS_back|<span id="cent_soixante_LPdS"><sup>5</sup></span>]] Les deux manu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}crits royaux portent ''anno CLX'' : c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t la leçon qu’il faut {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uivre. En effet, Rome, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}elon Varron, fut fondée l’an 2 de la {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ixieme olympiade, c’est-à-dire, dans l’année olympiadique 22. Mais comme chaque olympiade, depuis leur premiere in{{Info|ſ|forme ancienne longue de la lettre s minuscule}}titution, commençoit après le {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ol{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tice d’été, & comme l’année Romaine avoit toujours commencé au plus tard en Mars {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous Romulus, & depuis en Janvier {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous Numa, il s’en{{Info|ſ|forme ancienne longue de la lettre s minuscule}}uit que la premiere année de Rome, qui répondoit à l’année olympiadique 22, répondoit en même-tems, de quatre mois au moins, à l’année olympíadique 23. Selon ce calcul, la quatrieme année de la quarante-huitieme olympiade, répond en partie à l’an 160, & en partie à l’an 161 de la fondation de Rome, pui{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que 48 olympiades font cent quatre-vingt-douze années, de{{Info|ſ|forme ancienne longue de la lettre s minuscule}}quelles {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i vous ôtez 22 ans écoulés, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}elon Varron, entre la premiere olympiade & la fondation de Rome, il re{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tera 160 ans, & 161 ans {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i l’on a égard à l’enjambement réciproque des années olympiadiques {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur les années Romaines, & des années Romaines {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur les années olympiadiques. Il e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t donc évident que le calcul de Pline (''anno CLX'') e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t ju{{Info|ſ|forme ancienne longue de la lettre s minuscule}}te, en admettant l’hypothe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e chronologique de Varron, à laquelle on voit bien que notre Auteur s’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t conformé en cette occa{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ion particuliere encore qu’en plu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ieurs autres rencontres il paroi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}e affecter de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uivre le {{Info|ſ|forme ancienne longue de la lettre s minuscule}}y{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tême de Caton : vici{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}itude pardonnable dans un ouvrage de compilation où Pline a dû, comme malgré lui, adopter tantôt le {{Info|ſ|forme ancienne longue de la lettre s minuscule}}tyle d’un Auteur, tantôt celui d’un autre, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}elon la {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ource où il pui{{Info|ſ|forme ancienne longue de la lettre s minuscule}}oit pour l’heure. Si Pline eût {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uivi l’hypothe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e de Caton qui place la fondation de Rome deux ans plus tard que Varron, il eût fait tomber le rapport {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur l’année 157 ou 158 de la fondation de Rome. C’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t le parti que prend le Pere Hardouin, & c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t de là qu’il part pour propo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}er une correction dans le texte. Mais encore une fois, c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t commettre {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oi-même une faute que d’en trouver une chez Pline en cette occa{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ion ; pui{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que cet Auteur a été en droit de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ervir du {{Info|ſ|forme ancienne longue de la lettre s minuscule}}y{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tème Varronien, ou ce qui revient au même, de con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}erver la date Varronienne dont s’étoit {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ervi l’Auteur de qui il emprunte le fait hi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}torique en que{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tion.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Hipparque_LPdS_back|<span id="Hipparque_LPdS"><sup>6</sup></span>]] Voyez les notes {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur le premier livre au mot ''Hipparque'' : HIPPARCHUS (de Nicée, en Bithinie comme l’ob{{Info|ſ|forme ancienne longue de la lettre s minuscule}}erve [[w:Souda|Suidas]]), flori{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}oit dans la quatre-vingt-quatorzieme olympiade. Nous avons {{Info|ſ|forme ancienne longue de la lettre s minuscule}}es trois livres d’Enarrations {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur les Phénomenes d’[[w:Aratos_de_Soles|Aratus]] & d’[[w:Eudoxe_de_Cnide|Eudoxe]], traduits par le [[w:Paul_Petau|P. Petau]]. Il avoit compo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}é un autre livre ''De {{Info|ſ|forme ancienne longue de la lettre s minuscule}}tellarum inerrantium Con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}titutione'', {{Info|ſ|forme ancienne longue de la lettre s minuscule}}elon Suidas. Son livre du mois lunaire e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t cité par [[w:Claude_Galien|Galien]].''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#En_vers_LPdS_back|<span id="En_vers_LPdS"><sup>7</sup></span>]] ''En Vers.'' Je préfume que c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t-là le {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ens de ''præcinere'', qui ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ignifie pas {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eulement prédire, mais prédire en chant, c’est-à-dire en Vers. Sur ce pied-là, ce {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eroit d’un Poëme dans le genre de celui d’[[w:Aratos_de_Soles|Aratus]], dont il {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eroit ici que{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tion. Si par hazard Pline n’a point prétendu parler d’un Poëme, au-moins s’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t-il {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ervi d’une expre{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ion propre à dé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}igner ce genre d’écrire. Pour décider la que{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tion, il faudroit avoir tous les ouvrages d’Hipparque, & {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur-tout celui-ci.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#témoignage_LPdS_back|<span id="témoignage_LPdS"><sup>8</sup></span>]] Ces tables étoient dre{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ées pour {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ix cents ans. Or Hipparque flori{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}oit 150 ans avant J.C. Ain{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i du tems de Pline, on avoit encore à jouir de ces tables pour quatre cents ans ou environ.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#chaque_nation_LPdS_back|<span id="chaque_nation_LPdS"><sup>9</sup></span>]] La lune ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e levant pas & ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e couchant pas à la même heure pour toutes les nations, les diver{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es époques & pha{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es qu’elle forme n’appartiennent pas non plus au même point de tems pour tous les peuples, pui{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que les uns ont la nuit quand les autres ont le jour; & que même lor{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que la lune s’éclip{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e, la partie de l’heure où ce phénomene e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t {{Info|ſ|forme ancienne longue de la lettre s minuscule}}en{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ible, n’a pas la même évaluation pour tous les climats qui l’apperçoivent. Hipparque avoit donc eu égard à cette différence d’époques, relativement aux diver{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es longitudes, &par-con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}équent aux diver{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es nations, tellement que les tables de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}es éphémérides étoient accommodées à l’u{{Info|ſ|forme ancienne longue de la lettre s minuscule}}age de tous les peuples : ouvrage dont on ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}auroit trop regretter la perte, & qui jetteroit le plus grand jour {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur l’ancienne géographie.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Stésikhore_LPdS_back|<span id="Stésikhore_LPdS"><sup>10</sup></span>]] Ste{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ikhore, l’un des plus fameux Poètes de la Grece, dont, par malheur, nous avons perdu tous les ouvrages, à l’exception d’une vingtaine de lignes décou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ues. Il vivoit dans la quarante-deuxieme olympiade, c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t-à-dire, vers l’an {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ix cents dix avant J.C.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Pindare_LPdS_back|<span id="Pindare_LPdS"><sup>11</sup></span>]] Pindare, le plus fameux Poète de la Grece après Homere. Il vint au monde l’an 134 avant l’ere chrétienne.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#bruit_discordant_LPdS_back|<span id="bruit_discordant_LPdS"><sup>12</sup></span>]] Cet u{{Info|ſ|forme ancienne longue de la lettre s minuscule}}age {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uper{{Info|ſ|forme ancienne longue de la lettre s minuscule}}titieux a fourni un Vers fort plai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ant à Juvenal, lor{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’après avoir épui{{Info|ſ|forme ancienne longue de la lettre s minuscule}}é toute {{Info|ſ|forme ancienne longue de la lettre s minuscule}}orte d’exagération pour repré{{Info|ſ|forme ancienne longue de la lettre s minuscule}}enter le bruit qu’une femme fait en criant, il finit par dire :<br /><p style="text-align: justify; text-indent: 15px;">''Una laboranti poterit {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uccurrere luna.''<br /><p style="text-align: justify; text-indent: 15px;">Elle {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eule au be{{Info|ſ|forme ancienne longue de la lettre s minuscule}}oin décharmeroit la lune.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Nicias_LPdS_back|<span id="Nicias_LPdS"><sup>13</sup></span>]] C’étoit un Général Athénien, qui fut malheureux dans pre{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que toutes {{Info|ſ|forme ancienne longue de la lettre s minuscule}}es expéditions. Les Athéniens finirent par le condamner à mort. Il étoit contemporain d’[[w:Alcibiade|Alcibiade]] & de [[w:Lamachos|Lamachus]], & leur collegue dans le commandement. Voyez {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur le fait dont parle ici Pline, Quintilien, l. I. ch. 10, & Plutarque à l’article Nicias.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Honneur_LPdS_back|<span id="Honneur_LPdS"><sup>14</sup></span>]] Au lieu de ''macte ingenio'', le Pere Hardouin lit ''macti'' ; mais {{Info|ſ|forme ancienne longue de la lettre s minuscule}}elon les meilleurs Latini{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tes ''macte'' e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t indéclinable, ou pour mieux dire, c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t un adverbe qui répond au ''bravò'' des Italiens. Fe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tus prétend que ''macte'' e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t un compo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}é de ''magis auctus''.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Esprits_LPdS_back|<span id="Esprits_LPdS"><sup>15</sup></span>]] Cette apo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}trophe de Pline aux A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tronomes rappelle ces beaux Vers d'Ovide {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur le même {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ujet :<br />Felices animos quibus hæc cogno{{Info|ſ|forme ancienne longue de la lettre s minuscule}}cere primise<br /><p style="text-align: justify; text-indent: 15px;">Inque Domos {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uperas {{Info|ſ|forme ancienne longue de la lettre s minuscule}}candere cura fuit!<br />Credibile e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t illos pariter vitli{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que joci{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que<br /><p style="text-align: justify; text-indent: 15px;">Altius humanis ex{{Info|ſ|forme ancienne longue de la lettre s minuscule}}eruifle caput,<br />Non Venus aut Vinum {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ublimia pectora fregit<br /><p style="text-align: justify; text-indent: 15px;">Officiumve {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ori, militiæve labor :<br />Nec levis ambitio, perfu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}aque gloria fuco,<br /><p style="text-align: justify; text-indent: 15px;">Magnarumve fames {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ollicitavit opum.<br />Admovere oculis di{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tantia {{Info|ſ|forme ancienne longue de la lettre s minuscule}}idera no{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tris,<br /><p style="text-align: justify; text-indent: 15px;">Ætheraque ingenio {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uppo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}uere {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uo.<br />Sic petitur cœlum: non ut ferat O{{Info|ſ|forme ancienne longue de la lettre s minuscule}}lan Olympus<br /><p style="text-align: justify; text-indent: 15px;">Summaque Peliacus {{Info|ſ|forme ancienne longue de la lettre s minuscule}}idera tangat apex, &c.<br /><p style="text-align: right; text-indent: 15px;">Ovid. {{Info|ſ|forme ancienne longue de la lettre s minuscule}}a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t. l. I.''' </td> </tr> </table><br/><br/></div> {{Boîte déroulante fin}} <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=UnhluychtF8C&newbks=1&newbks_redir=0&dq=Histoire%20naturelle%20Pline&hl=fr&pg=PP7#v=onepage&q&f=true <u>Histoire Naturelle de Pline. Tome Premier</u>], [https://books.google.fr/books?id=UnhluychtF8C&newbks=1&newbks_redir=0&dq=Histoire%20naturelle%20Pline&hl=fr&pg=RA1-PA3#v=onepage&q&f=true ''Livre Second.''], [https://books.google.fr/books?id=UnhluychtF8C&newbks=1&newbks_redir=0&dq=Histoire%20naturelle%20Pline&hl=fr&pg=RA1-PA59#v=onepage&q&f=true ''Des inventions astronomiques, & de leurs Auteurs.''], traduction en françois, avec le texte latin rétabli d’après les meilleures leçons manu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}crites ; accompagnée de Notes critiques pour l’éclairci{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ement du texte, & d’Ob{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ervations {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur les connoi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ances des Anciens comparées avec les découvertes des Modernes, par M. [[w:Louis_Poinsinet_de_Sivry|Louis Poinsinet de Sivry]], Chez la veuve Desaint, Paris, 1771</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div> </div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ==== Livre XVIII ==== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Enquête sur l’agriculture</div> ===== <div style="text-align: center;">Chapitre LVII.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage d’une théorie astronomique de '''Thalès''', du [[w:Lever_héliaque|''coucher matinal'']] des [[w:Pléiades_(astronomie)|''Pléiades'']] 25 jours après l’[[w:Équinoxe_de_septembre|''équinoxe d’automne'']].</div> :'''Texte latin''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''LVII.''' Primum omnium dierum ipsorum anni solisque motus prope inexplicabilis ratio est. Ad CCCLXV adjiciunt etiamnum intercalarios diei noctisque quadrantes. Ita fit, ut tradi non possint certa siderum tempora. Accedit confessa rerum obscuritas, nunc præcurrenle, nec paucis diebus, tempestatum significatu, quod προϰειμασιν Græci vocant : nunc postveniente, quod ἐπιϰεἰμασιν : et plerumque alias citius, alias tardius cæli effectu ad terram deciduo : vulgo serenitate reddita, confectum sidus audimus. Præterea quum omnia hæc statis sideribus cæloque affixis constent, interveniunt motu stellarum grandines, imbres, et ipsi non levi effectu, ut docuimus, turbantque conceptæ spei ordinem. ldque ne nobis tantum putemus accidere, et reliqua fallit animalia sagaciora circa hoc, ut quo vita eorum constet : æstivasque alites præposteri aut præproperi rigores necant, hibernas æstus. Ideo '''Virgilius''' errantium quoque siderum rationem ediscendam præcipit, admonens observandum frigidæ Saturni stellæ transitum. Sunt qui certissimum veris indicium arbitrentur ob infirmitatem animalis, papilionis proventum. Id eo ipso anno, quum commentaremur hæc, notatum est, proventum eorum ter repetito frigore exstinctum, advenasque volucres a. d. VI kalendas februarii spem veris attulisse, mox sævissima hieme conflictatas. Res anceps : primum omnium a cælo peti legem : deinde eam argumentis esse quærendam. Super omnia est mundi convexitas, terrarumque globi differentia, eodem sidere alio tempore aliis aperiente se gentibus : quo fit ut causa ejus non lisdem diebus ubique valeat. Addidere difficultatem et auclores diversis in locis observando, mox etiam in iisdem diversa prodendo. Très autem fuere sectæ : ''Chaldæa'', ''Ægyptia'', ''Græca''. His addidit apud nos quartam Cæsar dictator, annos ad solis cursum redigens singulos, '''Sosigene''' perito scientiæ ejus adhibito. Et ea ipsa ratio postea comperto errore correcta est : ita ut XII annis continuis non intercalaretur, quia cœperat sidera annus morari, qui prius antecedebat. Et '''Sosigenes''' ipse trinis commentationibus, quanquam diligentior cæteris, non cessavit tamen addubitare, ipse semet corrigendo. Auctores prodidere ea, quos prætexuimus volumini huic, raro ullius sententia cum alio congruente. Minus hoc in reliquis mirum, quos diversi excusaverint tractus. Eorum qui in eadem regione dissedere, unam discordiam ponemus exempli gratia : occasum matutinum Vergiliarum '''Hesiodus''' (nam hujus quoque nomine exstat Astrologia) tradidit fieri, quum æquinoctium autumni conficeretur, '''Thales''' vigesimo quinto die ab æquinoctio, '''Anaximander''' vigesimo nono, '''Euctemon''' XLVIII. Nos sequemur observationem Cæsaris : maximeque hæc erit ''Italiæ'' ratio. Dicemus tamen et aliorum placita : quoniam non unius terræ, sed totius naturæ interpretes sumus, non auctoribus positis (id enim verbosum est), sed regionibus : legentes tantum meminerint, brevitatis gratia, quum ''Altica'' nominata fuerit, simul intelligere ''Cycladas'' insulas ; quum ''Macedonia'', ''Magnesiam'', ''Thraciam'' ; quum ''Ægyptus'', ''Phœnicen'', ''Cyprum'', ''Ciliciam'' ; quum ''Bœotia'', ''Locridem'', ''Phocidem'', et finitimos semper tractus ; quum ''Hellespontus'', ''Cherronesum'', et continentia usque ''Atho'' montem ; quum ''Ionia'', ''Asiam'', et insulas ''Asiæ'' ; quum ''Peloponnesus'', ''Achaiam'', et ad ''Hesperum'' jacentes terras. ''Chaldæi Assyriam'' et ''Babyloniam'' demonstrabunt. ''Africam'', ''Hispanias'', ''Gallias'' sileri non erit mirum. Nemo enim observavit in iis, qui siderum proderet exortus. Non tamen difficili ratione dignoscentur in illis quoque terris digestione circulorum, quam in sexto volumine fecimus : qua cognatio cæli, non gentium modo, verum urbium quoque singularum intelligitur, nota ex his terris, quas nominavimus, sumta convexitate circuli, pertinentis ad quas quisque quæret terras, et ad earum siderum exortus, per omnium circulorum pares umbras. Indicandum et illud, tempestates ipsas ardores suos habere quadrinis annis : et easdem non magna differentia reverti ratione solis : octonis vero augeri easdem, centesima revolvente se luna.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/b24875958_0001/page/n7/mode/2up <u>Histoire Naturelle de Pline.</u>], [https://archive.org/details/b24875958_0001/page/652/mode/2up ''Livre XVIII.''], [https://archive.org/details/b24875958_0001/page/684/mode/2up ''Chap. LVII.''], texte corrigé par [[w:Émile_Littré|M. É. Littré]], à partir de celui de [[w:Jean_Hardouin|Hardouin]], Librairie de Firmin-Didot et C<sup>ie</sup>, Paris, 1883<br />(également disponible une édition de 1831 [https://gallica.bnf.fr/ark:/12148/bpt6k5804072n/f339.item ici] et de 1848 [[s:Page:Pline_l'ancien_-_Histoire_naturelle,_Littré,_T1_-_1848.djvu/708|là]])</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''LVII.''' Avant tout, le calcul des jours même de l’année et du mouvement solaire est d’une difficulté presque insurmontable. Aux trois cent soixante-cinq jours on ajoute des jours intercalaires, produits de quarts de jour et de nuit ; de là vient qu’on ne peut indiquer des époques fixes pour les astres. Ajoutez une obscurité des choses avouée de tous : tantôt en effet la mauvaise saison, s’annonçant, anticipe même de plusieurs jours, ce que les Grecs appellent προϰεἰμασις (avant-hiver), et la belle saison retarde, ce qui est nommé ἐπιϰεἰμασις (arriere-hiver) : l’effet du ciel tombe sur la terre tantôt plus vite, tantôt plus tardivement ; et d’ordinaire c’est quand la sérénité est rétablie que nous entendons dire que l’action de l’astre est accomplie. En outre, car tous ces phénomènes dépendent d’astres réglés et fixés au ciel, le mouvement des étoiles amène intercurremment des grêles, des pluies qui ne sont pas non plus d’une faible action, comme nous l’avons enseigné (XVII, 2), et qui troublent l’ordre espéré. Et ne pensons pas que ces méprises n’arrivent qu’à nous; les autres animaux s’y trompent, bien que plus sagaces que nous sur ce point, vu que leur vie en dépend : l’on voit les oiseaux d’été tués par des froids hâtifs ou tardifs, et les oiseaux d’hiver par des chaleurs hâtives ou tardives. Aussi [[w:Virgile|'''Virgile''']] [[#Virgile|<span id="Virgile_back"><sup>'''I'''</sup></span>]] ([[w:Géorgiques|''Georg.'']], I, 335) recommande-t-il d’étudier encore le cours des astres errants, avertissant d’observer le passage de Saturne, planète froide. Il en est qui regardent comme l’indice le plus sûr du printemps l’apparition des papillons, à cause de la délicatesse de cet insecte. Or, l’année même où nous écrivions ceci (an 830 de ''Rome''), il a été noté que les papillons, ayant éclos, furent détruits à trois reprises par le froid, et que les oiseaux étrangers, ayant apporté l’espérance du printemps avant le 6 des calendes de février (27 janvier), eurent bientôt après à essuyer un hiver très-rigoureux. La double difficulté est d’abord d’avoir à demander au ciel la règle de toute chose, puis d’être obligé de contrôler cette règle par des faits apparents. Avant tout signalons la convexité du monde et les différences du globe terrestre, qui font que le même astre se montre à des temps divers suivant les nations, de sorte que l’influence ne s’en fait pas sentir partout aux mêmes jours. La difficulté a été encore accrue par les auteurs qui ont observé en des lieux différents, ou même qui, ayant observé dans les mêmes lieux, ont publié des résultats divergents. Il y a eu trois écoles, la ''Chaldéenne'', l’Égyptienne, la ''Grecque''. Une quatrième a été formée chez nous par le dictateur [[w:Jules_César|'''César''']], qui ramena l’année à la révolution solaire avec l’aide de [[w:Sosigène_d'Alexandrie|'''Sosigène''']] [[#Sosigène|<span id="Sosigène_back"><sup>'''II'''</sup></span>]], astronome habile. Et ce calcul même, où l’on découvrit une erreur, a été corrigé : pendant douze années consécutives on ne fit pas d’intercalation, attendu que l’année, qui auparavant anticipait, maintenant retardait sur les astres. '''Sosigène''' lui-même, quoique plus exact que les autres, n’a pas cessé, dans trois mémoires, de témoigner de ses doutes en se corrigeant lui-même. Les auteurs que nous avons indiqués au commencement de ce livre [[#auteurs_JH|<span id="auteurs_JH_back"><sup>'''1'''</sup></span>]] ont révélé ces discordances, l’avis de l’un s’accordant rarement avec l’avis de l’autre. Cela est moins étonnant dans ceux qui s’excuseront par la différence des lieux. Parmi ceux qui dans le même pays sont en désaccord, nous choisirons un exemple de dissidence : [[w:Hésiode|'''Hésiode''']] [[#Hésiode|<span id="Hésiode_back"><sup>'''III'''</sup></span>]] (car nous avons aussi sous son nom un livre sur les astres) a rapporté que le [[w:Lever_héliaque|''coucher matinal'']] des [[w:Pléiades_(astronomie)|''Pléiades'']] se faisait au moment de l’[[w:Équinoxe_de_septembre|''équinoxe d’automne'']] ; '''Thalès''', qu’il se faisait vingt-cinq jours après cet équinoxe; [[w:Anaximandre|'''Anaximandre''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Anaximandre_back|<sup>🔄</sup>]], vingt-neuf; [[w:Euctémon|'''Euctémon''']] [[#Euctémon|<span id="Euctémon_back"><sup>'''IV'''</sup></span>]], quarante-huit. Quant à nous, nous suivrons les calculs de '''César''' : ils se rapportent spécialement à l’Italie. Toutefois, nous relaterons aussi les opinions des autres ; car nous sommes les interprètes, non d’un seul pays, mais de la nature entière. Nous nommerons, non pas les auteurs, ce qui serait trop long, mais les pays. Les lecteurs auront seulement à se souvenir que, pour abréger, sous le nom d’[[w:Attique|''Attique'']] nous entendons aussi les [[w:Cyclades|''Cyclades'']]; sous celui de [[w:Macédoine_(province_romaine)|''Macédoine'']], la [[w:Magnésie_antique|''Magnésie'']] et la [[w:Thrace_(province_romaine)|''Thrace'']]; sous celui d’[[w:Égypte_romaine_et_byzantine|''Égypte'']], la [[w:Syrie-Phénicie_(province_romaine)|''Phénicie'']], [[w:Chypre_(province_romaine)|''Chypre'']] et la [[w:Cilicie|''Cilicie'']]; sous celui de [[w:Béotie#Antiquité|''Béotie'']], la [[w:Locride_(Grèce)|''Locride'']], la [[w:Phocide#Antiquité_et_période_byzantine|''Phocide'']] et les contrées limitrophes ; sous celui d’[[w:Hellespontique|''Hellespont'']], la [[w:Chersonèse_(cité_grecque)|''Chersonèse'']] et le continent jusqu’au [[w:Mont_Athos|''mont Athos'']]; sous celui d’[[w:Ionie|''Ionie'']], l’Asie et les îles ''Asiatiques'' ; sous celui de [[w:Péloponnèse#Antiquité|''Péloponnèse'']], l’[[w:Achaïe|''Achaïe'']] et les terres situées à l’occident; la [[w:Chaldée|''Chaldée'']] indiquera la [[w:Histoire_de_la_Syrie#Antiquité|''Syrie'']] et la [[w:Babylone_(civilisation)|''Babylonie'']]. On ne s’étonnera pas que je passe sous silence l’[[w:Afrique_romaine|''Afrique'']], l’[[w:Hispanie_romaine|''Espagne'']] et les [[w:Gaule|''Gaules'']], car personne dans ces contrées n’a laissé d’observations sur le lever des astres. Toutefois, il ne sera pas difficile de le calculer, même dans ces contrées, en étudiant la disposition des cercles que nous avons présentés dans le sixième livre (VI, 39). Grâce à cette étude, on connaît les relations astronomiques nou-seulement des nations, mais encore des villes en particulier : étant donnés les cercles déterminés par l’égalité des ombres, on choisit, dans les terres que nous avons nommées, le cercle qui a rapport à la localité objet du problème, et qui détermine en même temps le lever des astres pour cette localité. Il faut encore remarquer (II, 48) que tous les quatre ans les saisons ont leurs excès, et qu’elles reviennent les mêmes sans grande différence, en raison du soleil ; mais que tous les huit ans elles ont un redoublement, à la révolution de la centième lune.</div> <table cellspacing=15 align=center style="margin: 0 4em; font-size:85%;"> <tr> <td style="text-align: justify; margin: 0 4em;">'''[[#auteurs_JH_back|<span id="auteurs_JH"><sup>1</sup></span>]] Ce passage porte à croire que les auteurs dont Pline s’était servi pour composer chacun des livres de son ouvrage avaient été placés en tête du livre auquel ils se rapportaient. Les éditions mettent cette liste d’auteurs à la suite de la table de chaque livre, dans la table générale dressée par Pline lui-même.'''</td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/b24875958_0001/page/n7/mode/2up <u>Histoire Naturelle de Pline.</u>], [https://archive.org/details/b24875958_0001/page/652/mode/2up ''Livre XVIII.''], [https://archive.org/details/b24875958_0001/page/684/mode/2up ''Chap. LVII.''], texte corrigé par [[w:Émile_Littré|M. É. Littré]], à partir de celui de [[w:Jean_Hardouin|Hardouin]] [https://archive.org/details/b24875958_0001/page/708/mode/2up <sup>NOTES</sup>], Librairie de Firmin-Didot et C<sup>ie</sup>, Paris, 1883<br />(également disponible une édition 1848 [[s:Page:Pline_l'ancien_-_Histoire_naturelle,_Littré,_T1_-_1848.djvu/708|ici]])</div> {{Boîte déroulante début|titre=NdA de trad. Jean Hardouin 1883|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Virgile_back|<span id="Virgile"><sup>I</sup></span>]] [[w:Nom_romain|Tria Nomina]] en latin {{Info|Publius|praenomen, nom individuel du citoyen romain}} {{Info|Vergilius|nomen, nom de famille}} {{Info|Maro|cognomen, surnom héréditaire, servant à distinguer les diverses branches d’une même gens}};<br /><p style="margin: 0 2em; text-indent: 15px">Poète latin renommé dans les styles [[w:Épopée|''épique'']] (l’[[w:Énéide|''Énéide'']]), [[w:Poésie_pastorale|''pastorale'']] (les [[w:Bucoliques|''Bucoliques'']]) et [[w:Poésie_didactique|''didactique'']] (les [[w:Géorgiques|''Géorgiques'']]).<br /><p style="text-align: right; margin: 0 2em;">(15 octobre [[w:Années_70_av._J.-C.|-70]], [[w:Virgilio_(Lombardie)#Histoire|''Andes'']], au sud-est de l’actuelle [[w:Lombardie#Histoire|''Lombardie'']], au nord de l’Italie — 21 septembre [[w:Années_19_av._J.-C.|-19]], [[w:Brindisi#Histoire|''Brundisium'']], au sud-est des actuelles [[w:Pouilles#Domination_romaine|''Pouilles'']], au sud-est de l’Italie)<sup>[[w:Ier_siècle_av._J.-C.|⏳]]</sup> <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Sosigène_back|<span id="Sosigène"><sup>II</sup></span>]] Du nom propre grec ancien Σωσῐγένης / Sōsigénēs [[wikt:en:Σωσιγένης#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;">➥ du verbe σῴζω / sṓizō, « 1. Sauver : • Guérir ; • (rare chez Homère) Garder en sécurité, préserver ; • Garder, observer, maintenir ; • (généralement au milieu) Garder à l’esprit, se souvenir ; • Conduire en toute sécurité (à) ; • Secourir ; • Conserver pour. »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ + du nom commun‎ γένος / génos [[wikt:en:γένος#Ancient_Greek|(en)]], « 1. Race, souche, parenté : Descendance directe, par opposition à une relation collatérale. 2. Progéniture, descendant : (collectif) progéniture, postérité. 3. (en général) Race d’êtres : • Famille, clan, maison ; • Tribu, nation, race, en tant que subdivision de ἔθνος / éthnos [[wikt:en:ἔθνος#Ancient_Greek|(en)]] ; • Caste ; • Race d’animaux. 4. Âge, génération, période de la vie. 5. Sexe, genre : (grammaire) Genre grammatical. 6. Classe, sorte, genre : • (logique) L’opposé de εἶδος / eîdos [[wikt:en:εἶδος#Ancient_Greek|(en)]] ; • (taxonomie) Classe : • (taxonomie) Genre ; • Espèce de plante ; culture, produit ; matériau ; • Élément. »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ +‎ du suffixe nominal propre -ης / -ēs [[wikt:en:-ης#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;"> Astronome grec, connu pour avoir participer à la conception du [[w:Calendrier_julien|''calendrier julien'']] (instauré par Jules César en [[w:Années_46_av._J.-C.|-46]]/[[w:Années_45_av._J.-C.|-45]], lorsqu’il était [[w:Pontifex_maximus|''pontifex maximus'']]), avec une année commune de 365 jours divisée en 12 mois, et un jour intercalaire ajouté tous les 4 ans, lors des années bissextiles.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:Ier_siècle_av._J.-C.|I<sup>er</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]]) <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Hésiode_back|<span id="Hésiode"><sup>III</sup></span>]] Du nom propre grec ancien Ἡσῐ́οδος / Hēsíodos;<br /><p style="margin: 0 2em; text-indent: 15px">Poète ''grec'', renommé pour 2 ouvrages :<br /><p style="margin: 0 2em; text-indent: 15px;">• [[w:Théogonie_(Hésiode)|''la Théogonie'']], une généalogie des dieux (dans laquelle il présente la multitude des dieux célébrés par les mythes grecs où trois générations divines se succèdent : celle d’Ouranos, celle de Cronos, celle de Zeus qui sort triomphant) et une cosmogonie (qui retrace la création du monde à partir du Chaos) ;<br /><p style="margin: 0 2em; text-indent: 15px;">• et [[w:Les_Travaux_et_les_Jours|''les Travaux et les Jours'']], un almanac sur l’agriculture à destination de son frère Perses.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:VIIIe_siècle_av._J.-C.|VIII<sup>ème</sup>]] — [[w:VIIe_siècle_av._J.-C.|VII<sup>ème</sup>]] siècles {{Info|AEC|Avant l’Ère Commune}}) <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Euctémon_back|<span id="Euctémon"><sup>IV</sup></span>]] Du nom propre grec ancien Ευκτήμων / Euktémōn;<br /><p style="margin: 0 2em; text-indent: 15px;">Astronome ''athénien'', contemporain et collègue de l’astronome [[w:Méton|Méton]], avec qui, il a fait une série d’observations des [[w:Solstice|''solstices'']] afin de déterminer la durée de l’[[w:Année_tropique|''année tropique'']] [https://ecliptiqc.ca/Almageste_Livre3.php#III1 <sup>Ptolémée, Almageste, liv. III, chap. 1</sup>].<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:Ve_siècle_av._J.-C.|V<sup>ème</sup>]] siècle {{Info|AEC|Avant l’Ère Commune}})'''<br/><br/></div> {{Boîte déroulante fin}} <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: center; margin: 0 2em;">Des découvertes astronomiques : part de chaque observateur dans la science.<br /><p style="text-align: justify; text-indent: 15px;">'''LVII.''' D’abord, il est presque impossible de déterminer d’une manière précise le nombre des jours de l’année et le cours du soleil [[#Primum_omnium_dierum_AdG|<span id="Primum_omnium_dierum_AdG_back"><sup>'''1'''</sup></span>]]. Aux trois cent soixante-cinq jours qui composent l’année, on ajoute le quart d’un jour et d’une nuit, pour en faire ensuite un jour intercalaire ; de là il suit qu’on ne saurait indiquer avec précision le moment du lever et du coucher des astres. On convient qu’il y a encore dans cette théorie beaucoup d’obscurité ; en effet, les saisons quelquefois commencent plusieurs jours avant le terme qui leur a été fixé, ce que les ''Grecs'' appellent ''procheimasis'' ; d’autres fois, plusieurs jours après, ce qu’ils appellent ''épicheimasis'' [[#Accedit_confessa_rerum_obscuritas_AdG|<span id="Accedit_confessa_rerum_obscuritas_AdG_back"><sup>'''2'''</sup></span>]]. Presque toujours l’action des astres se fait sentir sur la terre ou plus tôt ou plus tard qu’il ne devrait ; aussi dit-on communément, lorsque le beau temps est revenu, que tel astre a produit son effet. Ces phénomènes dépendent des astres fixés à la voûte des cieux, ainsi que des étoiles, dont les mouvemens particuliers excitent des grêles et des pluies qui sont d’une très-grande conséquence pour les biens de la terre, comme nous l’avons observé, et amènent dans la température des changemens sur lesquels le laboureur ne pouvait compter. Non-seulement les hommes y sont trompés, mais aussi les animaux, bien plus habiles que nous à prévoir ces vicissitudes, puisque d’ailleurs leur vie en dépend ; en effet, on a vu des oiseaux d’été périr par des froids arrivés trop tôt ou trop tard, et des oiseaux d’hiver par des chaleurs également imprévues. Aussi '''Virgile''' veut-il qu’on étudie aussi le cours des ''planètes'', et qu’on observe avec soin le passage du froid ''Saturne'' [[#Ideo_Virgilius_errantium_quoque_siderum_rationem_ediscendam_prœcipit_AdG|<span id="Ideo_Virgilius_errantium_quoque_siderum_rationem_ediscendam_prœcipit_AdG_back"><sup>'''3'''</sup></span>]].<br /><p style="text-align: justify; text-indent: 15px;">Quelques-uns fixent le commencement du printemps à l’apparition des papillons, parce que ces insectes sont fort délicats. Néanmoins on a observé, dans l’année même où j’écris cette partie de mon ouvrage, que le froid, ayant repris trois fois, a fait périr autant de fois les papillons, et que les hirondelles qui, s’étaient montrées dès le 6 des [[w:Calendes|''kalendes'']] de février, et semblaient annoncer le retour du printemps, ont eu à essuyer un rigoureux hiver.<br /><p style="text-align: justify; text-indent: 15px;">C’est donc une science très-problématique que celle de l’influence des astres, et les inductions qu’elle fournit sont fort douteuses [[#Res_anceps_AdG|<span id="Res_anceps_AdG_back"><sup>'''4'''</sup></span>]]. Ce qui augmente la difficulté, c’est la convexité du ciel et la différence des climats de la terre : le même astre se montre ici dans un temps, et là dans un autre ; d’où il suit que son influence ne se fait pas sentir en même temps partout. Pour surcroît d’embarras, les observations recueillies par les auteurs ont été faites dans des lieux différens, et ceux du même pays ne s’accordent pas même entre eux. On compte trois écoles astronomiques, la ''chaldéenne'', l’égyptienne et la ''grecque''. Le dictateur '''César''' en a fondé, chez les ''Romains'', une quatrième, lorsqu’aidé de '''Sosigène''', habile astronome, il fixa la longueur de l’année à une révolution du soleil. On trouva dans la suite que son calendrier était défectueux, parce que l’année, auparavant plus courte, se trouvait alors plus longue que le cours du soleil. Pour y remédier, il fallut, pour douze années consécutives, supprimer les jours intercalaires. '''Sosigène''' lui-même, le mathématicien le plus exact de son temps, après avoir revu jusqu’à trois fois ses calculs, sembla toujours douter de leur justesse, et ne cessa jamais de se corriger lui-même. De tous les auteurs qui ont traité ce sujet, et que nous avons cités au commencement de ce livre, il en est rarement deux qui soient de même avis. Cette divergence d’opinions est moins surprenante et plus excusable chez ceux qui écrivaient en des pays différens. Mais que dire de ceux qui, habitant le même pays, sont néanmoins d’avis différens ? En voici un exemple : '''Hésiode''', qui nous a laissé aussi un ouvrage sur le cours des astres, fixe le coucher matutinal des ''Pléiades'' au moment de l’équinoxe d’automne ; '''Thales''' prétend qu’il n’arrive que vingt-cinq jours après ; '''Anaximandre''' en met vingt-neuf ; '''Euctémon''', quarante-huit.<br /><p style="text-align: justify; text-indent: 15px;">Quant à nous, nous suivrons les calculs de '''César''', qui se rapportent spécialement à l’Italie ; mais nous rapporterons aussi les observations étrangères, car notre plan n’est pas de traiter d’un seul pays, mais de la nature entière. Pour être moins longs, nous citerons les pays, et non les auteurs ; et, pour abréger davantage encore, les lecteurs se souviendront que, sous le nom d’Attique, il faut aussi entendre les ''Cyclades'' ; sous le nom de ''Macédoine'', la ''Magnésie'' et la ''Thrace'' ; sous le nom d’Égypte , la ''Phénicie'', l’île de ''Cypre'' et la ''Cilicie'' ; sous celui de ''Béotie'', la ''Locride'', la ''Phocide'' et les contrées voisines ; sous le nom d’Hellespont, la ''Chersonèse'' et partie du continent jusqu’au mont ''Athos'' ; sous le nom de l’Ionie, l’Asie et les îles ''Asiatiques'' ; sous le nom du ''Péloponnèse'', l’Achaïe et les pays adjacens au couchant ; enfin sous le nom de ''Chaldée'', l’Assyrie et la ''Babylonie''. On ne sera pas étonné que nous ne parlions ni de l’Afrique, ni de l’Espagne, ni des ''Gaules''. Aucun auteur dans ces contrées n’a laissé d’observations sur le lever ou le coucher des astres. Il ne sera pas difficile néanmoins de déterminer l’époque de ces phénomènes dans ces contrées, en étudiant la disposition des cercles, telle que nous l’avons présentée dans le sixième livre. Par ce moyen, on déterminera la position astronomique, non-seulement de chaque pays, mais encore de chaque ville dont nous avons pu parler, en prenant par les ombres égales de tous les cercles, une portion du cercle de telle contrée qu’on voudra choisir, et en calculant son rapport avec le lever des astres. Il faut faire observer encore que tous les quatre ans les chaleurs reviennent à peu près les mêmes pour chaque saison, en raison du mouvement du soleil, et que toutes les huitièmes années elles sont plus fortes, à cause de la centième lunaison.</div> <table cellspacing=15 align=center style="margin: 0 4em; font-size:85%;"> <tr> <td style="text-align: justify; margin: 0 4em;">'''[[#Primum_omnium_dierum_AdG_back|<span id="Primum_omnium_dierum_AdG"><sup>1</sup></span>]] Cf. sur la plupart des difficultés que le texte de notre auteur révèle, les notes relatives à l’astronomie, au livre II. L’année romaine fut d’abord celle des [[w:Albe_la_Longue|''Albains'']], c’est-à-dire lunaire ; dix mois la composaient, mars en était le premier : elle avait cinquante jours de moins que l’année lunaire réelle, et soixante-un de moins que l’année solaire, c’est-à-dire trois cent quatre jours seulement ; c’était là l’[[w:Calendrier_romain|{{Info|''année de Romulus''|le calendrier dit romuléen}}]]. [[w:Calendrier_romain|{{Info|''Numa''|le calendrier dit pompilien}}]] ajouta deux mois à cette année, janvier et février, et elle se trouva être composée de trois cent cinquante-cinq jours. Elle demeura ainsi jusqu’à Jules César, où commence l’[[w:Calendrier_julien|''année julienne'']], qui se compose de trois cent soixante-cinq jours, huit heures, auxquels [[w:Calendrier_grégorien|''Grégoire le Grand'']] ajouta onze minutes, pour arriver à la plus grande exactitude possible.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Accedit_confessa_rerum_obscuritas_AdG_back|<span id="Accedit_confessa_rerum_obscuritas_AdG"><sup>2</sup></span>]] L’entrée du soleil dans tel ou tel signe du zodiaque, son passage à l’équateur, etc., ne sont pas toujours le signal d’un changement dans la température. [[w:Végèce|Végèce]] a parlé des jours prokéimasiques et épikéiniasiques :''' {{Info|''Aut enim circa diem statutum, aut ante, vel postea, tempestates fieri, compertum est : unde præcedentes, ωροϰεἰμασιν : nascentes die solenni, επιϰεἰμασιν : subsequentes, μεταϰεἰμασιν, græco vocabulo nuncuperaverunt''|Car on a constaté que les tempêtes se produisent soit vers le jour fixé, soit avant, soit après : d’où les précédents, ωροϰεἰμασιν : nés le jour solennel, επιϰεἰμασιν : les suivants, μεταϰεἰμασιν, étaient appelés par le mot grec. TdA.}} '''(IV, 40).''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Ideo_Virgilius_errantium_quoque_siderum_rationem_ediscendam_prœcipit_AdG_back|<span id="Ideo_Virgilius_errantium_quoque_siderum_rationem_ediscendam_prœcipit_AdG"><sup>3</sup></span>]] <p style="margin: 0 6em; text-indent: 0px">'''{{Info|Hoc metuens, cæli menses et sidera serva,<br />Frigida Saturni sese quo stella receptet.|Craignant cela, gardez les lunes et les étoiles du ciel, le froid de Saturne lui-même, où l’étoile les recevra. TdA.}}'''<p style="text-align: right; margin: 0 6em; text-indent: 0px">''Georg.'', I, 335.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Res_anceps_AdG_back|<span id="Res_anceps_AdG"><sup>4</sup></span>]] Voici enfin quelques idées philosophiques qui se trouvent sous la plume de Pline ; malheureusement la cause par laquelle notre auteur explique l’influence des astres est problématique, et montre que les sciences astronomiques des anciens laissaient beaucoup à désirer. Les Grecs croyaient qu’il y avait autant de cieux que de planètes ; le huitième ciel, ou le firmament, était celui dès étoiles fixés.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Occasum_matutinum_Vergiliarum_Hesiodus_AdG_back|<span id="Occasum_matutinum_Vergiliarum_Hesiodus_AdG"><sup>5</sup></span>]] L’ouvrage auquel Pline fait allusion a été mentionné par [[w:Théon_d'Alexandrie|Théon]] qui le nomme Αστριϰὴ βίϐλος [[w:en:Astronomia_(poem)|(en)]]. Cet ouvrage est perdu.'''</td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k5804072n <u>Histoire Naturelle de Pline. Tome Onzième</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k5804072n/f196.item ''Livre XVIII.''], [https://gallica.bnf.fr/ark:/12148/bpt6k5804072n/f340.item ''chap. LVII.''], traduction nouvelle par M. [[w:Stéphane_Ajasson_de_Grandsagne|Ajasson de Grandsagne]] [https://gallica.bnf.fr/ark:/12148/bpt6k5804072n/f453.item <sup>NOTES</sup>], C. L. F. Panckoucke, Paris, 1829</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: center; margin: 0 2em;">''Divi[[w:S_long|{{Info|ſ|forme ancienne longue de la lettre s minuscule}}]]<nowiki />ion des jours & des nuits [[w:S_long|{{Info|ſ|forme ancienne longue de la lettre s minuscule}}]]<nowiki />uivant le cours du Soleil ; lever & coucher des étoiles ; ordre des [[w:S_long|{{Info|ſ|forme ancienne longue de la lettre s minuscule}}]]<nowiki />ai[[w:S_long|{{Info|ſ|forme ancienne longue de la lettre s minuscule}}]]<nowiki />ons ; tems où l’on [[w:S_long|{{Info|ſ|forme ancienne longue de la lettre s minuscule}}]]<nowiki />eme les bleds d’hiver.''<br /><p style="text-align: justify; text-indent: 15px;">'''D'''’ABORD il e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t pre{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que impo{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ible de déterminer au ju{{Info|ſ|forme ancienne longue de la lettre s minuscule}}te le nombre des jours de l’année, & le cours du Soleil ; car comme aux trois cents {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oixante & cinq jours dont l’année e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t compo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ée, on ajoute le quart d’un jour & d’une nuit, autrement {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ix heures, qui, au bout de quatre ans, font un jour intercalaire [[#jour_intercalaire_LPdS|<span id="jour_intercalaire_LPdS_back"><sup>'''1'''</sup></span>]], il arrive qu’on ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}auroit a{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}igner avec certitude le tems du lever & du coucher des a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tres. En {{Info|ſ|forme ancienne longue de la lettre s minuscule}}econd lieu, l’on convient qu’il y a dans cette théorie beaucoup d’ob{{Info|ſ|forme ancienne longue de la lettre s minuscule}}curité ; car quelquefois les {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ons [[#quelques_les_saisons_LPdS|<span id="quelques_les_saisons_LPdS_back"><sup>'''2'''</sup></span>]] commencent plu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ieurs jours avant le terme qui leur a été fixé, ce que les Grecs appellent ''prokheïma{{Info|ſ|forme ancienne longue de la lettre s minuscule}}is'' ; & d’autres fois plu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ieurs jours après, ce que ces mêmes Grecs expriment par le mot ''epikheïma{{Info|ſ|forme ancienne longue de la lettre s minuscule}}is'' : & l’on éprouve très {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ouvent que l’action des a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tres {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ait {{Info|ſ|forme ancienne longue de la lettre s minuscule}}entir {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur la terre, tantôt plutôt, tantôt plus tard. Au{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}i dit-on communément, lor{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que le beau tems e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t revenu, que tel a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tre a produit {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on effet. D’ailleurs comme tout cela dépend des globes céle{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tes, leur mouvement relatif excite quelquefois des grêles & des pluies, qui, comme nous l’avons déja [[#déjà_fait_observer_LPdS|<span id="déjà_fait_observer_LPdS_back"><sup>'''3'''</sup></span>]] fait ob{{Info|ſ|forme ancienne longue de la lettre s minuscule}}erver, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont de la plus grande con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}équence pour les biens de la terre, & qui renver{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ent l’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}pérance qu’on avoit du beau tems. Et non {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eulement les hommes y {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont trompés, mais au{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}i les animaux, quoiqu’ils aient bien plus de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}agacité que nous pour pre{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}entir ces vici{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}itudes du ciel, d’autant que leur vie en dépend. En effet, on voit quelquefois les oi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}eaux d’été mourir par des froids qui viennent trop tard ou trop tôt, & les oi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}eaux d’hiver par des chaleurs qui arrivent de même. C’est pourquoi '''Virgile''' veut qu’on étudie au{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}i le cours des planetes, & qu’on ob{{Info|ſ|forme ancienne longue de la lettre s minuscule}}erve à quelle partie du zodiaque répond la planete du froid Saturne [[#Saturne_LPdS|<span id="Saturne_LPdS_back"><sup>'''4'''</sup></span>]]. Quelques-uns croient que le {{Info|ſ|forme ancienne longue de la lettre s minuscule}}igne le plus certain du printems commencé, c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t lor{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’on voit des papillons, & cela parceque ces in{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ectes {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont fort délicats. Néanmoins on a remarqué que dans l’année même [[#lAnnée_dÉcriture_LPdS|<span id="lAnnée_dÉcriture_LPdS_back"><sup>'''5'''</sup></span>]] où j’écris ceci, le froid ayant recommencé ju{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’à trois fois, a fait mourir autant de fois les papillons ; & que les hirondelles, qui, s’étant montrées dès le vingt-{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ept de Janvier, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}embloient annoncer le retour du printems, ont en{{Info|ſ|forme ancienne longue de la lettre s minuscule}}uite e{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}uyé un très cruel hiver.<br /><p style="text-align: justify; text-indent: 15px;">C’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t donc une {{Info|ſ|forme ancienne longue de la lettre s minuscule}}cience très problématique que celle de l’influence des a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tres, & les inductions que l’on en tire {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont fort douteuses. Mais ce qui cau{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e le plus d’incertitude, c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t cette convexité du ciel & la différence des climats de la terre, parceque le même a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tre {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e montre ici dans un tems, & là dans un autre, d’où il ré{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ulte que {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on influence ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e fait pas {{Info|ſ|forme ancienne longue de la lettre s minuscule}}entir en même tems par-tout. Un autre {{Info|ſ|forme ancienne longue de la lettre s minuscule}}urcroît de difficulté, c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t que les ob{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ervations recueillies par les Auteurs ont été faites en différents lieux, & que ceux même qui ont écrit dans le même endroit ne s’accordent nullement entre eux dans ce qu’ils écrivent. On compte ju{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’à trois différentes {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ortes de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ectes en A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tronomie ; {{Info|ſ|forme ancienne longue de la lettre s minuscule}}avoir, celle des Chaldéens [[#secte_des_Chaldéens_LPdS|<span id="secte_des_Chaldéens_LPdS_back"><sup>'''5*'''</sup></span>]], celle des Egyptiens & celle des Grecs. On peut même dire que le Dictateur Cé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ar [[#Dictateur_César_LPdS|<span id="Dictateur_César_LPdS_back"><sup>'''6'''</sup></span>]] en produi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}it, chez les Romains, une quatrieme, lor{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’il rédui{{Info|ſ|forme ancienne longue de la lettre s minuscule}}it chaque année au cours du {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oleil, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ervant à cet effet du travail de So{{Info|ſ|forme ancienne longue de la lettre s minuscule}}igene, très habile A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tronome. Néanmoins on découvrit en{{Info|ſ|forme ancienne longue de la lettre s minuscule}}uite que le calendrier de Cé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ar étoit défectueux [[#calendrier_César_défectueux_LPdS|<span id="calendrier_César_défectueux_LPdS_back"><sup>'''7'''</sup></span>]], parceque l’année qui auparavant étoit plus courte que le cours du {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oleil, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e trouvoit alors plus longue : & pour corriger cette erreur, on ordonna que pendant douze années de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uite, il n’y auroit point de jour intercalaire [[#correction_erreur_LPdS|<span id="correction_erreur_LPdS_back"><sup>'''8'''</sup></span>]]. So{{Info|ſ|forme ancienne longue de la lettre s minuscule}}igene lui-même, quoique Mathématicien plus exact que les autres, ne lai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}a pas de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e conduire con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tamment en homme qui doutoit de la ju{{Info|ſ|forme ancienne longue de la lettre s minuscule}}te{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}e de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on propre calcul, pui{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’il en fit ju{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’à trois différentes corrections. De tous les Auteurs [[#Auteurs_calendrier_LPdS|<span id="Auteurs_calendrier_LPdS_back"><sup>'''9'''</sup></span>]] qui ont écrit {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur cette matiere, & que nous avons allégués au commencement de ce livre, il s’en trouve rarement deux qui {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oient de même {{Info|ſ|forme ancienne longue de la lettre s minuscule}}entiment. Cette variété e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t moins {{Info|ſ|forme ancienne longue de la lettre s minuscule}}urprenante, comme au{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}i plus excu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}able, chez ceux qui écrivoient en des pays différents. Mais que dire de ceux qui, écrivant dans le même pays, n’ont pas lai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}é d’être partagés d’opinion ? En voici un exemple. '''Hé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iode''', dont il y a au{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}i un ouvrage [[#ouvrage_astronomique_Hésiode_LPdS|<span id="ouvrage_astronomique_Hésiode_LPdS_back"><sup>'''10'''</sup></span>]] {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur le cours des a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tres, dit que les Pléiades {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e couchent le matin dans le tems même de l’équinoxe d’automne. '''Thalès''' [[#opinion_Thalès_Hésiode_Anaximandre_LPdS|<span id="opinion_Thalès_Hésiode_Anaximandre_LPdS_back"><sup>'''11'''</sup></span>]] dit que cela arrive vingt-cinq jours après. '''Anaximandre''' en met vingt-neuf ; '''Euctémon''' [[#Euctémon_LPdS|<span id="Euctémon_LPdS_back"><sup>'''12'''</sup></span>]] quarante-huit.<br /><p style="text-align: justify; text-indent: 15px;">Quant à nous, nous {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uivrons le calcul de Cé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ar, ayant principalement égard à l’Italie. Nous ne lai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}erons néanmoins de rapporter les opinions étrangeres, parceque notre objet n’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t pas de traiter d’un {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eul pays, mais de la Nature entiere. Seulement, pour éviter les longueurs, nous n’indiquerons que les pays où chaque opinion a lieu, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ans faire mention des auteurs de ces a{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ertions : & pour abréger encore davantage, les Lecteurs voudront bien {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ouvenir que quand il e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t parlé de l’Attique, il faut, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous ce nom, entendre au{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}i les Cyclades ; que {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous le nom de Macédoine, il faut entendre au{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}i la Magné{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ie & la Thrace ; {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous le nom de l’Egypte, la Phénicie, l’i{{Info|ſ|forme ancienne longue de la lettre s minuscule}}le de Chypre & la Cilicie; {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous celui de la Béotie, la Locride, la Phocide & les contrées voi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ines ; {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous le nom de l’Hel le{{Info|ſ|forme ancienne longue de la lettre s minuscule}}pont, la pre{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’i{{Info|ſ|forme ancienne longue de la lettre s minuscule}}le de Thrace & le pays de terre ferme, ju{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’au mont Athos ; {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous le nom de l’Ionie, l’A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ie & les i{{Info|ſ|forme ancienne longue de la lettre s minuscule}}les A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iatiques ; {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous le nom du Péloponne{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e, l’Achaïe & les contrées [[#contrées_adjacentes_ouest_Péloponnese_LPdS|<span id="contrées_adjacentes_ouest_Péloponnese_LPdS_back"><sup>'''13'''</sup></span>]] adjacentes qu’elle a à {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on couchant ; {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous le nom des Chaldéens, l’Assyrie & la Babylonie. Il ne faudra pas s’étonner {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i je ne parle ici ni de l’Afrique, ni de l’Espagne, ni des Gaules, pui{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que ces pays n’ont eu aucun Auteur qui ait écrit du cours des a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tres, ni de leur lever. Toutefois il ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}era pas difficile de connoître le tems où ils {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e levent dans ces pays-là même, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i l’on e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t in{{Info|ſ|forme ancienne longue de la lettre s minuscule}}truit de l’arrangement des cercles céle{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tes, tel que nous l’avons expliqué au {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ixieme livre de cet ouvrage ; car, par ce moyen, & par les {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eules notions que nous avons expo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ées en donnant une nomenclature des lieux, on {{Info|ſ|forme ancienne longue de la lettre s minuscule}}aura la po{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ition, non {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eulement de chaque pays, mais encore de chaque ville, en prenant par les ombres égales de tous les cercles, un {{Info|ſ|forme ancienne longue de la lettre s minuscule}}egment du cercle de tel pays qu’on voudra choi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ir, & en cherchant {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on rapport avec le lever des a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tres. Il faut remarquer au{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}i que de quatre [[#Columelle_LPdS|<span id="Columelle_LPdS_back"><sup>'''14'''</sup></span>]] en quatre ans les {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ons & les chaleurs reviennent à peu près les mêmes, & cela à cau{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e du mouvement du Soleil ; & que de huit en huit ans ces mêmes chaleurs reviennent plus con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}idérables, en vertu de la centieme lunai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}on.</div> {{Boîte déroulante début|titre=Notes du traducteur|alignT=center}} <div style="text-align: justify; border: 2px; border-radius:15px; font-size:85%;"><br/> <table cellspacing=15 align=center style="margin: 0 4em;"> <tr> <td style="text-align: justify; margin: 0 4em; text-indent: 15px">'''[[#jour_intercalaire_LPdS_back|<span id="jour_intercalaire_LPdS"><sup>1</sup></span>]] Con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ultez, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur toute cette que{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tion, nos notes 13 & 14 {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur le huitieme chapitre du {{Info|ſ|forme ancienne longue de la lettre s minuscule}}econd livre de Pline, tome 1, p. 41 & 42 :<br /><p style="text-align: justify; text-indent: 15px; margin: 0 5em;">(13) [[w:Suétone|Suétone]] s’exprime mieux, lor{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’il écrit : chaque quatrieme année ''quarto quoque anno''. Il est vrai que, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}elon le [[w:Jean_Hardouin|Pere Hardouin]], il faut comprendre dans la période de cinq ans, dont parle Pline, la premiere & la cinquieme année comme Bi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}extiles ; ce qui revient aux quatre années de Suétone, dont la quatrieme avoit un ''bi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ex'' ; mais en vérité cette explication est des plus forcées. Je {{Info|ſ|forme ancienne longue de la lettre s minuscule}}erois donc d’avis qu’il faudroit lire dans Pline comme dans Suétone, ''quarto anno'', {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i nous n’apprenions d’ailleurs de cet Hi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}torien, que dès le regne d’Augu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}te il s’étoit déja gli{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}é plu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ieurs abus & altérations dans l’année Julienne. On voit du moins qu’il y réforma plu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ieurs cho{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es, sous prétexte de la remettre {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur le pied où Cé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ar l’avoit in{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tituée. Cela me donneroit à pen{{Info|ſ|forme ancienne longue de la lettre s minuscule}}er qu’on fit dès-lors attention à la fau{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}eté & à l’excédence du calcul Julien ; mais qu’Augu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}te, par respect pour la mémoire de Cé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ar, affecta d’imputer la faute à la négligence des Prêtres chargés à Rome de l’in{{Info|ſ|forme ancienne longue de la lettre s minuscule}}pection du Calendrier ; qu’au demeurant, on découvrit l’abus, & qu’on e{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}aya d’y remédier, en n’ajoûtant un jour entier à l’année ordinaire que chaque ''cinquieme année'' comme Pline paroît l’articuler ici expre{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ement. Mais d’ailleurs il e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t évident qu’à la longue le période bi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}extile de quatre années en quatre années prévalut {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur celui de chaque cinquieme année, dont parle Pline ; & même il paroît que ceux qui, par la {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uite, voulurent {{Info|ſ|forme ancienne longue de la lettre s minuscule}}upputer les tems, récapitulerent, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ans exception, toutes les bi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}extiles quartenaires écoulées depuis l’in{{Info|ſ|forme ancienne longue de la lettre s minuscule}}titution Julienne ; car en 1582, on trouva par ce moyen que l’année étoit reculée de dix jours & plus; d’autant que l’excédence du calcul Julien, qui {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uppo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e à l’année révolue 365 jours & {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ix heures, au lieu de 365 jours 5 heures 49 minutes, 8 {{Info|ſ|forme ancienne longue de la lettre s minuscule}}econdes 17 tierces & 13 quarts qu’elle a réellement, forme tous les ans environ 11 minutes de trop, & tous les cent trente-quatre ans un jour entier d’excès. Le Pape Grégoire XIII trouvant donc l’année reculée de plus de dix jours ; ce qui dérangeoit l’économie annuelle des {{Info|ſ|forme ancienne longue de la lettre s minuscule}}olemnités, remédia à cet inconvénient en retranchant de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on autorité dix jours au mois d’Octobre de l’année 1582, où l’on étoit alors ; & en réglant qu’à l’avenir tous les quatre cents ans on omettroit trois années bi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}extiles. Ce réglement devint une loi pour pre{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que toute l’Europe chrétienne. L’autre maniere de compter fut appellée l’ancien {{Info|ſ|forme ancienne longue de la lettre s minuscule}}tyle. La Grande-Bretagne a long-tems per{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i{{Info|ſ|forme ancienne longue de la lettre s minuscule}}té à s’en {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ervir malgré {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on abus manife{{Info|ſ|forme ancienne longue de la lettre s minuscule}}te. Enfin le Parlement d’Angleterre, par acte du mois de Septembre 1752, a adopté la réforme Grégorienne.<br /><p style="text-align: justify; text-indent: 15px; margin: 0 4em;">(14) Le {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oleil, en fai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ant le tour du cercle oblique, parcourt réellement 360 degrés ou {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ections ; pui{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que tout cercle {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e divi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e en 360 parties appellées degrés : mais la me{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ure de chaque degré du cercle parcouru annuellement par le {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oleil, excede tant {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oit peu, c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t-à-dire de quelques légeres fractions de tems, la durée de chacun de nos jours révolus ; durée qui n’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t, comme on {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ait, que de 24 heures préci{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es ; le{{Info|ſ|forme ancienne longue de la lettre s minuscule}}quelles, comparées à un degré, en produi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ent, au bout de l’année, 365 & plus pour le cercle, au lieu de 360 {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eulement que le cercle requerroit. D’après une connoi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ance con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}u{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e de ces principes, Jules Cé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ar {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e voyant Dictateur, Grand-Pontife, & maître du monde, entreprit, l’an 140 avant J. C. de réformer les abus qui s’étoient gli{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}és, tant dans l’année Pompilienne, ou de Numa, que dans celle des Pontifes, encore plus irréguliere que celle de Numa. A cet effet, il fit venir d’Alexandrie le Philo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ophe So{{Info|ſ|forme ancienne longue de la lettre s minuscule}}igenes. Celui-ci décida fau{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ement que le cercle des jours de l’année révolue excédoit du nombres 5 joint au quart de 1 les 360 degrés du cercle oblique parcouru par le {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oleil : expo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}é faux, auquel le Dictateur, occupé d’autres {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oins, déféra {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ans autre examen. Jules Cé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ar régla donc, de l’avis de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tronome, que l’année {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eroit divisée en 365 jours ; & quant au quart de jour re{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tant, qui produit {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ix heures, il ordonna qu’on n’y auroit aucun égard pour chaque année particuliere ; mais que chaque quatrieme année on réuniroit la totalité de quatre fois {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ix heures, qui en font vingt-quatre, pour en compo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}er un jour entier; & qu’ain{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i cette quatrieme année auroit 366 jours. Il régla de plus, que ce jour intercalaire, ou ajoûté à chaque quatrieme année, seroit le 24 Février. Les Romains nommoient ce jour-là ''bis {{Info|ſ|forme ancienne longue de la lettre s minuscule}}exto calendas Martii'', c’est-à-dire, le ''{{Info|ſ|forme ancienne longue de la lettre s minuscule}}econd {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ixieme avant les calendes de Mars'' ; d’où il arriva que l’année où tomboit ce jour intercalaire fut appellée bis-{{Info|ſ|forme ancienne longue de la lettre s minuscule}}extile.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#quelques_les_saisons_LPdS_back|<span id="quelques_les_saisons_LPdS"><sup>2</sup></span>]] Végece dit pareillement, liv. 4, chap. 40 : ''Aut enim circa diem {{Info|ſ|forme ancienne longue de la lettre s minuscule}}tatutum, aut ante, vel po{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tea, tempe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tates fieri compertum e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t : unde præcedentes, ωροϰεἰμασιν : na{{Info|ſ|forme ancienne longue de la lettre s minuscule}}centes die {{Info|ſ|forme ancienne longue de la lettre s minuscule}}olenni, επιϰεἰμασιν : {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ub{{Info|ſ|forme ancienne longue de la lettre s minuscule}}equentes, μεταϰεἰμασιν, Græco vocabulo nuncuperaverunt'' [[#Accedit_confessa_rerum_obscuritas_AdG_back|<sup>⤴️</sup>]]. On lit au{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}i chez [[w:Columelle|Columelle]], dans {{Info|ſ|forme ancienne longue de la lettre s minuscule}}a Préface :''' {{Info|''Neque enim ſemper eumdem, cælum & annus, velut ex præſcripto habitum gerunt : nec omnibus annis eodem vultu venit aſtas, aut hyems, &c.''|Car le ciel et l’année ne portent pas toujours le même habit, comme par un précepte : ni l’automne n’arrive chaque année avec la même apparence, ni l’hiver, etc. TdA}} </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#déjà_fait_observer_LPdS_back|<span id="déjà_fait_observer_LPdS"><sup>3</sup></span>]] Au liv. 17, chap. 2.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Saturne_LPdS_back|<span id="Saturne_LPdS"><sup>4</sup></span>]] Ain{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i qu’il l’in{{Info|ſ|forme ancienne longue de la lettre s minuscule}}inue dans {{Info|ſ|forme ancienne longue de la lettre s minuscule}}es ''Géorg.'' liv. I, v. 335 :'''<br /><p style="margin: 0 6em; text-indent: 0px">{{Info|Hoc metuens, cæli menses et sidera serva,<br />Frigida Saturni sese quo stella receptet.|Craignant cela, gardez les lunes et les étoiles du ciel, le froid de Saturne lui-même, où l’étoile les recevra. TdA.}} </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#lAnnée_dÉcriture_LPdS_back|<span id="lAnnée_dÉcriture_LPdS"><sup>5</sup></span>]] Pline, au quatorzieme livre, chap. 4, comptoit deux cents trente ans depuis la mort de [[w:Cicéron|Cicéron]] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Cicéron_I|<sup>🔄</sup>]], arrivée l’an de Rome 600. L’année qu’il indique ici, & où il {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e trouvoit avoir compo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}é quatre livres de plus, e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t probablement la {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uivante, c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t-à-dire l’année 831 de la fondation de Rome.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#secte_des_Chaldéens_LPdS_back|<span id="secte_des_Chaldéens_LPdS"><sup>5*</sup></span>]] Sur l’année Chaldéenne, qui étoit la même que la Judaïque, con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ultez [[w:Eusèbe_de_Césarée|Eu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ebe]], ''Præpar. Evang.'' liv. 9, chap. 17, où il fait Abraham inventeur de l’a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tronomie chez les Chaldéens. Les A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}trologues Chaldéens étoient ordinairement des Prêtres des Dieux, tels que [[w:Bérose|Béro{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e]], auquel les Athéniens éleverent dans leur Gymna{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e une {{Info|ſ|forme ancienne longue de la lettre s minuscule}}tatue à langue dorée. Sur quoi voyez Pline, liv. 7, chap. 37. Ce Béro{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e étoit un Prêtre de [[w:Bēl|Belus]] ; il e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t cité par [[w:Clément_d'Alexandrie|Clément d’Alexandrie]], & par [[w:Flavius_Josèphe|Jo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}eph]] [[#Flavius_Josèphe_I|<sup>⤵️</sup>]], contre Apion, liv. 1. Sur l’année Egyptienne, & {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur l’ancienne année Grecque, con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ultez [[w:Hérodote|Hérodote]] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Hérodote_I|<sup>🔄</sup>]] liv. 2, n°. 4. Cicéron rend ju{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tice à l’étude que firent des a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tres les Egyptiens & les Babyloniens, liv. 1, de ''Divinat.'' n°. 16 :''' {{Info|''Ægyptii, & Babylonii, in camporum patentium aquoribus habitantes, cùm ex terra nihil emineret, quod contemplationi cæli officere poſſet, omnem curam in ſiderum cognitione poſuerunt''|Les Égyptiens et les Babyloniens, vivant dans les eaux des plaines découvertes, alors que rien ne dépassait de la terre qui pût gêner la contemplation du ciel, mettaient tous leurs soins dans la connaissance des étoiles. TdA}}. </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Dictateur_César_LPdS_back|<span id="Dictateur_César_LPdS"><sup>6</sup></span>]] Voyez les notes 13 & 14 {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur le chap. 8 du liv. 2, tome 1, p. 41 & 42.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#calendrier_César_défectueux_LPdS_back|<span id="calendrier_César_défectueux_LPdS"><sup>7</sup></span>]] Voyez les notes indiquées dans la note précédente ; & joignez-y les ob{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ervations {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uivantes, qui {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont de M. De{{Info|ſ|forme ancienne longue de la lettre s minuscule}}places, p. 339 : « Le calendrier chrétien, ayant {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uivi la réformation de Jules Cé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ar, il {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e trouva qu’en l’année 1582, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous le Pape Grégoire XIII, l’équinoxe étoit remontée ju{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’au 11 de Mars, au lieu du 21, où elle devoit être. Ce Pape, après avoir con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ulté Clavius & Ciaconius, les plus habiles A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tronomes du tems, ordonna qu’en cette même année 1582, on compteroit le 5 du mois d’Octobre, au lieu du 15, afin de retrancher les dix jours qui s’étoient gli{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}és de trop, en {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uivant la {{Info|ſ|forme ancienne longue de la lettre s minuscule}}upputation Julienne, depuis le Concile de Nicée, tenu en 325 : on convint encore de continuer l’intercalation d’un jour tous les quatre ans ; & qu’en outre, pour éviter dans la {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uite pareille erreur, il {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eroit fait un retranchement de trois jours intercalaires, dans l’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}pace de quatre {{Info|ſ|forme ancienne longue de la lettre s minuscule}}iecles, à cau{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e des onze minutes qui manquent aux {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ix heures des années, dont on compo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e l’année intercalaire, ou bi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}extile ; ces trois jours {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e retranchent en l’année qui finit les trois premiers {{Info|ſ|forme ancienne longue de la lettre s minuscule}}iecles. De célebres A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tronomes modernes ont fait voir que, malgré cette précaution, il y auroit encore, au bout de quatre cents ans, plu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ieurs jours de variation dans l’équinoxe ».''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#correction_erreur_LPdS_back|<span id="correction_erreur_LPdS"><sup>8</sup></span>]] Etabli par Jules Cé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ar, & qui revenoit tous les quatre ans. Ecoutons Suétone, vie de ce Dictateur, chap. 40 : {{Info|''Faſtos correxit, jampridem vitio Pontiſicum, per intercalandi licentiam adeo turbatos, ut neque meſſium feria aſtati, neque vindemiarum autumno competerent, annumque ad curſum ſolis accommodevit, ut CCCLXV dierum eſſet, & intercalario menſe ſublato, unus dies quarto quoque anno intercalaretur, &c''|Il corrigea les jeûnes, qui avaient toujours été une faute pontique, si perturbés par la permission de l’intercalation, que ni les fêtes du mois ne tenaient, ni les récoltes ne correspondaient à l’automne, et il ajusta l’année à la course du soleil, de sorte que c’était 365 jours, et après le mois intercalaire, un jour était intercalé tous les quatre ans, etc. TdA}}. On s’apperçut que cette correction de Jules Cé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ar étoit elle-même fautive. On tenta de nouveau de remédier au vice du calendrier ; {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur quoi con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ultez Solin, chapitre 1, p. 5 ; le P. Petau, ''de Doctr. temp.'' chap. 3 ; mais {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur-tout [[w:Macrobe|Macrobe]], qui s’exprime ain{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i, liv. 1, ''Saturn.'' chap. 14, p. 255 :''' {{Info|''Sacerdotes ſibi errorem novum ex ipſa emendatione ſecerunt. Nam cùm oporteret diem, qui ex quadrantibus conſit, quarto quoque anno conſecto, antequam quintus inciperet, intercalare, illi quarto non peracto ſed incipiente, intercalabant. Hic error ſex & triginta annis permanſit : quibus annis intercalati ſunt dies duodecim, cùm deberent intercalari novem. Sed hunc quoque errorem ſerò deprehenſum correxit Auguſtus, qui annos duodecim ſine intercalari die tranſigi juſſit : ut illi tres dies, qui per annos triginta & ſex vitio ſacerdotalis ſeſtinationis excreverant, ſequentibus annis duodecim, nullo die intercalato, devorarentur. Poſt hoc unum diem, ſecundùm ordinationem Caſaris, quinto quoque incipiente anno intercalari juſſit : & omnem hunc ordinem area tabula ad aternam cuſtodiam inciſione mandavit.''|Les prêtres retranchèrent une nouvelle erreur de leur correction. Car lorsqu’il fallait intercaler le jour qui est composé de quadrants, la quatrième année consécutive, avant que la cinquième ne commence, on intercalait ceux lorsque la quatrième n’était pas terminée mais commençait. Cette erreur a duré trente-six ans : années au cours desquelles douze jours ont été intercalés, alors qu’il aurait fallu en intercaler neuf. Mais cette erreur fut également détectée par Auguste, qui ordonna que douze années s’écoulèrent sans jour intercalaire : afin que ces trois jours, qui avaient été excrétés pendant les trente-six années du vice sacerdotal de cessation, soient dévorés dans le douze années suivantes, sans jour intercalaire. Après ce jour, selon l’ordonnance de César, il décréta que la cinquième année serait également intercalée : et tout l’ordre fut ordonné d’être gravé par le conseil du domaine pour la garde éternelle. TdA}}. </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Auteurs_calendrier_LPdS_back|<span id="Auteurs_calendrier_LPdS"><sup>9</sup></span>]] Ces Auteurs {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont Hiéron, Philomêtor, Attale, Archelaüs, Xénophon, Magon, Caton, Silanus, Varron, &c. dont Pline a fait mention {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur la fin du chapitre 3.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#ouvrage_astronomique_Hésiode_LPdS_back|<span id="ouvrage_astronomique_Hésiode_LPdS"><sup>10</sup></span>]] Nous apprenons de Théon que cet ouvrage {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e nommoit l’A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}trique, Ἀςριϰὴ ϐίϐλος. Voyez au{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}i {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur ce même ouvrage, une Epigramme de [[w:Callimaque_de_Cyr%C3%A8ne|Callimaque]] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Callimaque_I_de_Cyrène_II|<sup>🔄</sup>]], citée dans la vie d’Aratus, qui fait partie de l’Uranologie de [[w:Denis_Pétau|Petau]], liv. 2, ''Var. Di{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ert.'' chap. 9, p. 97.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#opinion_Thalès_Hésiode_Anaximandre_LPdS_back|<span id="opinion_Thalès_Hésiode_Anaximandre_LPdS"><sup>11</sup></span>]] Con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ultez, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur cette opinion de Thalès, ain{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i que {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur celles d’Hé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iode & d’Anaximandre, l’Uranologie citée note précédente.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Euctémon_LPdS_back|<span id="Euctémon_LPdS"><sup>12</sup></span>]] ''Euctemon'' ; ain{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i portent les manu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}crits, & non pas ''Eudemon''. J’ai traité d’Euctêmon (en Grec Εὐϰτημον) dans les notes alphabétiques du premier livre, & plus récemment dans la note 21 du chapitre précédent.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#contrées_adjacentes_ouest_Péloponnese_LPdS_back|<span id="contrées_adjacentes_ouest_Péloponnese_LPdS"><sup>13</sup></span>]] Telles que l’Elide, l’Arcadie, la Me{{Info|ſ|forme ancienne longue de la lettre s minuscule}}lénie.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Columelle_LPdS_back|<span id="Columelle_LPdS"><sup>14</sup></span>]] Columelle, liv. 3, chap. 6 :''' {{Info|''Quo tempore ſol in eamdem partem ſigniſeri per eoſdem numeros redit, per quos cursus ſui principium cæperat : quem circuitum meatus dierum integrorum mille quadringentorum ſexaginta unius [[w:Apocatastase|ὰ τοκατάςασιν]] vocant ſtudioſi rerum cæleſtium''|A ce moment-là, le soleil revient dans la même direction au moyen des mêmes nombres par lesquels il a commencé sa course : laquelle course de mille quatre cent soixante et un jours entiers est appelée ὰ τοκατάςασιν par ceux qui étudient les choses célestes. TdA}}.</td> </tr> </table><br/><br/></div> {{Boîte déroulante fin}} <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=JeyFTzG771cC&newbks=1&newbks_redir=0&dq=Louis%20Poinsinet%20de%20Sivry%20Pline%20l'ancien&hl=fr&pg=PP9#v=onepage&q&f=true <u>Histoire Naturelle de Pline. Tome Sixieme</u>], [https://books.google.fr/books?id=JeyFTzG771cC&newbks=1&newbks_redir=0&dq=Louis%20Poinsinet%20de%20Sivry%20Pline%20l'ancien&hl=fr&pg=PA257#v=onepage&q&f=true ''Livre Dix-huitieme.''], [https://books.google.fr/books?id=JeyFTzG771cC&newbks=1&newbks_redir=0&dq=Louis%20Poinsinet%20de%20Sivry%20Pline%20l'ancien&hl=fr&pg=PA455#v=onepage&q&f=true ''Diviſion des jours & des nuits ſuivant le cours du Soleil ; lever & coucher des étoiles ; ordre des ſaiſons ; tems où l’on ſeme les bleds d’hiver.''], traduction en françois, avec le texte latin rétabli d’après les meilleures leçons manu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}crites ; accompagnée de Notes critiques pour l’éclairci{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ement du texte, & d’Ob{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ervations {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur les connoi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ances des Anciens comparées avec les découvertes des Modernes, par M. [[w:Louis_Poinsinet_de_Sivry|Louis Poinsinet de Sivry]], Chez la veuve Desaint, Paris, 1771</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div> </div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ==== Livre XXXVI ==== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Enquête sur la nature des pierres.</div> ===== <div style="text-align: center;">Chapitre XVII.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage de la mesure de la hauteur des pyramides et autres édifices semblables par comparaison des longueurs d'ombre, par '''Thalès'''.</div> :'''Texte latin''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''XVII.''' [...] Mensuram altitudinis earum omniumque similium deprehendere, invenit '''Thales''' ''Milesius'' umbram metiendo, qua hora par esse corpori solet.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=L249AAAAcAAJ&hl=fr&pg=PP11#v=onepage&q&f=false <u>Histoire Naturelle de Pline ― Tome Second</u>], [https://books.google.fr/books?id=L249AAAAcAAJ&hl=fr&pg=PA500#v=onepage&q&f=false ''Livre XXXVI.''], [https://books.google.fr/books?id=L249AAAAcAAJ&hl=fr&pg=PA513#v=onepage&q&f=false ''Chap. XVII.''], texte corrigé par [[w:Émile_Littré|M. É. Littré]], à partir de celui de [[w:Jean_Hardouin|Hardouin]], Librairie de Firmin-Didot et C<sup>ie</sup>, Paris, 1850<br />(également disponible une édition de 1877 sur [https://gallica.bnf.fr/ark:/12148/bpt6k282082c/f517.image ''Gallica''], ainsi qu’une édition de 1838 par [[w:Stéphane_Ajasson_de_Grandsagne|Ajasson de Grandsagne]] également sur [https://gallica.bnf.fr/ark:/12148/bpt6k1522394n/f179.item ''Gallica''])</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''XVII.''' [...] Le moyen de mesurer la hauteur des pyramides et autres édifices semblables, fut trouvé par '''Thalès''' de ''Milet'' : il mesura l’ombre à l’heure où elle est égale aux corps.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=L249AAAAcAAJ&hl=fr&pg=PP11#v=onepage&q&f=false <u>Histoire Naturelle de Pline ― Tome Second</u>], [https://books.google.fr/books?id=L249AAAAcAAJ&hl=fr&pg=PA500#v=onepage&q&f=false ''Livre XXXVI.''], [https://books.google.fr/books?id=L249AAAAcAAJ&hl=fr&pg=PA513#v=onepage&q&f=false ''Chap. XVII.''], texte corrigé par [[w:Émile_Littré|M. É. Littré]], à partir de celui de [[w:Jean_Hardouin|Hardouin]], Librairie de Firmin-Didot et C<sup>ie</sup>, Paris, 1850<br />(également disponible une édition de 1848 sur [https://remacle.org/bloodwolf/erudits/plineancien/livre36.htm ''Remacle''], sur [[s:Histoire_naturelle_(trad._Littré)/XXXVI|''wikisource'']] et une édition de 1877 sur [https://gallica.bnf.fr/ark:/12148/bpt6k282082c/f517.image ''Gallica''])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: center; margin: 0 2em;">Des découvertes astronomiques : part de chaque observateur dans la science.<br /><p style="text-align: justify; text-indent: 15px;">'''XVII.''' [...] '''Thalès''' découvrit le moyen de mesurer et les pyramides et toutes les hauteurs semblables par la mesure de l’ombre à l’instant où elle est égale au corps.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k1522394n/f9.item <u>Histoire Naturelle de Pline. Tome Vingtième</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k1522394n/f127.item ''Livre XXXVI.''], [https://gallica.bnf.fr/ark:/12148/bpt6k1522394n/f179.item ''chap. XVII.''], traduction nouvelle par M. [[w:Stéphane_Ajasson_de_Grandsagne|Ajasson de Grandsagne]], C. L. F. Panckoucke, Paris, 1838</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Flavius_Josèphe|'''Flavius Josèphe''']] [[#Flavius_Josèphe|<span id="Flavius_Josèphe_back"><sup>'''I'''</sup></span>]] == <p style="text-align: right;">([[w:37|37]]/[[w:38|38]], à [[w:Histoire_de_Jérusalem#Période_romaine_et_byzantine_(63_av._J.-C._-_638)|''Jérusalem'']] — vers [[w:100|100]], à [[w:Rome_antique|''Rome'']]) [[w:Ier_siècle|<sup>⏳</sup>]] [[s:Auteur:Flavius_Josèphe|<sup>📚</sup>]] <div style="text-align: justify; margin: 0 1em; text-indent: 15px">[[w:historiographe|Historiographe]] ''romain'' [[w:Juifs|''juif'']] d’origine [[w:Judée_(province romaine)|''judéenne'']], il participe activement au début de la ''première guerre judéo-romaine'' en tant que commandant militaire de ''Galilée'' contre les Romains, avant de se rendre à [[w:Vespasien|'''Vespasien''']] [[#Vespasien|<span id="Vespasien_back"><sup>'''II'''</sup></span>]] lors de la prise de la garnison juive de la forteresse de [[w:Jotapata|''Jotapata'']] en juillet 67, et de devenir intermédiaire, interprète et négociateur entre les ''romains'' et les ''Juifs'' lors du siège de ''Jérusalem'' conduit par '''Titus''' [[#Titus_back|<sup>⤴️</sup>]] en 70. Après la fin de la grande révolte ''judéenne'', en 71, il s’établit auprès de son protecteur à ''Rome'' où il obtient la [[w:citoyenneté_romaine|''citoyenneté romaine'']].</div> {{Boîte déroulante début|titre=NdA Flavius Josèphe|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Flavius_Josèphe_back|<span id="Flavius_Josèphe"><sup>I</sup></span>]] De son nom de naissance Joseph ben (fils de) Matthatias, de l’hébreu יוסף בן מתתיהו / Yossef [[wikt:en:יוסף#Hebrew|(en)]] ben [[wikt:en:בן#Noun|(en)]] Matityahou [[wikt:en:מתתיהו#Hebrew|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;">• de la troisième personne du singulier [[w:Jussif|''jussive'']], signifiant ainsi « peut-il ajouter », du verbe הוֹסִיף / hosíf [[wikt:en:הוסיף#Hebrew|(en)]], « 1. Ajouter (quelque chose) à (quelque chose d'autre). 2. (littéraire) Continuer (à faire quelque chose). 3. (archaïque) Coordonné avec un autre verbe pour indiquer que l’action de ce verbe "ajoute" d’une manière ou d’une autre. »;<br /><p style="margin: 0 2em; text-indent: 15px;">• du nom commun בֵּן / bén, « 1. Fils. 2. (ne produit plus de mot ou d’expression) Un descendant mâle direct. 3. Un mec, un garçon. 4. (n’est plus productif, état de construction) Possesseur de (connaissance, capacité, etc.). 5. (État construit) Utilisé pour exprimer l’âge d’un homme, d’un garçon ou le référent d’un nom masculin : âge, âgé. »;<br /><p style="margin: 0 2em; text-indent: 15px;">• de la contraction du nom commun מַתָּנַת / mataná [[wikt:en:מתנה#Hebrew|(en)]], « cadeau, présent, don »;<br /><p style="margin: 0 2em; text-indent: 30px;">➥ du verbe נתן / natán [[wikt:en:נתן#Verb|(en)]], « 1. Donner. 2. Autoriser, permettre, laisser. 3. (archaïque) Mettre, placer. 4. (archaïque, hébreu biblique) Se transformer en. »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ et du nom propre יהוה / YHWH [[wikt:en:יהוה#Hebrew|(en)]], « (Judaïsme) Tétragramme : mot en quatre lettres hébraïques utilisé comme nom [[wikt:ineffable#Français|''ineffable'']] de Dieu dans la Bible hébraïque, diversement rendu par Yahweh ou Jéhovah. »;<br /><p style="margin: 0 2em; text-indent: 15px;">Son tria nomina à l’obtention de sa ''citoyenneté romaine'' est {{Info|Titus|praenomen, nom individuel du citoyen romain}} {{Info|Flavius|nomen, nom de famille}} {{Info|Josephus|cognomen, surnom héréditaire, servant à distinguer les diverses branches d’une même gens}}, prenant ainsi le nom de son bienfaiteur :<br /><br /><p style="margin: 0 2em; text-indent: 15px;">[[#Vespasien_back|<span id="Vespasien"><sup>II</sup></span>]] [[w:Nom_romain|Tria Nomina]] en latin {{Info|Titus|praenomen, nom individuel du citoyen romain}} {{Info|Flavius|nomen, nom de famille}} {{Info|Vespasianus|cognomen, surnom héréditaire, servant à distinguer les diverses branches d’une même gens}};<br /><p style="margin: 0 2em; text-indent: 15px;">[[w:L%C3%A9gat_(Rome_antique)|''Légat'']] lors de la [[w:Conqu%C3%AAte_romaine_de_la_Grande-Bretagne|''conquête de la Bretagne en 43'']] et lors de la [[w:Premi%C3%A8re_guerre_jud%C3%A9o-romaine|''rébellion juive de 66'']] en [[w:Jud%C3%A9e_(province_romaine)|''Judée'']]. Fin décembre 69, il est couronné empereur par le [[w:S%C3%A9nat_romain|''Sénat'']] après la guerre civile de l’[[w:Ann%C3%A9e_des_quatre_empereurs|''année des quatre empereurs'']], et fonde la dynastie des [[w:Flaviens|''Flaviens'']].<br /><p style="text-align: right; margin: 0 2em;">(17 novembre [[w:9|9]], près de [[w:Reate|''Reate'']] dans la région centrale italienne du [[w:Latium|''Latium'']] — 23/24 juin [[w:79|79]], à la station thermale de [[w:Aquae_Cutiliae|''Aquae Cutiliae'']], à l’est de ''Reate'')<sup>[[w:Ier_siècle|⏳]]</sup><br/><br/></div> ''' {{Boîte déroulante fin}} === [[w:Contre_Apion|Contre Apion]] === <p style="text-align: right;">[[s:Contre_Apion|📚]] {| cellpadding="0" align="{{{align|right}}}" style="margin-left: 2em; width:40%; border-spacing:3px; text-align:center; background-color:#F8F9FA; border:2px solid #C8CCD1" |- | style="border:solid 1px #F8F9FA" | [https://archive.org/details/contreapiontexte0000jose/page/n156/mode/1up {{Info|'''Éditions & Manuscrits'''|Flavius Josèphe Contre Apion, Théodore Reinach & Léon Blum, 1930}}] |- style="font-size:8pt; line-height:10pt; vertical-align:middle" | align="center" | <div style="margin-right: 1em; padding:0 0 4px 0; text-align:justify;">{{{légende| * La traduction ''latine'' a été imprimée dès 1480 à [[w:Vérone#Époque_moderne|''Vérone'']] par '''Pierre Maufer''' [[w:en:Petrus_Maufer|(en)]]. L’édition de cette traduction, due à [[w:Sigismund_Gelenius|'''Sigismond Gelenius''']] (''Paris'', 1535), qui constitue la « [[w:Vulgate|Vulgate]] », présente un texte souvent « amélioré » de façon arbitraire. La seule édition critique est celle de '''Ch. Boysen''' (''Vienne'', 1898) qui fait partie du [[w:Corpus_scriptorum_ecclesiasticorum_latinorum|{{Info|''Corpus scriptorum ecclesiasticorum latinorum''|Le corpus des écrits ecclésiastiques latins}}]]. Elle repose principalement sur les manuscrits L(aurentianus LXVI, 2), B(odleianus Canonicianus 148), R(egius Parisinus 5049) de la I<sup>re</sup> classe, C(heltenhamensis Phillipicus 12311), P(arisinus 1615), Pa(rsinus 5054) de la seconde. * Le texte grec est édité pour la première fois dans l’édition complète de '''Josèphe''' à [[w:Bâle#XVIe_siècle|''Bâle'']], chez [[w:Johann_Froben|''Froben'']], en 1544 par [[w:Arnoldus_Arlenius|'''Arlenius''']] qui a peut-être fait usage du ''Schleusingensis'' (un des fils du Laurentianus), mais a introduit grand nombre de corrections tantôt heureuses, et tantôt arbitraires. Par la suite notre traité n’a guère été imprimé que comme partie intégrante d’éditions complètes des œuvres de '''Josèphe'''. Les plus importantes sont celles de '''E. Bernard''' (1700), de [[w:John_Hudson_(classiciste)|'''Hudson''']] (1720) — le premier qui ait utilisé L —, de [[w:Sigebert_Havercamp|'''Havercamp''']] (1726), simple compilateur, de [[w:Karl_Wilhelm_Dindorf|'''L. Dindorf''']] (1847), de [[w:Immanuel_Bekker|'''Imm. Bekker''']] (1856), tout à fait manquée. L’édition critique de '''Niese''' [[w:en:Benedikt_Niese|(en)]] (1889) est la base de tous les travaux ultérieurs, notamment des éditions de '''Naber''' (1896) et de [[w:Henry_St._John_Thackeray|'''H. St. J. Thackeray''']] (coll. Loeb, 1926 : il n’a encore paru que le ''C. Apion'', la ''Vita'' et le commencement de la ''Guerre'') qui ont pu profiter aussi des conjectures de '''Cobet''', de '''Holwerda''', et de '''Herwerden'''.}}}</div> |} <div style="text-align: justify; margin: 0 1em; text-indent: 15px">Dernière œuvre écrite par '''Flavius Josèphe''', vers [[w:93|93]], dont l’objectif est de répondre aux critiques qu’ont soulevées ses [[w:Antiquit%C3%A9s_juda%C3%AFques|''Antiquités judaïques'']], de défendre l’ancienneté du peuple ''juif'' et du [[w:Judaïsme#Judaïsme_antique|''judaïsme'']] (Livre I) et les accusations d’[[w:Apion_(grammairien)|'''Apion''']] [[#Apion|<span id="Apion_back"><sup>'''I'''</sup></span>]] (Livre II).</div> {{Boîte déroulante début|titre=NdA Apion|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Apion_back|<span id="Apion"><sup>I</sup></span>]] Du nom propre grec ancien [[wikt:Apion#Latin|Ἀπίων / Apíôn]]; <br/><br /><p style="margin: 0 2em; text-indent: 15px;">'''[[w:Grammaticus|''Grammairien'']] [[#grammairien|<span id="grammairien_back"><sup>II</sup></span>]] et [[w:Polygraphe_(auteur)|''polygraphe'']] [[#polygraphe|<span id="Grammairien_back"><sup>III</sup></span>]] ''grec'' d’Alexandrie.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] seconde moitié du [[w:Ier_siècle_av._J.-C.|I<sup>er</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]] — première moitié du [[w:Ier_siècle|I<sup>er</sup> siècle {{Info|EC|de l’Ère Commune}}]]) <br /><br /><p style="margin: 0 2em; text-indent: 15px;">'''[[#grammairien_back|<span id="grammairien"><sup>II</sup></span>]] Du nom commun latin grammaticus [[wikt:en:grammaticus#Latin|(en)]]; du nom commun grec ancien γραμματικός / grammatikós [[wikt:en:γραμματικός#Noun|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px">➥ du nom commun γρᾰ́μμᾰ / grámma [[wikt:en:γράμμα#Noun|(en)]], « 1. Ce qui est écrit, ce qui est dessiné. 2. Lettre. 3. (au pluriel) Alphabet. 4. Écriture, livre. »;<br /><p style="margin: 0 2em; text-indent: 30px">➥ du verbe γράφω / gráphō [[wikt:en:γράφω#Ancient_Greek|(en)]], « 1. (Homérique) égratigner, couper en dedans. 2. Dessiner, esquisser, peindre. 3. Écrire. 4. Écrire, proposer une loi. 5. ([[w:Diathèse#Moyen|''voix moyenne'']]) : • (''[[w:Réflexivité_(grammaire)|réflexif]] indirect'') Écrire pour soi, noter ; • Accuser, poursuivre. 6. ([[w:Conjugaison_latine|''passif parfait'']]) Être écrit, être sous forme écrite. »;<br /><p style="margin: 0 2em; text-indent: 30px">➥ + du suffixe nominal de résultat‎ -μα / -ma [[wikt:en:-μα#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px">➥ +‎ du suffixe adjectival -ῐκός / -ikós, de ou se rapportant à, de la manière de ; « -ique »;<br /><p style="margin: 0 2em; text-indent: 15px">Enseignant responsable de la deuxième étape du système éducatif traditionnel, après l’apprentissage de l’alphabet, la lecture et l’écriture, et l’initiation au calcul avec un abaque chez un ''magister ludi'' [[w:en:Ludi_magister|(en)]] et avant celle de l’art du discours chez un [[w:Rhétorique#Rhétorique_dans_l'Antiquité_grecque|''rhéteur'']]. Le travail du grammairien était d’enseigner la lecture, l’analyse de textes des poètes antiques tels qu’Homère, Tite-Live et Virgile, et la grammaire [https://archive.wikiwix.com/cache/index2.php?url=http%3A%2F%2Fwww.antiquite.ac-versailles.fr%2Feducatio%2Fedrom2.htm#federation=archive.wikiwix.com&tab=url {{Info|<sup>➕</sup>|« L’école du grammaticus », ac-Versailles}}] [https://philo-lettres.fr/latin/rome_vie-quotidienne/ecole-romaine/ {{Info|<sup>➕➕</sup>|« L’École dans l’antiquité romaine, philo-lettres}}]. <br /><br /><p style="margin: 0 2em; text-indent: 15px;">'''[[#polygraphe_back|<span id="polygraphe"><sup>III</sup></span>]] Du nom commun grec ancien [[wikt:polygraphe|πολύγραφος / polýgraphos]], « qui écrit beaucoup de sujets »;<br /><p style="margin: 0 2em; text-indent: 15px">➥ de l’adjectif πολῠ́ς / polús [[wikt:en:πολύς#Ancient_Greek|(en)]], « (de nombre, au pluriel) Beaucoup de : • (avec des noms de multitude) Grand ; • (de quantité, avec des noms de masse) beaucoup de ; • (rare, d'une personne) Grand, puissant ; • (de son) Fort ; • (attributivement, adverbial) Fortement, pleinement ; • (d'espace) Large, grand ; • (de distance) Loin ; • (de temps) Long, en retard. »;<br /><p style="margin: 0 2em; text-indent: 15px">➥ +‎ du verbe γράφω / gráphō [[wikt:en:γράφω#Ancient_Greek|(en)]], « 1. (Homérique) égratigner, couper en dedans. 2. Dessiner, esquisser, peindre. 3. Écrire. 4. Écrire, proposer une loi. 5. (''voix moyenne'') : • (''réflexif indirect'') Écrire pour soi, noter ; • Accuser, poursuivre. 6. (''passif parfait'') Être écrit, être sous forme écrite. »;<br /><p style="margin: 0 2em; text-indent: 15px;">Le terme semble avoir été employé au cours de l’Antiquité dans un sens différent de celui que nous l’entendons aujourd’hui, pas dans le sens de diversité mais, de façon restreinte, le fait de composer un grand nombre de textes [https://eriac.univ-rouen.fr/la-polygraphie-comme-norme/ {{Info|<sup>➕</sup>|Isabelle Gassino, Université de Rouen et Dimitri Kasprzyk, université de Brest, « Colloque "La polygraphie comme norme" », 16 et 17 novembre 2017.}}].'''<br/><br/></div> {{Boîte déroulante fin}} ==== Livre I ==== ===== <div style="text-align: center;">Chapitre II.</div> ===== <div style="text-align: justify; margin: 0 1em;">Témoignage de '''Thales''' comme : * l’un des premiers ''philosophes grecs'' ayant traité des choses célestes et divines ; * disciple des ''Égyptiens'' et des ''Chaldéens'' (premier témoignage) ; * auteur de court(s)/rare(s) ouvrages (supposément unanimement admis), que les ''Grecs'' considéreraient comme les plus anciens, et douteraient, selon '''Flavius Josèphe''', de leur authenticité.</div> :'''Texte latin''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">qui autem historias apud eos conscribere temptauerunt, id est hi, qui circa '''Cadmum''' ''Milesium'', et '''Acusilaus''' ''Argiuus'' et post hunc quicumque alii fuisse referuntur, paululum tempus ''Persicam'' apud ''Helladium'' militiam praecesserunt. sed etiam eos, qui de caelestibus et diuinis primitus apud ''Graecos philosophati'' sund, id est '''Pherecydem''' ''Syrum'' et '''Pythagoram''' et '''Thaletem''' omnes concorditer confidentur ''Aegyptiorum'' et ''Chaldaeorum'' fuisse discipulos et breuiter conscripsisse quae a ''Graecis'' omnium antiquissima iudicantur ita ut uix ea credant ab illis fuisse conscripta.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[[w:Corpus_scriptorum_ecclesiasticorum_latinorum|<u>Corpus scriptorum ecclesiasticorum latinorum</u>]], [https://verlag.oeaw.ac.at/produkt/flavii-iosephi-opera-ex-versione-latina-antiqua-pars-vi-de-iudaeorum-vetustate-sive-contra-apionem-libri-ii/601067?name=flavii-iosephi-opera-ex-versione-latina-antiqua-pars-vi-de-iudaeorum-vetustate-sive-contra-apionem-libri-ii&product_form=5107 <u>Tome XXXVII, Flavius Iosephus, Contra Apionem</u>], ''Livre I'', ''chap. II.'', ''l.13, 14'', p.64, 1898</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">Οἱ μέντοι τὰς ἱστορίας ἐπιχειρήσαντες συγγράφειν παρ' αὐτοῖς, λέγω δὲ τοὺς περὶ '''Κάδμον''' τε τὸν ''Μιλήσιον'' καὶ τὸν ''Ἀργεῖον'' '''Ἀκουσίλαον''' καὶ μετὰ τοῦτον εἴ τινες ἄλλοι λέγονται γενέσθαι, βραχὺ τῆς ''Περσῶν'' ἐπὶ τὴν ''Ἑλλάδα'' στρατείας τῷ χρόνῳ προύλαβον. Ἀλλὰ μὴν καὶ τοὺς περὶ τῶν οὐρανίων τε καὶ θείων πρώτους παρ' ''Ἕλλησι φιλοσοφήσαντας'', οἷον '''Φερεκύδην''' τε τὸν ''Σύριον'' καὶ '''Πυθαγόραν''' καὶ '''Θάλητα''', πάντες συμφώνως ὁμολογοῦσιν ''Αἰγυπτίων'' καὶ ''Χαλδαίων'' γενομένους μαθητὰς ὀλίγα συγγράψαι, καὶ ταῦτα τοῖς ''Ἕλλησιν'' εἶναι δοκεῖ πάντων ἀρχαιότατα καὶ μόλις αὐτὰ πιστεύουσιν ὑπ' ἐκείνων γεγράφθαι.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://remacle.org/bloodwolf/historiens/Flajose/Apion1gr.htm <u>Φλαίίου Ἰωσήπου, περὶ ἀρχαιότητος Ἰουδαίων</u>, ''λόγος α''], ''chap. II.'', ''l.13, 14'', 1898</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">Quant aux Grecs qui ont entrepris d’écrire l’histoire, comme [[w:Cadmos_de_Milet|'''Cadmos''' de ''Milet'']], [[w:Acousilaos|'''Acousilaos''' d’Argos]] et ceux qu’on cite après lui, ils n’ont vécu que peu de temps [[#Cadmos_NdT_LB|<span id="Cadmos_NdT_LB_back"><sup>1</sup></span>]] avant [[w:Guerres_médiques|''l’expédition des Perses contre la Grèce'']]. Mais bien certainement les premiers ''philosophes grecs'' qui aient traité des choses célestes et divines, comme [[w:Phérécyde_de_Syros|'''Phérécyde''' de ''Syros'']] [[#Phérécyde_de_Syros_NdT_LB|<span id="Phérécyde_de_Syros_NdT_LB_back"><sup>2</sup></span>]], '''Pythagore''' et '''Thalès'''[[#Thales_NdT_LB|<span id="Thales_NdT_LB_back"><sup>3</sup></span>]] furent, tout le monde s’accorde là-dessus, les disciples des ''Égyptiens'' et des ''Chaldéens'' avant de composer leurs courts ouvrages, et ces écrits sont aux yeux des ''Grecs'' les plus anciens de tous ; à peine même les croient-ils authentiques.</div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Cadmos_NdT_LB_back|<span id="Cadmos_NdT_LB"><sup>1.</sup></span>]] En réalité, Cadmos paraît avoir fleuri vers le milieu [[w:VIe_siècle_av._J.-C.|VI<sup>ème</sup> siècle]] [{{Info|AEC|Avant l’Ère Commune}}].''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Phérécyde_de_Syros_NdT_LB_back|<span id="Phérécyde_de_Syros_NdT_LB"><sup>2</sup></span>]] Seul texte qui attribue une origine égyptienne ou chaldéenne aux doctrines de Phérécyde de Syros. Cependant [[w:Theodor_Gomperz|Gompers]], [https://archive.org/details/bub_gb_QrfVAAAAMAAJ/page/n434/mode/1up Griechische Denker, I, 430], identifie ᾿Ογηνός avec l’Ouginna babylonien.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Thales_NdT_LB_back|<span id="Thales_NdT_LB"><sup>3</sup></span>]] On retrouve chez [[w:Apollonios_de_Tyane|Apollonios de Tyane]] ([[w:Jamblique|Jamblique]] [[#Jamblique_back|<sup>⤵️</sup>]], Vit. Pyth. [[#Vie_de_Pythagore_back|<sup>⤵️</sup>]], 12) et [[w:Plutarque|Plutarque]] [[#Plutarque_back|<sup>⤵️</sup>]] l’idée que Thalès de Milet fut disciple des Égyptiens ; l’adjonction des Chaldéens est propre Josèphe.''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/contreapiontexte0000jose/page/n6/mode/1up?view=theater <u>Flavius Josèphe, Contre Apion</u>], ''Livre I'', [https://archive.org/details/contreapiontexte0000jose/page/n49/mode/1up?view=theater&q=Thales ''chap. 2''], traduction du grec ancien par Léon Blum, agrégé des Lettres, professeur au lycée Janson-de-Sailly, texte établi et annotée par [[w:Théodore_Reinach|Théodore Reinach]] Membre de l’[[w:Institut_de_France|Institut]], professeur au Collège de France, 1930<br />(édition bilingue de 1911 également disponible [https://remacle.org/bloodwolf/historiens/Flajose/Apion1.htm ici])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: justify; margin: 0 2em;">Quant aux Grecs qui ont entrepris d’écrire l’histoire, comme '''Cadmos''' de ''Milet'', '''Acousilaos''' d’''Argos'' et ceux qu’on nomme après lui, ils n’ont vécu que peu de temps[2] avant l’expédition des ''Perses'' contre la ''Grèce''. [14]. De même, les premiers ''philosophes grecs'' qui aient traité des choses célestes et divines, comme '''Phérécyde''' de ''Syros''[3], '''Pythagore''' et '''Thalès'''[4] furent, tout le monde s’accorde là dessus, les disciples des ''Égyptiens'' et des ''Chaldéens'' avant de composer leurs rares ouvrages, et ces écrits sont aux yeux des ''Grecs'' les plus anciens de tous ; à peine même les croient-ils authentiques.</div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Cadmos_NdT_LB_back|<span id="Cadmos_NdT_LB"><sup>1.</sup></span>]] En réalité, Cadmos paraît avoir fleuri vers le milieu [[w:VIe_siècle_av._J.-C.|VI<sup>ème</sup> siècle]] [{{Info|AEC|Avant l’Ère Commune}}].''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Phérécyde_de_Syros_NdT_LB_back|<span id="Phérécyde_de_Syros_NdT_LB"><sup>2</sup></span>]] Seul texte qui attribue une origine égyptienne ou chaldéenne aux doctrines de Phérécyde de Syros. Cependant [[w:Theodor_Gomperz|Gompers]], [https://archive.org/details/bub_gb_QrfVAAAAMAAJ/page/n434/mode/1up Griechische Denker, I, 430], identifie ᾿Ογηνός avec l’Ouginna babylonien.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Thales_NdT_LB_back|<span id="Thales_NdT_LB"><sup>3</sup></span>]] On retrouve chez [[w:Apollonios_de_Tyane|Apollonios de Tyane]] ([[w:Jamblique|Jamblique]] [[#Jamblique_back|<sup>⤵️</sup>]], Vit. Pyth. [[#Vie_de_Pythagore_back|<sup>⤵️</sup>]], 12) et [[w:Plutarque|Plutarque]] [[#Plutarque_back|<sup>⤵️</sup>]] l’idée que Thalès de Milet fut disciple des Égyptiens ; l’adjonction des Chaldéens est propre Josèphe.''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Flavius Josèphe, De l’ancienneté du peuple juif (Contre Apion)</u>, ''Livre I'', [[s:Page:Flavius_Josephe_-_Leon_Blum_-_Contre_Apion,_Leroux,_Paris,_1902.djvu/17|''Chap. 2'']], traduction de Léon Blum, agrégé des lettres, professeur au lycée du Havre, sous la direction de [[w:Théodore_Reinach|Théodore Reinach]], 1902.</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div> </div> <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Plutarque|'''Plutarque''']] [[#Plutarque|<span id="Plutarque_back"><sup>'''I'''</sup></span>]] == <p style="text-align: right;">([[w:Circa|{{Info|''ca.''|Circa, locution latine que l’on emploie pour indiquer l’approximation d’une date}}]] [[w:45|45]]'' <sup>[[w:Ier_siècle|⏳]]</sup>'', à [[w:Chéronée|''Chéronée'']] en [[w:Béotie|''Béotie'']] — {{Info|''ca.''|Circa, locution latine que l’on emploie pour indiquer l’approximation d’une date}} [[w:125|125]]'' <sup>[[w:IIe_siècle|⏳]]</sup>)[[s:Auteur:Plutarque|<sup>📚</sup>]] [https://books.google.fr/books?id=qfl1xwEACAAJ&lpg=PA1067&hl=fr&pg=PA1097#v=onepage&q&f=false {{Info|<sup>🔍</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume Vb, §210 - Plutarque de Chéronée}}] [[Fichier:Plutarch at Delphi.jpg|vignette|<p style="text-align: justify; text-indent: 15px;">Buste probable de Plutarque du [[w:IIe_siècle|II<sup>ème</sup>]] ou [[w:IIIe_siècle|III<sup>ème</sup>]] siècles {{Info|EC|de l’Ère Commune}}, en marbre de [[w:Marbre_de_Paros|''Paros'']].<br /><p style="text-align: justify; text-indent: 15px;">Provenance : découvert lors de fouilles près de l’angle sud-est du [[w:Temple d'Apollon (Delphes)|''temple d’Apollon'']] de [[w:Delphes|''Delphes'']], au côté d'une [[w:Fichier:Plutarch_stele_inscription_100_AD,_AM_of_Delphi_4070060092.jpg|''stèle'']] portant une inscription gravée : ΔΕΛΦΟΙ ΧΑΙΡΩΝΕΥΣΙΝ ΟΜΟΥ ΠΛΟΥΤΑΡΧΟΝ ΕΘΗΚΑΝ ΤΟΙΣ ΑΜΦΙΚΤΥΟΝΩΝ ΔΟΓΜΑΣΙ ΠΕΙΘΟΜΕΝΟΙ — Les ''Delphiens'', avec les ''Chéronéens'', dédièrent ce(tte image de) Plutarque, suivant les préceptes de l’[[w:Amphictyonie|''Amphictyonie'']].<br /><p style="text-align: justify; text-indent: 15px;">Exposition : Salle XIV, [[w:Mus%C3%A9e_arch%C3%A9ologique_de_Delphes|''Musée archéologique de Delphes'']].]] <div style="text-align: justify; margin: 0 1em; text-indent: 15px">Biographe, philosophe et moraliste grec, auteur d’une œuvre importante, comportant un ensemble varié de traités et de dialogues consacrés à des questions de philosophie morale, mais abordant aussi des sujets littéraires, politiques, scientifiques, religieux.</div> {{Boîte déroulante début|titre=NdA Plutarque|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Plutarque_back|<span id="Plutarque"><sup>I</sup></span>]] Du nom propre grec ancien πλούταρχος / ploútarkhos [[wikt:en:Πλούταρχος#Ancient_Greek|(en)]], « maître des richesses » ; <br /><p style="margin: 0 2em; text-indent: 15px">➥ du nom commun πλοῦτος / ploûtos [[wikt:en:πλοῦτος#Ancient_Greek|(en)]], « richesses » ;<br /><p style="margin: 0 2em; text-indent: 15px">➥ +‎ du nom commun ἀρχός / arkhós, « souverain, chef, prince »)'''<br/><br/></div> {{Boîte déroulante fin}} {{Boîte déroulante début|titre=Remarque|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>''' Dans la ''Vie de [[w:Lycurgue_(législateur)|Lycurgue]]'' et la ''Vie d’Agis et Cléomène'' (''Vies parallèles''), et le traité ''Un philosophe doit surtout converser avec les princes'' (''Œuvres morales''), il est fait mention d’un Thalès : il s’agit de [[w:Thalétas|Thalétas]], aussi appelé Thalès de [[w:Crète|''Crète'']], un musicien et poète, originaire de la cité de [[w:Gortyne|''Gortyne'']] en ''Crète'', et actif à la fin du [[w:VIIIe_siècle_av._J.-C.|VIII<sup>ème</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]] et au début du siècle suivant.'''<br/><br/></div> {{Boîte déroulante fin}} === [[w:Vies_parallèles|Vies parallèles]] [[#Vies_parallèles|<span id="Vies_parallèles_back"><sup>'''I'''</sup></span>]] === <div style="text-align: center; margin: 0 1em;">Recueil de 50 biographies de grands hommes de l’histoire, dont 46 présentées par paires : un ''Grec'' mis en parallèle avec un ''Romain'' [https://books.google.fr/books?id=qfl1xwEACAAJ&lpg=PA1059&hl=fr&pg=PA1115#v=onepage&f=false {{info|<sup>🔍</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume Vb, §210 - Plutarque de Chéronée, pp.1115 - 1119, (7) Le Moraliste et l’entreprise des Vies Parallèles}}]. {{Boîte déroulante début|titre=NdA Vies parallèles|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Vies_parallèles_back|<span id="Vies_parallèles"><sup>I</sup></span>]] En grec ancien Βίοι Παράλληλοι / Bíoi Parállêloi :<br /><p style="margin: 0 2em; text-indent: 15px;">➥ Du nom commun βῐ́ος / bĭ́os [[wikt:en:βίος#Ancient_Greek|(en)]], « Vie (souvent avec une connotation positive : la vie heureuse) » ;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ De l’adjectif πᾰρᾰ́λληλος / părắllēlos [[wikt:en:παράλληλος#Ancient_Greek|(en)]], « 1. À côté l’un de l’autre, côte à côte. 2. Parallèle à ou avec. 3. Pléonastique, redondant.<br /><p style="margin: 0 2em; text-indent: 30px;">➥ du préfixe παρα- / para- [[wikt:en:παρα-#Ancient_Greek|(en)]], « 1. À côté. 2. Contrairement à. » ;<br /><p style="margin: 0 2em; text-indent: 45px;">➥ de la préposition πᾰρᾰ́ / părắ [[wikt:en:παρά#Ancient_Greek|(en)]], « 1. [avec génitif] : • De ; • À cause de. 2. [avec datif] : • À, à côté de, près de. 3. [avec accusatif] : • Contraire à ; • À côté de, près de (avec les verbes de venir ou d’aller ; avec les verbes de mouvement passé ; avec les verbes de frapper ou de blesser) » ;<br /><p style="margin: 0 2em; text-indent: 30px;">➥ +‎ du pronom ᾰ̓λλήλων / ăllḗlōn [[wikt:en:ἀλλήλων#Ancient_Greek|(en)]], « Se rapportant à un sujet pluriel et exprimant une action bilatérale : l’un de l’autre, l’un à l’autre, l’un l’autre, l’un l’autre, mutuellement, réciproquement. » ;<br /><p style="margin: 0 2em; text-indent: 45px;">➥ À partir d’expressions telles que ᾰ̓́λλος ᾰ̓́λλον / ắllos ắllon, ᾰ̓́λλοι ᾰ̓́λλους / ắlloi ắllous, « les uns les autres », avec perte de λ soit par dissimilation, soit par allongement de α, ainsi que restauration de la deuxième voyelle initiale ή / ḗ.'''<br/><br/></div> {{Boîte déroulante fin}} ==== Vie de [[w:Solon|'''Solon''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Solon|<sup>🔄</sup>]] ==== <div style="text-align: center; margin: 0 1em;">Biographie de '''Solon''', qui précède celle de [[w:Publius_Valerius_Publicola_(consul_en_-509)|'''Publicola''']] [[#Publicola|<span id="Publicola_back"><sup>'''I'''</sup></span>]], et avec laquelle '''Plutarque''' la compare.</div> {{Boîte déroulante début|titre=NdA Vie de Solon|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Publicola_back|<span id="Publicola"><sup>I</sup></span>]] [[w:Nom_romain|Tria Nomina]] en latin {{Info|Publius|praenomen, nom individuel du citoyen romain}} {{Info|Valerius|nomen, nom de famille}} {{Info|Publicola ou Poplicola|cognomen, surnom héréditaire, servant à distinguer les diverses branches d’une même gens}}, « celui qui prend soin de l’armée. »[https://academic.oup.com/bics/advance-article/doi/10.1093/bics/qbaf002/8117642?login=false {{Info|<sup>🔍</sup>|M. Gallo, « Misinterpreting a compound name. The origin of the agnomen Publicola in Dionysius of Halicarnassus and Plutarch », Bulletin of the Institute of Classical Studies,‎ 22 avril 2025}}].<br /><p style="margin: 0 2em; text-indent: 15px">[[w:Consul_(Rome_antique)|Consul]] de la [[w:république_romaine|''République Romaine'']], à quatre reprises : en [[w:-509|-509]], [[w:-508|-508]], [[w:-507|-507]] et [[w:-504|-504]], et l’un des instaurateurs légendaires de la ''République Romaine'' en -509, suite au viol et au suicide de [[w:Lucrèce_(dame_romaine)|Lucrèce]], une femme aristocratique ''romaine'', par [[w:Sextus_Tarquin|Sextus Tarquin]], le fils du dernier [[w:Roi_de_Rome|roi de ''Rome'']] [[w:Tarquin_le_Superbe|Tarquin le Superbe]].<br /><p style="text-align: right; margin: 0 2em;">(date et lieu de naissance inconnu.e.s — [[w:-503|-503]], soit sur le champ de bataille pendant les [[w:Guerres_romano-sabelliennes|''guerres romano-sabelliennes'']], soit de maladie)<sup>[[w:VIe_siècle_av._J.-C.|⏳]]</sup> '''<br/><br/></div> {{Boîte déroulante fin}} ===== <div style="text-align: center;">Chapitre II.</div> ===== ====== <div style="text-align: center;">Paragraphe III.</div> ====== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage de '''Thalès''' ''commerçant''.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''III.''' Κωλύει δὲ οὐδὲν τὸν ἀγαθὸν καὶ πολιτικὸν ἄνδρα μήτε τῶν περιττῶν τὴν κτῆσιν ἐν σπουδῇ τίθεσθαι μήτε τῆς χρείας τῶν ἀναγκαίων καὶ ἱκανῶν καταφρονεῖν. Ἐν δὲ τοῖς τότε χρόνοις, καθ' Ἡσίοδον, ἔργον οὐδὲν ἦν ὄνειδος, οὐδὲ τέχνη διαφορὰν ἔφερεν, ἐμπορία δὲ καὶ δόξαν εἶχεν οἰκειουμένη τὰ βαρβαρικὰ καὶ προξενοῦσα φιλίας βασιλέων καὶ πραγμάτων ἐμπείρους ποιοῦσα πολλῶν. Ἔνιοι δὲ καὶ πόλεων οἰκισταὶ γεγόνασι μεγάλων, ὡς καὶ Μασσαλίας Πρῶτις ὑπὸ Κελτῶν τῶν περὶ τὸν Ῥοδανὸν ἀγαπηθείς. Καὶ Θαλῆν δέ φασιν ἐμπορίᾳ χρήσασθαι καὶ Ἱπποκράτην τὸν μαθηματικόν, καὶ Πλάτωνι τῆς ἀποδημίας ἐφόδιον ἐλαίου τινὸς ἐν Αἰγύπτῳ διάθεσιν γενέσθαι.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://remacle.org/bloodwolf/historiens/Plutarque/solon.htm <u>Plutarque, Vie de Solon</u>], ''chap. II'', ''§3'', traduction par [[w:Dominique_Ricard|Dominique Ricard]], 1844<br />(également disponible une édition de 1853 [https://remacle.org/bloodwolf/historiens/Plutarque/solonpierrron.htm ici] et de 1862 [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f16.item là])</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 390px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''III.''' Mais rien n’empêche l’homme de bien, le citoyen dévoué à son pays, de garder un juste milieu : il peut ne point s’attacher à la poursuite du superflu, sans pour cela mépriser le nécessaire et ce qui suffit à ses besoins.<br />Dans ce temps-là, pour parler comme [[w:Hésiode|'''Hésiode''']] [[#Hésiode|<span id="Hésiode_back"><sup>'''I'''</sup></span>]] [[#Hésiode_NdT_AP|<span id="Hésiode_NdT_AP_back"><sup>1</sup></span>]], il n’y avait pas de travail qui fût honteux; aucun art ne mettait de différence entre les hommes : le négoce surtout était honoré, qui met en possession des avantages dont jouissent les étrangers, gagne l’amitié des rois, et donne une grande expérience. On a même vu des trafiquants fonder de grandes villes : ainsi [[w:Mythe_fondateur_de_Marseille|'''Protis''']] bâtit [[w:Marseille_antique|''Marseille'']], après s'être concilié l’amitié des ''Gaulois'' qui habitent les bords du [[w:Rhône#Histoire|''Rhône'']]. '''Thales''' se livra, dit-on, au négoce, ainsi qu’[[w:Hippocrate_de_Chios|'''Hippocrate''']] [[#Hippocrate|<span id="Hippocrate_back"><sup>'''II'''</sup></span>]] le mathématicien[[#Hippocrate_NdT_AP|<span id="Hippocrate_NdT_AP_back"><sup>2</sup></span>]] ; et [[w:Platon|'''Platon''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Platon|<sup>🔄</sup>]] vendit de l’huile en [[w:Basse_Époque|''Égypte'']] , pour fournir aux frais de son voyage.</div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Hésiode_NdT_AP_back|<span id="Hésiode_NdT_AP"><sup>1.</sup></span>]] Œuvres et Jours, vers 309.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Hippocrate_NdT_AP_back|<span id="Hippocrate_NdT_AP"><sup>2</sup></span>]] Cet Hippocrate n’est point connu d’ailleurs.''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/viesdeshommesill01plut/page/n6/mode/1up?view=theater <u>Vie des Hommes Illustres de Plutarque</u>], [https://archive.org/details/viesdeshommesill01plut/page/182/mode/1up?view=theater ''Solon''], ''Chap. II'', ''§3'', [https://archive.org/details/viesdeshommesill01plut/page/184/mode/1up?view=theater p.184], traduit par [[w:Alexis_Pierron|Alexis Pierron]], professeur au lycée Louis-le-Grand, 1877<br />(également disponible une édition de 1853 [[s:Vies_des_hommes_illustres/Solon|ici]])</div> {{Boîte déroulante début|titre=NdA trad. par Alexis Pierron de 1877|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Hésiode_back|<span id="Hésiode"><sup>I</sup></span>]] Du nom propre grec ancien Ἡσῐ́οδος / Hēsĭ́odos [[wikt:en:Ἡσίοδος#Ancient_Greek|(en)]].<br /><p style="margin: 0 2em; text-indent: 15px">Berger sur les pentes du Mont [[w:Mont_Hélicon|Hélicon]] et un des plus grands poètes grecs. Il s’agit plus précisément d’un ''aède'' (il « chante » ses vers avec sa lyre) et un ''rhapsode'' (il « coud » des chants entre eux)[https://odysseum.eduscol.education.fr/hesiode-un-des-premiers-poetes-grecs {{Info|<sup>🔍</sup>|Hésiode, un des premiers poètes grecs - Odysseum, la maison numérique des Humanités}}]. <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Hippocrate_back|<span id="Hippocrate"><sup>II</sup></span>]] Du nom propre grec ancien Ῐ̔πποκρᾰ́της / Hĭppokrắtēs [[wikt:en:Ἱπποκράτης#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px">➥ du nom commun ῐ̔́ππος / hĭ́ppos [[wikt:en:ἵππος#Ancient_Greek|(en)]], « cheval »;<br /><p style="margin: 0 2em; text-indent: 15px">➥ + du nom commun‎ κρᾰ́τος / krắtos [[wikt:en:κράτος#Ancient_Greek|(en)]], « 1. Puissance, force. 2. Acte de force, acte de bravoure. 3. (au pluriel) Actes de violence. 4. Domination, pouvoir. »;<br /><p style="margin: 0 2em; text-indent: 15px">➥ +‎ du suffixe nominal -ης / -ēs.<br /><p style="margin: 0 2em; text-indent: 15px"> Mathématicien (géomètre) et astronome « para-pythagoricien », dont l’œuvre ne nous est pas parvenue.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] milieu du [[w:Ve_siècle_av._J.-C.|V<sup>ème</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]]) [https://books.google.fr/books?id=DrvWAAAAMAAJ&newbks=1&newbks_redir=0&lpg=PA764&vq=Hippocrate&dq=bibliogroup%3A%22Dictionnaire%20des%20philosophes%20antiques%22&hl=fr&pg=PA764#v=onepage&q&f=true {{Info|<sup>🔍</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume III, §151 - Hippocrate de Chios}}]'''<br/><br/></div> {{Boîte déroulante fin}} <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: center; margin: 0 2em;">'''II. Dans sa jeunesse il se livre au commerce maritime; la modicité de sa fortune et son goût pour la sagesse l’y décident. Faveur du commerce à cette époque ; grands noms qui l’ont illustré.'''<br /><br /><p style="text-align: justify; text-indent: 15px;">Mais rien n’empêche qu’un homme de bien, un sage politique tienne à cet égard un juste milieu, et que sans rechercher des richesses superflues, il ne méprise pas celles qui sont nécessaires et qui suffisent. Dans ce temps-là, comme dit [[w:Hésiode|'''Hésiode''']], aucun travail n’était regardé comme honteux; aucun art ne mettait de différence entre les hommes. Le commerce maritime surtout était honorable; il ouvrait des communications utiles avec les nations étrangères, procurait des alliances avec les rois, et donnait une grande expérience. On a même vu des commerçants fonder de grandes villes. Ainsi '''Protus''' gagna l’amitié des Gaulois qui habitaient les bords du ''Rhône'', et bâtit ''Marseille''. '''Thalès''' et '''Hippocrate''' le mathématicien firent aussi le commerce ; et '''Platon''' vendit de l’huile en ''Égypte'' pour fournir aux frais de son voyage.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f7.item <u>Plutarque, Vie de Solon</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f16.item ''chap. II''], traduction correcte et précédée du texte grec, par une société de professeurs et d’helléniste, 1862<br />(également disponible une édition de 1844 [https://remacle.org/bloodwolf/historiens/Plutarque/solon.htm#1a ici] et de 1829 [[s:Les_Vies_des_hommes_illustres/Vie_de_Solon|là]])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Mais rien n’empêche l’homme de-bien et l’homme politique ni se mettre en souci (rechercher) l’acquisition des choses superflues, ni mépriser l’usage des choses nécessaires et suffisantes. Or dans les temps d’alors, selon '''Hésiode''', aucun travail n’était sujet-de-honte, ni aucun métier n’apportait de différence entre les citoyens mais même le commerce-maritime avait de la gloire, rendant-amies les nations-barbares, et procurant des amitiés de rois, et faisant les hommes expérimentés d’affaires nombreuses. Et quelques-uns aussi sont devenus fondateurs de grandes villes, comme aussi le '''Protus''' de ''Marseille'' ayant été aimé par les ''Celtes'' ceux autour du ''Rhône''. Et on dit aussi '''Thalès''', avoir fait-usage du commerce-maritime et '''Hippocrate''' le mathématicien, et la vente d'une certaine huile en ''Égypte'' avoir été pour '''Platon''' ressource du voyage.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f7.item <u>Plutarque, Vie de Solon</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f16.item ''chap. II''], traduction littérale et juxtalinéaire présentant le mot à mot français en regard des mots grecs correspondants, par une société de professeurs et d’helléniste, 1862</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ====== <div style="text-align: center;">Paragraphe IV.</div> ====== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage de la sagesse de '''Thalès''' en ''philosophie naturelle''</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''IV.''' Φιλοσοφίας δὲ τοῦ ἠθικοῦ μάλιστα τὸ πολιτικόν, ὥσπερ οἱ πλεῖστοι τῶν σοφῶν, ἠγάπησεν. Ἐν δὲ τοῖς φυσικοῖς ἁπλοῦς ἐστι λίαν καὶ ἀρχαῖος, ὡς δῆλον ἐκ τούτων· [...].<br /><p style="text-indent: 15px">Καὶ ὅλως ἔοικεν ἡ Θάλεω μόνου σοφία τότε περαιτέρω τῆς χρείας ἐξικέσθαι τῇ θεωρίᾳ· τοῖς δὲ ἄλλοις ἀπὸ τῆς πολιτικῆς ἀρετῆς τοὔνομα τῆς σοφίας ὑπῆρξε.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://remacle.org/bloodwolf/historiens/Plutarque/solon.htm <u>Plutarque, Vie de Solon</u>], ''chap. II'', ''§4'', traduction par [[w:Dominique_Ricard|Dominique Ricard]], 1844<br />(également disponible une édition de 1853 [https://remacle.org/bloodwolf/historiens/Plutarque/solonpierrron.htm ici] et de 1862 [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f20.item là])</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 390px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''IV.''' Il s’attacha, comme presque tous les sages d’alors, à cette partie de la philosophie morale qui traite de la politique. Pour la philosophie naturelle, il en était aux rudiments, et aux notions du vieux temps sans plus; [...].<br /><p style="text-indent: 15px;">Aussi bien n’y eut-il, en somme, que '''Thalès''' dont la science dépassât alors les notions d’un usage vulgaire : tous les autres ne durent qu’à leurs connaissances politiques leur réputation de sagesse.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/viesdeshommesill01plut/page/n6/mode/1up?view=theater <u>Vie des Hommes Illustres de Plutarque</u>], [https://archive.org/details/viesdeshommesill01plut/page/182/mode/1up?view=theater ''Solon''], ''Chap. II'', ''§4'', [https://archive.org/details/viesdeshommesill01plut/page/185/mode/1up?view=theater p.185], traduit par [[w:Alexis_Pierron|Alexis Pierron]], professeur au lycée Louis-le-Grand, 1877<br />(également disponible une édition de 1853 [[s:Vies_des_hommes_illustres/Solon|ici]])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">A l’exemple des sages de son temps, il cultiva principalement cette partie de la morale qui traite de la politique. Il n’avait en physique que des connaissances très-superficielles, et en était aux premiers éléments de cette science, [...].<br/><p style="text-indent: 15px">En général '''Thalès''' fut, de tous les sages d’alors, le seul qui porta au delà des besoins de la vie la théorie des sciences ; tous les autres ne durent qu’à leurs connaissances politiques leur réputation de sagesse.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f7.item <u>Plutarque, Vie de Solon</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f20.item ''chap. II''], traduction correcte et précédée du texte grec, par une société de professeurs et d’helléniste, 1862<br />(également disponible une édition de 1844 [https://remacle.org/bloodwolf/historiens/Plutarque/solon.htm#1a ici] et de 1829 [[s:Les_Vies_des_hommes_illustres/Vie_de_Solon|là]])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Mais de la partie morale de la philosophie il embrassa surtout la partie politique, comme la plupart des sages d’alors. Mais dans les sciences physiques il est extrêmement simple (ignorant) et primitif, [...]. Et en-un-mot la science de '''Thalès''' seul paraît s’être avancée alors par la théorie plus loin que le besoin ; et le nom de la science a appartenu aux autres par-suite des qualités politiques.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f7.item <u>Plutarque, Vie de Solon</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f21.item ''chap. II''], traduction littérale et juxtalinéaire présentant le mot à mot français en regard des mots grecs correspondants, par une société de professeurs et d’helléniste, 1862</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ====== <div style="text-align: center;">Paragraphe V.</div> ====== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Version alternative du récit de la coupe de [[w:Bathyclès_de_Magnésie|'''Bathyclès''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Bathyclès_back|<sup>🔄</sup>]] par [[w:Callimaque_de_Cyrène|'''Callimaque''']] de [[w:Cyrène|''Cyrène'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Callimaque_back|<sup>🔄</sup>]].</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''V.''' Γενέσθαι δὲ μετ' ἀλλήλων ἔν τε Δελφοῖς ὁμοῦ λέγονται καὶ πάλιν ἐν Κορίνθῳ, Περιάνδρου σύλλογόν τινα κοινὸν αὐτῶν καὶ συμπόσιον κατασκευάσαντος. Ἔτι δὲ μᾶλλον εἰς ἀξίωμα καὶ δόξαν αὐτοὺς κατέστησεν ἡ τοῦ [[w:τρίπους#Grec_ancien|'''τρίποδος''']] περίοδος καὶ διὰ πάντων ἀνακύκλησις καὶ ἀνθύπειξις μετ' εὐμενείας φιλοτίμου γενομένη. Κῴων γάρ, ὥς φασι, καταγόντων σαγήνην, καὶ ξένων ἐκ Μιλήτου πριαμένων τὸν βόλον οὔπω φανερὸν ὄντα, χρυσοῦς ἐφάνη τρίπους ἑλκόμενος, ὃν λέγουσιν Ἑλένην πλέουσαν ἐκ Τροίας αὐτόθι καθεῖναι χρησμοῦ τινος ἀναμνησθεῖσαν παλαιοῦ. Γενομένης δὲ τοῖς ξένοις πρῶτον ἀντιλογίας πρὸς τοὺς ἁλιέας περὶ τοῦ τρίποδος, εἶτα τῶν πόλεων ἀναδεξαμένων τὴν διαφορὰν ἄχρι πολέμου προελθοῦσαν, ἀνεῖλεν ἀμφοτέροις ἡ Πυθία τῷ σοφωτάτῳ τὸν τρίποδα ἀποδοῦναι. Καὶ πρῶτον μὲν ἀπεστάλη πρὸς Θαλῆν εἰς Μίλητον, ἑκουσίως τῶν Κῴων ἑνὶ δωρουμένων ἐκείνῳ περὶ οὗ πρὸς ἅπαντας ὁμοῦ Μιλησίους ἐπολέμησαν. Θάλεω δὲ Βίαντα σοφώτερον ἀποφαίνοντος αὑτοῦ πρὸς ἐκεῖνον ἧκεν· ἀπ' ἐκείνου δ' αὖθις ἀπεστάλη πρὸς ἄλλον ὡς σοφώτερον. Εἶτα περιϊὼν καὶ ἀναπεμπόμενος οὕτως ἐπὶ Θαλῆν τὸ δεύτερον ἀφίκετο, καὶ τέλος εἰς Θήβας ἐκ Μιλήτου κομισθεὶς τῷ Ἰσμηνίῳ Ἀπόλλωνι καθιερώθη. Θεόφραστος δέ φησι,πρῶτον μὲν εἰς Πριήνην Βίαντι τὸν τρίποδα πεμφθῆναι, δεύτερον δ' εἰς Μίλητον Θαλῇ Βίαντος ἀποπέμψαντος· οὕτω δὲ διὰ πάντων πάλιν εἰς Βίαντα περιελθεῖν, τέλος δὲ εἰς Δελφοὺς ἀποσταλῆναι. Ταῦτα μὲν οὖν ὑπὸ πλειόνων τεθρύληται, πλὴν ὅτι τὸ δῶρον ἀντὶ τοῦ τρίποδος οἱ μὲν φιάλην ὑπὸ Κροίσου πεμφθεῖσαν, οἱ δὲ ποτήριον Βαθυκλέους ἀπολιπόντος εἶναι λέγουσιν.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://remacle.org/bloodwolf/historiens/Plutarque/solon.htm <u>Plutarque, Vie de Solon</u>], ''chap. II'', ''§5'', traduction par [[w:Dominique_Ricard|Dominique Ricard]], 1844<br />(également disponible une édition de 1853 [https://remacle.org/bloodwolf/historiens/Plutarque/solonpierrron.htm ici] et de 1862 [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f22.item là])</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 390px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''V.''' On raconte que les sept sages se réunirent une fois à [[w:Delphes|''Delphes'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Delphes_back|<sup>🔄</sup>]], et une autre fois à [[w:Histoire_de_Corinthe_dans_l%27Antiquité|''Corinthe'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Corinthe_back|<sup>🔄</sup>]], où [[w:Périandre|'''Périandre''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Périandre_back|<sup>🔄</sup>]] les avait convoqués pour leur offrir un banquet. Rien ne contribua tant à leur réputation et à leur gloire, que le renvoi qu’ils se firent successivement l’un à l’autre du trépied d’or, et l’honorable humilité avec laquelle ils refusèrent le prix tour à tour. Des hommes de [[w:Kos_(Dodécanèse)#Kos_à_l'époque_hellénistique|''Cos'']] [[#Cos|<span id="Cos_back"><sup>'''I'''</sup></span>]] venaient, dit-on, de jeter leur filet en mer : des étrangers de ''Milet'' achetèrent le coup, avant que les pêcheurs y eussent regardé. Il se trouva, dans le filet, un trépied d’or qu’[[w:Hélène_(mythologie)|'''Hélène''']] [[#Hélène|<span id="Hélène_back"><sup>'''II'''</sup></span>]], à ce qu’on prétend, pour obéir à un ancien oracle, avait jeté dans la mer à son retour de [[w:Troie|''Troie'']] [[#Troie|<span id="Troie_back"><sup>'''III'''</sup></span>]]. Ce fut un sujet de débat, d’abord entre les pêcheurs et les étrangers, ensuite entre les deux villes, qui prirent parti dans la querelle : la guerre allait s’allumer, lorsque la [[w:Pythie|''Pythie'']] [[#Pythie|<span id="Pythie_back"><sup>'''IV'''</sup></span>]], que les deux partis avaient consultée, commanda de donner le trépied au plus sage. On l’envoya d’abord à ''Milet'', pour '''Thalès''', et ceux de ''Cos'' cédèrent sans peine à un seul particulier ce qu’ils allaient disputer par les armes à tous les ''Milésiens'' ensemble. '''Thalès''' déclara que [[w:Bias_de_Priène|'''Bias''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Bias_back|<sup>🔄</sup>]] était plus sage que lui, et le lui fit passer. '''Bias''', avec la même modestie, le fit passer à un autre; et le trépied, après avoir été envoyé successivement à tous les sept, revint une seconde fois à '''Thalès'''. Enfin, il fut transporté de ''Milet'' à [[w:Thèbes_(Grèce)|''Thèbes'']] [[#Thèbes|<span id="Thèbes_back"><sup>'''V'''</sup></span>]], et consacré à Apollon [[w:en:Ismenus|''Isménien'']]. Cependant [[w:Théophaste|'''Théophaste''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Théophaste_back|<sup>🔄</sup>]] dit qu’on envoya le trépied d’abord à '''Bias''', dans ''Priène'' ; que '''Bias''' le fit porter à '''Thalès''' ; qu’après avoir passé alternativement chez tous les sages, il revint à '''Bias''', et qu’il finit par être envoyé à ''Delphes''. Telle est la tradition commune : seulement quelques-uns prétendent qu’il s’agissait de décerner non point un trépied, mais un vase que [[w:Crésus|'''Crésus''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Crésus_back|<sup>🔄</sup>]] avait envoyé ; et, suivant d’autres, c’était une coupe, héritage de '''Bathyclès'''.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/viesdeshommesill01plut/page/n6/mode/1up?view=theater <u>Vie des Hommes Illustres de Plutarque</u>], [https://archive.org/details/viesdeshommesill01plut/page/182/mode/1up?view=theater ''Solon''], ''Chap. II'', ''§5'', [https://archive.org/details/viesdeshommesill01plut/page/185/mode/1up?view=theater p.185], traduit par [[w:Alexis_Pierron|Alexis Pierron]], professeur au lycée Louis-le-Grand, 1877<br />(également disponible une édition de 1853 [[s:Vies_des_hommes_illustres/Solon|ici]])</div> {{Boîte déroulante début|titre=NdA trad. par Alexis Pierron de 1877|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Cos_back|<span id="Cos"><sup>I</sup></span>]] Du nom propre grec ancien Κῶς / Kôs [[wikt:en:Κῶς#Ancient_Greek|(en)]] ;<br /><p style="margin: 0 2em; text-indent: 15px">Île grecque l’archipel du [[w:Dodécanèse|''Dodécanèse'']], au Sud-Est de la [[w:Mer_Égée|''mer Égée'']], au large des côtes ''turques''. <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Hélène_back|<span id="Hélène"><sup>II</sup></span>]] Du nom propre grec ancien Ἑλένη / Helénē [[wikt:en:Ἑλένη#Ancient_Greek|(en)]] ;<br /><p style="margin: 0 2em; text-indent: 15px">Fille de [[w:Zeus|Zeus]] et de [[w:Léda (mythologie)|Léda]], considérée comme la plus belle femme du monde, uniquement surpassée par la déesse [[w:Aphrodite|Aphrodite]]. Elle est mariée à [[w:Ménélas|Ménélas]], roi de [[w:Sparte|Sparte]], et est enlevée par [[w:Pâris|Pâris]], prince [[w:Troie|''troyen'']] [[#Troie|<sup>'''III'''</sup>]], ce qui déclencha la [[w:guerre de Troie|guerre de Troie]] qui opposa ''Grecs'' et ''Troyens''. <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Troie_back|<span id="Troie"><sup>III</sup></span>]] Du nom propre grec ancien Τροίᾱ / Troíā [[wikt:en:Τροία#Ancient_Greek|(en)]] ; [[w:Troie#Toponymie|''toponymie incertaine'']] ;<br /><p style="margin: 0 2em; text-indent: 15px"> Cité semi-légendaire, située sur la colline d’''[[w:site archéologique de Troie|{{lang|tr|Hisarlık}}]]'', à l’entrée de l’''[[w:Hellespont|Hellespont]]'', non loin de la ''[[w:mer Égée|mer Égée]]'', au nord-ouest de la ''péninsule anatolienne'', dans la région ''[[w:Troade|Troade]]'' en ''[[w:Asie Mineure|Asie Mineure]]''.<br /><p style="margin: 0 2em; text-indent: 15px"> Le site a fait l’objet de nombreuses campagnes de fouilles, à la suite de celles entreprises par [[w:Heinrich Schliemann|Heinrich Schliemann]] en 1870, ponctuées par des découvertes fortement médiatisées, qui ont popularisé son identification avec la Troie homérique (qui reste un sujet de débat en l’absence de preuve décisive), le lieu principal des événements du ''[[w:cycle troyen|cycle troyen]]'' rapportés dans les ''[[w:Épopée|poèmes épiques]]'' ''[[w:Homère|homériques]]'' l’''[[w:Iliade|Iliade]]'' et l’''[[w:Odyssée|Odyssée]]''. <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Pythie_back|<span id="Pythie"><sup>IV</sup></span>]] Du nom commun grec ancien Πῡθῐ́ᾱ / Pūthĭ́ā,<br /><p style="margin: 0 2em; text-indent: 15px">➥ du nom propre Πῡθώ / Pūthṓ, « [[w:Delphes#Histoire_du_site|''Pythô'']], ancien nom de ''Delphes'' » ;<br /><p style="margin: 0 2em; text-indent: 15px">➥ +‎ du suffixe adjectival féminin -ῐος / -ĭos [[wikt:en:-ιος#Ancient_Greek|(en)]], « relatif à, appartenant à (de) ».<br /><p style="margin: 0 2em; text-indent: 15px">[[w:Divination_dans_la_Grèce_antique|''Oracle'']] du [[w:Temple_d%27Apollon_(Delphes)|''temple d’Apollon'']] à ''Delphes''.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:XIVe_siècle_av._J.-C.|XIV<sup>ème</sup>]]/[[w:VIIIe_siècle_av._J.-C.|VIII<sup>ème</sup>]] siècles {{Info|AEC|Avant l’Ère Commune}} — [[w:IVe_siècle_av._J.-C.|IV<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]]) <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Thèbes_back|<span id="Thèbes"><sup>V</sup></span>]] Du nom propre grec ancien Θῆβαι / Thêbai [[wikt:en:Θῆβαι#Ancient_Greek|(en)]], désigne indistinctement la cité ''grecque'' comme [[w:Thèbes_(Égypte)|celle ''égyptienne'']] ; mais leur étymologie diffère :<br /><p style="margin: 0 2em; text-indent: 15px;">➥ pour celle de la cité grecque, de l’[[w:Ionien-attique|''ionien-attique'']] Θήβη / Thḗbē ; du grec mycénien 𐀳𐀣 / te-qa (/Tʰēgʷā/) ;<br /><p style="margin: 0 2em; text-indent: 15px;">(➥ pour celle de la cité égyptienne, de l’égyptien démotique tꜣ-jpy, « Thèbes, littéralement "le temple" » ;<br /><p style="margin: 0 2em; text-indent: 30px;">➥ de l’article défini tꜣ [[wikt:en:tꜣ#Demotic_Egyptian|(en)]], « le/la » ;<br /><p style="margin: 0 2em; text-indent: 30px;">➥ + du nom propre et commun jpt [[wikt:en:jpt#Etymology_3|(en)]], « Louxor, littéralement "sanctuaire intérieur" »).<br /><p style="margin: 0 2em; text-indent: 15px">Cité grecque de la région de [[w:Béotie#Antiquité|''Béotie'']], au centre de la ''Grèce''.'''<br/><br/></div> {{Boîte déroulante fin}} <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">On raconte que les sept sages se trouvèrent un jour ensemble à ''Delphes'', et une autre fois à ''Corinthe'', chez '''Périandre''', qui les avait réunis pour un banquet. Rien ne contribua autant à leur réputation et à leur gloire, que la modestie empressée avec laquelle ils se renvoyèrent l’un à l’autre le trépied d’or. Des ''Milésiens'' qui se trouvaient à l’île de ''Cos'', avaient acheté d’avance de quelques pêcheurs ce que retirerait de l’eau le filet qu’ils allaient y jeter. Quand on l’eut tiré, il s’y trouva un trépied d’or qu’'''Hélène''', à ce qu’on prétend, pour obéir à un oracle, avait jeté dans la mer, à son retour de ''Troie''. Cet incident donna lieu à une vive dispute d’abord entre les pêcheurs et les étrangers, ensuite entre les deux villes, qui prirent parti dans la querelle et étaient près d’en venir aux mains, lorsque la ''Pythie'' consultée leur ordonna de porter ce trépied au plus sage. On l’envoya d’abord à '''Thalès''', et ceux de ''Cos'' cédèrent sans peine à un seul particulier ce qu’ils allaient disputer par les armes à tous les ''Milésiens'' ensemble. '''Thalès''' le renvoya à '''Bias''', qui, disait-il, était plus sage que lui ; '''Bias''', avec la même modestie, le fit passer à un autre ; et après avoir été envoyé successivement à tous les sept, il revint une seconde fois à '''Thalès''' : enfin il fut porté à ''Thèbes'', et consacré à ''Apollon Isménien''. '''Théophraste''' dit qu’on l’envoya d’abord à '''Bias''', qui demeurait à ''Priène'' ; que '''Bias''' le fit porter à '''Thalès''' ; qu’après avoir été envoyé alternativement à tous les sages, il revint à '''Bias''', et qu’enfin il fut porté à ''Delphes''. Telle est la tradition la plus commune sur ce fait ; seulement quelques auteurs disent que ce n’était pas un trépied, mais un vase que '''Crésus''' envoyait à ''Delphes''; suivant d’autres, c’était une coupe que '''Bathyclès''' avait laissée.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f7.item <u>Plutarque, Vie de Solon</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f22.item ''chap. II''], traduction correcte et précédée du texte grec, par une société de professeurs et d’helléniste, 1862<br />(également disponible une édition de 1844 [https://remacle.org/bloodwolf/historiens/Plutarque/solon.htm#1a ici] et de 1829 [[s:Les_Vies_des_hommes_illustres/Vie_de_Solon|là]])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Or ils (les sept sages) sont dits s’être trouvés aussi ensemble les uns avec les autres et à ''Delphes'' et de nouveau à ''Corinthe'', '''Périandre''' ayant préparé une certaine réunion commune d’eux et un banquet. Or le tour du trépied, et sa circulation à travers tous et sa cession se faisant avec une bienveillance pleine-d’émulation mit eux encore davantage en considération et renommée. Car des ''habitants-de-Cos'', comme on dit, jetant le filet, et des hôtes venus de ''Milet'' ayant acheté le coup qui n’était pas encore apparent, un trépied d’-or apparut étant retiré, lequel on dit '''Hélène''' naviguant pour revenir de ''Troie'' avoir jeté là, s’étant souvenue d’un certain oracle ancien. Mais une contestation ayant eu lieu d’abord aux hôtes vis-à-vis des pécheurs au sujet du trépied, ensuite les villes ayant pris-sur-elles le différend qui alla jusqu'à une guerre, la ''Pythie'' répondit aux-uns-et-aux-autres de donner le trépied au plus sage des hommes. Et d’abord il fut envoyé à '''Thalès''' à ''Milet'', les ''habitants-de-Cos'' donnant volontairement à celui-là seul le trépied, au sujet duquel ils avaient fait-la-guerre contre tous les ''Milésiens'' à-la-fois. Mais '''Thalès''' déclarant '''Bias''' plus sage que lui-même, il renvoya vers celui-là. Et de nouveau il fut envoyé par celui-là vers un autre, comme plus sage. Ensuite faisant-le-tour et étant envoyé-successivement ainsi il arriva pour la seconde fois à '''Thalès''' ; et à la fin transporté de ''Milet'' à ''Thèbes'', il fut consacré à ''Apollon Isménien''. Mais '''Théophraste''' dit le trépied avoir été envoyé d’abord à la vérité à ''Priène'' à '''Bias''', mais en-second-lieu à ''Milet'' à '''Thalès''', '''Bias''' l’ayant renvoyé ; et ainsi à travers tous (de l’un à l’autre) être venu-en-faisant-le-tour de nouveau à '''Bias''', et à la fin avoir été envoyé à ''Delphes''. Ces choses donc ont été répandues par plusieurs, excepté qu’ils disent le présent au lieu du trépied les uns être un vase à boire envoyé par '''Crésus''', les autres une coupe. '''Bathyclès''' rayant laissée (laissée par '''Bathyclès'''). </div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f7.item <u>Plutarque, Vie de Solon</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f23.item ''chap. II''], traduction littérale et juxtalinéaire présentant le mot à mot français en regard des mots grecs correspondants, par une société de professeurs et d’helléniste, 1862</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Chapitre VI.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;"> Récit d’une entrevue de '''Thalès''' avec '''Solon''', de son stoïcisme, de son célibat et de l’adoption du fils de sa sœur, '''Cybistus'''.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;"> '''VI.''' Ἰδίᾳ δ' Ἀναχάρσεώς τε πρὸς Σόλωνα καὶ πάλιν Θάλεω συνουσίαν τινὰ καὶ λόγους ἀναγράφουσι τοιούτους. [...]<br /><p style="text-indent: 15px"> '''VII.''' Πρὸς Θαλῆν δ' εἰς Μίλητον ἐλθόντα τὸν Σόλωνα θαυμάζειν ὅτι γάμου καὶ παιδοποιΐας τὸ παράπαν ἠμέληκε. Καὶ τὸν Θαλῆν τότε μὲν σιωπῆσαι, διαλιπόντα δ' ὀλίγας ἡμέρας ἄνδρα παρασκευάσαι ξένον, ἀρτίως ἥκειν φάσκοντα δεκαταῖον ἐξ Ἀθηνῶν. Πυθομένου δὲ τοῦ Σόλωνος εἰ δή τι καινὸν ἐν ταῖς Ἀθήναις, δεδιδαγμένον ἃ χρὴ λέγειν τὸν ἄνθρωπον, « οὐδέν,» εἰπεῖν, « ἕτερον, εἰ μὴ νὴ Δία νεανίσκου τινὸς ἦν ἐκφορὰ καὶ προὔπεμπεν ἡ πόλις. Ἦν γὰρ υἱός, ὡς ἔφασαν, ἀνδρὸς ἐνδόξου καὶ πρωτεύοντος ἀρετῇ τῶν πολιτῶν· οὐ παρῆν δέ, ἀλλ' ἀποδημεῖν ἔφασαν αὐτὸν ἤδη πολὺν χρόνον.» « Ὡς δυστυχὴς ἐκεῖνος,» φάναι τὸν Σόλωνα. « Τίνα δὲ ὠνόμαζον αὐτόν;» « ἤκουσα,» φάναι, « τοὔνομα,» τὸν ἄνθρωπον, « ἀλλ' οὐ μνημονεύω· πλὴν ὅτι πολὺς λόγος ἦν αὐτοῦ σοφίας καὶ δικαιοσύνης.» Οὕτω δὴ καθ' ἑκάστην ἀπόκρισιν τῷ φόβῳ προσαγόμενον τὸν Σόλωνα καὶ τέλος ἤδη συντεταραγμένον αὐτὸν ὑποβάλλειν τοὔνομα τῷ ξένῳ, πυνθανόμενον μὴ Σόλωνος ὁ τεθνηκὼς υἱὸς ὠνομάζετο. Φήσαντος δὲ τοῦ ἀνθρώπου, τὸν μὲν ὁρμῆσαι παίειν τὴν κεφαλὴν καὶ τἆλλα ποιεῖν καὶ λέγειν ἃ συμβαίνει τοῖς περιπαθοῦσι, τὸν δὲ Θαλῆν ἐπιλαβόμενον αὐτοῦ καὶ γελάσαντα, « ταῦτά τοι,» φάναι, « ὦ Σόλων, ἐμὲ γάμου καὶ παιδοποιΐας ἀφίστησιν, ἃ καὶ σὲ κατερείπει τὸν ἐρρωμενέστατον. Ἀλλὰ θάρρει τῶν λόγων ἕνεκα τούτων· οὐ γάρ εἰσιν ἀληθεῖς.» ταῦτα μὲν οὖν Ἕρμιππος ἱστορεῖν φησι Πάταικον, ὃς ἔφασκε τὴν Αἰσώπου ψυχὴν ἔχειν.<br /><p style="text-indent: 15px">'''VIII.''' Ἄτοπος δὲ καὶ ἀγεννὴς ὁ τῷ φόβῳ τῆς ἀποβολῆς τὴν κτῆσιν ὧν χρὴ προϊέμενος· οὕτω γὰρ ἄν τις οὐ πλοῦτον, οὐ δόξαν, οὐ σοφίαν ἀγαπήσειε παραγενομένην, δεδιὼς στέρεσθαι. Καὶ γὰρ ἀρετήν, ἧς κτῆμα μεῖζον οὐδὲν οὐδ' ἥδιον, ἐξισταμένην ὑπὸ νόσων καὶ φαρμάκων ὁρῶμεν· αὐτῷ τε '''Θαλῇ''' μὴ γήμαντι πλέον οὐδὲν εἰς ἀφοβίαν, εἰ μὴ καὶ φίλων κτῆσιν ἔφυγε καὶ οἰκείων καὶ πατρίδος. Ἀλλὰ καὶ παῖδα θετὸν ἔσχε ποιησάμενος αὐτὸς τὸν τῆς ἀδελφῆς, ὥς φασι, '''Κύβισθον'''.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://remacle.org/bloodwolf/historiens/Plutarque/solon.htm <u>Plutarque, Vie de Solon</u>], ''chap. II'', ''§§6-8'', traduction par [[w:Dominique_Ricard|Dominique Ricard]], 1844<br />(également disponible une édition de 1853 [https://remacle.org/bloodwolf/historiens/Plutarque/solonpierrron.htm ici] et de 1862 [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f26.item là])</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 390px; border: 2px solid; text-indent: 15px"><br /><div style="margin: 0 2em; text-align: justify; direction: ltr;">'''VI.''' '''Solon''' connut [[w:Anacharsis|'''Anacharsis''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Anacharsis_back|<sup>🔄</sup>]] et '''Thalès''', et l’on cite des mots qui s’étaient dits dans leurs entrevues. <br /><p style="text-align: center"> [...]<br /><p style="text-indent: 15px; text-align: justify;">'''Solon''' alla à ''Milet'', pour voir '''Thalès''' : là, il lui témoigna sa surprise dans ce qu’il n’avait jamais voulu se marier et avoir des enfants. '''Thalès''' ne répondit rien sur l’heure; mais, quelques jours après, il fit paraître un étranger, qui disait arriver d’''Athènes'', et qu’il n’en était parti que depuis dix jours. '''Solon''' demanda à cet homme s’il n’y avait rien de nouveau à ''Athènes''. Celui-ci, à qui '''Thalès''' avait fait la leçon, répondit qu’il n’y avait rien de nouveau , sinon la mort d’un jeune homme dont toute la ville menait les funérailles. C’était, en effet, à ce qu’on disait, le fils d’un personnage considérable, d’une vertu éprouvée : le père n’était pas alors à ''Athènes'', et il voyageait depuis longtemps. « L’infortuné père! s’écria '''Solon'''. Mais comment s’appelait-il? — Je l’ai entendu nommer, répondit l’étranger, mais j’ai oublié son nom ; je me souviens seulement qu’on ne parlait que de sa sagesse et de sa justice. » A chacune de ces réponses, '''Solon''' sentait augmenter ses craintes; enfin, ne se possédant plus , il suggéra le nom à l’étranger, et lui demanda si le mort n’était pas le fils de '''Solon'''. « Oui. » répondit l’étranger. A cette parole, '''Solon''' se frappa la tête, et il se mit à faire et à dire tout ce qu’inspire une douleur violente. Alors '''Thalès''' lui prit la main, et lui dit en riant : « Voilà, '''Solon''', ce qui m’éloigne de me marier et d’avoir des enfants. J’ai redouté le coup sous lequel tu fléchis, toi le plus ferme des hommes. Mais rassure-toi; car il n’y a rien de vrai dans tout ce qu’on vient de te dire. » [[w:Hermippe_de_Smyrne|'''Hermippus''']] [[#Hermippe|<span id="Hermippe_back"><sup>'''I'''</sup></span>]] rapporte cette histoire d’après '''Patécus''', celui qui prétendait avoir hérité de l’âme d’[[w:Ésope|'''Ésope''']] [[#Ésope|<span id="Ésope_back"><sup>'''II'''</sup></span>]].<br /><p style="text-indent: 15px">Pourtant il y a faute de sens et de cœur à refuser d’acquérir les choses nécessaires, par la crainte de les perdre. A ce compte, on devra n’aimer ni la richesse, ni la gloire, ni la sagesse, quand on les possède, de peur d’en être privé. En effet, la vertu, le plus grand des biens et le plus doux, nous quitte quelquefois par l’action de certaines maladies ou de certains breuvages. '''Thalès''' lui-même, en ne se mariant point, n’était pas pour cela à l’abri de la crainte, à moins qu’il n'eût renoncé aussi à ses parents, à ses amis, à sa patrie. Mais il n’en était rien : il avait adopté, dit-on, '''Cybisthus''', le fils de sa sœur. </div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/viesdeshommesill01plut/page/n6/mode/1up?view=theater <u>Vie des Hommes Illustres de Plutarque</u>], [https://archive.org/details/viesdeshommesill01plut/page/182/mode/1up?view=theater ''Solon''], ''Chap. II'', ''§6'', [https://archive.org/details/viesdeshommesill01plut/page/185/mode/1up?view=theater p.185], traduit par [[w:Alexis_Pierron|Alexis Pierron]], professeur au lycée Louis-le-Grand, 1877<br />(également disponible une édition de 1853 [[s:Vies_des_hommes_illustres/Solon|ici]])</div> {{Boîte déroulante début|titre=NdA trad. par Alexis Pierron de 1877|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Hermippe_back|<span id="Hermippe"><sup>I</sup></span>]] Du nom propre [[w:Nom_théophore|''théophore'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#théophore_back|<sup>🔄</sup>]] grec ancien Ἕρμιππος / Hérmippos [[wikt:en:Ἕρμιππος#Ancient_Greek|(en)]] ;<br /><p style="margin: 0 2em; text-indent: 15px">➥ du nom propre Ἑρμῆς / Hermês [[wikt:en:Ἑρμῆς#Ancient_Greek|(en)]], « Hermès » ;<br /><p style="margin: 0 2em; text-indent: 15px">➥ +‎ du nom commun ἵππος / híppos [[wikt:en:ἵππος#Ancient_Greek|(en)]], « cheval » ;<br /><p style="margin: 0 2em; text-indent: 15px">« Péripatéticien » grec, disciple de [[w:Callimaque_de_Cyr%C3%A8ne|Callimaque de ''Cyrène'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Callimaque_back|<sup>🔄</sup>]], auteur de nombreuses biographies toutes perdues, mais listées par plusieurs auteurs.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] seconde moitié du [[w:IIIe_siècle_av._J.-C.|III<sup>ème</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]]) [https://books.google.fr/books?id=DrvWAAAAMAAJ&newbks=1&newbks_redir=0&lpg=PA497&dq=bibliogroup%3A%22Dictionnaire%20des%20philosophes%20antiques%22&hl=fr&pg=PA655#v=onepage&q&f=false {{Info|<sup>🔍</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume III, §86 - Hermippe de Smyrne}}] <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Ésope_back|<span id="Ésope"><sup>II</sup></span>]] Du nom propre grec ancien Αἴσωπος / Aísōpos [[wikt:en:Αἴσωπος#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px">➥ du nom commun αἶσα / aîsa, « destin »;<br /><p style="margin: 0 2em; text-indent: 15px">➥ +‎ du nom commun ὄψ / óps, « voix »;<br /><br /><p style="margin: 0 2em; text-indent: 15px">Auteur grec de fable.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] seconde moitié du [[w:VIe_siècle_av._J.-C.|VI<sup>ème</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]]) [https://books.google.fr/books?id=DrvWAAAAMAAJ&newbks=1&newbks_redir=0&lpg=PA497&dq=bibliogroup%3A%22Dictionnaire%20des%20philosophes%20antiques%22&hl=fr&pg=PA240#v=onepage&q&f=false {{Info|<sup>🔍</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume III, §60 - Ésope(Αἴσωπος)}}]'''<br/><br/></div> {{Boîte déroulante fin}} <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">'''V.''' Voici les particularités qu’on raconte d’une entrevue de '''Solon''' avec '''Anacharsis''', et d’un entretien qu’il eut avec '''Thalès'''.<br /><p style="text-align: center"> [...]<br /><p style="text-indent: 15px; text-align: justify;">'''VI.''' '''Solon''', étant allé à ''Milet'' pour voir '''Thalès''', lui témoigna sa surprise de ce qu’il n’avait jamais voulu se marier et avoir des enfants. '''Thalès''' ne lui répondit rien dans le moment; mais ayant laissé passer quelques jours, il fit paraître un étranger qui disait arriver d’''Athènes'', d’où il était parti depuis dix jours. '''Solon''' lui demanda s’il n’y avait rien de nouveau, lorsqu’il en était parti. Cet homme, à qui '''Thalès''' avait fait la leçon, lui répondit qu’il n’y avait autre chose que la mort d’un jeune homme dont toute la ville accompagnait le convoi. C’était, disait-on, le fils d’un des premiers et des plus vertueux citoyens, qui n'’était pas alors à ''Athènes'' et qui voyageait depuis longtemps, « Le malheureux père! s’écria Solon. Comment s’appelle-t-il? ― Je l’ai entendu nommer, répondit l’étranger; mais j’ai oublié son nom; je me souviens seulement qu’on ne parlait que de sa sagesse et de sa justice. » A chacune de ces réponses, les craintes de '''Solon''' augmentaient; enfin, troublé, hors de lui-même, il suggéra le nom à l’étranger, et lui demanda si ce jeune homme n’était pas le fils de '''Solon'''. « C’est lui-même, » dit l’autre. A cette parole, '''Solon''', se frappant la tête, se mit à faire et à dire tout ce que la douleur la plus violente peut inspirer. Alors '''Thalès''' l’arrêta et lui dit en souriant : « Voilà, '''Solon''', ce qui m’a éloigné de me marier et d’avoir des enfants; j’ai redouté le coup qui vous accable aujourd’hui, et contre lequel toute votre fermeté est impuissante. Mais rassurez-vous ; il n’y a rien de vrai dans tout ce qu’on vient de vous dire. » '''Hermippus''' rapporte cette histoire d’après le récit qu’en fait '''Patécus''', qui prétendait avoir hérité de l’âme d’'''Ésope'''.<br /><p style="text-indent: 15px; text-align: justify;">'''VII.''' Cependant c’est manquer de sens et de courage que de renoncer à acquérir des choses nécessaires par la crainte de les perdre. A ce compte, il ne faudrait aimer ni la richesse, ni la gloire, ni la sagesse, quand on les possède, de peur d’en être privé. La vertu même, le plus grand et le plus agréable des biens, se perd souvent par l’effet. de quelques maladies ou de certains breuvages. '''Thalès''' lui-même, en ne se mariant point, n’était pas à l’abri de toute crainte, à moins qu’il ne renonçât aussi à ses parents, à ses amis et à sa patrie. Mais au contraire, il avait adopté '''Cybistus''', le fils de sa sœur. </div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f7.item <u>Plutarque, Vie de Solon</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f26.item ''chap. II''], traduction correcte et précédée du texte grec, par une société de professeurs et d’helléniste, 1862<br />(également disponible une édition de 1844 [https://remacle.org/bloodwolf/historiens/Plutarque/solon.htm#1a ici] et de 1829 [[s:Les_Vies_des_hommes_illustres/Vie_de_Solon|là]])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">'''V.''' Mais en particulier on rapporte une certaine entrevue et de tels discours et d’'''Anacharsis''' à '''Solon''' et une-autre-fois de '''Thalès'''.<br /><p style="text-align: center"> [...]<br /><p style="text-indent: 15px; text-align: justify;">'''VI.''' Et on raconte '''Solon''' étant venu vers '''Thalès''' à ''Milet'' s’étonner de ce qu’il avait négligé absolument le mariage et la création-d’enfants. Et '''Thalès''' alors à la vérité s’être tu, mais ayant laissé-d’intervalle peu-de jours, avoir aposté un homme étranger, disant être arrivé récemment parti-depuis-dix-jours d’''Athènes''. Et '''Solon''' s’étant informé si donc il y a quelque chose de nouveau à ''Athènes'', l’homme instruit des choses qu’il faut dire n’avoir dit aucune autre chose, si ce n’est :<br /><p style="text-indent: 15px"> « Par '''Jupiter''', il y avait le convoi d’un certain jeune-homme, et la ville l’accompagnait. Car il était fils, comme on disait, d’un homme illustre et étant-le-premier des citoyens par la vertu; mais il n’était-pas-présent, mais on disait lui être-en-voyage depuis un temps déjà long.<br /><p style="text-align: left; text-indent: 15px">― Combien cet homme-là est malheureux! avoir dit '''Solon'''. Mais quel (comment) appelaient-ils lui ?<br /><p style="text-align: left; text-indent: 15px">― J’ai entendu le nom, avoir dit l’homme (répondit l’étranger), mais je ne me le rappelle pas; excepté qu’un discours fréquent était de la sagesse et de la justice de lui. »<br /><p style="text-indent: 15px">'''Solon''' donc étant-approché ainsi de-la crainte à chaque réponse, et à la fin déjà étant tout-troublé, lui-même avoir suggéré le nom à l’étranger, demandant si le mort n’était pas nommé fils de '''Solon'''. Et l’homme ayant dit-oui, celui-ci ('''Solon''') avoir commencé à frapper sa tête, et à faire et à dire les autres choses, qu’il arrive de faire et de dire à ceux affligés-à-l’excès. Mais '''Thalès''' ayant arrêté lui, et ayant ri, avoir dit :<br /><p style="text-indent: 15px">« Ces choses donc, ô '''Solon''', écartent moi du mariage et de la création-d’enfants, lesquelles abattent même toi le très-fort. Mais aie-confiance quant-à ces discours: car ils ne sont pas vrais. »<br /><p style="text-indent: 15px">'''Hermippe''' donc dit '''Patécus''', qui disait-souvent avoir l’âme d’'''Ésope''', raconter ces choses. <br /><p style="text-indent: 15px">'''VII.''' Or il est absurde et dépourvu de courage celui rejetant par la crainte de la perte l’acquisition des choses qu’il faut; car ainsi quelqu’un n’aimerait pas la richesse, n’aimerait pas la gloire, n’aimerait pas la sagesse étant survenue à lui, craignant (par crainte) d’en être privé. Et en effet nous voyons la vertu, au prix de laquelle aucune possession n’est plus grande, ni plus agréable, déplacée (chassée) par des maladies et des breuvages; et rien de plus n’être pour l’exemption-de-crainte à '''Thalès''' lui-même ne s’étant pas marié, s’il n’avait pas évité la possession et d’amis et de parents et de patrie. Mais même il eut un fils adoptif se l’étant fait tel lui-même, celui de sa sœur, comme on dit '''Cybisthe'''.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f7.item <u>Plutarque, Vie de Solon</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f27.item ''chap. II''], traduction littérale et juxtalinéaire présentant le mot à mot français en regard des mots grecs correspondants, par une société de professeurs et d’helléniste, 1862</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ====== <div style="text-align: center;">Paragraphe XV.</div> ====== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;"> Testament d’inhumation de '''Thalès'''.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''XV.''' Καὶ φόβοι τινὲς ἐκ δεισιδαιμονίας ἅμα καὶ φάσματα κατεῖχε τὴν πόλιν, οἵ τε μάντεις ἄγη καὶ μιασμοὺς δεομένους καθαρμῶν προφαίνεσθαι διὰ τῶν ἱερῶν ἠγόρευον. Οὕτω δὴ μετάπεμπτος αὐτοῖς ἧκεν ἐκ Κρήτης Ἐπιμενίδης ὁ Φαίστιος, ὃν ἕβδομον ἐν τοῖς σοφοῖς καταριθμοῦσιν ἔνιοι τῶν οὐ προσιεμένων τὸν Περίανδρον. Ἐδόκει δέ τις εἶναι θεοφιλὴς καὶ σοφὸς περὶ τὰ θεῖα τὴν ἐνθουσιαστικὴν καὶ τελεστικὴν σοφίαν, διὸ καὶ παῖδα νύμφης ὄνομα Βάλτης καὶ Κούρητα νέον αὐτὸν οἱ τότε ἄνθρωποι προσηγόρευον. <br /><p style="text-align: center">[...]<br /><p style="text-indent: 15px; text-align: justify;">Τὸ δὲ μέγιστον, ἱλασμοῖς τισι καὶ καθαρμοῖς καὶ ἱδρύσεσι κατοργιάσας καὶ καθοσιώσας τὴν πόλιν ὑπήκοον τοῦ δικαίου καὶ μᾶλλον εὐπειθῆ πρὸς ὁμόνοιαν κατέστησε. Λέγεται δὲ τὴν Μουνυχίαν ἰδὼν καὶ καταμαθὼν πολὺν χρόνον, εἰπεῖν πρὸς τοὺς παρόντας ὡς τυφλόν ἐστι τοῦ μέλλοντος ἄνθρωπος· ἐκφαγεῖν γὰρ ἂν Ἀθηναίους τοῖς αὑτῶν ὀδοῦσιν, εἰ προῄδεσαν ὅσα τὴν πόλιν ἀνιάσει τὸ χωρίον· ὅμοιον δέ τι καὶ Θαλῆν εἰκάσαι λέγουσι· κελεῦσαι γὰρ αὐτὸν ἔν τινι τόπῳ τῆς Μιλησίας φαύλῳ καὶ παρορωμένῳ τελευτήσαντα θεῖναι, προειπὼν ὡς ἀγορά ποτε τοῦτο Μιλησίων ἔσται τὸ χωρίον. Ἐπιμενίδης μὲν οὖν μάλιστα θαυμασθείς, καὶ χρήματα διδόντων πολλὰ καὶ τιμὰς μεγάλας τῶν Ἀθηναίων, οὐδὲν ἢ θαλλὸν ἀπὸ τῆς ἱερᾶς ἐλαίας αἰτησάμενος καὶ λαβὼν ἀπῆλθεν. </div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://remacle.org/bloodwolf/historiens/Plutarque/solon.htm <u>Plutarque, Vie de Solon</u>], ''chap. II'', ''§15'', traduction par [[w:Dominique_Ricard|Dominique Ricard]], 1844<br />(également disponible une édition de 1853 [https://remacle.org/bloodwolf/historiens/Plutarque/solonpierrron.htm ici] et de 1862 [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f26.item là])</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 390px; border: 2px solid; text-indent: 15px"><br /><div style="margin: 0 2em; text-align: justify; direction: ltr;">'''XV.''' Au chagrin que ces pertes causèrent à ceux-ci [les ''Athéniens''], se joignirent des craintes superstitieuses dont la ville [''Athènes''] fut frappée, et qui venaient d’apparitions de spectres et de fantômes. Les devins déclarèrent aussi que l’état des victimes qu’ils avaient offertes annonçait des crimes et des profanations qu’il fallait expier. On fit donc venir de ''Crète'' [[w:Épiménide|'''Épiménide''']] [[#Épiménide|<span id="Épiménide_back"><sup>'''I'''</sup></span>]] le [[w:Phaistos|''Phestien'']] [[#Phaistos|<span id="Phaistos_back"><sup>'''II'''</sup></span>]], qui est mis au nombre des sept sages par ceux qui n’y comptent pas '''Périandre'''. Il passait pour un homme chéri des dieux, doué d’une grande sagesse, fort instruit des choses divines, surtout versé dans la science des inspirations et dans la connaissance des mystères; on l’appelait, même de son vivant, le nouveau [[w:Curètes|'''Curète''']], le fils de la nymphe '''Balté'''.<br /><p style="text-align: center">[...]<br /><p style="text-indent: 15px; text-align: justify;">Mais ce qui était plus important, il fit un grand nombre d’expiations et de sacrifices, il fonda plusieurs temples; et par ces différentes cérémonies il purifia entièrement la ville, en bannit l’impiété et l’injustice, et la rendit plus soumise, plus disposée à l’union et à la paix. On rapporte aussi que lorsqu’il vit le fort de [[w:Munichie|''Munychium'']] [[#Munichie|<span id="Munichie_back"><sup>'''III'''</sup></span>]], il le considéra longtemps, et dit à ceux qui l’accompagnaient : Que les hommes sont aveugles sur l’avenir ! Si les ''Athéniens'' pouvaient prévoir tous les maux que ce lieu doit un jour causer à leur ville, ils l’emporteraient à belles dents ». '''Thalès''' eut aussi, dit-on, un pressentiment à peu près semblable. Il ordonna qu’on l’enterrât dans le lieu le plus sauvage et le plus désert du territoire de ''Milet''; et il prédit aux ''Milésiens'' qu’un jour leur marché public y serait transporté. Les ''Athéniens'', pleins de reconnaissance et d’admiration pour '''Épiménide''', voulurent le combler d’honneurs et de présents; mais il ne demanda qu’une branche de l’olivier sacré, qui lui fut accordée, et il s’en retourna en ''Crète''.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/viesdeshommesill01plut/page/n6/mode/1up?view=theater <u>Vie des Hommes Illustres de Plutarque</u>], [https://archive.org/details/viesdeshommesill01plut/page/182/mode/1up?view=theater ''Solon''], ''Chap. II'', ''§15'',[https://archive.org/details/viesdeshommesill01plut/page/185/mode/1up?view=theater p.185], traduit par [[w:Alexis_Pierron|Alexis Pierron]], professeur au lycée Louis-le-Grand, 1877<br />(également disponible une édition de 1853 [[s:Vies_des_hommes_illustres/Solon|ici]])</div> {{Boîte déroulante début|titre=NdA trad. par Alexis Pierron de 1877|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Épiménide_back|<span id="Épiménide"><sup>I</sup></span>]] Du nom propre grec ancien Ἐπιμενίδης / Epimenídēs [[wikt:en:Ἐπιμενίδης#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px">Poète, philosophe et [[w:Iatromante|''iatromante'']] crétois.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] milieu du [[w:VIe_siècle_av._J.-C.|VI<sup>ème</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]]) <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Phaistos_back|<span id="Phaistos"><sup>II</sup></span>]] Du nom propre grec ancien Φαιστός / Phaistós [[wikt:en:Φαιστός#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px">Ancienne ville du Sud de la [[w:Histoire_de_la_Crète#Antiquité|''Crète'']].<br /><br /><p style="margin: 0 2em; text-indent: 15px">[[#Munichie_back|<span id="Munichie"><sup>III</sup></span>]] Du nom propre grec ancien Μουνιχία / Mounikhia [[wikt:en:Μουνυχία#Grec_ancien|(en)]] ;<br /><p style="margin: 0 2em; text-indent: 15px">Nom d’une colline du [[w:Le_Pirée|''Pirée'']] et de l’[[w:Port_de_Munichie|un des ports du ''Pirée'']].'''<br/><br/></div> {{Boîte déroulante fin}} <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">'''XII.''' Au chagrin que ces pertes causèrent à ceux-ci, se joignirent des craintes superstitieuses dont la ville fut frappée, et qui venaient d’apparitions de spectres et de fantômes. Les devins déclarèrent aussi que l’état des victimes annonçait des crimes et des profanations qu’il fallait expier. On fit donc venir de ''Crète'' '''Épiménide''' le ''Phestien'' qui est mis au nombre des sept sages par ceux qui n’y comptent pas '''Périandre'''. Il passait pour un homme chéri des dieux, doué d’une grande sagesse, fort instruit des choses divines, surtout versé dans la science des inspirations et dans la connaissance des mystères; on l’appelait, même de son vivant, le nouveau '''Curète''', le fils de la nymphe '''Balté'''.<br /><p style="text-align: center">[...]<br /><p style="text-indent: 15px; text-align: justify;">Mais ce qui était plus important, il fit un grand nombre d’expiations et de sacrifices; il fonda plusieurs temples; et par ces différentes cérémonies, il purifia entièrement la ville, en bannit l’impiété et l’injustice, et la rendit plus soumise, plus disposée à l’union et à la paix. On rapporte aussi que lorsqu’il vit ''Munychie'', il la considéra longtemps, et dit à ceux qui l’accompagnaient :<br /><p style="text-align: justify; text-indent: 15px"> « Que les hommes sont aveugles sur l’avenir! Si les ''Athéniens'' pouvaient prévoir tous les maux que ce lieu doit un jour causer à leur ville, il l’emporteraient à belles dents. »<br /><p style="text-align: justify; text-indent: 15px"> '''Thalès''' eut aussi, dit-on, un pressentiment à peu près semblable. Il ordonna qu’on l’enterrât dans le lieu le plus sauvage et le plus désert du territoire de ''Milet''; et il prédit aux ''Milésiens'' qu’un jour leur marché public y serait transporté. Les ''Athéniens'', pleins de reconnaissance et d’admiration pour '''Épiménide''', voulurent le combler d’honneurs et de présents; mais il ne demanda qu’une branche de l’olivier sacré, qui lui fut accordée, et il s’en retourna en ''Crète''.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f7.item <u>Plutarque, Vie de Solon</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f58.item ''chap. II''], traduction correcte et précédée du texte grec, par une société de professeurs et d’helléniste, 1862<br />(également disponible une édition de 1844 [https://remacle.org/bloodwolf/historiens/Plutarque/solon.htm#1a ici] et de 1829 [[s:Les_Vies_des_hommes_illustres/Vie_de_Solon|là]])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Et certaines craintes nées de la superstition en-même-temps aussi des apparitions occupaient la ville; et les devins disaient des impiétés et des souillures ayant-besoin de purifications être indiquées par les victimes. Et ainsi vint à eux mandé (ils firent venir) de ''Crète'' '''Épiménide''' le ''Phestien'', que quelques-uns de ceux n’admettant pas '''Périandre''' comptent le septième parmi les sages. Or il avait-la-réputation d’être un homme ami-des-dieux, et habile dans la science de-l’inspiration et des-mystères. C’est-pourquoi les hommes d’alors appelaient lui et fils de la nymphe de nom (nommée) '''Balté''', et nouveau '''Curète'''.<br /><p style="text-align: center">[...]<br /><p style="text-indent: 15px; text-align: justify;">Mais le plus grand (le plus important), ayant initié-aux-mystères et ayant purifié la ville par certaines expiations et purifications et fondations, il la rendit prêtant-l’oreille à la justice et plus obéissante pour la concorde. Et il est dit, ayant vu ''Munychie'' et l’ayant examinée un temps long, avoir dit à ceux présents, que l’homme est un être aveugle sur l’avenir ; car les ''Athéniens'' avoir dû manger ''Munychie'' avec les dents d’eux-mêmes, s’ils avaient prévu en combien de choses cette place affligera la ville. Et on dit aussi '''Thalès''' avoir conjecturé quelque chose de semblable; lui avoir ordonné en effet de placer lui ayant cessé de vivre dans un certain lieu de la ''Milésie'' méprisé et dédaigné, ayant prédit que cet endroit sera (serait) un jour le marché des ''Milésiens''. '''Épiménide''' donc ayant été admiré très-grandement, et les ''Athéniens'' lui donnant des sommes nombreuses et des honneurs grands, n’ayant demandé rien qu’un rameau détaché de l’olivier sacré et l’ayant pris (reçu) s’en alla.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f7.item <u>Plutarque, Vie de Solon</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f59.item ''chap. II''], traduction littérale et juxtalinéaire présentant le mot à mot français en regard des mots grecs correspondants, par une société de professeurs et d’helléniste, 1862</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto; color: #3366BB">═✳═</div> === [[w:Œuvres_morales|Œuvres morales]] [[#Œuvres_morales|<span id="Œuvres_morales_back"><sup>'''I'''</sup></span>]] === <div style="text-align: center; margin: 0 1em;">Ensemble de 78 textes de traitant de sujets extrêmement variés (religieux, éthiques, politiques, philosophiques, littéraires, historiques), et s'inscrivant dans des genres littéraires également divers (traité, différentes sortes de dialogues, lettres, réponses à des Questions ([[wikt:ζήτημα#Grec_ancien|''zetemata'']]), « dits » ([[w:Apophtegme|''apophtegmes'']])).</div> {{Boîte déroulante début|titre=NdA Le Banquet des Septs Sages|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Cléobuline_back|<span id="Cléobuline"><sup>I</sup></span>]] En grec ancien Ἠθικὰ / Ethikà [[wikt:en:ἠθικός#Ancient_Greek|(en)]], «1. Relatif au caractère ou au tempérament : • (d’une personne) Qui exprime ou manifeste sa nature ; • (théâtre) Conforme au personnage. 2. Éthique moral (relatif à la moralité) : (philosophie) Relatif à l’éthique (l’étude des principes régissant la conduite juste ou injuste) ; (d’un texte) qui traite de la conduite et de la vertu. 3. (rhétorique) Empreint de tact. » ; <br /><p style="margin: 0 2em; text-indent: 15px;">➥ du nom commun ἦθος / êthos [[wikt:en:ἦθος#Ancient_Greek|(en)]], « 1. Le lieu habituel ou coutumier (de quelque chose) : • Le domicile ou le lieu de résidence (d’une personne) ; • Le territoire (d’un animal). 2. Le caractère ; le tempérament : • (théâtre) Personnage (dramatique). 3. La coutume ; l’habitude : • (au pluriel) Les manières ; l’étiquette. » ;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ +‎ du suffixe adjectival -ῐκός/-ĭkós, « relatif à, à la manière de ; -ique ».<br /><br /><p style="margin: 0 2em; text-indent: 15px;">En latin Moralia ; de l’adjectif mōrālis [[wikt:en:moralis#Latin|(en)]], « Qui a trait aux mœurs ou à l'éthique ; moral. » ;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ du nom commun mōs [[wikt:en:mos#Latin|(en)]], « 1. Manière d’agir ; comportement ; conduite. 2. Coutume ; habitude ; pratique ; usage. 3. (surtout au pluriel) Caractère ; disposition ; inclination ; tempérament. 4. Volonté ; obstination ; humeur ; caprice. 5. (sens dérivé) Qualité ; nature ; mode ; façon. 6. (sens dérivé) Précepte ; loi ; règle. 7. (au pluriel uniquement) mœurs ; principes »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ + du suffixe adjectival -ālis [[wikt:en:-alis#Latin|(en)]]. Utilisé pour la première fois par Cicéron pour traduire le terme grec ancien ēthikós, « moral ». <br /><br /><p style="margin: 0 2em; text-indent: 15px;">En retraçant l’usage de l’adjectif ἠθικός à partir de la Rhétorique d’Aristote, le professeur de littérature latine [https://cv.hal.science/charles-guerin Charles Guérin] démontre que Cicéron l’utilise dans son dernier traité rhétorique non comme un équivalent du style moyen, mais comme une catégorie nouvelle permettant d’opposer éloquence du ''mouere'' [[wikt:en:movere#Latin|(en)]] et éloquence du ''conciliare'' [[wikt:en:conciliare#Latin|(en)]]. Cicéron réintroduit ainsi dans son traité la notion de conciliation du public qu’il avait tout d’abord éliminée de son architecture théorique (au profit de la notion de ''delectare'' [[wikt:en:delectare#Latin|(en)]]) afin de garantir la cohérence conceptuelle de sa doctrine. L’ἠθικόν correspond ainsi à l’idée d’une adaptation du style à l’orateur, non sur le mode pragmatique défendu par Aristote (chez qui la λέξις ἠθική désigne l’adaptation du style aux caractéristiques concrètes de l’orateur), mais sur un mode idéalisant : l’ἠθικόν est une catégorie stylistique prescriptive, celle du style de l’orateur accompli [https://hal.science/hal-03189440 {{Info|<sup>🔍</sup>|Charles Guérin. Orator 128: Cicéron et la catégorie rhétorique de l’ethikon. Pierre Chiron; Carlos Lévy. Les noms du style, Peeters, pp.143-164, 2010. ⟨hal-03189440⟩}}].<br /><br /></div> {{Boîte déroulante fin}} ==== Le Banquet des Sept Sages ==== {| cellpadding="0" align="{{{align|right}}}" style="margin-left: 2em; width:40%; border-spacing:3px; text-align:center; background-color:#F8F9FA; border:2px solid #C8CCD1" |- | style="border:solid 1px #F8F9FA" | '''Manuscrit''' [https://archive.org/details/p.-oxy.-16/Oxyrhynchus%20Papyri/P.%20Oxy.%2052/page/n66/mode/1up {{info|<sup>➕</sup>|The Oxyrhynchus Papyri, Volume LII, 1984}}] [https://books.google.fr/books?id=qfl1xwEACAAJ&lpg=PA1059&hl=fr&pg=PA1171#v=onepage&q=Plutarque&f=false {{info|<sup>➕➕</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume Vb, §210 - Plutarque de Chéronée, p.1171}}] |- style="font-size:8pt; line-height:10pt; vertical-align:middle" | align="center" | <div style="margin-right: 1em; padding:0 0 4px 0; text-align:justify;">{{{légende| Le P. Oxy. 3685 conserve les vestiges assez détériorés de deux colonnes du Banquet des Sept Sages, datant de la première moitié du [[w:IIe_siècle|II<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]], c’est-à-dire presque contemporain de '''Plutarque'''. Ce petit fragment de papyrus (9,6 x 8 cm) présente un intérêt à deux titres : * d’une part, sa datation étant proche de l’époque de '''Plutarque''', il apporte des éléments sur l’authenticité de l’œuvre ; * d’autre part, une partie du texte se retrouve également chez '''Stobée'''. Les doutes quant à l'attribution du Banquet des Sept Sages à Plutarque ne semblent être apparus qu'à une époque relativement récente ; en effet, l'ouvrage figure dans ce que l'on appelle le « Catalogue de Lamprias », une liste des œuvres de Plutarque dressée au [[w:IIIe_siècle|III<sup>ème</sup>]] ou au [[w:IVe_siècle|IV<sup>ème</sup>]] siècle {{Info|EC|de l’Ère Commune}}. Toutefois, ces réserves ont désormais été levées de manière convaincante par J. Defradas pp.7-12 de l’édition de la Budé de 1985. NB : Les [[w:Papyrus_d%27Oxyrhynque|''papyrus d’Oxyrhynque'']] constituent un ensemble de manuscrits découverts à la fin du [[w:XIXe_siècle|XIX<sup>ème</sup>]] et au début du [[w:XXe_siècle|XX<sup>ème</sup>]] siècles {{Info|EC|de l’Ère Commune}} par les papyrologues [[w:Bernard_Pyne_Grenfell|'''Bernard Pyne Grenfell''']] et [[w:Arthur_Surridge_Hunt|'''Arthur Surridge Hunt''']], dans une ancienne décharge située près d’[[w:Oxyrhynque|''Oxyrhynque'']], en ''Égypte''.}}}</div> |} <div style="text-align: center; margin: 0 1em;">Dialogue faisant intervenir 20 personnages, dont une liste des sept sages : '''Thalès''', [[w:Solon|'''Solon''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Solon_back|<sup>🔄</sup>]], [[w:Bias_de_Priène|'''Bias''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Bias_back|<sup>🔄</sup>]], [[w:Chilon|'''Chilon''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Chilon_back|<sup>🔄</sup>]], [[w:Cléobule|'''Cléobule''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Cléobule_back|<sup>🔄</sup>]], [[w:Pittacos_de_Mytil%C3%A8ne|'''Pittacos''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Pittacos_back|<sup>🔄</sup>]], [[w:Périandre|'''Périandre''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Périandre_back|<sup>🔄</sup>]].</div> <div style="text-align: left; margin: 0 1em;">À ceux-ci se rajoutent : * [[w:Anacharsis|'''Anacharsis''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Anacharsis_back|<sup>🔄</sup>]], * '''[[w:Ésope|Ésope]]''' [[#Ésope|<span id="Ésope_back"><sup>'''I'''</sup></span>]], * '''Dioclès''' le ''devin'' et narrateur (possiblement fictif) [[#Dioclès_Cléodème_Chersias|<span id="Dioclès_Cléodème_Chersias_back"><sup>'''II'''</sup></span>]], * '''Nicarque''' le destinataire du récit (possiblement fictif), * [[w:Cléobuline|'''Cléobuline''']] [[#Cléobuline|<span id="Cléobuline_back"><sup>'''III'''</sup></span>]], * '''Mélissa''' la conjointe de '''Périandre''', * '''Niloxène''', * '''Alexidème''' un bâtard du ''tyran'' [[w:Thrasybule_de_Milet|'''Thrasybule''' de ''Milet'']], * '''Ardalus''' le joueur de flûte [[w:Trézène_(ville)|''trézénien'']] [[#Trézène|<span id="Trézène_back"><sup>'''IV'''</sup></span>]], * '''Cléodème''' le ''médecin'' (possiblement fictif) [[#Dioclès_Cléodème_Chersias|<sup>'''II'''</sup>]], * '''Mnésiphile''' un disciple de '''Solon''', * '''Chersias''' le ''poète'' (possiblement fictif) [[#Dioclès_Cléodème_Chersias|<sup>'''II'''</sup>]], * [[w:Gorgias|'''Gorgias''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Gorgias_back|<sup>🔄</sup>]].</div> {{Boîte déroulante début|titre=NdA Le Banquet des Septs Sages|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Ésope_back|<span id="Ésope"><sup>I</sup></span>]] Du nom propre grec ancien Αἴσωπος / Aísōpos ;<br /><p style="margin: 0 2em; text-indent: 15px;">Sous le nom d’Ésope ont circulé dans l’antiquité différents recueils de fables qui ont connu un succès universel et ont été traduites et imitées dans toute la tradition littéraire postérieure. On peut y voir l’expression d’une éthique populaire, rationaliste et cosmopolite, qui n’est pas sans intérêt pour l’histoire de la philosophie. Selon Hérodote, (livre II, chap. 134), il serait un ancien esclave d’Iadmon de ''Samos''.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] seconde moitié du [[w:VIe_siècle_av._J.-C.|VI<sup>ème</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]], selon la Souda, ({{Info|s.v.|Abréviation du latin sub verbo, « À l’article, à l’entrée, au mot. »}} Αἴσωπος, Αι 334), il aurait été précipité du haut des [[w:Phédriades|''Roches Phédriades'']] à ''Delphes'' en la 54<sup>ème</sup> Olympiade (564/561))[https://books.google.fr/books?id=DrvWAAAAMAAJ&newbks=1&newbks_redir=0&lpg=PA5&dq=bibliogroup%3A%22Dictionnaire%20des%20philosophes%20antiques%22&hl=fr&pg=PA240#v=onepage&q&f=false {{Info|<sup>🔍</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume III, §60 - Ésope (Αἴσωπος)}}] <br /><br /><p style="margin: 0 2em; text-indent: 15px;">'''[[#Dioclès_Cléodème_Chersias_back|<span id="Dioclès_Cléodème_Chersias"><sup>II</sup></span>]] D’après l’historienne [https://research-bulletin.chs.harvard.edu/authors/zoe-stamatopoulou/ Zoe Stamatopoulou] [https://research-bulletin.chs.harvard.edu/2017/04/17/periander-plutarch-symposium/ {{info|<sup>🔍</sup>|Stamatopoulou, Zoe. “Constructing Periander in Plutarch’s Symposium of the Seven Sages.” CHS Research Bulletin 5, no. 1 (2016). http://nrs.harvard.edu/urn-3:hlnc.essay:StamatopoulouZ.Constructing_Periander.2016.}}], il s’agit de non-Sages individualisés par leur profession. <br /><br /><p style="margin: 0 2em; text-indent: 15px;">'''[[#Cléobuline_back|<span id="Cléobuline"><sup>III</sup></span>]] Du nom propre grec ancien Κλεοβουλίνη / Kleoboulinè ;<br /><p style="margin: 0 2em; text-indent: 15px">➥ de Κλεόβουλος / Kleóboulos [[wikt:en:Κλεόβουλος#Ancient_Greek|(en)]], « Cléobule, le père de Cléobuline » <br /><p style="margin: 0 2em; text-indent: 15px">➥ du suffixe adjectival féminin -ῑ́νη / -ī́nē [[wikt:en:-ίνη#Ancient_Greek|(en)]], relatif à la matière, au temps, etc. : « fait de, pendant la durée de » ;<br /><p style="margin: 0 2em; text-indent: 15px">Philosophe et poétesse grecque, célèbre pour ses énigmes, fille du [[w:Tyran|''tyran'']] de [[w:Rhodes|''Rhodes'']], Cléobule, qui la surnommerait Εὔμητις / Eúmētis, « la Prudente » selon Plutarque.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:VIe_siècle_av._J.-C.|VI<sup>ème</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]], originaire de [[w:Lindos|''Lindos'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Lindos_back|<sup>🔄</sup>]] sur l’île de ''Rhodes'') <br /><br /><p style="margin: 0 2em; text-indent: 15px;">'''[[#Trézène_back|<span id="Trézène"><sup>IV</sup></span>]] Du nom propre grec ancien Τροιζήν / Troizḗn [[wikt:en:Τροιζήν#Ancient_Greek|(en)]] ;<br /><p style="margin: 0 2em; text-indent: 15px">[[w:polis|Cité grecque]] du [[w:Péloponnèse|''Péloponnèse'']], sur la côte nord de l’[[w:Argolide|''Argolide'']]. '''<br/><br/></div> {{Boîte déroulante fin}} ===== <div style="text-align: center;">Paragraphe I.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">'''Dioclès''' raconte le Banquet des Sept Sages organisé par '''Périandre''', pendant lequel il fût l’hôte de '''Thalès'''.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§1. Ἦ που προϊὼν ὁ χρόνος, ὦ '''Νίκαρχε''', πολὺ σκότος ἐπάξει τοῖς πράγμασι καὶ πᾶσαν ἀσάφειαν, εἰ νῦν ἐπὶ προσφάτοις οὕτω καὶ νεαροῖς λόγοι ψευδεῖς συντεθέντες ἔχουσι πίστιν. οὔτε γὰρ μόνων, ὡς ὑμεῖς ἀκηκόατε, τῶν ἑπτὰ γέγονε τὸ συμπόσιον, ἀλλὰ πλειόνων ἢ δὶς τοσούτων (ἐν οἷς καὶ αὐτὸς ἤμην, συνήθης μὲν ὢν '''Περιάνδρῳ''' διὰ τὴν τέχνην, ξένος δὲ '''Θάλεω'''· παρ´ ἐμοὶ γὰρ κατέλυσεν ὁ ἀνὴρ '''Περιάνδρου''' κελεύσαντος), οὔτε τοὺς λόγους ὀρθῶς ἀπεμνημόνευσεν ὅστις ἦν ὑμῖν ὁ διηγούμενος· ἦν δ´ ὡς ἔοικεν οὐδεὶς τῶν παραγεγονότων. ἀλλ´ ἐπεὶ σχολή τε πάρεστι πολλὴ καὶ τὸ γῆρας οὐκ ἀξιόπιστον ἐγγυήσασθαι τὴν ἀναβολὴν τοῦ λόγου, προθυμουμένοις ὑμῖν ἀπ´ ἀρχῆς ἅπαντα διηγήσομαι. </div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §1'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§1. '''D<span style ="font-size:85%;">IOCLÈS</span>'''. Certainement le long cours des âges, mon cher '''Nicarque''', jettera sur les faits d’épaisses ténèbres et une complète incertitude, puisque dès aujourd’hui, à propos de choses si récentes et si nouvelles, des relations mensongères et controuvées obtiennent crédit. Car d’abord le banquet en question ne se composait pas seulement des sept sages, comme vous autres l’avez ouï dire. Les convives étaient plus du double de ce nombre. J’en faisais moi-même partie, comme familier de '''Périandre''' en raison de notre profession commune, et comme hôte de '''Thalès''' : ce dernier était en effet descendu chez moi sur la recommandation de '''Périandre'''. Ensuite, on ne vous en a pas rapporté fidèlement les entretiens lorsqu’on vous a fait ce récit. Il faut que celui de qui vous le tenez n’ait pas été un des convives. Mais puisque nous avons un ample loisir et que la vieillesse est un garant trop peu sûr pour nous autoriser à remettre cet entretien, je vais, suivant votre désir unanime, vous en raconter tous les détails à partir du commencement. </div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §1'', traduction par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870<br/>(également disponible [[s:Page:Plutarque_-_Œuvres_complètes_de_Plutarque_-_Œuvres_morales_et_œuvres_diverses,_tome_1,_1870.djvu/424|ici]])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">'''D<span style ="font-size:85%;">IOCLÈS</span>'''. Quelle incertitude et quelle obscurité la succession des temps ne doit-elle pas répandre sur l’histoire, mon cher '''Nicarque''', puisque, dans des faits récents, et qui se sont passés presque sous nos yeux, le faux prend la place du vrai ? Ce banquet n’était pas, comme on vous l’a dit, composé seulement des sept sages ; les convives étaient plus du double de ce nombre. J’y assistai moi-même, et comme ami de '''Périandre''', avec qui ma profession ma lié depuis longtemps [[#Dioclès_NdT_DR|<span id="Dioclès_NdT_DR_back"><sup>1</sup></span>]], et comme hôte de '''Thalès''', à qui '''Périandre''' avait fait marquer son logement chez moi. Celui qui vous a fait le récit de ce qui s’y est passé n’en était sûrement pas, et vous a trompé sur presque tous les points. Mais, puisque nous en avons le loisir, et que notre âge avancé ne nous permet guère de différer, je vais vous satisfaire et vous en raconter tous les détails.</div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Dioclès_NdT_DR_back|<span id="Dioclès_NdT_DR"><sup>1.</sup></span>]] Dioclès était devin.''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' pp.325, 326, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe II.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage de la simplicité de '''Thalès''', de sa mesure de la pyramide d’''Égypte'' [[#mesure_pyramide|<span id="mesure_pyramide_back"><sup>'''I'''</sup></span>]], et de son aversion des [[w:Tyran|''tyrans'']] et des rois.</div> {{Boîte déroulante début|titre=NdA Mesure de la Pyramide d’Égypte|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#mesure_pyramide_back|<span id="mesure_pyramide"><sup>I</sup></span>]]'''<br/><br/></div> {{Boîte déroulante fin}} :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§2. Παρεσκευάκει μὲν γὰρ οὐκ ἐν τῇ πόλει τὴν ὑποδοχὴν ὁ Περίανδρος, ἀλλ´ ἐν τῷ περὶ τὸ Λέχαιον ἑστιατορίῳ παρὰ τὸ τῆς Ἀφροδίτης ἱερόν, ἧς ἦν καὶ ἡ θυσία. μετὰ γὰρ τὸν ἔρωτα τῆς μητρὸς αὐτοῦ προεμένης τὸν βίον ἑκουσίως οὐ τεθυκὼς τῇ Ἀφροδίτῃ, τότε πρῶτον ἔκ τινων ἐνυπνίων τῆς Μελίσσης ὥρμησε τιμᾶν καὶ θεραπεύειν τὴν θεόν. Τῶν δὲ κεκλημένων ἑκάστῳ συνωρὶς ἱκανῶς κεκοσμημένη προσήχθη· καὶ γὰρ ὥρα θέρους ἦν, καὶ τὴν ὁδὸν ἅπασαν ὑπὸ πλήθους ἁμαξῶν καὶ ἀνθρώπων ἄχρι θαλάττης κονιορτὸς καὶ θόρυβος κατεῖχεν. ὁ μέντοι Θαλῆς τὸ ζεῦγος ἐπὶ ταῖς θύραις ἰδὼν καὶ μειδιάσας ἀφῆκεν. ἐβαδίζομεν οὖν ἐκτραπόμενοι διὰ τῶν χωρίων, καθ´ ἡσυχίαν, καὶ μεθ´ ἡμῶν τρίτος ὁ Ναυκρατίτης Νειλόξενος, ἀνὴρ ἐπιεικὴς καὶ τοῖς περὶ Σόλωνα καὶ Θαλῆν γεγονὼς ἐν Αἰγύπτῳ συνήθης. ἐτύγχανε δὲ πρὸς Βίαντα πάλιν ἀπεσταλμένος· ὧν δὲ χάριν οὐδ´ αὐτὸς ᾔδει, πλὴν ὑπενόει πρόβλημα δεύτερον αὐτῷ κομίζειν ἐν βιβλίῳ κατασεσημασμένον· εἴρητο γάρ, εἰ Βίας ἀπαγορεύσειεν, ἐπιδεῖξαι τοῖς σοφωτάτοις Ἑλλήνων τὸ βιβλίον. « Ἕρμαιον » ὁ Νειλόξενος ἔφη « μοι γέγονεν ἐνταῦθα λαβεῖν ἅπαντας ὑμᾶς, καὶ κομίζω τὸ βιβλίον ὡς ὁρᾷς ἐπὶ τὸ δεῖπνον. » ἅμα δ´ ἡμῖν ἐπεδείκνυε. Καὶ ὁ Θαλῆς γελάσας « εἴ τι κακόν, » εἶπεν, « αὖθις εἰς Πριήνην· διαλύσει γὰρ ὁ Βίας, ὡς διέλυσεν αὐτὸς τὸ πρῶτον. » « Τί δ´ ἦν, » ἔφην ἐγώ, « τὸ πρῶτον; » « Ἱερεῖον, » εἶπεν, « ἔπεμψεν αὐτῷ, κελεύσας τὸ πονηρότατον ἐξελόντα καὶ χρηστότατον ἀποπέμψαι κρέας. ὁ δ´ ἡμέτερος εὖ καὶ καλῶς τὴν γλῶτταν ἐξελὼν ἔπεμψεν· ὅθεν εὐδοκιμῶν δῆλός ἐστι καὶ θαυμαζόμενος. » « Οὐ διὰ ταῦτ´ » ἔφη « μόνον » ὁ Νειλόξενος, « ἀλλ´ οὐ φεύγει τὸ φίλος εἶναι καὶ λέγεσθαι βασιλέων καθάπερ ὑμεῖς, ἐπεὶ σοῦ γε καὶ τἄλλα θαυμάζει, καὶ τῆς [[wikt:en:πυραμίδος#Ancient_Greek|πυραμίδος]] τὴν μέτρησιν ὑπερφυῶς ἠγάπησεν, ὅτι πάσης ἄνευ πραγματείας καὶ μηδενὸς ὀργάνου δεηθεὶς ἀλλὰ τὴν βακτηρίαν στήσας ἐπὶ τῷ πέρατι τῆς σκιᾶς ἣν ἡ πυραμὶς ἐποίει, γενομένων τῇ ἐπαφῇ τῆς ἀκτῖνος δυεῖν τριγώνων, ἔδειξας ὃν ἡ σκιὰ πρὸς τὴν σκιὰν λόγον εἶχε τὴν πυραμίδα πρὸς τὴν βακτηρίαν ἔχουσαν. ἀλλ´, ὅπερ ἔφην, διεβλήθης μισοβασιλεὺς εἶναι, καί τινες ὑβριστικαί σου περὶ τυράννων ἀποφάσεις ἀνεφέροντο πρὸς αὐτόν, ὡς ἐρωτηθεὶς ὑπὸ Μολπαγόρου τοῦ Ἴωνος τί παραδοξότατον εἴης ἑωρακώς, ἀποκρίναιο ‘τύραννον γέροντα,’ καὶ πάλιν ἔν τινι πότῳ, περὶ τῶν θηρίων λόγου γενομένου, φαίης κάκιστον εἶναι τῶν μὲν ἀγρίων θηρίων τὸν τύραννον, τῶν δ´ ἡμέρων τὸν κόλακα· ταῦτα γάρ, εἰ καὶ πάνυ προσποιοῦνται διαφέρειν οἱ βασιλεῖς τῶν τυράννων, οὐκ εὐμενῶς ἀκούουσιν. » « Ἀλλὰ τοῦτο μέν, » εἶπεν ὁ Θαλῆς, « Πιττακοῦ ἐστιν, εἰρημένον ἐν παιδιᾷ ποτε πρὸς Μυρσίλον· ἐγὼ δὲ θαυμάσαιμ´ ἄν, » ἔφη, « οὐ τύραννον ἀλλὰ [[wikt:κυβερνήτης#Grec_ancien|'''κυβερνήτην''']] γέροντα θεασάμενος. πρὸς δὲ τὴν μετάθεσιν τὸ τοῦ νεανίσκου πέπονθα τοῦ βαλόντος μὲν ἐπὶ τὴν κύνα πατάξαντος δὲ τὴν μητρυιὰν καὶ εἰπόντος ‘οὐδ´ οὕτω κακῶς.’ διὸ καὶ Σόλωνα σοφώτατον ἡγησάμην οὐ δεξάμενον τυραννεῖν. καὶ Πιττακὸς οὗτος εἰ μοναρχίᾳ μὴ προσῆλθεν, οὐκ ἂν εἶπεν ὡς ‘χαλεπὸν ἐσθλὸν ἔμμεναι.’ Περίανδρος δ´ ἔοικεν ὥσπερ ἐν νοσήματι πατρῴῳ τῇ τυραννίδι κατειλημμένος οὐ φαύλως ἐξαναφέρειν, χρώμενος ὁμιλίαις ὑγιειναῖς ἄχρι γε νῦν καὶ συνουσίας ἀνδρῶν νοῦν ἐχόντων ἐπαγόμενος, ἃς δὲ '''Θρασύβουλος''' αὐτῷ κολούσεις τῶν ἄκρων οὑμὸς πολίτης ὑφηγεῖται μὴ προσιέμενος. γεωργοῦ γὰρ [[wikt:en:αἶρα#Ancient_Greek|αἴρας]] καὶ [[wikt:ononis|ὀνώνιδας]] ἀντὶ [[wikt:πυρός#Grec_ancien|πυρῶν]] καὶ [[wikt:κριθή#Grec_ancien|κριθῶν]] συγκομίζειν ἐθέλοντος οὐδὲν διαφέρει τύραννος ἀνδραπόδων μᾶλλον ἄρχειν ἢ ἀνδρῶν βουλόμενος· ἓν γὰρ ἀντὶ πολλῶν κακῶν ἀγαθὸν αἱ δυναστεῖαι τὴν τιμὴν ἔχουσι καὶ τὴν δόξαν, ἄνπερ ἀγαθῶν ὡς κρείττονες ἄρχωσι καὶ μεγάλων μείζονες εἶναι δοκῶσι· τὴν δ´ ἀσφάλειαν ἀγαπῶντας ἄνευ τοῦ καλοῦ προβάτων ἔδει πολλῶν καὶ ἵππων καὶ βοῶν ἄρχειν, μὴ ἀνθρώπων. ἀλλὰ γὰρ εἰς οὐδὲν προσήκοντας ἐμβέβληκεν ἡμᾶς, » ἔφη, « ὁ ξένος οὑτοσὶ λόγους, ἀμελήσας λέγειν τε καὶ ζητεῖν ἃ ἁρμόττει ἐπὶ δεῖπνον βαδίζουσιν. ἦ γὰρ οὐκ οἴει, καθάπερ ἑστιάσοντος ἔστι τις παρασκευή, καὶ δειπνήσοντος εἶναι; Συβαρῖται μὲν γὰρ ὡς ἔοικε πρὸ ἐνιαυτοῦ τὰς κλήσεις ποιοῦνται τῶν γυναικῶν, ὅπως ἐκγένοιτο κατὰ σχολὴν παρασκευασαμέναις ἐσθῆτι καὶ χρυσῷ φοιτᾶν ἐπὶ τὸ δεῖπνον· ἐγὼ δὲ πλείονος οἶμαι χρόνου δεῖσθαι τὴν ἀληθινὴν τοῦ δειπνήσοντος ὀρθῶς παρασκευήν, ὅσῳ χαλεπώτερόν ἐστιν ἤθει τὸν πρέποντα κόσμον ἢ σώματι τὸν περιττὸν ἐξευρεῖν καὶ ἄχρηστον. οὐ γὰρ ὡς ἀγγεῖον ἥκει κομίζων ἑαυτὸν ἐμπλῆσαι πρὸς τὸ δεῖπνον ὁ νοῦν ἔχων, ἀλλὰ καὶ σπουδάσαι τι καὶ παῖξαι καὶ ἀκοῦσαι καὶ εἰπεῖν ὡς ὁ καιρὸς παρακαλεῖ τοὺς συνόντας, εἰ μέλλουσι μετ´ ἀλλήλων ἡδέως ἔσεσθαι. καὶ γὰρ καὶ ὄψον πονηρὸν ἔστι παρώσασθαι, κἂν οἶνος ᾖ φαῦλος, ἐπὶ τὰς νύμφας καταφυγεῖν· σύνδειπνος δὲ κεφαλαλγὴς καὶ βαρὺς καὶ ἀνάγωγος παντὸς μὲν οἴνου καὶ ὄψου πάσης δὲ μουσουργοῦ χάριν ἀπόλλυσι καὶ λυμαίνεται, καὶ οὐδ´ ἀπεμέσαι τὴν τοιαύτην ἀηδίαν ἕτοιμόν ἐστιν, ἀλλ´ ἐνίοις εἰς ἅπαντα τὸν βίον ἐμμένει τὸ πρὸς ἀλλήλους δυσάρεστον, ὥσπερ ἑωλοκρασία τις ὕβρεως ἢ ὀργῆς ἐν οἴνῳ γενομένης. ὅθεν ἄριστα Χίλων, καλούμενος ἐχθές, οὐ πρότερον ὡμολόγησεν ἢ πυθέσθαι τῶν κεκλημένων ἕκαστον. ἔφη γὰρ ὅτι σύμπλουν ἀγνώμονα δεῖ φέρειν καὶ σύσκηνον οἷς πλεῖν ἀνάγκη καὶ στρατεύεσθαι· τὸ δὲ συμπόταις ἑαυτὸν ὡς ἔτυχε καταμιγνύειν οὐ νοῦν ἔχοντος ἀνδρός ἐστιν. ὁ δ´ Αἰγύπτιος σκελετός, ὃν ἐπιεικῶς εἰσφέροντες εἰς τὰ συμπόσια προτίθενται καὶ παρακαλοῦσι μεμνῆσθαι τάχα δὴ τοιούτους ἐσομένους, καίπερ ἄχαρις καὶ ἄωρος ἐπίκωμος ἥκων, ὅμως ἔχει τινὰ καιρόν, καὶ εἰ μὴ πρὸς τὸ πίνειν καὶ ἡδυπαθεῖν ἀλλὰ πρὸς φιλίαν καὶ ἀγάπησιν ἀλλήλων προτρέπεται, καὶ παρακαλεῖ τὸν βίον μὴ τῷ χρόνῳ βραχὺν ὄντα πράγμασι κακοῖς μακρὸν ποιεῖν. » </div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §2'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§2. La réception avait été préparée par '''Périandre''', non pas dans la ville même, mais dans son [[w:Cénacle|''cénacle'']] du port de [[w:Léchaion|''Léchée'']], près du temple de '''Vénus''' en l’honneur de laquelle il y avait même un sacrifice. Car depuis l’incestueux amour à la suite duquel sa mère avait volontairement abandonné la vie, '''Périandre''' n’avait pas sacrifié à '''Vénus''' ; et c’était alors la première fois que, d’après certains songes de '''Mélissa''' il s’était décidé à honorer la déesse et à lui rendre des hommages. Pour chacun des invités on avait amené un attelage approprié convenablement. Nous étions en été, et tout le long de la route, en raison du grand nombre de chariots et de piétons, ce n’était jusqu’à la mer que poussière et que bruit. Pourtant '''Thalès''', ayant vu l’attelage à notre porte, se mit à sourire et le renvoya. Nous partîmes donc à pied en faisant un détour, et à travers champs nous cheminâmes à loisir. Un troisième compagnon s’était joint à nous, '''Niloxène''' de ''Naucratie'', homme plein de mérite, que '''Thalès''' et '''Solon''' avaient autrefois beaucoup connu en ''Égypte''. Il se trouvait envoyé de nouveau vers '''Bias''' ; mais pour quelle mission ? Il n’en savait rien lui-même, hormis qu’il se soupçonnait porteur d’une seconde question à résoudre, contenue dans un pli cacheté; et il lui avait été dit, au cas où '''Bias''' renoncerait, de la présenter aux plus sages d’entre les Grecs. « C’est », dit '''Niloxène''', « une chance heureuse que de vous trouver ici tous, et j’apporte, comme vous voyez, cette lettre pour le banquet. » En même temps, il nous la faisait voir. '''Thalès''' se mit à rire : « Si c’est une question épineuse », dit-il, « qu’on aille encore à ''Priène'' : '''Bias''' la résoudra comme il a résolu la première. » — « Quelle était donc cette première question ? » lui demandai-je. — « Le roi d’Égypte », dit '''Thalès''', « avait envoyé à '''Bias''' une victime, en lui faisant dire d’en couper ce qu’il y avait de plus mauvais et de meilleur, et de le lui renvoyer. Notre sage, avec un discernement merveilleux, en ôta la langue et la fit porter au Roi. Voilà ce qui lui a valu une estime et une admiration si déclarée ». — « Cette raison n’est pas la seule », ajouta '''Niloxène''' ; « c’est encore, que '''Bias''' ne fuit pas, comme vous autres, l’amitié des rois eux-mêmes. Ainsi, vous, '''Thalès''', le roi d’Égypte vous admire beaucoup, et, entre autres choses, il a été, au-delà de ce qu’on peut dire, ravi de la manière dont vous avez mesuré la pyramide sans le moindre embarras et sans avoir eu besoin d’aucun instrument. Après avoir dressé votre bâton à l’extrémité de l’ombre que projetait la pyramide, vous construisîtes deux triangles par la tangence d’un rayon, et vous démontrâtes qu’il y avait la même proportion entre la hauteur du bâton et la hauteur de la pyramide qu’entre la longueur des deux ombres. Mais, comme j’ai dit, on vous accuse de détester les rois ; quelques boutades injurieuses prononcées par vous contre des ''tyrans'' ont été rapportées à [[w:Ahmôsis_II|'''Amasis''']]. Par exemple, l’Ionien '''Molpagore''' vous ayant demandé ce que vous aviez jamais vu de plus extraordinaire, vous lui auriez répondu : « C’est un tyran parvenu à la vieillesse. » Une autre fois, dans un festin, la conversation étant venue à tomber sur les bêtes féroces, vous auriez dit : « La plus méchante bête parmi les animaux sauvages, c’est le tyran, et parmi les animaux apprivoisés le flatteur. » De tels propos ne sont pas de ceux que les rois entendent avec plaisir, lors même qu’ils affectent de n’avoir rien de commun avec les tyrans. » Pour cette dernière réponse, dit '''Thalès''', elle est de '''Pittacus''' : il l’avait adressée un jour en plaisantant à '''Myrsile'''. Quant au premier propos, ce n’était pas « un tyran » que j’avais dit, mais « un [[wikt:κυβερνήτης#Grec_ancien|''pilote'']] », qui soit parvenu à la vieillesse. Toutefois, puisqu’on a changé la destination du mot, je fais comme le jeune homme qui, ayant jeté une pierre à un chien, atteignit sa belle-mère et s’écria : Même ainsi, ce n’est pas mal. » C’est pourquoi je regardai '''Solon''' comme éminemment sage lorsqu’il n’accepta pas la tyrannie ; et '''Pittacus''', s’il n’eût approché de la monarchie, n’aurait pas eu à dire : « Il est difficile d’être homme de bien. » Quant à '''Périandre''', il semble qu’ayant été saisi par le souverain pouvoir comme par une maladie de famille, il ne s’en tire pas trop mal. Il use, au moins jusqu’à présent, de sociétés salutaires. Il réunit, pour entretenir commerce avec eux, ses hommes remplis de sens ; et le conseil que lui a donné mon compatriote [[w:Thrasybule_de_Milet|'''Thrasybule''']] [[#Thrasybule|<span id="Thrasybule_back"><sup>'''I'''</sup></span>]], de décapiter l’aristocratie, il ne l’a pas accepté. Entre un laboureur qui aimerait mieux voir dans son champ de l’[[w:Ivraie|''ivraie'']] ou de l’[[w:Orobanche|''orobanche'']] que de l’orge ou du blé, et un tyran qui veut régner sur des esclaves plutôt que sur des hommes de coeur, je ne vois aucune différence. Un seul bien compense les maux nombreux attachés au pouvoir des tyrans : c’est la gloire et l’honneur qui leur sont réservés lorsque, commandant à des hommes vertueux, ils sont plus vertueux eux-mêmes, et qu’au milieu de grands ils se montrent plus grands. Ceux qui préfèrent leur sûreté en renonçant à ce beau rôle, étaient faits pour réunir sous leur main beaucoup de moutons, de chevaux et de boeufs, mais non des hommes. » « Du reste », continua '''Thalès''', « ce sont propos sans portée aucune que ceux où nous a jetés cet étranger, et nous avons omis de dire et de chercher les choses qui conviennent bien à des gens partis pour un banquet. Ne croyez-vous pas, '''Nicarque''', qu’il y ait des préparatifs à faire quand on vient prendre place à un festin, comme il y en a pour celui qui doit le donner ? Les [[w:Sybaris|''Sybarites'']] [[#Sybaris|<span id="Sybaris_back"><sup>'''II'''</sup></span>]], à ce qu’il paraît, s’y prennent un an d’avance pour adresser leurs invitations aux femmes, afin qu’elles puissent à loisir préparer leur toilette et leurs bijoux en or avant de se rendre au festin; et, selon moi, il faut plus de temps encore à un convive pour les préparatifs vraiment nécessaires, parce qu’il est plus difficile de trouver un ajustement convenable pour son moral que la vaine et inutile parure dont on s’inquiète pour son corps. Un homme sensé ne se transporte pas à un festin comme un bocal qu’il s’agit d’y remplir. Il songe à trouver là une occasion de passer tour à tour du sérieux au badinage, d’entendre et de tenir lui-même ces propos auxquels la circonstance invite les convives s’ils veulent se rendre la réunion agréable les uns aux autres. En effet on est libre de repousser un mauvais ragoût, et si le vin ne vaut rien on peut « recourir aux [[w:Naïades|''Naïades'']] »; mais un convive qui vous donne mal à la tête, qui est lourd, qui ne sait pas se conduire, vous fait perdre et vous gâte le plaisir de tout vin, de toute bonne chère, de toute musique. On n’est même pas le maître de se débarrasser aussi complétement qu’on le voudrait d’un tel désagrément. Quelques-uns en gardent tant qu’ils vivent du mécontentement les uns contre les autres : il leur semble qu’il leur reste comme un arrière-goût de viandes mal digérées, parce qu’ils conservent le souvenir d’injures ou de colères échangées dans le vin. C’est pour cela que '''Chilon''', invité hier, n’a pas voulu promettre avant d’avoir su le nom de chacun des convives : « Car on est bien obligé, a-t-il dit, de supporter un désagréable compagnon de traversée, de tente, quand il faut être sur terre ou à l’armée ; mais se mêler indifféremment à table avec les premiers venus, n’est pas le propre d’un homme sensé. » Le squelette des ''Égyptiens'', qu’ils ont la sage coutume de produire et de placer dans la salle du festin afin d’engager à se souvenir que l’on sera bientôt comme lui, survient là comme un convive assez désagréable et intempestif, mais enfin la présence s’en explique. Si cette vue n’excite pas à boire et à se réjouir, elle engage du moins à s’aimer, à se chérir les uns les autres, et elle exhorte à ne pas allonger par des tracas pénibles une existence dont la durée est si courte. </div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §2'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> {{Boîte déroulante début|titre=NdA trad. par Victor Bétolaud de 1870|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Thrasybule_back|<span id="Thrasybule"><sup>I</sup></span>]] Du nom propre grec ancien Θρᾰσῠ́βουλος / Thrăsŭ́boulos [[wikt:en:Θρασύβουλος#Ancient_Greek|(en)]] ;<br /><p style="margin: 0 2em; text-indent: 15px">➥ de l’adjectif [[wikt:θρασύς#Grec_ancien|θρᾰσύς / thrăsús]], « confiant, audacieux » ;<br /><p style="margin: 0 2em; text-indent: 15px">➥ +‎ du nom commun [[wikt:βουλή#Grec_ancien|βουλή / boulế]], « Volonté. Décision, conseil. Conseil, sénat athénien. »; du verbe [[wikt:βούλομαι#Grec_ancien|βούλομαι / boúlomai]], « Vouloir, désirer, souhaiter. Vouloir bien, consentir à. » ;<br /><p style="margin: 0 2em; text-indent: 15px">➥ +‎ -ος (-os).<br /><br /><p style="margin: 0 2em; text-indent: 15px">[[#Sybaris_back|<span id="Sybaris"><sup>II</sup></span>]] Du nom propre grec ancien Σῠ́βᾰρῐς / Sŭ́bărĭs [[wikt:en:Σύβαρις#Ancient_Greek|(en)]] ;<br /><p style="margin: 0 2em; text-indent: 15px">[[w:Colonisation grecque|Colonie grecque]] du sud de l’Italie (en [[w:Calabre|Calabre]] actuelle), fondée au [[w:VIIIe_siècle_av._J.-C.|VIII<sup>ème</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]] dans le cadre du mouvement d’établissement et d’[[w:Colonisation_grecque|''essaimage'']] des Grecs vers l’Occident, particulièrement en [[w:Grande-Grèce|''Grande-Grèce'']]. Réputée dès l’Antiquité pour sa richesse devenue proverbiale, ainsi que pour son emprise sur les peuples voisins et différentes cités grecques de son voisinage, elle est détruite à l’issue d’une [[w:Guerre entre Sybaris et Crotone|guerre]] qui l’oppose à [[w:Crotone|''Crotone'']] à la fin du [[w:VIe_siècle_av._J.-C.|VI<sup>ème</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]], et enfouie sous les eaux du fleuve ''Crathis'' (aujourd’hui [[Crati]]), avant de voir son site réoccupé, soixante ans plus tard, par la colonie [[w:Panhellénisme|''panhellénique'']] de [[w:Thourioï|''Thourioï'']].'''<br/><br/></div> {{Boîte déroulante fin}} <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">'''Périandre''' avait fait préparer le banquet, non à la ville même, mais au ''port de Léchée'' [[#Léchée_NdT_DR|<span id="Léchée_NdT_DR_back"><sup>1</sup></span>]], dans une salle voisine du ''temple de Vénus'', à qui l’on devait offrir un sacrifice. Depuis que sa mère, victime d’un malheureux amour [[#Cratée_NdT_DR|<span id="Cratée_NdT_DR_back"><sup>2</sup></span>]], s’était donné la mort, il n’avait pas encore sacrifié à cette déesse, et c’était la première fois qu’il y pensait, d’après un songe de '''Mélisse''' [[#Mélisse_NdT_DR|<span id="Mélisse_NdT_DR_back"><sup>3</sup></span>]]. Nous étions dans les plus grandes chaleurs de l’été. Le grand nombre des voitures et des gens de pied qui fréquentaient le chemin qui conduit à la mer, l’avaient couvert de poussière et le rendaient fort incommode pour les voyageurs. On avait amené, pour chaque convive, un char commode et proprement orné. '''Thalès''', en voyant le sien à ma porte, se mit à sourire et le refusa. Nous primes donc, à travers les champs, un sentier détourné, et nous allâmes, en nous promenant, suivis de '''Niloxène''' de ''Naucrate'' [[#Niloxène_NdT_DR|<span id="Niloxène_NdT_DR_back"><sup>4</sup></span>]], homme du plus grand mérite, que '''Thalès''' et '''Solon''' avaient autrefois beaucoup connu en ''Égypte''. Il était envoyé, pour la seconde fois, vers '''Bias''', sans savoir lui-même quel était l’objet de sa mission. Il se doutait seulement que la lettre dont '''Amasis''' l’avait chargé contenait une seconde question à résoudre. Il avait ordre, en cas que '''Bias''' refusât d’y répondre, de la proposer aux plus sages d’entre les ''Grecs''. Dès qu’il m’eut aperçu, il me dit en me montrant sa lettre : « J’ai du bonheur aujourd’hui. Cette lettre vous trouve tous réunis. Je la porte au banquet, comme vous voyez. - Si c’est une question épineuse, dit '''Thalès''' en souriant, retournez à ''Priene'' [[#Priene_NdT_DR|<span id="Priene_NdT_DR_back"><sup>5</sup></span>]], '''Bias''' la résoudra, comme il a résolu la première. - Quelle était cette première question, demandai-je à '''Thalès''' ? - Le roi d’Égypte, me répondit-il, avait envoyé une victime à '''Bias''', en lui faisant dire d’en couper ce qu’il y avait de meilleur et de plus mauvais, et de le lui renvoyer. Notre sage, fort habilement en ôta la langue, qu’il lui fit porter. Voilà ce qui lui a mérité l’estime et l’admiration de ce prince. - Ajoutez encore à cette première raison, dit '''Niloxène''', que '''Bias''' ne dédaigne pas, comme vous, l’amitié des rois ; car '''Amasis''' n’a pas moins d’estime pour vous ; il admire surtout la manière dont vous mesurâtes, avec la plus grande facilité et sans aucun instrument mathématique, la hauteur de la pyramide. En dressant votre bâton à l’extrémité de l’ombre qu’elle faisait sur la terre, le rayon solaire qui touchait le sommet de la pyramide et l’extrémité du bâton forma deux triangles ; et vous démontrâtes qu’il y avait la même proportion entre la hauteur du bâton et celle de la pyramide qu’entre la longueur des ombres projetées par l’une et par l’autre. Mais, comme je viens de le dire, on vous accuse, auprès de lui, d’être l’ennemi des rois, et on lui a rapporté plusieurs propos injurieux que vous avez tenus contre les tyrans [[#tyrans_NdT_DR|<span id="tyrans_NdT_DR_back"><sup>6</sup></span>]] ; entre autres que l’''Ionien'' '''Molpagore''' [[#Molpagore_NdT_DR|<span id="Molpagore_NdT_DR_back"><sup>7</sup></span>]] vous ayant demandé ce qui vous paraîtrait plus extraordinaire dans la vie, vous lui répondîtes : de voir vieillir un tyran. Une autre fois, comme on vint à parler, dans un repas, du naturel des animaux, vous dîtes que le plus méchant des animaux sauvages était le tyran, et des animaux domestiques, le flatteur. Les rois, quoiqu’ils affectent de ne rien avoir de commun avec les tyrans, n’aiment pas cependant ces sortes de discours. Cette dernière réponse, dit '''Thalès''', est de '''Pittacus''' ; il la fit un jour, en plaisantant, à ''Myrsile'' [[#Myrsile_NdT_DR|<span id="Myrsile_NdT_DR_back"><sup>8</sup></span>]]. Dans la première, je parlais d’un pilote, et non pas d’un tyran. Mais puisqu’on en a fait application au tyran, je dirai comme ce jeune homme qui, jetant une pierre à son chien, en avait atteint sa belle-mère : « Le coup n’est pas perdu. » Aussi jamais '''Solon''' ne montra-t-il plus de sagesse, à mon gré, que lorsqu’il refusa la tyrannie ; et si '''Pittacus''' n’eût pas été contraint de l’accepter, il n’eût point dit qu’il est à charge d’être vertueux [[#Pittacus_NdT_DR|<span id="Pittacus_NdT_DR_back"><sup>9</sup></span>]]. Il est vrai que '''Périandre''', qui a succédé à l’autorité des tyrans, paraît jusqu’ici opposer à ce mal héréditaire un remède puissant, par le soin qu’il a de rechercher les entretiens et les avis salutaires des hommes vertueux , et par l’horreur qu’il a témoignée pour le conseil barbare que notre compatriote '''Thrasybule''' lui donnait de faire mourir les grands. Un tyran qui veut commander à des esclaves, plutôt qu’à des hommes, ressemble à un laboureur qui aimerait mieux voir son champ couvert de passereaux et de sauterelles que d’orge et de froment. Le seul bien qui puisse compenser tant de maux attachés au pouvoir des tyrans, c’est d’avoir, même sur les plus grands et les plus vertueux de leurs sujets, la supériorité de l’honneur et de la vertu. Ceux qui préfèrent la sûreté à la gloire sont faits pour commander à des troupeaux, et non pour gouverner des hommes. « Mais '''Niloxène''' nous a jetés dans une conversation absolument étrangère à notre objet, et nous a fait négliger ce qui devait nous occuper en allant au banquet. Ne pensez-vous pas que les conviés ont, aussi bien que leur hôte, des apprêts à faire. Les ''Sybarites'', dit-on, prient les femmes à souper un an d’avance, afin qu’elles puissent préparer à loisir leurs habits et leurs bijoux [[#Sybarites_NdT_DR|<span id="Sybarites_NdT_DR_back"><sup>10</sup></span>]]. Pour moi, je pense qu’il faut encore plus de temps à un convive pour faire tous les préparatifs convenables, parcequ’il est bien plus difficile d’orner son esprit comme il faut, que de donner à son corps une parure vaine et superflue. Un homme sensé doit aller à un festin, non pour y remplir son estomac, comme un vase, mais pour écouter et tenir à son tour des propos utiles ou amusants, suivant les circonstances. C’est le seul moyen de rendre le repas agréable aux convives. En effet, on peut laisser un mauvais ragoût, et recourir à l’eau quand le vin n’est pas bon ; mais un convive désagréable, importun et fatigant, fait perdre tout le plaisir de la bonne chère et de la musique. On ne peut se délivrer de l’ennui qu’il cause, et souvent même une parole vive ou offensante qu’il se sera permise dans la liberté de la table, fait naître des aversions et des ressentiments qui ne finissent qu’avec la vie. Aussi '''Chilon''', invité hier à ce banquet, ne voulut-il accepter qu’après qu’on lui eut nommé tous les convives. Il disait avec raison, que quand on est sur mer ou dans un camp, il faut nécessairement supporter les compagnons qui nous sont associés, quelque fâcheux qu’ils soient ; mais dans un festin, il n’est pas d’un homme sensé de se mêler indifféremment avec toutes sortes de personnes. Le squelette que les ''Égyptiens'' placent ordinairement à côté d’eux dans leurs repas, en s’exhortant à penser qu’ils seront bientôt dans le même état, est, à la vérité, un compagnon de table assez triste et assez déplacé. Il est néanmoins utile, sinon pour les exciter au plaisir, du moins pour les porter à la bienveillance et à l’amitié réciproque, et pour les avertir de ne pas remplir d’aigreur et de querelles le temps si court de la vie [[#squelette_NdT_DR|<span id="squelette_NdT_DR_back"><sup>11</sup></span>]]. » </div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Léchée_NdT_DR_back|<span id="Léchée_NdT_DR"><sup>1</sup></span>]] L’isthme de ''Corinthe'' avait deux ports, l’un sur la côte orientale, appelé ''Cenchrées'' ; et l’autre sur la côte occidentale, nommé ''Léchée''. Pausanias, qui a donné une description si détaillée de la ''Grèce'', parle d’un ''temple de Vénus'', bâti sur le port de ''Cenchrées'', et dont la statue était de marbre ; mais il ne fait pas mention de celui que cite Plutarque, et qu’il place près du port occidental. ''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Cratée_NdT_DR_back|<span id="Cratée_NdT_DR"><sup>2</sup></span>]] La mère de Périandre se nommait Cratée. On peut voir dans Parthenius la manière dont elle conçut et nourrit une passion incestueuse pour son fils, les moyens qu'elle prit pour la satisfaire sans être connue, et comment elle fut découverte. Les remords qu’elle en eut l’obligèrent de se donner la mort.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Mélisse_NdT_DR_back|<span id="Mélisse_NdT_DR"><sup>3</sup></span>]] Mélisse était fille de Proclès, roi d’[[w:Épidaure_(cité_antique)|''Épidaure'']]. On prétend que Périandre en devint éperdument amoureux pour l’avoir vue dans l’habillement ordinaire aux femmes du ''Péloponnèse''. Cette passion toutefois ne l’empêcha pas de partager son cœur entre elle et plusieurs concubines. Elles parvinrent à l’irriter contre elle au point qu’un jour, par un mouvement de jalousie, il la frappa d’un coup de pied, sans songer qu’elle était enceinte, et la fit mourir.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Niloxène_NdT_DR_back|<span id="Niloxène_NdT_DR"><sup>4</sup></span>]] Niloxène signifie hôte du ''Nil'' : ce nom semble indiquer que c’est un personnage supposé.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Priene_NdT_DR_back|<span id="Priene_NdT_DR"><sup>5</sup></span>]] Ville d’''Ionie'', colonie des ''Thébains'' et patrie de Bias.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#tyrans_NdT_DR_back|<span id="tyrans_NdT_DR"><sup>6</sup></span>]] Par le mot [[wikt:τύραννος#Grec_ancien|τύραννος]], que nous ne pouvons rendre en français que par celui de tyran, les ''Grecs'' entendaient, non pas seulement, comme nous, un prince injuste et cruel ; mais, en général, tout homme qui s’était emparé de l’autorité monarchique dans un état libre, sans qu’elle lui fût légitimement acquise.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Molpagore_NdT_DR_back|<span id="Molpagore_NdT_DR"><sup>7</sup></span>]] Ce Molpagore est peut-être le père d’Aristagore, que Darius établit tyran à ''Milet''.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Myrsile_NdT_DR_back|<span id="Myrsile_NdT_DR"><sup>8</sup></span>]] Myrsile n’est guère mieux connu que Molpagore. Strabon le met au nombre de ces ''Lesbiens'' ambitieux, qui, du temps de Pittacus, s’étaient emparés de l’autorité souveraine à ''Lesbos'', et dont le poète [[w:Alcée_de_Mytilène|Alcée]] avait flétri la mémoire.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Pittacus_NdT_DR_back|<span id="Pittacus_NdT_DR"><sup>9</sup></span>]] Pittacus en se voyant forcé, dans sa vieillesse, de reprendre le gouvernement des affaires, prononça cette maxime.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Sybarites_NdT_DR_back|<span id="Sybarites_NdT_DR"><sup>10</sup></span>]] Cet usage des ''Sybarites'' n’avait lieu que dans les festins publics.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#squelette_NdT_DR_back|<span id="squelette_NdT_DR"><sup>11</sup></span>]] Cet usage, d’abord particulier aux ''Egyptiens'', avait ensuite passé chez les ''Grecs'', de qui les ''Romains'' l’empruntèrent. ''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' pp.326-330, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe III.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage de la reconnaissance de la sagesse de '''Cléobuline''' ''« Eumétis »'' par '''Thalès''', de l’humilité de ce dernier et de son [[w:Cynisme|''cynisme'']], en particulier à la vue d’un ''centaure'' [[#centaure|<span id="centaure_back"><sup>'''I'''</sup></span>]]. </div> {{Boîte déroulante début|titre=NdA centaure|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#centaure_back|<span id="centaure"><sup>I</sup></span>]] Il s’agit d’une adaptation d’une fable de [[w:Phèdre_(fabuliste)|Phèdre]] [[#Phèdre|<span id="Phèdre_back"><sup>II</sup></span>]], où Ésope [[#Ésope_back|<sup>⤴️</sup>]] remplace Thalès [https://books.openedition.org/pur/12177 {{info|<sup>🔍</sup>|Gourmelen, Laurent. « Imposture ou dualité : que faut-il penser de la naissance d’un centaure ? Sur un curieux passage du Banquet des Sept Sages (Plutarque, Moralia, 149 C-F) ». L’imposture dans la littérature, édité par Arlette Bouloumié, Presses universitaires de Rennes, 2011, https://doi.org/10.4000/books.pur.12177.}}] :'''<br /><br /><p style="margin: 0 2em; text-align: center;">« Un homme d’expérience en sait plus long qu’un devin. C’est un proverbe; d’où vient-il? on ne le dit pas. Ma fable, la première, va l’apprendre.<br /><br />Un fermier avait des brebis qui lui donnaient des agneaux à tête humaine. Épouvanté d’une monstruosité pareille, il court tout affligé consulter les devins. L’un répond que la vie du maître est menacée, et qu’il faut conjurer le péril par une victime. L’autre assure au fermier que sa femme lui est infidèle, et que cela signifie l’illégitimité des enfants; mais qu’un sacrifice important peut tout expier. Enfin, tous diffèrent d’opinion et ne font qu’aggraver le souci du paysan. '''Ésope''', vieillard plein de finesse et de sagacité, et que la nature ne put jamais tromper, se trouvait là par hasard : "Villageois, lui dit-il, si tu veux faire cesser ce prodige, donne des femmes tes bergers." » <br /><br /><p style="text-align: right; margin: 0 2em 0 1em;">'''[https://remacle.org/bloodwolf/fabulistes/phedre/livre3.htm <u>Fables de Phèdre</u>, livre III], §3 - Ésope et le paysan, traduites par M. E. Panckoucke, 1864.<br /><br /><p style="margin: 0 2em; text-indent: 15px;">[[#Phèdre_back|<span id="Phèdre"><sup>II</sup></span>]] [[w:Nom_romain|Tria Nomina]] en latin {{Info|Caius|praenomen, nom individuel du citoyen romain}} {{Info|Iulius|nomen, nom de famille}} {{Info|Phaedrus ou Phaeder|cognomen, surnom héréditaire, servant à distinguer les diverses branches d’une même gens}} ;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ du grec ancien Φαῖδρος / Phaîdros [[wikt:en:Φαῖδρος#Ancient_Greek|(en)]] ; de l’adjectif phaidrós / phaidrós [[wikt:en:φαιδρός#Ancient_Greek|(en)]], « 1. Lumineux, rayonnant. 2. (au sens figuré) Rayonnant de joie, brillant, joyeux. » ;<br /><p style="margin: 0 2em; text-indent: 15px;">Fabuliste latin d’origine ''[[w:thrace|thrace]]'', esclave à son arrivée à ''Rome'' et affranchi par un décret d’[[w:Auguste|Auguste]]. Près d’un tiers de son œuvre est repris d’Ésope dont il adapte les fables ; les deux autres tiers sont issus de son imagination. Tout comme son prédécesseur, Phèdre raconte des histoires d’animaux, mais il met en scène aussi des personnages humains et parmi ceux-ci Ésope :'''<br /><br /><p style="margin: 0 2em; text-align: center;">« C’est '''Ésope''' qui, le premier, a trouvé la matière : moi, je l’ai polie en vers [[w:Sénaire iambique|''sénaires'']]. Ce petit livre a un double mérite : il fait rire et il donne de sages conseils pour la conduite de la vie. À celui qui viendrait me reprocher injustement de faire parler non seulement les animaux, mais même les arbres, je rappellerai que je m’amuse ici à de pures fictions. »<br /><p style="margin: 0 2em; text-align: right;">'''Phèdre, ''Fables'', I, prologue'''<br /><br /><p style="margin: 0 2em; text-align: center;">« Le genre d’'''Ésope''' est tout en exemples, et on ne doit y chercher que le but de ses fables : corriger les erreurs des hommes, et exciter en eux une vive émulation. Quelle que soit donc la nature d’un récit, s’il captive, et remplit son objet, il se recommande de lui-même, sans aucun nom d’auteur. Aussi suivrai-je scrupuleusement les traces du vieillard. »<br /><p style="margin: 0 2em; text-align: right;">'''Phèdre, ''Fables'', II, prologue'''<br /><br /><p style="margin: 0 2em; text-indent: 15px;">'''Au total, il composera cent-vingt-trois fables, divisées en cinq livres.<br /><p style="text-align: right; margin: 0 2em;">(vers [[w:-14|-14]] <sup>[[w:Ier_siècle_av._J.-C.|⏳]]</sup>, en ''Thrace'' ― vers [[w:50|50]] <sup>[[w:Ier_siècle|⏳]]</sup>, lieu de décès inconnu)'''<br /><br /> </div>{{Boîte déroulante fin}} :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§3. Ἐν τοιούτοις λόγοις γενόμενοι κατὰ τὴν ὁδὸν ἀφικόμεθα πρὸς τὴν οἰκίαν, καὶ λούσασθαι μὲν ὁ Θαλῆς οὐκ ἠθέλησεν, ἀληλιμμένοι γὰρ ἦμεν· ἐπιὼν δὲ τούς τε δρόμους ἐθεᾶτο καὶ τὰς παλαίστρας καὶ τὸ ἄλσος τὸ παρὰ τὴν θάλατταν ἱκανῶς διακεκοσμημένον, ὑπ´ οὐδενὸς ἐκπληττόμενος τῶν τοιούτων, ἀλλ´ ὅπως μὴ καταφρονεῖν δοκοίη μηδ´ ὑπερορᾶν τοῦ Περιάνδρου τῆς φιλοτιμίας. τῶν δ´ ἄλλων τὸν ἀλειψάμενον ἢ λουσάμενον οἱ θεράποντες εἰσῆγον εἰς τὸν ἀνδρῶνα διὰ τῆς στοᾶς. Ὁ δ´ Ἀνάχαρσις ἐν τῇ στοᾷ καθῆστο, καὶ παιδίσκη προειστήκει τὴν κόμην ταῖς χερσὶ διακρίνουσα. ταύτην ὁ Θαλῆς ἐλευθεριώτατά πως αὐτῷ προσδραμοῦσαν ἐφίλησε καὶ γελάσας « οὕτως, » ἔφη, « ποίει καλὸν τὸν ξένον, ὅπως ἡμερώτατος ὢν μὴ φοβερὸς ᾖ τὴν ὄψιν ἡμῖν μηδ´ ἄγριος. » Ἐμοῦ δ´ ἐρομένου περὶ τῆς παιδὸς ἥτις εἴη, « τὴν σοφήν, » ἔφη, « καὶ περιβόητον ἀγνοεῖς Εὔμητιν; οὕτω γὰρ ταύτην ὁ πατὴρ αὐτός, οἱ δὲ πολλοὶ πατρόθεν ὀνομάζουσι Κλεοβουλίνην. » Καὶ ὁ Νειλόξενος εἶπεν « ἦ που τὴν περὶ τὰ αἰνίγματα δεινότητα καὶ σοφίαν, » ἔφη, « τῆς κόρης ἐπαινεῖς· καὶ γὰρ εἰς Αἴγυπτον ἔνια τῶν προβαλλομένων ὑπ´ αὐτῆς διῖκται. » « Οὐκ ἔγωγ´, » εἶπεν ὁ Θαλῆς· « τούτοις γὰρ ὥσπερ ἀστραγάλοις, ὅταν τύχῃ, παίζουσα χρῆται καὶ διαβάλλεται πρὸς τοὺς ἐντυχόντας. ἀλλὰ καὶ φρόνημα θαυμαστὸν καὶ νοῦς ἔνεστι πολιτικὸς καὶ φιλάνθρωπον ἦθος, καὶ τὸν πατέρα τοῖς πολίταις πραότερον ἄρχοντα παρέχει καὶ δημοτικώτερον. » « Εἶεν, » ὁ Νειλόξενος ἔφη, « καὶ φαίνεται βλέποντι πρὸς τὴν λιτότητα καὶ ἀφέλειαν αὐτῆς· Ἀνάχαρσιν δὲ πόθεν οὕτω τημελεῖ φιλοστόργως; » « Ὅτι, » ἔφη, « σώφρων ἀνήρ ἐστι καὶ πολυμαθής, καὶ τὴν δίαιταν αὐτῇ καὶ τὸν καθαρμόν, ᾧ χρῶνται Σκύθαι περὶ τοὺς κάμνοντας, ἀφθόνως καὶ προθύμως παραδέδωκε. καὶ νῦν οἶμαι περιέπειν αὐτὴν τὸν ἄνδρα καὶ φιλοφρονεῖσθαι, μανθάνουσάν τι καὶ προσδιαλεγομένην. » Ἤδη δὲ πλησίον οὖσιν ἡμῖν τοῦ ἀνδρῶνος ἀπήντησεν Ἀλεξίδημος ὁ Μιλήσιος (ἦν δὲ Θρασυβούλου τοῦ τυράννου νόθος) καὶ ἐξῄει τεταραγμένος καὶ σὺν ὀργῇ τινι πρὸς αὑτὸν οὐδὲν ἡμῖν γε σαφὲς διαλεγόμενος. ὡς δὲ τὸν Θαλῆν εἶδε, μικρὸν ἀνενεγκὼν καὶ καταστάς « οἵαν ὕβριν, » εἶπεν, « εἰς ἡμᾶς Περίανδρος ὕβρικεν, ἐκπλεῦσαι μὲν οὐκ ἐάσας ὡρμημένον ἀλλὰ προσμεῖναι δεηθεὶς τὸ δεῖπνον, ἐλθόντι δὲ νέμων κλισίαν ἄτιμον, Αἰολεῖς δὲ καὶ νησιώτας (καὶ τίνας γὰρ οὐχί;) Θρασυβούλου προτιμῶν· Θρασύβουλον γὰρ ἐν ἐμοὶ τὸν πέμψαντα προπηλακίσαι βουλόμενος καὶ καταβαλεῖν ὡς δὴ περιορῶν δῆλός ἐστιν. » « Εἶτ´, » ἔφη, « σὺ δέδιας μὴ καθάπερ Αἰγύπτιοι τοὺς ἀστέρας ὑψώματα καὶ ταπεινώματα λαμβάνοντας ἐν τοῖς τόποις οὓς διεξίασι γίγνεσθαι βελτίονας ἢ χείρονας ἑαυτῶν λέγουσιν, οὕτως ἡ περὶ σὲ διὰ τὸν τόπον ἀμαύρωσις ἢ ταπείνωσις γένηται; καὶ τοῦ Λάκωνος ἔσῃ φαυλότερος, ὃς ἐν χορῷ τινι κατασταθεὶς εἰς τὴν ἐσχάτην χώραν ὑπὸ τοῦ ἄρχοντος ‘εὖ γ´,’ εἶπεν, ‘ἐξεῦρες, ὡς καὶ αὕτα ἔντιμος γένηται.’ οὐ καταλαβόντας, » ἔφη, « τόπον μετὰ τίνας κατακείμεθα δεῖ ζητεῖν, μᾶλλον δ´ ὅπως εὐάρμοστοι τοῖς συγκατακειμένοις ὦμεν, ἀρχὴν καὶ λαβὴν φιλίας εὐθὺς ἐν αὐτοῖς ζητοῦντες, μᾶλλον δ´ ἔχοντες τὸ μὴ δυσκολαίνειν ἀλλ´ ἐπαινεῖν ὅτι τοιούτοις συγκατεκλίθημεν· ὡς ὅ γε τόπῳ κλισίας δυσχεραίνων δυσχεραίνει τῷ συγκλίτῃ μᾶλλον ἢ τῷ κεκληκότι, καὶ πρὸς ἀμφοτέρους ἀπεχθάνεται. » « Λόγος, » ἔφη, « ταῦτ´ ἄλλως ἐστίν » ὁ Ἀλεξίδημος, « ἔργῳ δὲ καὶ τοὺς σοφοὺς ὑμᾶς ὁρῶ τὸ τιμᾶσθαι διώκοντας, » καὶ ἅμα παραμειψάμενος ἡμᾶς ἀπῆλθε. Καὶ ὁ Θαλῆς πρὸς ἡμᾶς τὴν ἀτοπίαν τοῦ ἀνθρώπου θαυμάζοντας, « ἔμπληκτος, » ἔφη, « καὶ ἀλλόκοτος φύσει, ἐπεὶ καὶ μειράκιον ὢν ἔτι, μύρου σπουδαίου Θρασυβούλῳ κομισθέντος, εἰς ψυκτῆρα κατεράσας μέγαν καὶ προσεγχέας ἄκρατον ἐξέπιεν, ἔχθραν ἀντὶ φιλίας Θρασυβούλῳ διαπεπραγμένος. » Ἐκ τούτου περιελθὼν ὑπηρέτης « κελεύει σε Περίανδρος, » ἔφη, « καὶ Θαλῆν παραλαβόντα τοῦτον ἐπισκέψασθαι τὸ κεκομισμένον ἀρτίως αὐτῷ πότερον ἄλλως γέγονεν ἤ τι σημεῖόν ἐστι καὶ τέρας· αὐτὸς μὲν γὰρ ἔοικε τεταράχθαι σφόδρα, μίασμα καὶ κηλῖδα τῆς θυσίας ἡγούμενος. » ἅμα δ´ ἀπῆγεν ἡμᾶς εἴς τι οἴκημα τῶν περὶ τὸν κῆπον. ἐνταῦθα νεανίσκος ὡς ἐφαίνετο νομευτικός, οὔπω γενειῶν ἄλλως τε τὸ εἶδος οὐκ ἀγεννής, ἀναπτύξας τινὰ διφθέραν ἔδειξεν ἡμῖν βρέφος ὡς ἔφη γεγονὸς ἐξ ἵππου, τὰ μὲν ἄνω μέχρι τοῦ τραχήλου καὶ τῶν χειρῶν ἀνθρωπόμορφον, τὰ λοιπὰ δ´ ἔχον ἵππου, τῇ δὲ φωνῇ καθάπερ τὰ νεογνὰ παιδάρια κλαυθμυριζόμενον. ὁ μὲν οὖν Νειλόξενος, « Ἀλεξίκακε » εἰπών, ἀπεστράφη τὴν ὄψιν, ὁ δὲ Θαλῆς προσέβλεπε τῷ νεανίσκῳ πολὺν χρόνον, εἶτα μειδιάσας (εἰώθει δ´ ἀεὶ παίζειν πρὸς ἐμὲ περὶ τῆς τέχνης) « ἦ που τὸν καθαρμόν, ὦ Διόκλεις, » ἔφη, « κινεῖν διανοῇ καὶ παρέχειν πράγματα τοῖς ἀποτροπαίοις, ὥς τινος δεινοῦ καὶ μεγάλου συμβάντος; » « Τί δ´, » εἶπον, « οὐ μέλλω; στάσεως γάρ, ὦ Θαλῆ, καὶ διαφορᾶς τὸ σημεῖόν ἐστι, καὶ δέδια μὴ μέχρι γάμου καὶ γενεᾶς ἐξίκηται, πρὶν ἢ τὸ πρῶτον ἐξιλάσασθαι μήνιμα, τῆς θεοῦ δεύτερον ὡς ὁρᾷς προφαινούσης. » Πρὸς τοῦτο μηδὲν ἀποκρινάμενος ὁ Θαλῆς ἀλλὰ γελῶν ἀπηλλάττετο. καὶ τοῦ Περιάνδρου πρὸς τὰς θύρας ἀπαντήσαντος ἡμῖν καὶ διαπυθομένου περὶ ὧν εἴδομεν, ἀφεὶς ὁ Θαλῆς με καὶ λαβόμενος τῆς ἐκείνου χειρὸς ἔφη, « ἃ μὲν Διοκλῆς κελεύει δράσεις καθ´ ἡσυχίαν· ἐγὼ δέ σοι παραινῶ νέοις οὕτω μὴ χρῆσθαι νομεῦσιν ἵππων, ἢ διδόναι γυναῖκας αὐτοῖς. » Ἔδοξε μὲν οὖν μοι τῶν λόγων ἀκούσας ὁ Περίανδρος ἡσθῆναι σφόδρα· καὶ γὰρ ἐξεγέλασε καὶ τὸν Θαλῆν περιβαλὼν κατησπάσατο. κἀκεῖνος « οἶμαι δ´, » εἶπεν, « ὦ Διόκλεις, καὶ πέρας ἔσχε τὸ σημεῖον· ὁρᾷς γὰρ ἡλίκον κακὸν γέγονεν ἡμῖν, Ἀλεξιδήμου συνδειπνεῖν μὴ θελήσαντος. » </div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §3'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§3. Ce fut en tenant de tels propos chemin faisant, que nous arrivâmes à la maison. '''Thalès''' ne voulut pas se baigner : « Je me suis frotté d’huile. » dit-il. Il se promena donc de côté et d’autre, regardant les champs de course, les palestres, et le bois sacré, voisin de la mer, que l’on avait bien convenablement disposé. Ce n’était pas qu’il fût frappé par aucun de ces préparatifs, mais il voulait ne pas avoir l’air de mépriser '''Périandre''' et de faire peu de cas de l’empressement avec lequel celui-ci honorait ses hôtes. Pour les autres convives, à mesure qu’ils s’étaient parfumés ou baignés, les serviteurs les introduisaient par la galerie dans la salle du banquet. Or '''Anacharsis''' s’était installé dans cette galerie, et devant lui une jeune fille se tenait, lui séparant les cheveux avec ses mains. Lorsqu’entra '''Thalès''', elle s’élança très librement à sa rencontre, et '''Thalès''', après l’avoir embrassée, lui dit en riant : « Continue à rendre bien beau notre étranger, afin qu’étant devenu la douceur même il ne conserve pas au milieu de nous une mine à faire peur et un aspect sauvage. » Je lui demandai quelle était cette jeune enfant : « Quoi ! » me dit-il, « vous ne connaissez pas la savante et célèbre '''Eumétis''' ! car c’est ainsi que son père la nomme : le plus communément on l’appelle '''Cléobuline''', du nom paternel. » Et '''Niloxène''' : « C’est sans doute à cause de son talent et de son habileté pour les énigmes, que vous faites l’éloge de cette jeune fille : car quelques-unes de celles qu’elle a proposées sont parvenues jusqu’en ''Égypte''. » — « Ce n’est pas à cause de cela », répondit '''Thalès''' : « les énigmes sont pour elle des joujoux dont elle s’amuse à l’occasion pour faire sa partie avec ceux qui se rencontrent. Mais ce qui est admirable en elle c’est sa profondeur d’esprit, son sens politique, l’aménité de son caractère, et le talent qu’elle a de rendre plus douce l’autorité de son père et d’inspirer à celui-ci des sentiments plus humains à l’égard du peuple. » — « Soit », dit '''Niloxène''' ; « et cela se reconnaît à voir sa modestie et sa simplicité. Mais d’où vient qu’elle prend un soin si amoureux de la toilette d’'''Anacharsis''' ? » — Parce que c’est, répondit '''Thalès''', « un sage, un homme des plus instruits, et parce qu’il lui a communiqué, avec de nombreux détails et de grand coeur, l’ensemble des pratiques sanitaires et des purifications que les ''Scythes'' appliquent au traitement des malades. Et dans ce moment je suppose qu’elle l’entoure de soins et d’amitiés parce qu’elle s’instruit de quelque chose en conversant avec lui. » Comme nous étions déjà près de la salle, '''Alexidème''' le ''Milésien'' vint à notre rencontre. C’était un bâtard du tyran '''Thrasybule'''. Il était sorti tout troublé, et avec une sorte de fureur il se parlait à lui-même, mais ses paroles n’avaient rien de clair pour nous. Quand il eut vu '''Thalès''', il se remit un peu ; puis, s’arrêtant tout court : « Quel affront '''Périandre''' vient de nous faire ! Je voulais mettre à la voile : il ne l’a pas permis ; il m’a supplié de rester à son festin, et quand j’arrive, il me donne une des dernières places, faisant passer des [[w:Éoliens|''Éoliens'']], des insulaires (je ne sais qui il ne me préfère pas), les faisant passer, dis je, avant '''Thrasybule''', car c’est '''Thrasybule''' en ma personne, c’est celui par lequel je suis envoyé qu’il a l’intention de traîner dans la boue et de ravaler comme le méprisant : la chose est bien claire. » — « Eh quoi ! » lui dit '''Thalès''', « êtes-vous comme les ''Égyptiens'', qui prétendent que les astres, suivant qu’ils prennent une position élevée ou basse en parcourant leur orbite, ont une condition meilleure ou pire qu’ils ne l’avaient ? Craignez-vous, pareillement, qu’autour de vous, en raison de la place où vous serez, il ne se produise obscurité ou dépression ? Serez-vous moins résigné que certain ''Spartiate'' ? À je ne sais quelle représentation il avait été placé au dernier rang par le maître des cérémonies : « Voilà qui va bien », lui dit-il : « tu as trouvé moyen de rendre honorable ce lieu même. Quand nous avons pris une place nous ne devons pas chercher au-dessous de qui nous sommes installés, mais plutôt comment nous nous mettrons en bon accord avec nos voisins. À leur occasion nous ferons voir tout d’abord, ou plutôt nous l’éprouverons réellement, un désir d’initiative et de prise de possession en matière d’amitié, et nous manifesterons ce désir en nous félicitant, loin d’en montrer du dépit, de ce que l’on nous a placés en une telle compagnie. Mais celui qui se plaint du rang qu’on lui donne à table montre plus de mécontentement contre son commensal que contre son hôte, et il se rend odieux à l’un et à l’autre. » — « Paroles que tout cela, » dit '''Alexidème''', « et paroles sans portée ! Mais je vois que de fait, vous autres sages, vous recherchez aussi les honneurs. » En même temps il s’éloigna de nous et disparut. Une conduite si étrange nous semblait étonnante. « C’est », nous dit '''Thalès''', « un homme écervelé et naturellement bizarre. Vous allez en juger. Il était encore tout jeune ; on avait apporté à '''Thrasybule''' un parfum d’un très haut prix. '''Alexidème''' le versa dans un grand vase à rafraîchir, y mêla du vin pur, et avala le tout, rendant son père odieux au lieu de le faire aimer. » Au même moment parut un serviteur : « Vous êtes invité par '''Périandre''' », me dit-il, « à venir, en vous faisant accompagner de '''Thalès''' que voici, examiner l’objet qu’on lui a récemment apporté, afin que vous disiez si c’est une création toute fortuite, ou bien un présage et une monstruosité; car, pour ce qui est de '''Périandre''', il a l’air grandement troublé, pensant que c’est une souillure et une profanation pour son sacrifice. » En même temps, il nous emmena vers une des salles qui donnaient sur le jardin. Là un jeune homme paraissant appartenir à la classe des bergers, qui n’avait pas encore de barbe et dont la physionomie ne manquait pas de noblesse, déploya une espèce de couverture en cuir, et nous montra un petit enfant né, disait-il, d’une cavale. Par le haut, jusqu’au cou et aux mains, cette créature était de forme humaine ; mais le reste était d’un cheval, et sa voix avait quelque chose des vagissements poussés par les petits enfants qui viennent de naître. « Dieu préservateur ! » s’écria '''Niloxène''', et il détourna les yeux. Mais '''Thalès''' fixa longtemps son regard sur le jeune pâtre; puis s’étant mis à sourire, (car il avait l’habitude de plaisanter toujours avec moi sur ma profession) : « Eh bien, '''Dioclès''', » dit-il, « songez-vous à préparer quelque expiation, et à donner de la besogne aux dieux préservateurs, comme vous trouvant en présence de quelque événement grave et considérable ? » — « Pourquoi non ? » répondis-je : « j’y vois le présage de troubles et de discordes qui s’étendront, j’en ai peur, jusqu’à un mariage et une génération avant que le courroux de la déesse ait été apaisé, puisqu’elle fait, vous le savez, une seconde manifestation ». À ces paroles '''Thalès''' ne répondit rien : il se contenta de rire et de s’en aller. Et comme '''Périandre''' était à la porte, s’avançant pour nous interroger sur ce que nous venions de voir, '''Thalès''' me quitta et le prit par la main : « Ce que '''Dioclès''' prescrira, vous l’exécuterez à loisir », lui dit-il ; « mais moi j’ai un conseil à vous donner : pour faire paître vos juments ne prenez pas de jeunes garçons, ou bien à ceux-ci donnez des femmes. » Ces paroles me semblèrent causer, des qu’il les eut entendues, une vive satisfaction à '''Périandre''', car il éclata de rire et serra très affectueusement '''Thalès''' dans ses bras. '''Thalès''' alors : « '''Dioclès''' », me dit-il, « si je conjecture bien, le prodige reçoit déjà son accomplissement. Car vous voyez quel grand malheur nous est arrivé, '''Alexidème''' n’ayant pas voulu souper avec nous. »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §3'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Après avoir ainsi conversé pendant le chemin, nous arrivâmes au lieu destiné pour le banquet. '''Thalès''' ne voulut point entrer dans le bain, parcequ’il s’était déja parfumé, mais il se promena dans les dehors, s’arrêta à voir les luttes et les courses ; il alla voir le bocage voisin de la mer, qu’on avait décoré avec beaucoup de soin, non qu’il fût frappé de tout cet appareil, mais pour ne point paraître mépriser '''Périandre''' et dédaigner sa magnificence. Tous les autres convives, à mesure qu’ils sortaient du bain, étaient introduits par des esclaves dans la salle du banquet. '''Anacharsis''' seul était assis sous le portique, une jeune fille, debout, lui arrangeait les cheveux. Dès qu’elle vit '''Thalès''', elle accourut très librement au-devant de lui ; ce philosophe l’embrassa, et lui dit en riant : « Parez cet hôte du mieux que vous pourrez, afin que le plus doux des hommes n'’ait plus un extérieur sauvage et effrayant. » Je lui demandai quelle était cette jeune personne : « Eh quoi ! me répondit-il, vous ne connaissez pas la sage et fameuse '''Eumétis''' ? C’est le nom que '''Cléobule''' lui donne, mais les autres l’appellent '''Cléobuline''', du nom de son père. - Est-ce, dit '''Niloxène''', à cause de sa subtilité et de son adresse à composer des énigmes, que vous faites ainsi son éloge ? Quelques unes de celles qu’on lui attribue ont pénétré jusqu’en ''Egypte''. - Non, répliqua '''Thalès''' ; ces énigmes ne sont que des jouets dont elle s’amuse dans l’occasion pour éprouver la perspicacité de ceux qu’elle rencontre. Ce qu’elle a de vraiment admirable, c’est sa grande prudence, sa capacité pour les affaires, son humanité, et l’attention qu’elle a de rendre le gouvernement de son père doux et bienfaisant. - Il est vrai, reprit '''Niloxène''', que sa modestie et sa simplicité annoncent combien elle est populaire. Mais d’où viennent ces soins et cet intérêt pour '''Anacharsis''' ? - Parceque c’est un homme sensé et très instruit, répondit '''Thalès''', qu’il s’est fait un plaisir de lui apprendre en détail le régime et le traitement que les ''Scythes'' emploient dans les maladies. Je suis sûr que dans ce moment même où elle le pare avec tant de soin, elle s’entretient utilement avec lui, et cherche à s’instruire. » Nous approchions de la salle, lorsque nous rencontrâmes '''Alexidème''' de ''Milet'', fils naturel du tyran '''Thrasybule'''. Il sortait tout troublé, et d’un ton de colère murmurait quelques mots que nous ne pûmes entendre. Dès qu’il vit '''Thalès''', il se remit un peu ; et en lui adressant la parole, il lui dit : « Quel indigne affront '''Périandre''' vient de nous faire ! J’allais partir, il me retient, il me prie de rester à son festin ; et quand j’arrive, il m’y donne la dernière place : il préfère un ''éolien'', un insulaire, enfin je ne sais qui, à '''Thrasybule''', car il est évident que c’est '''Thrasybule''' que '''Périandre''' méprise, et brave ouvertement dans la personne de son envoyé [[#Thrasybule_NdT_DR|<span id="Thrasybule_NdT_DR_back"><sup>1</sup></span>]]. - Eh quoi ! lui dit '''Thalès''', craignez-vous que la place que vous occuperez à table ne vous rende plus grand ou plus petit, comme les ''Égyptiens'' disent que les astres brillent plus ou moins, suivant que le cercle qu’ils parcourent est plus ou moins élevé ? Et vous estimeriez-vous moins que ce ''Lacédémonien'', qui, dans une assemblée publique, placé par le magistrat au dernier rang, lui dit : Vous avez trouvé le moyen de rendre cette place honorable [[#place_honorable_NdT_DR|<span id="place_honorable_NdT_DR_back"><sup>2</sup></span>]] ? Doit-on en effet examiner après qui l’on est placé ? Ne faut-il pas plutôt s’accommoder de ceux qu’on a pour voisins, afin d’avoir une occasion naturelle de se lier avec eux, et loin de se fâcher du rang qu’on occupe, témoigner sa satisfaction de se trouver auprès d’eux ? Celui qui se plaint de la place qu’on lui assigne semble plus mécontent de son voisin que de son hôte, et se rend odieux à l’un et à l’autre . - Belles paroles que cela, repartit '''Alexidème'''. Mais, dans le fait, je vois que vous autres sages, vous recherchez les honneurs aussi bien que nous. » En même temps, il nous quitte brusquement, et s’en va. Une conduite si étrange nous étonna tous : « Ce jeune et homme, nous dit '''Thalès''', a montré dès l’enfance un caractère dur et emporté. Un jour qu’on avait fait présent à '''Thrasybule''' d’un parfum de grand prix, il le versa dans une coupe mêlé avec du vin, et l’avala, payant ainsi d’ingratitude la tendresse de son père. » Au même instant, un des gens de '''Périandre''' vint me prier d’aller avec '''Thalès''' voir quelque chose d’extraordinaire qu’on venait de lui apporter, afin de juger si c’était un jeu de la nature ou un prodige menaçant ; il nous dit qu’il en était tout troublé, et qu’il craignait que son sacrifice n’en fût souillé. En même temps, il nous conduit dans une salle qui donnait sur le jardin. Nous y trouvâmes un jeune homme sans barbe, d’une figure intéressante, qui avait l’air d’un berger. Il lève une espèce de peau, et nous fait voir un enfant qu’il disait être né d’une cavale, qui avait la tête, le cou et les mains d’un homme, et dans tout le reste, était fait comme un cheval. Sa voix ressemblait à celle d’un enfant qui vient de naître : « Dieu préservateur ! s’écria '''Niloxène''', en détournant la vue. » Mais '''Thalès''', qui a coutume de plaisanter avec moi sur mon art, après avoir longtemps considéré ce jeune homme, me dit en souriant : « Ne pensez-vous pas déja, '''Dioclès''', à faire des expiations ? Et pour détourner un présage si terrible, n’allez-vous pas donner bien de l’ouvrage aux dieux préservateurs ? - Pourquoi non ? lui répondis-je. Ce prodige, '''Thalès''', est un signe menaçant de troubles et de discorde ; et je crains bien que l’épouse et les enfants de '''Périandre''' n’en éprouvent les tristes suites, puisque enfin, comme vous voyez, avant que la déesse soit apaisée, elle donne une nouvelle marque de son courroux. » A ces mots, '''Thalès''' sourit et sortit sans rien répondre. Il vit, à la porte de la salle, '''Périandre''' venir au-devant de nous, pour savoir notre sentiment. Il me quitta, lui prit la main, et lui dit : « '''Dioclès''' vous parlera ; vous ferez à loisir ce qu’il vous dira. Pour moi, je pense que vous ne devez pas avoir, pour garder vos juments, des bergers aussi jeunes, ou que vous devez les marier. » Ce discours parut faire grand plaisir à '''Périandre''', car il en rit beaucoup, et embrassa affectueusement '''Thalès'''. Celui-ci s’adressant à moi : « Je crois, '''Dioclès''', me dit-il, que le prodige a déja eu son accomplissement. Vous voyez le malheur qui vient de nous arriver ; '''Alexidème''' a refusé de souper avec nous. » </div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Thrasybule_NdT_DR_back|<span id="Thrasybule_NdT_DR"><sup>1</sup></span>]]Dans les ''Propos de table'', on trouve une aventure pareille, arrivée chez Timon, frère de Plutarque ; mais le personnage n’est pas nommé. ''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#place_honorable_NdT_DR_back|<span id="place_honorable_NdT_DR"><sup>2</sup></span>]] Plutarque, dans les ''apophthegmes des Lacédémoniens'', nomme ce ''Spartiate'' Dæmonidas, et attribue un mot semblable au fameux Agésilas. ''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' pp.330-334, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe IV.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage du caractère désinvolte de '''Thalès'''.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§4. Ἐπεὶ δ´ εἰσήλθομεν, ἤδη μεῖζον ὁ Θαλῆς φθεγξάμενος « ποῦ δ´ » εἶπεν « ὁ ἀνὴρ κατακλινάμενος ἐδυσχέρανεν; » ἀποδειχθείσης δὲ τῆς χώρας περιελθὼν ἐκεῖ κατέκλινεν ἑαυτὸν καὶ ἡμᾶς « ἀλλὰ κἂν ἐπριάμην » εἰπών « Ἀρδάλῳ κοινωνεῖν μιᾶς τραπέζης. » ἦν δὲ Τροιζήνιος ὁ Ἄρδαλος, αὐλῳδὸς καὶ ἱερεὺς τῶν Ἀρδαλείων Μουσῶν, ἃς ὁ παλαιὸς Ἄρδαλος ἱδρύσατο ὁ Τροιζήνιος.<br /><p style="text-align: centre">[...]<br /><p style="text-align: justify; text-indent: 15px">καὶ ὁ Θαλῆς ἐμὲ προσαγορεύσας ἐπάνω τοῦ Βίαντος κατακείμενον « τί οὐκ ἔφρασας, » εἶπεν, « ὦ Διόκλεις, Βίαντι τὸν Ναυκρατίτην ξένον ἥκοντα μετὰ προβλημάτων βασιλικῶν αὖθις ἐπ´ αὐτόν, ὅπως νήφων καὶ προσέχων ἑαυτῷ τὸν λόγον δέχηται; » Καὶ ὁ Βίας « ἀλλ´ οὗτος μέν, » ἔφη, « πάλαι δεδίττεται ταῦτα παρακελευόμενος, ἐγὼ δὲ τὸν Διόνυσον οἶδα τά τ´ ἄλλα δεινὸν ὄντα καὶ Λύσιον ἀπὸ σοφίας προσαγορευόμενον, ὥστ´ οὐ δέδια τοῦ θεοῦ μεστὸς γενόμενος μὴ ἀθαρσέστερον ἀγωνίσωμαι. » Τοιαῦτα μὲν ἐκεῖνοι πρὸς ἀλλήλους ἅμα δειπνοῦντες ἔπαιζον·</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §4'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§4. Après que nous fûmes entrés, '''Thalès''' ayant déjà élevé plus haut la voix: « Où donc », dit-il, « l’avait-on placé, cet homme qui s’en est formalisé ? » Quand on lui eut montré l’endroit il fit le tour de la salle, et ce fut là-même qu’il se plaça et nous installa. « En vérité », ajouta-t-il, « j’aurais payé pour partager la même table qu’'''Ardalus'''. » Cet '''Ardalus''' était un joueur de flûte ''Trézénien'', prêtre des ''muses Ardalides'' auxquelles l’antique [[w:Ardalos|'''Ardalus''']] de ''Trézène'' avait dressé des statues.<br /><p style="text-align: center">[...]<br /><p style="text-indent: 15px">Moi, j’étais au-dessus de '''Bias''', et '''Thalès''' m’ayant interpellé : « '''Dioclès''' », me dit-il, « pourquoi n’avez-vous pas dit à '''Bias''' que l’étranger de ''Naucratie'' est venu une seconde fois le trouver avec des questions de la part de son prince, afin que ce soit à jeun qu’il reçoive ces communications et qu’il y applique son esprit ? » Et '''Bias''' : « Il y a longtemps », dit-il, « que '''Dioclès''' me menace de m’y contraindre ; mais je sais que '''Bacchus''', entre autres attributions merveilleuses, possède une sagacité qui l’a fait surnommer le dieu qui délie, de sorte que je ne crains pas, étant rempli de la divinité, que la confiance m’abandonne au moment de la lutte. » C’est ainsi que, pendant le repas, ils échangeaient entre eux des plaisanteries.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §4'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Quand nous fûmes dans la salle, il demanda, en élevant la voix : « Où est donc cette place qui a tant fâché notre homme ? » Quand on la lui eut montrée, il alla s’y placer avec nous : « Certes, ajouta-t-il, j’aurais payé pour être à la même table qu’'''Ardalus'''. » Cet '''Ardalus''' était un joueur de flûte ''træzenien'', prêtre du temple des muses ''Ardalides'', que l’ancien '''Ardalus''' avait fait bâtir à ''Træzène'' [[#Ardalus_NdT_DR|<span id="Ardalus_NdT_DR_back"><sup>1</sup></span>]].<br /><p style="text-align: center">[...]<br /><p style="text-indent: 15px">Comme j’étais au-dessus de '''Bias''', '''Thalès''' m’adressant la parole : « Pourquoi, me dit-il, ne pas avertir '''Bias''' que '''Niloxène''' vient une seconde fois de la part de son prince lui proposer des problèmes à résoudre ? Il y penserait plus librement, tandis qu’il est à jeun. - Il y a longtemps, répondit '''Bias''', que '''Dioclès''' me menace de le faire. Mais je connais la puissance de '''Bacchus''', et surtout cette sagesse qui lui a fait donner le surnom de [[wikt:λύσις#Grec_ancien|''Lysien'']] ou Dieu qui délie. Ainsi, quand je serai plein de ce dieu, je ne crains pas de combattre avec moins d'avantage. ». Ce ton de gaieté régna pendant le repas. </div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Ardalus_NdT_DR_back|<span id="Ardalus_NdT_DR"><sup>1</sup></span>]] Plutarque, dans son traité de la musique, dit qu’Ardalus, fils de Vulcain, selon la Fable, passait pour l’inventeur de la flûte.''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' pp.334, 335, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe VII.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Réflexions de '''Thalès''' sur le défi de sagacité posé par le roi des ''Éthiopiens'' au roi d’''Égypte'', [[w:Ahmôsis_II|'''Amasis''']], consistant à boire la mer. Ce dernier fait appel à '''Bias''' pour la résoudre, et celui-ci souhaite l’examiner en commun avec les sages. '''Chilon''' explique qu’il ne s’agit pas de faire disparaître tant d’eau salée, mais de rendre la domination d’'''Amasis''' potable et douce à ses sujets (§6).</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§7. [...] Ἐπὶ τούτῳ δ´ ὁ '''Θαλῆς''' ἔφησεν, εὐδαιμονίαν ἄρχοντος νομίζειν, εἰ τελευτήσειε γηράσας κατὰ φύσιν.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §7'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§7. [...] Après lui '''Thalès''' prit la parole : « J’estime que le bonheur pour un souverain, c’est s’il meurt de vieillesse et naturellement. ».</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §7'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Après lui, '''Thalès''' dit que le plus grand bonheur d’un prince serait ''de mourir de vieillesse''.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' p.339, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe IX.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Réflexions de '''Thalès''' sur le défi de sagacité posé par le roi d’''Égypte'', [[w:Ahmôsis_II|'''Amasis''']], au roi des ''Éthiopiens'', consistant en une série de questions : « Qu’y a-t-il de plus ancien ? Le temps. — De plus grand ? Le monde. — De plus habile/sage ? La vérité. — De plus beau ? La lumière. — De plus commun ? La mort. — De plus utile ? Dieu. — De plus nuisible ? Le mauvais Génie/démon. — De plus puissant/fort ? La Fortune. — De plus facile ? Le plaisir. ». '''Amasis''' fait encore appel à '''Bias''' pour analyser les réponses du roi des ''Éthiopiens'', qui les examinent également en commun avec les sages.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§9. Τούτων πάλιν ἀναγνωσθέντων, ὦ Νίκαρχε, γενομένης σιωπῆς Θαλῆς ἠρώτησε τὸν Νειλόξενον εἰ προσήκατο τὰς λύσεις ὁ Ἄμασις. ἐκείνου δ´ εἰπόντος ὅτι τὰς μὲν ἀπεδέξατο ταῖς δ´ ἐδυσκόλαινε, « καὶ μὴν οὐδέν, » εἶπεν ὁ Θαλῆς, « ἀνεπίληπτόν ἐστιν, ἀλλ´ ἔχει πάντα διαμαρτίας μεγάλας καὶ ἀγνοίας. οἷον εὐθὺς ὁ χρόνος πῶς ἂν εἴη πρεσβύτατον, εἰ τὸ μὲν αὐτοῦ γεγονὸς τὸ δ´ ἐνεστώς ἐστι τὸ δὲ μέλλον; ὁ γὰρ μεθ´ ἡμᾶς ἐσόμενος χρόνος καὶ πραγμάτων τῶν νῦν καὶ ἀνθρώπων νεώτερος ἂν φανείη. τὸ δὲ τὴν ἀλήθειαν ἡγεῖσθαι σοφίαν οὐδὲν ἐμοὶ δοκεῖ διαφέρειν τοῦ τὸ φῶς ὀφθαλμὸν ἀποφαίνειν. εἰ δὲ τὸ φῶς καλόν, ὥσπερ ἐστὶν, ἐνόμιζε, πῶς τὸν ἥλιον αὐτὸν παρεῖδε; τῶν δ´ ἄλλων ἡ μὲν περὶ θεῶν καὶ δαιμόνων ἀπόκρισις θράσος ἔχει καὶ κίνδυνον, ἀλογίαν δὲ καὶ πολλὴν ἡ περὶ τῆς τύχης· οὐ γὰρ ἂν μετέπιπτε ῥᾳδίως οὕτως, ἰσχυρότατον οὖσα τῶν ὄντων καὶ ῥωμαλεώτατον. οὐ μὴν οὐδ´ ὁ θάνατος κοινότατόν ἐστιν· οὐ γάρ ἐστι πρὸς τοὺς ζῶντας. ἀλλ´ ἵνα μὴ δοκῶμεν εὐθύνειν τὰς τῶν ἑτέρων ἀποφάσεις, ἰδίας ταῖς ἐκείνου παραβάλωμεν· ἐμαυτὸν δὲ παρέχω πρῶτον, εἰ βούλεται Νειλόξενος, ἐρωτᾶν καθ´ ἕκαστον. ὡς οὖν ἐγένοντο τότε, κἀγὼ νῦν διηγήσομαι τὰς ἐρωτήσεις καὶ τὰς ἀποκρίσεις· ‘Τί πρεσβύτατον;’ [[wikt:en:θεός#Ancient_Greek|‘θεός,’]] » ἔφη Θαλῆς· « ‘ἀγέν νητον γάρ ἐστι.’ ‘Τί μέγιστον;’ ‘τόπος· τἄλλα μὲν γὰρ ὁ κόσμος, τὸν δὲ κόσμον οὗτος περιέχει.’ ‘Τί κάλλιστον;’ ‘κόσμος· πᾶν γὰρ τὸ κατὰ τάξιν τούτου μέρος ἐστί.’ ‘Τί σοφώτατον;’ ‘χρόνος· τὰ μὲν γὰρ εὕρηκεν οὗτος ἤδη, τὰ δ´ εὑρήσει.’ ‘Τί κοινότατον;’ ‘ἐλπίς· καὶ γὰρ οἷς ἄλλο μηδέν, αὕτη πάρεστι.’ ‘Τί ὠφελιμώτατον;’ ‘ἀρετή· καὶ γὰρ τἄλλα τῷ χρῆσθαι καλῶς ὠφέλιμα ποιεῖ.’ ‘Τί βλαβερώτατον;’ ‘κακία· καὶ γὰρ τὰ πλεῖστα βλάπτει παραγενομένη.’ ‘Τί ἰσχυρότατον;’ ‘ἀνάγκη· μόνον γὰρ ἀνίκητον.’ ‘Τί ῥᾷστον;’ ‘τὸ κατὰ φύσιν, ἐπεὶ πρὸς ἡδονάς γε πολλάκις ἀπαγορεύουσιν.’ » <br /><br /><p style="text-indent: 15px;">§10. Ἀποδεξαμένων δὲ πάντων τὸν Θαλῆν, ὁ Κλεόδωρος εἶπε, « τοιαῦτ´ ἐρωτᾶν καὶ ἀποκρίνεσθαι βασιλεῦσιν, ὦ Νειλόξενε, προσῆκόν ἐστιν· ὁ δὲ προπίνων τὴν θάλατταν Ἀμάσιδι βάρβαρος ἐδεῖτο τῆς Πιττακοῦ βραχυλογίας, ᾗ πρὸς Ἀλυάττην ἐχρήσατο προστάττοντά τι καὶ γράφοντα Λεσβίοις ὑπερήφανον, ἀποκρινάμενος οὐδὲν ἀλλ´ ἢ μόνον κελεύσας κρόμμυα καὶ θερμὸν ἄρτον ἐσθίειν. »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §9'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§9. Cette lecture ainsi reproduite, mon cher '''Nicarque''', il se fit un moment de silence. Après quoi '''Thalès''' demanda à '''Niloxène''' si '''Amasis''' avait accepté de telles solutions. Il répondit que ce monarque avait accepté les unes et qu’il avait été mécontent des autres. « C’est qu’en effet », dit '''Thalès''', « il n’en est aucune qui soit irréprochable, et toutes sont grandement entachées d’erreur et d’ignorance. Ainsi, d’abord, comment le temps pourrait-il être ce qu’il y a de plus ancien, puisque, une partie étant écoulée, je le veux bien, une autre est le présent, une autre est l’avenir ? Le temps qui doit venir après nous est évidemment plus jeune que les hommes d’aujourd’hui, que les événements actuels. Croire que ce qu’il y a de plus habile, ce soit la vérité, c’est, à mon avis, ne pas émettre une autre opinion que celle-ci : l’oeil et la lumière sont tout un. Si du reste l’''Éthiopien'' a cru, ce qui est réel, la lumière plus belle que tout, pourquoi a-t-il négligé de nommer le soleil lui-même ? Des autres réponses, celle qui concerne la Divinité et le Génie est aussi téméraire que dangereuse ; et ce qu’il dit de la Fortune est tout à fait déraisonnable : car elle ne changerait pas avec tant de facilité, si elle était ce qu’il y a de plus puissant et de plus fort au monde. De même, la mort n’est pas ce qu’il y a de plus commun, puisqu’elle n’est pas commune aux vivants. Mais pour que nous ne semblions pas nous borner à redresser les réponses des autres, il faut y opposer nos propres solutions. Je m’y offre le premier, si '''Niloxène''' veut reprendre chaque question ». Telles que furent faites alors et les demandes et les réponses, je vais vous les reproduire aujourd’hui : Qu’y a-t-il de plus ancien ? C’est dieu, répondit '''Thalès''', attendu qu’il est incréé. — De plus grand ? L’espace : car si le monde contient le reste, à son tour il est contenu dans l’espace. — De plus beau ? Le monde : car tout ce qui est bien ordonné en fait partie. ― De plus habile ? Le temps : car c’est lui qui a découvert et qui découvrira tout. — De plus commun ? L’espérance : car ceux même qui n’ont rien autre chose la possèdent. — De plus utile ? La vertu : car elle rend toutes les autres choses utiles par le bon usage qu’elle en fait. — De plus nuisible ? Le vice : car il corrompt tout par sa présence. — De plus puissant ? La nécessité : car elle est seule invincible. De plus facile ? Ce qui est selon la nature : car, pour ce qui est du plaisir, il amène souvent la lassitude.<br /><br /><p style="text-indent: 15px;">§10. Tout le monde ayant accueilli ces réponses de '''Thalès''', '''Cléodème''' prit la parole : « Voilà », dit-il, « ô '''Niloxène''', les questions et les réponses qu’il est convenable de faire à des rois. Mais le barbare qui veut faire boire la mer à '''Amasis''' aurait besoin de la concision employée par '''Pittacus''' à l’égard d’[[w:Alyatte_II|'''Alyatte''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Alyatte_back|<sup>🔄</sup>]], quand celui-ci enjoignait aux ''Lesbiens'' un ordre des plus insolents. Il se contenta, pour toute réponse, de l’engager « à manger des oignons et du pain chaud. »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §9'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Cette lecture étant finie, il se fit un moment de silence ; après quoi, '''Thalès''' demanda si le roi d’''Égypte'' avait approuvé toutes ces solutions. '''Niloxène''' lui répondit qu’il avait adopté les unes et rejeté les autres : « Mais, reprit '''Thalès''', il n’en est aucune d’admissible, et qui ne soit marquée au coin de l’erreur et de l’ignorance. D'abord, comment le temps peut-il être ce qu’il y a de plus ancien, puisqu’on le divise en passé, présent et avenir ? Ce dernier est certainement moins ancien que les hommes et que les événements actuels. Dire que la vérité est la sagesse, c’est, ce me semble, confondre l’œil avec la lumière. Si d’ailleurs la lumière est, selon lui, ce qu'’il y a de plus beau, pourquoi ne pas nommer le soleil lui-même ? Quant aux autres réponses, celles qu’il a faites sur les dieux et les démons sont aussi hardies que dangereuses. Ce qu’il dit de la fortune est tout à fait déraisonnable. Si elle est réellement si forte et si puissante, comment change-t-elle avec tant de facilité ? Enfin la mort n’est pas ce qu’il y a de plus commun, puisqu’elle n’existe point parmi les vivants. Mais pour qu’on ne croie pas que nous voulons seulement critiquer, opposons à ces réponses nos solutions. Je m’offre le premier pour répondre , si '''Niloxène''' veut reprendre les questions . »<br /><br /><p style="text-indent: 15px;">'''Niloxène''' le fit, et '''Thalès''' donna ses réponses, que je vais vous répéter. Qu’y a-t-il de plus ancien ? Dieu ; car il est éternel. De plus grand ? l’espace ; il contient le monde, qui lui-même renferme tout le reste. De plus beau ? le monde ; tout ce qui est dans l’ordre en fait partie. De plus sage ? le temps ; il a découvert ou découvrira tout. De plus commun ? l’espérance ; elle reste à ceux mêmes qui n’ont rien. De plus utile ? la vertu; elle fait bien user de tout. De plus nuisible ? le vice ; il corrompt tout par sa présence. De plus fort ? la nécessité ; elle seule est invincible. De plus facile ? ce qui est selon la nature ; on se lasse souvent du plaisir même.<br /><br /><p style="text-indent: 15px;">Tout le monde applaudit aux solutions de '''Thalès''' : « Voilà, dit '''Cléodème''', les questions et les réponses qu’il convient à des rois de faire. Pour ce barbare, qui propose à votre prince de boire toute la mer, il lui fallait une réponse aussi courte que celle de '''Pittacus''' au roi de ''Lydie'' '''Alyatte''', qui , dans une lettre, donnait aux ''Lesbiens'' un ordre très impérieux. '''Pittacus''' se contenta de lui récrire : ''Mangez des ognons et du pain chaud'' [[#expression_proverbiale_mépris_NdT_DR|<span id="expression_proverbiale_mépris_NdT_DR_back"><sup>1</sup></span>]].</div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#expression_proverbiale_mépris_NdT_DR_back|<span id="expression_proverbiale_mépris_NdT_DR"><sup>1</sup></span>]] C’est-à-dire : pleurez ; expression proverbiale, pour témoigner du mépris à quelqu’un.''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' pp.341, 342, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe XI.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Réflexion de '''Thalès''' sur les gouvernements où la loi est égale pour tous.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§11. Ἐπὶ τούτῳ '''Θαλῆς''' τὴν μήτε πλουσίους ἄγαν μήτε πένητας ἔχουσαν πολίτας.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §11'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§11. Après lui '''Thalès''' : « que c’est celle qui n’a ni des citoyens trop riches, ni des citoyens trop pauvres. »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §11'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">'''Thalès''' : ''celle dont les citoyens ne sont ni trop riches ni trop pauvres''.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' p.345, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe XII.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Réflexion de '''Thalès''' sur la maison la mieux réglée.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§12. Ὁ δὲ '''Θαλῆς''' ἐν ᾧ πλείστην ἄγειν τῷ δεσπότῃ σχολὴν ἔξεστιν.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §12'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§12. '''Thalès''' : « celle où le maître peut avoir un très grand loisir. »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §12'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">'''Thalès''' : ''celle qui donne le moins d’affaires à son maître''.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' p.346, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe XIII.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Référence à l’anecdote de la coupe de [[w:Bathyclès_de_Magnésie|'''Bathyclès''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_période_Grèce_Hellénistique#Bathyclès_back|<sup>🔄</sup>]] par [[w:Callimaque_de_Cyrène|'''Callimaque''']] de [[w:Cyrène|''Cyrène'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_période_Grèce_Hellénistique#Callimaque_back|<sup>🔄</sup>]].</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§13. Ἐπεὶ δὲ καὶ οὗτος ἔσχεν ὁ λόγος τέλος, ἡ μὲν Εὔμητις ἐξῆλθε μετὰ τῆς Μελίσσης, τοῦ δὲ Περιάνδρου τῷ Χίλωνι προπιόντος εὐμεγέθη κύλικα, τῷ δὲ Βίαντι τοῦ Χίλωνος, Ἄρδαλος ἐπαναστὰς καὶ προσαγορεύσας τὸν Αἴσωπον, « σὺ δ´ οὐκ ἄν, » ἔφη, « διαπέμψαιο δεῦρο τὸ ποτήριον πρὸς ἡμᾶς, ὁρῶν τούτους ὥσπερ τὴν Βαθυκλέους κύλικα διαπεμπομένους ἀλλήλοις, ἑτέρῳ δὲ μὴ μεταδιδόντας; » Καὶ ὁ Αἴσωπος, « ἀλλ´ οὐδὲ τοῦτ´, » ἔφη, « τὸ ποτήριον δημοτικόν ἐστι· Σόλωνι γὰρ ἔκπαλαι παράκειται μόνῳ. »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §13'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§13. Ce texte de conversation se trouvant à son tour épuisé, et '''Eumétis''' étant sortie avec '''Mélissa''', '''Périandre''' but une grande coupe à '''Chilon''', et '''Chilon''', à '''Bias'''. '''Ardalus''' alors se leva, et interpellant '''Ésope''' : « Ne feras-tu pas, dit-il, circuler la coupe jusqu’à nous, quand tu vois qu’ils se la passent mutuellement comme s’il s’agissait de celle de '''Bathycle''' et qu’ils ne la partagent pas avec un autre ? » Et '''Esope''' : « Mais ce vase non plus, dit-il, n’est pas une propriété populaire : car voilà longtemps qu’il reste devant '''Solon''' tout seul ».</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §13'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Après tous ces propos, '''Mélisse''' sortit avec '''Eumétis'''. '''Périandre''' alors boit le premier dans une grande coupe, la présente à '''Chilon''' [[#Chilon_NdT_DR|<span id="Chilon_NdT_DR_back"><sup>1</sup></span>]], et celui-ci à '''Bias''', qui la remit à '''Solon'''. Comme ce dernier la gardait, '''Ardalus''' se lève , et s’adressant à '''Esope''' : « Ne nous ferez-vous point, lui dit-il, passer ce vase, que nos sages, comme vous voyez, se renvoient l’un à l’autre, ainsi que la coupe de '''Bathycle''', sans le faire parvenir jusqu’à nous [[#Bathycle_NdT_DR|<span id="Bathycle_NdT_DR_back"><sup>2</sup></span>]] ? ― Ce vase, lui répondit '''Esope''', n’est sûrement pas populaire, puisqu’il reste si longtemps devant '''Solon'''. »</div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Chilon_NdT_DR_back|<span id="Chilon_NdT_DR"><sup>1</sup></span>]] Cet usage était constant chez les anciens. A la fin du repas, on remplissait de vin une grande coupe. Le principal personnage de l’assemblée en buvait le premier, et la coupe passait ainsi de main en main.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Bathycle_NdT_DR_back|<span id="Bathycle_NdT_DR"><sup>2</sup></span>]] Tout le monde sait l’histoire du fameux trépied d’or, trouvé par des pêcheurs, qui, pour terminer leurs débats, ayant eu recours à l’oracle de ''Delphes'', reçurent ordre d’en faire présent au plus sage, et l’envoyèrent à Thalès. Après avoir passé successivement par les mains des sept sages, il revint à Thalès, qui le consacra dans un temple d’Apollon. Selon Léandre de ''Milet'', cité par Diogène Laërce, c’était une coupe d’or que l’''Arcadien'' Bathycle avait laissée, par son testament, au plus sage, et c’est ce dernier récit que Plutarque semble préférer.''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' p.347, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe XIV.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage de l’''espièglerie'' de '''Thalès'''.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§14. [...] '''Ἐπιστήσαντος''' δὲ τοῦ λόγου τὸ συμπόσιον ὁ μὲν '''Θαλῆς''' ἐπισκώπτων εὖ φρονεῖν ἔφη τὸν '''Ἐπιμενίδην''' ὅτι μὴ βούλεται πράγματα ἔχειν ἀλῶν τὰ σιτία καὶ πέττων ἑαυτῷ, καθάπερ '''Πιττακός'''. « ἐγὼ γάρ, » εἶπε, « τῆς ξένης ἤκουον ᾀδούσης πρὸς τὴν μύλην, ἐν [[w:Eresós|''Ἐρέσῳ'']] γενόμενος, ἄλει, μύλα, ἄλει· καὶ γὰρ '''Πιττακὸς''' ἄλει μεγάλας ''Μυτιλάνας'' βασιλεύων. »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §14'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§14. [...] Ces paroles ayant mis en arrêt les convives, '''Thalès''' dit en raillant qu’'''Epiménide''' avait bien raison de ne pas vouloir se donner l’embarras de moudre et de cuire lui-même son manger, comme faisait '''Pittacus''' : « Car je me souviens », ajouta-t-il, « qu’étant à ''Lesbos'', j’entendis mon hôtesse chanter à sa meule : Va ton train, meule, va ton train, puisque '''Pittacus''', le roi de la grande ''Mitylène'', s’occupe bien à moudre. »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §14'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Ce discours ayant frappé tout le monde, '''Thalès''' dit en plaisantant qu’il approuvait '''Epiménides''' [[#Epiménides_NdT_DR|<span id="Epiménides_NdT_DR_back"><sup>1</sup></span>]] de s’épargner la peine de moudre et de cuire lui-même son pain, comme faisait '''Pittacus'''. « Je me souviens , ajouta-t-il, qu’étant à ''Lesbos'', j’ai entendu une meunière qui chantait : ''Moulez, meule, moulez ; '''Pittacus''', qui règne dans la superbe Mitylène, s’occupe aussi à moudre'' [[#Pittacus_NdT_DR|<span id="Pittacus_NdT_DR_back"><sup>2</sup></span>]]. »</div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Epiménides_NdT_DR_back|<span id="Epiménides_NdT_DR"><sup>1</sup></span>]] Epiménides était un poète de l’île de ''Crète''. Les nymphes, disait-on, lui avaient donné un aliment miraculeux, qu’il conservait dans une corne de bœuf, et dont une très petite quantité suffisait pour le nourrir. ''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Pittacus_NdT_DR_back|<span id="Pittacus_NdT_DR"><sup>2</sup></span>]] Pittacus, au rapport de différents historiens, s’exerçait à moudre du blé. Il faisait un grand éloge de l’utilité des moulins, et insistait sur l’avantage qu’a le moulin de fournir, dans un très petit espace, le moyen de prendre différents exercices. ''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' p.351, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe XV.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage d’une doctrine de '''Thalès''' sur l’importance vitale de l’agriculture.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§15. [...] « Οὐδαμῶς, » ὁ '''Κλεόδωρος''', « ἔμοιγ´, » εἶπεν, « εἰ δεῖ τὸ φαινόμενον εἰπεῖν, καὶ μάλιστα παρακειμένης τραπέζης, ἣν ἀναιροῦσιν αἰρομένης τροφῆς φιλίων θεῶν βωμὸν οὖσαν καὶ ξενίων. ὡς δὲ '''Θαλῆς''' λέγει τῆς γῆς ἀναιρεθείσης σύγχυσιν τὸν ὅλον ἕξειν κόσμον, οὕτως οἴκου διάλυσις ἐστι· συναναιρεῖται γὰρ αὐτῇ πῦρ ἑστιοῦχον ἑστία κρατῆρες ὑποδοχαὶ ξενισμοί, φιλανθρωπότατα καὶ πρῶτα κοινωνήματα πρὸς ἀλλήλους, μᾶλλον δὲ σύμπας ὁ βίος, εἴ γε διαγωγή τίς ἐστιν ἀνθρώπου πράξεων ἔχουσα διέξοδον, ὧν ἡ τῆς τροφῆς χρεία καὶ παρασκευὴ τὰς πλείστας παρακαλεῖ. [...] »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §15'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§15. [...] « S’il faut dire ce que je pense », reprit '''Cléodème''', « ce n’est nullement mon avis, et surtout quand est dressée la table, que l’on supprime si la nourriture est supprimée et qui est l’autel des dieux amis et hospitaliers. Et s’il est vrai, comme dit '''Thalès''', que la suppression de la terre dût entraîner le désordre et la ruine du monde entier, de même anéantir la table ce serait anéantir la maison. Avec la table disparaîtraient le feu qui consacre le foyer, le foyer lui-même, les coupes, les réceptions, les hospitalités, qui sont les plus affectueux et les premiers rapports de communauté entre les hommes; ou plutôt disparaîtrait la vie entière, s’il est vrai que la vie soit une sorte de courant formé par la série des actes de l’homme, actes dont le plus grand nombre est commandé par le besoin et la préparation de la nourriture.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §15'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">S’il faut, reprit '''Cléodème''', que je dise mon sentiment, je ne suis point du tout de cet avis-là, surtout quand la table est dressée. Nous ôter le besoin de nourriture, c’est détruire cet autel des dieux hospitaliers. Et comme la destruction de la terre, selon '''Thalès''', entraînerait la ruine de l’univers, ainsi la chute de la table causerait celle de la maison. Avec elle, on détruirait le feu sacré de nos foyers, les dieux pénates, les libations, le plaisir si touchant de recevoir et de traiter ses amis, tous ces usages respectables qui sont les premiers fondements et les plus doux liens de la société ; disons mieux, on détruirait la vie entière, puisqu’elle est remplie par des occupations et des soins successifs, dont la plupart ont pour objet la nourriture et sa préparation.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' pp.353, 354, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe XVII.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage d’une parole sage de '''Thalès''' : Ne croire ni ses ennemis sur les choses croyables, ni ses amis sur les choses incroyables.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§17. τέλος δὲ γελάσας πρὸς ἡμᾶς « βούλομαι μέν, » ἔφη, « πρὸς τὸ παρὸν φράσαι τὸ προσηγγελμένον· ὀκνῶ δ´ ἀκούσας '''Θαλέω''' ποτ´ εἰπόντος ὅτι δεῖ τὰ μὲν εἰκότα λέγειν, τὰ δ´ ἀμήχανα σιωπᾶν. » Ὑπολαβὼν οὖν ὁ '''Βίας''' « ἀλλὰ καὶ τοῦτ´, » ἔφη, « '''Θαλέω''' τὸ σοφόν ἐστιν, ὅτι δεῖ τοῖς μὲν ἐχθροῖς καὶ περὶ τῶν πιστῶν ἀπιστεῖν, τοῖς δὲ φίλοις καὶ τὰ ἄπιστα πιστεύειν, ἐχθροὺς μέν, ἔγωγ´ ἡγοῦμαι, τοὺς πονηροὺς καὶ ἀνοήτους, φίλους δὲ τοὺς χρηστοὺς καὶ φρονίμους αὐτοῦ καλοῦντος. οὐκοῦν, »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §17'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§17. [...] A la fin il s’adressa à nous en éclatant de rire : « Je voudrais vous faire connaître, sans plus attendre, ce que '''Gorgias''' vient de me conter; et pourtant j’hésite, parce que j’ai autrefois entendu dire à '''Thalès''' qu’il faut dire les choses vraisemblables et taire les impossibles. « Mais, reprit '''Bias''', « c’est à '''Thalès''' aussi qu’appartient cette sage parole : qu’il faut ne pas croire ses ennemis même sur les choses croyables, et croire ses amis même sur celles qui ne le sont pas : par ennemis il entendait, je suppose, les méchants et les sots, par amis, les gens vertueux et sensés. »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §17'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Mais quand '''Gorgias''' [[#Gorgias_NdT_DR|<span id="Gorgias_NdT_DR_back"><sup>1</sup></span>]] eut achevé, il nous dit en riant : « Je voudrais vous répéter ce que je viens d’entendre ; mais je n’ose le faire après ce mot de '''Thalès''' : qu’il faut dire les choses vraisemblables, et taire celles qui paraissent impossibles. - Mais, repartit '''Bias''' , n’est-ce pas aussi '''Thalès''' qui a dit cette autre maxime si sage, qu’il faut ne pas croire ses ennemis même sur les choses croyables, et croire ses amis sur les choses même les moins vraisemblables. Par les ennemis, il entend, sans doute, les méchants et les insensés ; par les amis, les bons et les sages.</div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Gorgias_NdT_DR_back|<span id="Gorgias_NdT_DR"><sup>1</sup></span>]] Tout ce qu’on sait de ce frère de Périandre, c’est qu’il fonda une colonie dans l’''[[w:Ambracie|Ambracie]]'', et qu’il mourut vraisemblablement avant son frère, puisque son fils [[w:Psammétique_(Corinthe)|Psammétique]] succéda à Périandre, et fut le dernier tyran de ''Corinthe'' de la race de [[w:Cypsélos|Cypsèle]]. ''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' p.358, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe XXI.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage d’une doctrine de '''Thalès''' sur la résidence de l'âme dans toutes les parties du monde les plus essentielles.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§21. Μετὰ δὲ τοῦτον ὁ '''Ἀνάχαρσις''' εἶπεν ὅτι τοῦ '''Θαλέω''' καλῶς ὑπολαμβάνοντος ἐν πᾶσιν εἶναι τοῖς κυριωτάτοις μέρεσι τοῦ κόσμου καὶ μεγίστοις ψυχήν, [...].</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §21'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§21. Après '''Pittacus''', '''Anacharsis''' prit la parole : « Puisque, comme '''Thalès''' l’a magnifiquement établi, une âme réside dans toutes les parties du monde les plus essentielles, [...].</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §21'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">'''Pittacus''' ayant cessé de parler, '''Anacharsis''' prit la parole : « S’il est vrai, dit-il, comme '''Thalès''' le croit avec raison, que les plus grandes et les principales parties du monde ont une ame, [...].</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' p.365, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto; color: #3366BB">― ✳ ―</div> ==== Du démon de '''Socrate''' ==== <div style="text-align: center; margin: 0 1em;">Discussion autour de la libération de [[w:Thèbes (Grèce)|''Thèbes'']] de ''[[w:Sparte|Sparte]]'' grâce à une conjuration de '''[[w:Pélopidas|Pélopidas]]''' [[#Pélopidas|<span id="Pélopidas_back"><sup>'''I'''</sup></span>]] en [[w:-379|-379]]. Le récit est ici plus ample que lors de la biographie de Pélopidas dans les ''[[w:Vies parallèles|Vies parallèles]]''. La source de '''Plutarque''' est d’origine ''thébaine'', la même que '''[[w:Cornélius Népos|Cornélius Népos]]''' [[#Cornélius_Népos|<span id="Cornélius_Népos_back"><sup>'''II'''</sup></span>]]. Le traité porte sur la ''[[w:démonologie|démonologie]]'', le démon de '''Socrate''' peut-être une voix intérieure ou ses capacités [[w:divinatoires|divinatoires]]'', la légende étant d’origine [[w:pythagoricienne|pythagoricienne]] et évoque l’oracle '''[[w:Trophonios|Trophonios]]'''.</div> {{Boîte déroulante début|titre=NdA du Démon de Socrate|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Pélopidas_back|<span id="Pélopidas"><sup>I</sup></span>]] Du nom propre grec ancien Πελοπῐ́δᾱς / Pelopĭ́dās [[wikt:en:Πελοπίδας#Ancient_Greek|(en)]] ;<br /><p style="margin: 0 2em; text-indent: 15px;">Stratège [[w:Thèbes (Grèce)|''thébain'']]. Chassé en [[w:-382|-382]] de ''Thèbes'' après la prise de la [[w:Cadmée_(Thèbes)|Cadmée]], la citadelle située au sommet de son ''[[w:acropole|acropole]]'', par [[w:Phébidas|Phébidas]] avec l’aide des ''[[w:Sparte|Spartiates]]'', il renverse le gouvernement pro-spartiate d’[[w:Archias de Thèbes|Archias]] et de Léontidas en [[w:-379|-379]], qu’il tue, et rétablit la ''[[w:démocratie|démocratie]]''.<br /><p style="text-align: right; margin: 0 2em;">(date de naissance inconnue, à ''Thèbes'' — [[w:364_av._J.-C.|-364]]<sup>[[w:IVe_siècle_av._J.-C.|⏳]]</sup>, mort lors de la [[w:Bataille_de_Cynoscéphales_(364_av._J.-C.)|''bataille de Cynoscéphales'']], dans le cadre d’une vengeance pour sa captivité par le ''tyran'' de [[w:Thessalie|''Thessalie'']], [[w:Alexandre_de_Phères|Alexandre]] de [[w:Phères|''Phères'']], alors qu’il était en ambassade chez lui)<br /><br /><p style="margin: 0 2em; text-indent: 15px;">[[#Cornélius_Népos|<span id="Cornélius_Népos"><sup>II</sup></span>]] [[w:Nom_romain|Tria Nomina]] en latin ''{{Info|<nowiki>[praenomen inconnu]</nowiki>|praenomen, nom individuel du citoyen romain}}'' {{Info|Cornélius|nomen, nom de famille}} {{Info|Népos|cognomen, surnom héréditaire, servant à distinguer les diverses branches d’une même gens}}<br /><p style="margin: 0 2em; text-indent: 15px;">Auteur ''latin''. On sait par les lettres de Cicéron que Cornelius Népos n’aimait pas les écrits moraux, leur préférant la description de la nature et l’étude de l’histoire. Aucun des ouvrages qu’il avait composés dans ce genre n’est parvenu en entier jusqu’à nous. Les « Vies des grands capitaines de l’antiquité » qui subsistent aujourd’hui, et qui ont connu de multiples éditions, lui ont été attribuées jusqu'au XVIIIe siècle ; mais l'analyse de ce court recueil montre qu'il ne serait qu'un abrégé (attribué à Æmilius Probus), de l’ouvrage original de Cornelius Népos.<br /><p style="text-align: right; margin: 0 2em;">(vers [[w:-100|-100]], au pays des [[w:Insubres|Insubres]] à [[w:Mantoue|Mantoue]] ou à [[w:Pavie|''Ticinum'']], dans le nord de l’''Italie'' — vers [[w:-29|-29]]/[[w:-25|-25]], à ''Rome'')<sup>[[w:Ier_siècle_av._J.-C.|⏳]]</sup>'''<br /><br /> </div>{{Boîte déroulante fin}} ===== <div style="text-align: center;">Paragraphe VI.</div> ===== <div style="text-align: center; margin: 0 1em;">Témoignage de l’aversion de '''Thalès''' pour les [[w:Tyran|''tyrans'']].</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid;"><br /><div style="text-align: justify; margin: 0 2em; text-indent: 15px">§6. Ταῦτα τοῦ '''Θεοκρίτου''' λέγοντος ὁ '''Λεοντίδης''' ἐξῄει μετὰ τῶν φίλων, ἡμεῖς δ´ εἰσελθόντες ἠσπαζόμεθα τὸν '''Σιμμίαν''' ἐπὶ τῆς κλίνης καθεζόμενον οὐ κατατετευχότα τῆς δεήσεως, οἶμαι, μάλα σύννουν καὶ διαλελυπημένον· ἀποβλέψας δὲ πρὸς ἅπαντας ἡμᾶς ‘ὦ '''Ἡράκλεις''',’ εἶπεν ‘ἀγρίων καὶ βαρβάρων ἠθῶν· εἶτ´ οὐχ ὑπέρευ '''Θαλῆς''' ὁ παλαιὸς ἀπὸ ξένης ἐλθὼν διὰ χρόνου τῶν φίλων ἐρωτώντων ὅ τι καινότατον ἱστορήκοι ’τύραννον‘ ἔφη ’γέροντα.‘ καὶ γὰρ ᾧ μηδὲν ἰδίᾳ συμβέβηκεν ἀδικεῖσθαι, τὸ βάρος αὐτὸ καὶ τὴν σκληρότητα τῆς ὁμιλίας δυσχεραίνων ἐχθρός ἐστι τῶν ἀνόμων καὶ ἀνυπευθύνων δυναστειῶν.[...]</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome II, [https://remacle.org/bloodwolf/historiens/Plutarque/demonsocrategr.htm Περι του Σωκρατους Δαιμονιου - Le Démon de Socrate], §6'', traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§6. Pendant que [[w:Théocrite|'''Théocritos''']] [[#Théocrite|<span id="Théocrite_back"><sup>'''I'''</sup></span>]] parlait, '''Léontidas''' sortit avec ses amis, et nous entrâmes chez [[w:Simmias_de_Thèbes|'''Simmias''']] [[#Simmias_de_Thèbes|<span id="Simmias_de_Thèbes_back"><sup>'''II'''</sup></span>]], que nous saluâmes affectueusement. Il était assis sur son lit, et j’attribuai à l’insuccès de sa demande son air pensif et affligé. Après nous avoir regardés tous : « Par '''Hercule''' ! s’écria-t-il, quelles mœurs sauvages et barbares ! Eh bien ! n’avait-il pas cent fois raison le '''Thalès''' des anciens jours ? Comme il était revenu d’un long voyage à l’étranger, ses amis lui demandaient ce qu’il avait vu de plus curieux : « Un tyran parvenu à la vieillesse », répondit-il. Car ceux même qui n’ont pas éprouvé de la part d’un despote une injustice personnelle, supportent avec peine le poids et la dureté d’un semblable régime. On déteste tout pouvoir qui est en dehors de la loi et qui ne veut rendre de comptes à personne. [...]</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome III, [[s:Page:Plutarque_-_Œuvres_complètes_de_Plutarque_-_Œuvres_morales_et_œuvres_diverses,_tome_3,_1870.djvu/74|Περι του Σωκρατους Δαιμονιου - Le Démon de Socrate]], [[s:Page:Plutarque_-_Œuvres_complètes_de_Plutarque_-_Œuvres_morales_et_œuvres_diverses,_tome_3,_1870.djvu/83|§6]]'', traduites par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> {{Boîte déroulante début|titre=NdA de trad. Victor Bétolaud de 1870|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Théocrite_back|<span id="Théocrite"><sup>I</sup></span>]] Du nom propre [[w:Nom_théophore|''théophore'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_période_Grèce_Classique#théophore_back|<sup>🔄</sup>]] grec ancien Θεόκριτος / Theókritos [[wikt:en:Θεόκριτος#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;">➥ de l’adjectif et du nom commun θεός / theós [[wikt:en:θεός#Ancient_Greek|(en)]], « divin, dieu, divinité »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ +‎ du verbe κρίνω / krínō, « 1. (transitif) Séparer, diviser, distinguer entre deux choses ou personnes ou parmi un groupe de choses ou de personnes. 2. (transitif) Commander, organiser. 3. S’enquérir, enquêter. 4. Sélectionner, choisir, préférer. 5. (transitif) Trancher un différend ou un concours ; (intransitif) Porter un jugement, prendre une décision : • (voix moyenne, voix passive) Décider d’un concours ; (voix moyenne et voix passive) Se disputer, se disputer, se quereller. 6. Décider ou juger [+accusatif et infinitif = que quelque chose fait quelque chose], [+accusatif et accusatif = que quelque chose est quelque chose]. 7. Discerner entre le bien et le mal. 8. Juger, prononcer. 9. Traduire en justice, accuser. 10. Condamner, critiquer. 11. Sécréter, cacher, dissimuler. »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ + le suffixe adjectival récessif‎ -τος / -tos [[wikt:en:-τος#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;">''Poète'', auteur de [[w:Mime|''mimes'']] (imitations comiques du langage ou des gestes), d’[[w:Poésie_pastorale|''idylles pastorales'']] et de [[w:Épopée|''contes épiques'']].<br /><p style="text-align: right; margin: 0 2em;">([[w:Circa|{{Info|''ca.''|Circa, locution latine que l’on emploie pour indiquer l’approximation d’une date}}]] [[w:310_av._J.-C.|-310]]<sup>[[w:IVe_siècle_av._J.-C.|⏳]]</sup>, à [[w:Théocrite#cite_ref-2|''Syracuse'']] — {{Info|''ca.''|Circa, locution latine que l’on emploie pour indiquer l’approximation d’une date}} [[w:250_av._J.-C.|-250]]<sup>[[w:IIIe_siècle_av._J.-C.|⏳]]</sup>) <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Simmias_de_Thèbes_back|<span id="Simmias_de_Thèbes"><sup>II</sup></span>]] Du grec ancien Σιμμίας ο Θηβαίος / Simmías o Thēbaíos ;<br /><p style="margin: 0 2em; text-indent: 15px;">Philosophe grec et disciple de [[w:Socrate|Socrate]] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Socrate_back|<sup>🔄</sup>]].<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:Ve_siècle_av._J.-C.|V<sup>ème</sup>]] et [[w:IVe_siècle_av._J.-C.|IV<sup>ème</sup>]] siècles {{Info|AEC|Avant l’Ère Commune}}, ''Thèbes'')'''<br /><br /> </div>{{Boîte déroulante fin}} <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">§6. Pendant que '''Théocritos''' discourait ainsi, '''Léontidas''' sortit avec ses amis ; nous entrâmes et saluâmes '''Simmias''', qui était assis sur son lit, tout soucieux et triste, parce que sa demande avait été rejetée sans doute. En nous regardant tous, il s’écria : « '''Héraclès''' ! les moeurs sauvages et barbares ! Ah ! que '''Thalès''' l’ancien avait raison de répondre, lorsqu’après un long voyage à l’étranger ses amis lui demandaient ce qu’il avait remarqué de plus extraordinaire : « Un tyran âgé ». Même un homme qui a eu la chance de n’être pour son compte victime d’aucune injustice exècre déjà le poids et la dureté de ce commerce et est ennemi des dictatures, des dominations arbitraires.[...]</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome II, [https://remacle.org/bloodwolf/historiens/Plutarque/demonsocrate.htm Περι του Σωκρατους Δαιμονιου - Le Démon de Socrate], §6'', traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto; color: #3366BB">― ✳ ―</div> ==== Les [[w:Alimentation_en_Grèce_antique#Banquets|''Symposiaques'']] [[#Symposiaques|<span id="Symposiaques_back"><sup>'''I'''</sup></span>]], ou questions de table ==== <div style="text-align: center; margin: 0 1em;"></div> {{Boîte déroulante début|titre=NdA Les Symposiaques|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Symposiaques_back|<span id="Symposiaques"><sup>I</sup></span>]] Du nom commun grec ancien συμπόσιον / sympósion [[wikt:en:συμπόσιον#Ancient_Greek|(en)]], « Seconde partie d’un repas pendant laquelle un groupe restreint de convives buvaient et discutaient sur un sujet. » ; <br /><p style="margin: 0 2em; text-indent: 15px;">➥ du nom commun σῠμπότης / sŭmpótēs [[wikt:en:συμπότης#Ancient_Greek|(en)]], « compagnon de boisson » ; <br /><p style="margin: 0 4em; text-indent: 15px;">➥ du préfixe σῠν- / sŭn- [[wikt:en:συν-#Ancient_Greek|(en)]], « avec, ensemble » ;<br /><p style="margin: 0 4em; text-indent: 15px;">➥ +‎ du nom commun ποτής / potḗs [[wikt:en:ποτής#Ancient_Greek|(en)]], « boisson » ;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ +‎ du suffixe -ῐον / -ĭon [[wikt:en:-ιον#Ancient_Greek|(en)]] ;<br /><p style="margin: 0 2em; text-indent: 15px;">Entretiens dans un banquet, propos de table. '''<br /><br /> </div>{{Boîte déroulante fin}} ===== <div style="text-align: center;">Livre III</div> ===== <div style="text-align: center; margin: 0 1em;"></div> ====== <div style="text-align: center;">Question VI. Sur le temps où il est à propos de se rapprocher d’une femme.</div> ====== <div style="text-align: center; margin: 0 1em;">Témoignage du statut marital de '''Thalès''' et de sa relation avec sa mère</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid;"><br /><div style="text-align: justify; margin: 0 2em; text-indent: 15px">Καθάπερ οὖν '''Θαλῆς''' ὁ σοφὸς ὑπὸ τῆς μητρὸς ἐνοχλούμενος γῆμαι κελευούσης πῶς ὑπεξέφυγε παρήγαγε λέγων πρὸς αὐτὴν ἐν ἀρχῇ μέν « οὔπω καιρὸς ὦ μῆτερ, » ὕστερον δ´ « οὐκέτι καιρὸς ὦ μῆτερ », οὕτως ἄρα καὶ πρὸς ἀφροδίσια κράτιστον {ἔσται} ἔχειν ἕκαστον, ὥστε κατακλινόμενον λέγειν «οὔπω καιρός», ἀνιστάμενον δ´ « οὐκέτι καιρός ».</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome III, [https://remacle.org/bloodwolf/historiens/Plutarque/sympos3.htm#VI Προβλημα Ϛ. Περὶ καιροῦ συνουσίας. - Question VI. Quel est le temps le plus propre à l'amour?]'', traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div></div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§3. Ainsi donc, comme le sage '''Thalès''', fatigué par sa mère qui l’engageait à se marier, trouva le moyen de lui échapper et de lui donner le change en lui disant une première fois : « Il n’est pas encore temps, ma mère », et, lorsqu’elle insistait encore après qu’il avait passé l’âge : « Il n’est plus temps » ; de même, pour ce qui regarde les plaisirs de l’amour, le mieux sera que chacun se détermine à dire, en se mettant au lit : « Il n’est pas temps encore », et, en sortant du lit : « il n’est plus temps ».</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome III, [[s:Page:Plutarque_-_Œuvres_complètes_de_Plutarque_-_Œuvres_morales_et_œuvres_diverses,_tome_3,_1870.djvu/268|Question VI. Sur le temps où il est à propos de se rapprocher d’une femme]], [[s:Page:Plutarque_-_Œuvres_complètes_de_Plutarque_-_Œuvres_morales_et_œuvres_diverses,_tome_3,_1870.djvu/271|§3]]'', traduites par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Le sage '''Thalès''', pressé par sa mère de se marier, lui répondit avec beaucoup d’adresse. Au commencement, il lui dit : Ma mère, il n’est pas encore temps. Quand il eut passé la fleur de son âge, et qu’elle lui fit de nouvelles instances, il lui répondit : Il n’est plus temps. De même, par rapport à la question proposée, le mieux serait que chacun pût se dire le soir en se couchant : Il n’est pas encore temps ; et le matin, quand il se lève : Il n’est plus temps. »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome III, [https://remacle.org/bloodwolf/historiens/Plutarque/sympos3.htm#VI Προβλημα Ϛ. Περὶ καιροῦ συνουσίας. - Question VI. Quel est le temps le plus propre à l’amour?]'', traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto; color: #3366BB">― ✳ ―</div> ==== De la malignité d’[[w:Hérodote|'''Hérodote''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Chapitre_XX|<sup>🔄</sup>]] ==== <div style="text-align: center; margin: 0 1em;">Ouvrage critique contre l’impartialité d’'''Hérodote''', ses contre-vérités face à la dévaluation des héros et peuples ''grecs''. Le ton critique surprend de la part de '''Plutarque''' au point que l’on contesta l’authenticité du traité, sans succès.</div> ===== Paragraphe XV ===== <div style="text-align: center; margin: 0 1em;">Remise en question de l’origine phénicienne de '''Thalès''' donnée par '''Hérodote'''.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid;"><br /><div style="text-align: justify; margin: 0 2em; text-indent: 15px">Καὶ μὴν τῶν ἑπτὰ σοφῶν, οὓς αὐτὸς σοφιστὰς προσεῖπε, τὸν μὲν '''Θάλητα''' Φοίνικα τῷ γένει τὸ ἀνέκαθεν ἀποφαίνεται βάρβαρον·</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome IV, [https://remacle.org/bloodwolf/historiens/Plutarque/malignhero.htm Περι της Ηροδοτου κακοηθειας]'' traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§15. Quand il parle des sept sages, il les appelle des ''sophistes''. Il prétend démontrer que '''Thalès''' est d’origine ''phénicienne''[[#phénicienne_NdT_DR|<span id="phénicienne_NdT_DR_back"><sup>1</sup></span>]], et qu’à remonter en arrière ce personnage appartient aux Barbares.</div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#phénicienne_NdT_DR_back|<span id="phénicienne_NdT_DR"><sup>1</sup></span>]] I, 170.''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome III, [[s:Page:Plutarque_-_Œuvres_complètes_de_Plutarque_-_Œuvres_morales_et_œuvres_diverses,_tome_3,_1870.djvu/773|De la malignité d’Hérodote]], [[s:Page:Plutarque_-_Œuvres_complètes_de_Plutarque_-_Œuvres_morales_et_œuvres_diverses,_tome_3,_1870.djvu/782|§15]]'', traduites par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Entre les sept sages qu’il appelle ''sophistes'', il enlève '''Thalès''' à la ''Grèce'' pour le donner aux Barbares, en le faisant descendre d’une famille ''phénicienne''.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome IV, [https://remacle.org/bloodwolf/historiens/Plutarque/malignhero.htm De la malignité d’Hérodote]'' traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto; color: #3366BB">― ✳ ―</div> ==== Les opinions des Philosophes ==== <div style="text-align: center; margin: 0 1em;">Ouvrage [[w:doxographe|'''doxographe''']], à la manière de [[w:Diogène Laërce|'''Diogène Laërce''']] [[#Diogène_Laërce_back|<sup>⤵️</sup>]] et [[w:Alcinoos_(philosophe)|'''Alcinoos''']] [[#Alcinoos|<span id="Alcinoos_back"><sup>'''I'''</sup></span>]], qui cite un nombre important de [[w:présocratiques|''présocratiques'']].</div> {{Boîte déroulante début|titre=NdA Les opinions des Philosophes|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Alcinoos_back|<span id="Alcinoos"><sup>I</sup></span>]] Du grec ancien Ἀλκίνοος / Alkínoos [[wikt:en:Ἀλκίνοος#Ancient_Greek|(en)]] ; <br /><p style="margin: 0 2em; text-indent: 15px;">➥ du nom commun ἀλκή / alkḗ [[wikt:en:ἀλκή#Ancient_Greek|(en)]], « 1. Prouesse; force. 2. Défense; garde. 3. Bataille; combat. » ;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ +‎ du nom commun νόος / nóos [[wikt:en:νόος#Ancient_Greek|(en)]], « 1. Esprit : • Perception, sens ; • L’esprit en tant que siège des sentiments, le cœur, l’âme ; • L’esprit en tant que faculté de décision et d’intention, la volonté. 2. Un acte de l’esprit : • Pensée ; • Intention, dessein. 3. Le sens ou la signification d’un mot. 4. (philosophie) Intelligence, intellect, raison. 5. (métaphysique) Le principe agissant sur les particules élémentaires de la matière (tel que décrit par [[w:Anaxagore|Anaxagore]] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Anaxagore_back|<sup>🔄</sup>]]) » ;<br /><p style="margin: 0 2em; text-indent: 15px;">Philosophe de l’époque [[w:Moyen-platonisme|''médio-platonicienne'']] [[#moyen-platonisme|<span id="moyen-platonisme_back"><sup>II</sup></span>]], auteur du Διδασκαλικὸς τῶν Πλάτωνος δογμάτων / Didaskalikòs tō̃n Plátōnos dogmátōn, « Enseignement des doctrines de Platon » [[#Didaskalikos|<span id="Didaskalikos_back"><sup>III</sup></span>]].<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:IIe_siècle|II<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]])<br /><br /><p style="margin: 0 2em; text-indent: 15px;">[[#moyen-platonisme_back|<span id="moyen-platonisme"><sup>II</sup></span>]] Le ''moyen-platonisme'' ou ''médio-platonisme'' est un courant philosophique regroupant des penseurs qui se réclament de Platon, depuis le [[w:Ier_siècle_av._J.-C.|I<sup>er</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]] jusqu'au [[w:IIe_siècle|II<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]].<br /><br /><p style="margin: 0 2em; text-indent: 15px;">[[#Didaskalikos_back|<span id="Didaskalikos"><sup>III</sup></span>]] Le ''Didaskalikos'' se rattache étroitement à la branche du ''moyen-platonisme'' qui interprétait Platon à la lumière surtout d’Aristote. On constate en plus une certaine influence du ''stoïcisme'', en particulier l’emprunt d’un extrait conséquent au ''stoïcien'' Arius Didyme [[#Arius_Didyme|<span id="Arius_Didyme_back"><sup>'''IV'''</sup></span>]]. Souvent pourtant les doctrines du ''stoïcisme'' sont combattues, avant tout, mais pas exclusivement, en ce qui concerne la morale : il est donc impossible que l’auteur du ''Didaskalikos'' fût ''stoïcien orthodoxe'', dont la persistance au [[w:IIe_siècle|II<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]] est sujet à débat. Pour autant, l’auteur veut maintenir une certaine réserve à l’égard des doctrines dont il fait l’exposé : d’où l’emploi de la troisième personne à propos des ''platoniciens''. Enfin, il ne se comptait pas non plus parmi les grands du ''moyen-platonisme''.<br /><p style="margin: 0 2em; text-indent: 15px;">Le Didaskalikos ne peut donc pas être antérieur à Arius Didyme, contemporain de l’empereur Auguste. Il est impossible d’établir un [[wikt:terminus_ad_quem|''terminus ante quem'']] précis. L’ouvrage présente en effet des coïncidences frappantes avec une gamme d’auteurs s’échelonnant de Philon d’Alexandrie jusqu’à Plotin. Depuis fin [[w:XIXe_siècle|XIX<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]], l’habitude a été prise de dater le ''Didaskalikos'' des environs de l’an [[w:150|150]] EC ; et même si cela semble raisonnable, il y a d’autres possibilités à prendre en considération, en l’absence de tout renseignement biographique.<br /><br /><p style="margin: 0 2em; text-indent: 15px;">[[#Arius_Didyme_back|<span id="Arius_Didyme"><sup>IV</sup></span>]] Du nom propre grec ancien Ἄρειος Δίδυμος / Areios Didymos ;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ du nom propre [[w:Nom_théophore|''théophore'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#théophore_back|<sup>🔄</sup>]] Ἄρειος / Áreios [[wikt:en:Ἄρειος#Ancient_Greek|(en)]], « Relatif à Ares »; <br /><p style="margin: 0 2em; text-indent: 30px;">➥ du nom propre Ἄρης / Árēs [[wikt:Ἄρης#Ancient_Greek|(en)]], « 1. (mythologie grecque) La divinité Arès. 2. (par transfert) La planète Mars. 3. (par antonomase) Rencontre ou situation hostile entre groupes de personnes : bataille, affrontement, combat, escarmouche, guerre. 4. (par antonomase) Événements ou conséquences liés aux hostilités : boucherie, carnage, embrasement, massacre, tuerie. 5. (par antonomase, avec synecdoque comme substantif désignant une qualité) Esprit guerrier ou esprit combatif. 6. Épithète de Zeus, « le vengeur » »;<br /><p style="margin: 0 2em; text-indent: 30px;">➥ +‎ du suffixe adjectival -ιος / -ios [[wikt:en:-ιος#Ancient_Greek|(en)]], « Relatif à, appartenant à : "de" » ;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ de l’adjectif δῐ́δῠμος / dĭ́dŭmos [[wikt:en:δίδυμος#Ancient_Greek|(en)]], « 1. Double. 2. Jumeaux. » ;<br /><p style="margin: 0 2em; text-indent: 30px;">➥ [[wikt:en:réduplication|''Réduplication'']] de δύο / dúo [[wikt:en:δύο#Ancient_Greek|(en)]], « deux » ; <br /><p style="margin: 0 2em; text-indent: 30px;">➥ + du suffixe -μος / -mos [[wikt:en:-μος#Ancient_Greek|(en)]] ; forme alternative du suffixe adjectival -ιμος / -imos [[wikt:en:-ιμος#Ancient_Greek|(en)]] de possibilité ou de capacité, « -able » ;<br /><p style="margin: 0 2em; text-indent: 15px;">Philosophe ''alexandrin'' et doxographe de tendance éclectique, il est ami et conseiller d’Auguste, au moins de [[w:-30|-30]] (date fondée sur des références à Auguste et à Arius dans le contexte de la prise d’Alexandrie, épargnée par Auguste - entre autres raisons – grâce à Arius) à [[w:9|9]]. Bien que nous ne connaissions pas de façon certaine l’école à laquelle il se rattachait, il était probablement ''stoïcien'' : il manifeste des affinités avec la ''philosophie académicienne'' telle qu’elle est présentée par Antiochus d’''Ascalon'', de la sympathie pour l’''académicien'' Eudore, une grande précision dans le traitement du matériel ''stoïcien'' et une ouverture à la pensée ''péripatéticienne''.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:Ier_siècle_av._J.-C.|I<sup>er</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]]) [https://books.google.fr/books?id=crnWAAAAMAAJ&newbks=1&newbks_redir=0&lpg=PA3&dq=Richard%20Goulet%20dictionnaire%20des%20auteurs%20antiques&hl=fr&pg=PA345#v=onepage&q&f=false {{Info|<sup>🔍</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume I, §324 - Areios Didymos}}]'''<br/><br/></div> {{Boîte déroulante fin}} ===== <div style="text-align: center;">Livre I</div> ===== <div style="text-align: center; margin: 0 1em;"></div> <div style="text-align: center; margin: 0 auto;">― ● ―</div> ===== <div style="text-align: center;">Livre II</div> ===== <div style="text-align: center; margin: 0 1em;"></div> <div style="text-align: center; margin: 0 auto;">― ● ―</div> ===== <div style="text-align: center;">Livre III</div> ===== <div style="text-align: center; margin: 0 1em;"></div> <div style="text-align: center; margin: 0 auto;">― ● ―</div> ===== <div style="text-align: center;">Livre IV</div> ===== <div style="text-align: center; margin: 0 1em;"></div> <div style="text-align: center; margin: 0 auto; color: #3366BB">― ✳ ―</div> ==== Les animaux de terre ont-ils plus d'adresse que ceux de mer? ==== <div style="text-align: center; margin: 0 1em;"></div> <div style="text-align: center; margin: 0 auto; color: #3366BB">― ✳ ―</div> ==== D’'''Isis''' et d’'''Osiris'''==== <div style="text-align: center; margin: 0 1em;">[[w:Diatribe|Diatribe]] ''[[w:Isis|Isiaque]]'', avec une interprétation ''platonique'' pour intéresser '''Cléa''', admiratrice du mystère d’'''Isis''' à la [[w:Religion_%C3%A9gyptienne|religion ''égyptienne'']]. C’est un plaidoyer, exégèse, avec '''[[w:Osiris|Osiris]]''' qui évoque '''[[w:Dionysos|Dionysos]]''' et '''[[w:Hadès|Hadès]]''', ainsi que des notions de ''[[w:démonologie|démonologie]]'', ''[[w:Dualisme (philosophie)|dualisme]]'' et ''[[w:didactique|didactique]]''. Il contient le premier récit suivi et cohérent du [[w:Mythe_d'Osiris|mythe d’'''Osiris''']]. L’une de ses sources est probablement '''[[w:Hérodote|Hérodote]]'''. mais on croit qu’il s’est rendu lui-même à ''Alexandrie'' pour suivre des cours de médecine.</div> ===== <div style="text-align: center;">Paragraphe IX.</div> ===== <div style="text-align: center; margin: 0 1em;">Témoignage d’un voyage de '''Thalès''' en ''Égypte'', de rencontres avec des prêtres et de récit sur leur divinités.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid;"><br /><div style="text-align: justify; margin: 0 2em; text-indent: 15px">§9. [...] '''Ἑκαταῖος''' δ´ ὁ ''Ἀβδηρίτης'' φησὶ τούτῳ καὶ πρὸς ἀλλήλους τῷ ῥήματι χρῆσθαι τοὺς ''Αἰγυπτίους'', ὅταν τινὰ προσκαλῶνται· προσκλητικὴν γὰρ εἶναι τὴν φωνήν. Διὸ τὸν πρῶτον θεόν, ὃν τῷ παντὶ τὸν αὐτὸν νομίζουσιν, ὡς ἀφανῆ καὶ κεκρυμμένον ὄντα προσκαλούμενοι καὶ παρακαλοῦντες ἐμφανῆ γενέσθαι καὶ δῆλον αὐτοῖς ''Ἀμοῦν'' λέγουσιν.<br /><p style="text-indent: 15px">§10. Ἡ μὲν οὖν εὐλάβεια τῆς περὶ τὰ θεῖα σοφίας '''Αἰγυπτίων''' τοσαύτη {ἦν}, μαρτυροῦσι δὲ καὶ τῶν ''Ἑλλήνων'' οἱ σοφώτατοι, '''Σόλων''' '''Θαλῆς''' '''Πλάτων''' '''Εὔδοξος''' '''Πυθαγόρας''', ὡς δ´ ἔνιοί φασι, καὶ '''Λυκοῦργος''' εἰς ''Αἴγυπτον'' ἀφικόμενοι καὶ συγγενόμενοι τοῖς ἱερεῦσιν.[...]</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome V, [https://remacle.org/bloodwolf/historiens/Plutarque/isisetosiris.htm Περι Ισιδος και Οσιριδος - Traité d’Isis et d’Osiris], §34'', traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1870<br />(également disponible une édition de 1844 [https://remacle.org/bloodwolf/historiens/Plutarque/isisetosiris1.htm ici])</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§9. [...] '''Hécatée''' d’''Abdère'' dit que les ''Égyptiens'' emploient ce mot pour s’appeler les uns les autres, attendu qu’il est essentiellement appellatif. C’est pourquoi, s’adressant au premier Dieu, le même, selon eux, que l’Univers, comme à un être invisible et caché, ils l’exhortent avec supplications, en l’appelant "Amoun", à se faire voir et à se découvrir à eux. Voilà jusqu’à quel point était grande la réserve qui caractérisait la philosophie religieuse des ''Égyptiens''.<br /><p style="text-indent: 15px">§10. C’est ce que témoignent les plus éclairés d’entre les ''Grecs'': '''Solon''', '''Thalès''', '''Platon''', '''Eudoxe''', '''Pythagore''', et aussi, d’après quelques-uns, '''Lycurgue'''. Ils étaient allés en ''Égypte'' et avaient eu des conférences avec les prêtres. [...]</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome V, [https://remacle.org/bloodwolf/historiens/Plutarque/isisetosiris.htm Περι Ισιδος και Οσιριδος - Traité d’Isis et d’Osiris], §§9, 10'', traduites par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870<br/>(également disponible [[s:Sur_Isis_et_Osiris|ici]])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">§9. [...] '''Hécatée''' d’''Abdère'' dit que les ''Egyptiens'' s’en servent pour s’appeler les uns les autres; que ce nom est de sa nature appellatif ; que ce peuple , qui croit que le premier des dieux, qu’il confond avec l’univers, est un dieu caché et inconnu, l’invoque et le prie de se découvrir à eux, en lui disant ''Amoun'' ;<br /><p style="text-indent: 15px">§10. tant ce peuple portait de retenue et de réserve dans sa philosophie religieuse ! C’est ce qu'attestent unanimement les plus sages d’entre les ''Grecs'', '''Solon''', '''Thalès''', '''Platon''', '''Eudoxe''', '''Pythagore''', et, suivant quelques uns, '''Lycurgue''' lui-même, qui tous voyagèrent en ''Egypte'', et y conférèrent avec les prêtres du pays.[...]</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome V, [https://remacle.org/bloodwolf/historiens/Plutarque/isisetosiris1.htm Περι Ισιδος και Οσιριδος - Traité d’Isis et d’Osiris], §§9, 10'', traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe XXXIV.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage de la théorie de '''Thalès''' de l’eau principe de tous les êtres.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§34. Ἥλιον δὲ καὶ Σελήνην οὐχ ἅρμασιν ἀλλὰ πλοίοις ὀχήμασι χρωμένους περιπολεῖν φασιν αἰνιττόμενοι τὴν ἀφ´ ὑγροῦ τροφὴν αὐτῶν καὶ γένεσιν. Οἴονται δὲ καὶ '''Ὅμηρον''' ὥσπερ '''Θαλῆν''' μαθόντα παρ´ ''Αἰγυπτίων'' ὕδωρ ἀρχὴν ἁπάντων καὶ γένεσιν τίθεσθαι· τὸν γὰρ '''Ὠκεανὸν''' '''Ὄσιριν''' εἶναι, τὴν δὲ '''Τηθὺν''' '''Ἶσιν''' ὡς τιθηνουμένην πάντα καὶ συνεκτρέφουσαν. [...]</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome V, [https://remacle.org/bloodwolf/historiens/Plutarque/isisetosiris.htm Περι Ισιδος και Οσιριδος - Traité d’Isis et d’Osiris], §34'', traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1870<br />(également disponible une édition de 1844 [https://remacle.org/bloodwolf/historiens/Plutarque/isisetosiris1.htm ici])</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§34. Ils disent que le soleil et la lune parcourent leur route perpétuelle non pas sur des chars, mais sur des bâtiments de navigation: signifiant par là, que c’est le principe humide qui les entretient et qui leur a donné naissance. Ils croient aussi que c’est des ''Egyptiens'' qu’'''Homère''', et après lui '''Thalès''', ont appris à établir l’eau comme principe générateur de tous les êtres. Ils veulent qu’'''Osiris''' soit l’'''Océan''', qu’'''Isis''' soit '''Téthys''', laquelle nourrit et entretient tout ce qui existe.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome V, [https://remacle.org/bloodwolf/historiens/Plutarque/isisetosiris1.htm Περι Ισιδος και Οσιριδος - Traité d’Isis et d’Osiris], §34'', traduites par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870<br/>(également disponible [[s:Sur_Isis_et_Osiris|ici]])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">§34. Ils disent que le soleil et la lune parcourent les cieux, portés, non sur des chars, mais sur des vaisseaux, pour signifier que tout est nourri et mis en mouvement par l’eau. Ils pensent que c’est des ''Egyptiens'' qu’'''Homère''' et '''Thalès''' avaient pris cette opinion, que l’eau est le principe de tous les êtres, qu’'''Osiris''' est l’'''Océan''', et qu’'''Isis''' est '''Thétis''', qui nourrit et alimente toutes les substances.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome V, [https://remacle.org/bloodwolf/historiens/Plutarque/isisetosiris1.htm Περι Ισιδος και Οσιριδος - Traité d’Isis et d’Osiris], §34'', traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Valère_Maxime|'''Valère Maxime''']] ''([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l'on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:Ier_siècle|I<sup>er</sup> siècle {{Info|EC|de l’Ère Commune}}]])'' [[s:Auteur:Valère_Maxime|<sup>📚</sup>]] == === Actions et paroles mémorables, VII, § 2 === :8. Il y a aussi un mot admirable de Thalès. On lui demandait si les actions des hommes échappaient à la connaissance des dieux. "Leurs pensées non plus", répondit-il. Aussi faut-il nous appliquer à avoir, je ne dis pas seulement les mains, mais encore le cœur pur, dans la persuasion que la divinité est témoin des mouvements les plus secrets de nos âmes. <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Tatien_le_Syrien|'''Tatien''']] le [[w:Assyrie_(province_romaine)|''Syrien'']] ''(vers [[w:120|120]], en [[w:Halicarnasse|''Halicarnasse'']] en [[w:Assyrie_(province_romaine)|Assyrie]] — vers [[w:173|173]], en Assyrie)'' <sup>[[w:IIe_siècle|⏳]]</sup> [[s:Auteur:Tatien_le_Syrien|<sup>📚</sup>]] == === Discours aux Grecs, 41 === == [[w:Lucien_de_Samosate|'''Lucien de Samosate''']] ''(vers [[w:120|120]], à [[w:Samosate|Samosate]] — vers [[w:180|180]], en [[w:Égypte_romaine_et_byzantine|Égypte]])'' <sup>[[w:IIe_siècle|⏳]]</sup> [[s:Auteur:Lucien_de_Samosate|<sup>📚</sup>]] == === Dialogues des morts === https://gallica.bnf.fr/ark:/12148/bpt6k6227866x/f7.item https://gallica.bnf.fr/ark:/12148/bpt6k6227866x/f103.double === Hippias ou le bain === :(2) Mon but est de prouver que les constructeurs de machines qui méritent le plus notre admiration sont ceux qui, distingués par leur science théorique, ont laissé en outre à la postérité des monuments de leur art et des œuvres de leur génie, tandis que les hommes, qui se sont seulement exercés dans la parole méritent plutôt le nom de sophistes que celui de savants. C'est sur la liste traditionnelle de ces artistes que nous voyons figurer Archimède et Socrate de Cnide, qui inventèrent, l'un les moyens de soumettre à Ptolémée la ville de Memphis, sans recourir à un siège, mais en détournant et en divisant le cours du Nil ; l'autre, ceux d'incendier les galères des ennemis. Avant eux, Thalès de Milet, ayant promis à Crésus de faire passer à pied sec à son armée les eaux du fleuve Halys, imagina de les détourner en une seule nuit derrière le camp ; et pourtant ce n'était pas un mécanicien de profession, mais un sage d'un esprit inventif et à l'intelligence duquel on pouvait s'en rapporter. === Exemples de longévité === :(18) Solon, Thalès et Pittacus, que l'on compte au nombre des Sept sages, vécurent chacun cent années. <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Athénée_de_Naucratis|'''Athénée''' de ''Naucratis'']] == [[w:https://remacle.org/bloodwolf/erudits/athenee/livre11.htm|''Le Livre XI des Deipnosophistes'']] [781d] « Alcmène reçoit le vase d'or, et le contemple aussitôt avec admiration. » Stésichore dit qu'Hercule traverse l'Océan dans son vase à boire (poteerioo) ; qu'il s'en servit même pour le franchir et aller enlever les bœufs de Géryon. Nous connaissons aussi par l'histoire le vase à boire (poteerion) de l'arcadien Bathyclès, qui le laissa pour présent à celui qui fut appelé le sage par excellence entre les Sept de la Grèce; mais nombre de potiers de terre font le vase de Nestor, car plusieurs écrivains en ont donné des détails. <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Clément_d%27Alexandrie|'''Clément''']] d'[[w:Histoire_d%27Alexandrie#Annexion|''Alexandrie'']] ''(vers [[w:150|150]]'' <sup>[[w:IIe_siècle|⏳]]</sup>'', à [[w:Athènes#Antiquité|Athènes]] — vers [[w:215|215]]'' <sup>[[w:IIIe_siècle|⏳]]</sup>'', à [[w:Kayseri|Kayseri]])'' [[s:Auteur:Clément_d’Alexandrie|<sup>📚</sup>]] == === Stromates, I, 65 === <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Claude_Élien|'''Claude Élien''']] ''(vers [[w:175|175]]''<sup>[[w:IIe_siècle|⏳]]</sup>'', à [[w:Préneste|Préneste]] — vers [[w:235|235]]''<sup>[[w:IIIe_siècle|⏳]]</sup>'', en [[w:Rome_antique|Rome]])'' [[s:Auteur:Élien_le_sophiste|<sup>📚</sup>]] == === Histoires diverses === :On a vu des philosophes à la tête des affaires publiques : d'autres, se bornant à cultiver leur raison, ont passé leur vie dans le repos. Entre les premiers sont Zaleucus et Charondas qui réformèrent, l'un, le gouvernement des Locriens, l'autre, d'abord celui des Catanéens, puis, après qu'il eut été exilé de Catane, celui des Rhéginiens. Archytas servit utilement les Tarentins. Les Athéniens durent tout à Solon. Bias et Thalès rendirent les mêmes services à l'Ionie, Chilon à Lacédémone, Pittacus à Mitylène, Cléobule à Rhodes. <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Sextus_Empiricus|'''Sextus Empiricus''']] ''([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l'on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:IIe_siècle|II<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]])'' [[s:Auteur:Sextus_Empiricus|<sup>📚</sup>]] == Hypot III, 30, et Liv I contre les phys., sect. 319 https://gallica.bnf.fr/ark:/12148/bpt6k9796311p/f305.item.r=thales <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Lactance|'''Lactance''']] ''(vers [[w:250|250]]''<sup>[[w:IIIe_siècle|⏳]]</sup>'', à [[w:Henchir_Kssiba#Histoire|Civitas Popthensis]] — vers [[w:325|325]]''<sup>[[w:IVe_siècle|⏳]]</sup>'', en [[w:Gaule#La_Gaule_dans_l'Antiquité_tardive|Gaule]])'' == Épit. 4 (https://gallica.bnf.fr/ark:/12148/bpt6k282068z/f300.image.r=thales) Inst. 111, 16 (https://gallica.bnf.fr/ark:/12148/bpt6k282068z/f621.item.r=thales) <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Jamblique|'''Jamblique''']] ''(vers [[w:250|250]]''<sup>[[w:IIIe_siècle|⏳]]</sup>'', à [[w:Qinnasrīn|Chalcis ad Belum]] — vers [[w:333|333]]''<sup>[[w:IVe_siècle|⏳]]</sup>'')'' == === Vie de Pythagore === ==== chap. II ==== (https://web.archive.org/web/20110721184914/http://www.aurumsolis.info/index.php?option=com_phocadownload&view=category&download=1%3Aiamblichus-the-pythagorean-life&id=19%3Awritings-from-the-founders&Itemid=143&lang=en) <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Eusèbe_de_Césarée|'''Eusèbe''']] de [[w:Césarée#Césarée_au_début_du_christianisme|''Césarée'']] ''(vers [[w:265|265]]'' <sup>[[w:IIIe_siècle|⏳]]</sup>'', à Césarée — [[w:340|340]]'' <sup>[[w:IVe_siècle|⏳]]</sup>'', à Césarée)'' [[s:Auteur:Eusèbe_de_Césarée|<sup>📚</sup>]] == Preparation Évangélique, XI, 2 Prepar. évang. I, 8, page 22-25 https://gallica.bnf.fr/ark:/12148/bpt6k9796311p/f310.image.r=thales <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Diogène_Laërce|'''Diogène Laërce''']] ''([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l'on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:IIIe_siècle|III<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]])'' [[s:Auteur:Diogène_Laërce|<sup>📚</sup>]] == ''Ce texte est un extrait de la traduction de Robert Genaille (1933)'' Thalès[1], au dire d’Hérodote, de Douris et de Démocrite, était fils d’Examios et de Cléobuline, et membre de la famille des Thélides, Phéniciens descendant en droite ligne d’Agénor[2] et de Cadmus[3], s’il faut en croire Platon. Le premier, il porta le nom de sage, au temps où Damasias était archonte à Athènes[4]. C’est sous le même archontat que fut créée l’expression : « les sept sages » (cf. Démocrite de Phalère, Registre des Archontes). Thalès fut inscrit comme citoyen de Milet quand il vint dans cette ville avec Nélée chassé de Phénicie. Une autre tradition très courante veut qu’il soit natif de Milet et qu’il descende d’une bonne famille. Il s’occupa de politique avant d’étudier la nature. On croit qu’il ne laissa aucun écrit, car l’Astrologie nautique qu’on lui attribue est de Phocos de Samos. Callimaque[5] croit qu’il découvrit la Petite Ourse et le raconte en vers iambiques : Il mesura, dit-on, les étoiles du Chariot Sur quoi les Phéniciens règlent leur navigation. D’autres auteurs disent qu’il écrivit seulement deux ouvrages, un sur le solstice et un sur l’équinoxe, car il pensait le reste inaccessible. Il passe pour avoir le premier étudié l’astrologie et prédit les éclipses de soleil et les solstices (cf. Eudème, Histoire de l’astrologie)[6]. Xénophane et Hérodote le louent à ce propos, et leur témoignage est confirmé par celui d’Héraclite et de Démocrite. On dit encore (cf. le poète Choirilos) qu’il fut le premier à affirmer l’immortalité des âmes. Le premier il dessina la course du soleil d’un solstice à l’autre, et démontra que comparée au soleil, la lune en est la cent vingtième partie. C’est encore lui qui fixa à trente jours la durée du mois, et qui écrivit le premier traité sur la Nature. Aristote et Hippias disent aussi qu’il accordait une âme aux choses qu’on croit inanimées ; il en donnait pour preuve l’ambre et la pierre de Magnésie. Selon Pamphile[7], il apprit des Égyptiens la géométrie, inscrivit dans un cercle le triangle rectangle, et pour cette découverte immola un bœuf. D’autres, comme Apollodore le calculateur, attribuent cette invention à Pythagore. Thalès a encore développé et précisé l’invention du Phrygien Euphorbe citée par Callimaque dans ses Iambes et concernant le triangle scalène, et tout ce qui touche aux considérations sur les lignes. Il semble encore avoir été en politique un homme de bon conseil. Ainsi, quand Crésus[8] envoya une ambassade aux Milésiens pour demander leur alliance, il s’y opposa, et son intervention sauva la ville, puisque Cyrus l’emporta. Héraclite cite une opinion de Clytos selon laquelle Thalès aurait eu une vie retirée et solitaire. Les uns disent qu’il se maria et eut un fils nommé Kibissos. D’autres prétendent qu’il resta célibataire et adopta le fils de sa sœur, qu’on lui demanda un jour pourquoi il ne cherchait pas à avoir des enfants, et qu’il répondit : « Par amour pour les enfants. » Sa mère l’exhortait à se marier, il lui répondit : « Non, par Zeus, il n’est pas encore temps. » Elle l’y invita une nouvelle fois quand il eut pris de l’âge, mais il lui dit : « Il n’est plus temps. » D’après Hiéronyme de Rhodes (Notes, livre II), il voulut montrer combien il était facile de s’enrichir ayant prévu pour l’année une abondante récolte d’huile, il prit à loyer une oliveraie et gagna beaucoup d’argent[9]. Il soupçonna que l’eau était le principe des choses, que le monde était animé et rempli de démons. On dit qu’il découvrit les saisons de l’année, et qu’il la divisa en trois cent soixante-cinq jours. Il ne suivit les leçons d’aucun maître, sauf en Égypte, où il fréquenta les prêtres du pays. A ce propos, Hiéronyme dit qu’il mesura les Pyramides en calculant le rapport entre leur ombre et celle de notre corps. Si l’on en croit Minuès, il vivait au temps de Thrasybule, qui fut tyran de Milet[10]. L’histoire du trépied trouvé par des pêcheurs et dédié aux sages par le peuple de Milet est bien connue. Des jeunes gens d’Ionie achetèrent à des pêcheurs milésiens leur coup de filet. Ils tirèrent de l’eau un trépied. On se querella et les Milésiens envoyèrent une ambassade à Delphes. Voici quel fut l’oracle de la divinité : Race de Milet, tu interroges Phébus au sujet d’un trépied ? Au plus sage de tous, je donne ce trépied[11]. Ils le donnent alors à Thalès, qui le donne à un autre, et cet autre à un autre, et ainsi de suite jusqu’à Solon, qui, déclarant que seul le dieu était le plus sage de tous, rendit le trépied à Delphes. Callimaque, dans ses Iambes, rapporte cette histoire autrement ; il la tient de Léandre de Milet. Il dit qu’un certain Bathyclès d’Arcadie laissa en mourant une coupe pour qu’elle fût donnée à l’homme le plus sage. Elle fut donc donnée à Thalès, et après être passée de main en main et avoir fait le tour des sages, elle revint à Thalès. Celui-ci en fit don alors à Apollon de Didyme, en ces termes selon le poème de Callimaque : Thalès me donne au protecteur du peuple du Nil, Thalès qui a reçu deux fois ce présent, ce qui, en prose, se dit ainsi : « Thalès de Milet, fils d’Examios, à Apollon delphien, ce présent qu’il a reçu deux fois des Grecs. » Celui qui portait la coupe de sage en sage, le fils de Bathyclès, s’appelait Thyrion (cf. Éleusis, Livre sur Achille, et Alexon de Mynde, Fables, livre IX). Eudoxe de Cnide et Évanthès de Milet disent de leur côté qu’un ami de Crésus reçut du roi un vase d’or, pour le donner au plus sage des Grecs, qu’il le donna à Thalès et que ce vase parvint jusqu’à Chilon. Celui-ci consulta la Pythie, pour savoir qui était plus sage que lui. Elle répondit que c’était Myson (je parlerai de lui : Eudoxe le met parmi les sages à la place de Cléobule et Platon à la place de Périandre.) Voici la réponse que lui fit la Pythie : Il y a un habitant de l’Oeta, Myson, né à Chénée, Qui plus que toi est riche de sages pensées. L’homme qui consulta l’oracle pour Chilon s’appelait Anacharsis. Dédale le Platonicien et Cléarque disent que la coupe fut envoyée par Crésus à Pittacos, et que c’est ainsi qu’elle passa de main en main. D’après Andron, d’autre part (Livre du trépied), les Argiens décidèrent que le trépied serait attribué comme prix de vertu au plus sage des Grecs. Aristodème de Sparte fut choisi et c’est lui qui donna le trépied à Chilon. Alcée est aussi partisan d’Aristodème dont il parle dans les vers suivants : :Comme jadis Aristodème, dit-on, :Prononça à Sparte cette parole bien juste : :C’est de l’argent, un homme, oui de l’argent, :Car l’homme vertueux n’est jamais pauvre. D’autres disent encore que Périandre envoya à Thrasybule, tyran de Milet, un navire chargé, que ce navire fit naufrage dans la mer de Cos, et que quelque temps après le trépied fut trouvé par des pêcheurs. Phanodicos dit que le trépied fut trouvé dans la mer Attique, porté à la ville, et que l’assemblée du peuple s’étant réunie le fit porter à Bias. Pourquoi cela, je le dirai quand je parlerai de Bias. Selon d’autres auteurs, le trépied avait été fabriqué par Héphaïstos et donné en présent de la part de ce dieu à Pélops lors de son mariage. Il vint ensuite à Ménélas, fut enlevé avec Hélène par Alexandre, jeté dans la mer de Cos à l’instigation de la Spartiate qui prévoyait qu’il serait un sujet de querelle. Plus tard, en ce lieu, des Lébédiens achetèrent le produit d’un coup de filet et c’est le trépied qui fut tiré de l’eau. Il y eut querelle avec les pêcheurs, on vint jusqu’à Cos, et comme on ne s’accordait pas, on s’adressa à Milet, qui était la capitale. Les Milésiens envoyèrent des députés qui ne furent pas écoutés, aussi firent-ils la guerre aux gens de Cos. Comme de chaque côté il mourait beaucoup de gens, l’oracle déclara qu’il fallait donner le trépied au plus sage. Les deux camps s’entendirent alors pour l’attribuer à Thalès, qui par la suite le consacra à Apollon de Didyme. Pour en revenir à la réponse de l’oracle aux gens de Cos, elle disait ceci : La querelle entre Ioniens et Méropes ne cessera pas Avant que le trépied d’or qu’Héphaïstos jeta dans la mer N’ait quitté votre ville pour la maison de l’homme Qui connaît le présent, l’avenir et le passé. La réponse aux Milésiens fut la suivante : Race de Milet, tu interroges Phoebus au sujet d’un trépied... comme il a été dit plus haut. En voilà assez sur ce sujet[12]. Hermippe, dans ses Vies, rapporte à Thalès ce qui est dit par d’autres de Socrate : il aimait à dire qu’il remerciait la fortune de trois choses : d’être un humain et non une bête, d’être un homme et non une femme, enfin d’être un Grec, et non un barbare. On raconte encore qu’étant sorti de chez lui pour contempler les astres, il tomba dans un puits[13]. Une vieille femme survenant se moqua de lui en ces mots : « Comment, Thalès, toi qui n’es pas capable de voir ce qui est à tes pieds, t’imagines-tu pouvoir connaître ce qui est dans le ciel ? » Timon[14] a bien connu aussi la science de Thalès en astronomie, et dans ses Silles, il le loue en ces termes : Comme Thalès, un des sept sages, qui fut savant astronome. L’Argien Lobon dit que ses écrits font un total de quelque deux cents vers, et que sous sa statue on écrivit : Thalès de Milet repose ici dans le sol qui l’a nourri, Il fut un sage, et le premier des astrologues. Voici un de ses poèmes : Le trop parler n’est pas marque d’esprit. Trouvez une seule chose sage, Choisissez une seule chose belle, Et vous clouerez le bec à bien des bavards. On lui attribue encore les sentences suivantes : de tous les êtres, le plus ancien, c’est Dieu, car il n’a pas été engendré ; le plus beau, c’est le monde, car il est l’ouvrage du dieu ; le plus grand, c’est l’espace, car il contient tout ; le plus rapide, c’est l’esprit, car il court partout ; le plus fort, c’est la nécessité, car elle vient à bout de tout ; le plus sage, c’est le temps, parce qu’il découvre tout. La mort, dit-il, ne diffère en rien de la vie. On lui répond : « Pourquoi, alors, ne te donnes-tu pas la mort ? » ; « Parce que vie ou mort, c’est tout un », réplique-t-il. Quelqu’un lui demande ce qui du jour ou de la nuit fut créé d’abord ; il répond : « La nuit est en avance d’un jour. » On lui demande si les mauvaises actions d’un homme échappent au regard des dieux. Il répond : « Ils voient même les mauvaises pensées. » Un homme adultère lui demandait s’il pouvait jurer qu’il n’avait pas commis d’adultère. Il répondit : « Le parjure n’est pas pire que l’adultère. » On lui demandait ce qui était difficile : « Se connaître » dit-il ; ce qui était facile : donner un conseil à autrui ; ce qui était le plus doux : jouir ; ce que c’était que la divinité : un être sans commencement ni fin ; encore une chose difficile : voir un tyran âgé ; comment supporter aisément l’infortune : en voyant ses ennemis plus malheureux encore ; comment vivre vertueusement : en ne faisant pas ce que nous reprochons à autrui ; qui est heureux : l’homme bien portant, riche, courageux et instruit. Il disait encore que l’on doit penser à ses amis aussi bien en leur absence qu’en leur présence, que la beauté ne vient pas d’un beau visage, mais de belles actions. « Ne t’enrichis pas injustement, conseillait-il, et veille à ne pas être cité en justice pour de mauvaises paroles contre tes proches et tes amis. Comme tu traites tes parents, tes enfants te traiteront. » Du Nil[15] il disait qu’il débordait quand ses eaux étaient repoussées par les vents étésiens qui soufflent contre son cours. Apollodore dans ses Chroniques dit que Thalès naquit la première année de la trente-cinquième olympiade[16]. Il mourut dans sa soixante-dix-huitième année ou, comme le dit Sosicrate, dans sa quatre-vingt-dixième année, car ce fut dans la cinquante-huitième olympiade. Il vécut du temps de Crésus, auquel il promit de faire traverser l’Hallys[17] sans pont, en détournant le cours du fleuve. Il y eut cinq autres personnages du nom de Thalès (cf. Démétrios de Magnésie, Homonymes) : un rhéteur de Callatie, au style prétentieux, un peintre de Sicyone, de noble origine, un troisième, très ancien, du temps d’Hésiode, d’Homère et de Lycurgue, un quatrième, mentionné par Douris dans son traité de la peinture, un cinquième, plus jeune et peu connu, cité par Denys dans ses Critiques. Pour en revenir à notre sage, il mourut en regardant les jeux gymniques, pour avoir eu trop chaud et trop soif et par suite de sa fatigue et de son grand âge. Voici son épitaphe : :Ce tombeau, certes, est bien petit, :Mais la renommée de l’homme est allée au ciel. :C’est celui de Thalès le très sage. J’ai écrit sur lui les vers suivants dans le premier livre de mes épigrammes ou « vers de mètres divers[18] : :Tandis qu’il regardait les jeux, ô Zeus Hélios, :Tu as ravi du stade le sage Thalès. :Je te loue de l’avoir rapproché du ciel. Il était si vieux :Que de la terre il ne pouvait plus voir les astres. Thalès est l’auteur du fameux « connais-toi toi-même » qu’Antisthène (Livre des Filiations) attribue à Phémonoé, en déclarant que Chilon se l’appropria mensongèrement. Sur les sept sages, qu’il est juste de citer maintenant l’un après l’autre, voici la tradition. Damon de Cyrène, qui blâme tous les philosophes dans ses écrits, s’attaque surtout aux sept sages. Anaximène dit que tous étaient poètes. Dicéarque dit qu’ils n’étaient ni sages ni philosophes, mais hommes d’esprit et législateurs. Archétimos de Syracuse a décrit leurs assemblées chez Cypsélos[19] et dit qu’il y assista personnellement. Euphoros dit que tous, sauf Thalès, fréquentèrent Crésus. D’autres disent qu’ils se réunirent à Panionium, à Corinthe et à Delphes. On rapporte même leurs paroles, et qui a prononcé telle ou telle. Exemple : Le Spartiate Chilon fut sage, Lui qui dit : Rien de trop, Tout est bien qui vient en son temps ! On n’est pas d’accord sur leur nombre. Léandre, au lieu de Cléobule et de Myson, met Léophante, fils de Gorsias, ou Lébédios d’Éphèse et Épiménide de Crète. Platon, dans le Protagoras[20], met Myson à la place de Périandre. Éphoros met Anacharsis à la place de Myson et d’autres ajoutent Pythagore. Selon Dicéarque, il y en a quatre sur qui tout le monde est d’accord : Thalès, Bias, Pittacos et Solon. Le même auteur en nomme six autres, parmi lesquels il en choisit trois : Aristodème, Pamphile, le Lacédémonien Chilon, Cléobule, Anacharsis et Périandre. D’autres ajoutent Acousilaos, Caba ou Scala, un Argien. Hermippe, dans son livre sur les sages, dit qu’ils furent dix-sept et que chacun en choisit sept selon ses préférences. Ce sont Solon, Thalès, Pittacos, Bias, Chilon, Cléobule, Périandre, Anacharsis, Acousilaos, Épiménide, Léophante, Phérécyde, Aristodème, Pythagore, Lasos, fils de Charmantidas ou de Sisambrinos ou, selon Aristoxène, de Chabrinus, Hermonée, Anaxagore. Hippobotos (Catalogue des Philosophes) les inscrit ainsi : Orphée, Linos, Solon, Périandre, Anacharsis, Cléobule, Myson, Thalès, Bias, Pittacos, Épicharme et Pythagore. Voici des lettres attribuées à Thalès[21] : ==== Thalès à Phérécyde ==== « J’apprends que vous vous disposez à présenter aux Grecs le premier traité ionien des choses divines. Vous agiriez peut-être plus sagement en lisant votre ouvrage à vos amis, qu’en communiquant à n’importe quelles gens des écrits qui ne peuvent guère leur être utiles. « Si cela vous plaît, j’aimerais profiter de vos recherches et, si vous m’y invitez, je viendrai vous trouver au plus tôt. Car Solon d’Athènes et moi, qui avons déjà traversé deux fois la mer pour aller visiter la Crète, et pour aller en Égypte nous entretenir avec les prêtres et les astronomes du lieu, nous sommes assez sages pour ne pas hésiter à la traverser de nouveau pour aller vous voir. « Je parle de Solon, parce qu’il viendra avec moi si vous le permettez. Vous êtes un sédentaire, vous allez rarement en Ionie, vous n’aimez guère aller voir les étrangers, et vous ne songez, j’imagine, qu’à écrire. « Mais nous qui n’écrivons pas, nous parcourons volontiers la Grèce et l’Italie. » ==== Thalès à Solon ==== « Si vous quittez Athènes, vous aurez, je crois, tout avantage à venir vous établir à Milet, parmi les colons athéniens. Il n’y a là pour vous aucun danger. Si vous hésitez, sous prétexte que nous, Milésiens, sommes gouvernés par un tyran (je sais que vous haïssez tout pouvoir absolu), songez du moins que vous aurez plaisir à vivre avec nous qui sommes vos amis. Je sais que Bias vous a écrit et vous invite à aller à Priène. Si vous trouvez préférable d’habiter la ville de Priène, j’irai vivre là-bas avec vous. » <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Ausone|'''Ausone''']] ''([[w:309|309]]/[[w:310|310]], à [[w:Bazas|Bazas]] ou à [[w:Bordeaux#Burdigala,_cité_romaine_(Ier_siècle_-_Ve_siècle)|Bordeaux]] — [[w:394|394]]/[[w:395|395]], entre [[w:Langon_(Gironde)|Langon]] et [[w:La_Réole|La Réole]])'' <sup>[[w:IVe_siècle|⏳]]</sup> [[s:Auteur:Ausone|<sup>📚</sup>]] == === Le Jeu des Sept Sages === :Thalès a trouvé [texte grec] pour nous défendre de nous porter cautions, parce qu'il y a du danger à répondre ainsi pour d'autres[iv]. Nous donnons-là un avis qui ne plaira pas beaucoup aux emprunteurs. :THALÈS : Je suis Thalès de Milet ; j'ai dit, comme le poète Pindare, que l'eau est, le principe de toute chose. C'est à moi que des pêcheurs donnèrent autrefois [un trépied d'or] qu'ils avaient tiré de la mer : ils m'avaient choisi pour obéir au dieu de Délos, qui envoyait ce présent à un sage. Je refusai de le recevoir, je le leur rendis pour le porter à d'autres que je croyais plus dignes. Envoyé à tous les sept Sages, et renvoyé par eux, il nie fut rapporté. Je le reçus alors pour le consacrer à Apollon : car si Phébus a voulu qu'on choisit un sage, ce n'était pas d'un homme, mais d'un dieu qu'il fallait l'entendre. Je suis donc ce Thalès : mais un motif m'amène sur la scène. Comme les deux sages qui m'ont précédé, je viens défendre la sentence dont je suis l'auteur. Elle déplaira, mais non certes aux esprits prudents que l'expérience a instruits et rendus plus avisés. Nous avons dit : [texte grec], ou, en latin : Cautionne, mais tu t'en trouveras mal. Je pourrais parcourir mille exemples pour vous montrer des cautions et des répondants bien et dûment convaincus de repentir. Mais je ne veux nommer personne. Que chacun de, vous ré-fléchisse, et compte en lui-même combien de gens ont perdu ou souffert de s'être ainsi portés cautions pour d'autres. Toutefois, si un pareil service a du charme pour vous, n'y renoncez ni les uns ni les autres. :Alors que les uns applaudissent, et que les autres, si je les blesse, me sifflent. :THALÈS DE MILET. :AVANT d'oser une mauvaise action, à défaut de Témoin redoute ta conscience. La vie s'éteint, mais la gloire de la mort ne meurt point. Ce que tu veux faire, abstiens-toi de le dire. C'est un supplice de craindre ce qu'on ne peut empêcher. Si tu blâmes avec raison, ton hostilité même est profitable ; si tu loues mal à propos, ton amitié même est nuisible. Rien de trop. - Arrêtons-nous, et qu'ici même il n'y ait rien de trop. <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Proclus|'''Proclus''']] ''(le 7 ou 8 février [[w:412|412]], à [[w:Constantinople|Constantinople]] — le 17 avril [[w:485|485]], à [[w:Histoire_d%27Athènes#Antiquité_tardive|Athènes]])''<sup>[[w:Ve_siècle|⏳]]</sup> [[s:Auteur:Proclus|<sup>📚</sup>]] == === Commentaire sur le premier livre d'Euclide, 65, 3 === ὥσπερ οὖν παρὰ τοῖς Φοίνιξιν διὰ τὰς ἐμπορείας καὶ τὰ συναλλάγματα τὴν ἀρχὴν ἔλαβεν ἡ τῶν ἀριθμῶν ἀκριβὴς γνῶσις, οὕτω δὴ καὶ παρ' Αἰγυπτίοις ἡ γεωμετρία διὰ τὴν εἰρημένην αἰτίαν εὕρηται. Θαλῆς δὲ πρῶτον εἰς Αἴγυπτον ἐλθὼν μετήγαγεν εἰς τὴν Ἑλλάδα τὴν θεωρίαν ταύτην καὶ πολλὰ μὲν αὐτὸς εὗρεν, πολλῶν δὲ τὰς ἀρχὰς τοῖς μετ' αὐτὸν ὑφηγήσατο τοῖς μὲν καθολικώτερον ἐπιβάλλων, τοῖς δὲ αἰσθητικώτερον. <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == « [[w:Souda|'''Suidas''']] » ''([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l'on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] fin du [[w:IXe_siècle|IX<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]])'' [[s:Auteur:Suidas|<sup>📚</sup>]] == === La Souda === Θαλῆς, Ἐξαμύου καὶ Κλεοβουλίνης, Μιλήσιος, ὡς δὲ Ἡρόδοτος Φοῖνιξ: γεγονὼς πρὸ Κροίσου, ἐπὶ τῆς λε# ὀλυμπιάδος, κατὰ δὲ Φλέγοντα γνωριζόμενος ἤδη ἐπὶ τῆς ζ#. ἔγραψε περὶ μετεώρων ἐν ἔπεσι, Περὶ ἰσημερίας, καὶ ἄλλα πολλά. ἐτελεύτησε δὲ γηραιός, θεώμενος γυμνικὸν ἀγῶνα, πιληθεὶς δὲ ὑπὸ τοῦ ὄχλου καὶ ἐκλυθεὶς ὑπὸ τοῦ καύματος. πρῶτος δὲ Θαλῆς τὸ τοῦ σοφοῦ ἔσχεν ὄνομα καὶ πρῶτος τὴν ψυχὴν εἶπεν ἀθάνατον ἐκλείψεις τε καὶ ἰσημερίας κατείληφεν. ἀποφθέγματα δὲ αὐτοῦ πλεῖστα: καὶ τὸ θρυλλούμενον: γνῶθι σαυτόν. τὸ γάρ, ἐγγύα, πάρα δ' ἄτα, Χίλωνός ἐστι μᾶλλον, ἰδιοποιησαμένου αὐτό: καὶ τό, μηδὲν ἄγαν. ey1ff0vvn45e7tsarndi5culotz2z8p 773691 773690 2026-09-30T07:14:00Z Alex Mtlr 103840 /* Chapitre XVII. */ 773691 wikitext text/x-wiki {| border="0" cellpadding="0" width="100%" style="background: #f9f9f9" | colspan="3" height="25"|<div style="text-align: center;">[[Philosophie/Thalès de Milet|'''Thalès de Milet''']]</div> |- | width="33%"|'''[[Philosophie/Thalès de Milet/Textes_et_traductions_période_République_Romaine|Période République Romaine]]''' |- | width="33%"|'''[[Philosophie/Thalès de Milet/Textes_et_traductions_période_Grèce_Hellénistique|Période de la Grèce Hellénistique]]''' |- | width="33%"|'''[[Philosophie/Thalès de Milet/Textes_et_traductions_Ier_millénaire_AEC|Période de la Grèce Classique]]''' |} {{EnTravaux}} <span style="font-size:18pt;">Période du Principat de l’[[w:Empire_romain|''Empire'']] [[#Empire|<span id="Empire_back"><sup>'''I'''</sup></span>]] [[w:Rome_antique|''Romain'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Rome_back|<sup>🔄</sup>]]</span> <p style="text-align: right;">(16 janvier [[w:27_av._J.-C.|-27]] <sup>[[w:Ier_siècle_av._J.-C.|⏳]]</sup>, nomination de [[w:Auguste|'''Caius Iulius Caesar Octavianus''']] aux titres d’[[w:Auguste_(titre)|''Augustus'']] et de [[w:Princeps_senatus|''Princeps'']] par le [[w:Sénat_romain|''Sénat romain'']] — fin du [[w:IIIe_siècle|III<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]], création du système [[w:Tétrarchie|''tétrarchique'']] [[#tétrarchie|<span id="tétrarchie_back"><sup>'''II'''</sup></span>]] par [[w:Dioclétien|'''Dioclétien''']] [[#Dioclétien|<span id="Dioclétien_back"><sup>'''III'''</sup></span>]] pour faire face aux [[w:Invasions_barbares#Première_période_:_les_mouvements_migratoires_germaniques_du_IIIe_siècle|''incursions barbares'']]) {{Boîte déroulante début|titre=NdA Empire|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Empire_back|<span id="Empire"><sup>I</sup></span>]] Du nom commun latin imperium [[wikt:en:imperium#Latin|(en)]], « 1. L’empire, l’État, le gouvernement impérial, le royaume, la domination. 2. Le droit ou le pouvoir de commander ou d’avoir le contrôle ; domination. 3. Commandement ou autorité absolue sur l’empire (ou un autre régime politique) ; souveraineté ; domination. 4. (militaire) Autorité militaire, commandement (d’une armée). 5. L’exercice de l’autorité, de la règle, de la loi, du contrôle, de la souveraineté. 6. Un commandement, un ordre, une direction, une injonction.) »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ du verbe imperō, « 1. (avec datif) Commander, donner des ordres à, imposer, exiger. 2. Gouverner. »;<br /><p style="margin: 0 2em; text-indent: 30px;">➥ du préfixe prépositionnal in-, « 1. Dans, à l’intérieur. 2. Contre; dans; sur; vers. 3. (utiliser comme un intensifieur). 4. Attaché à des [[w:Aspect_inchoatif|''verbes inchoatifs'']], il peut exprimer le sens d’un changement en cours ou d’un achèvement partiel. »;<br /><p style="margin: 0 2em; text-indent: 30px;">➥ +‎ du verbe parō [[wikt:en:paro#Latin|(en)]], « 1. Arranger, ordonner, concevoir. 2. Fournir, meubler, préparer. 3. Résoudre, viser, décider. 4. Obtenir, acquérir, se procurer, se faire. »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ + du suffixe nominal abstractif‎ -ium [[wikt:en:-ium#Latin|(en)]], désignant parfois des offices et des groupes. »;<br /><p style="margin: 0 2em; text-indent: 15px;">L’historien spécialiste de l’[[w:Grèce_antique|''antiquité grecque'']] [[w:Moses_Finley|Moses Finley]] définit un empire par tout {{Info|''« exercice durable par un État d’une autorité, d’un pouvoir, ou d’un contrôle sur un ou plusieurs États, communautés ou peuples »''|Moses Finley, Économie et société en Grèce antique, La Découverte, 2007.}}. L’historien [[w:Jean_Tulard|Jean Tulard]], précise cette définition par {{Info|''cinq traits suivants''|Jean Tulard, Les Empires occidentaux de Rome à Berlin, PUF, 1997.}} : :::* '''Une volonté expansionniste ; :::* '''Une organisation centralisée ; :::* '''Des peuples encadrés par une armature politique et fiscale commune ; :::* '''La croyance en une supériorité d’essence ; :::* '''Un début et une fin clairement identifiés. <br /><p style="margin: 0 2em; text-indent: 15px;">'''[[#tétrarchie_back|<span id="tétrarchie"><sup>II</sup></span>]] Du nom commun grec ancien τετραρχία / tetrarkhía;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ du préfixe τετρα- / tétra- [[wikt:en:τετρα-#Ancient_Greek|(en)]], « quatre »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ + du suffixe -αρχία / -arkhía [[wikt:en:-αρχία#Ancient_Greek|(en)]], « -archie (forme de gouvernement ou de règle) »;<br /><p style="margin: 0 2em; text-indent: 15px;"> Système de gouvernement de l’Empire ''romain'' mis en place par Dioclétien à la fin du [[w:IIIe_siècle|III<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]], pour faire face aux invasions barbares. Il consiste en la division de la direction de l’empire entre, d’une part deux [[w:Empereur_romain|''empereurs'']] — les [[w:Auguste_(titre)|''augustes'']] —, d’autre part deux ''lieutenants'' (successeurs désignés des ''augustes'') — les [[w:C%C3%A9sar_(titre)|''césars'']]. <br /><br /><p style="margin: 0 2em; text-indent: 15px;">'''[[#Dioclétien_back|<span id="Dioclétien"><sup>III</sup></span>]] [[w:Nom_romain|Tria Nomina]] en latin {{Info|Gaius|praenomen, nom individuel du citoyen romain}} {{Info|Aurelius|nomen, nom de famille}} {{Info|Valerius|cognomen, surnom héréditaire, servant à distinguer les diverses branches d’une même gens}}, surnommé Dioclētiānus [[wikt:en:Diocletian#English|(en)]] lorsqu’il a été proclamé empereur par ses troupes;<br /><p style="margin: 0 2em; text-indent: 15px;"> Militaire et empereur, connu pour avoir séparé et élargi les services civils et militaires de l’empire, et réorganisé les divisions provinciales de l’empire, établissant le gouvernement le plus vaste et le plus bureaucratique de l’histoire de l’empire. En [[w:286|286]], il nomme son ''césar'', ou adjoint et successeur, [[w:Maximien_Hercule|Maximien]] ''Auguste'', co-empereur, et partage l’Empire entre l’Orient et l’Occident, puis en 293, y nomme respectivement [[w:Galère_(empereur_romain)|Maximien Galère]] et [[w:Constance_Chlore|Constance Chlore]] comme ''césar''.<br/><br/></div> ''' {{Boîte déroulante fin}} == [[w:Sénèque|'''Sénèque''']] [[#Sénèque|<span id="Sénèque_back"><sup>'''I'''</sup></span>]] == <p style="text-align: right;">([[w:5_av._J.-C.|-5]] <sup>[[w:Ier_siècle_av._J.-C.|⏳]]</sup> / [[w:1|1]] <sup>[[w:Ier_siècle|⏳]]</sup>, à [[w:Corduba|Corduba]] — 12 avril [[w:65|65]], à [[w:Rome_antique|''Rome'']], dans une maison de plaisance, la « quatrième pierre milliaire », contraint au [[w:Suicide_forcé|''suicide forcé'']] par l’empereur [[w:Néron|'''Néron''']] après avoir été dénoncé dans la [[w:Conjuration_de_Pison|''Conjuration de Pison'']], sans preuve selon [[w:Tacite|'''Tacite''']] [https://remacle.org/bloodwolf/historiens/tacite/annales15.htm <sup>Annales, l.V, §§LX-LXVI.</sup>]) [[s:Auteur:Sénèque_le_Jeune|<sup>📚</sup>]] [https://books.google.fr/books?id=_HZTvAxN7CIC&newbks=1&newbks_redir=0&lpg=PA3&dq=bibliogroup%3A%22Dictionnaire%20des%20philosophes%20antiques%22&hl=fr&pg=PA177#v=onepage&q&f=true {{Info|<sup>🔍</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume VI, §43 - Seneca (Lucius Annaeus –)}}] [[Fichier:Duble_herma_of_Socrates_and_Seneca_Antikensammlung_Berlin_03_.jpg|vignette|<p style="text-align: justify; text-indent: 15px;">Double-hermès du [[w:IIIe_siècle|III<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]], unique portrait de '''Sénèque''' nommé et authentifié, et associé à celui de '''Socrate''', dont le point commun est celui d’avoir été contraint de se donner la mort. Copie ''romaine'' d’un modèle fait du vivant même du philosophe [https://books.google.fr/books?id=_HZTvAxN7CIC&newbks=1&newbks_redir=0&lpg=PA3&dq=bibliogroup%3A%22Dictionnaire%20des%20philosophes%20antiques%22&hl=fr&pg=PA180#v=onepage&q&f=true {{Info|<sup>➕</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume VI, §43 - Seneca (Lucius Annaeus –), Iconographie}}] [https://books.google.fr/books?id=_HZTvAxN7CIC&newbks=1&newbks_redir=0&lpg=PA3&dq=bibliogroup%3A%22Dictionnaire%20des%20philosophes%20antiques%22&hl=fr&pg=PA201#v=onepage&q&f=true {{Info|<sup>➕➕</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume VI, §43 - Seneca (Lucius Annaeus –), Iconographie - contribution de J. Lang}}].<br /><p style="text-align: justify; text-indent: 15px;">Matériau : Marbre blanc-brunâtre, légèrement veiné, finement cristallin.<br /><p style="text-indent: 15px;">Provenance : ''Rome'', 1813.<br /><p style="text-align: justify; text-indent: 15px;">Exposition : Staatliche Museen zu Berlin, Antikensammlung, SK. 391 [https://recherche.smb.museum/detail/698814/doppelherme-des-sokrates-und-seneca-mit-namensbeischriften-der-dargestellten <sup>🔍</sup>].]] <div style="text-align: justify; margin: 0 1em; text-indent: 15px">Homme politique romain, philosophe stoïcien et dramaturge, il devient tour à tour conseiller à la cour impériale sous '''Caligula''' puis '''Claude''', est exilé en 41 en ''Corse'', où il écrit ses premiers traités philosophiques avant d’être rappelé comme tuteur du jeune '''Néron''' en 49, et enfin, lorsque ce dernier accède au pouvoir, en devient le conseiller et l’un des personnages les plus influents de l’Empire.</div> {{Boîte déroulante début|titre=NdA Sénèque|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Sénèque_back|<span id="Sénèque"><sup>I</sup></span>]] [[w:Nom_romain|Tria Nomina]] en latin {{Info|Lucius|praenomen, nom individuel du citoyen romain}} {{Info|Annaeus|nomen, nom de famille}} {{Info|Seneca|cognomen, surnom héréditaire, servant à distinguer les diverses branches d’une même gens}}'''<br/><br/></div> {{Boîte déroulante fin}} === [[w:Sénèque#Physique|Questions naturelles]] === <p style="text-align: right;">[[s:Questions_naturelles|📚]] <div style="text-align: justify; margin: 0 1em; text-indent: 15px">Ouvrage de philosophie naturelle écrit vers 65. Il ne s’agit pas d’une [[w:Encyclopédie|encyclopédie]] [[#encyclopédie|<span id="encyclopédie_back"><sup>'''I'''</sup></span>]] systématique comme l’[[w:Histoire_naturelle_(Pline_l'Ancien)|''Histoire naturelle'']] [[#Histoire_naturelle|<sup>⤵️</sup>]] de [[w:Pline_l'Ancien|'''Pline l’Ancien''']] [[#Pline_l’Ancien_I|<sup>⤵️</sup>]], bien que ces 2 œuvres représentent les rares ouvrages romains consacrés à l’étude du monde naturel. L’investigation de '''Sénèque''' se déroule principalement à travers la prise en compte des points de vue d’autres penseurs, ''grecs'' et ''romains'', bien qu’elle ne soit pas dénuée de pensées originales, dont éthiques conforment à la pensée ''stoïcienne''.</div> {{Boîte déroulante début|titre=NdA Questions naturelles|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#encyclopédie_back|<span id="encyclopédie"><sup>I</sup></span>]] Du nom commun [[w:Latin#Latin_humaniste|latin Renaissance]] encyclopaedīa [[wikt:en:encyclopaedia#Latin|(en)]]; de l’expression grec ancien ἐγκύκλῐος παιδείᾱ / enkúklios paideíā [https://dumas.ccsd.cnrs.fr/dumas-03927443/file/DONNADILLE-MR2-Pline-VERS-FINALE.pdf {{Info|<sup>🔍</sup>|Lisa Donnadille. Merveilles animalières dans les livres VIII à XI de l’Histoire naturelle de Pline l’Ancien. Littératures. 2020. ffdumas-03927443, p.21}}], « cercle de l’éducation ou des sciences, l’ensemble des sciences qui constituent une éducation complète »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ de l’adjectif ἐγκύκλιος / enkúklios, littéralement « qui est rond ou tourne en rond, circulaire », ou au sens figuré « qui revient en cercle sur soi-même, périodique », « qui embrasse un cercle entier »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ du nom commun παιδεία / paideía, « l’éducation »;'''<br /><p style="margin: 0 2em; text-align: center;">« ''Si à première vue la signification de cette expression semble être sans ambiguïté, sa portée réelle et la compréhension qu’en avaient les auteurs grecs puis latins font l’objet de débats parmi les spécialistes. En effet, deux interprétations sont possibles lorsqu’un auteur de l’Antiquité a recours à cette expression dans l’un de ses textes. Dans le premier cas, cela équivaudrait à parler d’une éducation ordinaire, commune à tous ; et dans le second cas, cela ferait référence à la quantité de connaissances et de sciences qu’il faudrait maîtriser au préalable avant de commencer l’étude d’un sujet précis, qui serait dans ce cas placé en haut d’une hiérarchie dans les savoirs.'' »<br /><p style="margin: 0 2em; text-align: right;">''' Lisa Donnadille. [https://dumas.ccsd.cnrs.fr/dumas-03927443/file/DONNADILLE-MR2-Pline-VERS-FINALE.pdf Merveilles animalières dans les livres VIII à XI de l’Histoire naturelle de Pline l’Ancien. Littératures. 2020. ffdumas-03927443], p.21'''<br/><br/></div> {{Boîte déroulante fin}} ==== Livre III — De l’eau ==== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">En prologue, Sénèque explique pourquoi il est plus important de s’intéresser à l’observation du monde, à sa connaissance et à sa compréhension plutôt qu’à sa conquête. Puis, il développe diverses théories sur la formation des rivières, les eaux souterraines et les propriétés de l’eau. Dans une critique morale aux chapitres XVII à XIX, il fustige la mauvaise pratique consistant à amener à table des poissons, notamment des rougets, vivants et à se délecter de leurs couleurs changeantes à l’agonie avant de les préparer devant les convives. En épilogue, il énonce son [[w:Eschatologie|''eschatologie'']], sa vision de la fin du monde où les êtres vivants seront anéantis par des raz-de-marée, marquant la fin d’un cycle du vivant et le début d’un autre.</div> ===== <div style="text-align: center;">Chapitre XIII.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage de la doctrine de '''Thalès''' faisant de l’eau l’élément à l’origine de la vie et critique d’une autre de la terre flottant dessus.</div> :'''Texte latin''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''13.''' Adiciam, ut '''Thales''' ait, «ualentissimum elementum est». Hoc fuisse primum putat, ex hoc surrexisse omnia. Sed nos quoque aut in eadem sententia, aut in uicinia eius sumus. Dicimus enim ignem esse qui occupet mundum et in se cuncta conuertat; hunc euanidum languentemque considere et nihil relinqui aliud in rerum natura igne restincto quam umoren; in hoc futuri mundi spem latere. Ita ignis exitus mundi est, umor primordium. Miraris ex hoc posse amnes semper exire qui pro omnibus fuit et ex quo sunt omnia? Hic umor in diductione rerum ad quartas redactus est, sic positus ut sufficere fluminibus edendis, ut riuis, ut fontibus posset.<br /><p style="text-indent: 15px;">'''14.''' Quae sequitur '''Thaletis''' inepta sententia est. Ait enim terrarum orbem aqua sustineri et uehi more nauigii mobilitateque eius fluctuare tunc cum dicitur tremere; non est ergo mirum si abundat umor ad flumina profundenda, cum in umore sit totus. Hanc ueterem et rudem sententiam explode. Nec est quod credas in hunc orbem aquam subire per rimas et facere sentinam.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/seneca.-cuestiones-naturales.-naturales-quaestiones.-vol.-i-1979/page/n1/mode/2up <u>L. Annaei Senecae, Natvrales Qvaestiones</u>], [https://archive.org/details/seneca.-cuestiones-naturales.-naturales-quaestiones.-vol.-i-1979/page/n261/mode/2up ''Liber Tertivs.''], [https://archive.org/details/seneca.-cuestiones-naturales.-naturales-quaestiones.-vol.-i-1979/page/n293/mode/2up ''chap. 13.-14.''], texte établi par Carmen Codoñer Merino [[w:es:Carmen_Codoñer_Merino|(es)]], Consejo Superior de Investigaciones Científicas, Madrid, 1979</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: justify; margin: 0 2em;">'''XIII.''' Aqua, ait '''Thales''', valentissimum elementum est : hoc fuisse primum putat, et hoc surrexisse omnia. Sed et nos quoque aut in eadem sententia, aut in ultima sumus. Dicimus enim ignem esse, qui occupet mundum, et in se cuncta convertat ; hunc evanidum considere, et nihil relinqui aliud in rerum natura, igne restincto, quam humorem : in hoc futuri mundi spem latere. Ita ignis exitus mundi est, humor primordium. Miraris amnes ex hoc posse exire semper, qui pro omnibus fuit, et ex quo sunt omnia? Hic humor in diductione rerum ad quartas redactus est, sic positus, ut fluminibus edendis sufficere, ut rivis, ut fontibus posset. Quæ sequitur, '''Thaletis''' inepta sententia est : ait enim , terrarum orbem aqua sustineri, et vehi more navigii, mobilitateque ejus fluctuare, tum quum dicitur tremere. Non est ergo mirum, si abundat humor ad flumina fundenda, quum mundus in humore sit totus. Hanc veterem et rudem sententiam explode : nec est quod credas, in hunc orbem aquam subire per rimas et facere sentiuam.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PP9#v=onepage&q&f=true <u>Œuvres Complètes de Sénèque, Tome Quatrième</u>], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA327#v=onepage&q&f=true ''Questions Naturelles, De Sénèque à Lucilius - Livre Troisième.''], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA342#v=onepage&q&f=true ''chap. XIII.''], traduction française de la collection Panckoucke, nouvelle édition très soigneusement revue par M. Charpentier et M. Félix Lemaistre, 1860</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''XIII.''' L’eau, dit '''Thalès''', est le plus puissant des éléments, le premier en date, celui par qui tout a pris vie. Nous pensons comme '''Thalès''', au moins sur le dernier point. En effet, nous prétendons que le feu doit s’emparer du monde entier et convertir tout en sa propre substance, puis s’évaporer, s’affaisser, s’éteindre et ne rien laisser autre chose dans la nature que l’eau ; qu’enfin l’eau recèle l’espoir du monde futur. Ainsi périra par le feu cette création dont l’eau fut le principe. Es-tu surpris que des fleuves sortent incessamment d’un élément qui a tenu lieu de tout, et duquel tout est sorti ? Quand les éléments furent séparés les uns des autres, l’eau fut réduite au quart de l’univers, et placée de manière à suffire à l’écoulement des fleuves, des ruisseaux, des fontaines. Mais voici une idée absurde de ce même '''Thalès'''. Il dit que la terre est soutenue par l’eau sur laquelle elle vogue comme un navire ; qu’à la mobilité d’un tel support sont dues les fluctuations qu’on appelle tremblements de terre. Ce ne sera donc pas merveille qu’il y ait assez d’eau pour entretenir les fleuves, si tout le globe est dans l’eau. Ce système grossier et suranné n’est que risible ; tu ne saurais admettre que l’eau pénètre notre globe par ses interstices, et que la cale est entr’ouverte.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[[s:Questions_naturelles_(trad._Baillard)|<u>Sénèque le Jeune</u>]], [[s:Questions_naturelles_(trad._Baillard)/Livre_3|''Livre III. chap. 13.'']], traduction par [[s:Auteur:Joseph_Baillard|Joseph Baillard]], Hachette, 1914<br />(également disponible [https://remacle.org/bloodwolf/philosophes/seneque/questionsnaturelles3.htm ici])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: justify; margin: 0 2em;">'''XIII.''' L’eau, dit '''Thalès''', est le plus puissant des éléments : elle existait avant tout, elle est le principe de tout. Nous pensons comme '''Thalès''', au moins sur le dernier point. En effet, nous croyons que le feu, s’emparant du monde entier, convertira tout en sa propre substance : mais il finira par cesser ses ravages, et quand il sera éteint, dans toute la nature il ne restera que l’eau, et cette eau renfermera le germe et l’espérance d’un monde futur. Ainsi par le feu s’accomplira la destruction de l’univers, et par l’eau sa réorganisation. Êtes-vous surpris, maintenant, qu’après avoir tenu lieu de tous les éléments, et les avoir produits tous, l’eau suffise à l’entretien perpétuel des fleuves ? Quand les éléments furent séparés les uns des autres, l’eau fut réduite au quart de l’univers, et dans une proportion convenable pour suffire à l’alimentation des fontaines, des ruisseaux et des rivières. Mais voici une idée absurde du même '''Thalès''' : il dit que la terre est soutenue par l’eau, et qu’elle flotte sur elle comme un navire ; que les tremblements de terre sont causés par les oscillations et les mouvements du fluide qui la soutient. Il n’est donc pas étonnant qu’il y ait assez d’eau pour alimenter les fleuves, puisque tout le globe est dans l’eau. Mais rejetons cette vieille et informe hypothèse, qui assimile les sources aux flots que la cale entr’ouverte laisse pénétrer dans le vaisseau.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PP9#v=onepage&q&f=true <u>Œuvres Complètes de Sénèque, Tome Quatrième</u>], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA327#v=onepage&q&f=true ''Questions Naturelles, De Sénèque à Lucilius - Livre Troisième.''], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA342#v=onepage&q&f=true ''chap. XIII.''], traduction française de la collection Panckoucke, nouvelle édition très soigneusement revue par M. Charpentier et M. Félix Lemaistre, 1860</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: justify; margin: 0 2em;">'''Chap. III.'''<br />''Opiniõ de Thales touchant l’eau.''<br /><p style="text-align: justify; text-indent: 15px;">L’eau , comme dit '''Thales''' , e[[w:S_long|{{Info|ſ|forme ancienne longue de la lettre s minuscule}}]]<nowiki>t</nowiki> le plus fort des Elemens. Il croit me{{Info|ſ|forme ancienne longue de la lettre s minuscule}}me qu’elle e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t le premier , & que toutes cho{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es en ont pris nai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ance. Pour moy ie {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uis de cette opinion , ou du moins de la derniere partie de cette opinion. Car nous [[#nous_stoiciens_NdT_dR|<span id="nous_stoiciens_NdT_dR_back"><sup>1</sup></span>]] di{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ons que c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t le feu qui enueloppera tout le monde , & qui conuertira en {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oy toutes cho{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es; qu’il deuiendra {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ans force quand il n’aura plus de nourriture , qu’apres que le feu {{Info|ſ|forme ancienne longue de la lettre s minuscule}}era e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}teint il ne demeurera rien de re{{Info|ſ|forme ancienne longue de la lettre s minuscule}}te à la nature que l’eau {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eulement , & que c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t en elle {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eule que con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i{{Info|ſ|forme ancienne longue de la lettre s minuscule}}te l’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}perance d’vn monde futur. Ain{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i le feu e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t la fin du monde , & l’eau en e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t le commencement. Vous e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tonnez-vous donc que les fleuues pui{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ent tou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iours {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ortir d’vn Element , qui e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t fait pour toutes cho{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es & dont toutes cho{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e font ? Lors que la nature fit le departement des Elemens , l’eau fut placée de telle {{Info|ſ|forme ancienne longue de la lettre s minuscule}}orte , qu’elle peut {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uffire pour les fleuues , pour les rui{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}eaux , pour les fontaines. Mais ce que '''Thales''' dit en {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uitte e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t ridicule , car il dit que le Globe de la terre e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tenu par les eaux ; qu’elles le portent comme vn vai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}eau , & qu’elles l’agitent de la me{{Info|ſ|forme ancienne longue de la lettre s minuscule}}me {{Info|ſ|forme ancienne longue de la lettre s minuscule}}orte , lors que nous croyons qu’il tremble. Il ne faut donc pas s’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tonner , s’il ya tou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iours a{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ez d’eau pour former de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i grands fleuues , puis que tout le monde nage fur l’eau. Mais me{{Info|ſ|forme ancienne longue de la lettre s minuscule}}pri{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ez cette vieille , & cette gro{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}iere opinion , & ne croyez pas que l’eau vienne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur la terre , comme par des fentes & par des creua{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}es , & qu’elle y {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oit {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eulement comme dans le fond d’vn vai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}eau.</div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#nous_stoiciens_NdT_dR_back|<span id="nous_stoiciens_NdT_dR"><sup>1.</sup></span>]] Les Stoïciens.''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=ktOcOg9lr54C&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles%20iii&hl=fr&pg=PA1#v=onepage&q&f=true <u>Seneque Des Qvestions Natvrelles</u>], [https://books.google.fr/books?id=ktOcOg9lr54C&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles%20iii&hl=fr&pg=PA202#v=onepage&q&f=true ''Livre Troisiesme. Des eaux.''], [https://books.google.fr/books?id=ktOcOg9lr54C&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles%20iii&hl=fr&pg=PA234#v=onepage&q&f=true ''chap. XIII.''], traduction par [[w:Pierre_Du_Ryer|Pierre Du Ryer]], A Lyon, Chez Christofle Fovrmy, 1663</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div> </div> <div style="text-align: center; margin: 0 auto;">― ● ―</div> ==== Livre IV — Du Nil ==== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">En prologue, '''Sénèque''' fait l’éloge de [[w:Lucilius_le_Jeune|'''Lucilius''']] [[#Lucilius|<span id="Lucilius_back"><sup>'''I'''</sup></span>]] avant de lui expliquer les dangers de la flatterie. Puis, il décrit la crue du [[w:Nil|''Nil'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Nil_back|<sup>🔄</sup>]], expose les théories tentant de l’expliquer et les réfute. En épilogue, il fait le procès du luxe, et plus particulièrement celui d’acheter de la neige, et donc de marchandiser l’eau, regrettant qu’on ne puisse faire de même avec l’air et le soleil.</div> {{Boîte déroulante début|titre=NdA Lucilius|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Lucilius_back|<span id="Lucilius"><sup>I</sup></span>]] Du nom propre latin Lucilius [[wikt:en:Lucilius#Latin|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;">Gouverneur ''romain'' de Sicile durant le règne de [[w:Néron|Néron]], ainsi qu’un ami et un correspondant de Sénèque.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:Ier_siècle_av._J.-C.|I<sup>er</sup> siècle {{Info|EC|de l’Ère Commune}}]], [[w:Campanie#Histoire|''Campanie'']], [[w:Quatorze_régions_de_la_Rome_augustéenne#Regio_I_:_Porte_Capène|''Regio I'']])'''<br/><br/></div> {{Boîte déroulante fin}} ===== <div style="text-align: center;">Chapitre II.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Réfutation par '''Sénèque''' d’une théorie explicite de '''Thalès''' sur la crue du ''Nil'' (théorie identique mais supposément implicite rapportée par [[w:Hérodote|'''Hérodote''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Chapitre_XX|<sup>🔄</sup>]]).</div> :'''Texte latin''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''2.''' [...] Si '''Thaleti''' credis, etesiae descendenti ''Nilo'' resistunt et cursum eius acto contra ostia mari sustinent. Ita reuerberatus in se recurrit, nec crescit, sed exitu prohibitus resistit et quacumque mox potuit ui congestus erumpit. '''Euthymenes''' ''Massiliensis'' testimonium dicit: «Nauigaui, inquit, ''Atlanticum'' mare. Inde ''Nilus'' fluit, maior, quamdiu etesiae tempus obseruant; tunc enim eicitur mare instantibus uentis. Cum resederunt, et pelagus conquiescit minorque descendenti inde uis ''Nilo'' est. Ceterum dulcis mari sapor est et similes ''Niloticis'' beluae». Quare ergo, si ''Nilum'' etesiae prouocant, et ante illos incipit incrementum eius et post eos durat? Praeterea non fit maior quo illi flauere uehementius, nec remittitur incitaturque, prout illis impetus fuit; quod fieret, si illorum uiribus cresceret. Quid quod etesiae litus ''Aegyptium'' uerberant et contra illos ''Nilus'' descendit, inde uenturus unde illi, si origo ab illis esset? Praeterea ex mari purus et caeruleus efflueret, non, ut nunc, turbidus ueniret. Adde quod testimonium eius testium turba coarguitur. Tunc erat mendacio locus; cum ignota essent externa, licebat illis fabulas mittere. Nunc uero tota exteri maris ora mercatorum nauibus stringitur, quorum nemo narrat initium ''Nili'' aut mare saporis alterius: quae natura credi uetat, quia dulcissimum quodque et leuissimum sol trahit. Praeterea quare hieme non crescit? Et tunc potest uentis concitari mare, aliquanto quidem majoribus; nam etesiae temperati sunt. Quod si e mari ferretur ''Atlantico'', semel oppleret ''Aegyptum''. At nunc per gradus crescit.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/seneca.-cuestiones-naturales.-naturales-quaestiones.-vol.-ii-1979/page/n1/mode/2up <u>L. Annaei Senecae, Natvrales Qvaestiones</u>], [https://archive.org/details/seneca.-cuestiones-naturales.-naturales-quaestiones.-vol.-ii-1979/page/n7/mode/2up ''Liber Qvartvs A.''], [https://archive.org/details/seneca.-cuestiones-naturales.-naturales-quaestiones.-vol.-ii-1979/page/n41/mode/2up ''chap. 2.''], texte établi par Carmen Codoñer Merino [[w:es:Carmen_Codoñer_Merino|(es)]], Consejo Superior de Investigaciones Científicas, Madrid, 1979</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: justify; margin: 0 2em;">'''II.''' [...] Si '''Thaleti''' credis, Etesiæ descendenti ''Nilo'' resistunt, et cursus ejus acto contra ostia mari sustinent : ita reverberatus in se recurrit : nec crescit, sed exitu prohibitus resistit, et quacumque mox potuit, inconcessus erumpit.<br /><p style="text-align: justify; text-indent: 15px;">'''Euthymenes''' ''Massiliensis'' testimonium dicit : « Navigavi, inquit, ''Atlanticum'' mare. Inde ''Nilus'' fluit major, quamdiu Etesiæ tempus observant : tunc enim ejicitur mare instantibus ventis. Quum resederint, et pelagus conquiescit, minorque descendenti inde vis ''Nilo'' est. Ceterum dulcis maris sapor est, et similes ''Niloticis'' belluæ. » Quare ergo, si ''Nilum'' Etesiæ provocant, et ante illos incipit incrementum ejus, et post eos durat ? Præterea non fit major, quo illi flavere vehementius. Nec remittitur, incitaturque, prout illis impetus fuit : quod fieret, si illorum viribus cresceret. Quid, quod Etesiæ littus ''ægyptium'' verberant, et contra illos ''Nilus'' descendit, inde venturus, unde illi, si origo ab illis esset ? Præterea ex mari purus et cæruleus efflueret, non ut nunc turbidus venit. Adde, quod testimonium ejus testium turba coarguitur. Tunc erat mendacio locus, quum ignota essent externa. Licebat illis fabulas mittere. Nunc vero tota exteri maris ora mercatorum navibus stringitur : quorum nemo narrat nunc cæruleum ''Nilum'', aut mare saporis alterius ; quod et natura credi vetat, quia dulcissimum quodque et levissimum sol trahit. Præterea quare hieme non crescit ? et tunc potest ventis concitari mare, aliquando quidem majoribus ; nam Etesiæ temperati sunt. Quod si e mari ferretur ''Atlantico'', semel oppleret ''Ægyptum''. At nunc per gradus crescit.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PP9#v=onepage&q&f=true <u>Œuvres Complètes de Sénèque, Tome Quatrième</u>], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA371#v=onepage&q&f=true ''Questions Naturelles, De Sénèque à Lucilius - Livre Quatrième.''], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA385#v=onepage&q&f=true ''chap. II.''], traduction française de la collection Panckoucke, nouvelle édition très soigneusement revue par M. Charpentier et M. Félix Lemaistre, 1860</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''II.''' [...] À en croire '''Thalès''', les vents étésiens repoussent le ''Nil'' à sa descente dans la mer, et suspendent son cours en poussant la mer contre ses embouchures. Ainsi refoulé, il revient sur lui-même, sans pour cela grossir ; mais l’issue lui étant barrée, il s’arrête, et bientôt, partout où il le peut, force le passage qui lui est refusé. [[w:Euthymènes|'''Euthymène''']] [[#Euthymènes|<span id="Euthymènes_back"><sup>'''I'''</sup></span>]], de ''Marseille'', en parle comme témoin : « J’ai navigué, dit-il, sur la mer ''Atlantique''. Elle cause le débordement du ''Nil'', tant que les vents étésiens se soutiennent ; car c’est leur souffle qui alors pousse cette mer hors de son lit. Dès qu’ils tombent, la mer aussi redevient calme, et le ''Nil'' à sa descente déploie moins de puissance. Du reste, l’eau de cette mer est douce, et nourrit des animaux semblables à ceux du ''Nil''. » Mais pourquoi, si les vents étésiens font gonfler le ''Nil'', la crue commence-t-elle avant la saison de ces vents, et dure-t-elle encore après ? D’ailleurs le fleuve ne grossit pas à mesure qu’ils soufflent plus violemment. Son plus ou moins de fougue n’est point réglé sur celle des vents étésiens, ce qui aurait lieu, si leur action le faisait hausser. Et puis ils battent la côte ''égyptienne'', le ''Nil'' descend à leur encontre : il faudrait qu’il vînt du même point qu’eux, si son accroissement était leur ouvrage. De plus, il sortirait pur et azuré de la mer, et non pas trouble comme il est. Ajoute que le témoignage d’'''Euthymène''' est réfuté par une foule d’autres. Le mensonge avait libre carrière, quand les plages étrangères étaient inconnues ; on pouvait de là nous envoyer des fables, À présent, la mer extérieure est côtoyée sur tous ses bords par des trafiquants dont pas un ne raconte qu’aujourd’hui le ''Nil'' soit azuré ou que l’eau de la mer soit douce. La nature elle-même repousse cette idée ; car les parties les plus douces et les plus légères sont pompées par le soleil. Et encore pourquoi le ''Nil'' ne croît-il pas en hiver ? Alors aussi la mer peut être agitée par des vents quelque peu plus forts que les étésiens, qui sont modérés. Si le mouvement venait de l’Atlantique, il couvrirait tout d’un coup l’Égypte : or l’inondation est graduelle.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[[s:Questions_naturelles_(trad._Baillard)|<u>Sénèque le Jeune</u>]], [[s:Questions_naturelles_(trad._Baillard)/Livre_4|''Livre IV.'']] ''chap. 2.'', traduction par [[s:Auteur:Joseph_Baillard|Joseph Baillard]], Hachette, 1914<br />(également disponible [https://remacle.org/bloodwolf/philosophes/seneque/questionsnaturelles4.htm ici])</div> {{Boîte déroulante début|titre=NdA trad. par Joseph Baillard de 1914|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Euthymènes_back|<span id="Euthymènes"><sup>I</sup></span>]] Du nom propre grec ancien Εὐθυμένης / Euthuménēs [[wikt:en:Εὐθυμένης#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;"> ➥ de l’adjectif εὐθύς / euthús, « 1. Droit, direct : (au sens moral) direct, ouvert, franc. »;<br /><p style="margin: 0 2em; text-indent: 15px;"> ➥ + du nom commun μενος / ménos, « 1. Esprit. 2. Désir, ardeur, souhait, but. 3. Colère. 4. Courage, esprit, vigueur. 5. Pouvoir, force. 6. Violence. »;<br /><p style="margin: 0 2em; text-indent: 15px;"> ➥ + du suffixe nominal‎ propre -ης / -ēs [[wikt:en:-ης#Suffix_2|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;"> Navigateur et explorateur de la mer Extérieure le long des côtes africaines (actuelle Atlantique sud).<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:VIeme_siècle_av._J.-C.|VI<sup>ème</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]], [[w:Marseille_antique#Massalia,_une_cité_grecque|''Massalia'']], actuelle Marseille)'''<br/><br/></div> {{Boîte déroulante fin}} <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: justify; margin: 0 2em;">'''II.''' [...] Selon '''Thalès''', le phénomène a pour cause les vents Étésiens, qui s’opposent au cours du ''Nil'' et font rebrousser ses eaux en sens inverse du mouvement qui le porte vers la mer. Refoulés sur eux-mêmes, les flots refluent sans pour cela grossir ; mais l’issue leur étant fermée, ils s’arrêtent, et bientôt ils s’ouvrent partout où ils peuvent le passage qui leur est refusé.<br /><p style="text-align: justify; text-indent: 15px;">'''Euthymène''' de ''Marseille'' en parle comme témoin : « J’ai navigué, dit-il, sur la mer ''Atlantique''. Le ''Nil'' roule des eaux plus abondantes, tant que durent les vents Étésiens ; car alors ils refoulent la mer sur le fleuve. Dès qu’ils se sont abattus et que la mer est devenue calme, le ''Nil'', qui peut redescendre vers celle-ci, diminue. Au reste, les eaux de cette mer sont douces et contiennent des animaux semblables à ceux du ''Nil''. » Dans cette hypothèse, qui donne les vents Étésiens pour cause des crues du ''Nil'', qu’on me dise pourquoi ces crues précèdent les vents, persistent quand les vents ne sont plus, enfin n’augmentent plus d’intensité et de violence, et ne diminuent pas selon la violence et l’impétuosité du vent même ; c’est pourtant ce qui devrait arriver, si les vents déterminaient la hausse des eaux. De plus, les vents Étésiens battent directement la côte ''égyptienne'' : pourquoi donc le ''Nil'' descend-il contre le souffle de ces vents, tandis qu’il devrait couler dans la même direction, s’il leur devait ses débordements ? Enfin, pourquoi, au lieu d’être diaphanes et azurés, ces flots, qu’on fait venir de la mer, sont-ils chargés de limon ? Ajoutez qu’une foule de témoignages réfutent '''Euthymène'''. On pouvait mentir, quand les plages étrangères étaient inconnues : c’était alors le temps des fables ; mais aujourd’hui mille vaisseaux marchands côtoient la mer extérieure ; personne ne dit que le ''Nil'' ait des flots d’azur ; personne ne donne à la mer une saveur douce, que la nature refuse à ses eaux : car le soleil en pompe sans cesse la partie la plus douce et la plus légère ; ensuite pourquoi le ''Nil'' ne croîtrait-il point pendant l’hiver ? la mer alors peut être battue par les vents, par des vents plus violents que les Étésiens, qui sont modérés. Enfin, si le mouvement venait de l’Atlantique, l’Égypte entière serait inondée tout d’un coup : or, l’inondation est graduelle.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PP9#v=onepage&q&f=true <u>Œuvres Complètes de Sénèque, Tome Quatrième</u>], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA371#v=onepage&q&f=true ''Questions Naturelles, De Sénèque à Lucilius - Livre Quatrième.''], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA385#v=onepage&q&f=true ''chap. II.''], traduction française de la collection Panckoucke, nouvelle édition très soigneusement revue par M. Charpentier et M. Félix Lemaistre, 1860</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: justify; margin: 0 2em;">'''Chap. II.'''<br />''En quelle fai[[w:S_long|{{Info|ſ|forme ancienne longue de la lettre s minuscule}}]]<nowiki>ó</nowiki> {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e fait l’accroi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ement du Nil.''<br /><p style="text-align: justify; text-indent: 15px;">[...] Si vous en croyez '''Thales''' , les vents Ethe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iens re{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tent au ''Nil'' en de{{Info|ſ|forme ancienne longue de la lettre s minuscule}}cendant dans la mer; & arre{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tent {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on cours, en pou{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ant la mer contre {{Info|ſ|forme ancienne longue de la lettre s minuscule}}es {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ept emboucheures. Si bien qu’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es {{Info|ſ|forme ancienne longue de la lettre s minuscule}}tant repou{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}é de la {{Info|ſ|forme ancienne longue de la lettre s minuscule}}orte il retourne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oy-me{{Info|ſ|forme ancienne longue de la lettre s minuscule}}me , & ne croi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t pas comme l’on pen{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e , mais par ce qu’il trouue vn ob{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tacle qui l’empe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}che de pa{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}er outre , il e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t contraint de s’arre{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ter , & ne pouuant plus pour{{Info|ſ|forme ancienne longue de la lettre s minuscule}}uiure {{Info|ſ|forme ancienne longue de la lettre s minuscule}}a cour{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e , il {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e re{{Info|ſ|forme ancienne longue de la lettre s minuscule}}pand par où il peut {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e répandre. '''Euthimenes''' de ''Mar{{Info|ſ|forme ancienne longue de la lettre s minuscule}}eille'' en rend ce te{{Info|ſ|forme ancienne longue de la lettre s minuscule}}moignage. I’ay nauigé, dit il, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur la mer ''Atlantique'' , & c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t par elle que le ''Nil'' deuient plus grand, lors que les vents Ethe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iens {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oufflent ; car alors cette mer {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ort pour ain{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i dire d’elle-me{{Info|ſ|forme ancienne longue de la lettre s minuscule}}me par la force & par la violence de ces vents. Mais lors qu’ils ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oufflent plus la mer demeure tranquille, & le Nil ne trouue plus rien qui l’empe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}che de de{{Info|ſ|forme ancienne longue de la lettre s minuscule}}cendre , Au re{{Info|ſ|forme ancienne longue de la lettre s minuscule}}te l’eau de la mer e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t douce en ce temps-là , & l’on y void des be{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tes {{Info|ſ|forme ancienne longue de la lettre s minuscule}}emblables à celles du Nil. Mais {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i les Ethe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iens {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont enfler le Nil, pourquoy {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on débordement commence il auant qu’ils {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oufflent & pourquoy dure - il encore lors qu’ils ont ce{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}é de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ouffler. Dauantage ils ne s’enfle pas plus que de cou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tume , quand ces vents {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oufflent auecque plus de violence qu’ils ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont ordinairement. Enfim il ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e hau{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}e & ne s’abai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}e pas {{Info|ſ|forme ancienne longue de la lettre s minuscule}}elon que leur impetuo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ité e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t plus ou moins grande , ce qui arriveroit {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ans doute s’il s’enfloit par la force de ces véts. Mais comme les Ete{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iens battent directement les bords de l’Egypte, & que le Nil de{{Info|ſ|forme ancienne longue de la lettre s minuscule}}cend contre eux ; il faudroit s’ils e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}toient cau{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on accroi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ement , qu’il commença{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t par l’endroit d’où ils viennent. Outre cela il {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ortiroit tout pur de la mer, & de la couleur de la mer, & ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eroit pas trouble & limonneux , comme il e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t. Et apres tout le te{{Info|ſ|forme ancienne longue de la lettre s minuscule}}moignage d’'''Euthimene''' , e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t condamné par le plus grand nombre. Il e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}toit permis de mentir quand on n’auoit point de connoi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ance des pays e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}trangers ; & alors on pouuoit facilement nous en enuoyer des fables. Mais aujourd’huy tous les riuages des mers les plus e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}loignées {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont remplis de vai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}eaux de marchands, & pas vn ne nous apporte que le ''Nil'' {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oit de la couleur de la mer, ou que la mer ait vn autre gou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t. Quand nous aurions des rai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ons pour nous la per{{Info|ſ|forme ancienne longue de la lettre s minuscule}}uader , la nature nous empe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}cheroit de le croire par ce que le Soleil en attire ce qu’il y a de plus leger & de plus doux. Dauantage pourquoy ne croi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t-il pas en Hyuer , puis que la met en ce temps là peut e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tre agitée par des vents plus violents, que les Ethe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iens qui {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont tou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iours moderez. Que {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i le ''Nil'' venoit de la mer ''Atlantique'' , il couuriroit l’Egypte tout d’vn coup, & neantmoins il ne la couure que peu à peu.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=gEzVYlz3c3cC&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles%20iii%20volume%202&hl=fr&pg=PA1#v=onepage&q&f=true <u>Seneque Des Qvestions Natvrelles</u>], [https://books.google.fr/books?id=gEzVYlz3c3cC&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles%20iii%20volume%202&hl=fr&pg=PA3#v=onepage&q&f=true ''Livre Qvatriesme. De la Nege, de la Greſle, & de la Pluye.''], [https://books.google.fr/books?id=gEzVYlz3c3cC&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles%20iii%20volume%202&hl=fr&pg=PA37#v=onepage&q&f=true ''chap. II.''], traduction par [[w:Pierre_Du_Ryer|Pierre Du Ryer]], A Lyon, Chez Christofle Fovrmy, 1663</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div> </div> <div style="text-align: center; margin: 0 auto;">― ● ―</div> ==== Livre VI — Des tremblements de terre ==== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">En prologue, '''Sénèque''' énonce le plan du livre, des causes des tremblements de terre et des peurs qu’ils provoquent, en s’appuyant sur celui de ''Campanie'' qui a récemment causé d’importants dégâts à ''Pompéi'' et à ''Herculanum''. Des chapitres IV à XX, de nombreuses théories sismiques sont présentées, la plupart liées au nom d’un philosophe qui les prône. Le feu, l’eau et l’air sont cités comme causes, et plusieurs d’entre-elles les combinent. À partir du chapitre XXIV, '''Sénèque''' développe sa propre opinion : l’air pénétrant, qui remplit complètement les cavités souterraines sous une forte pression, en est la cause. En épilogue, il explique à '''Lucilius''' quel comportement adopté en de telles situations, à savoir être courageux en ne craignant pas la mort</div> ===== <div style="text-align: center;">Chapitre VI.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Réfutation d’une théorie de '''Thalès''' de la Terre flottant sur l’eau, et témoignage d’une de ses preuves portant sur les tremblements de terre.</div> :'''Texte latin''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''6.''' In aqua causam esse nec ab uno dictum est nec uno modo. '''Thales''' ''Milesius'' totam terram subiecto iudicat umore portari et innare, siue illud oceanum uocas, siue magnum mare, siue alterius naturae simplicem adhuc aquam et umidum elementum. Hac, inquit, unda sustinetur orbis uelut aliquod grande nauigium et graue his aquis quas premit. Superuacuum est reddere causas propter quas existimat grauissimam partem mundi non posse spiritu tam tenui fugacique gestari; non enim nunc de situ terrarum sed de motu agitur. Illud argumenti loco ponit aquas esse in causa quibus hic orbis agitetur, quod in omni maiore motu erumpunt fere noui fontes, sicut in nauigiis quoque euenit ut, si inclinata sunt et abierunt in latus, aquam sorbeant, quae in omni eorum onere quae uehit, si immodice depressa sunt, aut superfunditur aut certe dextra sinistraque solito magis surgit. Hanc opinionem falsam esse non est diu colligendum. Nam, si terra aqua sustineretur et ea aliquando concuteretur, semper moueretur, nec agitari illam miraremur sed manere; deinde tota concuteretur, non ex parte; numquam enim nauis dimidia iactatur. Nunc uero terrarum non uniuersarum sed ex parte motus est. Quomodo ergo fieri potest ut, quod totum uehitur, totum non agitetur, si eo quo uehitur agitatum est? — At quare aquae erumpunt? — Primum omnium saepe tremuit terra et nihil umoris noui fluxit. Deinde, si ex hac causa unda prorumperet, a lateribus terrae circumfunderetur, sicut in fluminibus ac mari uidemus incidere ut incrementum aquarum, quotiens nauigia desidunt, in lateribus maxime appareat. Ad ultimum non tam exigua fieret quam tu dicis eruptio nec uelut per rimam sentina subreperet, sed fieret ingens inundatio ut ex infinito liquore et ferente uniuersa.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/seneca.-cuestiones-naturales.-naturales-quaestiones.-vol.-ii-1979/page/n1/mode/2up <u>L. Annaei Senecae, Natvrales Qvaestiones</u>], [https://archive.org/details/seneca.-cuestiones-naturales.-naturales-quaestiones.-vol.-ii-1979/page/n135/mode/2up ''Liber Qvintvs - De terrae motv''], [https://archive.org/details/seneca.-cuestiones-naturales.-naturales-quaestiones.-vol.-ii-1979/page/n155/mode/2up ''chap. 6.''], texte établi par Carmen Codoñer Merino [[w:es:Carmen_Codoñer_Merino|(es)]], Consejo Superior de Investigaciones Científicas, Madrid, 1979</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: justify; margin: 0 2em;">'''VI.''' In aqua causam esse, nec ab uno dictum est, nec uno modo. '''Thales''' ''Milesius'' totam terram subjecto judicat humore portari et innatare : sive illud Oceanum vocas, sive magnum mare, sive alterius naturæ simplicem adhuc aquam et humidum elementum. Hac, inquit, unda sustinetur orbis, velut aliquod grande navigium et grave his aquis, quas premit. Supervacuum est reddere causas, propter quas existimat, gravissimam partem mundi non posse spiritu tam tenui fugacique gestari ; non enim nunc de situ terrarum, sed de motu agitur. Illud argumenti loco ponit, aquas esse in causa, quibus hic orbis agitatur, quod in omui majore motu erumpunt fere novi fontes : sicut in navigiis quoque evenit, ut, si inclinata sunt et abiere in latus, aquam sorbeant, quæ in omni onere eorum quæ vehit, si immodice depressa sunt, aut superfunditur, aut certe dextra sinistraque solito magis surgit. Hanc opinionem falsam esse, non est diu colligendum ; nam, si terram aqua sustineret, et ea aliquando concuteretur : semper moveretur, nec agitari illam miraremur, sed manere. Tum tota concuteretur, non ex parte : nunquam enim navis dimidia jactatur. Nunc vero non terrarum universarum, sed ex parte motus est. Quomodo ergo fieri potest, ut quod totum vehitur, totum non agitetur, si eo quo vehitur, agitatum est ? At quare aquæ erumpunt ? Primum omnium sæpe tremuit terra, et nihil humoris novi fluxit. Deinde si ex hac causa unda prorumperet, a lateribus terræ circumfunderetur : sicut in fluminibus ac mari videmus accidere, ut incrementum aquarum, quoties navigia desidunt, in lateribus maxime appareat. Ad ultimum non tam exigua fieret quam dicit eruptio, nec velut per rimam sentina subreperet, sed fieret ingens inundatio, ut ex infinito liquore, et ferente universa.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PP9#v=onepage&q&f=true <u>Œuvres Complètes de Sénèque, Tome Quatrième</u>], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA420#v=onepage&q&f=true ''Questions Naturelles, De Sénèque à Lucilius - Livre Sixième.''], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA429#v=onepage&q&f=true ''chap. VI.''], traduction française de la collection Panckoucke, nouvelle édition très soigneusement revue par M. Charpentier et M. Félix Lemaistre, 1860</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''VI.''' Que l’eau soit cause des tremblements de terre, c’est ce qu’affirment divers auteurs et avec divers arguments. '''Thalès''' de ''Milet'' estime que le globe entier a pour support une masse d’eaux sur laquelle il flotte, et qu’on peut appeler Océan ou grande mer, ou élément jusqu’ici de nature simple, l’élément humide. Cette eau, dit-il, soutient la terre ; et l’immense navire pèse sur le liquide qu’il comprime. Il est superflu d’exposer les motifs qui font croire à '''Thalès''' que la partie de l’univers la plus pesante ne saurait porter sur une substance aussi ténue, aussi fugace que l’air : il ne s’agit pas maintenant de l’assiette du globe, mais de ses secousses. '''Thalès''' apporte en preuve de son système, que presque toujours les grandes secousses font jaillir des sources nouvelles, comme il arrive dans les navires qui, lorsqu’ils penchent et s’inclinent sur le flanc, sont envahis par l’eau ; toujours, s’il y a surcharge, l’eau vient couvrir le bâtiment, ou du moins s’élève à droite et à gauche plus que de coutume. La fausseté de cette opinion se démontre sans longs raisonnements. Si la terre était soutenue par l’eau, elle tremblerait quelquefois dans toute sa masse et toujours serait en mouvement ; ce ne serait pas son agitation qui étonnerait, mais son repos. Elle s’ébranlerait tout entière, non partiellement ; car ce n’est jamais la moitié seulement d’un navire qui est battue des flots. Or, les tremblements de notre terre ne sont pas universels, mais partiels. Comment serait-il possible qu’un corps porté tout entier par l’eau ne fût pas agité tout entier, quand ce fluide est agité ? « Mais d’où viennent les eaux qu’on a vues jaillir ? » D’abord, souvent la terre tremble, sans qu’il en sorte de nouvelles eaux. Ensuite, si telle était la cause de ces éruptions, elles n’auraient lieu qu’autour des flancs du globe ; ce que nous voyons arriver sur les fleuves et en mer : l’exhaussement de l’onde, à mesure que s’enfonce le navire, se remarque surtout aux flancs du bâtiment. Enfin l’éruption dont on parle ne serait pas si minime, et comme une voie d’eau qui s’infiltre par une fente légère ; l’inondation serait immense en raison de l’abîme infini sur lequel flotterait le monde.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[[s:Questions_naturelles_(trad._Baillard)|<u>Sénèque le Jeune</u>]], [[s:Questions_naturelles_(trad._Baillard)/Livre_6|''Livre VI.'']] ''chap. 6.'', traduction par [[s:Auteur:Joseph_Baillard|Joseph Baillard]], Hachette, 1914<br />(également disponible [https://remacle.org/bloodwolf/philosophes/seneque/questionsnaturelles6.htm ici])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: justify; margin: 0 2em;">'''VI.''' Plusieurs philosophes ont prétendu que l’eau est la cause de ces secousses : ce que chacun explique à sa manière. '''Thalès''' de ''Milet'' prétend que le globe entier a pour support une masse d’eau sur laquelle il flotte ; peu importe qu’on donne à cet amas le nom d’Océan, de grande mer ou d’eau élémentaire, eau simple. Cette eau, dit-il, soutient la terre comme un grand vaisseau pesant sur le liquide qu’il comprime. Il est inutile d’exposer les raisons qui font croire à '''Thalès''' que le corps le plus pesant de la nature ne peut être soutenu par un fluide aussi délié et aussi rare que l’air : car il s’agit ici des tremblements de terre et non de l’assiette du globe. La grande raison de '''Thales''' pour faire de l’eau la cause des secousses de la terre, c’est que, dans tout tremblement considérable, jaillissent des eaux nouvelles ainsi les vaisseaux se remplissent d’eau quand ils penchent d’un côté ; chargés à l’excès, ou ils sont submergés, ou ils s’enfoncent à droite et à gauche plus profondément dans la mer. Il ne faut pas longtemps discuter pour voir la fausseté de cette opinion. Si la terre était soutenue par les eaux, elle serait quelquefois fortement ébranlée, mais de plus elle serait toujours flottante, et il faudrait s’étonner non de son agitation , mais de son repos ; enfin, au lieu d’être ébranlée en partie, elle le serait tout entière : car jamais la moitié d’un vaisseau n’est battue des flots. Or, on sait que les secousses de la terre sont partielles et non universelles : comment se ferait-il donc que ce qui est entièrement porté par les eaux ne fût pas entièrement agité, tandis que les eaux mêmes le sont en totalité ? Mais, dit-on, qui fait jaillir les eaux ? D'abord, souvent la terre tremble sans qu’il se produise des eaux nouvelles ; ensuite, si telle était la cause de ces éruptions, les eaux se répandraient latéralement autour de la terre. Ainsi, par exemple, quand un vaisseau s’enfonce ou dans la mer ou dans les fleuves, c’est vers les bords surtout que l’accroissement devient sensible. Enfin les sources qui jaillissent ne seraient pas si peu considérables ; on ne pourrait pas les comparer à une voie d’eau qui pénètre par les fentes du fond de cale : ce serait une inondation immense comme l’abîme infini sur lequel flotterait le monde.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PP9#v=onepage&q&f=true <u>Œuvres Complètes de Sénèque, Tome Quatrième</u>], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA420#v=onepage&q&f=true ''Questions Naturelles, De Sénèque à Lucilius - Livre Sixième.''], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA429#v=onepage&q&f=true ''chap. VI.''], traduction française de la collection Panckoucke, nouvelle édition très soigneusement revue par M. Charpentier et M. Félix Lemaistre, 1860</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: justify; margin: 0 2em;">'''Chap. VI.'''<br />''Si l’eau e[[w:S_long|{{Info|ſ|forme ancienne longue de la lettre s minuscule}}]]<nowiki>t</nowiki> la cau{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e des tréblemés de terre.''<br /><p style="text-align: justify; text-indent: 15px;">Ce n'e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t pas vn homme {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eul qui a dit , que l’eau e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}toit cau{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e du tremblement de la terre ; & l’on ne l’a pas dit d’vne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eule façó. '''Thales''' ''Mile{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ien'' a crû que toute la terre e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}toit portée {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur l’eau , & qu’elle y nageoit, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oit que vous appelliez cette eau Ocean, ou que vous l’appelliez grade mer, ou vne eau d’vne autre nature , eau {{Info|ſ|forme ancienne longue de la lettre s minuscule}}imple , element humide. C’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur cette eau, dit-il, que le monde e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tenu, comme quelque vai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}eau d’vne grandeur deme{{Info|ſ|forme ancienne longue de la lettre s minuscule}}urée , qui charge les eaux qui le {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tiennent. Il {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eroit inutile de rapporter les rai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ons qui luy {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont croire que la plus pe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ante partie du móde ne peut e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tre {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tenuë par l’air qui e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ubtil, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i fluide & {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i delié ; & d’ailleurs, il ne s’agit pas icy de l’a{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}iete de la terre , mais du tremblement de la terre. Ain{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i pour preuue que les eaux {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont cau{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e que la terre tremble , il dit qu’il ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e fait pre{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que point de grands tremblemens de terre, qu’on n’en voye {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ortir en{{Info|ſ|forme ancienne longue de la lettre s minuscule}}uitte de nouuelles {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ources; que la terre re{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}emble en cela aux vai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}eaux qui ne peuuent pancher d’vn co{{Info|ſ|forme ancienne longue de la lettre s minuscule}}té, qu’ils ne pui{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ent de l’eau, qui {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e re{{Info|ſ|forme ancienne longue de la lettre s minuscule}}pand {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur toutes les cho{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es qu’ils portent , {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i elles {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont trop enfoncées; ou qui s’éleue de part & d’autre à la gauche , & à la droite. Il n’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t pas besoin d’vn long di{{Info|ſ|forme ancienne longue de la lettre s minuscule}}cours pour montrer la fau{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}eté de cette opinion ; car {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i l’eau {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tenoit la terre, quelquesfois elle trembleroit toute entiere, & {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eroit tou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iours en mouuement; & nous ne nous e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tonnerions point de la voir remuer, mais de la voir ferme & inébranlable. Elle trembleroit toute entiere , & non pas en partie , car vn vai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}eau n’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t iamais agité par vne moitié {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eulement ; & apres tout nous voyons que le tremblement ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e fait pas de toute la terre , mais {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eulement d’vne partie. Comment donc {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e peut-il faire que ce qui e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t porté tout entier ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oit pas entierement agité , {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i la cho{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e me{{Info|ſ|forme ancienne longue de la lettre s minuscule}}me qui porte e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}meuë & agitée ? Mais pourquoy {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ort-il de l’eau apres vn tremblement de terre ? Premierement la terre a {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ouuent tremblé {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ans qu’on en ayt veu {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ortir de nouuelles {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ources. D’ailleurs {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i l’eau {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ortoit par cette rai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}on elle {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e re{{Info|ſ|forme ancienne longue de la lettre s minuscule}}pandroit par les co{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tez de la terre , comme nous voyons dans les fleuues & dans la mer , où lors que le vai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}eau s’enfonce on remarque que l’eau s'éleue , principalement par les co{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tez. Enfin ces eaux ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ortiroient pas en {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i petite quantité, ny par vne fi petite ouuerture , mais il {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eroit vne grande inondation, comme procedant de cette abondance d’eaux qui {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tiennent tout l’vniuers.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=gEzVYlz3c3cC&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles%20iii%20volume%202&hl=fr&pg=PA1#v=onepage&q&f=true <u>Seneque Des Qvestions Natvrelles</u>], [https://books.google.fr/books?id=gEzVYlz3c3cC&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles%20iii%20volume%202&hl=fr&pg=PA141#v=onepage&q&f=true ''Livre Sixiesme. Des tremblemens de terre.''], [https://books.google.fr/books?id=gEzVYlz3c3cC&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles%20iii%20volume%202&hl=fr&pg=PA164#v=onepage&q&f=true ''chap. VI.''], traduction par [[w:Pierre_Du_Ryer|Pierre Du Ryer]], A Lyon, Chez Christofle Fovrmy, 1663</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Pline_l%27Ancien|'''Pline l’Ancien''']] [[#Pline|<span id="Pline_back"><sup>'''I'''</sup></span>]] == <p style="text-align: right;">([[w:23|23]]/[[w:24|24]], à [[w:Côme|''Novum Comum'']] ou [[w:Vérone|Vérone]] — [[w:79|79]], à [[w:Stabies|Stabies]], [[w:Mort_de_Pline_l%27Ancien|mort]] par asphyxie près de [[w:Pompéi|Pompéi]], lors de l’éruption du [[w:Vésuve|Vésuve]], en voulant observer le phénomène au plus près et en désirant porter secours aux victimes, alors en poste à [[w:Misène|''Misène'']] en tant que Préfet commandant la flotte militaire ''romaine'') <sup>[[w:Ier_siècle|⏳]]</sup> [[s:Auteur:Pline_l’Ancien|<sup>📚</sup>]] [https://books.google.fr/books?id=tRsuD3WJT-UC&newbks=1&newbks_redir=0&lpg=PA3&dq=bibliogroup%3A%22Dictionnaire%20des%20philosophes%20antiques%22&hl=fr&pg=PA876#v=onepage&q&f=true {{Info|<sup>🔍</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume Va, §204 - Plinius Secundus (Caius —)}}] <div style="text-align: justify; margin: 0 1em; text-indent: 15px">Haut fonctionnaire militaire et civique, issu de l’[[w:Chevalier_romain|''orde équestre'']], et écrivain prolifique dans de très nombreux domaines.</div> {{Boîte déroulante début|titre=NdA Pline l’Ancien|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Pline_back|<span id="Pline"><sup>I</sup></span>]] [[w:Nom_romain|Tria Nomina]] en latin {{Info|Caius|praenomen, nom individuel du citoyen romain}} {{Info|Plinius|nomen, nom de famille}} {{Info|Secundus|cognomen, surnom héréditaire, servant à distinguer les diverses branches d’une même gens}}'''<br/><br/></div> {{Boîte déroulante fin}} === [[w:Histoire_naturelle_(Pline_l'Ancien)|Histoire naturelle]] === <p style="text-align: right;">[[s:Histoire_naturelle_(Pline)|📚]] <div style="text-align: justify; margin: 0 1em; text-indent: 15px">Ouvrage de 37 livres dédié à l’empereur [[w:Titus_(empereur_romain)|'''Titus''']] [[#Titus|<span id="Titus_back"><sup>'''I'''</sup></span>]], dont il a été le ''{{Lang|la|contubernium}}'' pendant son service en tant que commandant des armées du ''Rhin'' en ''Germanie'' en [[w:47|47]]. '''Pline''' définit lui-même son enquête [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Histoire/Enquête_I|<sup>🔄</sup>]] sur la nature comme une reproduction de la vie — ''{{Lang|la|rerum natura, hoc est uita narratur}}'' (Livre I, Préface, 10), qu’il inscrit dans la tradition encyclopédique [[#encyclopédie_back|<sup>⤴️</sup>]] grecque mais s’en différencie par son exhaustivité : ''{{Lang|la|Jam omnia attingenda, quæ Græci}}'' ''{{Lang|grc|τάς έγχυχλοπαιδείας}}'' ''{{Lang|la|vocant : et tamen ignota aut incerta ingeniis facta; alia vero ita multis prodita, ut in fastidium sint adducta}}'' (Préface, 11). Il a, dans ce but, compilé « vingt mille faits dignes d’intérêt, tirés de la lecture d’environ deux mille volumes, [...] provenant de cent auteurs de choix » — ''{{Lang|la|Viginti millia rerum dignarum cura ex lectione voluminum circiter duum millium, [...] ex exquisitis auctoribus centum}}'' (Préface, 13).</div> {{Boîte déroulante début|titre=NdA Titus|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Titus_back|<span id="Titus"><sup>I</sup></span>]] Du nom propre latin Titus [[wikt:en:Titus#Latin|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;">Commandant militaire, notamment pendant la [[w:Premi%C3%A8re_guerre_jud%C3%A9o-romaine|''première guerre judéo-romaine'']], au cours de laquelle il prend ''Jérusalem'' que ses troupes mettent à sac et fait détruire le [[w:Second_temple_de_Jérusalem#Destruction|''Second Temple'']], et empereur ''romain'', de la dynastie des [[w:Flaviens|''Flaviens'']], de [[w:79|79]] à [[w:81|81]].<br /><p style="text-align: right; margin: 0 2em;">(30 décembre [[w:39|39]] , ''Rome'' — 13 septembre [[w:81|81]], mort par fièvre selon [[w:Suétone|Suétone]] [http://remacle.org/bloodwolf/historiens/suetone/titus.htm <sup>VdDC, Titus</sup>] ou par empoisonnement avec du venin de [[w:Aplysia|''lièvre marin'']] par son propre frère [[w:Domitien|Domitien]] selon [[w:Philostrate_d%27Ath%C3%A8nes|Philostrate]] [https://remacle.org/bloodwolf/roman/philiostrate/apollonius6.htm <sup>AdT, l. VI, chap. 32</sup>])<sup>[[w:Ier_siècle|⏳]]</sup>'''<br/><br/></div> {{Boîte déroulante fin}} ==== Livre II ==== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Enquête sur l’astronomie et la physique du monde, basée sur les quatre éléments : air, terre, eau et feu.</div> ===== <div style="text-align: center;">Chapitre IX.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage de la première prédiction grecque d’une éclipse solaire (ou lunaire selon les traductions) par '''Thalès'''.</div> :'''Texte latin''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''IX.''' Et rationem quidem defectus utriusque primus ''Romani'' generis in vulgus extulit '''Sulpicius Gallus''', qui consul cum '''Marcello''' fuit, sed tum tribunus militum, sollicitudine exercitu liberato, pridie quam '''Perseus''' rex superatus a '''Paulo''' est, in concionem ab imperatore productus ad prædicendam eclipsim, mox et composito volumine. Apud Græcos autem investigavit primus omnium '''Thales''' ''Milesius'', Olympiadis XLVIII anno quarto, prædicto solis defectu, qui '''Alyatte''' rege factus est, Urbis conditæ; anno CLXX. Post eos utriusque sideris cursum in sexcentos annos præcinuit '''Hipparchus''', menses gentium, diesque et horas, ac situs locorum, et visus populorum complexus, ævo teste, haud alio modo, quam consiliorum naturæ particeps. Viri ingentes supraque mortalium naturam, tantorum numinum lege deprehensa, et misera hominum mente absoluta, in defectibus scelera aut mortem aliquam siderum pavente (quo in metu fuisse '''Stesichori''' et '''Pindari''' vatum sublimia ora palam est deliquio Solis), et in Luna veneficia arguente mortalitate, et ob id crepitu dissono auxiliante. Quo pavore, ignarus causæ, '''Nicias''' ''Atheniensium'' imperator, veritus classem portu educere, opes eorum afflixit. Macti ingenio este, cæli interpretes, rerumque naturæ capaces, argumenti repertores, quo deos hominesque vinxistis. Quis enim hæc cernens, et statos siderum (quoniam ita placuit appellare) labores, non suæ necessitati mortalis genitus ignoscat ? Nunc confessa de iisdem breviter atque capitulatim attingam, ratione admodum necessariis locis strictimque reddita : nam neque instituti operis talis argumentatio est : neque omnium rerum afferri posse causas, minus mirum est, quam consfare in aliquibus.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/b24875958_0001/page/n7/mode/2up <u>Histoire Naturelle de Pline.</u>], [https://archive.org/details/b24875958_0001/page/98/mode/2up ''Livre II.''], [https://archive.org/details/b24875958_0001/page/106/mode/2up ''chap. IX.''], texte corrigé par [[w:Émile_Littré|M. É. Littré]], à partir de celui de [[w:Jean_Hardouin|Hardouin]], Librairie de Firmin-Didot et C<sup>ie</sup>, Paris, 1883<br />(également disponible une édition 1848 [[s:Page:Pline_l'ancien_-_Histoire_naturelle,_Littré,_T1_-_1848.djvu/130|ici]] et 1829 [https://gallica.bnf.fr/ark:/12148/bpt6k5773334c/f45.item là])</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''IX.''' Le premier ''Romain'' qui exposa publiquement la théorie des éclipses du soleil et de la lune est [[w:Caius_Sulpicius_Gallus|'''Sulpicius Gallus''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Caius_Sulpicius_Gallus_back|<sup>🔄</sup>]], qui fut consul avec [[w:Marcus_Claudius_Marcellus_(consul_en_-166)|'''Marcellus''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Marcellus-166_back|<sup>🔄</sup>]], mais qui alors était tribun militaire. La veille du jour où [[w:Persée_(roi)|'''Persée''']] [[#Persée_(roi)|<span id="Persée_(roi)_back"><sup>'''I'''</sup></span>]] fut défait par [[w:Lucius_Æmilius_Paullus_Macedonicus|'''Paul-Emile''']] [[#Lucius_Æmilius_Paullus_Macedonicus|<span id="Lucius_Æmilius_Paullus_Macedonicus_back"><sup>'''II'''</sup></span>]] il parut par ordre du général, afin de prévenir les alarmes de l’armée, devant les troupes assemblées pour annoncer l’éclipse qui allait survenir; peu de temps après, il composa un livre sur ce sujet. Le premier qui s’en occupa chez les ''Grecs'' fut '''Thalès''' de ''Milet'', dans la quatrième année de la quarante-huitième olympiade (an 585 av. J. C. [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#éclipse_back|<sup>🔄</sup>]]), l’an 170 de la fondation de ''Rome'', et prédit une éclipse de lune qui arriva sous le roi [[w:Alyatte_II|'''Alyatte''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Alyatte_back|<sup>🔄</sup>]]. Après eux, [[w:Hipparque_(astronome)|'''Hipparque''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Hipparque_back|<sup>🔄</sup>]] dressa pour six cents ans la table du cours du soleil et de la lune, déterminant les mois des divers calendriers, les jours, les heures, les localités et les aspects, suivant les contrées. Le cours des ans ne lui a donné aucun démenti, et il semble avoir été admis aux conseils de la nature. Génies puissants et élevés au dessus de l’humanité, ils ont découvert la loi qui régit ces grandes divinités, et ils ont délivré de ses craintes l’esprit misérable des hommes, qui dans les éclipses, tantôt croyaient voir une influence malfaisante ou une espèce de mort des astres, crainte qui, comme on sait, a, pour l’éclipse du soleil, troublé [[w:Stésichore|'''Stésichore''']] [[#Stésichore|<span id="Stésichore_back"><sup>'''III'''</sup></span>]] et [[w:Pindare|'''Pindare''']] [[#Pindare|<span id="Pindare_back"><sup>'''IV'''</sup></span>]], poètes sublimes, et tantôt attribuaient l’obscurcissement de la lune à des maléfices, et lui venaient en aide par un bruit dissonnant. Redoutant ce phénomène, dont il ignorait la cause, [[w:Nicias|'''Nicias''']] [[#Nicias|<span id="Nicias_back"><sup>'''V'''</sup></span>]], général des ''Athéniens'', n’osa pas faire sortir la flotte du port de [[w:Syracuse#Antiquité|''Syracuse'']], et ruina la puissance de sa patrie. Redoublez de génie, interprètes du ciel, vous dont l’intelligence, embrassant la nature, a inventé des théories qui ont créé un lien entre les dieux et les hommes [[#Vicistis_JH|<span id="Vicistis_JH_back"><sup>'''1'''</sup></span>]] ! A la vue de ce spectacle, à la vue des labeurs (puisque c’est le nom qu’on a voulu donner aux éclipses), des labeurs réguliers auxquels les astres sont soumis, quel mortel ne pardonnerait à la nécessité sous laquelle il est né ? Maintenant je vais parler, d’une manière brève et sommaire, des points sur lesquels on est d’accord en cette matière. Je ne donnerai que de courtes explications, et là où il sera tout à fait nécessaire; car les explications n’entrent pas dans le plan de cet ouvrage, et il n’y a pas moins de mérite à énumérer les causes de toutes choses qu’à s’appesantir sur quelques-unes.</div> <table cellspacing=15 align=center style="margin: 0 4em; font-size:85%;"> <tr> <td style="text-align: justify; margin: 0 4em;">'''[[#Vicistis_JH_back|<span id="Vicistis_JH"><sup>1</sup></span>]] Vicistis Vulg. — Vinxistis cod. Dalech. — Vinxistis me parait meilleur. Comp. ce que dit Pline plus loin, ch. 24, sur l’affinité de l’esprit humain avec les astres.'''</td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/b24875958_0001/page/n7/mode/2up <u>Histoire Naturelle de Pline.</u>], [https://archive.org/details/b24875958_0001/page/98/mode/2up ''Livre II.''], [https://archive.org/details/b24875958_0001/page/106/mode/2up ''chap. IX.''], texte corrigé par [[w:Émile_Littré|M. É. Littré]], à partir de celui de [[w:Jean_Hardouin|Hardouin]], Librairie de Firmin-Didot et C<sup>ie</sup>, Paris, 1883<br />(édition 1848 également disponible [[s:Page:Pline_l'ancien_-_Histoire_naturelle,_Littré,_T1_-_1848.djvu/130|ici]])</div> {{Boîte déroulante début|titre=NdA de trad. Jean Hardouin 1883|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Persée_(roi)_back|<span id="Persée_(roi)"><sup>I</sup></span>]] Du nom propre grec ancien Περσεύς / Perseús[[wikt:en:Περσεύς#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px">Dernier roi de [[w:Royaume_de_Mac%C3%A9doine|''Macédoine'']] de la dynastie des [[w:Antigonides|''Antigonides'']], vaincu en [[w:-168|-168]] à la [[w:bataille de Pydna|bataille de ''Pydna'']] à l’issue de la [[w:troisième guerre macédonienne|''troisième guerre macédonienne'']], causant la disparition du ''Royaume de Macédoine''.<br /><p style="text-align: right; margin: 0 2em;">([[w:Années_212_av._J.-C.|-212]]<sup>[[w:IIIe_siècle_av._J.-C.|⏳]]</sup>, [[w:Pella_(cité_antique)|''Pella'']], au nord de l’actuelle ''Grèce'' — [[w:Années_166_av._J.-C.|-166]]<sup>[[w:IIe_siècle_av._J.-C.|⏳]]</sup>, [[w:Alba_Fucens|''Alba Fucens'']], au centre de l’actuelle ''Italie'') <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Lucius_Æmilius_Paullus_Macedonicus_back|<span id="Lucius_Æmilius_Paullus_Macedonicus"><sup>II</sup></span>]] [[w:Nom_romain|Tria Nomina]] en latin {{Info|Lucius|praenomen, nom individuel du citoyen romain}} {{Info|Æmilius|nomen, nom de famille}} {{Info|Paullus|cognomen, surnom héréditaire, servant à distinguer les diverses branches d’une même gens}}, surnommé [[wikt:Macedonicus#Latin|Macedonicus]] par le [[w:Sénat_romain|''Sénat'']] à la suite de sa victoire;<br /><p style="margin: 0 2em; text-indent: 15px">Homme politique ''romain'', consul à 2 reprises en [[w:Années_182_av._J.-C.|-182]] et [[w:Années_169_av._J.-C.|-169]]. Il remporta la victoire contre le ''royaume de Macédoine'' à ''Pydna'' en battant le roi Persée [[#Persée_(roi)|<sup>I</sup>]], ce qui mit fin à la dynastie des ''Antigonides''.<br /><p style="text-align: right; margin: 0 2em;">([[w:Circa|{{Info|''ca.''|Circa, locution latine que l’on emploie pour indiquer l’approximation d’une date}}]] [[w:Années_230_av._J.-C.|-230]]<sup>[[w:IIIe_siècle_av._J.-C.|⏳]]</sup>, ''Rome'' — ''ca.'' [[w:Années_160_av._J.-C.|-160]]<sup>[[w:IIe_siècle_av._J.-C.|⏳]]</sup>, ''Rome'') <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Stésichore_back|<span id="Stésichore"><sup>III</sup></span>]] Du nom propre grec ancien Στησίχορος /Stēsíkhoros [[wikt:en:Στησίχορος#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;">➥ du verbe ἵστημι /hístēmi, « 1. (voix transitive, active des temps présent, imparfait, futur et 1er aoriste) : • Faire se tenir debout, se tenir debout; • Arrêter, rester, vérifier; • Mettre en place : - Faire monter, élever, réveiller, remuer; - Nommer, désigner; - Établir, instituer; • Mettre dans la balance, peser. 2. (voix intransitive, moyenne et passive, voix active du 2e aoriste, parfait et plus-que-parfait) : • Se tenir debout; • Se tenir immobile : (au sens figuré) Rester ferme; • Être dressé ou debout, se lever, s’élever : - (en général) Se lever, commencer; - (en marquant le pas) Être; - Être désigné. »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ +‎ du nom commun χορός / khorós, « 1. Danse en rond. 2. Danse accompagnée de chant, danse chorale. 3. Chœur, chorale, groupe de chanteurs et de danseurs. 4. Groupe, troupe. 5. Rangée. 6. Lieu de danse. 7. (théâtre) Chœur »;<br /><p style="margin: 0 2em; text-indent: 15px">Poète lyrique grec, considéré comme l’un des [[w:Neuf_lyriques_grecs|''neuf poètes lyriques'']] de la Grèce antique.<br /><p style="text-align: right; margin: 0 2em;">([[w:Circa|{{Info|''ca.''|Circa, locution latine que l’on emploie pour indiquer l’approximation d’une date}}]] [[w:Années_630_av._J.-C.|-630]]<sup>[[w:VIIe_siècle_av._J.-C.|⏳]]</sup>, [[w:Metauria|''Metauria'']], colonie de la [[w:Grande-Grèce|''Grande-Grèce'']], au sud de la région de [[w:Calabre|''Calabre'']], au sud de l’Italie — ''ca.'' [[w:Années_555_av._J.-C.|-555]]<sup>[[w:VIe_siècle_av._J.-C.|⏳]]</sup>, [[w:Catane|''Catane'']], colonie de la ''Grande-Grèce'', à l’est de la [[w:Sicile|''Sicile'']]) <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Pindare_back|<span id="Pindare"><sup>IV</sup></span>]] Du nom propre grec ancien Πίνδᾰρος /Píndaros [[wikt:en:Πίνδαρος#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px">Poète lyrique grec, considéré comme l’un des [[w:Neuf_lyriques_grecs|''neuf poètes lyriques'']] de la Grèce antique.<br /><p style="text-align: right; margin: 0 2em;">([[w:Années_518_av._J.-C.|-518]]<sup>[[w:VIe_siècle_av._J.-C.|⏳]]</sup>, [[w:Cynocéphales|''Cynocéphales'']], cité grecque située près de [[w:Thèbes_(Grèce)|''Thèbes'']], en [[w:Béotie|''Béotie'']] — [[w:Années_438_av._J.-C.|-438]]<sup>[[w:Ve_siècle_av._J.-C.|⏳]]</sup>, [[w:Árgos|''Árgos'']], cité grecque de la région de l’[[w:Argolide|''Argolide'']], à l’est de la [[w:Péloponnèse|''péninsule du Péloponnèse'']]) <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Nicias_back|<span id="Nicias"><sup>V</sup></span>]] Du nom propre grec ancien Νῑκίᾱς /Nīkíās [[wikt:en:Νικίας#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;">➥ du nom commun νίκη / níkē [[wikt:en:νίκη#Ancient_Greek|(en)]], « 1. Le fait de gagner : la victoire, le succès [avec le génitif "sur, dans quelque chose"] : • Les choses gagnées dans la victoire, les fruits de la victoire; • La supériorité, l’avantage. »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ + du suffixe nominal masculin -ίας / -ías [[wikt:en:-ίας#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px">Homme politique et général ''athénien'' durant la [[w:Guerre_du_Péloponnèse|''guerre du Péloponnèse'']], qui oppose la [[w:Ligue_de_Délos|''ligue de Délos'']], menée par ''Athènes'', et la [[w:Ligue_du_Péloponnèse|''ligue du Péloponnèse'']], sous l’[[w:Hégémonie|hégémonie]] de ''Sparte'' de [[w:Années_431_av._J.-C.|-431]] à [[w:Années_404_av._J.-C.|-404]]. Sa supersition liée à une éclipse lunaire, s’étant produite lors de l’[[w:Expédition_de_Sicile|''expédition de Sicile'']], est également relatée par [[w:Thucydide|Thucydide]] [http://remacle.org/bloodwolf/historiens/thucydide/livre7.htm#L <sup>{{Info|HdlgdP|Histoire de la guerre du Péloponnèse}} l.VII, §.L</sup>] et [[w:Plutarque|Plutarque]] [[#Plutarque_back|<sup>⤵️</sup>]] [http://remacle.org/bloodwolf/historiens/Plutarque/supestition.htm#23 <sup>{{Info|DlS|De la Superstition}} l.I</sup>].<br /><p style="text-align: right; margin: 0 2em;">([[w:Circa|{{Info|''ca.''|Circa, locution latine que l’on emploie pour indiquer l’approximation d’une date}}]] [[w:Années_470_av._J.-C.|-470]], ''Athènes'' — ''ca.'' [[w:Années_413_av._J.-C.|-413]], ''Syracuse'')<sup>[[w:Ve_siècle_av._J.-C.|⏳]]</sup>'''<br/><br/></div> {{Boîte déroulante fin}} <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: center; margin: 0 2em;">Des découvertes astronomiques : part de chaque observateur dans la science.<br /><p style="text-align: justify; text-indent: 15px;">'''IX.''' '''Sulpicius Gallus''' [[#Sulpicius_Gallus_AdG|<span id="Sulpicius_Gallus_AdG_back"><sup>'''1'''</sup></span>]] fut le premier ''Romain'' qui expliqua au vulgaire la raison des éclipses de soleil et de lune. Il fut consul avec '''Marcus Marcellus''' ; mais il n’était que tribun militaire lorsque la veille de la victoire que '''Paul Emile''' remporta sur '''Persée''' [[#Pridie_quam_Perses_rex_AdG|<span id="Pridie_quam_Perses_rex_AdG_back"><sup>'''2'''</sup></span>]], son général le fit paraître devant l’armée assemblée, pour lui annoncer l’éclipse qui allait arriver, et la délivrer de l’alarme qu’elle aurait pu en concevoir. Il composa bientôt après un volume sur ce sujet. Parmi les ''Grecs'', '''Thalès''' de ''Milet'' [[#Primus_omnium_Thales_AdG|<span id="Primus_omnium_Thales_AdG_back"><sup>'''3'''</sup></span>]] dirigea le premier ses recherches sur ce phénomène, et la quatrième année de la 48e olympiade, qui répond à l’an 170 [[#Anno_CLXX_AdG|<span id="Anno_CLXX_AdG_back"><sup>'''4'''</sup></span>]] de ''Rome'', il prédit l’éclipse de soleil qui eut lieu sous le règne d’'''Alyatte''' [[#Alyatte_rege_AdG|<span id="Alyatte_rege_AdG_back"><sup>'''5'''</sup></span>]]. Après eux, '''Hipparque''' dressa des tables du cours de ces deux astres pour six cents ans [[#In_sexcentos_annos_AdG|<span id="In_sexcentos_annos_AdG_back"><sup>'''6'''</sup></span>]] : mois, heures, jours, situations respectives des lieux, aspects du ciel selon les diverses nations [[#Menses_gentium_etc_AdG|<span id="Menses_gentium_etc_AdG_back"><sup>'''7'''</sup></span>]], tout y est compris, tout a été vérifié par le temps [[#Aevo_teste_AdG|<span id="Aevo_teste_AdG_back"><sup>'''8'''</sup></span>]]; on croirait l’astronome admis au conseil de la nature. Génies vastes et plus qu’humains, d’avoir ainsi surpris la loi de ces deux grandes divinités [[#Numinum_AdG|<span id="Numinum_AdG_back"><sup>'''9'''</sup></span>]], et affranchi d’effroi la malheureuse espèce humaine, qui tremblait en voyant dans chaque éclipse l’annonce de quelque grand crime, ou craignait la mort des astres [[#In_defectibus_scelera_etc_AdG|<span id="In_defectibus_scelera_etc_AdG_back"><sup>'''10'''</sup></span>]] (effroi dont '''Stésichore''' et '''Pindare''' [[#Pindari_AdG|<span id="Pindari_AdG_back"><sup>'''11'''</sup></span>]], ces poètes sublimes, ne furent point exempts dans les éclipses de soleil), ou qui attribuait à des enchantemens celles de la lune, et venait à son secours en faisant un bruit discordant [[#Crepitu_dissono_AdG|<span id="Crepitu_dissono_AdG_back"><sup>'''12'''</sup></span>]]. C’est pour en avoir ignoré la cause, que, frappé de cette même terreur, '''Nicias''' [[#Nicias_AdG|<span id="Nicias_AdG_back"><sup>'''13'''</sup></span>]], général des ''Athéniens'', n’osa pas faire sortir sa flotte du port, et causa la ruine de leur puissance. Gloire à vous, interprètes du ciel, génies aussi étendus que la nature, inventeurs d’une science qui enchaîne à une même destinée les dieux et les mortels ! Quel est donc l’homme qui, voyant les astres en travail (pour me servir du nom qu’il a plu de donner aux crises qu’ils, subissent périodiquement), ne se soumettra pas à sa destinée?<br /><p style="text-align: justify; text-indent: 15px;">Je vais maintenant toucher brièvement et sommairement les points sur lesquels on est d’accord dans cette matière, et j’en rendrai raison en passant, lorsque cela sera tout-à-fait nécessaire; car un développement de preuves n’est pas le but de l’ouvrage que j’ai entrepris, et il n’y a pas, je pense, moins de mérite à pouvoir rendre raison de toutes choses, qu’à s’arrêter à en prouver quelques-unes.</div> {{Boîte déroulante début|titre=Notes du traducteur|alignT=center}} <div style="text-align: justify; border: 2px; border-radius:15px; font-size:85%;"><br/> <table cellspacing=15 align=center style="margin: 0 4em;"> <tr> <td style="text-align: justify; margin: 0 4em; text-indent: 15px">'''[[#Sulpicius_Gallus_AdG_back|<span id="Sulpicius_Gallus_AdG"><sup>1</sup></span>]] [[w:Tite-Live|Tite-Live]], XLIV, 37, [[w:Quintilien|Quintilien]], I, 10, [[w:Plutarque|Plutarque]] [[#Plutarque_back|<sup>⤵️</sup>]], [[w:Vies_parallèles|''Vie de Paul Emile'']], [[w:Frontin|Frontin]], I, etc., prétendent, comme Pline, que Sulpicius Gallus prédit l’éclipse anx soldats romains. [[w:Cicéron|'''Cicéron''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Cicéron_back|<sup>🔄</sup>]] ([[w:De_Republica|''Répub.'']], I, 15 , page 44, ''édit. Maj.'') dit au contraire que l’éclipse était déjà arrivée lorsque Sulpicius Gailus commençait à s’efforcer d’ôter aux soldats romains la terreur qu’ils avaient conçue de cet événement, en leur expliquant les causes des éclipses.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Pridie_quam_Perses_rex_AdG_back|<span id="Pridie_quam_Perses_rex_AdG"><sup>2</sup></span>]] Selon Tite-Live (XLIV, 37), l’éclipse eut lieu dans la soirée du 3 septembre, cent huit ans avant J.-C., entre sept et dix heures (''ab hora secunda usque ad quartam noctis, quam pridie nonas sept, secula est dies''). M. [[w:Christian_Ludwig_Ideler|Ideler]] (''Chronologie'', II, 104) a calculé cette éclipse. Il a trouvé, comme M. de Nauze, que, selon le calendrier Julien, elle arriva dans la soirée du 21 juin de l’an 168 avant J.-C. à Rome, la lune commença à s’éclipser vers 5h.44’ du soir ; depuis 6h.51’ jusqu’à 8h.18’, la lune fut totalement éclipsée, ; à 9h.,24’, la lune ne fut plus obscurcie du tout. En Macédoine, tous ces phénomènes arrivèrent 39 minutes plus tard. Le 21 juin, le soleil se coucha à Rome et en Macédoine vers 7h.33’, et s’y montra alors à 44 1/2’ h. équatoriales. Ainsi, la première heure de la nuit finissait vers 8h.17’, la seconde vers 9h.2’, la troisième vers 9h.46’, la quatrième vers 10h.31’. La lune fut donc éclipsée totalement au moment où elle se leva dans la Macédoine, et cette éclipse totale y finit dans la seconde heure de la nuit ; au milieu de la quatrième, la lune ne fut plus obscurcie du tout. S’il est vrai, que cette éclipse lunaire, comme Pline, Tite-Live et d’autres le disent, fut prédite par Sulpicius Gallus, l’on devrait avouer que ce Romain s’entendait très-bien au calcul des éclipses lunaires. Mais les récits de Cicéron et de [[w:Valère_Maxime|Valère-Maxime]] ne seraient-ils pas plus vrais que ceux de Pline et de Tite-Live ?''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Primus_omnium_Thales_AdG_back|<span id="Primus_omnium_Thales_AdG"><sup>3</sup></span>]] Le même fait est rapporté par [[w:Hérodote|Hérodote]] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Hérodote_back|<sup>🔄</sup>]], I, 74, par [[w:Diogène_Laërce|Diogène Laërce]] [[#Diogène_Laërce_back|<sup>⤵️</sup>]], I, 6 , par [[w:Clément_d'Alexandrie|Clément d’Alexandrie]] [[#Clément_d'Alexandrie_back|<sup>⤵️</sup>]], ''Strom.'', I, page 302 , par Plutarque, ''Opinions des Philosophes'', II, 24, par [[w:Jean_Tzétzès|Tzetzès]], ''Chil.'' II, v. 869, et par Hardouin.<br /><p style="text-align: justify; text-indent: 15px;">Oltmann a publié une dissertation dans laquelle, à l’aide des tables astronomiques les plus modernes, il est arrivé à ce résultat, que l’éclipse solaire dont il est question ici eut lieu le 3o septembre 610 ans avant J.-C. L’éclipse était totale pour les environs de la ville d’[[w:Erzurum|Érzerum]] sur le [[w:Kızılırmak_(fleuve)|Halys]] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Halys_back|<sup>🔄</sup>]], où [[w:Volney|Volney]] place le champ de bataille des rois [[w:Alyatte_II|Halyattes]] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Alyatte_back|<sup>🔄</sup>]] et [[w:Cyaxare|Cyaxare]] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Cyaxare_back|<sup>🔄</sup>]]. La quatre-vingtième partie du disque solaire seule ne fut pas éclipsée pour le lieu de la terre où Oltmann place le champ de bataille, qui est situé, selon lui, sous 36° long. à l’est de Terro et sous 40° lat. sept. Dans le pays des Ioniens où Thalès prédit l’éclipse, selon Hérodote, l’éclipse se monta à 11 1/2’. M. [[w:Alphonse_Des_Vignoles|Desvignolles]] (''Chronologie de l’histoire sainte'', t. II, pag. 245 et suiv.) fixe l’éclipsé prédite par Thales au 38 mai de l’an 585 avant J.-C. ; son opinion a été adoptée depuis par presque tous les chronologistes et historiens, et par [[w:Gabriel_Brotier|Brotier]] et M. Alexandre. Elle a été réfutée avec succès par Oltmann, qui s’est servi de tables astronomiques bien plus exactes que celles de M. Desvignolles ; en effet, celui-ci a démontré par ses calculs que l’éclipse totale du soleil du 28 mai de l’an 585 avant J.-C., ne fut pas totale dans les lieux où les troupes du roi lydien Halyatte combattirent contre celles du roi Cyaxare ; que, dans ces régions, elle ne se monta pas à plus de 7 1/2 pouces, et que, d’ailleurs, le soleil ne s’était pas encore levé lorsque Féclipse était le plus forte pour les habitans des pays nommés. Mais Hérodote dit positivement que l’éclipse prédite par Thalès fut totale dans ces contrées, et qu’elle eut lieu en plein jour. (Voyez IDELER, ''Chronologie'', t. I, pag. 209 et 210.) Nous remarquerons pourtant avant de finir cette note que la date de Desvignolles est plus conforme que celle d’Oltmann à l’année dans laquelle l’éclipse prédite par Thalès, arriva selon Pline. En effet, le naturaliste romain dit que cette année est la six cent quatre-vingt-cinquième avant J.—C., et c’est justement le 28 mai de cette année que l’éclipse prédite par Thalès arriva, selon M. Desvignolles.<br /><p style="text-align: justify; text-indent: 15px;">Volney pense que l’éclipse en question arriva le 3 février de de l’an 626. Oltman a démontré, dans son Mémoire sur l’éclipse de Thalès, que celle de Volney était déjà passée lorsque le soleil se leva sur le champ de bataille des rois Halyattes et Cyaxare.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Anno_CLXX_AdG_back|<span id="Anno_CLXX_AdG"><sup>4</sup></span>]] L’an 170. C’est ainsi que l’on doit lire, et non CLX, comme l’ont fait Hardouin et Poinsinet; la quatrième année de la quarante-huitième olympiade, correspondant à l’an 170 de Rome, si l’on suppose avec [[w:Varron_(écrivain)|Varron]] que cette ville a été fondée dans la deuxième année de la 6e olympiade.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Alyatte_rege_AdG_back|<span id="Alyatte_rege_AdG"><sup>5</sup></span>]] Le nom de ce roi est écrit avec un esprit rude dans Hérodote, ce qui a donné lieu à [[w:Louis_Poinsinet_de_Sivry|Poinsinet]] et à d’autres traducteurs de Pline de substituer le mot Halyatte à celui d’Alyatte.<br /><p style="text-align: justify; text-indent: 15px;">Alyatte ou Halyatte fut roi de la Lydie et père de Crésus. Il faisait la guerre à Cyaxare, roi des Mèdes, lorsque l’éclipse solaire en question interrompit le combat.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#In_sexcentos_annos_AdG_back|<span id="In_sexcentos_annos_AdG"><sup>6</sup></span>]] On lit dans [[w:Georges_le_Syncelle|le Syncelle]] (''Chronolog.'', pag. 17) que les Chaldéens ont connu une période de six cents années solaires. [[w:Flavius_Josèphe|Josèphe]] [[#Flavius_Josèphe_back|<sup>⤵️</sup>]] ([[w:Antiquités_judaïques|''Ant. jud.'']], I, page 17 et 18, édit. Havercamp) dit que Dieu donna une longue vie aux patriarches pour qu’ils pussent cultiver avec succès les sciences astronomiques et géométriques, ce qu’ils n’auraient pu faire s’ils n’avaient pas vécu au moins six cents ans ; car la grande année ne finit pas plus tôt. Ainsi, il est certain qu’avant Hipparque les Chaldéens et d’autres peuples asiatiques ont connu une période de six cents années solaires. Mais [[w:Jean-Dominique_Cassini|Cassini]] ([[w:Jean-Dominique_Cassini#Mémoires_de_l’Académie_royale_des_sciences|''Anciens mém. de l’Acad.'']], t. VIII, pag. 4 et 5) et [[w:Jean_Sylvain_Bailly|Bailly]] (''Hist. de l’astr. ancienne'', t. II, liv. 3, Eclairciss.) ont prouvé que tous les six cents ans les nouvelles et pleines lunes n’arrivent pas seulement au même jour et à la même heure qu’auparavant, mais encore à la même minute. Ne serait-il donc pas probable qu’Hipparque, comme le dit Ideler (''Historische untersuchungen uber die astronomischen beobachtungen der alten'', Berlin 1806, page 417) a connu cette période chaldéenne, et que delà résulte l’étendue de six cents ans donnée à son calendrier selon Pline.<br /><p style="text-align: justify; text-indent: 15px;">[[w:Abel_Burja|Abel-Burja]] de Leipzig a tâché d’expliquer d’une autre manière la durée du calendrier d’Hipparque (''Astronomisches Jahrbuch'', 1797, pag. 233 et 234). [[w:Claude_Ptolémée|Ptolémée]] et [[w:Censorin_(grammairien)|Censorin]] racontent qu’Hipparque est auteur d’une période soli-lunaire de trois cent quatre années solaires. En la prenant deux fois, on obtient une période de six cent huit ans. Celle-ci fut abrégée par Hipparque de huit ans, afin d’obtenir un nombre entier de siècles pour son calendrier. Ideler a fait une objection très-juste contre cette opinion de Burja ; c’est que la période de six cent huit ans n’a aucun avantage sur celle de trois cent quatre ans. On ne voit donc pas ce qui a pu engager Hipparque à préférer le nombre de six cents ans à celui de trois cents, lorsqu’il composait son calendrier.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Menses_gentium_etc_AdG_back|<span id="Menses_gentium_etc_AdG"><sup>7</sup></span>]] C’est-à-dire il écrivit des éphémérides dans lesquelles il avait calculé d’avance les néomenies et les pleines lunes. Il fit aussi entrer dans son calendrier les longueurs des jours et des heures variables, [[w:ὧραι|ὧραι]] καιρικαι, ainsi que les aspects du ciel, ''visus populorum'', tels qu’ils eurent lieu chez les habitans de différentes contrées de la terre. Il ajouta une table des longitudes et des latitudes des principaux pays et villes du globe. Ptolémée (''Géogr.'', I, ch. 4) en dit autant d’Hipparque.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Aevo_teste_AdG_back|<span id="Aevo_teste_AdG"><sup>8</sup></span>]] Les tables d’Hipparque étaient dressées pour six cents ans. Cet astronome florissait vers cent cinquante ans avant J.-C. Ainsi, du temps de Pline, on avait encore à jouir de ces tables pour quatre cents ans environ. POINSINET.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Numinum_AdG_back|<span id="Numinum_AdG"><sup>9</sup></span>]] Pline donne souvent l’épithète de divinités aux planètes, à la lune, au soleil, à la terre et aux étoiles fixes.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#In_defectibus_scelera_etc_AdG_back|<span id="In_defectibus_scelera_etc_AdG"><sup>10</sup></span>]] Nous transcrivons ici ce beau passage de l’Uranographie de M. [[w:Louis-Benjamin_Francœur|Francoeur]], qui mérite d’être mis en parallèle avec celui de Pline pour l’élégance du style et les pensées, et qui renferme le meilleur commentaire que nous puissions donner de tout ce que Pline dit des terreurs que les éclipses causaient autrefois aux hommes ignorans. « L’histoire, dit M. Francoeur (page 93), est pleine des exemples de l’effroi causé par les éclipses, et des dangers que produisent l’ignorance et la superstition. Nicias avait résolu de quitter la Sicile avec son armée ; effrayé par une éclipse de lune, et voulant temporiser plusieurs jours pour s’assurer si l’astre n’avait rien perdu après cet évènenement, il manqua ainsi l’occasion de sa retraite; son armée fut détruite ; Nicias périt, et ce malheur commença la ruine d’Athènes.<br /><p style="text-align: justify; text-indent: 15px;">« Souvent on a vu des hommes adroits tirer parti de la frayeur du peuple pour l’amener à remplir leurs desseins. Christophe Colomb, réduit à faire subsister ses soldats des dons volontaires d’une nation sauvage et indigente, était prêt à voir tarir cette ressource et à périr de faim ; il annonce qu’il va priver le monde de la lumière de la lune. L’éclipse commence et la terreur s’empare des Indiens, qui reviennent apporter aux pieds de Colomb les tributs accoutumés.<br /><p style="text-align: justify; text-indent: 15px;">« Drusus (TACITE , Annales, I, 28) apaisa une sédition dans son armée, en prédisant une éclipse de lune, et, selon Tite-Live, Sulpicius Gallus, dans la guerre de Paul-Emile contre Persée, usa du même stratagème. Periclès, [[w:Agathocle_de_Syracuse|Agathocles de Syracuse]], [[w:Dion_de_Syracuse|Dion]], roi de Sicile, ont failli être victimes de l’ignorance de leurs soldats. [[w:Alexandre_le_Grand|Alexandre]], près d’[[w:Bataille_de_Gaugamèles|Arbelles]], est réduit à user de toute son adresse pour calmer la terreur qu’une éclipse avait jetée parmi ses troupes. Les hommes supérieurs, plutôt que de plier sous les circonstances qui les maîtrisent, mettent leur art à les tourner à leur profit.<br /><p style="text-align: justify; text-indent: 15px;">« Combien de fables établies d’après l’opinion que les éclipses sont l’effet du courroux céleste qui se venge des iniquités de l’homme en le privant de la lumière! Tantôt [[w:Diane_(mythologie)|Diane]] va trouver [[w:Endymion|Endymion]] dans les montagnes de Carie; tantôt les magiciennes de Thessalie font descendre la lune sur les herbes qu’elles destinent aux enchantemens. »<br /><br /><p style="text-align: center;">''Carmina vel cælo possunt deducere lunam.''<br /><p style="text-align: right; text-indent: 15px;">Virg., ''Eclog.'' VIII.<br /><br /><p style="text-align: justify; text-indent: 15px;">« Ici c’est un dragon qui dévore l’astre, et qu’on cherche à épouvanter par des cris ; le dieu tient le soleil enfermé dans un tuyau, et nous ôte ou nous rend la vue de cet astre à l’aide d’un volet, etc. Les progrès des sciences ont fait connaître le ridicule de ces opinions et de ces craintes, depuis qu’on a vu qu’il était possible de calculer par les tables astronomiques, et de prévoir long-temps d’avance l’instant où la colère du ciel devait éclater.<br /><p style="text-align: justify; text-indent: 15px;">« Cependant, naguère encore, l’épouvante a causé les revers des armées de Louis XIV, près de Barcelone, lors de l’éclipse totale de l’an 1706 [[w:en:Solar_eclipse_of_May_12,_1706|(en)]], et la devise, ''nec pluribus impar'', a prêté aux allusions injurieuses ! »''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Pindari_AdG_back|<span id="Pindari_AdG"><sup>11</sup></span>]] Pindare était le plus fameux poète de la Grèce après Homère. Il vint au monde l’an 134 avant l’ère chrétienne. POINSINET.<br /><p style="text-align: justify; text-indent: 15px;">Plutarque (''De la face de la lune'', pag. 931) dit aussi que Stésichore et Pindare craignaient beaucoup les éclipses. Le dernier poète a peint les terreurs que lui causaient ces phénomènes dans son poëme sur le soleil. HARDOUIN et DALECHAMP.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Crepitu_dissono_AdG_back|<span id="Crepitu_dissono_AdG"><sup>12</sup></span>]] Cet usage superstitieux dont Plutarque parle au long dans sa vie de Paul-Émile, a fourni un vers fort plaisant à Juvénal, lorsqu’après avoir épuisé toute sorte d’exagération pour représenter le bruit qu’une femme fait en criant, il finit par dire :<br /><br /><p style="text-align: center;">''Una laboranti poterit succurrere lunæ.''<br /><br /><p style="text-align: justify; text-indent: 15px;">« Elle seule, au besoin, décharmerait la lune. » POINSINET.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Nicias_AdG_back|<span id="Nicias_AdG"><sup>13</sup></span>]] Le même fait est raconté par Plutarque dans la vie de Nicias, par Quintilien, I, 10, et par d’autres écrivains anciens. HARDOUIN.''' </td> </tr> </table><br/><br/></div>{{Boîte déroulante fin}} <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k5773334c/f10.item <u>Histoire Naturelle de Pline. Tome Second</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k5773334c/f14.item ''Livre II.''], [https://gallica.bnf.fr/ark:/12148/bpt6k5773334c/f46.item ''chap. IX.''], traduction nouvelle par M. [[w:Stéphane_Ajasson_de_Grandsagne|Ajasson de Grandsagne]] [https://gallica.bnf.fr/ark:/12148/bpt6k5773334c/f311.item <sup>NOTES</sup>], C. L. F. Panckoucke, Paris, 1829</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: center; margin: 0 2em;">''Des inventions a[[w:S_long|{{Info|ſ|forme ancienne longue de la lettre s minuscule}}]]<nowiki />tronomiques, & de leurs Auteurs.''<br /><p style="text-align: justify; text-indent: 15px;">'''L'''E PREMIER d’entre les ''Romains'' qui rendit publique la théorie des éclip{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oleil & de lune, fut '''Sulpicius Gallus''' [[#Sulpicius_Gallus_LPdS|<span id="Sulpicius_Gallus_LPdS_back"><sup>'''1'''</sup></span>]], celui que '''Marcus Marcellus''' eut pour Collegue au Con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ulat : mais il n’étoit que Tribun Militaire [[#Tribun_Militaire_LPdS|<span id="Tribun_Militaire_LPdS_back"><sup>'''2'''</sup></span>]], lor{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’il di{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ipa l’allarme qu’auroient pu prendre nos troupes la veille de la victoire remportée {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur '''Per{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ée''' par '''Paul Emile''' ; car ce Général l’ayant produit devant les {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oldats a{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}emblés, il leur prédit une éclip{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e qui devoit arriver [[#éclipse_LPdS|<span id="éclipse_LPdS_back"><sup>'''3'''</sup></span>]] ; il compo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}a même en{{Info|ſ|forme ancienne longue de la lettre s minuscule}}uite un Ouvrage {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur ce {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ujet. Parmi les ''Grecs'', '''Thalès''' de ''Milet'' prédit l’an quatrieme de la quarante-huitieme olympiade l’éclip{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oleil qui arriva {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous le regne de '''Halyattes''' [[#Halyattes_LPdS|<span id="Halyattes_LPdS_back"><sup>'''4'''</sup></span>]], l’an cent {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oixante de la fondation de [[#cent_soixante_LPdS|<span id="cent_soixante_LPdS_back"><sup>'''5'''</sup></span>]] ''Rome''. Après eux, Hipparque [[#Hipparque_LPdS|<span id="Hipparque_LPdS_back"><sup>'''6'''</sup></span>]] dre{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}a des Tables en vers [[#En_vers_LPdS|<span id="En_vers_LPdS_back"><sup>'''7'''</sup></span>]] du cours de ces deux aftres pour fix cents ans. Dans ces Tables , de l’exactitude deſquelles notre âge rend encore témoignage [[#témoignage_LPdS|<span id="témoignage_LPdS_back"><sup>'''8'''</sup></span>]], il embra{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}e les éphémérides propres à chaque nation [[#chaque_nation_LPdS|<span id="chaque_nation_LPdS_back"><sup>'''9'''</sup></span>]], les jours, les heures, le {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ite re{{Info|ſ|forme ancienne longue de la lettre s minuscule}}pectif de chaque lieu, & les divers a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}pects du ciel relativement aux divers peuples, comme {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i la Nature l’eût admis à {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}eil intime. Per{{Info|ſ|forme ancienne longue de la lettre s minuscule}}onnages vraiment grands! génies plus qu’humains, d’avoir ain{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i {{Info|ſ|forme ancienne longue de la lettre s minuscule}}urpris les loix qui font mouvoir ces va{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tes pui{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ances du ciel ; & d’avoir guéri de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}es allarmes l’imagination malade des hommes, qui ju{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’alors, ou avoient toujours vu dans les éclip{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es l’annonce effrayante de quelque grand crime & de quelque mort (terreur dont Sté{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ikhore [[#Stésikhore_LPdS|<span id="Stésikhore_LPdS_back"><sup>'''10'''</sup></span>]] & Pindare [[#Pindare_LPdS|<span id="Pindare_LPdS_back"><sup>'''11'''</sup></span>]], ces Poètes {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ublimes, ne furent point exempts à l’égard des éclip{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es {{Info|ſ|forme ancienne longue de la lettre s minuscule}}olaires), ou attribuoient les ténebres dont {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e couvre la lune à des maléfices opérés par le mêlange de certaines herbes magiques ; & croyoient devoir la {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ecourir par un bruit di{{Info|ſ|forme ancienne longue de la lettre s minuscule}}cordant [[#bruit_discordant_LPdS|<span id="bruit_discordant_LPdS_back"><sup>'''12'''</sup></span>]]. Cette même terreur fut cau{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e que le Général Nicias [[#Nicias_LPdS|<span id="Nicias_LPdS_back"><sup>'''13'''</sup></span>]], peu au fait des cau{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es phy{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iques, & n’o{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ant pas, par {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uper{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tition, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ortir {{Info|ſ|forme ancienne longue de la lettre s minuscule}}a flotte du Port, mit Athenes à deux doigts de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}a perte. Honneur [[#Honneur_LPdS|<span id="Honneur_LPdS_back"><sup>'''14'''</sup></span>]] à vous, Interpretes du Ciel ! E{{Info|ſ|forme ancienne longue de la lettre s minuscule}}prits [[#Esprits_LPdS|<span id="Esprits_LPdS_back"><sup>'''15'''</sup></span>]] dont l’étendue {{Info|ſ|forme ancienne longue de la lettre s minuscule}}urpa{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}e celle de la Nature ; Inventeurs d’une méthode qui a{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ujettit les dieux comme les hommes, à une même de{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tinée ! Eh! qui pourroit, en voyant les a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tres même ''en cri{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e'' (pour me {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ervir de l’expre{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ion commune), ne pas {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oumettre à la néce{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ité où {{Info|ſ|forme ancienne longue de la lettre s minuscule}}a condition mortelle l’enchaîne.<br /><p style="text-align: justify; text-indent: 15px;">Pré{{Info|ſ|forme ancienne longue de la lettre s minuscule}}entement je vais toucher par articles fort courts & fort précis les points {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur le{{Info|ſ|forme ancienne longue de la lettre s minuscule}}quels on s’accorde le plus. Je ré{{Info|ſ|forme ancienne longue de la lettre s minuscule}}oudrai, chemin fai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ant, quelques que{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tions, lor{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que le cas l’exigera, mais toujours d’une maniere très {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ommaire ; car une analy{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e en forme d’arguments {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uivis excéderoit le but de cet Ouvrage : & puis, je pen{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e qu’il n’y a pas moins de mérite à rendre une rai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}on plau{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ible de toutes cho{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es, qu’à rendre une rai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}on bien {{Info|ſ|forme ancienne longue de la lettre s minuscule}}olide de deux ou trois cho{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eulement.</div> {{Boîte déroulante début|titre=Notes du traducteur|alignT=center}} <div style="text-align: justify; border: 2px; border-radius:15px; font-size:85%;"><br/> <table cellspacing=15 align=center style="margin: 0 4em;"> <tr> <td style="text-align: justify; margin: 0 4em; text-indent: 15px">'''[[#Sulpicius_Gallus_LPdS_back|<span id="Sulpicius_Gallus_LPdS"><sup>1</sup></span>]] Son premier prénom étoit Caïus. Voyez à {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ujet Tite-Live, l. 44. Valere maxime, l. 8. Quintilien, l. I. ch. 10. Plutarque, vie de Paul-Emile, &c.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Tribun_Militaire_LPdS_back|<span id="Tribun_Militaire_LPdS"><sup>2</sup></span>]] Ce grade répond à celui de Major-général des Troupes.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#éclipse_LPdS_back|<span id="éclipse_LPdS"><sup>3</sup></span>]] Cette éclip{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}elon Tite-Live, fut annoncée aux {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oldats pour la nuit {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uivante. Sulpicius Gallus leur prédit que la lune s’éclip{{Info|ſ|forme ancienne longue de la lettre s minuscule}}eroit entre la {{Info|ſ|forme ancienne longue de la lettre s minuscule}}econde heure de la nuit & la quatrieme. Plutarque ajoute qu’on étoit alors à l’i{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ue de l’été (''{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ub exitum a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tatis''). [[w:Paulin_II_d'Aquilée|Paul d’Aquilée]] écrit que cette éclip{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e arriva aux nones de Septembre (''nonas Septembris''), c’est-à-dire au 4 Septembre : c’étoit l’an 168 avant J.C. {{Info|ſ|forme ancienne longue de la lettre s minuscule}}elon le calcul d’[[w:James_Ussher|U{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}erius]].''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Halyattes_LPdS_back|<span id="Halyattes_LPdS"><sup>4</sup></span>]] Il paroît que Ciceron & Eu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ebe {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e trompent lor{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’ils placent cet événement {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous ''A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tiages'' : [[w:Hermolaos_(Macédoine)|Hermolaüs]] s’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t trompé d’après eux, en {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ub{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tituant ''A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tiages'' à ''Halyattes'' dans le texte de Pline, contre la foi des manu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}crits, & contre le témoignage d’Herodote qui place cet événement dans une guerre entre Halyattes, Roi de Sardes, & Cyaxare, Roi des Medes, pere d’A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tiages.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#cent_soixante_LPdS_back|<span id="cent_soixante_LPdS"><sup>5</sup></span>]] Les deux manu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}crits royaux portent ''anno CLX'' : c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t la leçon qu’il faut {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uivre. En effet, Rome, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}elon Varron, fut fondée l’an 2 de la {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ixieme olympiade, c’est-à-dire, dans l’année olympiadique 22. Mais comme chaque olympiade, depuis leur premiere in{{Info|ſ|forme ancienne longue de la lettre s minuscule}}titution, commençoit après le {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ol{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tice d’été, & comme l’année Romaine avoit toujours commencé au plus tard en Mars {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous Romulus, & depuis en Janvier {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous Numa, il s’en{{Info|ſ|forme ancienne longue de la lettre s minuscule}}uit que la premiere année de Rome, qui répondoit à l’année olympiadique 22, répondoit en même-tems, de quatre mois au moins, à l’année olympíadique 23. Selon ce calcul, la quatrieme année de la quarante-huitieme olympiade, répond en partie à l’an 160, & en partie à l’an 161 de la fondation de Rome, pui{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que 48 olympiades font cent quatre-vingt-douze années, de{{Info|ſ|forme ancienne longue de la lettre s minuscule}}quelles {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i vous ôtez 22 ans écoulés, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}elon Varron, entre la premiere olympiade & la fondation de Rome, il re{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tera 160 ans, & 161 ans {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i l’on a égard à l’enjambement réciproque des années olympiadiques {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur les années Romaines, & des années Romaines {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur les années olympiadiques. Il e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t donc évident que le calcul de Pline (''anno CLX'') e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t ju{{Info|ſ|forme ancienne longue de la lettre s minuscule}}te, en admettant l’hypothe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e chronologique de Varron, à laquelle on voit bien que notre Auteur s’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t conformé en cette occa{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ion particuliere encore qu’en plu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ieurs autres rencontres il paroi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}e affecter de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uivre le {{Info|ſ|forme ancienne longue de la lettre s minuscule}}y{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tême de Caton : vici{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}itude pardonnable dans un ouvrage de compilation où Pline a dû, comme malgré lui, adopter tantôt le {{Info|ſ|forme ancienne longue de la lettre s minuscule}}tyle d’un Auteur, tantôt celui d’un autre, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}elon la {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ource où il pui{{Info|ſ|forme ancienne longue de la lettre s minuscule}}oit pour l’heure. Si Pline eût {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uivi l’hypothe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e de Caton qui place la fondation de Rome deux ans plus tard que Varron, il eût fait tomber le rapport {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur l’année 157 ou 158 de la fondation de Rome. C’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t le parti que prend le Pere Hardouin, & c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t de là qu’il part pour propo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}er une correction dans le texte. Mais encore une fois, c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t commettre {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oi-même une faute que d’en trouver une chez Pline en cette occa{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ion ; pui{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que cet Auteur a été en droit de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ervir du {{Info|ſ|forme ancienne longue de la lettre s minuscule}}y{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tème Varronien, ou ce qui revient au même, de con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}erver la date Varronienne dont s’étoit {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ervi l’Auteur de qui il emprunte le fait hi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}torique en que{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tion.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Hipparque_LPdS_back|<span id="Hipparque_LPdS"><sup>6</sup></span>]] Voyez les notes {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur le premier livre au mot ''Hipparque'' : HIPPARCHUS (de Nicée, en Bithinie comme l’ob{{Info|ſ|forme ancienne longue de la lettre s minuscule}}erve [[w:Souda|Suidas]]), flori{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}oit dans la quatre-vingt-quatorzieme olympiade. Nous avons {{Info|ſ|forme ancienne longue de la lettre s minuscule}}es trois livres d’Enarrations {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur les Phénomenes d’[[w:Aratos_de_Soles|Aratus]] & d’[[w:Eudoxe_de_Cnide|Eudoxe]], traduits par le [[w:Paul_Petau|P. Petau]]. Il avoit compo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}é un autre livre ''De {{Info|ſ|forme ancienne longue de la lettre s minuscule}}tellarum inerrantium Con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}titutione'', {{Info|ſ|forme ancienne longue de la lettre s minuscule}}elon Suidas. Son livre du mois lunaire e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t cité par [[w:Claude_Galien|Galien]].''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#En_vers_LPdS_back|<span id="En_vers_LPdS"><sup>7</sup></span>]] ''En Vers.'' Je préfume que c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t-là le {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ens de ''præcinere'', qui ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ignifie pas {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eulement prédire, mais prédire en chant, c’est-à-dire en Vers. Sur ce pied-là, ce {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eroit d’un Poëme dans le genre de celui d’[[w:Aratos_de_Soles|Aratus]], dont il {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eroit ici que{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tion. Si par hazard Pline n’a point prétendu parler d’un Poëme, au-moins s’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t-il {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ervi d’une expre{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ion propre à dé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}igner ce genre d’écrire. Pour décider la que{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tion, il faudroit avoir tous les ouvrages d’Hipparque, & {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur-tout celui-ci.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#témoignage_LPdS_back|<span id="témoignage_LPdS"><sup>8</sup></span>]] Ces tables étoient dre{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ées pour {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ix cents ans. Or Hipparque flori{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}oit 150 ans avant J.C. Ain{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i du tems de Pline, on avoit encore à jouir de ces tables pour quatre cents ans ou environ.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#chaque_nation_LPdS_back|<span id="chaque_nation_LPdS"><sup>9</sup></span>]] La lune ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e levant pas & ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e couchant pas à la même heure pour toutes les nations, les diver{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es époques & pha{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es qu’elle forme n’appartiennent pas non plus au même point de tems pour tous les peuples, pui{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que les uns ont la nuit quand les autres ont le jour; & que même lor{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que la lune s’éclip{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e, la partie de l’heure où ce phénomene e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t {{Info|ſ|forme ancienne longue de la lettre s minuscule}}en{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ible, n’a pas la même évaluation pour tous les climats qui l’apperçoivent. Hipparque avoit donc eu égard à cette différence d’époques, relativement aux diver{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es longitudes, &par-con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}équent aux diver{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es nations, tellement que les tables de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}es éphémérides étoient accommodées à l’u{{Info|ſ|forme ancienne longue de la lettre s minuscule}}age de tous les peuples : ouvrage dont on ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}auroit trop regretter la perte, & qui jetteroit le plus grand jour {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur l’ancienne géographie.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Stésikhore_LPdS_back|<span id="Stésikhore_LPdS"><sup>10</sup></span>]] Ste{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ikhore, l’un des plus fameux Poètes de la Grece, dont, par malheur, nous avons perdu tous les ouvrages, à l’exception d’une vingtaine de lignes décou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ues. Il vivoit dans la quarante-deuxieme olympiade, c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t-à-dire, vers l’an {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ix cents dix avant J.C.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Pindare_LPdS_back|<span id="Pindare_LPdS"><sup>11</sup></span>]] Pindare, le plus fameux Poète de la Grece après Homere. Il vint au monde l’an 134 avant l’ere chrétienne.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#bruit_discordant_LPdS_back|<span id="bruit_discordant_LPdS"><sup>12</sup></span>]] Cet u{{Info|ſ|forme ancienne longue de la lettre s minuscule}}age {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uper{{Info|ſ|forme ancienne longue de la lettre s minuscule}}titieux a fourni un Vers fort plai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ant à Juvenal, lor{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’après avoir épui{{Info|ſ|forme ancienne longue de la lettre s minuscule}}é toute {{Info|ſ|forme ancienne longue de la lettre s minuscule}}orte d’exagération pour repré{{Info|ſ|forme ancienne longue de la lettre s minuscule}}enter le bruit qu’une femme fait en criant, il finit par dire :<br /><p style="text-align: justify; text-indent: 15px;">''Una laboranti poterit {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uccurrere luna.''<br /><p style="text-align: justify; text-indent: 15px;">Elle {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eule au be{{Info|ſ|forme ancienne longue de la lettre s minuscule}}oin décharmeroit la lune.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Nicias_LPdS_back|<span id="Nicias_LPdS"><sup>13</sup></span>]] C’étoit un Général Athénien, qui fut malheureux dans pre{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que toutes {{Info|ſ|forme ancienne longue de la lettre s minuscule}}es expéditions. Les Athéniens finirent par le condamner à mort. Il étoit contemporain d’[[w:Alcibiade|Alcibiade]] & de [[w:Lamachos|Lamachus]], & leur collegue dans le commandement. Voyez {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur le fait dont parle ici Pline, Quintilien, l. I. ch. 10, & Plutarque à l’article Nicias.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Honneur_LPdS_back|<span id="Honneur_LPdS"><sup>14</sup></span>]] Au lieu de ''macte ingenio'', le Pere Hardouin lit ''macti'' ; mais {{Info|ſ|forme ancienne longue de la lettre s minuscule}}elon les meilleurs Latini{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tes ''macte'' e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t indéclinable, ou pour mieux dire, c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t un adverbe qui répond au ''bravò'' des Italiens. Fe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tus prétend que ''macte'' e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t un compo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}é de ''magis auctus''.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Esprits_LPdS_back|<span id="Esprits_LPdS"><sup>15</sup></span>]] Cette apo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}trophe de Pline aux A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tronomes rappelle ces beaux Vers d'Ovide {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur le même {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ujet :<br />Felices animos quibus hæc cogno{{Info|ſ|forme ancienne longue de la lettre s minuscule}}cere primise<br /><p style="text-align: justify; text-indent: 15px;">Inque Domos {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uperas {{Info|ſ|forme ancienne longue de la lettre s minuscule}}candere cura fuit!<br />Credibile e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t illos pariter vitli{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que joci{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que<br /><p style="text-align: justify; text-indent: 15px;">Altius humanis ex{{Info|ſ|forme ancienne longue de la lettre s minuscule}}eruifle caput,<br />Non Venus aut Vinum {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ublimia pectora fregit<br /><p style="text-align: justify; text-indent: 15px;">Officiumve {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ori, militiæve labor :<br />Nec levis ambitio, perfu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}aque gloria fuco,<br /><p style="text-align: justify; text-indent: 15px;">Magnarumve fames {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ollicitavit opum.<br />Admovere oculis di{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tantia {{Info|ſ|forme ancienne longue de la lettre s minuscule}}idera no{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tris,<br /><p style="text-align: justify; text-indent: 15px;">Ætheraque ingenio {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uppo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}uere {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uo.<br />Sic petitur cœlum: non ut ferat O{{Info|ſ|forme ancienne longue de la lettre s minuscule}}lan Olympus<br /><p style="text-align: justify; text-indent: 15px;">Summaque Peliacus {{Info|ſ|forme ancienne longue de la lettre s minuscule}}idera tangat apex, &c.<br /><p style="text-align: right; text-indent: 15px;">Ovid. {{Info|ſ|forme ancienne longue de la lettre s minuscule}}a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t. l. I.''' </td> </tr> </table><br/><br/></div> {{Boîte déroulante fin}} <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=UnhluychtF8C&newbks=1&newbks_redir=0&dq=Histoire%20naturelle%20Pline&hl=fr&pg=PP7#v=onepage&q&f=true <u>Histoire Naturelle de Pline. Tome Premier</u>], [https://books.google.fr/books?id=UnhluychtF8C&newbks=1&newbks_redir=0&dq=Histoire%20naturelle%20Pline&hl=fr&pg=RA1-PA3#v=onepage&q&f=true ''Livre Second.''], [https://books.google.fr/books?id=UnhluychtF8C&newbks=1&newbks_redir=0&dq=Histoire%20naturelle%20Pline&hl=fr&pg=RA1-PA59#v=onepage&q&f=true ''Des inventions astronomiques, & de leurs Auteurs.''], traduction en françois, avec le texte latin rétabli d’après les meilleures leçons manu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}crites ; accompagnée de Notes critiques pour l’éclairci{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ement du texte, & d’Ob{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ervations {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur les connoi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ances des Anciens comparées avec les découvertes des Modernes, par M. [[w:Louis_Poinsinet_de_Sivry|Louis Poinsinet de Sivry]], Chez la veuve Desaint, Paris, 1771</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div> </div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ==== Livre XVIII ==== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Enquête sur l’agriculture</div> ===== <div style="text-align: center;">Chapitre LVII.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage d’une théorie astronomique de '''Thalès''', du [[w:Lever_héliaque|''coucher matinal'']] des [[w:Pléiades_(astronomie)|''Pléiades'']] 25 jours après l’[[w:Équinoxe_de_septembre|''équinoxe d’automne'']].</div> :'''Texte latin''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''LVII.''' Primum omnium dierum ipsorum anni solisque motus prope inexplicabilis ratio est. Ad CCCLXV adjiciunt etiamnum intercalarios diei noctisque quadrantes. Ita fit, ut tradi non possint certa siderum tempora. Accedit confessa rerum obscuritas, nunc præcurrenle, nec paucis diebus, tempestatum significatu, quod προϰειμασιν Græci vocant : nunc postveniente, quod ἐπιϰεἰμασιν : et plerumque alias citius, alias tardius cæli effectu ad terram deciduo : vulgo serenitate reddita, confectum sidus audimus. Præterea quum omnia hæc statis sideribus cæloque affixis constent, interveniunt motu stellarum grandines, imbres, et ipsi non levi effectu, ut docuimus, turbantque conceptæ spei ordinem. ldque ne nobis tantum putemus accidere, et reliqua fallit animalia sagaciora circa hoc, ut quo vita eorum constet : æstivasque alites præposteri aut præproperi rigores necant, hibernas æstus. Ideo '''Virgilius''' errantium quoque siderum rationem ediscendam præcipit, admonens observandum frigidæ Saturni stellæ transitum. Sunt qui certissimum veris indicium arbitrentur ob infirmitatem animalis, papilionis proventum. Id eo ipso anno, quum commentaremur hæc, notatum est, proventum eorum ter repetito frigore exstinctum, advenasque volucres a. d. VI kalendas februarii spem veris attulisse, mox sævissima hieme conflictatas. Res anceps : primum omnium a cælo peti legem : deinde eam argumentis esse quærendam. Super omnia est mundi convexitas, terrarumque globi differentia, eodem sidere alio tempore aliis aperiente se gentibus : quo fit ut causa ejus non lisdem diebus ubique valeat. Addidere difficultatem et auclores diversis in locis observando, mox etiam in iisdem diversa prodendo. Très autem fuere sectæ : ''Chaldæa'', ''Ægyptia'', ''Græca''. His addidit apud nos quartam Cæsar dictator, annos ad solis cursum redigens singulos, '''Sosigene''' perito scientiæ ejus adhibito. Et ea ipsa ratio postea comperto errore correcta est : ita ut XII annis continuis non intercalaretur, quia cœperat sidera annus morari, qui prius antecedebat. Et '''Sosigenes''' ipse trinis commentationibus, quanquam diligentior cæteris, non cessavit tamen addubitare, ipse semet corrigendo. Auctores prodidere ea, quos prætexuimus volumini huic, raro ullius sententia cum alio congruente. Minus hoc in reliquis mirum, quos diversi excusaverint tractus. Eorum qui in eadem regione dissedere, unam discordiam ponemus exempli gratia : occasum matutinum Vergiliarum '''Hesiodus''' (nam hujus quoque nomine exstat Astrologia) tradidit fieri, quum æquinoctium autumni conficeretur, '''Thales''' vigesimo quinto die ab æquinoctio, '''Anaximander''' vigesimo nono, '''Euctemon''' XLVIII. Nos sequemur observationem Cæsaris : maximeque hæc erit ''Italiæ'' ratio. Dicemus tamen et aliorum placita : quoniam non unius terræ, sed totius naturæ interpretes sumus, non auctoribus positis (id enim verbosum est), sed regionibus : legentes tantum meminerint, brevitatis gratia, quum ''Altica'' nominata fuerit, simul intelligere ''Cycladas'' insulas ; quum ''Macedonia'', ''Magnesiam'', ''Thraciam'' ; quum ''Ægyptus'', ''Phœnicen'', ''Cyprum'', ''Ciliciam'' ; quum ''Bœotia'', ''Locridem'', ''Phocidem'', et finitimos semper tractus ; quum ''Hellespontus'', ''Cherronesum'', et continentia usque ''Atho'' montem ; quum ''Ionia'', ''Asiam'', et insulas ''Asiæ'' ; quum ''Peloponnesus'', ''Achaiam'', et ad ''Hesperum'' jacentes terras. ''Chaldæi Assyriam'' et ''Babyloniam'' demonstrabunt. ''Africam'', ''Hispanias'', ''Gallias'' sileri non erit mirum. Nemo enim observavit in iis, qui siderum proderet exortus. Non tamen difficili ratione dignoscentur in illis quoque terris digestione circulorum, quam in sexto volumine fecimus : qua cognatio cæli, non gentium modo, verum urbium quoque singularum intelligitur, nota ex his terris, quas nominavimus, sumta convexitate circuli, pertinentis ad quas quisque quæret terras, et ad earum siderum exortus, per omnium circulorum pares umbras. Indicandum et illud, tempestates ipsas ardores suos habere quadrinis annis : et easdem non magna differentia reverti ratione solis : octonis vero augeri easdem, centesima revolvente se luna.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/b24875958_0001/page/n7/mode/2up <u>Histoire Naturelle de Pline.</u>], [https://archive.org/details/b24875958_0001/page/652/mode/2up ''Livre XVIII.''], [https://archive.org/details/b24875958_0001/page/684/mode/2up ''Chap. LVII.''], texte corrigé par [[w:Émile_Littré|M. É. Littré]], à partir de celui de [[w:Jean_Hardouin|Hardouin]], Librairie de Firmin-Didot et C<sup>ie</sup>, Paris, 1883<br />(également disponible une édition de 1831 [https://gallica.bnf.fr/ark:/12148/bpt6k5804072n/f339.item ici] et de 1848 [[s:Page:Pline_l'ancien_-_Histoire_naturelle,_Littré,_T1_-_1848.djvu/708|là]])</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''LVII.''' Avant tout, le calcul des jours même de l’année et du mouvement solaire est d’une difficulté presque insurmontable. Aux trois cent soixante-cinq jours on ajoute des jours intercalaires, produits de quarts de jour et de nuit ; de là vient qu’on ne peut indiquer des époques fixes pour les astres. Ajoutez une obscurité des choses avouée de tous : tantôt en effet la mauvaise saison, s’annonçant, anticipe même de plusieurs jours, ce que les Grecs appellent προϰεἰμασις (avant-hiver), et la belle saison retarde, ce qui est nommé ἐπιϰεἰμασις (arriere-hiver) : l’effet du ciel tombe sur la terre tantôt plus vite, tantôt plus tardivement ; et d’ordinaire c’est quand la sérénité est rétablie que nous entendons dire que l’action de l’astre est accomplie. En outre, car tous ces phénomènes dépendent d’astres réglés et fixés au ciel, le mouvement des étoiles amène intercurremment des grêles, des pluies qui ne sont pas non plus d’une faible action, comme nous l’avons enseigné (XVII, 2), et qui troublent l’ordre espéré. Et ne pensons pas que ces méprises n’arrivent qu’à nous; les autres animaux s’y trompent, bien que plus sagaces que nous sur ce point, vu que leur vie en dépend : l’on voit les oiseaux d’été tués par des froids hâtifs ou tardifs, et les oiseaux d’hiver par des chaleurs hâtives ou tardives. Aussi [[w:Virgile|'''Virgile''']] [[#Virgile|<span id="Virgile_back"><sup>'''I'''</sup></span>]] ([[w:Géorgiques|''Georg.'']], I, 335) recommande-t-il d’étudier encore le cours des astres errants, avertissant d’observer le passage de Saturne, planète froide. Il en est qui regardent comme l’indice le plus sûr du printemps l’apparition des papillons, à cause de la délicatesse de cet insecte. Or, l’année même où nous écrivions ceci (an 830 de ''Rome''), il a été noté que les papillons, ayant éclos, furent détruits à trois reprises par le froid, et que les oiseaux étrangers, ayant apporté l’espérance du printemps avant le 6 des calendes de février (27 janvier), eurent bientôt après à essuyer un hiver très-rigoureux. La double difficulté est d’abord d’avoir à demander au ciel la règle de toute chose, puis d’être obligé de contrôler cette règle par des faits apparents. Avant tout signalons la convexité du monde et les différences du globe terrestre, qui font que le même astre se montre à des temps divers suivant les nations, de sorte que l’influence ne s’en fait pas sentir partout aux mêmes jours. La difficulté a été encore accrue par les auteurs qui ont observé en des lieux différents, ou même qui, ayant observé dans les mêmes lieux, ont publié des résultats divergents. Il y a eu trois écoles, la ''Chaldéenne'', l’Égyptienne, la ''Grecque''. Une quatrième a été formée chez nous par le dictateur [[w:Jules_César|'''César''']], qui ramena l’année à la révolution solaire avec l’aide de [[w:Sosigène_d'Alexandrie|'''Sosigène''']] [[#Sosigène|<span id="Sosigène_back"><sup>'''II'''</sup></span>]], astronome habile. Et ce calcul même, où l’on découvrit une erreur, a été corrigé : pendant douze années consécutives on ne fit pas d’intercalation, attendu que l’année, qui auparavant anticipait, maintenant retardait sur les astres. '''Sosigène''' lui-même, quoique plus exact que les autres, n’a pas cessé, dans trois mémoires, de témoigner de ses doutes en se corrigeant lui-même. Les auteurs que nous avons indiqués au commencement de ce livre [[#auteurs_JH|<span id="auteurs_JH_back"><sup>'''1'''</sup></span>]] ont révélé ces discordances, l’avis de l’un s’accordant rarement avec l’avis de l’autre. Cela est moins étonnant dans ceux qui s’excuseront par la différence des lieux. Parmi ceux qui dans le même pays sont en désaccord, nous choisirons un exemple de dissidence : [[w:Hésiode|'''Hésiode''']] [[#Hésiode|<span id="Hésiode_back"><sup>'''III'''</sup></span>]] (car nous avons aussi sous son nom un livre sur les astres) a rapporté que le [[w:Lever_héliaque|''coucher matinal'']] des [[w:Pléiades_(astronomie)|''Pléiades'']] se faisait au moment de l’[[w:Équinoxe_de_septembre|''équinoxe d’automne'']] ; '''Thalès''', qu’il se faisait vingt-cinq jours après cet équinoxe; [[w:Anaximandre|'''Anaximandre''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Anaximandre_back|<sup>🔄</sup>]], vingt-neuf; [[w:Euctémon|'''Euctémon''']] [[#Euctémon|<span id="Euctémon_back"><sup>'''IV'''</sup></span>]], quarante-huit. Quant à nous, nous suivrons les calculs de '''César''' : ils se rapportent spécialement à l’Italie. Toutefois, nous relaterons aussi les opinions des autres ; car nous sommes les interprètes, non d’un seul pays, mais de la nature entière. Nous nommerons, non pas les auteurs, ce qui serait trop long, mais les pays. Les lecteurs auront seulement à se souvenir que, pour abréger, sous le nom d’[[w:Attique|''Attique'']] nous entendons aussi les [[w:Cyclades|''Cyclades'']]; sous celui de [[w:Macédoine_(province_romaine)|''Macédoine'']], la [[w:Magnésie_antique|''Magnésie'']] et la [[w:Thrace_(province_romaine)|''Thrace'']]; sous celui d’[[w:Égypte_romaine_et_byzantine|''Égypte'']], la [[w:Syrie-Phénicie_(province_romaine)|''Phénicie'']], [[w:Chypre_(province_romaine)|''Chypre'']] et la [[w:Cilicie|''Cilicie'']]; sous celui de [[w:Béotie#Antiquité|''Béotie'']], la [[w:Locride_(Grèce)|''Locride'']], la [[w:Phocide#Antiquité_et_période_byzantine|''Phocide'']] et les contrées limitrophes ; sous celui d’[[w:Hellespontique|''Hellespont'']], la [[w:Chersonèse_(cité_grecque)|''Chersonèse'']] et le continent jusqu’au [[w:Mont_Athos|''mont Athos'']]; sous celui d’[[w:Ionie|''Ionie'']], l’Asie et les îles ''Asiatiques'' ; sous celui de [[w:Péloponnèse#Antiquité|''Péloponnèse'']], l’[[w:Achaïe|''Achaïe'']] et les terres situées à l’occident; la [[w:Chaldée|''Chaldée'']] indiquera la [[w:Histoire_de_la_Syrie#Antiquité|''Syrie'']] et la [[w:Babylone_(civilisation)|''Babylonie'']]. On ne s’étonnera pas que je passe sous silence l’[[w:Afrique_romaine|''Afrique'']], l’[[w:Hispanie_romaine|''Espagne'']] et les [[w:Gaule|''Gaules'']], car personne dans ces contrées n’a laissé d’observations sur le lever des astres. Toutefois, il ne sera pas difficile de le calculer, même dans ces contrées, en étudiant la disposition des cercles que nous avons présentés dans le sixième livre (VI, 39). Grâce à cette étude, on connaît les relations astronomiques nou-seulement des nations, mais encore des villes en particulier : étant donnés les cercles déterminés par l’égalité des ombres, on choisit, dans les terres que nous avons nommées, le cercle qui a rapport à la localité objet du problème, et qui détermine en même temps le lever des astres pour cette localité. Il faut encore remarquer (II, 48) que tous les quatre ans les saisons ont leurs excès, et qu’elles reviennent les mêmes sans grande différence, en raison du soleil ; mais que tous les huit ans elles ont un redoublement, à la révolution de la centième lune.</div> <table cellspacing=15 align=center style="margin: 0 4em; font-size:85%;"> <tr> <td style="text-align: justify; margin: 0 4em;">'''[[#auteurs_JH_back|<span id="auteurs_JH"><sup>1</sup></span>]] Ce passage porte à croire que les auteurs dont Pline s’était servi pour composer chacun des livres de son ouvrage avaient été placés en tête du livre auquel ils se rapportaient. Les éditions mettent cette liste d’auteurs à la suite de la table de chaque livre, dans la table générale dressée par Pline lui-même.'''</td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/b24875958_0001/page/n7/mode/2up <u>Histoire Naturelle de Pline.</u>], [https://archive.org/details/b24875958_0001/page/652/mode/2up ''Livre XVIII.''], [https://archive.org/details/b24875958_0001/page/684/mode/2up ''Chap. LVII.''], texte corrigé par [[w:Émile_Littré|M. É. Littré]], à partir de celui de [[w:Jean_Hardouin|Hardouin]] [https://archive.org/details/b24875958_0001/page/708/mode/2up <sup>NOTES</sup>], Librairie de Firmin-Didot et C<sup>ie</sup>, Paris, 1883<br />(également disponible une édition 1848 [[s:Page:Pline_l'ancien_-_Histoire_naturelle,_Littré,_T1_-_1848.djvu/708|ici]])</div> {{Boîte déroulante début|titre=NdA de trad. Jean Hardouin 1883|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Virgile_back|<span id="Virgile"><sup>I</sup></span>]] [[w:Nom_romain|Tria Nomina]] en latin {{Info|Publius|praenomen, nom individuel du citoyen romain}} {{Info|Vergilius|nomen, nom de famille}} {{Info|Maro|cognomen, surnom héréditaire, servant à distinguer les diverses branches d’une même gens}};<br /><p style="margin: 0 2em; text-indent: 15px">Poète latin renommé dans les styles [[w:Épopée|''épique'']] (l’[[w:Énéide|''Énéide'']]), [[w:Poésie_pastorale|''pastorale'']] (les [[w:Bucoliques|''Bucoliques'']]) et [[w:Poésie_didactique|''didactique'']] (les [[w:Géorgiques|''Géorgiques'']]).<br /><p style="text-align: right; margin: 0 2em;">(15 octobre [[w:Années_70_av._J.-C.|-70]], [[w:Virgilio_(Lombardie)#Histoire|''Andes'']], au sud-est de l’actuelle [[w:Lombardie#Histoire|''Lombardie'']], au nord de l’Italie — 21 septembre [[w:Années_19_av._J.-C.|-19]], [[w:Brindisi#Histoire|''Brundisium'']], au sud-est des actuelles [[w:Pouilles#Domination_romaine|''Pouilles'']], au sud-est de l’Italie)<sup>[[w:Ier_siècle_av._J.-C.|⏳]]</sup> <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Sosigène_back|<span id="Sosigène"><sup>II</sup></span>]] Du nom propre grec ancien Σωσῐγένης / Sōsigénēs [[wikt:en:Σωσιγένης#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;">➥ du verbe σῴζω / sṓizō, « 1. Sauver : • Guérir ; • (rare chez Homère) Garder en sécurité, préserver ; • Garder, observer, maintenir ; • (généralement au milieu) Garder à l’esprit, se souvenir ; • Conduire en toute sécurité (à) ; • Secourir ; • Conserver pour. »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ + du nom commun‎ γένος / génos [[wikt:en:γένος#Ancient_Greek|(en)]], « 1. Race, souche, parenté : Descendance directe, par opposition à une relation collatérale. 2. Progéniture, descendant : (collectif) progéniture, postérité. 3. (en général) Race d’êtres : • Famille, clan, maison ; • Tribu, nation, race, en tant que subdivision de ἔθνος / éthnos [[wikt:en:ἔθνος#Ancient_Greek|(en)]] ; • Caste ; • Race d’animaux. 4. Âge, génération, période de la vie. 5. Sexe, genre : (grammaire) Genre grammatical. 6. Classe, sorte, genre : • (logique) L’opposé de εἶδος / eîdos [[wikt:en:εἶδος#Ancient_Greek|(en)]] ; • (taxonomie) Classe : • (taxonomie) Genre ; • Espèce de plante ; culture, produit ; matériau ; • Élément. »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ +‎ du suffixe nominal propre -ης / -ēs [[wikt:en:-ης#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;"> Astronome grec, connu pour avoir participer à la conception du [[w:Calendrier_julien|''calendrier julien'']] (instauré par Jules César en [[w:Années_46_av._J.-C.|-46]]/[[w:Années_45_av._J.-C.|-45]], lorsqu’il était [[w:Pontifex_maximus|''pontifex maximus'']]), avec une année commune de 365 jours divisée en 12 mois, et un jour intercalaire ajouté tous les 4 ans, lors des années bissextiles.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:Ier_siècle_av._J.-C.|I<sup>er</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]]) <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Hésiode_back|<span id="Hésiode"><sup>III</sup></span>]] Du nom propre grec ancien Ἡσῐ́οδος / Hēsíodos;<br /><p style="margin: 0 2em; text-indent: 15px">Poète ''grec'', renommé pour 2 ouvrages :<br /><p style="margin: 0 2em; text-indent: 15px;">• [[w:Théogonie_(Hésiode)|''la Théogonie'']], une généalogie des dieux (dans laquelle il présente la multitude des dieux célébrés par les mythes grecs où trois générations divines se succèdent : celle d’Ouranos, celle de Cronos, celle de Zeus qui sort triomphant) et une cosmogonie (qui retrace la création du monde à partir du Chaos) ;<br /><p style="margin: 0 2em; text-indent: 15px;">• et [[w:Les_Travaux_et_les_Jours|''les Travaux et les Jours'']], un almanac sur l’agriculture à destination de son frère Perses.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:VIIIe_siècle_av._J.-C.|VIII<sup>ème</sup>]] — [[w:VIIe_siècle_av._J.-C.|VII<sup>ème</sup>]] siècles {{Info|AEC|Avant l’Ère Commune}}) <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Euctémon_back|<span id="Euctémon"><sup>IV</sup></span>]] Du nom propre grec ancien Ευκτήμων / Euktémōn;<br /><p style="margin: 0 2em; text-indent: 15px;">Astronome ''athénien'', contemporain et collègue de l’astronome [[w:Méton|Méton]], avec qui, il a fait une série d’observations des [[w:Solstice|''solstices'']] afin de déterminer la durée de l’[[w:Année_tropique|''année tropique'']] [https://ecliptiqc.ca/Almageste_Livre3.php#III1 <sup>Ptolémée, Almageste, liv. III, chap. 1</sup>].<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:Ve_siècle_av._J.-C.|V<sup>ème</sup>]] siècle {{Info|AEC|Avant l’Ère Commune}})'''<br/><br/></div> {{Boîte déroulante fin}} <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: center; margin: 0 2em;">Des découvertes astronomiques : part de chaque observateur dans la science.<br /><p style="text-align: justify; text-indent: 15px;">'''LVII.''' D’abord, il est presque impossible de déterminer d’une manière précise le nombre des jours de l’année et le cours du soleil [[#Primum_omnium_dierum_AdG|<span id="Primum_omnium_dierum_AdG_back"><sup>'''1'''</sup></span>]]. Aux trois cent soixante-cinq jours qui composent l’année, on ajoute le quart d’un jour et d’une nuit, pour en faire ensuite un jour intercalaire ; de là il suit qu’on ne saurait indiquer avec précision le moment du lever et du coucher des astres. On convient qu’il y a encore dans cette théorie beaucoup d’obscurité ; en effet, les saisons quelquefois commencent plusieurs jours avant le terme qui leur a été fixé, ce que les ''Grecs'' appellent ''procheimasis'' ; d’autres fois, plusieurs jours après, ce qu’ils appellent ''épicheimasis'' [[#Accedit_confessa_rerum_obscuritas_AdG|<span id="Accedit_confessa_rerum_obscuritas_AdG_back"><sup>'''2'''</sup></span>]]. Presque toujours l’action des astres se fait sentir sur la terre ou plus tôt ou plus tard qu’il ne devrait ; aussi dit-on communément, lorsque le beau temps est revenu, que tel astre a produit son effet. Ces phénomènes dépendent des astres fixés à la voûte des cieux, ainsi que des étoiles, dont les mouvemens particuliers excitent des grêles et des pluies qui sont d’une très-grande conséquence pour les biens de la terre, comme nous l’avons observé, et amènent dans la température des changemens sur lesquels le laboureur ne pouvait compter. Non-seulement les hommes y sont trompés, mais aussi les animaux, bien plus habiles que nous à prévoir ces vicissitudes, puisque d’ailleurs leur vie en dépend ; en effet, on a vu des oiseaux d’été périr par des froids arrivés trop tôt ou trop tard, et des oiseaux d’hiver par des chaleurs également imprévues. Aussi '''Virgile''' veut-il qu’on étudie aussi le cours des ''planètes'', et qu’on observe avec soin le passage du froid ''Saturne'' [[#Ideo_Virgilius_errantium_quoque_siderum_rationem_ediscendam_prœcipit_AdG|<span id="Ideo_Virgilius_errantium_quoque_siderum_rationem_ediscendam_prœcipit_AdG_back"><sup>'''3'''</sup></span>]].<br /><p style="text-align: justify; text-indent: 15px;">Quelques-uns fixent le commencement du printemps à l’apparition des papillons, parce que ces insectes sont fort délicats. Néanmoins on a observé, dans l’année même où j’écris cette partie de mon ouvrage, que le froid, ayant repris trois fois, a fait périr autant de fois les papillons, et que les hirondelles qui, s’étaient montrées dès le 6 des [[w:Calendes|''kalendes'']] de février, et semblaient annoncer le retour du printemps, ont eu à essuyer un rigoureux hiver.<br /><p style="text-align: justify; text-indent: 15px;">C’est donc une science très-problématique que celle de l’influence des astres, et les inductions qu’elle fournit sont fort douteuses [[#Res_anceps_AdG|<span id="Res_anceps_AdG_back"><sup>'''4'''</sup></span>]]. Ce qui augmente la difficulté, c’est la convexité du ciel et la différence des climats de la terre : le même astre se montre ici dans un temps, et là dans un autre ; d’où il suit que son influence ne se fait pas sentir en même temps partout. Pour surcroît d’embarras, les observations recueillies par les auteurs ont été faites dans des lieux différens, et ceux du même pays ne s’accordent pas même entre eux. On compte trois écoles astronomiques, la ''chaldéenne'', l’égyptienne et la ''grecque''. Le dictateur '''César''' en a fondé, chez les ''Romains'', une quatrième, lorsqu’aidé de '''Sosigène''', habile astronome, il fixa la longueur de l’année à une révolution du soleil. On trouva dans la suite que son calendrier était défectueux, parce que l’année, auparavant plus courte, se trouvait alors plus longue que le cours du soleil. Pour y remédier, il fallut, pour douze années consécutives, supprimer les jours intercalaires. '''Sosigène''' lui-même, le mathématicien le plus exact de son temps, après avoir revu jusqu’à trois fois ses calculs, sembla toujours douter de leur justesse, et ne cessa jamais de se corriger lui-même. De tous les auteurs qui ont traité ce sujet, et que nous avons cités au commencement de ce livre, il en est rarement deux qui soient de même avis. Cette divergence d’opinions est moins surprenante et plus excusable chez ceux qui écrivaient en des pays différens. Mais que dire de ceux qui, habitant le même pays, sont néanmoins d’avis différens ? En voici un exemple : '''Hésiode''', qui nous a laissé aussi un ouvrage sur le cours des astres, fixe le coucher matutinal des ''Pléiades'' au moment de l’équinoxe d’automne ; '''Thales''' prétend qu’il n’arrive que vingt-cinq jours après ; '''Anaximandre''' en met vingt-neuf ; '''Euctémon''', quarante-huit.<br /><p style="text-align: justify; text-indent: 15px;">Quant à nous, nous suivrons les calculs de '''César''', qui se rapportent spécialement à l’Italie ; mais nous rapporterons aussi les observations étrangères, car notre plan n’est pas de traiter d’un seul pays, mais de la nature entière. Pour être moins longs, nous citerons les pays, et non les auteurs ; et, pour abréger davantage encore, les lecteurs se souviendront que, sous le nom d’Attique, il faut aussi entendre les ''Cyclades'' ; sous le nom de ''Macédoine'', la ''Magnésie'' et la ''Thrace'' ; sous le nom d’Égypte , la ''Phénicie'', l’île de ''Cypre'' et la ''Cilicie'' ; sous celui de ''Béotie'', la ''Locride'', la ''Phocide'' et les contrées voisines ; sous le nom d’Hellespont, la ''Chersonèse'' et partie du continent jusqu’au mont ''Athos'' ; sous le nom de l’Ionie, l’Asie et les îles ''Asiatiques'' ; sous le nom du ''Péloponnèse'', l’Achaïe et les pays adjacens au couchant ; enfin sous le nom de ''Chaldée'', l’Assyrie et la ''Babylonie''. On ne sera pas étonné que nous ne parlions ni de l’Afrique, ni de l’Espagne, ni des ''Gaules''. Aucun auteur dans ces contrées n’a laissé d’observations sur le lever ou le coucher des astres. Il ne sera pas difficile néanmoins de déterminer l’époque de ces phénomènes dans ces contrées, en étudiant la disposition des cercles, telle que nous l’avons présentée dans le sixième livre. Par ce moyen, on déterminera la position astronomique, non-seulement de chaque pays, mais encore de chaque ville dont nous avons pu parler, en prenant par les ombres égales de tous les cercles, une portion du cercle de telle contrée qu’on voudra choisir, et en calculant son rapport avec le lever des astres. Il faut faire observer encore que tous les quatre ans les chaleurs reviennent à peu près les mêmes pour chaque saison, en raison du mouvement du soleil, et que toutes les huitièmes années elles sont plus fortes, à cause de la centième lunaison.</div> <table cellspacing=15 align=center style="margin: 0 4em; font-size:85%;"> <tr> <td style="text-align: justify; margin: 0 4em;">'''[[#Primum_omnium_dierum_AdG_back|<span id="Primum_omnium_dierum_AdG"><sup>1</sup></span>]] Cf. sur la plupart des difficultés que le texte de notre auteur révèle, les notes relatives à l’astronomie, au livre II. L’année romaine fut d’abord celle des [[w:Albe_la_Longue|''Albains'']], c’est-à-dire lunaire ; dix mois la composaient, mars en était le premier : elle avait cinquante jours de moins que l’année lunaire réelle, et soixante-un de moins que l’année solaire, c’est-à-dire trois cent quatre jours seulement ; c’était là l’[[w:Calendrier_romain|{{Info|''année de Romulus''|le calendrier dit romuléen}}]]. [[w:Calendrier_romain|{{Info|''Numa''|le calendrier dit pompilien}}]] ajouta deux mois à cette année, janvier et février, et elle se trouva être composée de trois cent cinquante-cinq jours. Elle demeura ainsi jusqu’à Jules César, où commence l’[[w:Calendrier_julien|''année julienne'']], qui se compose de trois cent soixante-cinq jours, huit heures, auxquels [[w:Calendrier_grégorien|''Grégoire le Grand'']] ajouta onze minutes, pour arriver à la plus grande exactitude possible.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Accedit_confessa_rerum_obscuritas_AdG_back|<span id="Accedit_confessa_rerum_obscuritas_AdG"><sup>2</sup></span>]] L’entrée du soleil dans tel ou tel signe du zodiaque, son passage à l’équateur, etc., ne sont pas toujours le signal d’un changement dans la température. [[w:Végèce|Végèce]] a parlé des jours prokéimasiques et épikéiniasiques :''' {{Info|''Aut enim circa diem statutum, aut ante, vel postea, tempestates fieri, compertum est : unde præcedentes, ωροϰεἰμασιν : nascentes die solenni, επιϰεἰμασιν : subsequentes, μεταϰεἰμασιν, græco vocabulo nuncuperaverunt''|Car on a constaté que les tempêtes se produisent soit vers le jour fixé, soit avant, soit après : d’où les précédents, ωροϰεἰμασιν : nés le jour solennel, επιϰεἰμασιν : les suivants, μεταϰεἰμασιν, étaient appelés par le mot grec. TdA.}} '''(IV, 40).''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Ideo_Virgilius_errantium_quoque_siderum_rationem_ediscendam_prœcipit_AdG_back|<span id="Ideo_Virgilius_errantium_quoque_siderum_rationem_ediscendam_prœcipit_AdG"><sup>3</sup></span>]] <p style="margin: 0 6em; text-indent: 0px">'''{{Info|Hoc metuens, cæli menses et sidera serva,<br />Frigida Saturni sese quo stella receptet.|Craignant cela, gardez les lunes et les étoiles du ciel, le froid de Saturne lui-même, où l’étoile les recevra. TdA.}}'''<p style="text-align: right; margin: 0 6em; text-indent: 0px">''Georg.'', I, 335.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Res_anceps_AdG_back|<span id="Res_anceps_AdG"><sup>4</sup></span>]] Voici enfin quelques idées philosophiques qui se trouvent sous la plume de Pline ; malheureusement la cause par laquelle notre auteur explique l’influence des astres est problématique, et montre que les sciences astronomiques des anciens laissaient beaucoup à désirer. Les Grecs croyaient qu’il y avait autant de cieux que de planètes ; le huitième ciel, ou le firmament, était celui dès étoiles fixés.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Occasum_matutinum_Vergiliarum_Hesiodus_AdG_back|<span id="Occasum_matutinum_Vergiliarum_Hesiodus_AdG"><sup>5</sup></span>]] L’ouvrage auquel Pline fait allusion a été mentionné par [[w:Théon_d'Alexandrie|Théon]] qui le nomme Αστριϰὴ βίϐλος [[w:en:Astronomia_(poem)|(en)]]. Cet ouvrage est perdu.'''</td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k5804072n <u>Histoire Naturelle de Pline. Tome Onzième</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k5804072n/f196.item ''Livre XVIII.''], [https://gallica.bnf.fr/ark:/12148/bpt6k5804072n/f340.item ''chap. LVII.''], traduction nouvelle par M. [[w:Stéphane_Ajasson_de_Grandsagne|Ajasson de Grandsagne]] [https://gallica.bnf.fr/ark:/12148/bpt6k5804072n/f453.item <sup>NOTES</sup>], C. L. F. Panckoucke, Paris, 1829</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: center; margin: 0 2em;">''Divi[[w:S_long|{{Info|ſ|forme ancienne longue de la lettre s minuscule}}]]<nowiki />ion des jours & des nuits [[w:S_long|{{Info|ſ|forme ancienne longue de la lettre s minuscule}}]]<nowiki />uivant le cours du Soleil ; lever & coucher des étoiles ; ordre des [[w:S_long|{{Info|ſ|forme ancienne longue de la lettre s minuscule}}]]<nowiki />ai[[w:S_long|{{Info|ſ|forme ancienne longue de la lettre s minuscule}}]]<nowiki />ons ; tems où l’on [[w:S_long|{{Info|ſ|forme ancienne longue de la lettre s minuscule}}]]<nowiki />eme les bleds d’hiver.''<br /><p style="text-align: justify; text-indent: 15px;">'''D'''’ABORD il e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t pre{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que impo{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ible de déterminer au ju{{Info|ſ|forme ancienne longue de la lettre s minuscule}}te le nombre des jours de l’année, & le cours du Soleil ; car comme aux trois cents {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oixante & cinq jours dont l’année e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t compo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ée, on ajoute le quart d’un jour & d’une nuit, autrement {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ix heures, qui, au bout de quatre ans, font un jour intercalaire [[#jour_intercalaire_LPdS|<span id="jour_intercalaire_LPdS_back"><sup>'''1'''</sup></span>]], il arrive qu’on ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}auroit a{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}igner avec certitude le tems du lever & du coucher des a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tres. En {{Info|ſ|forme ancienne longue de la lettre s minuscule}}econd lieu, l’on convient qu’il y a dans cette théorie beaucoup d’ob{{Info|ſ|forme ancienne longue de la lettre s minuscule}}curité ; car quelquefois les {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ons [[#quelques_les_saisons_LPdS|<span id="quelques_les_saisons_LPdS_back"><sup>'''2'''</sup></span>]] commencent plu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ieurs jours avant le terme qui leur a été fixé, ce que les Grecs appellent ''prokheïma{{Info|ſ|forme ancienne longue de la lettre s minuscule}}is'' ; & d’autres fois plu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ieurs jours après, ce que ces mêmes Grecs expriment par le mot ''epikheïma{{Info|ſ|forme ancienne longue de la lettre s minuscule}}is'' : & l’on éprouve très {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ouvent que l’action des a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tres {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ait {{Info|ſ|forme ancienne longue de la lettre s minuscule}}entir {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur la terre, tantôt plutôt, tantôt plus tard. Au{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}i dit-on communément, lor{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que le beau tems e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t revenu, que tel a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tre a produit {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on effet. D’ailleurs comme tout cela dépend des globes céle{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tes, leur mouvement relatif excite quelquefois des grêles & des pluies, qui, comme nous l’avons déja [[#déjà_fait_observer_LPdS|<span id="déjà_fait_observer_LPdS_back"><sup>'''3'''</sup></span>]] fait ob{{Info|ſ|forme ancienne longue de la lettre s minuscule}}erver, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont de la plus grande con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}équence pour les biens de la terre, & qui renver{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ent l’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}pérance qu’on avoit du beau tems. Et non {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eulement les hommes y {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont trompés, mais au{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}i les animaux, quoiqu’ils aient bien plus de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}agacité que nous pour pre{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}entir ces vici{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}itudes du ciel, d’autant que leur vie en dépend. En effet, on voit quelquefois les oi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}eaux d’été mourir par des froids qui viennent trop tard ou trop tôt, & les oi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}eaux d’hiver par des chaleurs qui arrivent de même. C’est pourquoi '''Virgile''' veut qu’on étudie au{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}i le cours des planetes, & qu’on ob{{Info|ſ|forme ancienne longue de la lettre s minuscule}}erve à quelle partie du zodiaque répond la planete du froid Saturne [[#Saturne_LPdS|<span id="Saturne_LPdS_back"><sup>'''4'''</sup></span>]]. Quelques-uns croient que le {{Info|ſ|forme ancienne longue de la lettre s minuscule}}igne le plus certain du printems commencé, c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t lor{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’on voit des papillons, & cela parceque ces in{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ectes {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont fort délicats. Néanmoins on a remarqué que dans l’année même [[#lAnnée_dÉcriture_LPdS|<span id="lAnnée_dÉcriture_LPdS_back"><sup>'''5'''</sup></span>]] où j’écris ceci, le froid ayant recommencé ju{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’à trois fois, a fait mourir autant de fois les papillons ; & que les hirondelles, qui, s’étant montrées dès le vingt-{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ept de Janvier, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}embloient annoncer le retour du printems, ont en{{Info|ſ|forme ancienne longue de la lettre s minuscule}}uite e{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}uyé un très cruel hiver.<br /><p style="text-align: justify; text-indent: 15px;">C’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t donc une {{Info|ſ|forme ancienne longue de la lettre s minuscule}}cience très problématique que celle de l’influence des a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tres, & les inductions que l’on en tire {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont fort douteuses. Mais ce qui cau{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e le plus d’incertitude, c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t cette convexité du ciel & la différence des climats de la terre, parceque le même a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tre {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e montre ici dans un tems, & là dans un autre, d’où il ré{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ulte que {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on influence ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e fait pas {{Info|ſ|forme ancienne longue de la lettre s minuscule}}entir en même tems par-tout. Un autre {{Info|ſ|forme ancienne longue de la lettre s minuscule}}urcroît de difficulté, c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t que les ob{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ervations recueillies par les Auteurs ont été faites en différents lieux, & que ceux même qui ont écrit dans le même endroit ne s’accordent nullement entre eux dans ce qu’ils écrivent. On compte ju{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’à trois différentes {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ortes de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ectes en A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tronomie ; {{Info|ſ|forme ancienne longue de la lettre s minuscule}}avoir, celle des Chaldéens [[#secte_des_Chaldéens_LPdS|<span id="secte_des_Chaldéens_LPdS_back"><sup>'''5*'''</sup></span>]], celle des Egyptiens & celle des Grecs. On peut même dire que le Dictateur Cé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ar [[#Dictateur_César_LPdS|<span id="Dictateur_César_LPdS_back"><sup>'''6'''</sup></span>]] en produi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}it, chez les Romains, une quatrieme, lor{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’il rédui{{Info|ſ|forme ancienne longue de la lettre s minuscule}}it chaque année au cours du {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oleil, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ervant à cet effet du travail de So{{Info|ſ|forme ancienne longue de la lettre s minuscule}}igene, très habile A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tronome. Néanmoins on découvrit en{{Info|ſ|forme ancienne longue de la lettre s minuscule}}uite que le calendrier de Cé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ar étoit défectueux [[#calendrier_César_défectueux_LPdS|<span id="calendrier_César_défectueux_LPdS_back"><sup>'''7'''</sup></span>]], parceque l’année qui auparavant étoit plus courte que le cours du {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oleil, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e trouvoit alors plus longue : & pour corriger cette erreur, on ordonna que pendant douze années de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uite, il n’y auroit point de jour intercalaire [[#correction_erreur_LPdS|<span id="correction_erreur_LPdS_back"><sup>'''8'''</sup></span>]]. So{{Info|ſ|forme ancienne longue de la lettre s minuscule}}igene lui-même, quoique Mathématicien plus exact que les autres, ne lai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}a pas de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e conduire con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tamment en homme qui doutoit de la ju{{Info|ſ|forme ancienne longue de la lettre s minuscule}}te{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}e de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on propre calcul, pui{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’il en fit ju{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’à trois différentes corrections. De tous les Auteurs [[#Auteurs_calendrier_LPdS|<span id="Auteurs_calendrier_LPdS_back"><sup>'''9'''</sup></span>]] qui ont écrit {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur cette matiere, & que nous avons allégués au commencement de ce livre, il s’en trouve rarement deux qui {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oient de même {{Info|ſ|forme ancienne longue de la lettre s minuscule}}entiment. Cette variété e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t moins {{Info|ſ|forme ancienne longue de la lettre s minuscule}}urprenante, comme au{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}i plus excu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}able, chez ceux qui écrivoient en des pays différents. Mais que dire de ceux qui, écrivant dans le même pays, n’ont pas lai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}é d’être partagés d’opinion ? En voici un exemple. '''Hé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iode''', dont il y a au{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}i un ouvrage [[#ouvrage_astronomique_Hésiode_LPdS|<span id="ouvrage_astronomique_Hésiode_LPdS_back"><sup>'''10'''</sup></span>]] {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur le cours des a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tres, dit que les Pléiades {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e couchent le matin dans le tems même de l’équinoxe d’automne. '''Thalès''' [[#opinion_Thalès_Hésiode_Anaximandre_LPdS|<span id="opinion_Thalès_Hésiode_Anaximandre_LPdS_back"><sup>'''11'''</sup></span>]] dit que cela arrive vingt-cinq jours après. '''Anaximandre''' en met vingt-neuf ; '''Euctémon''' [[#Euctémon_LPdS|<span id="Euctémon_LPdS_back"><sup>'''12'''</sup></span>]] quarante-huit.<br /><p style="text-align: justify; text-indent: 15px;">Quant à nous, nous {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uivrons le calcul de Cé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ar, ayant principalement égard à l’Italie. Nous ne lai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}erons néanmoins de rapporter les opinions étrangeres, parceque notre objet n’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t pas de traiter d’un {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eul pays, mais de la Nature entiere. Seulement, pour éviter les longueurs, nous n’indiquerons que les pays où chaque opinion a lieu, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ans faire mention des auteurs de ces a{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ertions : & pour abréger encore davantage, les Lecteurs voudront bien {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ouvenir que quand il e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t parlé de l’Attique, il faut, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous ce nom, entendre au{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}i les Cyclades ; que {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous le nom de Macédoine, il faut entendre au{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}i la Magné{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ie & la Thrace ; {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous le nom de l’Egypte, la Phénicie, l’i{{Info|ſ|forme ancienne longue de la lettre s minuscule}}le de Chypre & la Cilicie; {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous celui de la Béotie, la Locride, la Phocide & les contrées voi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ines ; {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous le nom de l’Hel le{{Info|ſ|forme ancienne longue de la lettre s minuscule}}pont, la pre{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’i{{Info|ſ|forme ancienne longue de la lettre s minuscule}}le de Thrace & le pays de terre ferme, ju{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’au mont Athos ; {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous le nom de l’Ionie, l’A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ie & les i{{Info|ſ|forme ancienne longue de la lettre s minuscule}}les A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iatiques ; {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous le nom du Péloponne{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e, l’Achaïe & les contrées [[#contrées_adjacentes_ouest_Péloponnese_LPdS|<span id="contrées_adjacentes_ouest_Péloponnese_LPdS_back"><sup>'''13'''</sup></span>]] adjacentes qu’elle a à {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on couchant ; {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous le nom des Chaldéens, l’Assyrie & la Babylonie. Il ne faudra pas s’étonner {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i je ne parle ici ni de l’Afrique, ni de l’Espagne, ni des Gaules, pui{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que ces pays n’ont eu aucun Auteur qui ait écrit du cours des a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tres, ni de leur lever. Toutefois il ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}era pas difficile de connoître le tems où ils {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e levent dans ces pays-là même, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i l’on e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t in{{Info|ſ|forme ancienne longue de la lettre s minuscule}}truit de l’arrangement des cercles céle{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tes, tel que nous l’avons expliqué au {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ixieme livre de cet ouvrage ; car, par ce moyen, & par les {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eules notions que nous avons expo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ées en donnant une nomenclature des lieux, on {{Info|ſ|forme ancienne longue de la lettre s minuscule}}aura la po{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ition, non {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eulement de chaque pays, mais encore de chaque ville, en prenant par les ombres égales de tous les cercles, un {{Info|ſ|forme ancienne longue de la lettre s minuscule}}egment du cercle de tel pays qu’on voudra choi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ir, & en cherchant {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on rapport avec le lever des a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tres. Il faut remarquer au{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}i que de quatre [[#Columelle_LPdS|<span id="Columelle_LPdS_back"><sup>'''14'''</sup></span>]] en quatre ans les {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ons & les chaleurs reviennent à peu près les mêmes, & cela à cau{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e du mouvement du Soleil ; & que de huit en huit ans ces mêmes chaleurs reviennent plus con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}idérables, en vertu de la centieme lunai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}on.</div> {{Boîte déroulante début|titre=Notes du traducteur|alignT=center}} <div style="text-align: justify; border: 2px; border-radius:15px; font-size:85%;"><br/> <table cellspacing=15 align=center style="margin: 0 4em;"> <tr> <td style="text-align: justify; margin: 0 4em; text-indent: 15px">'''[[#jour_intercalaire_LPdS_back|<span id="jour_intercalaire_LPdS"><sup>1</sup></span>]] Con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ultez, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur toute cette que{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tion, nos notes 13 & 14 {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur le huitieme chapitre du {{Info|ſ|forme ancienne longue de la lettre s minuscule}}econd livre de Pline, tome 1, p. 41 & 42 :<br /><p style="text-align: justify; text-indent: 15px; margin: 0 5em;">(13) [[w:Suétone|Suétone]] s’exprime mieux, lor{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’il écrit : chaque quatrieme année ''quarto quoque anno''. Il est vrai que, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}elon le [[w:Jean_Hardouin|Pere Hardouin]], il faut comprendre dans la période de cinq ans, dont parle Pline, la premiere & la cinquieme année comme Bi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}extiles ; ce qui revient aux quatre années de Suétone, dont la quatrieme avoit un ''bi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ex'' ; mais en vérité cette explication est des plus forcées. Je {{Info|ſ|forme ancienne longue de la lettre s minuscule}}erois donc d’avis qu’il faudroit lire dans Pline comme dans Suétone, ''quarto anno'', {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i nous n’apprenions d’ailleurs de cet Hi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}torien, que dès le regne d’Augu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}te il s’étoit déja gli{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}é plu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ieurs abus & altérations dans l’année Julienne. On voit du moins qu’il y réforma plu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ieurs cho{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es, sous prétexte de la remettre {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur le pied où Cé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ar l’avoit in{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tituée. Cela me donneroit à pen{{Info|ſ|forme ancienne longue de la lettre s minuscule}}er qu’on fit dès-lors attention à la fau{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}eté & à l’excédence du calcul Julien ; mais qu’Augu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}te, par respect pour la mémoire de Cé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ar, affecta d’imputer la faute à la négligence des Prêtres chargés à Rome de l’in{{Info|ſ|forme ancienne longue de la lettre s minuscule}}pection du Calendrier ; qu’au demeurant, on découvrit l’abus, & qu’on e{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}aya d’y remédier, en n’ajoûtant un jour entier à l’année ordinaire que chaque ''cinquieme année'' comme Pline paroît l’articuler ici expre{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ement. Mais d’ailleurs il e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t évident qu’à la longue le période bi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}extile de quatre années en quatre années prévalut {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur celui de chaque cinquieme année, dont parle Pline ; & même il paroît que ceux qui, par la {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uite, voulurent {{Info|ſ|forme ancienne longue de la lettre s minuscule}}upputer les tems, récapitulerent, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ans exception, toutes les bi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}extiles quartenaires écoulées depuis l’in{{Info|ſ|forme ancienne longue de la lettre s minuscule}}titution Julienne ; car en 1582, on trouva par ce moyen que l’année étoit reculée de dix jours & plus; d’autant que l’excédence du calcul Julien, qui {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uppo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e à l’année révolue 365 jours & {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ix heures, au lieu de 365 jours 5 heures 49 minutes, 8 {{Info|ſ|forme ancienne longue de la lettre s minuscule}}econdes 17 tierces & 13 quarts qu’elle a réellement, forme tous les ans environ 11 minutes de trop, & tous les cent trente-quatre ans un jour entier d’excès. Le Pape Grégoire XIII trouvant donc l’année reculée de plus de dix jours ; ce qui dérangeoit l’économie annuelle des {{Info|ſ|forme ancienne longue de la lettre s minuscule}}olemnités, remédia à cet inconvénient en retranchant de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on autorité dix jours au mois d’Octobre de l’année 1582, où l’on étoit alors ; & en réglant qu’à l’avenir tous les quatre cents ans on omettroit trois années bi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}extiles. Ce réglement devint une loi pour pre{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que toute l’Europe chrétienne. L’autre maniere de compter fut appellée l’ancien {{Info|ſ|forme ancienne longue de la lettre s minuscule}}tyle. La Grande-Bretagne a long-tems per{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i{{Info|ſ|forme ancienne longue de la lettre s minuscule}}té à s’en {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ervir malgré {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on abus manife{{Info|ſ|forme ancienne longue de la lettre s minuscule}}te. Enfin le Parlement d’Angleterre, par acte du mois de Septembre 1752, a adopté la réforme Grégorienne.<br /><p style="text-align: justify; text-indent: 15px; margin: 0 4em;">(14) Le {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oleil, en fai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ant le tour du cercle oblique, parcourt réellement 360 degrés ou {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ections ; pui{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que tout cercle {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e divi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e en 360 parties appellées degrés : mais la me{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ure de chaque degré du cercle parcouru annuellement par le {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oleil, excede tant {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oit peu, c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t-à-dire de quelques légeres fractions de tems, la durée de chacun de nos jours révolus ; durée qui n’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t, comme on {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ait, que de 24 heures préci{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es ; le{{Info|ſ|forme ancienne longue de la lettre s minuscule}}quelles, comparées à un degré, en produi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ent, au bout de l’année, 365 & plus pour le cercle, au lieu de 360 {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eulement que le cercle requerroit. D’après une connoi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ance con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}u{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e de ces principes, Jules Cé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ar {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e voyant Dictateur, Grand-Pontife, & maître du monde, entreprit, l’an 140 avant J. C. de réformer les abus qui s’étoient gli{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}és, tant dans l’année Pompilienne, ou de Numa, que dans celle des Pontifes, encore plus irréguliere que celle de Numa. A cet effet, il fit venir d’Alexandrie le Philo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ophe So{{Info|ſ|forme ancienne longue de la lettre s minuscule}}igenes. Celui-ci décida fau{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ement que le cercle des jours de l’année révolue excédoit du nombres 5 joint au quart de 1 les 360 degrés du cercle oblique parcouru par le {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oleil : expo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}é faux, auquel le Dictateur, occupé d’autres {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oins, déféra {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ans autre examen. Jules Cé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ar régla donc, de l’avis de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tronome, que l’année {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eroit divisée en 365 jours ; & quant au quart de jour re{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tant, qui produit {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ix heures, il ordonna qu’on n’y auroit aucun égard pour chaque année particuliere ; mais que chaque quatrieme année on réuniroit la totalité de quatre fois {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ix heures, qui en font vingt-quatre, pour en compo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}er un jour entier; & qu’ain{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i cette quatrieme année auroit 366 jours. Il régla de plus, que ce jour intercalaire, ou ajoûté à chaque quatrieme année, seroit le 24 Février. Les Romains nommoient ce jour-là ''bis {{Info|ſ|forme ancienne longue de la lettre s minuscule}}exto calendas Martii'', c’est-à-dire, le ''{{Info|ſ|forme ancienne longue de la lettre s minuscule}}econd {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ixieme avant les calendes de Mars'' ; d’où il arriva que l’année où tomboit ce jour intercalaire fut appellée bis-{{Info|ſ|forme ancienne longue de la lettre s minuscule}}extile.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#quelques_les_saisons_LPdS_back|<span id="quelques_les_saisons_LPdS"><sup>2</sup></span>]] Végece dit pareillement, liv. 4, chap. 40 : ''Aut enim circa diem {{Info|ſ|forme ancienne longue de la lettre s minuscule}}tatutum, aut ante, vel po{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tea, tempe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tates fieri compertum e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t : unde præcedentes, ωροϰεἰμασιν : na{{Info|ſ|forme ancienne longue de la lettre s minuscule}}centes die {{Info|ſ|forme ancienne longue de la lettre s minuscule}}olenni, επιϰεἰμασιν : {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ub{{Info|ſ|forme ancienne longue de la lettre s minuscule}}equentes, μεταϰεἰμασιν, Græco vocabulo nuncuperaverunt'' [[#Accedit_confessa_rerum_obscuritas_AdG_back|<sup>⤴️</sup>]]. On lit au{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}i chez [[w:Columelle|Columelle]], dans {{Info|ſ|forme ancienne longue de la lettre s minuscule}}a Préface :''' {{Info|''Neque enim ſemper eumdem, cælum & annus, velut ex præſcripto habitum gerunt : nec omnibus annis eodem vultu venit aſtas, aut hyems, &c.''|Car le ciel et l’année ne portent pas toujours le même habit, comme par un précepte : ni l’automne n’arrive chaque année avec la même apparence, ni l’hiver, etc. TdA}} </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#déjà_fait_observer_LPdS_back|<span id="déjà_fait_observer_LPdS"><sup>3</sup></span>]] Au liv. 17, chap. 2.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Saturne_LPdS_back|<span id="Saturne_LPdS"><sup>4</sup></span>]] Ain{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i qu’il l’in{{Info|ſ|forme ancienne longue de la lettre s minuscule}}inue dans {{Info|ſ|forme ancienne longue de la lettre s minuscule}}es ''Géorg.'' liv. I, v. 335 :'''<br /><p style="margin: 0 6em; text-indent: 0px">{{Info|Hoc metuens, cæli menses et sidera serva,<br />Frigida Saturni sese quo stella receptet.|Craignant cela, gardez les lunes et les étoiles du ciel, le froid de Saturne lui-même, où l’étoile les recevra. TdA.}} </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#lAnnée_dÉcriture_LPdS_back|<span id="lAnnée_dÉcriture_LPdS"><sup>5</sup></span>]] Pline, au quatorzieme livre, chap. 4, comptoit deux cents trente ans depuis la mort de [[w:Cicéron|Cicéron]] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Cicéron_I|<sup>🔄</sup>]], arrivée l’an de Rome 600. L’année qu’il indique ici, & où il {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e trouvoit avoir compo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}é quatre livres de plus, e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t probablement la {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uivante, c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t-à-dire l’année 831 de la fondation de Rome.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#secte_des_Chaldéens_LPdS_back|<span id="secte_des_Chaldéens_LPdS"><sup>5*</sup></span>]] Sur l’année Chaldéenne, qui étoit la même que la Judaïque, con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ultez [[w:Eusèbe_de_Césarée|Eu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ebe]], ''Præpar. Evang.'' liv. 9, chap. 17, où il fait Abraham inventeur de l’a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tronomie chez les Chaldéens. Les A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}trologues Chaldéens étoient ordinairement des Prêtres des Dieux, tels que [[w:Bérose|Béro{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e]], auquel les Athéniens éleverent dans leur Gymna{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e une {{Info|ſ|forme ancienne longue de la lettre s minuscule}}tatue à langue dorée. Sur quoi voyez Pline, liv. 7, chap. 37. Ce Béro{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e étoit un Prêtre de [[w:Bēl|Belus]] ; il e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t cité par [[w:Clément_d'Alexandrie|Clément d’Alexandrie]], & par [[w:Flavius_Josèphe|Jo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}eph]] [[#Flavius_Josèphe_I|<sup>⤵️</sup>]], contre Apion, liv. 1. Sur l’année Egyptienne, & {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur l’ancienne année Grecque, con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ultez [[w:Hérodote|Hérodote]] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Hérodote_I|<sup>🔄</sup>]] liv. 2, n°. 4. Cicéron rend ju{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tice à l’étude que firent des a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tres les Egyptiens & les Babyloniens, liv. 1, de ''Divinat.'' n°. 16 :''' {{Info|''Ægyptii, & Babylonii, in camporum patentium aquoribus habitantes, cùm ex terra nihil emineret, quod contemplationi cæli officere poſſet, omnem curam in ſiderum cognitione poſuerunt''|Les Égyptiens et les Babyloniens, vivant dans les eaux des plaines découvertes, alors que rien ne dépassait de la terre qui pût gêner la contemplation du ciel, mettaient tous leurs soins dans la connaissance des étoiles. TdA}}. </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Dictateur_César_LPdS_back|<span id="Dictateur_César_LPdS"><sup>6</sup></span>]] Voyez les notes 13 & 14 {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur le chap. 8 du liv. 2, tome 1, p. 41 & 42.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#calendrier_César_défectueux_LPdS_back|<span id="calendrier_César_défectueux_LPdS"><sup>7</sup></span>]] Voyez les notes indiquées dans la note précédente ; & joignez-y les ob{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ervations {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uivantes, qui {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont de M. De{{Info|ſ|forme ancienne longue de la lettre s minuscule}}places, p. 339 : « Le calendrier chrétien, ayant {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uivi la réformation de Jules Cé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ar, il {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e trouva qu’en l’année 1582, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous le Pape Grégoire XIII, l’équinoxe étoit remontée ju{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’au 11 de Mars, au lieu du 21, où elle devoit être. Ce Pape, après avoir con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ulté Clavius & Ciaconius, les plus habiles A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tronomes du tems, ordonna qu’en cette même année 1582, on compteroit le 5 du mois d’Octobre, au lieu du 15, afin de retrancher les dix jours qui s’étoient gli{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}és de trop, en {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uivant la {{Info|ſ|forme ancienne longue de la lettre s minuscule}}upputation Julienne, depuis le Concile de Nicée, tenu en 325 : on convint encore de continuer l’intercalation d’un jour tous les quatre ans ; & qu’en outre, pour éviter dans la {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uite pareille erreur, il {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eroit fait un retranchement de trois jours intercalaires, dans l’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}pace de quatre {{Info|ſ|forme ancienne longue de la lettre s minuscule}}iecles, à cau{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e des onze minutes qui manquent aux {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ix heures des années, dont on compo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e l’année intercalaire, ou bi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}extile ; ces trois jours {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e retranchent en l’année qui finit les trois premiers {{Info|ſ|forme ancienne longue de la lettre s minuscule}}iecles. De célebres A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tronomes modernes ont fait voir que, malgré cette précaution, il y auroit encore, au bout de quatre cents ans, plu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ieurs jours de variation dans l’équinoxe ».''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#correction_erreur_LPdS_back|<span id="correction_erreur_LPdS"><sup>8</sup></span>]] Etabli par Jules Cé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ar, & qui revenoit tous les quatre ans. Ecoutons Suétone, vie de ce Dictateur, chap. 40 : {{Info|''Faſtos correxit, jampridem vitio Pontiſicum, per intercalandi licentiam adeo turbatos, ut neque meſſium feria aſtati, neque vindemiarum autumno competerent, annumque ad curſum ſolis accommodevit, ut CCCLXV dierum eſſet, & intercalario menſe ſublato, unus dies quarto quoque anno intercalaretur, &c''|Il corrigea les jeûnes, qui avaient toujours été une faute pontique, si perturbés par la permission de l’intercalation, que ni les fêtes du mois ne tenaient, ni les récoltes ne correspondaient à l’automne, et il ajusta l’année à la course du soleil, de sorte que c’était 365 jours, et après le mois intercalaire, un jour était intercalé tous les quatre ans, etc. TdA}}. On s’apperçut que cette correction de Jules Cé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ar étoit elle-même fautive. On tenta de nouveau de remédier au vice du calendrier ; {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur quoi con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ultez Solin, chapitre 1, p. 5 ; le P. Petau, ''de Doctr. temp.'' chap. 3 ; mais {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur-tout [[w:Macrobe|Macrobe]], qui s’exprime ain{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i, liv. 1, ''Saturn.'' chap. 14, p. 255 :''' {{Info|''Sacerdotes ſibi errorem novum ex ipſa emendatione ſecerunt. Nam cùm oporteret diem, qui ex quadrantibus conſit, quarto quoque anno conſecto, antequam quintus inciperet, intercalare, illi quarto non peracto ſed incipiente, intercalabant. Hic error ſex & triginta annis permanſit : quibus annis intercalati ſunt dies duodecim, cùm deberent intercalari novem. Sed hunc quoque errorem ſerò deprehenſum correxit Auguſtus, qui annos duodecim ſine intercalari die tranſigi juſſit : ut illi tres dies, qui per annos triginta & ſex vitio ſacerdotalis ſeſtinationis excreverant, ſequentibus annis duodecim, nullo die intercalato, devorarentur. Poſt hoc unum diem, ſecundùm ordinationem Caſaris, quinto quoque incipiente anno intercalari juſſit : & omnem hunc ordinem area tabula ad aternam cuſtodiam inciſione mandavit.''|Les prêtres retranchèrent une nouvelle erreur de leur correction. Car lorsqu’il fallait intercaler le jour qui est composé de quadrants, la quatrième année consécutive, avant que la cinquième ne commence, on intercalait ceux lorsque la quatrième n’était pas terminée mais commençait. Cette erreur a duré trente-six ans : années au cours desquelles douze jours ont été intercalés, alors qu’il aurait fallu en intercaler neuf. Mais cette erreur fut également détectée par Auguste, qui ordonna que douze années s’écoulèrent sans jour intercalaire : afin que ces trois jours, qui avaient été excrétés pendant les trente-six années du vice sacerdotal de cessation, soient dévorés dans le douze années suivantes, sans jour intercalaire. Après ce jour, selon l’ordonnance de César, il décréta que la cinquième année serait également intercalée : et tout l’ordre fut ordonné d’être gravé par le conseil du domaine pour la garde éternelle. TdA}}. </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Auteurs_calendrier_LPdS_back|<span id="Auteurs_calendrier_LPdS"><sup>9</sup></span>]] Ces Auteurs {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont Hiéron, Philomêtor, Attale, Archelaüs, Xénophon, Magon, Caton, Silanus, Varron, &c. dont Pline a fait mention {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur la fin du chapitre 3.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#ouvrage_astronomique_Hésiode_LPdS_back|<span id="ouvrage_astronomique_Hésiode_LPdS"><sup>10</sup></span>]] Nous apprenons de Théon que cet ouvrage {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e nommoit l’A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}trique, Ἀςριϰὴ ϐίϐλος. Voyez au{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}i {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur ce même ouvrage, une Epigramme de [[w:Callimaque_de_Cyr%C3%A8ne|Callimaque]] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Callimaque_I_de_Cyrène_II|<sup>🔄</sup>]], citée dans la vie d’Aratus, qui fait partie de l’Uranologie de [[w:Denis_Pétau|Petau]], liv. 2, ''Var. Di{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ert.'' chap. 9, p. 97.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#opinion_Thalès_Hésiode_Anaximandre_LPdS_back|<span id="opinion_Thalès_Hésiode_Anaximandre_LPdS"><sup>11</sup></span>]] Con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ultez, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur cette opinion de Thalès, ain{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i que {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur celles d’Hé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iode & d’Anaximandre, l’Uranologie citée note précédente.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Euctémon_LPdS_back|<span id="Euctémon_LPdS"><sup>12</sup></span>]] ''Euctemon'' ; ain{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i portent les manu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}crits, & non pas ''Eudemon''. J’ai traité d’Euctêmon (en Grec Εὐϰτημον) dans les notes alphabétiques du premier livre, & plus récemment dans la note 21 du chapitre précédent.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#contrées_adjacentes_ouest_Péloponnese_LPdS_back|<span id="contrées_adjacentes_ouest_Péloponnese_LPdS"><sup>13</sup></span>]] Telles que l’Elide, l’Arcadie, la Me{{Info|ſ|forme ancienne longue de la lettre s minuscule}}lénie.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Columelle_LPdS_back|<span id="Columelle_LPdS"><sup>14</sup></span>]] Columelle, liv. 3, chap. 6 :''' {{Info|''Quo tempore ſol in eamdem partem ſigniſeri per eoſdem numeros redit, per quos cursus ſui principium cæperat : quem circuitum meatus dierum integrorum mille quadringentorum ſexaginta unius [[w:Apocatastase|ὰ τοκατάςασιν]] vocant ſtudioſi rerum cæleſtium''|A ce moment-là, le soleil revient dans la même direction au moyen des mêmes nombres par lesquels il a commencé sa course : laquelle course de mille quatre cent soixante et un jours entiers est appelée ὰ τοκατάςασιν par ceux qui étudient les choses célestes. TdA}}.</td> </tr> </table><br/><br/></div> {{Boîte déroulante fin}} <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=JeyFTzG771cC&newbks=1&newbks_redir=0&dq=Louis%20Poinsinet%20de%20Sivry%20Pline%20l'ancien&hl=fr&pg=PP9#v=onepage&q&f=true <u>Histoire Naturelle de Pline. Tome Sixieme</u>], [https://books.google.fr/books?id=JeyFTzG771cC&newbks=1&newbks_redir=0&dq=Louis%20Poinsinet%20de%20Sivry%20Pline%20l'ancien&hl=fr&pg=PA257#v=onepage&q&f=true ''Livre Dix-huitieme.''], [https://books.google.fr/books?id=JeyFTzG771cC&newbks=1&newbks_redir=0&dq=Louis%20Poinsinet%20de%20Sivry%20Pline%20l'ancien&hl=fr&pg=PA455#v=onepage&q&f=true ''Diviſion des jours & des nuits ſuivant le cours du Soleil ; lever & coucher des étoiles ; ordre des ſaiſons ; tems où l’on ſeme les bleds d’hiver.''], traduction en françois, avec le texte latin rétabli d’après les meilleures leçons manu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}crites ; accompagnée de Notes critiques pour l’éclairci{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ement du texte, & d’Ob{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ervations {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur les connoi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ances des Anciens comparées avec les découvertes des Modernes, par M. [[w:Louis_Poinsinet_de_Sivry|Louis Poinsinet de Sivry]], Chez la veuve Desaint, Paris, 1771</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div> </div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ==== Livre XXXVI ==== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Enquête sur la nature des pierres.</div> ===== <div style="text-align: center;">Chapitre XVII.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage de la mesure de la hauteur des pyramides et autres édifices semblables par comparaison des longueurs d'ombre, par '''Thalès'''.</div> :'''Texte latin''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''XVII.''' [...] Mensuram altitudinis earum omniumque similium deprehendere, invenit '''Thales''' ''Milesius'' umbram metiendo, qua hora par esse corpori solet.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=L249AAAAcAAJ&hl=fr&pg=PP11#v=onepage&q&f=false <u>Histoire Naturelle de Pline ― Tome Second</u>], [https://books.google.fr/books?id=L249AAAAcAAJ&hl=fr&pg=PA500#v=onepage&q&f=false ''Livre XXXVI.''], [https://books.google.fr/books?id=L249AAAAcAAJ&hl=fr&pg=PA513#v=onepage&q&f=false ''Chap. XVII.''], texte corrigé par [[w:Émile_Littré|M. É. Littré]], à partir de celui de [[w:Jean_Hardouin|Hardouin]], Librairie de Firmin-Didot et C<sup>ie</sup>, Paris, 1850<br />(également disponible une édition de 1877 sur [https://gallica.bnf.fr/ark:/12148/bpt6k282082c/f517.image ''Gallica''], ainsi qu’une édition de 1838 par [[w:Stéphane_Ajasson_de_Grandsagne|Ajasson de Grandsagne]] également sur [https://gallica.bnf.fr/ark:/12148/bpt6k1522394n/f179.item ''Gallica''])</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''XVII.''' [...] Le moyen de mesurer la hauteur des pyramides et autres édifices semblables, fut trouvé par '''Thalès''' de ''Milet'' : il mesura l’ombre à l’heure où elle est égale aux corps.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=L249AAAAcAAJ&hl=fr&pg=PP11#v=onepage&q&f=false <u>Histoire Naturelle de Pline ― Tome Second</u>], [https://books.google.fr/books?id=L249AAAAcAAJ&hl=fr&pg=PA500#v=onepage&q&f=false ''Livre XXXVI.''], [https://books.google.fr/books?id=L249AAAAcAAJ&hl=fr&pg=PA513#v=onepage&q&f=false ''Chap. XVII.''], texte corrigé par [[w:Émile_Littré|M. É. Littré]], à partir de celui de [[w:Jean_Hardouin|Hardouin]], Librairie de Firmin-Didot et C<sup>ie</sup>, Paris, 1850<br />(également disponible une édition de 1848 sur [https://remacle.org/bloodwolf/erudits/plineancien/livre36.htm ''Remacle''], sur [[s:Histoire_naturelle_(trad._Littré)/XXXVI|''wikisource'']] et une édition de 1877 sur [https://gallica.bnf.fr/ark:/12148/bpt6k282082c/f517.image ''Gallica''])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <p style="text-align: justify; text-indent: 15px;">'''XVII.''' [...] '''Thalès''' découvrit le moyen de mesurer et les pyramides et toutes les hauteurs semblables par la mesure de l’ombre à l’instant où elle est égale au corps.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k1522394n/f9.item <u>Histoire Naturelle de Pline. Tome Vingtième</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k1522394n/f127.item ''Livre XXXVI.''], [https://gallica.bnf.fr/ark:/12148/bpt6k1522394n/f179.item ''chap. XVII.''], traduction nouvelle par M. [[w:Stéphane_Ajasson_de_Grandsagne|Ajasson de Grandsagne]], C. L. F. Panckoucke, Paris, 1838</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Flavius_Josèphe|'''Flavius Josèphe''']] [[#Flavius_Josèphe|<span id="Flavius_Josèphe_back"><sup>'''I'''</sup></span>]] == <p style="text-align: right;">([[w:37|37]]/[[w:38|38]], à [[w:Histoire_de_Jérusalem#Période_romaine_et_byzantine_(63_av._J.-C._-_638)|''Jérusalem'']] — vers [[w:100|100]], à [[w:Rome_antique|''Rome'']]) [[w:Ier_siècle|<sup>⏳</sup>]] [[s:Auteur:Flavius_Josèphe|<sup>📚</sup>]] <div style="text-align: justify; margin: 0 1em; text-indent: 15px">[[w:historiographe|Historiographe]] ''romain'' [[w:Juifs|''juif'']] d’origine [[w:Judée_(province romaine)|''judéenne'']], il participe activement au début de la ''première guerre judéo-romaine'' en tant que commandant militaire de ''Galilée'' contre les Romains, avant de se rendre à [[w:Vespasien|'''Vespasien''']] [[#Vespasien|<span id="Vespasien_back"><sup>'''II'''</sup></span>]] lors de la prise de la garnison juive de la forteresse de [[w:Jotapata|''Jotapata'']] en juillet 67, et de devenir intermédiaire, interprète et négociateur entre les ''romains'' et les ''Juifs'' lors du siège de ''Jérusalem'' conduit par '''Titus''' [[#Titus_back|<sup>⤴️</sup>]] en 70. Après la fin de la grande révolte ''judéenne'', en 71, il s’établit auprès de son protecteur à ''Rome'' où il obtient la [[w:citoyenneté_romaine|''citoyenneté romaine'']].</div> {{Boîte déroulante début|titre=NdA Flavius Josèphe|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Flavius_Josèphe_back|<span id="Flavius_Josèphe"><sup>I</sup></span>]] De son nom de naissance Joseph ben (fils de) Matthatias, de l’hébreu יוסף בן מתתיהו / Yossef [[wikt:en:יוסף#Hebrew|(en)]] ben [[wikt:en:בן#Noun|(en)]] Matityahou [[wikt:en:מתתיהו#Hebrew|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;">• de la troisième personne du singulier [[w:Jussif|''jussive'']], signifiant ainsi « peut-il ajouter », du verbe הוֹסִיף / hosíf [[wikt:en:הוסיף#Hebrew|(en)]], « 1. Ajouter (quelque chose) à (quelque chose d'autre). 2. (littéraire) Continuer (à faire quelque chose). 3. (archaïque) Coordonné avec un autre verbe pour indiquer que l’action de ce verbe "ajoute" d’une manière ou d’une autre. »;<br /><p style="margin: 0 2em; text-indent: 15px;">• du nom commun בֵּן / bén, « 1. Fils. 2. (ne produit plus de mot ou d’expression) Un descendant mâle direct. 3. Un mec, un garçon. 4. (n’est plus productif, état de construction) Possesseur de (connaissance, capacité, etc.). 5. (État construit) Utilisé pour exprimer l’âge d’un homme, d’un garçon ou le référent d’un nom masculin : âge, âgé. »;<br /><p style="margin: 0 2em; text-indent: 15px;">• de la contraction du nom commun מַתָּנַת / mataná [[wikt:en:מתנה#Hebrew|(en)]], « cadeau, présent, don »;<br /><p style="margin: 0 2em; text-indent: 30px;">➥ du verbe נתן / natán [[wikt:en:נתן#Verb|(en)]], « 1. Donner. 2. Autoriser, permettre, laisser. 3. (archaïque) Mettre, placer. 4. (archaïque, hébreu biblique) Se transformer en. »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ et du nom propre יהוה / YHWH [[wikt:en:יהוה#Hebrew|(en)]], « (Judaïsme) Tétragramme : mot en quatre lettres hébraïques utilisé comme nom [[wikt:ineffable#Français|''ineffable'']] de Dieu dans la Bible hébraïque, diversement rendu par Yahweh ou Jéhovah. »;<br /><p style="margin: 0 2em; text-indent: 15px;">Son tria nomina à l’obtention de sa ''citoyenneté romaine'' est {{Info|Titus|praenomen, nom individuel du citoyen romain}} {{Info|Flavius|nomen, nom de famille}} {{Info|Josephus|cognomen, surnom héréditaire, servant à distinguer les diverses branches d’une même gens}}, prenant ainsi le nom de son bienfaiteur :<br /><br /><p style="margin: 0 2em; text-indent: 15px;">[[#Vespasien_back|<span id="Vespasien"><sup>II</sup></span>]] [[w:Nom_romain|Tria Nomina]] en latin {{Info|Titus|praenomen, nom individuel du citoyen romain}} {{Info|Flavius|nomen, nom de famille}} {{Info|Vespasianus|cognomen, surnom héréditaire, servant à distinguer les diverses branches d’une même gens}};<br /><p style="margin: 0 2em; text-indent: 15px;">[[w:L%C3%A9gat_(Rome_antique)|''Légat'']] lors de la [[w:Conqu%C3%AAte_romaine_de_la_Grande-Bretagne|''conquête de la Bretagne en 43'']] et lors de la [[w:Premi%C3%A8re_guerre_jud%C3%A9o-romaine|''rébellion juive de 66'']] en [[w:Jud%C3%A9e_(province_romaine)|''Judée'']]. Fin décembre 69, il est couronné empereur par le [[w:S%C3%A9nat_romain|''Sénat'']] après la guerre civile de l’[[w:Ann%C3%A9e_des_quatre_empereurs|''année des quatre empereurs'']], et fonde la dynastie des [[w:Flaviens|''Flaviens'']].<br /><p style="text-align: right; margin: 0 2em;">(17 novembre [[w:9|9]], près de [[w:Reate|''Reate'']] dans la région centrale italienne du [[w:Latium|''Latium'']] — 23/24 juin [[w:79|79]], à la station thermale de [[w:Aquae_Cutiliae|''Aquae Cutiliae'']], à l’est de ''Reate'')<sup>[[w:Ier_siècle|⏳]]</sup><br/><br/></div> ''' {{Boîte déroulante fin}} === [[w:Contre_Apion|Contre Apion]] === <p style="text-align: right;">[[s:Contre_Apion|📚]] {| cellpadding="0" align="{{{align|right}}}" style="margin-left: 2em; width:40%; border-spacing:3px; text-align:center; background-color:#F8F9FA; border:2px solid #C8CCD1" |- | style="border:solid 1px #F8F9FA" | [https://archive.org/details/contreapiontexte0000jose/page/n156/mode/1up {{Info|'''Éditions & Manuscrits'''|Flavius Josèphe Contre Apion, Théodore Reinach & Léon Blum, 1930}}] |- style="font-size:8pt; line-height:10pt; vertical-align:middle" | align="center" | <div style="margin-right: 1em; padding:0 0 4px 0; text-align:justify;">{{{légende| * La traduction ''latine'' a été imprimée dès 1480 à [[w:Vérone#Époque_moderne|''Vérone'']] par '''Pierre Maufer''' [[w:en:Petrus_Maufer|(en)]]. L’édition de cette traduction, due à [[w:Sigismund_Gelenius|'''Sigismond Gelenius''']] (''Paris'', 1535), qui constitue la « [[w:Vulgate|Vulgate]] », présente un texte souvent « amélioré » de façon arbitraire. La seule édition critique est celle de '''Ch. Boysen''' (''Vienne'', 1898) qui fait partie du [[w:Corpus_scriptorum_ecclesiasticorum_latinorum|{{Info|''Corpus scriptorum ecclesiasticorum latinorum''|Le corpus des écrits ecclésiastiques latins}}]]. Elle repose principalement sur les manuscrits L(aurentianus LXVI, 2), B(odleianus Canonicianus 148), R(egius Parisinus 5049) de la I<sup>re</sup> classe, C(heltenhamensis Phillipicus 12311), P(arisinus 1615), Pa(rsinus 5054) de la seconde. * Le texte grec est édité pour la première fois dans l’édition complète de '''Josèphe''' à [[w:Bâle#XVIe_siècle|''Bâle'']], chez [[w:Johann_Froben|''Froben'']], en 1544 par [[w:Arnoldus_Arlenius|'''Arlenius''']] qui a peut-être fait usage du ''Schleusingensis'' (un des fils du Laurentianus), mais a introduit grand nombre de corrections tantôt heureuses, et tantôt arbitraires. Par la suite notre traité n’a guère été imprimé que comme partie intégrante d’éditions complètes des œuvres de '''Josèphe'''. Les plus importantes sont celles de '''E. Bernard''' (1700), de [[w:John_Hudson_(classiciste)|'''Hudson''']] (1720) — le premier qui ait utilisé L —, de [[w:Sigebert_Havercamp|'''Havercamp''']] (1726), simple compilateur, de [[w:Karl_Wilhelm_Dindorf|'''L. Dindorf''']] (1847), de [[w:Immanuel_Bekker|'''Imm. Bekker''']] (1856), tout à fait manquée. L’édition critique de '''Niese''' [[w:en:Benedikt_Niese|(en)]] (1889) est la base de tous les travaux ultérieurs, notamment des éditions de '''Naber''' (1896) et de [[w:Henry_St._John_Thackeray|'''H. St. J. Thackeray''']] (coll. Loeb, 1926 : il n’a encore paru que le ''C. Apion'', la ''Vita'' et le commencement de la ''Guerre'') qui ont pu profiter aussi des conjectures de '''Cobet''', de '''Holwerda''', et de '''Herwerden'''.}}}</div> |} <div style="text-align: justify; margin: 0 1em; text-indent: 15px">Dernière œuvre écrite par '''Flavius Josèphe''', vers [[w:93|93]], dont l’objectif est de répondre aux critiques qu’ont soulevées ses [[w:Antiquit%C3%A9s_juda%C3%AFques|''Antiquités judaïques'']], de défendre l’ancienneté du peuple ''juif'' et du [[w:Judaïsme#Judaïsme_antique|''judaïsme'']] (Livre I) et les accusations d’[[w:Apion_(grammairien)|'''Apion''']] [[#Apion|<span id="Apion_back"><sup>'''I'''</sup></span>]] (Livre II).</div> {{Boîte déroulante début|titre=NdA Apion|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Apion_back|<span id="Apion"><sup>I</sup></span>]] Du nom propre grec ancien [[wikt:Apion#Latin|Ἀπίων / Apíôn]]; <br/><br /><p style="margin: 0 2em; text-indent: 15px;">'''[[w:Grammaticus|''Grammairien'']] [[#grammairien|<span id="grammairien_back"><sup>II</sup></span>]] et [[w:Polygraphe_(auteur)|''polygraphe'']] [[#polygraphe|<span id="Grammairien_back"><sup>III</sup></span>]] ''grec'' d’Alexandrie.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] seconde moitié du [[w:Ier_siècle_av._J.-C.|I<sup>er</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]] — première moitié du [[w:Ier_siècle|I<sup>er</sup> siècle {{Info|EC|de l’Ère Commune}}]]) <br /><br /><p style="margin: 0 2em; text-indent: 15px;">'''[[#grammairien_back|<span id="grammairien"><sup>II</sup></span>]] Du nom commun latin grammaticus [[wikt:en:grammaticus#Latin|(en)]]; du nom commun grec ancien γραμματικός / grammatikós [[wikt:en:γραμματικός#Noun|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px">➥ du nom commun γρᾰ́μμᾰ / grámma [[wikt:en:γράμμα#Noun|(en)]], « 1. Ce qui est écrit, ce qui est dessiné. 2. Lettre. 3. (au pluriel) Alphabet. 4. Écriture, livre. »;<br /><p style="margin: 0 2em; text-indent: 30px">➥ du verbe γράφω / gráphō [[wikt:en:γράφω#Ancient_Greek|(en)]], « 1. (Homérique) égratigner, couper en dedans. 2. Dessiner, esquisser, peindre. 3. Écrire. 4. Écrire, proposer une loi. 5. ([[w:Diathèse#Moyen|''voix moyenne'']]) : • (''[[w:Réflexivité_(grammaire)|réflexif]] indirect'') Écrire pour soi, noter ; • Accuser, poursuivre. 6. ([[w:Conjugaison_latine|''passif parfait'']]) Être écrit, être sous forme écrite. »;<br /><p style="margin: 0 2em; text-indent: 30px">➥ + du suffixe nominal de résultat‎ -μα / -ma [[wikt:en:-μα#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px">➥ +‎ du suffixe adjectival -ῐκός / -ikós, de ou se rapportant à, de la manière de ; « -ique »;<br /><p style="margin: 0 2em; text-indent: 15px">Enseignant responsable de la deuxième étape du système éducatif traditionnel, après l’apprentissage de l’alphabet, la lecture et l’écriture, et l’initiation au calcul avec un abaque chez un ''magister ludi'' [[w:en:Ludi_magister|(en)]] et avant celle de l’art du discours chez un [[w:Rhétorique#Rhétorique_dans_l'Antiquité_grecque|''rhéteur'']]. Le travail du grammairien était d’enseigner la lecture, l’analyse de textes des poètes antiques tels qu’Homère, Tite-Live et Virgile, et la grammaire [https://archive.wikiwix.com/cache/index2.php?url=http%3A%2F%2Fwww.antiquite.ac-versailles.fr%2Feducatio%2Fedrom2.htm#federation=archive.wikiwix.com&tab=url {{Info|<sup>➕</sup>|« L’école du grammaticus », ac-Versailles}}] [https://philo-lettres.fr/latin/rome_vie-quotidienne/ecole-romaine/ {{Info|<sup>➕➕</sup>|« L’École dans l’antiquité romaine, philo-lettres}}]. <br /><br /><p style="margin: 0 2em; text-indent: 15px;">'''[[#polygraphe_back|<span id="polygraphe"><sup>III</sup></span>]] Du nom commun grec ancien [[wikt:polygraphe|πολύγραφος / polýgraphos]], « qui écrit beaucoup de sujets »;<br /><p style="margin: 0 2em; text-indent: 15px">➥ de l’adjectif πολῠ́ς / polús [[wikt:en:πολύς#Ancient_Greek|(en)]], « (de nombre, au pluriel) Beaucoup de : • (avec des noms de multitude) Grand ; • (de quantité, avec des noms de masse) beaucoup de ; • (rare, d'une personne) Grand, puissant ; • (de son) Fort ; • (attributivement, adverbial) Fortement, pleinement ; • (d'espace) Large, grand ; • (de distance) Loin ; • (de temps) Long, en retard. »;<br /><p style="margin: 0 2em; text-indent: 15px">➥ +‎ du verbe γράφω / gráphō [[wikt:en:γράφω#Ancient_Greek|(en)]], « 1. (Homérique) égratigner, couper en dedans. 2. Dessiner, esquisser, peindre. 3. Écrire. 4. Écrire, proposer une loi. 5. (''voix moyenne'') : • (''réflexif indirect'') Écrire pour soi, noter ; • Accuser, poursuivre. 6. (''passif parfait'') Être écrit, être sous forme écrite. »;<br /><p style="margin: 0 2em; text-indent: 15px;">Le terme semble avoir été employé au cours de l’Antiquité dans un sens différent de celui que nous l’entendons aujourd’hui, pas dans le sens de diversité mais, de façon restreinte, le fait de composer un grand nombre de textes [https://eriac.univ-rouen.fr/la-polygraphie-comme-norme/ {{Info|<sup>➕</sup>|Isabelle Gassino, Université de Rouen et Dimitri Kasprzyk, université de Brest, « Colloque "La polygraphie comme norme" », 16 et 17 novembre 2017.}}].'''<br/><br/></div> {{Boîte déroulante fin}} ==== Livre I ==== ===== <div style="text-align: center;">Chapitre II.</div> ===== <div style="text-align: justify; margin: 0 1em;">Témoignage de '''Thales''' comme : * l’un des premiers ''philosophes grecs'' ayant traité des choses célestes et divines ; * disciple des ''Égyptiens'' et des ''Chaldéens'' (premier témoignage) ; * auteur de court(s)/rare(s) ouvrages (supposément unanimement admis), que les ''Grecs'' considéreraient comme les plus anciens, et douteraient, selon '''Flavius Josèphe''', de leur authenticité.</div> :'''Texte latin''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">qui autem historias apud eos conscribere temptauerunt, id est hi, qui circa '''Cadmum''' ''Milesium'', et '''Acusilaus''' ''Argiuus'' et post hunc quicumque alii fuisse referuntur, paululum tempus ''Persicam'' apud ''Helladium'' militiam praecesserunt. sed etiam eos, qui de caelestibus et diuinis primitus apud ''Graecos philosophati'' sund, id est '''Pherecydem''' ''Syrum'' et '''Pythagoram''' et '''Thaletem''' omnes concorditer confidentur ''Aegyptiorum'' et ''Chaldaeorum'' fuisse discipulos et breuiter conscripsisse quae a ''Graecis'' omnium antiquissima iudicantur ita ut uix ea credant ab illis fuisse conscripta.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[[w:Corpus_scriptorum_ecclesiasticorum_latinorum|<u>Corpus scriptorum ecclesiasticorum latinorum</u>]], [https://verlag.oeaw.ac.at/produkt/flavii-iosephi-opera-ex-versione-latina-antiqua-pars-vi-de-iudaeorum-vetustate-sive-contra-apionem-libri-ii/601067?name=flavii-iosephi-opera-ex-versione-latina-antiqua-pars-vi-de-iudaeorum-vetustate-sive-contra-apionem-libri-ii&product_form=5107 <u>Tome XXXVII, Flavius Iosephus, Contra Apionem</u>], ''Livre I'', ''chap. II.'', ''l.13, 14'', p.64, 1898</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">Οἱ μέντοι τὰς ἱστορίας ἐπιχειρήσαντες συγγράφειν παρ' αὐτοῖς, λέγω δὲ τοὺς περὶ '''Κάδμον''' τε τὸν ''Μιλήσιον'' καὶ τὸν ''Ἀργεῖον'' '''Ἀκουσίλαον''' καὶ μετὰ τοῦτον εἴ τινες ἄλλοι λέγονται γενέσθαι, βραχὺ τῆς ''Περσῶν'' ἐπὶ τὴν ''Ἑλλάδα'' στρατείας τῷ χρόνῳ προύλαβον. Ἀλλὰ μὴν καὶ τοὺς περὶ τῶν οὐρανίων τε καὶ θείων πρώτους παρ' ''Ἕλλησι φιλοσοφήσαντας'', οἷον '''Φερεκύδην''' τε τὸν ''Σύριον'' καὶ '''Πυθαγόραν''' καὶ '''Θάλητα''', πάντες συμφώνως ὁμολογοῦσιν ''Αἰγυπτίων'' καὶ ''Χαλδαίων'' γενομένους μαθητὰς ὀλίγα συγγράψαι, καὶ ταῦτα τοῖς ''Ἕλλησιν'' εἶναι δοκεῖ πάντων ἀρχαιότατα καὶ μόλις αὐτὰ πιστεύουσιν ὑπ' ἐκείνων γεγράφθαι.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://remacle.org/bloodwolf/historiens/Flajose/Apion1gr.htm <u>Φλαίίου Ἰωσήπου, περὶ ἀρχαιότητος Ἰουδαίων</u>, ''λόγος α''], ''chap. II.'', ''l.13, 14'', 1898</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">Quant aux Grecs qui ont entrepris d’écrire l’histoire, comme [[w:Cadmos_de_Milet|'''Cadmos''' de ''Milet'']], [[w:Acousilaos|'''Acousilaos''' d’Argos]] et ceux qu’on cite après lui, ils n’ont vécu que peu de temps [[#Cadmos_NdT_LB|<span id="Cadmos_NdT_LB_back"><sup>1</sup></span>]] avant [[w:Guerres_médiques|''l’expédition des Perses contre la Grèce'']]. Mais bien certainement les premiers ''philosophes grecs'' qui aient traité des choses célestes et divines, comme [[w:Phérécyde_de_Syros|'''Phérécyde''' de ''Syros'']] [[#Phérécyde_de_Syros_NdT_LB|<span id="Phérécyde_de_Syros_NdT_LB_back"><sup>2</sup></span>]], '''Pythagore''' et '''Thalès'''[[#Thales_NdT_LB|<span id="Thales_NdT_LB_back"><sup>3</sup></span>]] furent, tout le monde s’accorde là-dessus, les disciples des ''Égyptiens'' et des ''Chaldéens'' avant de composer leurs courts ouvrages, et ces écrits sont aux yeux des ''Grecs'' les plus anciens de tous ; à peine même les croient-ils authentiques.</div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Cadmos_NdT_LB_back|<span id="Cadmos_NdT_LB"><sup>1.</sup></span>]] En réalité, Cadmos paraît avoir fleuri vers le milieu [[w:VIe_siècle_av._J.-C.|VI<sup>ème</sup> siècle]] [{{Info|AEC|Avant l’Ère Commune}}].''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Phérécyde_de_Syros_NdT_LB_back|<span id="Phérécyde_de_Syros_NdT_LB"><sup>2</sup></span>]] Seul texte qui attribue une origine égyptienne ou chaldéenne aux doctrines de Phérécyde de Syros. Cependant [[w:Theodor_Gomperz|Gompers]], [https://archive.org/details/bub_gb_QrfVAAAAMAAJ/page/n434/mode/1up Griechische Denker, I, 430], identifie ᾿Ογηνός avec l’Ouginna babylonien.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Thales_NdT_LB_back|<span id="Thales_NdT_LB"><sup>3</sup></span>]] On retrouve chez [[w:Apollonios_de_Tyane|Apollonios de Tyane]] ([[w:Jamblique|Jamblique]] [[#Jamblique_back|<sup>⤵️</sup>]], Vit. Pyth. [[#Vie_de_Pythagore_back|<sup>⤵️</sup>]], 12) et [[w:Plutarque|Plutarque]] [[#Plutarque_back|<sup>⤵️</sup>]] l’idée que Thalès de Milet fut disciple des Égyptiens ; l’adjonction des Chaldéens est propre Josèphe.''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/contreapiontexte0000jose/page/n6/mode/1up?view=theater <u>Flavius Josèphe, Contre Apion</u>], ''Livre I'', [https://archive.org/details/contreapiontexte0000jose/page/n49/mode/1up?view=theater&q=Thales ''chap. 2''], traduction du grec ancien par Léon Blum, agrégé des Lettres, professeur au lycée Janson-de-Sailly, texte établi et annotée par [[w:Théodore_Reinach|Théodore Reinach]] Membre de l’[[w:Institut_de_France|Institut]], professeur au Collège de France, 1930<br />(édition bilingue de 1911 également disponible [https://remacle.org/bloodwolf/historiens/Flajose/Apion1.htm ici])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: justify; margin: 0 2em;">Quant aux Grecs qui ont entrepris d’écrire l’histoire, comme '''Cadmos''' de ''Milet'', '''Acousilaos''' d’''Argos'' et ceux qu’on nomme après lui, ils n’ont vécu que peu de temps[2] avant l’expédition des ''Perses'' contre la ''Grèce''. [14]. De même, les premiers ''philosophes grecs'' qui aient traité des choses célestes et divines, comme '''Phérécyde''' de ''Syros''[3], '''Pythagore''' et '''Thalès'''[4] furent, tout le monde s’accorde là dessus, les disciples des ''Égyptiens'' et des ''Chaldéens'' avant de composer leurs rares ouvrages, et ces écrits sont aux yeux des ''Grecs'' les plus anciens de tous ; à peine même les croient-ils authentiques.</div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Cadmos_NdT_LB_back|<span id="Cadmos_NdT_LB"><sup>1.</sup></span>]] En réalité, Cadmos paraît avoir fleuri vers le milieu [[w:VIe_siècle_av._J.-C.|VI<sup>ème</sup> siècle]] [{{Info|AEC|Avant l’Ère Commune}}].''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Phérécyde_de_Syros_NdT_LB_back|<span id="Phérécyde_de_Syros_NdT_LB"><sup>2</sup></span>]] Seul texte qui attribue une origine égyptienne ou chaldéenne aux doctrines de Phérécyde de Syros. Cependant [[w:Theodor_Gomperz|Gompers]], [https://archive.org/details/bub_gb_QrfVAAAAMAAJ/page/n434/mode/1up Griechische Denker, I, 430], identifie ᾿Ογηνός avec l’Ouginna babylonien.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Thales_NdT_LB_back|<span id="Thales_NdT_LB"><sup>3</sup></span>]] On retrouve chez [[w:Apollonios_de_Tyane|Apollonios de Tyane]] ([[w:Jamblique|Jamblique]] [[#Jamblique_back|<sup>⤵️</sup>]], Vit. Pyth. [[#Vie_de_Pythagore_back|<sup>⤵️</sup>]], 12) et [[w:Plutarque|Plutarque]] [[#Plutarque_back|<sup>⤵️</sup>]] l’idée que Thalès de Milet fut disciple des Égyptiens ; l’adjonction des Chaldéens est propre Josèphe.''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Flavius Josèphe, De l’ancienneté du peuple juif (Contre Apion)</u>, ''Livre I'', [[s:Page:Flavius_Josephe_-_Leon_Blum_-_Contre_Apion,_Leroux,_Paris,_1902.djvu/17|''Chap. 2'']], traduction de Léon Blum, agrégé des lettres, professeur au lycée du Havre, sous la direction de [[w:Théodore_Reinach|Théodore Reinach]], 1902.</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div> </div> <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Plutarque|'''Plutarque''']] [[#Plutarque|<span id="Plutarque_back"><sup>'''I'''</sup></span>]] == <p style="text-align: right;">([[w:Circa|{{Info|''ca.''|Circa, locution latine que l’on emploie pour indiquer l’approximation d’une date}}]] [[w:45|45]]'' <sup>[[w:Ier_siècle|⏳]]</sup>'', à [[w:Chéronée|''Chéronée'']] en [[w:Béotie|''Béotie'']] — {{Info|''ca.''|Circa, locution latine que l’on emploie pour indiquer l’approximation d’une date}} [[w:125|125]]'' <sup>[[w:IIe_siècle|⏳]]</sup>)[[s:Auteur:Plutarque|<sup>📚</sup>]] [https://books.google.fr/books?id=qfl1xwEACAAJ&lpg=PA1067&hl=fr&pg=PA1097#v=onepage&q&f=false {{Info|<sup>🔍</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume Vb, §210 - Plutarque de Chéronée}}] [[Fichier:Plutarch at Delphi.jpg|vignette|<p style="text-align: justify; text-indent: 15px;">Buste probable de Plutarque du [[w:IIe_siècle|II<sup>ème</sup>]] ou [[w:IIIe_siècle|III<sup>ème</sup>]] siècles {{Info|EC|de l’Ère Commune}}, en marbre de [[w:Marbre_de_Paros|''Paros'']].<br /><p style="text-align: justify; text-indent: 15px;">Provenance : découvert lors de fouilles près de l’angle sud-est du [[w:Temple d'Apollon (Delphes)|''temple d’Apollon'']] de [[w:Delphes|''Delphes'']], au côté d'une [[w:Fichier:Plutarch_stele_inscription_100_AD,_AM_of_Delphi_4070060092.jpg|''stèle'']] portant une inscription gravée : ΔΕΛΦΟΙ ΧΑΙΡΩΝΕΥΣΙΝ ΟΜΟΥ ΠΛΟΥΤΑΡΧΟΝ ΕΘΗΚΑΝ ΤΟΙΣ ΑΜΦΙΚΤΥΟΝΩΝ ΔΟΓΜΑΣΙ ΠΕΙΘΟΜΕΝΟΙ — Les ''Delphiens'', avec les ''Chéronéens'', dédièrent ce(tte image de) Plutarque, suivant les préceptes de l’[[w:Amphictyonie|''Amphictyonie'']].<br /><p style="text-align: justify; text-indent: 15px;">Exposition : Salle XIV, [[w:Mus%C3%A9e_arch%C3%A9ologique_de_Delphes|''Musée archéologique de Delphes'']].]] <div style="text-align: justify; margin: 0 1em; text-indent: 15px">Biographe, philosophe et moraliste grec, auteur d’une œuvre importante, comportant un ensemble varié de traités et de dialogues consacrés à des questions de philosophie morale, mais abordant aussi des sujets littéraires, politiques, scientifiques, religieux.</div> {{Boîte déroulante début|titre=NdA Plutarque|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Plutarque_back|<span id="Plutarque"><sup>I</sup></span>]] Du nom propre grec ancien πλούταρχος / ploútarkhos [[wikt:en:Πλούταρχος#Ancient_Greek|(en)]], « maître des richesses » ; <br /><p style="margin: 0 2em; text-indent: 15px">➥ du nom commun πλοῦτος / ploûtos [[wikt:en:πλοῦτος#Ancient_Greek|(en)]], « richesses » ;<br /><p style="margin: 0 2em; text-indent: 15px">➥ +‎ du nom commun ἀρχός / arkhós, « souverain, chef, prince »)'''<br/><br/></div> {{Boîte déroulante fin}} {{Boîte déroulante début|titre=Remarque|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>''' Dans la ''Vie de [[w:Lycurgue_(législateur)|Lycurgue]]'' et la ''Vie d’Agis et Cléomène'' (''Vies parallèles''), et le traité ''Un philosophe doit surtout converser avec les princes'' (''Œuvres morales''), il est fait mention d’un Thalès : il s’agit de [[w:Thalétas|Thalétas]], aussi appelé Thalès de [[w:Crète|''Crète'']], un musicien et poète, originaire de la cité de [[w:Gortyne|''Gortyne'']] en ''Crète'', et actif à la fin du [[w:VIIIe_siècle_av._J.-C.|VIII<sup>ème</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]] et au début du siècle suivant.'''<br/><br/></div> {{Boîte déroulante fin}} === [[w:Vies_parallèles|Vies parallèles]] [[#Vies_parallèles|<span id="Vies_parallèles_back"><sup>'''I'''</sup></span>]] === <div style="text-align: center; margin: 0 1em;">Recueil de 50 biographies de grands hommes de l’histoire, dont 46 présentées par paires : un ''Grec'' mis en parallèle avec un ''Romain'' [https://books.google.fr/books?id=qfl1xwEACAAJ&lpg=PA1059&hl=fr&pg=PA1115#v=onepage&f=false {{info|<sup>🔍</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume Vb, §210 - Plutarque de Chéronée, pp.1115 - 1119, (7) Le Moraliste et l’entreprise des Vies Parallèles}}]. {{Boîte déroulante début|titre=NdA Vies parallèles|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Vies_parallèles_back|<span id="Vies_parallèles"><sup>I</sup></span>]] En grec ancien Βίοι Παράλληλοι / Bíoi Parállêloi :<br /><p style="margin: 0 2em; text-indent: 15px;">➥ Du nom commun βῐ́ος / bĭ́os [[wikt:en:βίος#Ancient_Greek|(en)]], « Vie (souvent avec une connotation positive : la vie heureuse) » ;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ De l’adjectif πᾰρᾰ́λληλος / părắllēlos [[wikt:en:παράλληλος#Ancient_Greek|(en)]], « 1. À côté l’un de l’autre, côte à côte. 2. Parallèle à ou avec. 3. Pléonastique, redondant.<br /><p style="margin: 0 2em; text-indent: 30px;">➥ du préfixe παρα- / para- [[wikt:en:παρα-#Ancient_Greek|(en)]], « 1. À côté. 2. Contrairement à. » ;<br /><p style="margin: 0 2em; text-indent: 45px;">➥ de la préposition πᾰρᾰ́ / părắ [[wikt:en:παρά#Ancient_Greek|(en)]], « 1. [avec génitif] : • De ; • À cause de. 2. [avec datif] : • À, à côté de, près de. 3. [avec accusatif] : • Contraire à ; • À côté de, près de (avec les verbes de venir ou d’aller ; avec les verbes de mouvement passé ; avec les verbes de frapper ou de blesser) » ;<br /><p style="margin: 0 2em; text-indent: 30px;">➥ +‎ du pronom ᾰ̓λλήλων / ăllḗlōn [[wikt:en:ἀλλήλων#Ancient_Greek|(en)]], « Se rapportant à un sujet pluriel et exprimant une action bilatérale : l’un de l’autre, l’un à l’autre, l’un l’autre, l’un l’autre, mutuellement, réciproquement. » ;<br /><p style="margin: 0 2em; text-indent: 45px;">➥ À partir d’expressions telles que ᾰ̓́λλος ᾰ̓́λλον / ắllos ắllon, ᾰ̓́λλοι ᾰ̓́λλους / ắlloi ắllous, « les uns les autres », avec perte de λ soit par dissimilation, soit par allongement de α, ainsi que restauration de la deuxième voyelle initiale ή / ḗ.'''<br/><br/></div> {{Boîte déroulante fin}} ==== Vie de [[w:Solon|'''Solon''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Solon|<sup>🔄</sup>]] ==== <div style="text-align: center; margin: 0 1em;">Biographie de '''Solon''', qui précède celle de [[w:Publius_Valerius_Publicola_(consul_en_-509)|'''Publicola''']] [[#Publicola|<span id="Publicola_back"><sup>'''I'''</sup></span>]], et avec laquelle '''Plutarque''' la compare.</div> {{Boîte déroulante début|titre=NdA Vie de Solon|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Publicola_back|<span id="Publicola"><sup>I</sup></span>]] [[w:Nom_romain|Tria Nomina]] en latin {{Info|Publius|praenomen, nom individuel du citoyen romain}} {{Info|Valerius|nomen, nom de famille}} {{Info|Publicola ou Poplicola|cognomen, surnom héréditaire, servant à distinguer les diverses branches d’une même gens}}, « celui qui prend soin de l’armée. »[https://academic.oup.com/bics/advance-article/doi/10.1093/bics/qbaf002/8117642?login=false {{Info|<sup>🔍</sup>|M. Gallo, « Misinterpreting a compound name. The origin of the agnomen Publicola in Dionysius of Halicarnassus and Plutarch », Bulletin of the Institute of Classical Studies,‎ 22 avril 2025}}].<br /><p style="margin: 0 2em; text-indent: 15px">[[w:Consul_(Rome_antique)|Consul]] de la [[w:république_romaine|''République Romaine'']], à quatre reprises : en [[w:-509|-509]], [[w:-508|-508]], [[w:-507|-507]] et [[w:-504|-504]], et l’un des instaurateurs légendaires de la ''République Romaine'' en -509, suite au viol et au suicide de [[w:Lucrèce_(dame_romaine)|Lucrèce]], une femme aristocratique ''romaine'', par [[w:Sextus_Tarquin|Sextus Tarquin]], le fils du dernier [[w:Roi_de_Rome|roi de ''Rome'']] [[w:Tarquin_le_Superbe|Tarquin le Superbe]].<br /><p style="text-align: right; margin: 0 2em;">(date et lieu de naissance inconnu.e.s — [[w:-503|-503]], soit sur le champ de bataille pendant les [[w:Guerres_romano-sabelliennes|''guerres romano-sabelliennes'']], soit de maladie)<sup>[[w:VIe_siècle_av._J.-C.|⏳]]</sup> '''<br/><br/></div> {{Boîte déroulante fin}} ===== <div style="text-align: center;">Chapitre II.</div> ===== ====== <div style="text-align: center;">Paragraphe III.</div> ====== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage de '''Thalès''' ''commerçant''.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''III.''' Κωλύει δὲ οὐδὲν τὸν ἀγαθὸν καὶ πολιτικὸν ἄνδρα μήτε τῶν περιττῶν τὴν κτῆσιν ἐν σπουδῇ τίθεσθαι μήτε τῆς χρείας τῶν ἀναγκαίων καὶ ἱκανῶν καταφρονεῖν. Ἐν δὲ τοῖς τότε χρόνοις, καθ' Ἡσίοδον, ἔργον οὐδὲν ἦν ὄνειδος, οὐδὲ τέχνη διαφορὰν ἔφερεν, ἐμπορία δὲ καὶ δόξαν εἶχεν οἰκειουμένη τὰ βαρβαρικὰ καὶ προξενοῦσα φιλίας βασιλέων καὶ πραγμάτων ἐμπείρους ποιοῦσα πολλῶν. Ἔνιοι δὲ καὶ πόλεων οἰκισταὶ γεγόνασι μεγάλων, ὡς καὶ Μασσαλίας Πρῶτις ὑπὸ Κελτῶν τῶν περὶ τὸν Ῥοδανὸν ἀγαπηθείς. Καὶ Θαλῆν δέ φασιν ἐμπορίᾳ χρήσασθαι καὶ Ἱπποκράτην τὸν μαθηματικόν, καὶ Πλάτωνι τῆς ἀποδημίας ἐφόδιον ἐλαίου τινὸς ἐν Αἰγύπτῳ διάθεσιν γενέσθαι.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://remacle.org/bloodwolf/historiens/Plutarque/solon.htm <u>Plutarque, Vie de Solon</u>], ''chap. II'', ''§3'', traduction par [[w:Dominique_Ricard|Dominique Ricard]], 1844<br />(également disponible une édition de 1853 [https://remacle.org/bloodwolf/historiens/Plutarque/solonpierrron.htm ici] et de 1862 [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f16.item là])</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 390px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''III.''' Mais rien n’empêche l’homme de bien, le citoyen dévoué à son pays, de garder un juste milieu : il peut ne point s’attacher à la poursuite du superflu, sans pour cela mépriser le nécessaire et ce qui suffit à ses besoins.<br />Dans ce temps-là, pour parler comme [[w:Hésiode|'''Hésiode''']] [[#Hésiode|<span id="Hésiode_back"><sup>'''I'''</sup></span>]] [[#Hésiode_NdT_AP|<span id="Hésiode_NdT_AP_back"><sup>1</sup></span>]], il n’y avait pas de travail qui fût honteux; aucun art ne mettait de différence entre les hommes : le négoce surtout était honoré, qui met en possession des avantages dont jouissent les étrangers, gagne l’amitié des rois, et donne une grande expérience. On a même vu des trafiquants fonder de grandes villes : ainsi [[w:Mythe_fondateur_de_Marseille|'''Protis''']] bâtit [[w:Marseille_antique|''Marseille'']], après s'être concilié l’amitié des ''Gaulois'' qui habitent les bords du [[w:Rhône#Histoire|''Rhône'']]. '''Thales''' se livra, dit-on, au négoce, ainsi qu’[[w:Hippocrate_de_Chios|'''Hippocrate''']] [[#Hippocrate|<span id="Hippocrate_back"><sup>'''II'''</sup></span>]] le mathématicien[[#Hippocrate_NdT_AP|<span id="Hippocrate_NdT_AP_back"><sup>2</sup></span>]] ; et [[w:Platon|'''Platon''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Platon|<sup>🔄</sup>]] vendit de l’huile en [[w:Basse_Époque|''Égypte'']] , pour fournir aux frais de son voyage.</div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Hésiode_NdT_AP_back|<span id="Hésiode_NdT_AP"><sup>1.</sup></span>]] Œuvres et Jours, vers 309.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Hippocrate_NdT_AP_back|<span id="Hippocrate_NdT_AP"><sup>2</sup></span>]] Cet Hippocrate n’est point connu d’ailleurs.''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/viesdeshommesill01plut/page/n6/mode/1up?view=theater <u>Vie des Hommes Illustres de Plutarque</u>], [https://archive.org/details/viesdeshommesill01plut/page/182/mode/1up?view=theater ''Solon''], ''Chap. II'', ''§3'', [https://archive.org/details/viesdeshommesill01plut/page/184/mode/1up?view=theater p.184], traduit par [[w:Alexis_Pierron|Alexis Pierron]], professeur au lycée Louis-le-Grand, 1877<br />(également disponible une édition de 1853 [[s:Vies_des_hommes_illustres/Solon|ici]])</div> {{Boîte déroulante début|titre=NdA trad. par Alexis Pierron de 1877|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Hésiode_back|<span id="Hésiode"><sup>I</sup></span>]] Du nom propre grec ancien Ἡσῐ́οδος / Hēsĭ́odos [[wikt:en:Ἡσίοδος#Ancient_Greek|(en)]].<br /><p style="margin: 0 2em; text-indent: 15px">Berger sur les pentes du Mont [[w:Mont_Hélicon|Hélicon]] et un des plus grands poètes grecs. Il s’agit plus précisément d’un ''aède'' (il « chante » ses vers avec sa lyre) et un ''rhapsode'' (il « coud » des chants entre eux)[https://odysseum.eduscol.education.fr/hesiode-un-des-premiers-poetes-grecs {{Info|<sup>🔍</sup>|Hésiode, un des premiers poètes grecs - Odysseum, la maison numérique des Humanités}}]. <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Hippocrate_back|<span id="Hippocrate"><sup>II</sup></span>]] Du nom propre grec ancien Ῐ̔πποκρᾰ́της / Hĭppokrắtēs [[wikt:en:Ἱπποκράτης#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px">➥ du nom commun ῐ̔́ππος / hĭ́ppos [[wikt:en:ἵππος#Ancient_Greek|(en)]], « cheval »;<br /><p style="margin: 0 2em; text-indent: 15px">➥ + du nom commun‎ κρᾰ́τος / krắtos [[wikt:en:κράτος#Ancient_Greek|(en)]], « 1. Puissance, force. 2. Acte de force, acte de bravoure. 3. (au pluriel) Actes de violence. 4. Domination, pouvoir. »;<br /><p style="margin: 0 2em; text-indent: 15px">➥ +‎ du suffixe nominal -ης / -ēs.<br /><p style="margin: 0 2em; text-indent: 15px"> Mathématicien (géomètre) et astronome « para-pythagoricien », dont l’œuvre ne nous est pas parvenue.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] milieu du [[w:Ve_siècle_av._J.-C.|V<sup>ème</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]]) [https://books.google.fr/books?id=DrvWAAAAMAAJ&newbks=1&newbks_redir=0&lpg=PA764&vq=Hippocrate&dq=bibliogroup%3A%22Dictionnaire%20des%20philosophes%20antiques%22&hl=fr&pg=PA764#v=onepage&q&f=true {{Info|<sup>🔍</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume III, §151 - Hippocrate de Chios}}]'''<br/><br/></div> {{Boîte déroulante fin}} <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: center; margin: 0 2em;">'''II. Dans sa jeunesse il se livre au commerce maritime; la modicité de sa fortune et son goût pour la sagesse l’y décident. Faveur du commerce à cette époque ; grands noms qui l’ont illustré.'''<br /><br /><p style="text-align: justify; text-indent: 15px;">Mais rien n’empêche qu’un homme de bien, un sage politique tienne à cet égard un juste milieu, et que sans rechercher des richesses superflues, il ne méprise pas celles qui sont nécessaires et qui suffisent. Dans ce temps-là, comme dit [[w:Hésiode|'''Hésiode''']], aucun travail n’était regardé comme honteux; aucun art ne mettait de différence entre les hommes. Le commerce maritime surtout était honorable; il ouvrait des communications utiles avec les nations étrangères, procurait des alliances avec les rois, et donnait une grande expérience. On a même vu des commerçants fonder de grandes villes. Ainsi '''Protus''' gagna l’amitié des Gaulois qui habitaient les bords du ''Rhône'', et bâtit ''Marseille''. '''Thalès''' et '''Hippocrate''' le mathématicien firent aussi le commerce ; et '''Platon''' vendit de l’huile en ''Égypte'' pour fournir aux frais de son voyage.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f7.item <u>Plutarque, Vie de Solon</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f16.item ''chap. II''], traduction correcte et précédée du texte grec, par une société de professeurs et d’helléniste, 1862<br />(également disponible une édition de 1844 [https://remacle.org/bloodwolf/historiens/Plutarque/solon.htm#1a ici] et de 1829 [[s:Les_Vies_des_hommes_illustres/Vie_de_Solon|là]])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Mais rien n’empêche l’homme de-bien et l’homme politique ni se mettre en souci (rechercher) l’acquisition des choses superflues, ni mépriser l’usage des choses nécessaires et suffisantes. Or dans les temps d’alors, selon '''Hésiode''', aucun travail n’était sujet-de-honte, ni aucun métier n’apportait de différence entre les citoyens mais même le commerce-maritime avait de la gloire, rendant-amies les nations-barbares, et procurant des amitiés de rois, et faisant les hommes expérimentés d’affaires nombreuses. Et quelques-uns aussi sont devenus fondateurs de grandes villes, comme aussi le '''Protus''' de ''Marseille'' ayant été aimé par les ''Celtes'' ceux autour du ''Rhône''. Et on dit aussi '''Thalès''', avoir fait-usage du commerce-maritime et '''Hippocrate''' le mathématicien, et la vente d'une certaine huile en ''Égypte'' avoir été pour '''Platon''' ressource du voyage.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f7.item <u>Plutarque, Vie de Solon</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f16.item ''chap. II''], traduction littérale et juxtalinéaire présentant le mot à mot français en regard des mots grecs correspondants, par une société de professeurs et d’helléniste, 1862</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ====== <div style="text-align: center;">Paragraphe IV.</div> ====== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage de la sagesse de '''Thalès''' en ''philosophie naturelle''</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''IV.''' Φιλοσοφίας δὲ τοῦ ἠθικοῦ μάλιστα τὸ πολιτικόν, ὥσπερ οἱ πλεῖστοι τῶν σοφῶν, ἠγάπησεν. Ἐν δὲ τοῖς φυσικοῖς ἁπλοῦς ἐστι λίαν καὶ ἀρχαῖος, ὡς δῆλον ἐκ τούτων· [...].<br /><p style="text-indent: 15px">Καὶ ὅλως ἔοικεν ἡ Θάλεω μόνου σοφία τότε περαιτέρω τῆς χρείας ἐξικέσθαι τῇ θεωρίᾳ· τοῖς δὲ ἄλλοις ἀπὸ τῆς πολιτικῆς ἀρετῆς τοὔνομα τῆς σοφίας ὑπῆρξε.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://remacle.org/bloodwolf/historiens/Plutarque/solon.htm <u>Plutarque, Vie de Solon</u>], ''chap. II'', ''§4'', traduction par [[w:Dominique_Ricard|Dominique Ricard]], 1844<br />(également disponible une édition de 1853 [https://remacle.org/bloodwolf/historiens/Plutarque/solonpierrron.htm ici] et de 1862 [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f20.item là])</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 390px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''IV.''' Il s’attacha, comme presque tous les sages d’alors, à cette partie de la philosophie morale qui traite de la politique. Pour la philosophie naturelle, il en était aux rudiments, et aux notions du vieux temps sans plus; [...].<br /><p style="text-indent: 15px;">Aussi bien n’y eut-il, en somme, que '''Thalès''' dont la science dépassât alors les notions d’un usage vulgaire : tous les autres ne durent qu’à leurs connaissances politiques leur réputation de sagesse.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/viesdeshommesill01plut/page/n6/mode/1up?view=theater <u>Vie des Hommes Illustres de Plutarque</u>], [https://archive.org/details/viesdeshommesill01plut/page/182/mode/1up?view=theater ''Solon''], ''Chap. II'', ''§4'', [https://archive.org/details/viesdeshommesill01plut/page/185/mode/1up?view=theater p.185], traduit par [[w:Alexis_Pierron|Alexis Pierron]], professeur au lycée Louis-le-Grand, 1877<br />(également disponible une édition de 1853 [[s:Vies_des_hommes_illustres/Solon|ici]])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">A l’exemple des sages de son temps, il cultiva principalement cette partie de la morale qui traite de la politique. Il n’avait en physique que des connaissances très-superficielles, et en était aux premiers éléments de cette science, [...].<br/><p style="text-indent: 15px">En général '''Thalès''' fut, de tous les sages d’alors, le seul qui porta au delà des besoins de la vie la théorie des sciences ; tous les autres ne durent qu’à leurs connaissances politiques leur réputation de sagesse.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f7.item <u>Plutarque, Vie de Solon</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f20.item ''chap. II''], traduction correcte et précédée du texte grec, par une société de professeurs et d’helléniste, 1862<br />(également disponible une édition de 1844 [https://remacle.org/bloodwolf/historiens/Plutarque/solon.htm#1a ici] et de 1829 [[s:Les_Vies_des_hommes_illustres/Vie_de_Solon|là]])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Mais de la partie morale de la philosophie il embrassa surtout la partie politique, comme la plupart des sages d’alors. Mais dans les sciences physiques il est extrêmement simple (ignorant) et primitif, [...]. Et en-un-mot la science de '''Thalès''' seul paraît s’être avancée alors par la théorie plus loin que le besoin ; et le nom de la science a appartenu aux autres par-suite des qualités politiques.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f7.item <u>Plutarque, Vie de Solon</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f21.item ''chap. II''], traduction littérale et juxtalinéaire présentant le mot à mot français en regard des mots grecs correspondants, par une société de professeurs et d’helléniste, 1862</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ====== <div style="text-align: center;">Paragraphe V.</div> ====== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Version alternative du récit de la coupe de [[w:Bathyclès_de_Magnésie|'''Bathyclès''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Bathyclès_back|<sup>🔄</sup>]] par [[w:Callimaque_de_Cyrène|'''Callimaque''']] de [[w:Cyrène|''Cyrène'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Callimaque_back|<sup>🔄</sup>]].</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''V.''' Γενέσθαι δὲ μετ' ἀλλήλων ἔν τε Δελφοῖς ὁμοῦ λέγονται καὶ πάλιν ἐν Κορίνθῳ, Περιάνδρου σύλλογόν τινα κοινὸν αὐτῶν καὶ συμπόσιον κατασκευάσαντος. Ἔτι δὲ μᾶλλον εἰς ἀξίωμα καὶ δόξαν αὐτοὺς κατέστησεν ἡ τοῦ [[w:τρίπους#Grec_ancien|'''τρίποδος''']] περίοδος καὶ διὰ πάντων ἀνακύκλησις καὶ ἀνθύπειξις μετ' εὐμενείας φιλοτίμου γενομένη. Κῴων γάρ, ὥς φασι, καταγόντων σαγήνην, καὶ ξένων ἐκ Μιλήτου πριαμένων τὸν βόλον οὔπω φανερὸν ὄντα, χρυσοῦς ἐφάνη τρίπους ἑλκόμενος, ὃν λέγουσιν Ἑλένην πλέουσαν ἐκ Τροίας αὐτόθι καθεῖναι χρησμοῦ τινος ἀναμνησθεῖσαν παλαιοῦ. Γενομένης δὲ τοῖς ξένοις πρῶτον ἀντιλογίας πρὸς τοὺς ἁλιέας περὶ τοῦ τρίποδος, εἶτα τῶν πόλεων ἀναδεξαμένων τὴν διαφορὰν ἄχρι πολέμου προελθοῦσαν, ἀνεῖλεν ἀμφοτέροις ἡ Πυθία τῷ σοφωτάτῳ τὸν τρίποδα ἀποδοῦναι. Καὶ πρῶτον μὲν ἀπεστάλη πρὸς Θαλῆν εἰς Μίλητον, ἑκουσίως τῶν Κῴων ἑνὶ δωρουμένων ἐκείνῳ περὶ οὗ πρὸς ἅπαντας ὁμοῦ Μιλησίους ἐπολέμησαν. Θάλεω δὲ Βίαντα σοφώτερον ἀποφαίνοντος αὑτοῦ πρὸς ἐκεῖνον ἧκεν· ἀπ' ἐκείνου δ' αὖθις ἀπεστάλη πρὸς ἄλλον ὡς σοφώτερον. Εἶτα περιϊὼν καὶ ἀναπεμπόμενος οὕτως ἐπὶ Θαλῆν τὸ δεύτερον ἀφίκετο, καὶ τέλος εἰς Θήβας ἐκ Μιλήτου κομισθεὶς τῷ Ἰσμηνίῳ Ἀπόλλωνι καθιερώθη. Θεόφραστος δέ φησι,πρῶτον μὲν εἰς Πριήνην Βίαντι τὸν τρίποδα πεμφθῆναι, δεύτερον δ' εἰς Μίλητον Θαλῇ Βίαντος ἀποπέμψαντος· οὕτω δὲ διὰ πάντων πάλιν εἰς Βίαντα περιελθεῖν, τέλος δὲ εἰς Δελφοὺς ἀποσταλῆναι. Ταῦτα μὲν οὖν ὑπὸ πλειόνων τεθρύληται, πλὴν ὅτι τὸ δῶρον ἀντὶ τοῦ τρίποδος οἱ μὲν φιάλην ὑπὸ Κροίσου πεμφθεῖσαν, οἱ δὲ ποτήριον Βαθυκλέους ἀπολιπόντος εἶναι λέγουσιν.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://remacle.org/bloodwolf/historiens/Plutarque/solon.htm <u>Plutarque, Vie de Solon</u>], ''chap. II'', ''§5'', traduction par [[w:Dominique_Ricard|Dominique Ricard]], 1844<br />(également disponible une édition de 1853 [https://remacle.org/bloodwolf/historiens/Plutarque/solonpierrron.htm ici] et de 1862 [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f22.item là])</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 390px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''V.''' On raconte que les sept sages se réunirent une fois à [[w:Delphes|''Delphes'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Delphes_back|<sup>🔄</sup>]], et une autre fois à [[w:Histoire_de_Corinthe_dans_l%27Antiquité|''Corinthe'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Corinthe_back|<sup>🔄</sup>]], où [[w:Périandre|'''Périandre''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Périandre_back|<sup>🔄</sup>]] les avait convoqués pour leur offrir un banquet. Rien ne contribua tant à leur réputation et à leur gloire, que le renvoi qu’ils se firent successivement l’un à l’autre du trépied d’or, et l’honorable humilité avec laquelle ils refusèrent le prix tour à tour. Des hommes de [[w:Kos_(Dodécanèse)#Kos_à_l'époque_hellénistique|''Cos'']] [[#Cos|<span id="Cos_back"><sup>'''I'''</sup></span>]] venaient, dit-on, de jeter leur filet en mer : des étrangers de ''Milet'' achetèrent le coup, avant que les pêcheurs y eussent regardé. Il se trouva, dans le filet, un trépied d’or qu’[[w:Hélène_(mythologie)|'''Hélène''']] [[#Hélène|<span id="Hélène_back"><sup>'''II'''</sup></span>]], à ce qu’on prétend, pour obéir à un ancien oracle, avait jeté dans la mer à son retour de [[w:Troie|''Troie'']] [[#Troie|<span id="Troie_back"><sup>'''III'''</sup></span>]]. Ce fut un sujet de débat, d’abord entre les pêcheurs et les étrangers, ensuite entre les deux villes, qui prirent parti dans la querelle : la guerre allait s’allumer, lorsque la [[w:Pythie|''Pythie'']] [[#Pythie|<span id="Pythie_back"><sup>'''IV'''</sup></span>]], que les deux partis avaient consultée, commanda de donner le trépied au plus sage. On l’envoya d’abord à ''Milet'', pour '''Thalès''', et ceux de ''Cos'' cédèrent sans peine à un seul particulier ce qu’ils allaient disputer par les armes à tous les ''Milésiens'' ensemble. '''Thalès''' déclara que [[w:Bias_de_Priène|'''Bias''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Bias_back|<sup>🔄</sup>]] était plus sage que lui, et le lui fit passer. '''Bias''', avec la même modestie, le fit passer à un autre; et le trépied, après avoir été envoyé successivement à tous les sept, revint une seconde fois à '''Thalès'''. Enfin, il fut transporté de ''Milet'' à [[w:Thèbes_(Grèce)|''Thèbes'']] [[#Thèbes|<span id="Thèbes_back"><sup>'''V'''</sup></span>]], et consacré à Apollon [[w:en:Ismenus|''Isménien'']]. Cependant [[w:Théophaste|'''Théophaste''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Théophaste_back|<sup>🔄</sup>]] dit qu’on envoya le trépied d’abord à '''Bias''', dans ''Priène'' ; que '''Bias''' le fit porter à '''Thalès''' ; qu’après avoir passé alternativement chez tous les sages, il revint à '''Bias''', et qu’il finit par être envoyé à ''Delphes''. Telle est la tradition commune : seulement quelques-uns prétendent qu’il s’agissait de décerner non point un trépied, mais un vase que [[w:Crésus|'''Crésus''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Crésus_back|<sup>🔄</sup>]] avait envoyé ; et, suivant d’autres, c’était une coupe, héritage de '''Bathyclès'''.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/viesdeshommesill01plut/page/n6/mode/1up?view=theater <u>Vie des Hommes Illustres de Plutarque</u>], [https://archive.org/details/viesdeshommesill01plut/page/182/mode/1up?view=theater ''Solon''], ''Chap. II'', ''§5'', [https://archive.org/details/viesdeshommesill01plut/page/185/mode/1up?view=theater p.185], traduit par [[w:Alexis_Pierron|Alexis Pierron]], professeur au lycée Louis-le-Grand, 1877<br />(également disponible une édition de 1853 [[s:Vies_des_hommes_illustres/Solon|ici]])</div> {{Boîte déroulante début|titre=NdA trad. par Alexis Pierron de 1877|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Cos_back|<span id="Cos"><sup>I</sup></span>]] Du nom propre grec ancien Κῶς / Kôs [[wikt:en:Κῶς#Ancient_Greek|(en)]] ;<br /><p style="margin: 0 2em; text-indent: 15px">Île grecque l’archipel du [[w:Dodécanèse|''Dodécanèse'']], au Sud-Est de la [[w:Mer_Égée|''mer Égée'']], au large des côtes ''turques''. <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Hélène_back|<span id="Hélène"><sup>II</sup></span>]] Du nom propre grec ancien Ἑλένη / Helénē [[wikt:en:Ἑλένη#Ancient_Greek|(en)]] ;<br /><p style="margin: 0 2em; text-indent: 15px">Fille de [[w:Zeus|Zeus]] et de [[w:Léda (mythologie)|Léda]], considérée comme la plus belle femme du monde, uniquement surpassée par la déesse [[w:Aphrodite|Aphrodite]]. Elle est mariée à [[w:Ménélas|Ménélas]], roi de [[w:Sparte|Sparte]], et est enlevée par [[w:Pâris|Pâris]], prince [[w:Troie|''troyen'']] [[#Troie|<sup>'''III'''</sup>]], ce qui déclencha la [[w:guerre de Troie|guerre de Troie]] qui opposa ''Grecs'' et ''Troyens''. <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Troie_back|<span id="Troie"><sup>III</sup></span>]] Du nom propre grec ancien Τροίᾱ / Troíā [[wikt:en:Τροία#Ancient_Greek|(en)]] ; [[w:Troie#Toponymie|''toponymie incertaine'']] ;<br /><p style="margin: 0 2em; text-indent: 15px"> Cité semi-légendaire, située sur la colline d’''[[w:site archéologique de Troie|{{lang|tr|Hisarlık}}]]'', à l’entrée de l’''[[w:Hellespont|Hellespont]]'', non loin de la ''[[w:mer Égée|mer Égée]]'', au nord-ouest de la ''péninsule anatolienne'', dans la région ''[[w:Troade|Troade]]'' en ''[[w:Asie Mineure|Asie Mineure]]''.<br /><p style="margin: 0 2em; text-indent: 15px"> Le site a fait l’objet de nombreuses campagnes de fouilles, à la suite de celles entreprises par [[w:Heinrich Schliemann|Heinrich Schliemann]] en 1870, ponctuées par des découvertes fortement médiatisées, qui ont popularisé son identification avec la Troie homérique (qui reste un sujet de débat en l’absence de preuve décisive), le lieu principal des événements du ''[[w:cycle troyen|cycle troyen]]'' rapportés dans les ''[[w:Épopée|poèmes épiques]]'' ''[[w:Homère|homériques]]'' l’''[[w:Iliade|Iliade]]'' et l’''[[w:Odyssée|Odyssée]]''. <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Pythie_back|<span id="Pythie"><sup>IV</sup></span>]] Du nom commun grec ancien Πῡθῐ́ᾱ / Pūthĭ́ā,<br /><p style="margin: 0 2em; text-indent: 15px">➥ du nom propre Πῡθώ / Pūthṓ, « [[w:Delphes#Histoire_du_site|''Pythô'']], ancien nom de ''Delphes'' » ;<br /><p style="margin: 0 2em; text-indent: 15px">➥ +‎ du suffixe adjectival féminin -ῐος / -ĭos [[wikt:en:-ιος#Ancient_Greek|(en)]], « relatif à, appartenant à (de) ».<br /><p style="margin: 0 2em; text-indent: 15px">[[w:Divination_dans_la_Grèce_antique|''Oracle'']] du [[w:Temple_d%27Apollon_(Delphes)|''temple d’Apollon'']] à ''Delphes''.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:XIVe_siècle_av._J.-C.|XIV<sup>ème</sup>]]/[[w:VIIIe_siècle_av._J.-C.|VIII<sup>ème</sup>]] siècles {{Info|AEC|Avant l’Ère Commune}} — [[w:IVe_siècle_av._J.-C.|IV<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]]) <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Thèbes_back|<span id="Thèbes"><sup>V</sup></span>]] Du nom propre grec ancien Θῆβαι / Thêbai [[wikt:en:Θῆβαι#Ancient_Greek|(en)]], désigne indistinctement la cité ''grecque'' comme [[w:Thèbes_(Égypte)|celle ''égyptienne'']] ; mais leur étymologie diffère :<br /><p style="margin: 0 2em; text-indent: 15px;">➥ pour celle de la cité grecque, de l’[[w:Ionien-attique|''ionien-attique'']] Θήβη / Thḗbē ; du grec mycénien 𐀳𐀣 / te-qa (/Tʰēgʷā/) ;<br /><p style="margin: 0 2em; text-indent: 15px;">(➥ pour celle de la cité égyptienne, de l’égyptien démotique tꜣ-jpy, « Thèbes, littéralement "le temple" » ;<br /><p style="margin: 0 2em; text-indent: 30px;">➥ de l’article défini tꜣ [[wikt:en:tꜣ#Demotic_Egyptian|(en)]], « le/la » ;<br /><p style="margin: 0 2em; text-indent: 30px;">➥ + du nom propre et commun jpt [[wikt:en:jpt#Etymology_3|(en)]], « Louxor, littéralement "sanctuaire intérieur" »).<br /><p style="margin: 0 2em; text-indent: 15px">Cité grecque de la région de [[w:Béotie#Antiquité|''Béotie'']], au centre de la ''Grèce''.'''<br/><br/></div> {{Boîte déroulante fin}} <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">On raconte que les sept sages se trouvèrent un jour ensemble à ''Delphes'', et une autre fois à ''Corinthe'', chez '''Périandre''', qui les avait réunis pour un banquet. Rien ne contribua autant à leur réputation et à leur gloire, que la modestie empressée avec laquelle ils se renvoyèrent l’un à l’autre le trépied d’or. Des ''Milésiens'' qui se trouvaient à l’île de ''Cos'', avaient acheté d’avance de quelques pêcheurs ce que retirerait de l’eau le filet qu’ils allaient y jeter. Quand on l’eut tiré, il s’y trouva un trépied d’or qu’'''Hélène''', à ce qu’on prétend, pour obéir à un oracle, avait jeté dans la mer, à son retour de ''Troie''. Cet incident donna lieu à une vive dispute d’abord entre les pêcheurs et les étrangers, ensuite entre les deux villes, qui prirent parti dans la querelle et étaient près d’en venir aux mains, lorsque la ''Pythie'' consultée leur ordonna de porter ce trépied au plus sage. On l’envoya d’abord à '''Thalès''', et ceux de ''Cos'' cédèrent sans peine à un seul particulier ce qu’ils allaient disputer par les armes à tous les ''Milésiens'' ensemble. '''Thalès''' le renvoya à '''Bias''', qui, disait-il, était plus sage que lui ; '''Bias''', avec la même modestie, le fit passer à un autre ; et après avoir été envoyé successivement à tous les sept, il revint une seconde fois à '''Thalès''' : enfin il fut porté à ''Thèbes'', et consacré à ''Apollon Isménien''. '''Théophraste''' dit qu’on l’envoya d’abord à '''Bias''', qui demeurait à ''Priène'' ; que '''Bias''' le fit porter à '''Thalès''' ; qu’après avoir été envoyé alternativement à tous les sages, il revint à '''Bias''', et qu’enfin il fut porté à ''Delphes''. Telle est la tradition la plus commune sur ce fait ; seulement quelques auteurs disent que ce n’était pas un trépied, mais un vase que '''Crésus''' envoyait à ''Delphes''; suivant d’autres, c’était une coupe que '''Bathyclès''' avait laissée.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f7.item <u>Plutarque, Vie de Solon</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f22.item ''chap. II''], traduction correcte et précédée du texte grec, par une société de professeurs et d’helléniste, 1862<br />(également disponible une édition de 1844 [https://remacle.org/bloodwolf/historiens/Plutarque/solon.htm#1a ici] et de 1829 [[s:Les_Vies_des_hommes_illustres/Vie_de_Solon|là]])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Or ils (les sept sages) sont dits s’être trouvés aussi ensemble les uns avec les autres et à ''Delphes'' et de nouveau à ''Corinthe'', '''Périandre''' ayant préparé une certaine réunion commune d’eux et un banquet. Or le tour du trépied, et sa circulation à travers tous et sa cession se faisant avec une bienveillance pleine-d’émulation mit eux encore davantage en considération et renommée. Car des ''habitants-de-Cos'', comme on dit, jetant le filet, et des hôtes venus de ''Milet'' ayant acheté le coup qui n’était pas encore apparent, un trépied d’-or apparut étant retiré, lequel on dit '''Hélène''' naviguant pour revenir de ''Troie'' avoir jeté là, s’étant souvenue d’un certain oracle ancien. Mais une contestation ayant eu lieu d’abord aux hôtes vis-à-vis des pécheurs au sujet du trépied, ensuite les villes ayant pris-sur-elles le différend qui alla jusqu'à une guerre, la ''Pythie'' répondit aux-uns-et-aux-autres de donner le trépied au plus sage des hommes. Et d’abord il fut envoyé à '''Thalès''' à ''Milet'', les ''habitants-de-Cos'' donnant volontairement à celui-là seul le trépied, au sujet duquel ils avaient fait-la-guerre contre tous les ''Milésiens'' à-la-fois. Mais '''Thalès''' déclarant '''Bias''' plus sage que lui-même, il renvoya vers celui-là. Et de nouveau il fut envoyé par celui-là vers un autre, comme plus sage. Ensuite faisant-le-tour et étant envoyé-successivement ainsi il arriva pour la seconde fois à '''Thalès''' ; et à la fin transporté de ''Milet'' à ''Thèbes'', il fut consacré à ''Apollon Isménien''. Mais '''Théophraste''' dit le trépied avoir été envoyé d’abord à la vérité à ''Priène'' à '''Bias''', mais en-second-lieu à ''Milet'' à '''Thalès''', '''Bias''' l’ayant renvoyé ; et ainsi à travers tous (de l’un à l’autre) être venu-en-faisant-le-tour de nouveau à '''Bias''', et à la fin avoir été envoyé à ''Delphes''. Ces choses donc ont été répandues par plusieurs, excepté qu’ils disent le présent au lieu du trépied les uns être un vase à boire envoyé par '''Crésus''', les autres une coupe. '''Bathyclès''' rayant laissée (laissée par '''Bathyclès'''). </div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f7.item <u>Plutarque, Vie de Solon</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f23.item ''chap. II''], traduction littérale et juxtalinéaire présentant le mot à mot français en regard des mots grecs correspondants, par une société de professeurs et d’helléniste, 1862</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Chapitre VI.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;"> Récit d’une entrevue de '''Thalès''' avec '''Solon''', de son stoïcisme, de son célibat et de l’adoption du fils de sa sœur, '''Cybistus'''.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;"> '''VI.''' Ἰδίᾳ δ' Ἀναχάρσεώς τε πρὸς Σόλωνα καὶ πάλιν Θάλεω συνουσίαν τινὰ καὶ λόγους ἀναγράφουσι τοιούτους. [...]<br /><p style="text-indent: 15px"> '''VII.''' Πρὸς Θαλῆν δ' εἰς Μίλητον ἐλθόντα τὸν Σόλωνα θαυμάζειν ὅτι γάμου καὶ παιδοποιΐας τὸ παράπαν ἠμέληκε. Καὶ τὸν Θαλῆν τότε μὲν σιωπῆσαι, διαλιπόντα δ' ὀλίγας ἡμέρας ἄνδρα παρασκευάσαι ξένον, ἀρτίως ἥκειν φάσκοντα δεκαταῖον ἐξ Ἀθηνῶν. Πυθομένου δὲ τοῦ Σόλωνος εἰ δή τι καινὸν ἐν ταῖς Ἀθήναις, δεδιδαγμένον ἃ χρὴ λέγειν τὸν ἄνθρωπον, « οὐδέν,» εἰπεῖν, « ἕτερον, εἰ μὴ νὴ Δία νεανίσκου τινὸς ἦν ἐκφορὰ καὶ προὔπεμπεν ἡ πόλις. Ἦν γὰρ υἱός, ὡς ἔφασαν, ἀνδρὸς ἐνδόξου καὶ πρωτεύοντος ἀρετῇ τῶν πολιτῶν· οὐ παρῆν δέ, ἀλλ' ἀποδημεῖν ἔφασαν αὐτὸν ἤδη πολὺν χρόνον.» « Ὡς δυστυχὴς ἐκεῖνος,» φάναι τὸν Σόλωνα. « Τίνα δὲ ὠνόμαζον αὐτόν;» « ἤκουσα,» φάναι, « τοὔνομα,» τὸν ἄνθρωπον, « ἀλλ' οὐ μνημονεύω· πλὴν ὅτι πολὺς λόγος ἦν αὐτοῦ σοφίας καὶ δικαιοσύνης.» Οὕτω δὴ καθ' ἑκάστην ἀπόκρισιν τῷ φόβῳ προσαγόμενον τὸν Σόλωνα καὶ τέλος ἤδη συντεταραγμένον αὐτὸν ὑποβάλλειν τοὔνομα τῷ ξένῳ, πυνθανόμενον μὴ Σόλωνος ὁ τεθνηκὼς υἱὸς ὠνομάζετο. Φήσαντος δὲ τοῦ ἀνθρώπου, τὸν μὲν ὁρμῆσαι παίειν τὴν κεφαλὴν καὶ τἆλλα ποιεῖν καὶ λέγειν ἃ συμβαίνει τοῖς περιπαθοῦσι, τὸν δὲ Θαλῆν ἐπιλαβόμενον αὐτοῦ καὶ γελάσαντα, « ταῦτά τοι,» φάναι, « ὦ Σόλων, ἐμὲ γάμου καὶ παιδοποιΐας ἀφίστησιν, ἃ καὶ σὲ κατερείπει τὸν ἐρρωμενέστατον. Ἀλλὰ θάρρει τῶν λόγων ἕνεκα τούτων· οὐ γάρ εἰσιν ἀληθεῖς.» ταῦτα μὲν οὖν Ἕρμιππος ἱστορεῖν φησι Πάταικον, ὃς ἔφασκε τὴν Αἰσώπου ψυχὴν ἔχειν.<br /><p style="text-indent: 15px">'''VIII.''' Ἄτοπος δὲ καὶ ἀγεννὴς ὁ τῷ φόβῳ τῆς ἀποβολῆς τὴν κτῆσιν ὧν χρὴ προϊέμενος· οὕτω γὰρ ἄν τις οὐ πλοῦτον, οὐ δόξαν, οὐ σοφίαν ἀγαπήσειε παραγενομένην, δεδιὼς στέρεσθαι. Καὶ γὰρ ἀρετήν, ἧς κτῆμα μεῖζον οὐδὲν οὐδ' ἥδιον, ἐξισταμένην ὑπὸ νόσων καὶ φαρμάκων ὁρῶμεν· αὐτῷ τε '''Θαλῇ''' μὴ γήμαντι πλέον οὐδὲν εἰς ἀφοβίαν, εἰ μὴ καὶ φίλων κτῆσιν ἔφυγε καὶ οἰκείων καὶ πατρίδος. Ἀλλὰ καὶ παῖδα θετὸν ἔσχε ποιησάμενος αὐτὸς τὸν τῆς ἀδελφῆς, ὥς φασι, '''Κύβισθον'''.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://remacle.org/bloodwolf/historiens/Plutarque/solon.htm <u>Plutarque, Vie de Solon</u>], ''chap. II'', ''§§6-8'', traduction par [[w:Dominique_Ricard|Dominique Ricard]], 1844<br />(également disponible une édition de 1853 [https://remacle.org/bloodwolf/historiens/Plutarque/solonpierrron.htm ici] et de 1862 [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f26.item là])</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 390px; border: 2px solid; text-indent: 15px"><br /><div style="margin: 0 2em; text-align: justify; direction: ltr;">'''VI.''' '''Solon''' connut [[w:Anacharsis|'''Anacharsis''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Anacharsis_back|<sup>🔄</sup>]] et '''Thalès''', et l’on cite des mots qui s’étaient dits dans leurs entrevues. <br /><p style="text-align: center"> [...]<br /><p style="text-indent: 15px; text-align: justify;">'''Solon''' alla à ''Milet'', pour voir '''Thalès''' : là, il lui témoigna sa surprise dans ce qu’il n’avait jamais voulu se marier et avoir des enfants. '''Thalès''' ne répondit rien sur l’heure; mais, quelques jours après, il fit paraître un étranger, qui disait arriver d’''Athènes'', et qu’il n’en était parti que depuis dix jours. '''Solon''' demanda à cet homme s’il n’y avait rien de nouveau à ''Athènes''. Celui-ci, à qui '''Thalès''' avait fait la leçon, répondit qu’il n’y avait rien de nouveau , sinon la mort d’un jeune homme dont toute la ville menait les funérailles. C’était, en effet, à ce qu’on disait, le fils d’un personnage considérable, d’une vertu éprouvée : le père n’était pas alors à ''Athènes'', et il voyageait depuis longtemps. « L’infortuné père! s’écria '''Solon'''. Mais comment s’appelait-il? — Je l’ai entendu nommer, répondit l’étranger, mais j’ai oublié son nom ; je me souviens seulement qu’on ne parlait que de sa sagesse et de sa justice. » A chacune de ces réponses, '''Solon''' sentait augmenter ses craintes; enfin, ne se possédant plus , il suggéra le nom à l’étranger, et lui demanda si le mort n’était pas le fils de '''Solon'''. « Oui. » répondit l’étranger. A cette parole, '''Solon''' se frappa la tête, et il se mit à faire et à dire tout ce qu’inspire une douleur violente. Alors '''Thalès''' lui prit la main, et lui dit en riant : « Voilà, '''Solon''', ce qui m’éloigne de me marier et d’avoir des enfants. J’ai redouté le coup sous lequel tu fléchis, toi le plus ferme des hommes. Mais rassure-toi; car il n’y a rien de vrai dans tout ce qu’on vient de te dire. » [[w:Hermippe_de_Smyrne|'''Hermippus''']] [[#Hermippe|<span id="Hermippe_back"><sup>'''I'''</sup></span>]] rapporte cette histoire d’après '''Patécus''', celui qui prétendait avoir hérité de l’âme d’[[w:Ésope|'''Ésope''']] [[#Ésope|<span id="Ésope_back"><sup>'''II'''</sup></span>]].<br /><p style="text-indent: 15px">Pourtant il y a faute de sens et de cœur à refuser d’acquérir les choses nécessaires, par la crainte de les perdre. A ce compte, on devra n’aimer ni la richesse, ni la gloire, ni la sagesse, quand on les possède, de peur d’en être privé. En effet, la vertu, le plus grand des biens et le plus doux, nous quitte quelquefois par l’action de certaines maladies ou de certains breuvages. '''Thalès''' lui-même, en ne se mariant point, n’était pas pour cela à l’abri de la crainte, à moins qu’il n'eût renoncé aussi à ses parents, à ses amis, à sa patrie. Mais il n’en était rien : il avait adopté, dit-on, '''Cybisthus''', le fils de sa sœur. </div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/viesdeshommesill01plut/page/n6/mode/1up?view=theater <u>Vie des Hommes Illustres de Plutarque</u>], [https://archive.org/details/viesdeshommesill01plut/page/182/mode/1up?view=theater ''Solon''], ''Chap. II'', ''§6'', [https://archive.org/details/viesdeshommesill01plut/page/185/mode/1up?view=theater p.185], traduit par [[w:Alexis_Pierron|Alexis Pierron]], professeur au lycée Louis-le-Grand, 1877<br />(également disponible une édition de 1853 [[s:Vies_des_hommes_illustres/Solon|ici]])</div> {{Boîte déroulante début|titre=NdA trad. par Alexis Pierron de 1877|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Hermippe_back|<span id="Hermippe"><sup>I</sup></span>]] Du nom propre [[w:Nom_théophore|''théophore'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#théophore_back|<sup>🔄</sup>]] grec ancien Ἕρμιππος / Hérmippos [[wikt:en:Ἕρμιππος#Ancient_Greek|(en)]] ;<br /><p style="margin: 0 2em; text-indent: 15px">➥ du nom propre Ἑρμῆς / Hermês [[wikt:en:Ἑρμῆς#Ancient_Greek|(en)]], « Hermès » ;<br /><p style="margin: 0 2em; text-indent: 15px">➥ +‎ du nom commun ἵππος / híppos [[wikt:en:ἵππος#Ancient_Greek|(en)]], « cheval » ;<br /><p style="margin: 0 2em; text-indent: 15px">« Péripatéticien » grec, disciple de [[w:Callimaque_de_Cyr%C3%A8ne|Callimaque de ''Cyrène'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Callimaque_back|<sup>🔄</sup>]], auteur de nombreuses biographies toutes perdues, mais listées par plusieurs auteurs.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] seconde moitié du [[w:IIIe_siècle_av._J.-C.|III<sup>ème</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]]) [https://books.google.fr/books?id=DrvWAAAAMAAJ&newbks=1&newbks_redir=0&lpg=PA497&dq=bibliogroup%3A%22Dictionnaire%20des%20philosophes%20antiques%22&hl=fr&pg=PA655#v=onepage&q&f=false {{Info|<sup>🔍</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume III, §86 - Hermippe de Smyrne}}] <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Ésope_back|<span id="Ésope"><sup>II</sup></span>]] Du nom propre grec ancien Αἴσωπος / Aísōpos [[wikt:en:Αἴσωπος#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px">➥ du nom commun αἶσα / aîsa, « destin »;<br /><p style="margin: 0 2em; text-indent: 15px">➥ +‎ du nom commun ὄψ / óps, « voix »;<br /><br /><p style="margin: 0 2em; text-indent: 15px">Auteur grec de fable.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] seconde moitié du [[w:VIe_siècle_av._J.-C.|VI<sup>ème</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]]) [https://books.google.fr/books?id=DrvWAAAAMAAJ&newbks=1&newbks_redir=0&lpg=PA497&dq=bibliogroup%3A%22Dictionnaire%20des%20philosophes%20antiques%22&hl=fr&pg=PA240#v=onepage&q&f=false {{Info|<sup>🔍</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume III, §60 - Ésope(Αἴσωπος)}}]'''<br/><br/></div> {{Boîte déroulante fin}} <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">'''V.''' Voici les particularités qu’on raconte d’une entrevue de '''Solon''' avec '''Anacharsis''', et d’un entretien qu’il eut avec '''Thalès'''.<br /><p style="text-align: center"> [...]<br /><p style="text-indent: 15px; text-align: justify;">'''VI.''' '''Solon''', étant allé à ''Milet'' pour voir '''Thalès''', lui témoigna sa surprise de ce qu’il n’avait jamais voulu se marier et avoir des enfants. '''Thalès''' ne lui répondit rien dans le moment; mais ayant laissé passer quelques jours, il fit paraître un étranger qui disait arriver d’''Athènes'', d’où il était parti depuis dix jours. '''Solon''' lui demanda s’il n’y avait rien de nouveau, lorsqu’il en était parti. Cet homme, à qui '''Thalès''' avait fait la leçon, lui répondit qu’il n’y avait autre chose que la mort d’un jeune homme dont toute la ville accompagnait le convoi. C’était, disait-on, le fils d’un des premiers et des plus vertueux citoyens, qui n'’était pas alors à ''Athènes'' et qui voyageait depuis longtemps, « Le malheureux père! s’écria Solon. Comment s’appelle-t-il? ― Je l’ai entendu nommer, répondit l’étranger; mais j’ai oublié son nom; je me souviens seulement qu’on ne parlait que de sa sagesse et de sa justice. » A chacune de ces réponses, les craintes de '''Solon''' augmentaient; enfin, troublé, hors de lui-même, il suggéra le nom à l’étranger, et lui demanda si ce jeune homme n’était pas le fils de '''Solon'''. « C’est lui-même, » dit l’autre. A cette parole, '''Solon''', se frappant la tête, se mit à faire et à dire tout ce que la douleur la plus violente peut inspirer. Alors '''Thalès''' l’arrêta et lui dit en souriant : « Voilà, '''Solon''', ce qui m’a éloigné de me marier et d’avoir des enfants; j’ai redouté le coup qui vous accable aujourd’hui, et contre lequel toute votre fermeté est impuissante. Mais rassurez-vous ; il n’y a rien de vrai dans tout ce qu’on vient de vous dire. » '''Hermippus''' rapporte cette histoire d’après le récit qu’en fait '''Patécus''', qui prétendait avoir hérité de l’âme d’'''Ésope'''.<br /><p style="text-indent: 15px; text-align: justify;">'''VII.''' Cependant c’est manquer de sens et de courage que de renoncer à acquérir des choses nécessaires par la crainte de les perdre. A ce compte, il ne faudrait aimer ni la richesse, ni la gloire, ni la sagesse, quand on les possède, de peur d’en être privé. La vertu même, le plus grand et le plus agréable des biens, se perd souvent par l’effet. de quelques maladies ou de certains breuvages. '''Thalès''' lui-même, en ne se mariant point, n’était pas à l’abri de toute crainte, à moins qu’il ne renonçât aussi à ses parents, à ses amis et à sa patrie. Mais au contraire, il avait adopté '''Cybistus''', le fils de sa sœur. </div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f7.item <u>Plutarque, Vie de Solon</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f26.item ''chap. II''], traduction correcte et précédée du texte grec, par une société de professeurs et d’helléniste, 1862<br />(également disponible une édition de 1844 [https://remacle.org/bloodwolf/historiens/Plutarque/solon.htm#1a ici] et de 1829 [[s:Les_Vies_des_hommes_illustres/Vie_de_Solon|là]])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">'''V.''' Mais en particulier on rapporte une certaine entrevue et de tels discours et d’'''Anacharsis''' à '''Solon''' et une-autre-fois de '''Thalès'''.<br /><p style="text-align: center"> [...]<br /><p style="text-indent: 15px; text-align: justify;">'''VI.''' Et on raconte '''Solon''' étant venu vers '''Thalès''' à ''Milet'' s’étonner de ce qu’il avait négligé absolument le mariage et la création-d’enfants. Et '''Thalès''' alors à la vérité s’être tu, mais ayant laissé-d’intervalle peu-de jours, avoir aposté un homme étranger, disant être arrivé récemment parti-depuis-dix-jours d’''Athènes''. Et '''Solon''' s’étant informé si donc il y a quelque chose de nouveau à ''Athènes'', l’homme instruit des choses qu’il faut dire n’avoir dit aucune autre chose, si ce n’est :<br /><p style="text-indent: 15px"> « Par '''Jupiter''', il y avait le convoi d’un certain jeune-homme, et la ville l’accompagnait. Car il était fils, comme on disait, d’un homme illustre et étant-le-premier des citoyens par la vertu; mais il n’était-pas-présent, mais on disait lui être-en-voyage depuis un temps déjà long.<br /><p style="text-align: left; text-indent: 15px">― Combien cet homme-là est malheureux! avoir dit '''Solon'''. Mais quel (comment) appelaient-ils lui ?<br /><p style="text-align: left; text-indent: 15px">― J’ai entendu le nom, avoir dit l’homme (répondit l’étranger), mais je ne me le rappelle pas; excepté qu’un discours fréquent était de la sagesse et de la justice de lui. »<br /><p style="text-indent: 15px">'''Solon''' donc étant-approché ainsi de-la crainte à chaque réponse, et à la fin déjà étant tout-troublé, lui-même avoir suggéré le nom à l’étranger, demandant si le mort n’était pas nommé fils de '''Solon'''. Et l’homme ayant dit-oui, celui-ci ('''Solon''') avoir commencé à frapper sa tête, et à faire et à dire les autres choses, qu’il arrive de faire et de dire à ceux affligés-à-l’excès. Mais '''Thalès''' ayant arrêté lui, et ayant ri, avoir dit :<br /><p style="text-indent: 15px">« Ces choses donc, ô '''Solon''', écartent moi du mariage et de la création-d’enfants, lesquelles abattent même toi le très-fort. Mais aie-confiance quant-à ces discours: car ils ne sont pas vrais. »<br /><p style="text-indent: 15px">'''Hermippe''' donc dit '''Patécus''', qui disait-souvent avoir l’âme d’'''Ésope''', raconter ces choses. <br /><p style="text-indent: 15px">'''VII.''' Or il est absurde et dépourvu de courage celui rejetant par la crainte de la perte l’acquisition des choses qu’il faut; car ainsi quelqu’un n’aimerait pas la richesse, n’aimerait pas la gloire, n’aimerait pas la sagesse étant survenue à lui, craignant (par crainte) d’en être privé. Et en effet nous voyons la vertu, au prix de laquelle aucune possession n’est plus grande, ni plus agréable, déplacée (chassée) par des maladies et des breuvages; et rien de plus n’être pour l’exemption-de-crainte à '''Thalès''' lui-même ne s’étant pas marié, s’il n’avait pas évité la possession et d’amis et de parents et de patrie. Mais même il eut un fils adoptif se l’étant fait tel lui-même, celui de sa sœur, comme on dit '''Cybisthe'''.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f7.item <u>Plutarque, Vie de Solon</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f27.item ''chap. II''], traduction littérale et juxtalinéaire présentant le mot à mot français en regard des mots grecs correspondants, par une société de professeurs et d’helléniste, 1862</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ====== <div style="text-align: center;">Paragraphe XV.</div> ====== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;"> Testament d’inhumation de '''Thalès'''.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''XV.''' Καὶ φόβοι τινὲς ἐκ δεισιδαιμονίας ἅμα καὶ φάσματα κατεῖχε τὴν πόλιν, οἵ τε μάντεις ἄγη καὶ μιασμοὺς δεομένους καθαρμῶν προφαίνεσθαι διὰ τῶν ἱερῶν ἠγόρευον. Οὕτω δὴ μετάπεμπτος αὐτοῖς ἧκεν ἐκ Κρήτης Ἐπιμενίδης ὁ Φαίστιος, ὃν ἕβδομον ἐν τοῖς σοφοῖς καταριθμοῦσιν ἔνιοι τῶν οὐ προσιεμένων τὸν Περίανδρον. Ἐδόκει δέ τις εἶναι θεοφιλὴς καὶ σοφὸς περὶ τὰ θεῖα τὴν ἐνθουσιαστικὴν καὶ τελεστικὴν σοφίαν, διὸ καὶ παῖδα νύμφης ὄνομα Βάλτης καὶ Κούρητα νέον αὐτὸν οἱ τότε ἄνθρωποι προσηγόρευον. <br /><p style="text-align: center">[...]<br /><p style="text-indent: 15px; text-align: justify;">Τὸ δὲ μέγιστον, ἱλασμοῖς τισι καὶ καθαρμοῖς καὶ ἱδρύσεσι κατοργιάσας καὶ καθοσιώσας τὴν πόλιν ὑπήκοον τοῦ δικαίου καὶ μᾶλλον εὐπειθῆ πρὸς ὁμόνοιαν κατέστησε. Λέγεται δὲ τὴν Μουνυχίαν ἰδὼν καὶ καταμαθὼν πολὺν χρόνον, εἰπεῖν πρὸς τοὺς παρόντας ὡς τυφλόν ἐστι τοῦ μέλλοντος ἄνθρωπος· ἐκφαγεῖν γὰρ ἂν Ἀθηναίους τοῖς αὑτῶν ὀδοῦσιν, εἰ προῄδεσαν ὅσα τὴν πόλιν ἀνιάσει τὸ χωρίον· ὅμοιον δέ τι καὶ Θαλῆν εἰκάσαι λέγουσι· κελεῦσαι γὰρ αὐτὸν ἔν τινι τόπῳ τῆς Μιλησίας φαύλῳ καὶ παρορωμένῳ τελευτήσαντα θεῖναι, προειπὼν ὡς ἀγορά ποτε τοῦτο Μιλησίων ἔσται τὸ χωρίον. Ἐπιμενίδης μὲν οὖν μάλιστα θαυμασθείς, καὶ χρήματα διδόντων πολλὰ καὶ τιμὰς μεγάλας τῶν Ἀθηναίων, οὐδὲν ἢ θαλλὸν ἀπὸ τῆς ἱερᾶς ἐλαίας αἰτησάμενος καὶ λαβὼν ἀπῆλθεν. </div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://remacle.org/bloodwolf/historiens/Plutarque/solon.htm <u>Plutarque, Vie de Solon</u>], ''chap. II'', ''§15'', traduction par [[w:Dominique_Ricard|Dominique Ricard]], 1844<br />(également disponible une édition de 1853 [https://remacle.org/bloodwolf/historiens/Plutarque/solonpierrron.htm ici] et de 1862 [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f26.item là])</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 390px; border: 2px solid; text-indent: 15px"><br /><div style="margin: 0 2em; text-align: justify; direction: ltr;">'''XV.''' Au chagrin que ces pertes causèrent à ceux-ci [les ''Athéniens''], se joignirent des craintes superstitieuses dont la ville [''Athènes''] fut frappée, et qui venaient d’apparitions de spectres et de fantômes. Les devins déclarèrent aussi que l’état des victimes qu’ils avaient offertes annonçait des crimes et des profanations qu’il fallait expier. On fit donc venir de ''Crète'' [[w:Épiménide|'''Épiménide''']] [[#Épiménide|<span id="Épiménide_back"><sup>'''I'''</sup></span>]] le [[w:Phaistos|''Phestien'']] [[#Phaistos|<span id="Phaistos_back"><sup>'''II'''</sup></span>]], qui est mis au nombre des sept sages par ceux qui n’y comptent pas '''Périandre'''. Il passait pour un homme chéri des dieux, doué d’une grande sagesse, fort instruit des choses divines, surtout versé dans la science des inspirations et dans la connaissance des mystères; on l’appelait, même de son vivant, le nouveau [[w:Curètes|'''Curète''']], le fils de la nymphe '''Balté'''.<br /><p style="text-align: center">[...]<br /><p style="text-indent: 15px; text-align: justify;">Mais ce qui était plus important, il fit un grand nombre d’expiations et de sacrifices, il fonda plusieurs temples; et par ces différentes cérémonies il purifia entièrement la ville, en bannit l’impiété et l’injustice, et la rendit plus soumise, plus disposée à l’union et à la paix. On rapporte aussi que lorsqu’il vit le fort de [[w:Munichie|''Munychium'']] [[#Munichie|<span id="Munichie_back"><sup>'''III'''</sup></span>]], il le considéra longtemps, et dit à ceux qui l’accompagnaient : Que les hommes sont aveugles sur l’avenir ! Si les ''Athéniens'' pouvaient prévoir tous les maux que ce lieu doit un jour causer à leur ville, ils l’emporteraient à belles dents ». '''Thalès''' eut aussi, dit-on, un pressentiment à peu près semblable. Il ordonna qu’on l’enterrât dans le lieu le plus sauvage et le plus désert du territoire de ''Milet''; et il prédit aux ''Milésiens'' qu’un jour leur marché public y serait transporté. Les ''Athéniens'', pleins de reconnaissance et d’admiration pour '''Épiménide''', voulurent le combler d’honneurs et de présents; mais il ne demanda qu’une branche de l’olivier sacré, qui lui fut accordée, et il s’en retourna en ''Crète''.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/viesdeshommesill01plut/page/n6/mode/1up?view=theater <u>Vie des Hommes Illustres de Plutarque</u>], [https://archive.org/details/viesdeshommesill01plut/page/182/mode/1up?view=theater ''Solon''], ''Chap. II'', ''§15'',[https://archive.org/details/viesdeshommesill01plut/page/185/mode/1up?view=theater p.185], traduit par [[w:Alexis_Pierron|Alexis Pierron]], professeur au lycée Louis-le-Grand, 1877<br />(également disponible une édition de 1853 [[s:Vies_des_hommes_illustres/Solon|ici]])</div> {{Boîte déroulante début|titre=NdA trad. par Alexis Pierron de 1877|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Épiménide_back|<span id="Épiménide"><sup>I</sup></span>]] Du nom propre grec ancien Ἐπιμενίδης / Epimenídēs [[wikt:en:Ἐπιμενίδης#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px">Poète, philosophe et [[w:Iatromante|''iatromante'']] crétois.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] milieu du [[w:VIe_siècle_av._J.-C.|VI<sup>ème</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]]) <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Phaistos_back|<span id="Phaistos"><sup>II</sup></span>]] Du nom propre grec ancien Φαιστός / Phaistós [[wikt:en:Φαιστός#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px">Ancienne ville du Sud de la [[w:Histoire_de_la_Crète#Antiquité|''Crète'']].<br /><br /><p style="margin: 0 2em; text-indent: 15px">[[#Munichie_back|<span id="Munichie"><sup>III</sup></span>]] Du nom propre grec ancien Μουνιχία / Mounikhia [[wikt:en:Μουνυχία#Grec_ancien|(en)]] ;<br /><p style="margin: 0 2em; text-indent: 15px">Nom d’une colline du [[w:Le_Pirée|''Pirée'']] et de l’[[w:Port_de_Munichie|un des ports du ''Pirée'']].'''<br/><br/></div> {{Boîte déroulante fin}} <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">'''XII.''' Au chagrin que ces pertes causèrent à ceux-ci, se joignirent des craintes superstitieuses dont la ville fut frappée, et qui venaient d’apparitions de spectres et de fantômes. Les devins déclarèrent aussi que l’état des victimes annonçait des crimes et des profanations qu’il fallait expier. On fit donc venir de ''Crète'' '''Épiménide''' le ''Phestien'' qui est mis au nombre des sept sages par ceux qui n’y comptent pas '''Périandre'''. Il passait pour un homme chéri des dieux, doué d’une grande sagesse, fort instruit des choses divines, surtout versé dans la science des inspirations et dans la connaissance des mystères; on l’appelait, même de son vivant, le nouveau '''Curète''', le fils de la nymphe '''Balté'''.<br /><p style="text-align: center">[...]<br /><p style="text-indent: 15px; text-align: justify;">Mais ce qui était plus important, il fit un grand nombre d’expiations et de sacrifices; il fonda plusieurs temples; et par ces différentes cérémonies, il purifia entièrement la ville, en bannit l’impiété et l’injustice, et la rendit plus soumise, plus disposée à l’union et à la paix. On rapporte aussi que lorsqu’il vit ''Munychie'', il la considéra longtemps, et dit à ceux qui l’accompagnaient :<br /><p style="text-align: justify; text-indent: 15px"> « Que les hommes sont aveugles sur l’avenir! Si les ''Athéniens'' pouvaient prévoir tous les maux que ce lieu doit un jour causer à leur ville, il l’emporteraient à belles dents. »<br /><p style="text-align: justify; text-indent: 15px"> '''Thalès''' eut aussi, dit-on, un pressentiment à peu près semblable. Il ordonna qu’on l’enterrât dans le lieu le plus sauvage et le plus désert du territoire de ''Milet''; et il prédit aux ''Milésiens'' qu’un jour leur marché public y serait transporté. Les ''Athéniens'', pleins de reconnaissance et d’admiration pour '''Épiménide''', voulurent le combler d’honneurs et de présents; mais il ne demanda qu’une branche de l’olivier sacré, qui lui fut accordée, et il s’en retourna en ''Crète''.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f7.item <u>Plutarque, Vie de Solon</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f58.item ''chap. II''], traduction correcte et précédée du texte grec, par une société de professeurs et d’helléniste, 1862<br />(également disponible une édition de 1844 [https://remacle.org/bloodwolf/historiens/Plutarque/solon.htm#1a ici] et de 1829 [[s:Les_Vies_des_hommes_illustres/Vie_de_Solon|là]])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Et certaines craintes nées de la superstition en-même-temps aussi des apparitions occupaient la ville; et les devins disaient des impiétés et des souillures ayant-besoin de purifications être indiquées par les victimes. Et ainsi vint à eux mandé (ils firent venir) de ''Crète'' '''Épiménide''' le ''Phestien'', que quelques-uns de ceux n’admettant pas '''Périandre''' comptent le septième parmi les sages. Or il avait-la-réputation d’être un homme ami-des-dieux, et habile dans la science de-l’inspiration et des-mystères. C’est-pourquoi les hommes d’alors appelaient lui et fils de la nymphe de nom (nommée) '''Balté''', et nouveau '''Curète'''.<br /><p style="text-align: center">[...]<br /><p style="text-indent: 15px; text-align: justify;">Mais le plus grand (le plus important), ayant initié-aux-mystères et ayant purifié la ville par certaines expiations et purifications et fondations, il la rendit prêtant-l’oreille à la justice et plus obéissante pour la concorde. Et il est dit, ayant vu ''Munychie'' et l’ayant examinée un temps long, avoir dit à ceux présents, que l’homme est un être aveugle sur l’avenir ; car les ''Athéniens'' avoir dû manger ''Munychie'' avec les dents d’eux-mêmes, s’ils avaient prévu en combien de choses cette place affligera la ville. Et on dit aussi '''Thalès''' avoir conjecturé quelque chose de semblable; lui avoir ordonné en effet de placer lui ayant cessé de vivre dans un certain lieu de la ''Milésie'' méprisé et dédaigné, ayant prédit que cet endroit sera (serait) un jour le marché des ''Milésiens''. '''Épiménide''' donc ayant été admiré très-grandement, et les ''Athéniens'' lui donnant des sommes nombreuses et des honneurs grands, n’ayant demandé rien qu’un rameau détaché de l’olivier sacré et l’ayant pris (reçu) s’en alla.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f7.item <u>Plutarque, Vie de Solon</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f59.item ''chap. II''], traduction littérale et juxtalinéaire présentant le mot à mot français en regard des mots grecs correspondants, par une société de professeurs et d’helléniste, 1862</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto; color: #3366BB">═✳═</div> === [[w:Œuvres_morales|Œuvres morales]] [[#Œuvres_morales|<span id="Œuvres_morales_back"><sup>'''I'''</sup></span>]] === <div style="text-align: center; margin: 0 1em;">Ensemble de 78 textes de traitant de sujets extrêmement variés (religieux, éthiques, politiques, philosophiques, littéraires, historiques), et s'inscrivant dans des genres littéraires également divers (traité, différentes sortes de dialogues, lettres, réponses à des Questions ([[wikt:ζήτημα#Grec_ancien|''zetemata'']]), « dits » ([[w:Apophtegme|''apophtegmes'']])).</div> {{Boîte déroulante début|titre=NdA Le Banquet des Septs Sages|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Cléobuline_back|<span id="Cléobuline"><sup>I</sup></span>]] En grec ancien Ἠθικὰ / Ethikà [[wikt:en:ἠθικός#Ancient_Greek|(en)]], «1. Relatif au caractère ou au tempérament : • (d’une personne) Qui exprime ou manifeste sa nature ; • (théâtre) Conforme au personnage. 2. Éthique moral (relatif à la moralité) : (philosophie) Relatif à l’éthique (l’étude des principes régissant la conduite juste ou injuste) ; (d’un texte) qui traite de la conduite et de la vertu. 3. (rhétorique) Empreint de tact. » ; <br /><p style="margin: 0 2em; text-indent: 15px;">➥ du nom commun ἦθος / êthos [[wikt:en:ἦθος#Ancient_Greek|(en)]], « 1. Le lieu habituel ou coutumier (de quelque chose) : • Le domicile ou le lieu de résidence (d’une personne) ; • Le territoire (d’un animal). 2. Le caractère ; le tempérament : • (théâtre) Personnage (dramatique). 3. La coutume ; l’habitude : • (au pluriel) Les manières ; l’étiquette. » ;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ +‎ du suffixe adjectival -ῐκός/-ĭkós, « relatif à, à la manière de ; -ique ».<br /><br /><p style="margin: 0 2em; text-indent: 15px;">En latin Moralia ; de l’adjectif mōrālis [[wikt:en:moralis#Latin|(en)]], « Qui a trait aux mœurs ou à l'éthique ; moral. » ;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ du nom commun mōs [[wikt:en:mos#Latin|(en)]], « 1. Manière d’agir ; comportement ; conduite. 2. Coutume ; habitude ; pratique ; usage. 3. (surtout au pluriel) Caractère ; disposition ; inclination ; tempérament. 4. Volonté ; obstination ; humeur ; caprice. 5. (sens dérivé) Qualité ; nature ; mode ; façon. 6. (sens dérivé) Précepte ; loi ; règle. 7. (au pluriel uniquement) mœurs ; principes »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ + du suffixe adjectival -ālis [[wikt:en:-alis#Latin|(en)]]. Utilisé pour la première fois par Cicéron pour traduire le terme grec ancien ēthikós, « moral ». <br /><br /><p style="margin: 0 2em; text-indent: 15px;">En retraçant l’usage de l’adjectif ἠθικός à partir de la Rhétorique d’Aristote, le professeur de littérature latine [https://cv.hal.science/charles-guerin Charles Guérin] démontre que Cicéron l’utilise dans son dernier traité rhétorique non comme un équivalent du style moyen, mais comme une catégorie nouvelle permettant d’opposer éloquence du ''mouere'' [[wikt:en:movere#Latin|(en)]] et éloquence du ''conciliare'' [[wikt:en:conciliare#Latin|(en)]]. Cicéron réintroduit ainsi dans son traité la notion de conciliation du public qu’il avait tout d’abord éliminée de son architecture théorique (au profit de la notion de ''delectare'' [[wikt:en:delectare#Latin|(en)]]) afin de garantir la cohérence conceptuelle de sa doctrine. L’ἠθικόν correspond ainsi à l’idée d’une adaptation du style à l’orateur, non sur le mode pragmatique défendu par Aristote (chez qui la λέξις ἠθική désigne l’adaptation du style aux caractéristiques concrètes de l’orateur), mais sur un mode idéalisant : l’ἠθικόν est une catégorie stylistique prescriptive, celle du style de l’orateur accompli [https://hal.science/hal-03189440 {{Info|<sup>🔍</sup>|Charles Guérin. Orator 128: Cicéron et la catégorie rhétorique de l’ethikon. Pierre Chiron; Carlos Lévy. Les noms du style, Peeters, pp.143-164, 2010. ⟨hal-03189440⟩}}].<br /><br /></div> {{Boîte déroulante fin}} ==== Le Banquet des Sept Sages ==== {| cellpadding="0" align="{{{align|right}}}" style="margin-left: 2em; width:40%; border-spacing:3px; text-align:center; background-color:#F8F9FA; border:2px solid #C8CCD1" |- | style="border:solid 1px #F8F9FA" | '''Manuscrit''' [https://archive.org/details/p.-oxy.-16/Oxyrhynchus%20Papyri/P.%20Oxy.%2052/page/n66/mode/1up {{info|<sup>➕</sup>|The Oxyrhynchus Papyri, Volume LII, 1984}}] [https://books.google.fr/books?id=qfl1xwEACAAJ&lpg=PA1059&hl=fr&pg=PA1171#v=onepage&q=Plutarque&f=false {{info|<sup>➕➕</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume Vb, §210 - Plutarque de Chéronée, p.1171}}] |- style="font-size:8pt; line-height:10pt; vertical-align:middle" | align="center" | <div style="margin-right: 1em; padding:0 0 4px 0; text-align:justify;">{{{légende| Le P. Oxy. 3685 conserve les vestiges assez détériorés de deux colonnes du Banquet des Sept Sages, datant de la première moitié du [[w:IIe_siècle|II<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]], c’est-à-dire presque contemporain de '''Plutarque'''. Ce petit fragment de papyrus (9,6 x 8 cm) présente un intérêt à deux titres : * d’une part, sa datation étant proche de l’époque de '''Plutarque''', il apporte des éléments sur l’authenticité de l’œuvre ; * d’autre part, une partie du texte se retrouve également chez '''Stobée'''. Les doutes quant à l'attribution du Banquet des Sept Sages à Plutarque ne semblent être apparus qu'à une époque relativement récente ; en effet, l'ouvrage figure dans ce que l'on appelle le « Catalogue de Lamprias », une liste des œuvres de Plutarque dressée au [[w:IIIe_siècle|III<sup>ème</sup>]] ou au [[w:IVe_siècle|IV<sup>ème</sup>]] siècle {{Info|EC|de l’Ère Commune}}. Toutefois, ces réserves ont désormais été levées de manière convaincante par J. Defradas pp.7-12 de l’édition de la Budé de 1985. NB : Les [[w:Papyrus_d%27Oxyrhynque|''papyrus d’Oxyrhynque'']] constituent un ensemble de manuscrits découverts à la fin du [[w:XIXe_siècle|XIX<sup>ème</sup>]] et au début du [[w:XXe_siècle|XX<sup>ème</sup>]] siècles {{Info|EC|de l’Ère Commune}} par les papyrologues [[w:Bernard_Pyne_Grenfell|'''Bernard Pyne Grenfell''']] et [[w:Arthur_Surridge_Hunt|'''Arthur Surridge Hunt''']], dans une ancienne décharge située près d’[[w:Oxyrhynque|''Oxyrhynque'']], en ''Égypte''.}}}</div> |} <div style="text-align: center; margin: 0 1em;">Dialogue faisant intervenir 20 personnages, dont une liste des sept sages : '''Thalès''', [[w:Solon|'''Solon''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Solon_back|<sup>🔄</sup>]], [[w:Bias_de_Priène|'''Bias''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Bias_back|<sup>🔄</sup>]], [[w:Chilon|'''Chilon''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Chilon_back|<sup>🔄</sup>]], [[w:Cléobule|'''Cléobule''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Cléobule_back|<sup>🔄</sup>]], [[w:Pittacos_de_Mytil%C3%A8ne|'''Pittacos''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Pittacos_back|<sup>🔄</sup>]], [[w:Périandre|'''Périandre''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Périandre_back|<sup>🔄</sup>]].</div> <div style="text-align: left; margin: 0 1em;">À ceux-ci se rajoutent : * [[w:Anacharsis|'''Anacharsis''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Anacharsis_back|<sup>🔄</sup>]], * '''[[w:Ésope|Ésope]]''' [[#Ésope|<span id="Ésope_back"><sup>'''I'''</sup></span>]], * '''Dioclès''' le ''devin'' et narrateur (possiblement fictif) [[#Dioclès_Cléodème_Chersias|<span id="Dioclès_Cléodème_Chersias_back"><sup>'''II'''</sup></span>]], * '''Nicarque''' le destinataire du récit (possiblement fictif), * [[w:Cléobuline|'''Cléobuline''']] [[#Cléobuline|<span id="Cléobuline_back"><sup>'''III'''</sup></span>]], * '''Mélissa''' la conjointe de '''Périandre''', * '''Niloxène''', * '''Alexidème''' un bâtard du ''tyran'' [[w:Thrasybule_de_Milet|'''Thrasybule''' de ''Milet'']], * '''Ardalus''' le joueur de flûte [[w:Trézène_(ville)|''trézénien'']] [[#Trézène|<span id="Trézène_back"><sup>'''IV'''</sup></span>]], * '''Cléodème''' le ''médecin'' (possiblement fictif) [[#Dioclès_Cléodème_Chersias|<sup>'''II'''</sup>]], * '''Mnésiphile''' un disciple de '''Solon''', * '''Chersias''' le ''poète'' (possiblement fictif) [[#Dioclès_Cléodème_Chersias|<sup>'''II'''</sup>]], * [[w:Gorgias|'''Gorgias''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Gorgias_back|<sup>🔄</sup>]].</div> {{Boîte déroulante début|titre=NdA Le Banquet des Septs Sages|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Ésope_back|<span id="Ésope"><sup>I</sup></span>]] Du nom propre grec ancien Αἴσωπος / Aísōpos ;<br /><p style="margin: 0 2em; text-indent: 15px;">Sous le nom d’Ésope ont circulé dans l’antiquité différents recueils de fables qui ont connu un succès universel et ont été traduites et imitées dans toute la tradition littéraire postérieure. On peut y voir l’expression d’une éthique populaire, rationaliste et cosmopolite, qui n’est pas sans intérêt pour l’histoire de la philosophie. Selon Hérodote, (livre II, chap. 134), il serait un ancien esclave d’Iadmon de ''Samos''.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] seconde moitié du [[w:VIe_siècle_av._J.-C.|VI<sup>ème</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]], selon la Souda, ({{Info|s.v.|Abréviation du latin sub verbo, « À l’article, à l’entrée, au mot. »}} Αἴσωπος, Αι 334), il aurait été précipité du haut des [[w:Phédriades|''Roches Phédriades'']] à ''Delphes'' en la 54<sup>ème</sup> Olympiade (564/561))[https://books.google.fr/books?id=DrvWAAAAMAAJ&newbks=1&newbks_redir=0&lpg=PA5&dq=bibliogroup%3A%22Dictionnaire%20des%20philosophes%20antiques%22&hl=fr&pg=PA240#v=onepage&q&f=false {{Info|<sup>🔍</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume III, §60 - Ésope (Αἴσωπος)}}] <br /><br /><p style="margin: 0 2em; text-indent: 15px;">'''[[#Dioclès_Cléodème_Chersias_back|<span id="Dioclès_Cléodème_Chersias"><sup>II</sup></span>]] D’après l’historienne [https://research-bulletin.chs.harvard.edu/authors/zoe-stamatopoulou/ Zoe Stamatopoulou] [https://research-bulletin.chs.harvard.edu/2017/04/17/periander-plutarch-symposium/ {{info|<sup>🔍</sup>|Stamatopoulou, Zoe. “Constructing Periander in Plutarch’s Symposium of the Seven Sages.” CHS Research Bulletin 5, no. 1 (2016). http://nrs.harvard.edu/urn-3:hlnc.essay:StamatopoulouZ.Constructing_Periander.2016.}}], il s’agit de non-Sages individualisés par leur profession. <br /><br /><p style="margin: 0 2em; text-indent: 15px;">'''[[#Cléobuline_back|<span id="Cléobuline"><sup>III</sup></span>]] Du nom propre grec ancien Κλεοβουλίνη / Kleoboulinè ;<br /><p style="margin: 0 2em; text-indent: 15px">➥ de Κλεόβουλος / Kleóboulos [[wikt:en:Κλεόβουλος#Ancient_Greek|(en)]], « Cléobule, le père de Cléobuline » <br /><p style="margin: 0 2em; text-indent: 15px">➥ du suffixe adjectival féminin -ῑ́νη / -ī́nē [[wikt:en:-ίνη#Ancient_Greek|(en)]], relatif à la matière, au temps, etc. : « fait de, pendant la durée de » ;<br /><p style="margin: 0 2em; text-indent: 15px">Philosophe et poétesse grecque, célèbre pour ses énigmes, fille du [[w:Tyran|''tyran'']] de [[w:Rhodes|''Rhodes'']], Cléobule, qui la surnommerait Εὔμητις / Eúmētis, « la Prudente » selon Plutarque.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:VIe_siècle_av._J.-C.|VI<sup>ème</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]], originaire de [[w:Lindos|''Lindos'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Lindos_back|<sup>🔄</sup>]] sur l’île de ''Rhodes'') <br /><br /><p style="margin: 0 2em; text-indent: 15px;">'''[[#Trézène_back|<span id="Trézène"><sup>IV</sup></span>]] Du nom propre grec ancien Τροιζήν / Troizḗn [[wikt:en:Τροιζήν#Ancient_Greek|(en)]] ;<br /><p style="margin: 0 2em; text-indent: 15px">[[w:polis|Cité grecque]] du [[w:Péloponnèse|''Péloponnèse'']], sur la côte nord de l’[[w:Argolide|''Argolide'']]. '''<br/><br/></div> {{Boîte déroulante fin}} ===== <div style="text-align: center;">Paragraphe I.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">'''Dioclès''' raconte le Banquet des Sept Sages organisé par '''Périandre''', pendant lequel il fût l’hôte de '''Thalès'''.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§1. Ἦ που προϊὼν ὁ χρόνος, ὦ '''Νίκαρχε''', πολὺ σκότος ἐπάξει τοῖς πράγμασι καὶ πᾶσαν ἀσάφειαν, εἰ νῦν ἐπὶ προσφάτοις οὕτω καὶ νεαροῖς λόγοι ψευδεῖς συντεθέντες ἔχουσι πίστιν. οὔτε γὰρ μόνων, ὡς ὑμεῖς ἀκηκόατε, τῶν ἑπτὰ γέγονε τὸ συμπόσιον, ἀλλὰ πλειόνων ἢ δὶς τοσούτων (ἐν οἷς καὶ αὐτὸς ἤμην, συνήθης μὲν ὢν '''Περιάνδρῳ''' διὰ τὴν τέχνην, ξένος δὲ '''Θάλεω'''· παρ´ ἐμοὶ γὰρ κατέλυσεν ὁ ἀνὴρ '''Περιάνδρου''' κελεύσαντος), οὔτε τοὺς λόγους ὀρθῶς ἀπεμνημόνευσεν ὅστις ἦν ὑμῖν ὁ διηγούμενος· ἦν δ´ ὡς ἔοικεν οὐδεὶς τῶν παραγεγονότων. ἀλλ´ ἐπεὶ σχολή τε πάρεστι πολλὴ καὶ τὸ γῆρας οὐκ ἀξιόπιστον ἐγγυήσασθαι τὴν ἀναβολὴν τοῦ λόγου, προθυμουμένοις ὑμῖν ἀπ´ ἀρχῆς ἅπαντα διηγήσομαι. </div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §1'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§1. '''D<span style ="font-size:85%;">IOCLÈS</span>'''. Certainement le long cours des âges, mon cher '''Nicarque''', jettera sur les faits d’épaisses ténèbres et une complète incertitude, puisque dès aujourd’hui, à propos de choses si récentes et si nouvelles, des relations mensongères et controuvées obtiennent crédit. Car d’abord le banquet en question ne se composait pas seulement des sept sages, comme vous autres l’avez ouï dire. Les convives étaient plus du double de ce nombre. J’en faisais moi-même partie, comme familier de '''Périandre''' en raison de notre profession commune, et comme hôte de '''Thalès''' : ce dernier était en effet descendu chez moi sur la recommandation de '''Périandre'''. Ensuite, on ne vous en a pas rapporté fidèlement les entretiens lorsqu’on vous a fait ce récit. Il faut que celui de qui vous le tenez n’ait pas été un des convives. Mais puisque nous avons un ample loisir et que la vieillesse est un garant trop peu sûr pour nous autoriser à remettre cet entretien, je vais, suivant votre désir unanime, vous en raconter tous les détails à partir du commencement. </div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §1'', traduction par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870<br/>(également disponible [[s:Page:Plutarque_-_Œuvres_complètes_de_Plutarque_-_Œuvres_morales_et_œuvres_diverses,_tome_1,_1870.djvu/424|ici]])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">'''D<span style ="font-size:85%;">IOCLÈS</span>'''. Quelle incertitude et quelle obscurité la succession des temps ne doit-elle pas répandre sur l’histoire, mon cher '''Nicarque''', puisque, dans des faits récents, et qui se sont passés presque sous nos yeux, le faux prend la place du vrai ? Ce banquet n’était pas, comme on vous l’a dit, composé seulement des sept sages ; les convives étaient plus du double de ce nombre. J’y assistai moi-même, et comme ami de '''Périandre''', avec qui ma profession ma lié depuis longtemps [[#Dioclès_NdT_DR|<span id="Dioclès_NdT_DR_back"><sup>1</sup></span>]], et comme hôte de '''Thalès''', à qui '''Périandre''' avait fait marquer son logement chez moi. Celui qui vous a fait le récit de ce qui s’y est passé n’en était sûrement pas, et vous a trompé sur presque tous les points. Mais, puisque nous en avons le loisir, et que notre âge avancé ne nous permet guère de différer, je vais vous satisfaire et vous en raconter tous les détails.</div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Dioclès_NdT_DR_back|<span id="Dioclès_NdT_DR"><sup>1.</sup></span>]] Dioclès était devin.''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' pp.325, 326, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe II.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage de la simplicité de '''Thalès''', de sa mesure de la pyramide d’''Égypte'' [[#mesure_pyramide|<span id="mesure_pyramide_back"><sup>'''I'''</sup></span>]], et de son aversion des [[w:Tyran|''tyrans'']] et des rois.</div> {{Boîte déroulante début|titre=NdA Mesure de la Pyramide d’Égypte|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#mesure_pyramide_back|<span id="mesure_pyramide"><sup>I</sup></span>]]'''<br/><br/></div> {{Boîte déroulante fin}} :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§2. Παρεσκευάκει μὲν γὰρ οὐκ ἐν τῇ πόλει τὴν ὑποδοχὴν ὁ Περίανδρος, ἀλλ´ ἐν τῷ περὶ τὸ Λέχαιον ἑστιατορίῳ παρὰ τὸ τῆς Ἀφροδίτης ἱερόν, ἧς ἦν καὶ ἡ θυσία. μετὰ γὰρ τὸν ἔρωτα τῆς μητρὸς αὐτοῦ προεμένης τὸν βίον ἑκουσίως οὐ τεθυκὼς τῇ Ἀφροδίτῃ, τότε πρῶτον ἔκ τινων ἐνυπνίων τῆς Μελίσσης ὥρμησε τιμᾶν καὶ θεραπεύειν τὴν θεόν. Τῶν δὲ κεκλημένων ἑκάστῳ συνωρὶς ἱκανῶς κεκοσμημένη προσήχθη· καὶ γὰρ ὥρα θέρους ἦν, καὶ τὴν ὁδὸν ἅπασαν ὑπὸ πλήθους ἁμαξῶν καὶ ἀνθρώπων ἄχρι θαλάττης κονιορτὸς καὶ θόρυβος κατεῖχεν. ὁ μέντοι Θαλῆς τὸ ζεῦγος ἐπὶ ταῖς θύραις ἰδὼν καὶ μειδιάσας ἀφῆκεν. ἐβαδίζομεν οὖν ἐκτραπόμενοι διὰ τῶν χωρίων, καθ´ ἡσυχίαν, καὶ μεθ´ ἡμῶν τρίτος ὁ Ναυκρατίτης Νειλόξενος, ἀνὴρ ἐπιεικὴς καὶ τοῖς περὶ Σόλωνα καὶ Θαλῆν γεγονὼς ἐν Αἰγύπτῳ συνήθης. ἐτύγχανε δὲ πρὸς Βίαντα πάλιν ἀπεσταλμένος· ὧν δὲ χάριν οὐδ´ αὐτὸς ᾔδει, πλὴν ὑπενόει πρόβλημα δεύτερον αὐτῷ κομίζειν ἐν βιβλίῳ κατασεσημασμένον· εἴρητο γάρ, εἰ Βίας ἀπαγορεύσειεν, ἐπιδεῖξαι τοῖς σοφωτάτοις Ἑλλήνων τὸ βιβλίον. « Ἕρμαιον » ὁ Νειλόξενος ἔφη « μοι γέγονεν ἐνταῦθα λαβεῖν ἅπαντας ὑμᾶς, καὶ κομίζω τὸ βιβλίον ὡς ὁρᾷς ἐπὶ τὸ δεῖπνον. » ἅμα δ´ ἡμῖν ἐπεδείκνυε. Καὶ ὁ Θαλῆς γελάσας « εἴ τι κακόν, » εἶπεν, « αὖθις εἰς Πριήνην· διαλύσει γὰρ ὁ Βίας, ὡς διέλυσεν αὐτὸς τὸ πρῶτον. » « Τί δ´ ἦν, » ἔφην ἐγώ, « τὸ πρῶτον; » « Ἱερεῖον, » εἶπεν, « ἔπεμψεν αὐτῷ, κελεύσας τὸ πονηρότατον ἐξελόντα καὶ χρηστότατον ἀποπέμψαι κρέας. ὁ δ´ ἡμέτερος εὖ καὶ καλῶς τὴν γλῶτταν ἐξελὼν ἔπεμψεν· ὅθεν εὐδοκιμῶν δῆλός ἐστι καὶ θαυμαζόμενος. » « Οὐ διὰ ταῦτ´ » ἔφη « μόνον » ὁ Νειλόξενος, « ἀλλ´ οὐ φεύγει τὸ φίλος εἶναι καὶ λέγεσθαι βασιλέων καθάπερ ὑμεῖς, ἐπεὶ σοῦ γε καὶ τἄλλα θαυμάζει, καὶ τῆς [[wikt:en:πυραμίδος#Ancient_Greek|πυραμίδος]] τὴν μέτρησιν ὑπερφυῶς ἠγάπησεν, ὅτι πάσης ἄνευ πραγματείας καὶ μηδενὸς ὀργάνου δεηθεὶς ἀλλὰ τὴν βακτηρίαν στήσας ἐπὶ τῷ πέρατι τῆς σκιᾶς ἣν ἡ πυραμὶς ἐποίει, γενομένων τῇ ἐπαφῇ τῆς ἀκτῖνος δυεῖν τριγώνων, ἔδειξας ὃν ἡ σκιὰ πρὸς τὴν σκιὰν λόγον εἶχε τὴν πυραμίδα πρὸς τὴν βακτηρίαν ἔχουσαν. ἀλλ´, ὅπερ ἔφην, διεβλήθης μισοβασιλεὺς εἶναι, καί τινες ὑβριστικαί σου περὶ τυράννων ἀποφάσεις ἀνεφέροντο πρὸς αὐτόν, ὡς ἐρωτηθεὶς ὑπὸ Μολπαγόρου τοῦ Ἴωνος τί παραδοξότατον εἴης ἑωρακώς, ἀποκρίναιο ‘τύραννον γέροντα,’ καὶ πάλιν ἔν τινι πότῳ, περὶ τῶν θηρίων λόγου γενομένου, φαίης κάκιστον εἶναι τῶν μὲν ἀγρίων θηρίων τὸν τύραννον, τῶν δ´ ἡμέρων τὸν κόλακα· ταῦτα γάρ, εἰ καὶ πάνυ προσποιοῦνται διαφέρειν οἱ βασιλεῖς τῶν τυράννων, οὐκ εὐμενῶς ἀκούουσιν. » « Ἀλλὰ τοῦτο μέν, » εἶπεν ὁ Θαλῆς, « Πιττακοῦ ἐστιν, εἰρημένον ἐν παιδιᾷ ποτε πρὸς Μυρσίλον· ἐγὼ δὲ θαυμάσαιμ´ ἄν, » ἔφη, « οὐ τύραννον ἀλλὰ [[wikt:κυβερνήτης#Grec_ancien|'''κυβερνήτην''']] γέροντα θεασάμενος. πρὸς δὲ τὴν μετάθεσιν τὸ τοῦ νεανίσκου πέπονθα τοῦ βαλόντος μὲν ἐπὶ τὴν κύνα πατάξαντος δὲ τὴν μητρυιὰν καὶ εἰπόντος ‘οὐδ´ οὕτω κακῶς.’ διὸ καὶ Σόλωνα σοφώτατον ἡγησάμην οὐ δεξάμενον τυραννεῖν. καὶ Πιττακὸς οὗτος εἰ μοναρχίᾳ μὴ προσῆλθεν, οὐκ ἂν εἶπεν ὡς ‘χαλεπὸν ἐσθλὸν ἔμμεναι.’ Περίανδρος δ´ ἔοικεν ὥσπερ ἐν νοσήματι πατρῴῳ τῇ τυραννίδι κατειλημμένος οὐ φαύλως ἐξαναφέρειν, χρώμενος ὁμιλίαις ὑγιειναῖς ἄχρι γε νῦν καὶ συνουσίας ἀνδρῶν νοῦν ἐχόντων ἐπαγόμενος, ἃς δὲ '''Θρασύβουλος''' αὐτῷ κολούσεις τῶν ἄκρων οὑμὸς πολίτης ὑφηγεῖται μὴ προσιέμενος. γεωργοῦ γὰρ [[wikt:en:αἶρα#Ancient_Greek|αἴρας]] καὶ [[wikt:ononis|ὀνώνιδας]] ἀντὶ [[wikt:πυρός#Grec_ancien|πυρῶν]] καὶ [[wikt:κριθή#Grec_ancien|κριθῶν]] συγκομίζειν ἐθέλοντος οὐδὲν διαφέρει τύραννος ἀνδραπόδων μᾶλλον ἄρχειν ἢ ἀνδρῶν βουλόμενος· ἓν γὰρ ἀντὶ πολλῶν κακῶν ἀγαθὸν αἱ δυναστεῖαι τὴν τιμὴν ἔχουσι καὶ τὴν δόξαν, ἄνπερ ἀγαθῶν ὡς κρείττονες ἄρχωσι καὶ μεγάλων μείζονες εἶναι δοκῶσι· τὴν δ´ ἀσφάλειαν ἀγαπῶντας ἄνευ τοῦ καλοῦ προβάτων ἔδει πολλῶν καὶ ἵππων καὶ βοῶν ἄρχειν, μὴ ἀνθρώπων. ἀλλὰ γὰρ εἰς οὐδὲν προσήκοντας ἐμβέβληκεν ἡμᾶς, » ἔφη, « ὁ ξένος οὑτοσὶ λόγους, ἀμελήσας λέγειν τε καὶ ζητεῖν ἃ ἁρμόττει ἐπὶ δεῖπνον βαδίζουσιν. ἦ γὰρ οὐκ οἴει, καθάπερ ἑστιάσοντος ἔστι τις παρασκευή, καὶ δειπνήσοντος εἶναι; Συβαρῖται μὲν γὰρ ὡς ἔοικε πρὸ ἐνιαυτοῦ τὰς κλήσεις ποιοῦνται τῶν γυναικῶν, ὅπως ἐκγένοιτο κατὰ σχολὴν παρασκευασαμέναις ἐσθῆτι καὶ χρυσῷ φοιτᾶν ἐπὶ τὸ δεῖπνον· ἐγὼ δὲ πλείονος οἶμαι χρόνου δεῖσθαι τὴν ἀληθινὴν τοῦ δειπνήσοντος ὀρθῶς παρασκευήν, ὅσῳ χαλεπώτερόν ἐστιν ἤθει τὸν πρέποντα κόσμον ἢ σώματι τὸν περιττὸν ἐξευρεῖν καὶ ἄχρηστον. οὐ γὰρ ὡς ἀγγεῖον ἥκει κομίζων ἑαυτὸν ἐμπλῆσαι πρὸς τὸ δεῖπνον ὁ νοῦν ἔχων, ἀλλὰ καὶ σπουδάσαι τι καὶ παῖξαι καὶ ἀκοῦσαι καὶ εἰπεῖν ὡς ὁ καιρὸς παρακαλεῖ τοὺς συνόντας, εἰ μέλλουσι μετ´ ἀλλήλων ἡδέως ἔσεσθαι. καὶ γὰρ καὶ ὄψον πονηρὸν ἔστι παρώσασθαι, κἂν οἶνος ᾖ φαῦλος, ἐπὶ τὰς νύμφας καταφυγεῖν· σύνδειπνος δὲ κεφαλαλγὴς καὶ βαρὺς καὶ ἀνάγωγος παντὸς μὲν οἴνου καὶ ὄψου πάσης δὲ μουσουργοῦ χάριν ἀπόλλυσι καὶ λυμαίνεται, καὶ οὐδ´ ἀπεμέσαι τὴν τοιαύτην ἀηδίαν ἕτοιμόν ἐστιν, ἀλλ´ ἐνίοις εἰς ἅπαντα τὸν βίον ἐμμένει τὸ πρὸς ἀλλήλους δυσάρεστον, ὥσπερ ἑωλοκρασία τις ὕβρεως ἢ ὀργῆς ἐν οἴνῳ γενομένης. ὅθεν ἄριστα Χίλων, καλούμενος ἐχθές, οὐ πρότερον ὡμολόγησεν ἢ πυθέσθαι τῶν κεκλημένων ἕκαστον. ἔφη γὰρ ὅτι σύμπλουν ἀγνώμονα δεῖ φέρειν καὶ σύσκηνον οἷς πλεῖν ἀνάγκη καὶ στρατεύεσθαι· τὸ δὲ συμπόταις ἑαυτὸν ὡς ἔτυχε καταμιγνύειν οὐ νοῦν ἔχοντος ἀνδρός ἐστιν. ὁ δ´ Αἰγύπτιος σκελετός, ὃν ἐπιεικῶς εἰσφέροντες εἰς τὰ συμπόσια προτίθενται καὶ παρακαλοῦσι μεμνῆσθαι τάχα δὴ τοιούτους ἐσομένους, καίπερ ἄχαρις καὶ ἄωρος ἐπίκωμος ἥκων, ὅμως ἔχει τινὰ καιρόν, καὶ εἰ μὴ πρὸς τὸ πίνειν καὶ ἡδυπαθεῖν ἀλλὰ πρὸς φιλίαν καὶ ἀγάπησιν ἀλλήλων προτρέπεται, καὶ παρακαλεῖ τὸν βίον μὴ τῷ χρόνῳ βραχὺν ὄντα πράγμασι κακοῖς μακρὸν ποιεῖν. » </div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §2'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§2. La réception avait été préparée par '''Périandre''', non pas dans la ville même, mais dans son [[w:Cénacle|''cénacle'']] du port de [[w:Léchaion|''Léchée'']], près du temple de '''Vénus''' en l’honneur de laquelle il y avait même un sacrifice. Car depuis l’incestueux amour à la suite duquel sa mère avait volontairement abandonné la vie, '''Périandre''' n’avait pas sacrifié à '''Vénus''' ; et c’était alors la première fois que, d’après certains songes de '''Mélissa''' il s’était décidé à honorer la déesse et à lui rendre des hommages. Pour chacun des invités on avait amené un attelage approprié convenablement. Nous étions en été, et tout le long de la route, en raison du grand nombre de chariots et de piétons, ce n’était jusqu’à la mer que poussière et que bruit. Pourtant '''Thalès''', ayant vu l’attelage à notre porte, se mit à sourire et le renvoya. Nous partîmes donc à pied en faisant un détour, et à travers champs nous cheminâmes à loisir. Un troisième compagnon s’était joint à nous, '''Niloxène''' de ''Naucratie'', homme plein de mérite, que '''Thalès''' et '''Solon''' avaient autrefois beaucoup connu en ''Égypte''. Il se trouvait envoyé de nouveau vers '''Bias''' ; mais pour quelle mission ? Il n’en savait rien lui-même, hormis qu’il se soupçonnait porteur d’une seconde question à résoudre, contenue dans un pli cacheté; et il lui avait été dit, au cas où '''Bias''' renoncerait, de la présenter aux plus sages d’entre les Grecs. « C’est », dit '''Niloxène''', « une chance heureuse que de vous trouver ici tous, et j’apporte, comme vous voyez, cette lettre pour le banquet. » En même temps, il nous la faisait voir. '''Thalès''' se mit à rire : « Si c’est une question épineuse », dit-il, « qu’on aille encore à ''Priène'' : '''Bias''' la résoudra comme il a résolu la première. » — « Quelle était donc cette première question ? » lui demandai-je. — « Le roi d’Égypte », dit '''Thalès''', « avait envoyé à '''Bias''' une victime, en lui faisant dire d’en couper ce qu’il y avait de plus mauvais et de meilleur, et de le lui renvoyer. Notre sage, avec un discernement merveilleux, en ôta la langue et la fit porter au Roi. Voilà ce qui lui a valu une estime et une admiration si déclarée ». — « Cette raison n’est pas la seule », ajouta '''Niloxène''' ; « c’est encore, que '''Bias''' ne fuit pas, comme vous autres, l’amitié des rois eux-mêmes. Ainsi, vous, '''Thalès''', le roi d’Égypte vous admire beaucoup, et, entre autres choses, il a été, au-delà de ce qu’on peut dire, ravi de la manière dont vous avez mesuré la pyramide sans le moindre embarras et sans avoir eu besoin d’aucun instrument. Après avoir dressé votre bâton à l’extrémité de l’ombre que projetait la pyramide, vous construisîtes deux triangles par la tangence d’un rayon, et vous démontrâtes qu’il y avait la même proportion entre la hauteur du bâton et la hauteur de la pyramide qu’entre la longueur des deux ombres. Mais, comme j’ai dit, on vous accuse de détester les rois ; quelques boutades injurieuses prononcées par vous contre des ''tyrans'' ont été rapportées à [[w:Ahmôsis_II|'''Amasis''']]. Par exemple, l’Ionien '''Molpagore''' vous ayant demandé ce que vous aviez jamais vu de plus extraordinaire, vous lui auriez répondu : « C’est un tyran parvenu à la vieillesse. » Une autre fois, dans un festin, la conversation étant venue à tomber sur les bêtes féroces, vous auriez dit : « La plus méchante bête parmi les animaux sauvages, c’est le tyran, et parmi les animaux apprivoisés le flatteur. » De tels propos ne sont pas de ceux que les rois entendent avec plaisir, lors même qu’ils affectent de n’avoir rien de commun avec les tyrans. » Pour cette dernière réponse, dit '''Thalès''', elle est de '''Pittacus''' : il l’avait adressée un jour en plaisantant à '''Myrsile'''. Quant au premier propos, ce n’était pas « un tyran » que j’avais dit, mais « un [[wikt:κυβερνήτης#Grec_ancien|''pilote'']] », qui soit parvenu à la vieillesse. Toutefois, puisqu’on a changé la destination du mot, je fais comme le jeune homme qui, ayant jeté une pierre à un chien, atteignit sa belle-mère et s’écria : Même ainsi, ce n’est pas mal. » C’est pourquoi je regardai '''Solon''' comme éminemment sage lorsqu’il n’accepta pas la tyrannie ; et '''Pittacus''', s’il n’eût approché de la monarchie, n’aurait pas eu à dire : « Il est difficile d’être homme de bien. » Quant à '''Périandre''', il semble qu’ayant été saisi par le souverain pouvoir comme par une maladie de famille, il ne s’en tire pas trop mal. Il use, au moins jusqu’à présent, de sociétés salutaires. Il réunit, pour entretenir commerce avec eux, ses hommes remplis de sens ; et le conseil que lui a donné mon compatriote [[w:Thrasybule_de_Milet|'''Thrasybule''']] [[#Thrasybule|<span id="Thrasybule_back"><sup>'''I'''</sup></span>]], de décapiter l’aristocratie, il ne l’a pas accepté. Entre un laboureur qui aimerait mieux voir dans son champ de l’[[w:Ivraie|''ivraie'']] ou de l’[[w:Orobanche|''orobanche'']] que de l’orge ou du blé, et un tyran qui veut régner sur des esclaves plutôt que sur des hommes de coeur, je ne vois aucune différence. Un seul bien compense les maux nombreux attachés au pouvoir des tyrans : c’est la gloire et l’honneur qui leur sont réservés lorsque, commandant à des hommes vertueux, ils sont plus vertueux eux-mêmes, et qu’au milieu de grands ils se montrent plus grands. Ceux qui préfèrent leur sûreté en renonçant à ce beau rôle, étaient faits pour réunir sous leur main beaucoup de moutons, de chevaux et de boeufs, mais non des hommes. » « Du reste », continua '''Thalès''', « ce sont propos sans portée aucune que ceux où nous a jetés cet étranger, et nous avons omis de dire et de chercher les choses qui conviennent bien à des gens partis pour un banquet. Ne croyez-vous pas, '''Nicarque''', qu’il y ait des préparatifs à faire quand on vient prendre place à un festin, comme il y en a pour celui qui doit le donner ? Les [[w:Sybaris|''Sybarites'']] [[#Sybaris|<span id="Sybaris_back"><sup>'''II'''</sup></span>]], à ce qu’il paraît, s’y prennent un an d’avance pour adresser leurs invitations aux femmes, afin qu’elles puissent à loisir préparer leur toilette et leurs bijoux en or avant de se rendre au festin; et, selon moi, il faut plus de temps encore à un convive pour les préparatifs vraiment nécessaires, parce qu’il est plus difficile de trouver un ajustement convenable pour son moral que la vaine et inutile parure dont on s’inquiète pour son corps. Un homme sensé ne se transporte pas à un festin comme un bocal qu’il s’agit d’y remplir. Il songe à trouver là une occasion de passer tour à tour du sérieux au badinage, d’entendre et de tenir lui-même ces propos auxquels la circonstance invite les convives s’ils veulent se rendre la réunion agréable les uns aux autres. En effet on est libre de repousser un mauvais ragoût, et si le vin ne vaut rien on peut « recourir aux [[w:Naïades|''Naïades'']] »; mais un convive qui vous donne mal à la tête, qui est lourd, qui ne sait pas se conduire, vous fait perdre et vous gâte le plaisir de tout vin, de toute bonne chère, de toute musique. On n’est même pas le maître de se débarrasser aussi complétement qu’on le voudrait d’un tel désagrément. Quelques-uns en gardent tant qu’ils vivent du mécontentement les uns contre les autres : il leur semble qu’il leur reste comme un arrière-goût de viandes mal digérées, parce qu’ils conservent le souvenir d’injures ou de colères échangées dans le vin. C’est pour cela que '''Chilon''', invité hier, n’a pas voulu promettre avant d’avoir su le nom de chacun des convives : « Car on est bien obligé, a-t-il dit, de supporter un désagréable compagnon de traversée, de tente, quand il faut être sur terre ou à l’armée ; mais se mêler indifféremment à table avec les premiers venus, n’est pas le propre d’un homme sensé. » Le squelette des ''Égyptiens'', qu’ils ont la sage coutume de produire et de placer dans la salle du festin afin d’engager à se souvenir que l’on sera bientôt comme lui, survient là comme un convive assez désagréable et intempestif, mais enfin la présence s’en explique. Si cette vue n’excite pas à boire et à se réjouir, elle engage du moins à s’aimer, à se chérir les uns les autres, et elle exhorte à ne pas allonger par des tracas pénibles une existence dont la durée est si courte. </div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §2'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> {{Boîte déroulante début|titre=NdA trad. par Victor Bétolaud de 1870|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Thrasybule_back|<span id="Thrasybule"><sup>I</sup></span>]] Du nom propre grec ancien Θρᾰσῠ́βουλος / Thrăsŭ́boulos [[wikt:en:Θρασύβουλος#Ancient_Greek|(en)]] ;<br /><p style="margin: 0 2em; text-indent: 15px">➥ de l’adjectif [[wikt:θρασύς#Grec_ancien|θρᾰσύς / thrăsús]], « confiant, audacieux » ;<br /><p style="margin: 0 2em; text-indent: 15px">➥ +‎ du nom commun [[wikt:βουλή#Grec_ancien|βουλή / boulế]], « Volonté. Décision, conseil. Conseil, sénat athénien. »; du verbe [[wikt:βούλομαι#Grec_ancien|βούλομαι / boúlomai]], « Vouloir, désirer, souhaiter. Vouloir bien, consentir à. » ;<br /><p style="margin: 0 2em; text-indent: 15px">➥ +‎ -ος (-os).<br /><br /><p style="margin: 0 2em; text-indent: 15px">[[#Sybaris_back|<span id="Sybaris"><sup>II</sup></span>]] Du nom propre grec ancien Σῠ́βᾰρῐς / Sŭ́bărĭs [[wikt:en:Σύβαρις#Ancient_Greek|(en)]] ;<br /><p style="margin: 0 2em; text-indent: 15px">[[w:Colonisation grecque|Colonie grecque]] du sud de l’Italie (en [[w:Calabre|Calabre]] actuelle), fondée au [[w:VIIIe_siècle_av._J.-C.|VIII<sup>ème</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]] dans le cadre du mouvement d’établissement et d’[[w:Colonisation_grecque|''essaimage'']] des Grecs vers l’Occident, particulièrement en [[w:Grande-Grèce|''Grande-Grèce'']]. Réputée dès l’Antiquité pour sa richesse devenue proverbiale, ainsi que pour son emprise sur les peuples voisins et différentes cités grecques de son voisinage, elle est détruite à l’issue d’une [[w:Guerre entre Sybaris et Crotone|guerre]] qui l’oppose à [[w:Crotone|''Crotone'']] à la fin du [[w:VIe_siècle_av._J.-C.|VI<sup>ème</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]], et enfouie sous les eaux du fleuve ''Crathis'' (aujourd’hui [[Crati]]), avant de voir son site réoccupé, soixante ans plus tard, par la colonie [[w:Panhellénisme|''panhellénique'']] de [[w:Thourioï|''Thourioï'']].'''<br/><br/></div> {{Boîte déroulante fin}} <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">'''Périandre''' avait fait préparer le banquet, non à la ville même, mais au ''port de Léchée'' [[#Léchée_NdT_DR|<span id="Léchée_NdT_DR_back"><sup>1</sup></span>]], dans une salle voisine du ''temple de Vénus'', à qui l’on devait offrir un sacrifice. Depuis que sa mère, victime d’un malheureux amour [[#Cratée_NdT_DR|<span id="Cratée_NdT_DR_back"><sup>2</sup></span>]], s’était donné la mort, il n’avait pas encore sacrifié à cette déesse, et c’était la première fois qu’il y pensait, d’après un songe de '''Mélisse''' [[#Mélisse_NdT_DR|<span id="Mélisse_NdT_DR_back"><sup>3</sup></span>]]. Nous étions dans les plus grandes chaleurs de l’été. Le grand nombre des voitures et des gens de pied qui fréquentaient le chemin qui conduit à la mer, l’avaient couvert de poussière et le rendaient fort incommode pour les voyageurs. On avait amené, pour chaque convive, un char commode et proprement orné. '''Thalès''', en voyant le sien à ma porte, se mit à sourire et le refusa. Nous primes donc, à travers les champs, un sentier détourné, et nous allâmes, en nous promenant, suivis de '''Niloxène''' de ''Naucrate'' [[#Niloxène_NdT_DR|<span id="Niloxène_NdT_DR_back"><sup>4</sup></span>]], homme du plus grand mérite, que '''Thalès''' et '''Solon''' avaient autrefois beaucoup connu en ''Égypte''. Il était envoyé, pour la seconde fois, vers '''Bias''', sans savoir lui-même quel était l’objet de sa mission. Il se doutait seulement que la lettre dont '''Amasis''' l’avait chargé contenait une seconde question à résoudre. Il avait ordre, en cas que '''Bias''' refusât d’y répondre, de la proposer aux plus sages d’entre les ''Grecs''. Dès qu’il m’eut aperçu, il me dit en me montrant sa lettre : « J’ai du bonheur aujourd’hui. Cette lettre vous trouve tous réunis. Je la porte au banquet, comme vous voyez. - Si c’est une question épineuse, dit '''Thalès''' en souriant, retournez à ''Priene'' [[#Priene_NdT_DR|<span id="Priene_NdT_DR_back"><sup>5</sup></span>]], '''Bias''' la résoudra, comme il a résolu la première. - Quelle était cette première question, demandai-je à '''Thalès''' ? - Le roi d’Égypte, me répondit-il, avait envoyé une victime à '''Bias''', en lui faisant dire d’en couper ce qu’il y avait de meilleur et de plus mauvais, et de le lui renvoyer. Notre sage, fort habilement en ôta la langue, qu’il lui fit porter. Voilà ce qui lui a mérité l’estime et l’admiration de ce prince. - Ajoutez encore à cette première raison, dit '''Niloxène''', que '''Bias''' ne dédaigne pas, comme vous, l’amitié des rois ; car '''Amasis''' n’a pas moins d’estime pour vous ; il admire surtout la manière dont vous mesurâtes, avec la plus grande facilité et sans aucun instrument mathématique, la hauteur de la pyramide. En dressant votre bâton à l’extrémité de l’ombre qu’elle faisait sur la terre, le rayon solaire qui touchait le sommet de la pyramide et l’extrémité du bâton forma deux triangles ; et vous démontrâtes qu’il y avait la même proportion entre la hauteur du bâton et celle de la pyramide qu’entre la longueur des ombres projetées par l’une et par l’autre. Mais, comme je viens de le dire, on vous accuse, auprès de lui, d’être l’ennemi des rois, et on lui a rapporté plusieurs propos injurieux que vous avez tenus contre les tyrans [[#tyrans_NdT_DR|<span id="tyrans_NdT_DR_back"><sup>6</sup></span>]] ; entre autres que l’''Ionien'' '''Molpagore''' [[#Molpagore_NdT_DR|<span id="Molpagore_NdT_DR_back"><sup>7</sup></span>]] vous ayant demandé ce qui vous paraîtrait plus extraordinaire dans la vie, vous lui répondîtes : de voir vieillir un tyran. Une autre fois, comme on vint à parler, dans un repas, du naturel des animaux, vous dîtes que le plus méchant des animaux sauvages était le tyran, et des animaux domestiques, le flatteur. Les rois, quoiqu’ils affectent de ne rien avoir de commun avec les tyrans, n’aiment pas cependant ces sortes de discours. Cette dernière réponse, dit '''Thalès''', est de '''Pittacus''' ; il la fit un jour, en plaisantant, à ''Myrsile'' [[#Myrsile_NdT_DR|<span id="Myrsile_NdT_DR_back"><sup>8</sup></span>]]. Dans la première, je parlais d’un pilote, et non pas d’un tyran. Mais puisqu’on en a fait application au tyran, je dirai comme ce jeune homme qui, jetant une pierre à son chien, en avait atteint sa belle-mère : « Le coup n’est pas perdu. » Aussi jamais '''Solon''' ne montra-t-il plus de sagesse, à mon gré, que lorsqu’il refusa la tyrannie ; et si '''Pittacus''' n’eût pas été contraint de l’accepter, il n’eût point dit qu’il est à charge d’être vertueux [[#Pittacus_NdT_DR|<span id="Pittacus_NdT_DR_back"><sup>9</sup></span>]]. Il est vrai que '''Périandre''', qui a succédé à l’autorité des tyrans, paraît jusqu’ici opposer à ce mal héréditaire un remède puissant, par le soin qu’il a de rechercher les entretiens et les avis salutaires des hommes vertueux , et par l’horreur qu’il a témoignée pour le conseil barbare que notre compatriote '''Thrasybule''' lui donnait de faire mourir les grands. Un tyran qui veut commander à des esclaves, plutôt qu’à des hommes, ressemble à un laboureur qui aimerait mieux voir son champ couvert de passereaux et de sauterelles que d’orge et de froment. Le seul bien qui puisse compenser tant de maux attachés au pouvoir des tyrans, c’est d’avoir, même sur les plus grands et les plus vertueux de leurs sujets, la supériorité de l’honneur et de la vertu. Ceux qui préfèrent la sûreté à la gloire sont faits pour commander à des troupeaux, et non pour gouverner des hommes. « Mais '''Niloxène''' nous a jetés dans une conversation absolument étrangère à notre objet, et nous a fait négliger ce qui devait nous occuper en allant au banquet. Ne pensez-vous pas que les conviés ont, aussi bien que leur hôte, des apprêts à faire. Les ''Sybarites'', dit-on, prient les femmes à souper un an d’avance, afin qu’elles puissent préparer à loisir leurs habits et leurs bijoux [[#Sybarites_NdT_DR|<span id="Sybarites_NdT_DR_back"><sup>10</sup></span>]]. Pour moi, je pense qu’il faut encore plus de temps à un convive pour faire tous les préparatifs convenables, parcequ’il est bien plus difficile d’orner son esprit comme il faut, que de donner à son corps une parure vaine et superflue. Un homme sensé doit aller à un festin, non pour y remplir son estomac, comme un vase, mais pour écouter et tenir à son tour des propos utiles ou amusants, suivant les circonstances. C’est le seul moyen de rendre le repas agréable aux convives. En effet, on peut laisser un mauvais ragoût, et recourir à l’eau quand le vin n’est pas bon ; mais un convive désagréable, importun et fatigant, fait perdre tout le plaisir de la bonne chère et de la musique. On ne peut se délivrer de l’ennui qu’il cause, et souvent même une parole vive ou offensante qu’il se sera permise dans la liberté de la table, fait naître des aversions et des ressentiments qui ne finissent qu’avec la vie. Aussi '''Chilon''', invité hier à ce banquet, ne voulut-il accepter qu’après qu’on lui eut nommé tous les convives. Il disait avec raison, que quand on est sur mer ou dans un camp, il faut nécessairement supporter les compagnons qui nous sont associés, quelque fâcheux qu’ils soient ; mais dans un festin, il n’est pas d’un homme sensé de se mêler indifféremment avec toutes sortes de personnes. Le squelette que les ''Égyptiens'' placent ordinairement à côté d’eux dans leurs repas, en s’exhortant à penser qu’ils seront bientôt dans le même état, est, à la vérité, un compagnon de table assez triste et assez déplacé. Il est néanmoins utile, sinon pour les exciter au plaisir, du moins pour les porter à la bienveillance et à l’amitié réciproque, et pour les avertir de ne pas remplir d’aigreur et de querelles le temps si court de la vie [[#squelette_NdT_DR|<span id="squelette_NdT_DR_back"><sup>11</sup></span>]]. » </div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Léchée_NdT_DR_back|<span id="Léchée_NdT_DR"><sup>1</sup></span>]] L’isthme de ''Corinthe'' avait deux ports, l’un sur la côte orientale, appelé ''Cenchrées'' ; et l’autre sur la côte occidentale, nommé ''Léchée''. Pausanias, qui a donné une description si détaillée de la ''Grèce'', parle d’un ''temple de Vénus'', bâti sur le port de ''Cenchrées'', et dont la statue était de marbre ; mais il ne fait pas mention de celui que cite Plutarque, et qu’il place près du port occidental. ''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Cratée_NdT_DR_back|<span id="Cratée_NdT_DR"><sup>2</sup></span>]] La mère de Périandre se nommait Cratée. On peut voir dans Parthenius la manière dont elle conçut et nourrit une passion incestueuse pour son fils, les moyens qu'elle prit pour la satisfaire sans être connue, et comment elle fut découverte. Les remords qu’elle en eut l’obligèrent de se donner la mort.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Mélisse_NdT_DR_back|<span id="Mélisse_NdT_DR"><sup>3</sup></span>]] Mélisse était fille de Proclès, roi d’[[w:Épidaure_(cité_antique)|''Épidaure'']]. On prétend que Périandre en devint éperdument amoureux pour l’avoir vue dans l’habillement ordinaire aux femmes du ''Péloponnèse''. Cette passion toutefois ne l’empêcha pas de partager son cœur entre elle et plusieurs concubines. Elles parvinrent à l’irriter contre elle au point qu’un jour, par un mouvement de jalousie, il la frappa d’un coup de pied, sans songer qu’elle était enceinte, et la fit mourir.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Niloxène_NdT_DR_back|<span id="Niloxène_NdT_DR"><sup>4</sup></span>]] Niloxène signifie hôte du ''Nil'' : ce nom semble indiquer que c’est un personnage supposé.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Priene_NdT_DR_back|<span id="Priene_NdT_DR"><sup>5</sup></span>]] Ville d’''Ionie'', colonie des ''Thébains'' et patrie de Bias.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#tyrans_NdT_DR_back|<span id="tyrans_NdT_DR"><sup>6</sup></span>]] Par le mot [[wikt:τύραννος#Grec_ancien|τύραννος]], que nous ne pouvons rendre en français que par celui de tyran, les ''Grecs'' entendaient, non pas seulement, comme nous, un prince injuste et cruel ; mais, en général, tout homme qui s’était emparé de l’autorité monarchique dans un état libre, sans qu’elle lui fût légitimement acquise.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Molpagore_NdT_DR_back|<span id="Molpagore_NdT_DR"><sup>7</sup></span>]] Ce Molpagore est peut-être le père d’Aristagore, que Darius établit tyran à ''Milet''.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Myrsile_NdT_DR_back|<span id="Myrsile_NdT_DR"><sup>8</sup></span>]] Myrsile n’est guère mieux connu que Molpagore. Strabon le met au nombre de ces ''Lesbiens'' ambitieux, qui, du temps de Pittacus, s’étaient emparés de l’autorité souveraine à ''Lesbos'', et dont le poète [[w:Alcée_de_Mytilène|Alcée]] avait flétri la mémoire.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Pittacus_NdT_DR_back|<span id="Pittacus_NdT_DR"><sup>9</sup></span>]] Pittacus en se voyant forcé, dans sa vieillesse, de reprendre le gouvernement des affaires, prononça cette maxime.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Sybarites_NdT_DR_back|<span id="Sybarites_NdT_DR"><sup>10</sup></span>]] Cet usage des ''Sybarites'' n’avait lieu que dans les festins publics.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#squelette_NdT_DR_back|<span id="squelette_NdT_DR"><sup>11</sup></span>]] Cet usage, d’abord particulier aux ''Egyptiens'', avait ensuite passé chez les ''Grecs'', de qui les ''Romains'' l’empruntèrent. ''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' pp.326-330, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe III.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage de la reconnaissance de la sagesse de '''Cléobuline''' ''« Eumétis »'' par '''Thalès''', de l’humilité de ce dernier et de son [[w:Cynisme|''cynisme'']], en particulier à la vue d’un ''centaure'' [[#centaure|<span id="centaure_back"><sup>'''I'''</sup></span>]]. </div> {{Boîte déroulante début|titre=NdA centaure|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#centaure_back|<span id="centaure"><sup>I</sup></span>]] Il s’agit d’une adaptation d’une fable de [[w:Phèdre_(fabuliste)|Phèdre]] [[#Phèdre|<span id="Phèdre_back"><sup>II</sup></span>]], où Ésope [[#Ésope_back|<sup>⤴️</sup>]] remplace Thalès [https://books.openedition.org/pur/12177 {{info|<sup>🔍</sup>|Gourmelen, Laurent. « Imposture ou dualité : que faut-il penser de la naissance d’un centaure ? Sur un curieux passage du Banquet des Sept Sages (Plutarque, Moralia, 149 C-F) ». L’imposture dans la littérature, édité par Arlette Bouloumié, Presses universitaires de Rennes, 2011, https://doi.org/10.4000/books.pur.12177.}}] :'''<br /><br /><p style="margin: 0 2em; text-align: center;">« Un homme d’expérience en sait plus long qu’un devin. C’est un proverbe; d’où vient-il? on ne le dit pas. Ma fable, la première, va l’apprendre.<br /><br />Un fermier avait des brebis qui lui donnaient des agneaux à tête humaine. Épouvanté d’une monstruosité pareille, il court tout affligé consulter les devins. L’un répond que la vie du maître est menacée, et qu’il faut conjurer le péril par une victime. L’autre assure au fermier que sa femme lui est infidèle, et que cela signifie l’illégitimité des enfants; mais qu’un sacrifice important peut tout expier. Enfin, tous diffèrent d’opinion et ne font qu’aggraver le souci du paysan. '''Ésope''', vieillard plein de finesse et de sagacité, et que la nature ne put jamais tromper, se trouvait là par hasard : "Villageois, lui dit-il, si tu veux faire cesser ce prodige, donne des femmes tes bergers." » <br /><br /><p style="text-align: right; margin: 0 2em 0 1em;">'''[https://remacle.org/bloodwolf/fabulistes/phedre/livre3.htm <u>Fables de Phèdre</u>, livre III], §3 - Ésope et le paysan, traduites par M. E. Panckoucke, 1864.<br /><br /><p style="margin: 0 2em; text-indent: 15px;">[[#Phèdre_back|<span id="Phèdre"><sup>II</sup></span>]] [[w:Nom_romain|Tria Nomina]] en latin {{Info|Caius|praenomen, nom individuel du citoyen romain}} {{Info|Iulius|nomen, nom de famille}} {{Info|Phaedrus ou Phaeder|cognomen, surnom héréditaire, servant à distinguer les diverses branches d’une même gens}} ;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ du grec ancien Φαῖδρος / Phaîdros [[wikt:en:Φαῖδρος#Ancient_Greek|(en)]] ; de l’adjectif phaidrós / phaidrós [[wikt:en:φαιδρός#Ancient_Greek|(en)]], « 1. Lumineux, rayonnant. 2. (au sens figuré) Rayonnant de joie, brillant, joyeux. » ;<br /><p style="margin: 0 2em; text-indent: 15px;">Fabuliste latin d’origine ''[[w:thrace|thrace]]'', esclave à son arrivée à ''Rome'' et affranchi par un décret d’[[w:Auguste|Auguste]]. Près d’un tiers de son œuvre est repris d’Ésope dont il adapte les fables ; les deux autres tiers sont issus de son imagination. Tout comme son prédécesseur, Phèdre raconte des histoires d’animaux, mais il met en scène aussi des personnages humains et parmi ceux-ci Ésope :'''<br /><br /><p style="margin: 0 2em; text-align: center;">« C’est '''Ésope''' qui, le premier, a trouvé la matière : moi, je l’ai polie en vers [[w:Sénaire iambique|''sénaires'']]. Ce petit livre a un double mérite : il fait rire et il donne de sages conseils pour la conduite de la vie. À celui qui viendrait me reprocher injustement de faire parler non seulement les animaux, mais même les arbres, je rappellerai que je m’amuse ici à de pures fictions. »<br /><p style="margin: 0 2em; text-align: right;">'''Phèdre, ''Fables'', I, prologue'''<br /><br /><p style="margin: 0 2em; text-align: center;">« Le genre d’'''Ésope''' est tout en exemples, et on ne doit y chercher que le but de ses fables : corriger les erreurs des hommes, et exciter en eux une vive émulation. Quelle que soit donc la nature d’un récit, s’il captive, et remplit son objet, il se recommande de lui-même, sans aucun nom d’auteur. Aussi suivrai-je scrupuleusement les traces du vieillard. »<br /><p style="margin: 0 2em; text-align: right;">'''Phèdre, ''Fables'', II, prologue'''<br /><br /><p style="margin: 0 2em; text-indent: 15px;">'''Au total, il composera cent-vingt-trois fables, divisées en cinq livres.<br /><p style="text-align: right; margin: 0 2em;">(vers [[w:-14|-14]] <sup>[[w:Ier_siècle_av._J.-C.|⏳]]</sup>, en ''Thrace'' ― vers [[w:50|50]] <sup>[[w:Ier_siècle|⏳]]</sup>, lieu de décès inconnu)'''<br /><br /> </div>{{Boîte déroulante fin}} :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§3. Ἐν τοιούτοις λόγοις γενόμενοι κατὰ τὴν ὁδὸν ἀφικόμεθα πρὸς τὴν οἰκίαν, καὶ λούσασθαι μὲν ὁ Θαλῆς οὐκ ἠθέλησεν, ἀληλιμμένοι γὰρ ἦμεν· ἐπιὼν δὲ τούς τε δρόμους ἐθεᾶτο καὶ τὰς παλαίστρας καὶ τὸ ἄλσος τὸ παρὰ τὴν θάλατταν ἱκανῶς διακεκοσμημένον, ὑπ´ οὐδενὸς ἐκπληττόμενος τῶν τοιούτων, ἀλλ´ ὅπως μὴ καταφρονεῖν δοκοίη μηδ´ ὑπερορᾶν τοῦ Περιάνδρου τῆς φιλοτιμίας. τῶν δ´ ἄλλων τὸν ἀλειψάμενον ἢ λουσάμενον οἱ θεράποντες εἰσῆγον εἰς τὸν ἀνδρῶνα διὰ τῆς στοᾶς. Ὁ δ´ Ἀνάχαρσις ἐν τῇ στοᾷ καθῆστο, καὶ παιδίσκη προειστήκει τὴν κόμην ταῖς χερσὶ διακρίνουσα. ταύτην ὁ Θαλῆς ἐλευθεριώτατά πως αὐτῷ προσδραμοῦσαν ἐφίλησε καὶ γελάσας « οὕτως, » ἔφη, « ποίει καλὸν τὸν ξένον, ὅπως ἡμερώτατος ὢν μὴ φοβερὸς ᾖ τὴν ὄψιν ἡμῖν μηδ´ ἄγριος. » Ἐμοῦ δ´ ἐρομένου περὶ τῆς παιδὸς ἥτις εἴη, « τὴν σοφήν, » ἔφη, « καὶ περιβόητον ἀγνοεῖς Εὔμητιν; οὕτω γὰρ ταύτην ὁ πατὴρ αὐτός, οἱ δὲ πολλοὶ πατρόθεν ὀνομάζουσι Κλεοβουλίνην. » Καὶ ὁ Νειλόξενος εἶπεν « ἦ που τὴν περὶ τὰ αἰνίγματα δεινότητα καὶ σοφίαν, » ἔφη, « τῆς κόρης ἐπαινεῖς· καὶ γὰρ εἰς Αἴγυπτον ἔνια τῶν προβαλλομένων ὑπ´ αὐτῆς διῖκται. » « Οὐκ ἔγωγ´, » εἶπεν ὁ Θαλῆς· « τούτοις γὰρ ὥσπερ ἀστραγάλοις, ὅταν τύχῃ, παίζουσα χρῆται καὶ διαβάλλεται πρὸς τοὺς ἐντυχόντας. ἀλλὰ καὶ φρόνημα θαυμαστὸν καὶ νοῦς ἔνεστι πολιτικὸς καὶ φιλάνθρωπον ἦθος, καὶ τὸν πατέρα τοῖς πολίταις πραότερον ἄρχοντα παρέχει καὶ δημοτικώτερον. » « Εἶεν, » ὁ Νειλόξενος ἔφη, « καὶ φαίνεται βλέποντι πρὸς τὴν λιτότητα καὶ ἀφέλειαν αὐτῆς· Ἀνάχαρσιν δὲ πόθεν οὕτω τημελεῖ φιλοστόργως; » « Ὅτι, » ἔφη, « σώφρων ἀνήρ ἐστι καὶ πολυμαθής, καὶ τὴν δίαιταν αὐτῇ καὶ τὸν καθαρμόν, ᾧ χρῶνται Σκύθαι περὶ τοὺς κάμνοντας, ἀφθόνως καὶ προθύμως παραδέδωκε. καὶ νῦν οἶμαι περιέπειν αὐτὴν τὸν ἄνδρα καὶ φιλοφρονεῖσθαι, μανθάνουσάν τι καὶ προσδιαλεγομένην. » Ἤδη δὲ πλησίον οὖσιν ἡμῖν τοῦ ἀνδρῶνος ἀπήντησεν Ἀλεξίδημος ὁ Μιλήσιος (ἦν δὲ Θρασυβούλου τοῦ τυράννου νόθος) καὶ ἐξῄει τεταραγμένος καὶ σὺν ὀργῇ τινι πρὸς αὑτὸν οὐδὲν ἡμῖν γε σαφὲς διαλεγόμενος. ὡς δὲ τὸν Θαλῆν εἶδε, μικρὸν ἀνενεγκὼν καὶ καταστάς « οἵαν ὕβριν, » εἶπεν, « εἰς ἡμᾶς Περίανδρος ὕβρικεν, ἐκπλεῦσαι μὲν οὐκ ἐάσας ὡρμημένον ἀλλὰ προσμεῖναι δεηθεὶς τὸ δεῖπνον, ἐλθόντι δὲ νέμων κλισίαν ἄτιμον, Αἰολεῖς δὲ καὶ νησιώτας (καὶ τίνας γὰρ οὐχί;) Θρασυβούλου προτιμῶν· Θρασύβουλον γὰρ ἐν ἐμοὶ τὸν πέμψαντα προπηλακίσαι βουλόμενος καὶ καταβαλεῖν ὡς δὴ περιορῶν δῆλός ἐστιν. » « Εἶτ´, » ἔφη, « σὺ δέδιας μὴ καθάπερ Αἰγύπτιοι τοὺς ἀστέρας ὑψώματα καὶ ταπεινώματα λαμβάνοντας ἐν τοῖς τόποις οὓς διεξίασι γίγνεσθαι βελτίονας ἢ χείρονας ἑαυτῶν λέγουσιν, οὕτως ἡ περὶ σὲ διὰ τὸν τόπον ἀμαύρωσις ἢ ταπείνωσις γένηται; καὶ τοῦ Λάκωνος ἔσῃ φαυλότερος, ὃς ἐν χορῷ τινι κατασταθεὶς εἰς τὴν ἐσχάτην χώραν ὑπὸ τοῦ ἄρχοντος ‘εὖ γ´,’ εἶπεν, ‘ἐξεῦρες, ὡς καὶ αὕτα ἔντιμος γένηται.’ οὐ καταλαβόντας, » ἔφη, « τόπον μετὰ τίνας κατακείμεθα δεῖ ζητεῖν, μᾶλλον δ´ ὅπως εὐάρμοστοι τοῖς συγκατακειμένοις ὦμεν, ἀρχὴν καὶ λαβὴν φιλίας εὐθὺς ἐν αὐτοῖς ζητοῦντες, μᾶλλον δ´ ἔχοντες τὸ μὴ δυσκολαίνειν ἀλλ´ ἐπαινεῖν ὅτι τοιούτοις συγκατεκλίθημεν· ὡς ὅ γε τόπῳ κλισίας δυσχεραίνων δυσχεραίνει τῷ συγκλίτῃ μᾶλλον ἢ τῷ κεκληκότι, καὶ πρὸς ἀμφοτέρους ἀπεχθάνεται. » « Λόγος, » ἔφη, « ταῦτ´ ἄλλως ἐστίν » ὁ Ἀλεξίδημος, « ἔργῳ δὲ καὶ τοὺς σοφοὺς ὑμᾶς ὁρῶ τὸ τιμᾶσθαι διώκοντας, » καὶ ἅμα παραμειψάμενος ἡμᾶς ἀπῆλθε. Καὶ ὁ Θαλῆς πρὸς ἡμᾶς τὴν ἀτοπίαν τοῦ ἀνθρώπου θαυμάζοντας, « ἔμπληκτος, » ἔφη, « καὶ ἀλλόκοτος φύσει, ἐπεὶ καὶ μειράκιον ὢν ἔτι, μύρου σπουδαίου Θρασυβούλῳ κομισθέντος, εἰς ψυκτῆρα κατεράσας μέγαν καὶ προσεγχέας ἄκρατον ἐξέπιεν, ἔχθραν ἀντὶ φιλίας Θρασυβούλῳ διαπεπραγμένος. » Ἐκ τούτου περιελθὼν ὑπηρέτης « κελεύει σε Περίανδρος, » ἔφη, « καὶ Θαλῆν παραλαβόντα τοῦτον ἐπισκέψασθαι τὸ κεκομισμένον ἀρτίως αὐτῷ πότερον ἄλλως γέγονεν ἤ τι σημεῖόν ἐστι καὶ τέρας· αὐτὸς μὲν γὰρ ἔοικε τεταράχθαι σφόδρα, μίασμα καὶ κηλῖδα τῆς θυσίας ἡγούμενος. » ἅμα δ´ ἀπῆγεν ἡμᾶς εἴς τι οἴκημα τῶν περὶ τὸν κῆπον. ἐνταῦθα νεανίσκος ὡς ἐφαίνετο νομευτικός, οὔπω γενειῶν ἄλλως τε τὸ εἶδος οὐκ ἀγεννής, ἀναπτύξας τινὰ διφθέραν ἔδειξεν ἡμῖν βρέφος ὡς ἔφη γεγονὸς ἐξ ἵππου, τὰ μὲν ἄνω μέχρι τοῦ τραχήλου καὶ τῶν χειρῶν ἀνθρωπόμορφον, τὰ λοιπὰ δ´ ἔχον ἵππου, τῇ δὲ φωνῇ καθάπερ τὰ νεογνὰ παιδάρια κλαυθμυριζόμενον. ὁ μὲν οὖν Νειλόξενος, « Ἀλεξίκακε » εἰπών, ἀπεστράφη τὴν ὄψιν, ὁ δὲ Θαλῆς προσέβλεπε τῷ νεανίσκῳ πολὺν χρόνον, εἶτα μειδιάσας (εἰώθει δ´ ἀεὶ παίζειν πρὸς ἐμὲ περὶ τῆς τέχνης) « ἦ που τὸν καθαρμόν, ὦ Διόκλεις, » ἔφη, « κινεῖν διανοῇ καὶ παρέχειν πράγματα τοῖς ἀποτροπαίοις, ὥς τινος δεινοῦ καὶ μεγάλου συμβάντος; » « Τί δ´, » εἶπον, « οὐ μέλλω; στάσεως γάρ, ὦ Θαλῆ, καὶ διαφορᾶς τὸ σημεῖόν ἐστι, καὶ δέδια μὴ μέχρι γάμου καὶ γενεᾶς ἐξίκηται, πρὶν ἢ τὸ πρῶτον ἐξιλάσασθαι μήνιμα, τῆς θεοῦ δεύτερον ὡς ὁρᾷς προφαινούσης. » Πρὸς τοῦτο μηδὲν ἀποκρινάμενος ὁ Θαλῆς ἀλλὰ γελῶν ἀπηλλάττετο. καὶ τοῦ Περιάνδρου πρὸς τὰς θύρας ἀπαντήσαντος ἡμῖν καὶ διαπυθομένου περὶ ὧν εἴδομεν, ἀφεὶς ὁ Θαλῆς με καὶ λαβόμενος τῆς ἐκείνου χειρὸς ἔφη, « ἃ μὲν Διοκλῆς κελεύει δράσεις καθ´ ἡσυχίαν· ἐγὼ δέ σοι παραινῶ νέοις οὕτω μὴ χρῆσθαι νομεῦσιν ἵππων, ἢ διδόναι γυναῖκας αὐτοῖς. » Ἔδοξε μὲν οὖν μοι τῶν λόγων ἀκούσας ὁ Περίανδρος ἡσθῆναι σφόδρα· καὶ γὰρ ἐξεγέλασε καὶ τὸν Θαλῆν περιβαλὼν κατησπάσατο. κἀκεῖνος « οἶμαι δ´, » εἶπεν, « ὦ Διόκλεις, καὶ πέρας ἔσχε τὸ σημεῖον· ὁρᾷς γὰρ ἡλίκον κακὸν γέγονεν ἡμῖν, Ἀλεξιδήμου συνδειπνεῖν μὴ θελήσαντος. » </div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §3'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§3. Ce fut en tenant de tels propos chemin faisant, que nous arrivâmes à la maison. '''Thalès''' ne voulut pas se baigner : « Je me suis frotté d’huile. » dit-il. Il se promena donc de côté et d’autre, regardant les champs de course, les palestres, et le bois sacré, voisin de la mer, que l’on avait bien convenablement disposé. Ce n’était pas qu’il fût frappé par aucun de ces préparatifs, mais il voulait ne pas avoir l’air de mépriser '''Périandre''' et de faire peu de cas de l’empressement avec lequel celui-ci honorait ses hôtes. Pour les autres convives, à mesure qu’ils s’étaient parfumés ou baignés, les serviteurs les introduisaient par la galerie dans la salle du banquet. Or '''Anacharsis''' s’était installé dans cette galerie, et devant lui une jeune fille se tenait, lui séparant les cheveux avec ses mains. Lorsqu’entra '''Thalès''', elle s’élança très librement à sa rencontre, et '''Thalès''', après l’avoir embrassée, lui dit en riant : « Continue à rendre bien beau notre étranger, afin qu’étant devenu la douceur même il ne conserve pas au milieu de nous une mine à faire peur et un aspect sauvage. » Je lui demandai quelle était cette jeune enfant : « Quoi ! » me dit-il, « vous ne connaissez pas la savante et célèbre '''Eumétis''' ! car c’est ainsi que son père la nomme : le plus communément on l’appelle '''Cléobuline''', du nom paternel. » Et '''Niloxène''' : « C’est sans doute à cause de son talent et de son habileté pour les énigmes, que vous faites l’éloge de cette jeune fille : car quelques-unes de celles qu’elle a proposées sont parvenues jusqu’en ''Égypte''. » — « Ce n’est pas à cause de cela », répondit '''Thalès''' : « les énigmes sont pour elle des joujoux dont elle s’amuse à l’occasion pour faire sa partie avec ceux qui se rencontrent. Mais ce qui est admirable en elle c’est sa profondeur d’esprit, son sens politique, l’aménité de son caractère, et le talent qu’elle a de rendre plus douce l’autorité de son père et d’inspirer à celui-ci des sentiments plus humains à l’égard du peuple. » — « Soit », dit '''Niloxène''' ; « et cela se reconnaît à voir sa modestie et sa simplicité. Mais d’où vient qu’elle prend un soin si amoureux de la toilette d’'''Anacharsis''' ? » — Parce que c’est, répondit '''Thalès''', « un sage, un homme des plus instruits, et parce qu’il lui a communiqué, avec de nombreux détails et de grand coeur, l’ensemble des pratiques sanitaires et des purifications que les ''Scythes'' appliquent au traitement des malades. Et dans ce moment je suppose qu’elle l’entoure de soins et d’amitiés parce qu’elle s’instruit de quelque chose en conversant avec lui. » Comme nous étions déjà près de la salle, '''Alexidème''' le ''Milésien'' vint à notre rencontre. C’était un bâtard du tyran '''Thrasybule'''. Il était sorti tout troublé, et avec une sorte de fureur il se parlait à lui-même, mais ses paroles n’avaient rien de clair pour nous. Quand il eut vu '''Thalès''', il se remit un peu ; puis, s’arrêtant tout court : « Quel affront '''Périandre''' vient de nous faire ! Je voulais mettre à la voile : il ne l’a pas permis ; il m’a supplié de rester à son festin, et quand j’arrive, il me donne une des dernières places, faisant passer des [[w:Éoliens|''Éoliens'']], des insulaires (je ne sais qui il ne me préfère pas), les faisant passer, dis je, avant '''Thrasybule''', car c’est '''Thrasybule''' en ma personne, c’est celui par lequel je suis envoyé qu’il a l’intention de traîner dans la boue et de ravaler comme le méprisant : la chose est bien claire. » — « Eh quoi ! » lui dit '''Thalès''', « êtes-vous comme les ''Égyptiens'', qui prétendent que les astres, suivant qu’ils prennent une position élevée ou basse en parcourant leur orbite, ont une condition meilleure ou pire qu’ils ne l’avaient ? Craignez-vous, pareillement, qu’autour de vous, en raison de la place où vous serez, il ne se produise obscurité ou dépression ? Serez-vous moins résigné que certain ''Spartiate'' ? À je ne sais quelle représentation il avait été placé au dernier rang par le maître des cérémonies : « Voilà qui va bien », lui dit-il : « tu as trouvé moyen de rendre honorable ce lieu même. Quand nous avons pris une place nous ne devons pas chercher au-dessous de qui nous sommes installés, mais plutôt comment nous nous mettrons en bon accord avec nos voisins. À leur occasion nous ferons voir tout d’abord, ou plutôt nous l’éprouverons réellement, un désir d’initiative et de prise de possession en matière d’amitié, et nous manifesterons ce désir en nous félicitant, loin d’en montrer du dépit, de ce que l’on nous a placés en une telle compagnie. Mais celui qui se plaint du rang qu’on lui donne à table montre plus de mécontentement contre son commensal que contre son hôte, et il se rend odieux à l’un et à l’autre. » — « Paroles que tout cela, » dit '''Alexidème''', « et paroles sans portée ! Mais je vois que de fait, vous autres sages, vous recherchez aussi les honneurs. » En même temps il s’éloigna de nous et disparut. Une conduite si étrange nous semblait étonnante. « C’est », nous dit '''Thalès''', « un homme écervelé et naturellement bizarre. Vous allez en juger. Il était encore tout jeune ; on avait apporté à '''Thrasybule''' un parfum d’un très haut prix. '''Alexidème''' le versa dans un grand vase à rafraîchir, y mêla du vin pur, et avala le tout, rendant son père odieux au lieu de le faire aimer. » Au même moment parut un serviteur : « Vous êtes invité par '''Périandre''' », me dit-il, « à venir, en vous faisant accompagner de '''Thalès''' que voici, examiner l’objet qu’on lui a récemment apporté, afin que vous disiez si c’est une création toute fortuite, ou bien un présage et une monstruosité; car, pour ce qui est de '''Périandre''', il a l’air grandement troublé, pensant que c’est une souillure et une profanation pour son sacrifice. » En même temps, il nous emmena vers une des salles qui donnaient sur le jardin. Là un jeune homme paraissant appartenir à la classe des bergers, qui n’avait pas encore de barbe et dont la physionomie ne manquait pas de noblesse, déploya une espèce de couverture en cuir, et nous montra un petit enfant né, disait-il, d’une cavale. Par le haut, jusqu’au cou et aux mains, cette créature était de forme humaine ; mais le reste était d’un cheval, et sa voix avait quelque chose des vagissements poussés par les petits enfants qui viennent de naître. « Dieu préservateur ! » s’écria '''Niloxène''', et il détourna les yeux. Mais '''Thalès''' fixa longtemps son regard sur le jeune pâtre; puis s’étant mis à sourire, (car il avait l’habitude de plaisanter toujours avec moi sur ma profession) : « Eh bien, '''Dioclès''', » dit-il, « songez-vous à préparer quelque expiation, et à donner de la besogne aux dieux préservateurs, comme vous trouvant en présence de quelque événement grave et considérable ? » — « Pourquoi non ? » répondis-je : « j’y vois le présage de troubles et de discordes qui s’étendront, j’en ai peur, jusqu’à un mariage et une génération avant que le courroux de la déesse ait été apaisé, puisqu’elle fait, vous le savez, une seconde manifestation ». À ces paroles '''Thalès''' ne répondit rien : il se contenta de rire et de s’en aller. Et comme '''Périandre''' était à la porte, s’avançant pour nous interroger sur ce que nous venions de voir, '''Thalès''' me quitta et le prit par la main : « Ce que '''Dioclès''' prescrira, vous l’exécuterez à loisir », lui dit-il ; « mais moi j’ai un conseil à vous donner : pour faire paître vos juments ne prenez pas de jeunes garçons, ou bien à ceux-ci donnez des femmes. » Ces paroles me semblèrent causer, des qu’il les eut entendues, une vive satisfaction à '''Périandre''', car il éclata de rire et serra très affectueusement '''Thalès''' dans ses bras. '''Thalès''' alors : « '''Dioclès''' », me dit-il, « si je conjecture bien, le prodige reçoit déjà son accomplissement. Car vous voyez quel grand malheur nous est arrivé, '''Alexidème''' n’ayant pas voulu souper avec nous. »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §3'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Après avoir ainsi conversé pendant le chemin, nous arrivâmes au lieu destiné pour le banquet. '''Thalès''' ne voulut point entrer dans le bain, parcequ’il s’était déja parfumé, mais il se promena dans les dehors, s’arrêta à voir les luttes et les courses ; il alla voir le bocage voisin de la mer, qu’on avait décoré avec beaucoup de soin, non qu’il fût frappé de tout cet appareil, mais pour ne point paraître mépriser '''Périandre''' et dédaigner sa magnificence. Tous les autres convives, à mesure qu’ils sortaient du bain, étaient introduits par des esclaves dans la salle du banquet. '''Anacharsis''' seul était assis sous le portique, une jeune fille, debout, lui arrangeait les cheveux. Dès qu’elle vit '''Thalès''', elle accourut très librement au-devant de lui ; ce philosophe l’embrassa, et lui dit en riant : « Parez cet hôte du mieux que vous pourrez, afin que le plus doux des hommes n'’ait plus un extérieur sauvage et effrayant. » Je lui demandai quelle était cette jeune personne : « Eh quoi ! me répondit-il, vous ne connaissez pas la sage et fameuse '''Eumétis''' ? C’est le nom que '''Cléobule''' lui donne, mais les autres l’appellent '''Cléobuline''', du nom de son père. - Est-ce, dit '''Niloxène''', à cause de sa subtilité et de son adresse à composer des énigmes, que vous faites ainsi son éloge ? Quelques unes de celles qu’on lui attribue ont pénétré jusqu’en ''Egypte''. - Non, répliqua '''Thalès''' ; ces énigmes ne sont que des jouets dont elle s’amuse dans l’occasion pour éprouver la perspicacité de ceux qu’elle rencontre. Ce qu’elle a de vraiment admirable, c’est sa grande prudence, sa capacité pour les affaires, son humanité, et l’attention qu’elle a de rendre le gouvernement de son père doux et bienfaisant. - Il est vrai, reprit '''Niloxène''', que sa modestie et sa simplicité annoncent combien elle est populaire. Mais d’où viennent ces soins et cet intérêt pour '''Anacharsis''' ? - Parceque c’est un homme sensé et très instruit, répondit '''Thalès''', qu’il s’est fait un plaisir de lui apprendre en détail le régime et le traitement que les ''Scythes'' emploient dans les maladies. Je suis sûr que dans ce moment même où elle le pare avec tant de soin, elle s’entretient utilement avec lui, et cherche à s’instruire. » Nous approchions de la salle, lorsque nous rencontrâmes '''Alexidème''' de ''Milet'', fils naturel du tyran '''Thrasybule'''. Il sortait tout troublé, et d’un ton de colère murmurait quelques mots que nous ne pûmes entendre. Dès qu’il vit '''Thalès''', il se remit un peu ; et en lui adressant la parole, il lui dit : « Quel indigne affront '''Périandre''' vient de nous faire ! J’allais partir, il me retient, il me prie de rester à son festin ; et quand j’arrive, il m’y donne la dernière place : il préfère un ''éolien'', un insulaire, enfin je ne sais qui, à '''Thrasybule''', car il est évident que c’est '''Thrasybule''' que '''Périandre''' méprise, et brave ouvertement dans la personne de son envoyé [[#Thrasybule_NdT_DR|<span id="Thrasybule_NdT_DR_back"><sup>1</sup></span>]]. - Eh quoi ! lui dit '''Thalès''', craignez-vous que la place que vous occuperez à table ne vous rende plus grand ou plus petit, comme les ''Égyptiens'' disent que les astres brillent plus ou moins, suivant que le cercle qu’ils parcourent est plus ou moins élevé ? Et vous estimeriez-vous moins que ce ''Lacédémonien'', qui, dans une assemblée publique, placé par le magistrat au dernier rang, lui dit : Vous avez trouvé le moyen de rendre cette place honorable [[#place_honorable_NdT_DR|<span id="place_honorable_NdT_DR_back"><sup>2</sup></span>]] ? Doit-on en effet examiner après qui l’on est placé ? Ne faut-il pas plutôt s’accommoder de ceux qu’on a pour voisins, afin d’avoir une occasion naturelle de se lier avec eux, et loin de se fâcher du rang qu’on occupe, témoigner sa satisfaction de se trouver auprès d’eux ? Celui qui se plaint de la place qu’on lui assigne semble plus mécontent de son voisin que de son hôte, et se rend odieux à l’un et à l’autre . - Belles paroles que cela, repartit '''Alexidème'''. Mais, dans le fait, je vois que vous autres sages, vous recherchez les honneurs aussi bien que nous. » En même temps, il nous quitte brusquement, et s’en va. Une conduite si étrange nous étonna tous : « Ce jeune et homme, nous dit '''Thalès''', a montré dès l’enfance un caractère dur et emporté. Un jour qu’on avait fait présent à '''Thrasybule''' d’un parfum de grand prix, il le versa dans une coupe mêlé avec du vin, et l’avala, payant ainsi d’ingratitude la tendresse de son père. » Au même instant, un des gens de '''Périandre''' vint me prier d’aller avec '''Thalès''' voir quelque chose d’extraordinaire qu’on venait de lui apporter, afin de juger si c’était un jeu de la nature ou un prodige menaçant ; il nous dit qu’il en était tout troublé, et qu’il craignait que son sacrifice n’en fût souillé. En même temps, il nous conduit dans une salle qui donnait sur le jardin. Nous y trouvâmes un jeune homme sans barbe, d’une figure intéressante, qui avait l’air d’un berger. Il lève une espèce de peau, et nous fait voir un enfant qu’il disait être né d’une cavale, qui avait la tête, le cou et les mains d’un homme, et dans tout le reste, était fait comme un cheval. Sa voix ressemblait à celle d’un enfant qui vient de naître : « Dieu préservateur ! s’écria '''Niloxène''', en détournant la vue. » Mais '''Thalès''', qui a coutume de plaisanter avec moi sur mon art, après avoir longtemps considéré ce jeune homme, me dit en souriant : « Ne pensez-vous pas déja, '''Dioclès''', à faire des expiations ? Et pour détourner un présage si terrible, n’allez-vous pas donner bien de l’ouvrage aux dieux préservateurs ? - Pourquoi non ? lui répondis-je. Ce prodige, '''Thalès''', est un signe menaçant de troubles et de discorde ; et je crains bien que l’épouse et les enfants de '''Périandre''' n’en éprouvent les tristes suites, puisque enfin, comme vous voyez, avant que la déesse soit apaisée, elle donne une nouvelle marque de son courroux. » A ces mots, '''Thalès''' sourit et sortit sans rien répondre. Il vit, à la porte de la salle, '''Périandre''' venir au-devant de nous, pour savoir notre sentiment. Il me quitta, lui prit la main, et lui dit : « '''Dioclès''' vous parlera ; vous ferez à loisir ce qu’il vous dira. Pour moi, je pense que vous ne devez pas avoir, pour garder vos juments, des bergers aussi jeunes, ou que vous devez les marier. » Ce discours parut faire grand plaisir à '''Périandre''', car il en rit beaucoup, et embrassa affectueusement '''Thalès'''. Celui-ci s’adressant à moi : « Je crois, '''Dioclès''', me dit-il, que le prodige a déja eu son accomplissement. Vous voyez le malheur qui vient de nous arriver ; '''Alexidème''' a refusé de souper avec nous. » </div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Thrasybule_NdT_DR_back|<span id="Thrasybule_NdT_DR"><sup>1</sup></span>]]Dans les ''Propos de table'', on trouve une aventure pareille, arrivée chez Timon, frère de Plutarque ; mais le personnage n’est pas nommé. ''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#place_honorable_NdT_DR_back|<span id="place_honorable_NdT_DR"><sup>2</sup></span>]] Plutarque, dans les ''apophthegmes des Lacédémoniens'', nomme ce ''Spartiate'' Dæmonidas, et attribue un mot semblable au fameux Agésilas. ''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' pp.330-334, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe IV.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage du caractère désinvolte de '''Thalès'''.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§4. Ἐπεὶ δ´ εἰσήλθομεν, ἤδη μεῖζον ὁ Θαλῆς φθεγξάμενος « ποῦ δ´ » εἶπεν « ὁ ἀνὴρ κατακλινάμενος ἐδυσχέρανεν; » ἀποδειχθείσης δὲ τῆς χώρας περιελθὼν ἐκεῖ κατέκλινεν ἑαυτὸν καὶ ἡμᾶς « ἀλλὰ κἂν ἐπριάμην » εἰπών « Ἀρδάλῳ κοινωνεῖν μιᾶς τραπέζης. » ἦν δὲ Τροιζήνιος ὁ Ἄρδαλος, αὐλῳδὸς καὶ ἱερεὺς τῶν Ἀρδαλείων Μουσῶν, ἃς ὁ παλαιὸς Ἄρδαλος ἱδρύσατο ὁ Τροιζήνιος.<br /><p style="text-align: centre">[...]<br /><p style="text-align: justify; text-indent: 15px">καὶ ὁ Θαλῆς ἐμὲ προσαγορεύσας ἐπάνω τοῦ Βίαντος κατακείμενον « τί οὐκ ἔφρασας, » εἶπεν, « ὦ Διόκλεις, Βίαντι τὸν Ναυκρατίτην ξένον ἥκοντα μετὰ προβλημάτων βασιλικῶν αὖθις ἐπ´ αὐτόν, ὅπως νήφων καὶ προσέχων ἑαυτῷ τὸν λόγον δέχηται; » Καὶ ὁ Βίας « ἀλλ´ οὗτος μέν, » ἔφη, « πάλαι δεδίττεται ταῦτα παρακελευόμενος, ἐγὼ δὲ τὸν Διόνυσον οἶδα τά τ´ ἄλλα δεινὸν ὄντα καὶ Λύσιον ἀπὸ σοφίας προσαγορευόμενον, ὥστ´ οὐ δέδια τοῦ θεοῦ μεστὸς γενόμενος μὴ ἀθαρσέστερον ἀγωνίσωμαι. » Τοιαῦτα μὲν ἐκεῖνοι πρὸς ἀλλήλους ἅμα δειπνοῦντες ἔπαιζον·</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §4'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§4. Après que nous fûmes entrés, '''Thalès''' ayant déjà élevé plus haut la voix: « Où donc », dit-il, « l’avait-on placé, cet homme qui s’en est formalisé ? » Quand on lui eut montré l’endroit il fit le tour de la salle, et ce fut là-même qu’il se plaça et nous installa. « En vérité », ajouta-t-il, « j’aurais payé pour partager la même table qu’'''Ardalus'''. » Cet '''Ardalus''' était un joueur de flûte ''Trézénien'', prêtre des ''muses Ardalides'' auxquelles l’antique [[w:Ardalos|'''Ardalus''']] de ''Trézène'' avait dressé des statues.<br /><p style="text-align: center">[...]<br /><p style="text-indent: 15px">Moi, j’étais au-dessus de '''Bias''', et '''Thalès''' m’ayant interpellé : « '''Dioclès''' », me dit-il, « pourquoi n’avez-vous pas dit à '''Bias''' que l’étranger de ''Naucratie'' est venu une seconde fois le trouver avec des questions de la part de son prince, afin que ce soit à jeun qu’il reçoive ces communications et qu’il y applique son esprit ? » Et '''Bias''' : « Il y a longtemps », dit-il, « que '''Dioclès''' me menace de m’y contraindre ; mais je sais que '''Bacchus''', entre autres attributions merveilleuses, possède une sagacité qui l’a fait surnommer le dieu qui délie, de sorte que je ne crains pas, étant rempli de la divinité, que la confiance m’abandonne au moment de la lutte. » C’est ainsi que, pendant le repas, ils échangeaient entre eux des plaisanteries.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §4'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Quand nous fûmes dans la salle, il demanda, en élevant la voix : « Où est donc cette place qui a tant fâché notre homme ? » Quand on la lui eut montrée, il alla s’y placer avec nous : « Certes, ajouta-t-il, j’aurais payé pour être à la même table qu’'''Ardalus'''. » Cet '''Ardalus''' était un joueur de flûte ''træzenien'', prêtre du temple des muses ''Ardalides'', que l’ancien '''Ardalus''' avait fait bâtir à ''Træzène'' [[#Ardalus_NdT_DR|<span id="Ardalus_NdT_DR_back"><sup>1</sup></span>]].<br /><p style="text-align: center">[...]<br /><p style="text-indent: 15px">Comme j’étais au-dessus de '''Bias''', '''Thalès''' m’adressant la parole : « Pourquoi, me dit-il, ne pas avertir '''Bias''' que '''Niloxène''' vient une seconde fois de la part de son prince lui proposer des problèmes à résoudre ? Il y penserait plus librement, tandis qu’il est à jeun. - Il y a longtemps, répondit '''Bias''', que '''Dioclès''' me menace de le faire. Mais je connais la puissance de '''Bacchus''', et surtout cette sagesse qui lui a fait donner le surnom de [[wikt:λύσις#Grec_ancien|''Lysien'']] ou Dieu qui délie. Ainsi, quand je serai plein de ce dieu, je ne crains pas de combattre avec moins d'avantage. ». Ce ton de gaieté régna pendant le repas. </div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Ardalus_NdT_DR_back|<span id="Ardalus_NdT_DR"><sup>1</sup></span>]] Plutarque, dans son traité de la musique, dit qu’Ardalus, fils de Vulcain, selon la Fable, passait pour l’inventeur de la flûte.''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' pp.334, 335, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe VII.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Réflexions de '''Thalès''' sur le défi de sagacité posé par le roi des ''Éthiopiens'' au roi d’''Égypte'', [[w:Ahmôsis_II|'''Amasis''']], consistant à boire la mer. Ce dernier fait appel à '''Bias''' pour la résoudre, et celui-ci souhaite l’examiner en commun avec les sages. '''Chilon''' explique qu’il ne s’agit pas de faire disparaître tant d’eau salée, mais de rendre la domination d’'''Amasis''' potable et douce à ses sujets (§6).</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§7. [...] Ἐπὶ τούτῳ δ´ ὁ '''Θαλῆς''' ἔφησεν, εὐδαιμονίαν ἄρχοντος νομίζειν, εἰ τελευτήσειε γηράσας κατὰ φύσιν.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §7'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§7. [...] Après lui '''Thalès''' prit la parole : « J’estime que le bonheur pour un souverain, c’est s’il meurt de vieillesse et naturellement. ».</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §7'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Après lui, '''Thalès''' dit que le plus grand bonheur d’un prince serait ''de mourir de vieillesse''.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' p.339, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe IX.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Réflexions de '''Thalès''' sur le défi de sagacité posé par le roi d’''Égypte'', [[w:Ahmôsis_II|'''Amasis''']], au roi des ''Éthiopiens'', consistant en une série de questions : « Qu’y a-t-il de plus ancien ? Le temps. — De plus grand ? Le monde. — De plus habile/sage ? La vérité. — De plus beau ? La lumière. — De plus commun ? La mort. — De plus utile ? Dieu. — De plus nuisible ? Le mauvais Génie/démon. — De plus puissant/fort ? La Fortune. — De plus facile ? Le plaisir. ». '''Amasis''' fait encore appel à '''Bias''' pour analyser les réponses du roi des ''Éthiopiens'', qui les examinent également en commun avec les sages.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§9. Τούτων πάλιν ἀναγνωσθέντων, ὦ Νίκαρχε, γενομένης σιωπῆς Θαλῆς ἠρώτησε τὸν Νειλόξενον εἰ προσήκατο τὰς λύσεις ὁ Ἄμασις. ἐκείνου δ´ εἰπόντος ὅτι τὰς μὲν ἀπεδέξατο ταῖς δ´ ἐδυσκόλαινε, « καὶ μὴν οὐδέν, » εἶπεν ὁ Θαλῆς, « ἀνεπίληπτόν ἐστιν, ἀλλ´ ἔχει πάντα διαμαρτίας μεγάλας καὶ ἀγνοίας. οἷον εὐθὺς ὁ χρόνος πῶς ἂν εἴη πρεσβύτατον, εἰ τὸ μὲν αὐτοῦ γεγονὸς τὸ δ´ ἐνεστώς ἐστι τὸ δὲ μέλλον; ὁ γὰρ μεθ´ ἡμᾶς ἐσόμενος χρόνος καὶ πραγμάτων τῶν νῦν καὶ ἀνθρώπων νεώτερος ἂν φανείη. τὸ δὲ τὴν ἀλήθειαν ἡγεῖσθαι σοφίαν οὐδὲν ἐμοὶ δοκεῖ διαφέρειν τοῦ τὸ φῶς ὀφθαλμὸν ἀποφαίνειν. εἰ δὲ τὸ φῶς καλόν, ὥσπερ ἐστὶν, ἐνόμιζε, πῶς τὸν ἥλιον αὐτὸν παρεῖδε; τῶν δ´ ἄλλων ἡ μὲν περὶ θεῶν καὶ δαιμόνων ἀπόκρισις θράσος ἔχει καὶ κίνδυνον, ἀλογίαν δὲ καὶ πολλὴν ἡ περὶ τῆς τύχης· οὐ γὰρ ἂν μετέπιπτε ῥᾳδίως οὕτως, ἰσχυρότατον οὖσα τῶν ὄντων καὶ ῥωμαλεώτατον. οὐ μὴν οὐδ´ ὁ θάνατος κοινότατόν ἐστιν· οὐ γάρ ἐστι πρὸς τοὺς ζῶντας. ἀλλ´ ἵνα μὴ δοκῶμεν εὐθύνειν τὰς τῶν ἑτέρων ἀποφάσεις, ἰδίας ταῖς ἐκείνου παραβάλωμεν· ἐμαυτὸν δὲ παρέχω πρῶτον, εἰ βούλεται Νειλόξενος, ἐρωτᾶν καθ´ ἕκαστον. ὡς οὖν ἐγένοντο τότε, κἀγὼ νῦν διηγήσομαι τὰς ἐρωτήσεις καὶ τὰς ἀποκρίσεις· ‘Τί πρεσβύτατον;’ [[wikt:en:θεός#Ancient_Greek|‘θεός,’]] » ἔφη Θαλῆς· « ‘ἀγέν νητον γάρ ἐστι.’ ‘Τί μέγιστον;’ ‘τόπος· τἄλλα μὲν γὰρ ὁ κόσμος, τὸν δὲ κόσμον οὗτος περιέχει.’ ‘Τί κάλλιστον;’ ‘κόσμος· πᾶν γὰρ τὸ κατὰ τάξιν τούτου μέρος ἐστί.’ ‘Τί σοφώτατον;’ ‘χρόνος· τὰ μὲν γὰρ εὕρηκεν οὗτος ἤδη, τὰ δ´ εὑρήσει.’ ‘Τί κοινότατον;’ ‘ἐλπίς· καὶ γὰρ οἷς ἄλλο μηδέν, αὕτη πάρεστι.’ ‘Τί ὠφελιμώτατον;’ ‘ἀρετή· καὶ γὰρ τἄλλα τῷ χρῆσθαι καλῶς ὠφέλιμα ποιεῖ.’ ‘Τί βλαβερώτατον;’ ‘κακία· καὶ γὰρ τὰ πλεῖστα βλάπτει παραγενομένη.’ ‘Τί ἰσχυρότατον;’ ‘ἀνάγκη· μόνον γὰρ ἀνίκητον.’ ‘Τί ῥᾷστον;’ ‘τὸ κατὰ φύσιν, ἐπεὶ πρὸς ἡδονάς γε πολλάκις ἀπαγορεύουσιν.’ » <br /><br /><p style="text-indent: 15px;">§10. Ἀποδεξαμένων δὲ πάντων τὸν Θαλῆν, ὁ Κλεόδωρος εἶπε, « τοιαῦτ´ ἐρωτᾶν καὶ ἀποκρίνεσθαι βασιλεῦσιν, ὦ Νειλόξενε, προσῆκόν ἐστιν· ὁ δὲ προπίνων τὴν θάλατταν Ἀμάσιδι βάρβαρος ἐδεῖτο τῆς Πιττακοῦ βραχυλογίας, ᾗ πρὸς Ἀλυάττην ἐχρήσατο προστάττοντά τι καὶ γράφοντα Λεσβίοις ὑπερήφανον, ἀποκρινάμενος οὐδὲν ἀλλ´ ἢ μόνον κελεύσας κρόμμυα καὶ θερμὸν ἄρτον ἐσθίειν. »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §9'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§9. Cette lecture ainsi reproduite, mon cher '''Nicarque''', il se fit un moment de silence. Après quoi '''Thalès''' demanda à '''Niloxène''' si '''Amasis''' avait accepté de telles solutions. Il répondit que ce monarque avait accepté les unes et qu’il avait été mécontent des autres. « C’est qu’en effet », dit '''Thalès''', « il n’en est aucune qui soit irréprochable, et toutes sont grandement entachées d’erreur et d’ignorance. Ainsi, d’abord, comment le temps pourrait-il être ce qu’il y a de plus ancien, puisque, une partie étant écoulée, je le veux bien, une autre est le présent, une autre est l’avenir ? Le temps qui doit venir après nous est évidemment plus jeune que les hommes d’aujourd’hui, que les événements actuels. Croire que ce qu’il y a de plus habile, ce soit la vérité, c’est, à mon avis, ne pas émettre une autre opinion que celle-ci : l’oeil et la lumière sont tout un. Si du reste l’''Éthiopien'' a cru, ce qui est réel, la lumière plus belle que tout, pourquoi a-t-il négligé de nommer le soleil lui-même ? Des autres réponses, celle qui concerne la Divinité et le Génie est aussi téméraire que dangereuse ; et ce qu’il dit de la Fortune est tout à fait déraisonnable : car elle ne changerait pas avec tant de facilité, si elle était ce qu’il y a de plus puissant et de plus fort au monde. De même, la mort n’est pas ce qu’il y a de plus commun, puisqu’elle n’est pas commune aux vivants. Mais pour que nous ne semblions pas nous borner à redresser les réponses des autres, il faut y opposer nos propres solutions. Je m’y offre le premier, si '''Niloxène''' veut reprendre chaque question ». Telles que furent faites alors et les demandes et les réponses, je vais vous les reproduire aujourd’hui : Qu’y a-t-il de plus ancien ? C’est dieu, répondit '''Thalès''', attendu qu’il est incréé. — De plus grand ? L’espace : car si le monde contient le reste, à son tour il est contenu dans l’espace. — De plus beau ? Le monde : car tout ce qui est bien ordonné en fait partie. ― De plus habile ? Le temps : car c’est lui qui a découvert et qui découvrira tout. — De plus commun ? L’espérance : car ceux même qui n’ont rien autre chose la possèdent. — De plus utile ? La vertu : car elle rend toutes les autres choses utiles par le bon usage qu’elle en fait. — De plus nuisible ? Le vice : car il corrompt tout par sa présence. — De plus puissant ? La nécessité : car elle est seule invincible. De plus facile ? Ce qui est selon la nature : car, pour ce qui est du plaisir, il amène souvent la lassitude.<br /><br /><p style="text-indent: 15px;">§10. Tout le monde ayant accueilli ces réponses de '''Thalès''', '''Cléodème''' prit la parole : « Voilà », dit-il, « ô '''Niloxène''', les questions et les réponses qu’il est convenable de faire à des rois. Mais le barbare qui veut faire boire la mer à '''Amasis''' aurait besoin de la concision employée par '''Pittacus''' à l’égard d’[[w:Alyatte_II|'''Alyatte''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Alyatte_back|<sup>🔄</sup>]], quand celui-ci enjoignait aux ''Lesbiens'' un ordre des plus insolents. Il se contenta, pour toute réponse, de l’engager « à manger des oignons et du pain chaud. »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §9'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Cette lecture étant finie, il se fit un moment de silence ; après quoi, '''Thalès''' demanda si le roi d’''Égypte'' avait approuvé toutes ces solutions. '''Niloxène''' lui répondit qu’il avait adopté les unes et rejeté les autres : « Mais, reprit '''Thalès''', il n’en est aucune d’admissible, et qui ne soit marquée au coin de l’erreur et de l’ignorance. D'abord, comment le temps peut-il être ce qu’il y a de plus ancien, puisqu’on le divise en passé, présent et avenir ? Ce dernier est certainement moins ancien que les hommes et que les événements actuels. Dire que la vérité est la sagesse, c’est, ce me semble, confondre l’œil avec la lumière. Si d’ailleurs la lumière est, selon lui, ce qu'’il y a de plus beau, pourquoi ne pas nommer le soleil lui-même ? Quant aux autres réponses, celles qu’il a faites sur les dieux et les démons sont aussi hardies que dangereuses. Ce qu’il dit de la fortune est tout à fait déraisonnable. Si elle est réellement si forte et si puissante, comment change-t-elle avec tant de facilité ? Enfin la mort n’est pas ce qu’il y a de plus commun, puisqu’elle n’existe point parmi les vivants. Mais pour qu’on ne croie pas que nous voulons seulement critiquer, opposons à ces réponses nos solutions. Je m’offre le premier pour répondre , si '''Niloxène''' veut reprendre les questions . »<br /><br /><p style="text-indent: 15px;">'''Niloxène''' le fit, et '''Thalès''' donna ses réponses, que je vais vous répéter. Qu’y a-t-il de plus ancien ? Dieu ; car il est éternel. De plus grand ? l’espace ; il contient le monde, qui lui-même renferme tout le reste. De plus beau ? le monde ; tout ce qui est dans l’ordre en fait partie. De plus sage ? le temps ; il a découvert ou découvrira tout. De plus commun ? l’espérance ; elle reste à ceux mêmes qui n’ont rien. De plus utile ? la vertu; elle fait bien user de tout. De plus nuisible ? le vice ; il corrompt tout par sa présence. De plus fort ? la nécessité ; elle seule est invincible. De plus facile ? ce qui est selon la nature ; on se lasse souvent du plaisir même.<br /><br /><p style="text-indent: 15px;">Tout le monde applaudit aux solutions de '''Thalès''' : « Voilà, dit '''Cléodème''', les questions et les réponses qu’il convient à des rois de faire. Pour ce barbare, qui propose à votre prince de boire toute la mer, il lui fallait une réponse aussi courte que celle de '''Pittacus''' au roi de ''Lydie'' '''Alyatte''', qui , dans une lettre, donnait aux ''Lesbiens'' un ordre très impérieux. '''Pittacus''' se contenta de lui récrire : ''Mangez des ognons et du pain chaud'' [[#expression_proverbiale_mépris_NdT_DR|<span id="expression_proverbiale_mépris_NdT_DR_back"><sup>1</sup></span>]].</div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#expression_proverbiale_mépris_NdT_DR_back|<span id="expression_proverbiale_mépris_NdT_DR"><sup>1</sup></span>]] C’est-à-dire : pleurez ; expression proverbiale, pour témoigner du mépris à quelqu’un.''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' pp.341, 342, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe XI.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Réflexion de '''Thalès''' sur les gouvernements où la loi est égale pour tous.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§11. Ἐπὶ τούτῳ '''Θαλῆς''' τὴν μήτε πλουσίους ἄγαν μήτε πένητας ἔχουσαν πολίτας.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §11'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§11. Après lui '''Thalès''' : « que c’est celle qui n’a ni des citoyens trop riches, ni des citoyens trop pauvres. »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §11'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">'''Thalès''' : ''celle dont les citoyens ne sont ni trop riches ni trop pauvres''.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' p.345, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe XII.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Réflexion de '''Thalès''' sur la maison la mieux réglée.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§12. Ὁ δὲ '''Θαλῆς''' ἐν ᾧ πλείστην ἄγειν τῷ δεσπότῃ σχολὴν ἔξεστιν.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §12'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§12. '''Thalès''' : « celle où le maître peut avoir un très grand loisir. »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §12'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">'''Thalès''' : ''celle qui donne le moins d’affaires à son maître''.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' p.346, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe XIII.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Référence à l’anecdote de la coupe de [[w:Bathyclès_de_Magnésie|'''Bathyclès''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_période_Grèce_Hellénistique#Bathyclès_back|<sup>🔄</sup>]] par [[w:Callimaque_de_Cyrène|'''Callimaque''']] de [[w:Cyrène|''Cyrène'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_période_Grèce_Hellénistique#Callimaque_back|<sup>🔄</sup>]].</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§13. Ἐπεὶ δὲ καὶ οὗτος ἔσχεν ὁ λόγος τέλος, ἡ μὲν Εὔμητις ἐξῆλθε μετὰ τῆς Μελίσσης, τοῦ δὲ Περιάνδρου τῷ Χίλωνι προπιόντος εὐμεγέθη κύλικα, τῷ δὲ Βίαντι τοῦ Χίλωνος, Ἄρδαλος ἐπαναστὰς καὶ προσαγορεύσας τὸν Αἴσωπον, « σὺ δ´ οὐκ ἄν, » ἔφη, « διαπέμψαιο δεῦρο τὸ ποτήριον πρὸς ἡμᾶς, ὁρῶν τούτους ὥσπερ τὴν Βαθυκλέους κύλικα διαπεμπομένους ἀλλήλοις, ἑτέρῳ δὲ μὴ μεταδιδόντας; » Καὶ ὁ Αἴσωπος, « ἀλλ´ οὐδὲ τοῦτ´, » ἔφη, « τὸ ποτήριον δημοτικόν ἐστι· Σόλωνι γὰρ ἔκπαλαι παράκειται μόνῳ. »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §13'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§13. Ce texte de conversation se trouvant à son tour épuisé, et '''Eumétis''' étant sortie avec '''Mélissa''', '''Périandre''' but une grande coupe à '''Chilon''', et '''Chilon''', à '''Bias'''. '''Ardalus''' alors se leva, et interpellant '''Ésope''' : « Ne feras-tu pas, dit-il, circuler la coupe jusqu’à nous, quand tu vois qu’ils se la passent mutuellement comme s’il s’agissait de celle de '''Bathycle''' et qu’ils ne la partagent pas avec un autre ? » Et '''Esope''' : « Mais ce vase non plus, dit-il, n’est pas une propriété populaire : car voilà longtemps qu’il reste devant '''Solon''' tout seul ».</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §13'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Après tous ces propos, '''Mélisse''' sortit avec '''Eumétis'''. '''Périandre''' alors boit le premier dans une grande coupe, la présente à '''Chilon''' [[#Chilon_NdT_DR|<span id="Chilon_NdT_DR_back"><sup>1</sup></span>]], et celui-ci à '''Bias''', qui la remit à '''Solon'''. Comme ce dernier la gardait, '''Ardalus''' se lève , et s’adressant à '''Esope''' : « Ne nous ferez-vous point, lui dit-il, passer ce vase, que nos sages, comme vous voyez, se renvoient l’un à l’autre, ainsi que la coupe de '''Bathycle''', sans le faire parvenir jusqu’à nous [[#Bathycle_NdT_DR|<span id="Bathycle_NdT_DR_back"><sup>2</sup></span>]] ? ― Ce vase, lui répondit '''Esope''', n’est sûrement pas populaire, puisqu’il reste si longtemps devant '''Solon'''. »</div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Chilon_NdT_DR_back|<span id="Chilon_NdT_DR"><sup>1</sup></span>]] Cet usage était constant chez les anciens. A la fin du repas, on remplissait de vin une grande coupe. Le principal personnage de l’assemblée en buvait le premier, et la coupe passait ainsi de main en main.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Bathycle_NdT_DR_back|<span id="Bathycle_NdT_DR"><sup>2</sup></span>]] Tout le monde sait l’histoire du fameux trépied d’or, trouvé par des pêcheurs, qui, pour terminer leurs débats, ayant eu recours à l’oracle de ''Delphes'', reçurent ordre d’en faire présent au plus sage, et l’envoyèrent à Thalès. Après avoir passé successivement par les mains des sept sages, il revint à Thalès, qui le consacra dans un temple d’Apollon. Selon Léandre de ''Milet'', cité par Diogène Laërce, c’était une coupe d’or que l’''Arcadien'' Bathycle avait laissée, par son testament, au plus sage, et c’est ce dernier récit que Plutarque semble préférer.''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' p.347, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe XIV.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage de l’''espièglerie'' de '''Thalès'''.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§14. [...] '''Ἐπιστήσαντος''' δὲ τοῦ λόγου τὸ συμπόσιον ὁ μὲν '''Θαλῆς''' ἐπισκώπτων εὖ φρονεῖν ἔφη τὸν '''Ἐπιμενίδην''' ὅτι μὴ βούλεται πράγματα ἔχειν ἀλῶν τὰ σιτία καὶ πέττων ἑαυτῷ, καθάπερ '''Πιττακός'''. « ἐγὼ γάρ, » εἶπε, « τῆς ξένης ἤκουον ᾀδούσης πρὸς τὴν μύλην, ἐν [[w:Eresós|''Ἐρέσῳ'']] γενόμενος, ἄλει, μύλα, ἄλει· καὶ γὰρ '''Πιττακὸς''' ἄλει μεγάλας ''Μυτιλάνας'' βασιλεύων. »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §14'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§14. [...] Ces paroles ayant mis en arrêt les convives, '''Thalès''' dit en raillant qu’'''Epiménide''' avait bien raison de ne pas vouloir se donner l’embarras de moudre et de cuire lui-même son manger, comme faisait '''Pittacus''' : « Car je me souviens », ajouta-t-il, « qu’étant à ''Lesbos'', j’entendis mon hôtesse chanter à sa meule : Va ton train, meule, va ton train, puisque '''Pittacus''', le roi de la grande ''Mitylène'', s’occupe bien à moudre. »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §14'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Ce discours ayant frappé tout le monde, '''Thalès''' dit en plaisantant qu’il approuvait '''Epiménides''' [[#Epiménides_NdT_DR|<span id="Epiménides_NdT_DR_back"><sup>1</sup></span>]] de s’épargner la peine de moudre et de cuire lui-même son pain, comme faisait '''Pittacus'''. « Je me souviens , ajouta-t-il, qu’étant à ''Lesbos'', j’ai entendu une meunière qui chantait : ''Moulez, meule, moulez ; '''Pittacus''', qui règne dans la superbe Mitylène, s’occupe aussi à moudre'' [[#Pittacus_NdT_DR|<span id="Pittacus_NdT_DR_back"><sup>2</sup></span>]]. »</div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Epiménides_NdT_DR_back|<span id="Epiménides_NdT_DR"><sup>1</sup></span>]] Epiménides était un poète de l’île de ''Crète''. Les nymphes, disait-on, lui avaient donné un aliment miraculeux, qu’il conservait dans une corne de bœuf, et dont une très petite quantité suffisait pour le nourrir. ''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Pittacus_NdT_DR_back|<span id="Pittacus_NdT_DR"><sup>2</sup></span>]] Pittacus, au rapport de différents historiens, s’exerçait à moudre du blé. Il faisait un grand éloge de l’utilité des moulins, et insistait sur l’avantage qu’a le moulin de fournir, dans un très petit espace, le moyen de prendre différents exercices. ''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' p.351, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe XV.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage d’une doctrine de '''Thalès''' sur l’importance vitale de l’agriculture.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§15. [...] « Οὐδαμῶς, » ὁ '''Κλεόδωρος''', « ἔμοιγ´, » εἶπεν, « εἰ δεῖ τὸ φαινόμενον εἰπεῖν, καὶ μάλιστα παρακειμένης τραπέζης, ἣν ἀναιροῦσιν αἰρομένης τροφῆς φιλίων θεῶν βωμὸν οὖσαν καὶ ξενίων. ὡς δὲ '''Θαλῆς''' λέγει τῆς γῆς ἀναιρεθείσης σύγχυσιν τὸν ὅλον ἕξειν κόσμον, οὕτως οἴκου διάλυσις ἐστι· συναναιρεῖται γὰρ αὐτῇ πῦρ ἑστιοῦχον ἑστία κρατῆρες ὑποδοχαὶ ξενισμοί, φιλανθρωπότατα καὶ πρῶτα κοινωνήματα πρὸς ἀλλήλους, μᾶλλον δὲ σύμπας ὁ βίος, εἴ γε διαγωγή τίς ἐστιν ἀνθρώπου πράξεων ἔχουσα διέξοδον, ὧν ἡ τῆς τροφῆς χρεία καὶ παρασκευὴ τὰς πλείστας παρακαλεῖ. [...] »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §15'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§15. [...] « S’il faut dire ce que je pense », reprit '''Cléodème''', « ce n’est nullement mon avis, et surtout quand est dressée la table, que l’on supprime si la nourriture est supprimée et qui est l’autel des dieux amis et hospitaliers. Et s’il est vrai, comme dit '''Thalès''', que la suppression de la terre dût entraîner le désordre et la ruine du monde entier, de même anéantir la table ce serait anéantir la maison. Avec la table disparaîtraient le feu qui consacre le foyer, le foyer lui-même, les coupes, les réceptions, les hospitalités, qui sont les plus affectueux et les premiers rapports de communauté entre les hommes; ou plutôt disparaîtrait la vie entière, s’il est vrai que la vie soit une sorte de courant formé par la série des actes de l’homme, actes dont le plus grand nombre est commandé par le besoin et la préparation de la nourriture.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §15'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">S’il faut, reprit '''Cléodème''', que je dise mon sentiment, je ne suis point du tout de cet avis-là, surtout quand la table est dressée. Nous ôter le besoin de nourriture, c’est détruire cet autel des dieux hospitaliers. Et comme la destruction de la terre, selon '''Thalès''', entraînerait la ruine de l’univers, ainsi la chute de la table causerait celle de la maison. Avec elle, on détruirait le feu sacré de nos foyers, les dieux pénates, les libations, le plaisir si touchant de recevoir et de traiter ses amis, tous ces usages respectables qui sont les premiers fondements et les plus doux liens de la société ; disons mieux, on détruirait la vie entière, puisqu’elle est remplie par des occupations et des soins successifs, dont la plupart ont pour objet la nourriture et sa préparation.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' pp.353, 354, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe XVII.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage d’une parole sage de '''Thalès''' : Ne croire ni ses ennemis sur les choses croyables, ni ses amis sur les choses incroyables.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§17. τέλος δὲ γελάσας πρὸς ἡμᾶς « βούλομαι μέν, » ἔφη, « πρὸς τὸ παρὸν φράσαι τὸ προσηγγελμένον· ὀκνῶ δ´ ἀκούσας '''Θαλέω''' ποτ´ εἰπόντος ὅτι δεῖ τὰ μὲν εἰκότα λέγειν, τὰ δ´ ἀμήχανα σιωπᾶν. » Ὑπολαβὼν οὖν ὁ '''Βίας''' « ἀλλὰ καὶ τοῦτ´, » ἔφη, « '''Θαλέω''' τὸ σοφόν ἐστιν, ὅτι δεῖ τοῖς μὲν ἐχθροῖς καὶ περὶ τῶν πιστῶν ἀπιστεῖν, τοῖς δὲ φίλοις καὶ τὰ ἄπιστα πιστεύειν, ἐχθροὺς μέν, ἔγωγ´ ἡγοῦμαι, τοὺς πονηροὺς καὶ ἀνοήτους, φίλους δὲ τοὺς χρηστοὺς καὶ φρονίμους αὐτοῦ καλοῦντος. οὐκοῦν, »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §17'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§17. [...] A la fin il s’adressa à nous en éclatant de rire : « Je voudrais vous faire connaître, sans plus attendre, ce que '''Gorgias''' vient de me conter; et pourtant j’hésite, parce que j’ai autrefois entendu dire à '''Thalès''' qu’il faut dire les choses vraisemblables et taire les impossibles. « Mais, reprit '''Bias''', « c’est à '''Thalès''' aussi qu’appartient cette sage parole : qu’il faut ne pas croire ses ennemis même sur les choses croyables, et croire ses amis même sur celles qui ne le sont pas : par ennemis il entendait, je suppose, les méchants et les sots, par amis, les gens vertueux et sensés. »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §17'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Mais quand '''Gorgias''' [[#Gorgias_NdT_DR|<span id="Gorgias_NdT_DR_back"><sup>1</sup></span>]] eut achevé, il nous dit en riant : « Je voudrais vous répéter ce que je viens d’entendre ; mais je n’ose le faire après ce mot de '''Thalès''' : qu’il faut dire les choses vraisemblables, et taire celles qui paraissent impossibles. - Mais, repartit '''Bias''' , n’est-ce pas aussi '''Thalès''' qui a dit cette autre maxime si sage, qu’il faut ne pas croire ses ennemis même sur les choses croyables, et croire ses amis sur les choses même les moins vraisemblables. Par les ennemis, il entend, sans doute, les méchants et les insensés ; par les amis, les bons et les sages.</div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Gorgias_NdT_DR_back|<span id="Gorgias_NdT_DR"><sup>1</sup></span>]] Tout ce qu’on sait de ce frère de Périandre, c’est qu’il fonda une colonie dans l’''[[w:Ambracie|Ambracie]]'', et qu’il mourut vraisemblablement avant son frère, puisque son fils [[w:Psammétique_(Corinthe)|Psammétique]] succéda à Périandre, et fut le dernier tyran de ''Corinthe'' de la race de [[w:Cypsélos|Cypsèle]]. ''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' p.358, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe XXI.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage d’une doctrine de '''Thalès''' sur la résidence de l'âme dans toutes les parties du monde les plus essentielles.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§21. Μετὰ δὲ τοῦτον ὁ '''Ἀνάχαρσις''' εἶπεν ὅτι τοῦ '''Θαλέω''' καλῶς ὑπολαμβάνοντος ἐν πᾶσιν εἶναι τοῖς κυριωτάτοις μέρεσι τοῦ κόσμου καὶ μεγίστοις ψυχήν, [...].</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §21'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§21. Après '''Pittacus''', '''Anacharsis''' prit la parole : « Puisque, comme '''Thalès''' l’a magnifiquement établi, une âme réside dans toutes les parties du monde les plus essentielles, [...].</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §21'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">'''Pittacus''' ayant cessé de parler, '''Anacharsis''' prit la parole : « S’il est vrai, dit-il, comme '''Thalès''' le croit avec raison, que les plus grandes et les principales parties du monde ont une ame, [...].</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' p.365, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto; color: #3366BB">― ✳ ―</div> ==== Du démon de '''Socrate''' ==== <div style="text-align: center; margin: 0 1em;">Discussion autour de la libération de [[w:Thèbes (Grèce)|''Thèbes'']] de ''[[w:Sparte|Sparte]]'' grâce à une conjuration de '''[[w:Pélopidas|Pélopidas]]''' [[#Pélopidas|<span id="Pélopidas_back"><sup>'''I'''</sup></span>]] en [[w:-379|-379]]. Le récit est ici plus ample que lors de la biographie de Pélopidas dans les ''[[w:Vies parallèles|Vies parallèles]]''. La source de '''Plutarque''' est d’origine ''thébaine'', la même que '''[[w:Cornélius Népos|Cornélius Népos]]''' [[#Cornélius_Népos|<span id="Cornélius_Népos_back"><sup>'''II'''</sup></span>]]. Le traité porte sur la ''[[w:démonologie|démonologie]]'', le démon de '''Socrate''' peut-être une voix intérieure ou ses capacités [[w:divinatoires|divinatoires]]'', la légende étant d’origine [[w:pythagoricienne|pythagoricienne]] et évoque l’oracle '''[[w:Trophonios|Trophonios]]'''.</div> {{Boîte déroulante début|titre=NdA du Démon de Socrate|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Pélopidas_back|<span id="Pélopidas"><sup>I</sup></span>]] Du nom propre grec ancien Πελοπῐ́δᾱς / Pelopĭ́dās [[wikt:en:Πελοπίδας#Ancient_Greek|(en)]] ;<br /><p style="margin: 0 2em; text-indent: 15px;">Stratège [[w:Thèbes (Grèce)|''thébain'']]. Chassé en [[w:-382|-382]] de ''Thèbes'' après la prise de la [[w:Cadmée_(Thèbes)|Cadmée]], la citadelle située au sommet de son ''[[w:acropole|acropole]]'', par [[w:Phébidas|Phébidas]] avec l’aide des ''[[w:Sparte|Spartiates]]'', il renverse le gouvernement pro-spartiate d’[[w:Archias de Thèbes|Archias]] et de Léontidas en [[w:-379|-379]], qu’il tue, et rétablit la ''[[w:démocratie|démocratie]]''.<br /><p style="text-align: right; margin: 0 2em;">(date de naissance inconnue, à ''Thèbes'' — [[w:364_av._J.-C.|-364]]<sup>[[w:IVe_siècle_av._J.-C.|⏳]]</sup>, mort lors de la [[w:Bataille_de_Cynoscéphales_(364_av._J.-C.)|''bataille de Cynoscéphales'']], dans le cadre d’une vengeance pour sa captivité par le ''tyran'' de [[w:Thessalie|''Thessalie'']], [[w:Alexandre_de_Phères|Alexandre]] de [[w:Phères|''Phères'']], alors qu’il était en ambassade chez lui)<br /><br /><p style="margin: 0 2em; text-indent: 15px;">[[#Cornélius_Népos|<span id="Cornélius_Népos"><sup>II</sup></span>]] [[w:Nom_romain|Tria Nomina]] en latin ''{{Info|<nowiki>[praenomen inconnu]</nowiki>|praenomen, nom individuel du citoyen romain}}'' {{Info|Cornélius|nomen, nom de famille}} {{Info|Népos|cognomen, surnom héréditaire, servant à distinguer les diverses branches d’une même gens}}<br /><p style="margin: 0 2em; text-indent: 15px;">Auteur ''latin''. On sait par les lettres de Cicéron que Cornelius Népos n’aimait pas les écrits moraux, leur préférant la description de la nature et l’étude de l’histoire. Aucun des ouvrages qu’il avait composés dans ce genre n’est parvenu en entier jusqu’à nous. Les « Vies des grands capitaines de l’antiquité » qui subsistent aujourd’hui, et qui ont connu de multiples éditions, lui ont été attribuées jusqu'au XVIIIe siècle ; mais l'analyse de ce court recueil montre qu'il ne serait qu'un abrégé (attribué à Æmilius Probus), de l’ouvrage original de Cornelius Népos.<br /><p style="text-align: right; margin: 0 2em;">(vers [[w:-100|-100]], au pays des [[w:Insubres|Insubres]] à [[w:Mantoue|Mantoue]] ou à [[w:Pavie|''Ticinum'']], dans le nord de l’''Italie'' — vers [[w:-29|-29]]/[[w:-25|-25]], à ''Rome'')<sup>[[w:Ier_siècle_av._J.-C.|⏳]]</sup>'''<br /><br /> </div>{{Boîte déroulante fin}} ===== <div style="text-align: center;">Paragraphe VI.</div> ===== <div style="text-align: center; margin: 0 1em;">Témoignage de l’aversion de '''Thalès''' pour les [[w:Tyran|''tyrans'']].</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid;"><br /><div style="text-align: justify; margin: 0 2em; text-indent: 15px">§6. Ταῦτα τοῦ '''Θεοκρίτου''' λέγοντος ὁ '''Λεοντίδης''' ἐξῄει μετὰ τῶν φίλων, ἡμεῖς δ´ εἰσελθόντες ἠσπαζόμεθα τὸν '''Σιμμίαν''' ἐπὶ τῆς κλίνης καθεζόμενον οὐ κατατετευχότα τῆς δεήσεως, οἶμαι, μάλα σύννουν καὶ διαλελυπημένον· ἀποβλέψας δὲ πρὸς ἅπαντας ἡμᾶς ‘ὦ '''Ἡράκλεις''',’ εἶπεν ‘ἀγρίων καὶ βαρβάρων ἠθῶν· εἶτ´ οὐχ ὑπέρευ '''Θαλῆς''' ὁ παλαιὸς ἀπὸ ξένης ἐλθὼν διὰ χρόνου τῶν φίλων ἐρωτώντων ὅ τι καινότατον ἱστορήκοι ’τύραννον‘ ἔφη ’γέροντα.‘ καὶ γὰρ ᾧ μηδὲν ἰδίᾳ συμβέβηκεν ἀδικεῖσθαι, τὸ βάρος αὐτὸ καὶ τὴν σκληρότητα τῆς ὁμιλίας δυσχεραίνων ἐχθρός ἐστι τῶν ἀνόμων καὶ ἀνυπευθύνων δυναστειῶν.[...]</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome II, [https://remacle.org/bloodwolf/historiens/Plutarque/demonsocrategr.htm Περι του Σωκρατους Δαιμονιου - Le Démon de Socrate], §6'', traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§6. Pendant que [[w:Théocrite|'''Théocritos''']] [[#Théocrite|<span id="Théocrite_back"><sup>'''I'''</sup></span>]] parlait, '''Léontidas''' sortit avec ses amis, et nous entrâmes chez [[w:Simmias_de_Thèbes|'''Simmias''']] [[#Simmias_de_Thèbes|<span id="Simmias_de_Thèbes_back"><sup>'''II'''</sup></span>]], que nous saluâmes affectueusement. Il était assis sur son lit, et j’attribuai à l’insuccès de sa demande son air pensif et affligé. Après nous avoir regardés tous : « Par '''Hercule''' ! s’écria-t-il, quelles mœurs sauvages et barbares ! Eh bien ! n’avait-il pas cent fois raison le '''Thalès''' des anciens jours ? Comme il était revenu d’un long voyage à l’étranger, ses amis lui demandaient ce qu’il avait vu de plus curieux : « Un tyran parvenu à la vieillesse », répondit-il. Car ceux même qui n’ont pas éprouvé de la part d’un despote une injustice personnelle, supportent avec peine le poids et la dureté d’un semblable régime. On déteste tout pouvoir qui est en dehors de la loi et qui ne veut rendre de comptes à personne. [...]</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome III, [[s:Page:Plutarque_-_Œuvres_complètes_de_Plutarque_-_Œuvres_morales_et_œuvres_diverses,_tome_3,_1870.djvu/74|Περι του Σωκρατους Δαιμονιου - Le Démon de Socrate]], [[s:Page:Plutarque_-_Œuvres_complètes_de_Plutarque_-_Œuvres_morales_et_œuvres_diverses,_tome_3,_1870.djvu/83|§6]]'', traduites par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> {{Boîte déroulante début|titre=NdA de trad. Victor Bétolaud de 1870|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Théocrite_back|<span id="Théocrite"><sup>I</sup></span>]] Du nom propre [[w:Nom_théophore|''théophore'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_période_Grèce_Classique#théophore_back|<sup>🔄</sup>]] grec ancien Θεόκριτος / Theókritos [[wikt:en:Θεόκριτος#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;">➥ de l’adjectif et du nom commun θεός / theós [[wikt:en:θεός#Ancient_Greek|(en)]], « divin, dieu, divinité »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ +‎ du verbe κρίνω / krínō, « 1. (transitif) Séparer, diviser, distinguer entre deux choses ou personnes ou parmi un groupe de choses ou de personnes. 2. (transitif) Commander, organiser. 3. S’enquérir, enquêter. 4. Sélectionner, choisir, préférer. 5. (transitif) Trancher un différend ou un concours ; (intransitif) Porter un jugement, prendre une décision : • (voix moyenne, voix passive) Décider d’un concours ; (voix moyenne et voix passive) Se disputer, se disputer, se quereller. 6. Décider ou juger [+accusatif et infinitif = que quelque chose fait quelque chose], [+accusatif et accusatif = que quelque chose est quelque chose]. 7. Discerner entre le bien et le mal. 8. Juger, prononcer. 9. Traduire en justice, accuser. 10. Condamner, critiquer. 11. Sécréter, cacher, dissimuler. »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ + le suffixe adjectival récessif‎ -τος / -tos [[wikt:en:-τος#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;">''Poète'', auteur de [[w:Mime|''mimes'']] (imitations comiques du langage ou des gestes), d’[[w:Poésie_pastorale|''idylles pastorales'']] et de [[w:Épopée|''contes épiques'']].<br /><p style="text-align: right; margin: 0 2em;">([[w:Circa|{{Info|''ca.''|Circa, locution latine que l’on emploie pour indiquer l’approximation d’une date}}]] [[w:310_av._J.-C.|-310]]<sup>[[w:IVe_siècle_av._J.-C.|⏳]]</sup>, à [[w:Théocrite#cite_ref-2|''Syracuse'']] — {{Info|''ca.''|Circa, locution latine que l’on emploie pour indiquer l’approximation d’une date}} [[w:250_av._J.-C.|-250]]<sup>[[w:IIIe_siècle_av._J.-C.|⏳]]</sup>) <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Simmias_de_Thèbes_back|<span id="Simmias_de_Thèbes"><sup>II</sup></span>]] Du grec ancien Σιμμίας ο Θηβαίος / Simmías o Thēbaíos ;<br /><p style="margin: 0 2em; text-indent: 15px;">Philosophe grec et disciple de [[w:Socrate|Socrate]] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Socrate_back|<sup>🔄</sup>]].<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:Ve_siècle_av._J.-C.|V<sup>ème</sup>]] et [[w:IVe_siècle_av._J.-C.|IV<sup>ème</sup>]] siècles {{Info|AEC|Avant l’Ère Commune}}, ''Thèbes'')'''<br /><br /> </div>{{Boîte déroulante fin}} <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">§6. Pendant que '''Théocritos''' discourait ainsi, '''Léontidas''' sortit avec ses amis ; nous entrâmes et saluâmes '''Simmias''', qui était assis sur son lit, tout soucieux et triste, parce que sa demande avait été rejetée sans doute. En nous regardant tous, il s’écria : « '''Héraclès''' ! les moeurs sauvages et barbares ! Ah ! que '''Thalès''' l’ancien avait raison de répondre, lorsqu’après un long voyage à l’étranger ses amis lui demandaient ce qu’il avait remarqué de plus extraordinaire : « Un tyran âgé ». Même un homme qui a eu la chance de n’être pour son compte victime d’aucune injustice exècre déjà le poids et la dureté de ce commerce et est ennemi des dictatures, des dominations arbitraires.[...]</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome II, [https://remacle.org/bloodwolf/historiens/Plutarque/demonsocrate.htm Περι του Σωκρατους Δαιμονιου - Le Démon de Socrate], §6'', traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto; color: #3366BB">― ✳ ―</div> ==== Les [[w:Alimentation_en_Grèce_antique#Banquets|''Symposiaques'']] [[#Symposiaques|<span id="Symposiaques_back"><sup>'''I'''</sup></span>]], ou questions de table ==== <div style="text-align: center; margin: 0 1em;"></div> {{Boîte déroulante début|titre=NdA Les Symposiaques|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Symposiaques_back|<span id="Symposiaques"><sup>I</sup></span>]] Du nom commun grec ancien συμπόσιον / sympósion [[wikt:en:συμπόσιον#Ancient_Greek|(en)]], « Seconde partie d’un repas pendant laquelle un groupe restreint de convives buvaient et discutaient sur un sujet. » ; <br /><p style="margin: 0 2em; text-indent: 15px;">➥ du nom commun σῠμπότης / sŭmpótēs [[wikt:en:συμπότης#Ancient_Greek|(en)]], « compagnon de boisson » ; <br /><p style="margin: 0 4em; text-indent: 15px;">➥ du préfixe σῠν- / sŭn- [[wikt:en:συν-#Ancient_Greek|(en)]], « avec, ensemble » ;<br /><p style="margin: 0 4em; text-indent: 15px;">➥ +‎ du nom commun ποτής / potḗs [[wikt:en:ποτής#Ancient_Greek|(en)]], « boisson » ;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ +‎ du suffixe -ῐον / -ĭon [[wikt:en:-ιον#Ancient_Greek|(en)]] ;<br /><p style="margin: 0 2em; text-indent: 15px;">Entretiens dans un banquet, propos de table. '''<br /><br /> </div>{{Boîte déroulante fin}} ===== <div style="text-align: center;">Livre III</div> ===== <div style="text-align: center; margin: 0 1em;"></div> ====== <div style="text-align: center;">Question VI. Sur le temps où il est à propos de se rapprocher d’une femme.</div> ====== <div style="text-align: center; margin: 0 1em;">Témoignage du statut marital de '''Thalès''' et de sa relation avec sa mère</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid;"><br /><div style="text-align: justify; margin: 0 2em; text-indent: 15px">Καθάπερ οὖν '''Θαλῆς''' ὁ σοφὸς ὑπὸ τῆς μητρὸς ἐνοχλούμενος γῆμαι κελευούσης πῶς ὑπεξέφυγε παρήγαγε λέγων πρὸς αὐτὴν ἐν ἀρχῇ μέν « οὔπω καιρὸς ὦ μῆτερ, » ὕστερον δ´ « οὐκέτι καιρὸς ὦ μῆτερ », οὕτως ἄρα καὶ πρὸς ἀφροδίσια κράτιστον {ἔσται} ἔχειν ἕκαστον, ὥστε κατακλινόμενον λέγειν «οὔπω καιρός», ἀνιστάμενον δ´ « οὐκέτι καιρός ».</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome III, [https://remacle.org/bloodwolf/historiens/Plutarque/sympos3.htm#VI Προβλημα Ϛ. Περὶ καιροῦ συνουσίας. - Question VI. Quel est le temps le plus propre à l'amour?]'', traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div></div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§3. Ainsi donc, comme le sage '''Thalès''', fatigué par sa mère qui l’engageait à se marier, trouva le moyen de lui échapper et de lui donner le change en lui disant une première fois : « Il n’est pas encore temps, ma mère », et, lorsqu’elle insistait encore après qu’il avait passé l’âge : « Il n’est plus temps » ; de même, pour ce qui regarde les plaisirs de l’amour, le mieux sera que chacun se détermine à dire, en se mettant au lit : « Il n’est pas temps encore », et, en sortant du lit : « il n’est plus temps ».</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome III, [[s:Page:Plutarque_-_Œuvres_complètes_de_Plutarque_-_Œuvres_morales_et_œuvres_diverses,_tome_3,_1870.djvu/268|Question VI. Sur le temps où il est à propos de se rapprocher d’une femme]], [[s:Page:Plutarque_-_Œuvres_complètes_de_Plutarque_-_Œuvres_morales_et_œuvres_diverses,_tome_3,_1870.djvu/271|§3]]'', traduites par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Le sage '''Thalès''', pressé par sa mère de se marier, lui répondit avec beaucoup d’adresse. Au commencement, il lui dit : Ma mère, il n’est pas encore temps. Quand il eut passé la fleur de son âge, et qu’elle lui fit de nouvelles instances, il lui répondit : Il n’est plus temps. De même, par rapport à la question proposée, le mieux serait que chacun pût se dire le soir en se couchant : Il n’est pas encore temps ; et le matin, quand il se lève : Il n’est plus temps. »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome III, [https://remacle.org/bloodwolf/historiens/Plutarque/sympos3.htm#VI Προβλημα Ϛ. Περὶ καιροῦ συνουσίας. - Question VI. Quel est le temps le plus propre à l’amour?]'', traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto; color: #3366BB">― ✳ ―</div> ==== De la malignité d’[[w:Hérodote|'''Hérodote''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Chapitre_XX|<sup>🔄</sup>]] ==== <div style="text-align: center; margin: 0 1em;">Ouvrage critique contre l’impartialité d’'''Hérodote''', ses contre-vérités face à la dévaluation des héros et peuples ''grecs''. Le ton critique surprend de la part de '''Plutarque''' au point que l’on contesta l’authenticité du traité, sans succès.</div> ===== Paragraphe XV ===== <div style="text-align: center; margin: 0 1em;">Remise en question de l’origine phénicienne de '''Thalès''' donnée par '''Hérodote'''.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid;"><br /><div style="text-align: justify; margin: 0 2em; text-indent: 15px">Καὶ μὴν τῶν ἑπτὰ σοφῶν, οὓς αὐτὸς σοφιστὰς προσεῖπε, τὸν μὲν '''Θάλητα''' Φοίνικα τῷ γένει τὸ ἀνέκαθεν ἀποφαίνεται βάρβαρον·</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome IV, [https://remacle.org/bloodwolf/historiens/Plutarque/malignhero.htm Περι της Ηροδοτου κακοηθειας]'' traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§15. Quand il parle des sept sages, il les appelle des ''sophistes''. Il prétend démontrer que '''Thalès''' est d’origine ''phénicienne''[[#phénicienne_NdT_DR|<span id="phénicienne_NdT_DR_back"><sup>1</sup></span>]], et qu’à remonter en arrière ce personnage appartient aux Barbares.</div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#phénicienne_NdT_DR_back|<span id="phénicienne_NdT_DR"><sup>1</sup></span>]] I, 170.''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome III, [[s:Page:Plutarque_-_Œuvres_complètes_de_Plutarque_-_Œuvres_morales_et_œuvres_diverses,_tome_3,_1870.djvu/773|De la malignité d’Hérodote]], [[s:Page:Plutarque_-_Œuvres_complètes_de_Plutarque_-_Œuvres_morales_et_œuvres_diverses,_tome_3,_1870.djvu/782|§15]]'', traduites par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Entre les sept sages qu’il appelle ''sophistes'', il enlève '''Thalès''' à la ''Grèce'' pour le donner aux Barbares, en le faisant descendre d’une famille ''phénicienne''.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome IV, [https://remacle.org/bloodwolf/historiens/Plutarque/malignhero.htm De la malignité d’Hérodote]'' traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto; color: #3366BB">― ✳ ―</div> ==== Les opinions des Philosophes ==== <div style="text-align: center; margin: 0 1em;">Ouvrage [[w:doxographe|'''doxographe''']], à la manière de [[w:Diogène Laërce|'''Diogène Laërce''']] [[#Diogène_Laërce_back|<sup>⤵️</sup>]] et [[w:Alcinoos_(philosophe)|'''Alcinoos''']] [[#Alcinoos|<span id="Alcinoos_back"><sup>'''I'''</sup></span>]], qui cite un nombre important de [[w:présocratiques|''présocratiques'']].</div> {{Boîte déroulante début|titre=NdA Les opinions des Philosophes|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Alcinoos_back|<span id="Alcinoos"><sup>I</sup></span>]] Du grec ancien Ἀλκίνοος / Alkínoos [[wikt:en:Ἀλκίνοος#Ancient_Greek|(en)]] ; <br /><p style="margin: 0 2em; text-indent: 15px;">➥ du nom commun ἀλκή / alkḗ [[wikt:en:ἀλκή#Ancient_Greek|(en)]], « 1. Prouesse; force. 2. Défense; garde. 3. Bataille; combat. » ;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ +‎ du nom commun νόος / nóos [[wikt:en:νόος#Ancient_Greek|(en)]], « 1. Esprit : • Perception, sens ; • L’esprit en tant que siège des sentiments, le cœur, l’âme ; • L’esprit en tant que faculté de décision et d’intention, la volonté. 2. Un acte de l’esprit : • Pensée ; • Intention, dessein. 3. Le sens ou la signification d’un mot. 4. (philosophie) Intelligence, intellect, raison. 5. (métaphysique) Le principe agissant sur les particules élémentaires de la matière (tel que décrit par [[w:Anaxagore|Anaxagore]] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Anaxagore_back|<sup>🔄</sup>]]) » ;<br /><p style="margin: 0 2em; text-indent: 15px;">Philosophe de l’époque [[w:Moyen-platonisme|''médio-platonicienne'']] [[#moyen-platonisme|<span id="moyen-platonisme_back"><sup>II</sup></span>]], auteur du Διδασκαλικὸς τῶν Πλάτωνος δογμάτων / Didaskalikòs tō̃n Plátōnos dogmátōn, « Enseignement des doctrines de Platon » [[#Didaskalikos|<span id="Didaskalikos_back"><sup>III</sup></span>]].<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:IIe_siècle|II<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]])<br /><br /><p style="margin: 0 2em; text-indent: 15px;">[[#moyen-platonisme_back|<span id="moyen-platonisme"><sup>II</sup></span>]] Le ''moyen-platonisme'' ou ''médio-platonisme'' est un courant philosophique regroupant des penseurs qui se réclament de Platon, depuis le [[w:Ier_siècle_av._J.-C.|I<sup>er</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]] jusqu'au [[w:IIe_siècle|II<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]].<br /><br /><p style="margin: 0 2em; text-indent: 15px;">[[#Didaskalikos_back|<span id="Didaskalikos"><sup>III</sup></span>]] Le ''Didaskalikos'' se rattache étroitement à la branche du ''moyen-platonisme'' qui interprétait Platon à la lumière surtout d’Aristote. On constate en plus une certaine influence du ''stoïcisme'', en particulier l’emprunt d’un extrait conséquent au ''stoïcien'' Arius Didyme [[#Arius_Didyme|<span id="Arius_Didyme_back"><sup>'''IV'''</sup></span>]]. Souvent pourtant les doctrines du ''stoïcisme'' sont combattues, avant tout, mais pas exclusivement, en ce qui concerne la morale : il est donc impossible que l’auteur du ''Didaskalikos'' fût ''stoïcien orthodoxe'', dont la persistance au [[w:IIe_siècle|II<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]] est sujet à débat. Pour autant, l’auteur veut maintenir une certaine réserve à l’égard des doctrines dont il fait l’exposé : d’où l’emploi de la troisième personne à propos des ''platoniciens''. Enfin, il ne se comptait pas non plus parmi les grands du ''moyen-platonisme''.<br /><p style="margin: 0 2em; text-indent: 15px;">Le Didaskalikos ne peut donc pas être antérieur à Arius Didyme, contemporain de l’empereur Auguste. Il est impossible d’établir un [[wikt:terminus_ad_quem|''terminus ante quem'']] précis. L’ouvrage présente en effet des coïncidences frappantes avec une gamme d’auteurs s’échelonnant de Philon d’Alexandrie jusqu’à Plotin. Depuis fin [[w:XIXe_siècle|XIX<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]], l’habitude a été prise de dater le ''Didaskalikos'' des environs de l’an [[w:150|150]] EC ; et même si cela semble raisonnable, il y a d’autres possibilités à prendre en considération, en l’absence de tout renseignement biographique.<br /><br /><p style="margin: 0 2em; text-indent: 15px;">[[#Arius_Didyme_back|<span id="Arius_Didyme"><sup>IV</sup></span>]] Du nom propre grec ancien Ἄρειος Δίδυμος / Areios Didymos ;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ du nom propre [[w:Nom_théophore|''théophore'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#théophore_back|<sup>🔄</sup>]] Ἄρειος / Áreios [[wikt:en:Ἄρειος#Ancient_Greek|(en)]], « Relatif à Ares »; <br /><p style="margin: 0 2em; text-indent: 30px;">➥ du nom propre Ἄρης / Árēs [[wikt:Ἄρης#Ancient_Greek|(en)]], « 1. (mythologie grecque) La divinité Arès. 2. (par transfert) La planète Mars. 3. (par antonomase) Rencontre ou situation hostile entre groupes de personnes : bataille, affrontement, combat, escarmouche, guerre. 4. (par antonomase) Événements ou conséquences liés aux hostilités : boucherie, carnage, embrasement, massacre, tuerie. 5. (par antonomase, avec synecdoque comme substantif désignant une qualité) Esprit guerrier ou esprit combatif. 6. Épithète de Zeus, « le vengeur » »;<br /><p style="margin: 0 2em; text-indent: 30px;">➥ +‎ du suffixe adjectival -ιος / -ios [[wikt:en:-ιος#Ancient_Greek|(en)]], « Relatif à, appartenant à : "de" » ;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ de l’adjectif δῐ́δῠμος / dĭ́dŭmos [[wikt:en:δίδυμος#Ancient_Greek|(en)]], « 1. Double. 2. Jumeaux. » ;<br /><p style="margin: 0 2em; text-indent: 30px;">➥ [[wikt:en:réduplication|''Réduplication'']] de δύο / dúo [[wikt:en:δύο#Ancient_Greek|(en)]], « deux » ; <br /><p style="margin: 0 2em; text-indent: 30px;">➥ + du suffixe -μος / -mos [[wikt:en:-μος#Ancient_Greek|(en)]] ; forme alternative du suffixe adjectival -ιμος / -imos [[wikt:en:-ιμος#Ancient_Greek|(en)]] de possibilité ou de capacité, « -able » ;<br /><p style="margin: 0 2em; text-indent: 15px;">Philosophe ''alexandrin'' et doxographe de tendance éclectique, il est ami et conseiller d’Auguste, au moins de [[w:-30|-30]] (date fondée sur des références à Auguste et à Arius dans le contexte de la prise d’Alexandrie, épargnée par Auguste - entre autres raisons – grâce à Arius) à [[w:9|9]]. Bien que nous ne connaissions pas de façon certaine l’école à laquelle il se rattachait, il était probablement ''stoïcien'' : il manifeste des affinités avec la ''philosophie académicienne'' telle qu’elle est présentée par Antiochus d’''Ascalon'', de la sympathie pour l’''académicien'' Eudore, une grande précision dans le traitement du matériel ''stoïcien'' et une ouverture à la pensée ''péripatéticienne''.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:Ier_siècle_av._J.-C.|I<sup>er</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]]) [https://books.google.fr/books?id=crnWAAAAMAAJ&newbks=1&newbks_redir=0&lpg=PA3&dq=Richard%20Goulet%20dictionnaire%20des%20auteurs%20antiques&hl=fr&pg=PA345#v=onepage&q&f=false {{Info|<sup>🔍</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume I, §324 - Areios Didymos}}]'''<br/><br/></div> {{Boîte déroulante fin}} ===== <div style="text-align: center;">Livre I</div> ===== <div style="text-align: center; margin: 0 1em;"></div> <div style="text-align: center; margin: 0 auto;">― ● ―</div> ===== <div style="text-align: center;">Livre II</div> ===== <div style="text-align: center; margin: 0 1em;"></div> <div style="text-align: center; margin: 0 auto;">― ● ―</div> ===== <div style="text-align: center;">Livre III</div> ===== <div style="text-align: center; margin: 0 1em;"></div> <div style="text-align: center; margin: 0 auto;">― ● ―</div> ===== <div style="text-align: center;">Livre IV</div> ===== <div style="text-align: center; margin: 0 1em;"></div> <div style="text-align: center; margin: 0 auto; color: #3366BB">― ✳ ―</div> ==== Les animaux de terre ont-ils plus d'adresse que ceux de mer? ==== <div style="text-align: center; margin: 0 1em;"></div> <div style="text-align: center; margin: 0 auto; color: #3366BB">― ✳ ―</div> ==== D’'''Isis''' et d’'''Osiris'''==== <div style="text-align: center; margin: 0 1em;">[[w:Diatribe|Diatribe]] ''[[w:Isis|Isiaque]]'', avec une interprétation ''platonique'' pour intéresser '''Cléa''', admiratrice du mystère d’'''Isis''' à la [[w:Religion_%C3%A9gyptienne|religion ''égyptienne'']]. C’est un plaidoyer, exégèse, avec '''[[w:Osiris|Osiris]]''' qui évoque '''[[w:Dionysos|Dionysos]]''' et '''[[w:Hadès|Hadès]]''', ainsi que des notions de ''[[w:démonologie|démonologie]]'', ''[[w:Dualisme (philosophie)|dualisme]]'' et ''[[w:didactique|didactique]]''. Il contient le premier récit suivi et cohérent du [[w:Mythe_d'Osiris|mythe d’'''Osiris''']]. L’une de ses sources est probablement '''[[w:Hérodote|Hérodote]]'''. mais on croit qu’il s’est rendu lui-même à ''Alexandrie'' pour suivre des cours de médecine.</div> ===== <div style="text-align: center;">Paragraphe IX.</div> ===== <div style="text-align: center; margin: 0 1em;">Témoignage d’un voyage de '''Thalès''' en ''Égypte'', de rencontres avec des prêtres et de récit sur leur divinités.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid;"><br /><div style="text-align: justify; margin: 0 2em; text-indent: 15px">§9. [...] '''Ἑκαταῖος''' δ´ ὁ ''Ἀβδηρίτης'' φησὶ τούτῳ καὶ πρὸς ἀλλήλους τῷ ῥήματι χρῆσθαι τοὺς ''Αἰγυπτίους'', ὅταν τινὰ προσκαλῶνται· προσκλητικὴν γὰρ εἶναι τὴν φωνήν. Διὸ τὸν πρῶτον θεόν, ὃν τῷ παντὶ τὸν αὐτὸν νομίζουσιν, ὡς ἀφανῆ καὶ κεκρυμμένον ὄντα προσκαλούμενοι καὶ παρακαλοῦντες ἐμφανῆ γενέσθαι καὶ δῆλον αὐτοῖς ''Ἀμοῦν'' λέγουσιν.<br /><p style="text-indent: 15px">§10. Ἡ μὲν οὖν εὐλάβεια τῆς περὶ τὰ θεῖα σοφίας '''Αἰγυπτίων''' τοσαύτη {ἦν}, μαρτυροῦσι δὲ καὶ τῶν ''Ἑλλήνων'' οἱ σοφώτατοι, '''Σόλων''' '''Θαλῆς''' '''Πλάτων''' '''Εὔδοξος''' '''Πυθαγόρας''', ὡς δ´ ἔνιοί φασι, καὶ '''Λυκοῦργος''' εἰς ''Αἴγυπτον'' ἀφικόμενοι καὶ συγγενόμενοι τοῖς ἱερεῦσιν.[...]</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome V, [https://remacle.org/bloodwolf/historiens/Plutarque/isisetosiris.htm Περι Ισιδος και Οσιριδος - Traité d’Isis et d’Osiris], §34'', traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1870<br />(également disponible une édition de 1844 [https://remacle.org/bloodwolf/historiens/Plutarque/isisetosiris1.htm ici])</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§9. [...] '''Hécatée''' d’''Abdère'' dit que les ''Égyptiens'' emploient ce mot pour s’appeler les uns les autres, attendu qu’il est essentiellement appellatif. C’est pourquoi, s’adressant au premier Dieu, le même, selon eux, que l’Univers, comme à un être invisible et caché, ils l’exhortent avec supplications, en l’appelant "Amoun", à se faire voir et à se découvrir à eux. Voilà jusqu’à quel point était grande la réserve qui caractérisait la philosophie religieuse des ''Égyptiens''.<br /><p style="text-indent: 15px">§10. C’est ce que témoignent les plus éclairés d’entre les ''Grecs'': '''Solon''', '''Thalès''', '''Platon''', '''Eudoxe''', '''Pythagore''', et aussi, d’après quelques-uns, '''Lycurgue'''. Ils étaient allés en ''Égypte'' et avaient eu des conférences avec les prêtres. [...]</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome V, [https://remacle.org/bloodwolf/historiens/Plutarque/isisetosiris.htm Περι Ισιδος και Οσιριδος - Traité d’Isis et d’Osiris], §§9, 10'', traduites par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870<br/>(également disponible [[s:Sur_Isis_et_Osiris|ici]])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">§9. [...] '''Hécatée''' d’''Abdère'' dit que les ''Egyptiens'' s’en servent pour s’appeler les uns les autres; que ce nom est de sa nature appellatif ; que ce peuple , qui croit que le premier des dieux, qu’il confond avec l’univers, est un dieu caché et inconnu, l’invoque et le prie de se découvrir à eux, en lui disant ''Amoun'' ;<br /><p style="text-indent: 15px">§10. tant ce peuple portait de retenue et de réserve dans sa philosophie religieuse ! C’est ce qu'attestent unanimement les plus sages d’entre les ''Grecs'', '''Solon''', '''Thalès''', '''Platon''', '''Eudoxe''', '''Pythagore''', et, suivant quelques uns, '''Lycurgue''' lui-même, qui tous voyagèrent en ''Egypte'', et y conférèrent avec les prêtres du pays.[...]</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome V, [https://remacle.org/bloodwolf/historiens/Plutarque/isisetosiris1.htm Περι Ισιδος και Οσιριδος - Traité d’Isis et d’Osiris], §§9, 10'', traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe XXXIV.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage de la théorie de '''Thalès''' de l’eau principe de tous les êtres.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§34. Ἥλιον δὲ καὶ Σελήνην οὐχ ἅρμασιν ἀλλὰ πλοίοις ὀχήμασι χρωμένους περιπολεῖν φασιν αἰνιττόμενοι τὴν ἀφ´ ὑγροῦ τροφὴν αὐτῶν καὶ γένεσιν. Οἴονται δὲ καὶ '''Ὅμηρον''' ὥσπερ '''Θαλῆν''' μαθόντα παρ´ ''Αἰγυπτίων'' ὕδωρ ἀρχὴν ἁπάντων καὶ γένεσιν τίθεσθαι· τὸν γὰρ '''Ὠκεανὸν''' '''Ὄσιριν''' εἶναι, τὴν δὲ '''Τηθὺν''' '''Ἶσιν''' ὡς τιθηνουμένην πάντα καὶ συνεκτρέφουσαν. [...]</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome V, [https://remacle.org/bloodwolf/historiens/Plutarque/isisetosiris.htm Περι Ισιδος και Οσιριδος - Traité d’Isis et d’Osiris], §34'', traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1870<br />(également disponible une édition de 1844 [https://remacle.org/bloodwolf/historiens/Plutarque/isisetosiris1.htm ici])</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§34. Ils disent que le soleil et la lune parcourent leur route perpétuelle non pas sur des chars, mais sur des bâtiments de navigation: signifiant par là, que c’est le principe humide qui les entretient et qui leur a donné naissance. Ils croient aussi que c’est des ''Egyptiens'' qu’'''Homère''', et après lui '''Thalès''', ont appris à établir l’eau comme principe générateur de tous les êtres. Ils veulent qu’'''Osiris''' soit l’'''Océan''', qu’'''Isis''' soit '''Téthys''', laquelle nourrit et entretient tout ce qui existe.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome V, [https://remacle.org/bloodwolf/historiens/Plutarque/isisetosiris1.htm Περι Ισιδος και Οσιριδος - Traité d’Isis et d’Osiris], §34'', traduites par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870<br/>(également disponible [[s:Sur_Isis_et_Osiris|ici]])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">§34. Ils disent que le soleil et la lune parcourent les cieux, portés, non sur des chars, mais sur des vaisseaux, pour signifier que tout est nourri et mis en mouvement par l’eau. Ils pensent que c’est des ''Egyptiens'' qu’'''Homère''' et '''Thalès''' avaient pris cette opinion, que l’eau est le principe de tous les êtres, qu’'''Osiris''' est l’'''Océan''', et qu’'''Isis''' est '''Thétis''', qui nourrit et alimente toutes les substances.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome V, [https://remacle.org/bloodwolf/historiens/Plutarque/isisetosiris1.htm Περι Ισιδος και Οσιριδος - Traité d’Isis et d’Osiris], §34'', traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Valère_Maxime|'''Valère Maxime''']] ''([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l'on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:Ier_siècle|I<sup>er</sup> siècle {{Info|EC|de l’Ère Commune}}]])'' [[s:Auteur:Valère_Maxime|<sup>📚</sup>]] == === Actions et paroles mémorables, VII, § 2 === :8. Il y a aussi un mot admirable de Thalès. On lui demandait si les actions des hommes échappaient à la connaissance des dieux. "Leurs pensées non plus", répondit-il. Aussi faut-il nous appliquer à avoir, je ne dis pas seulement les mains, mais encore le cœur pur, dans la persuasion que la divinité est témoin des mouvements les plus secrets de nos âmes. <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Tatien_le_Syrien|'''Tatien''']] le [[w:Assyrie_(province_romaine)|''Syrien'']] ''(vers [[w:120|120]], en [[w:Halicarnasse|''Halicarnasse'']] en [[w:Assyrie_(province_romaine)|Assyrie]] — vers [[w:173|173]], en Assyrie)'' <sup>[[w:IIe_siècle|⏳]]</sup> [[s:Auteur:Tatien_le_Syrien|<sup>📚</sup>]] == === Discours aux Grecs, 41 === == [[w:Lucien_de_Samosate|'''Lucien de Samosate''']] ''(vers [[w:120|120]], à [[w:Samosate|Samosate]] — vers [[w:180|180]], en [[w:Égypte_romaine_et_byzantine|Égypte]])'' <sup>[[w:IIe_siècle|⏳]]</sup> [[s:Auteur:Lucien_de_Samosate|<sup>📚</sup>]] == === Dialogues des morts === https://gallica.bnf.fr/ark:/12148/bpt6k6227866x/f7.item https://gallica.bnf.fr/ark:/12148/bpt6k6227866x/f103.double === Hippias ou le bain === :(2) Mon but est de prouver que les constructeurs de machines qui méritent le plus notre admiration sont ceux qui, distingués par leur science théorique, ont laissé en outre à la postérité des monuments de leur art et des œuvres de leur génie, tandis que les hommes, qui se sont seulement exercés dans la parole méritent plutôt le nom de sophistes que celui de savants. C'est sur la liste traditionnelle de ces artistes que nous voyons figurer Archimède et Socrate de Cnide, qui inventèrent, l'un les moyens de soumettre à Ptolémée la ville de Memphis, sans recourir à un siège, mais en détournant et en divisant le cours du Nil ; l'autre, ceux d'incendier les galères des ennemis. Avant eux, Thalès de Milet, ayant promis à Crésus de faire passer à pied sec à son armée les eaux du fleuve Halys, imagina de les détourner en une seule nuit derrière le camp ; et pourtant ce n'était pas un mécanicien de profession, mais un sage d'un esprit inventif et à l'intelligence duquel on pouvait s'en rapporter. === Exemples de longévité === :(18) Solon, Thalès et Pittacus, que l'on compte au nombre des Sept sages, vécurent chacun cent années. <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Athénée_de_Naucratis|'''Athénée''' de ''Naucratis'']] == [[w:https://remacle.org/bloodwolf/erudits/athenee/livre11.htm|''Le Livre XI des Deipnosophistes'']] [781d] « Alcmène reçoit le vase d'or, et le contemple aussitôt avec admiration. » Stésichore dit qu'Hercule traverse l'Océan dans son vase à boire (poteerioo) ; qu'il s'en servit même pour le franchir et aller enlever les bœufs de Géryon. Nous connaissons aussi par l'histoire le vase à boire (poteerion) de l'arcadien Bathyclès, qui le laissa pour présent à celui qui fut appelé le sage par excellence entre les Sept de la Grèce; mais nombre de potiers de terre font le vase de Nestor, car plusieurs écrivains en ont donné des détails. <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Clément_d%27Alexandrie|'''Clément''']] d'[[w:Histoire_d%27Alexandrie#Annexion|''Alexandrie'']] ''(vers [[w:150|150]]'' <sup>[[w:IIe_siècle|⏳]]</sup>'', à [[w:Athènes#Antiquité|Athènes]] — vers [[w:215|215]]'' <sup>[[w:IIIe_siècle|⏳]]</sup>'', à [[w:Kayseri|Kayseri]])'' [[s:Auteur:Clément_d’Alexandrie|<sup>📚</sup>]] == === Stromates, I, 65 === <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Claude_Élien|'''Claude Élien''']] ''(vers [[w:175|175]]''<sup>[[w:IIe_siècle|⏳]]</sup>'', à [[w:Préneste|Préneste]] — vers [[w:235|235]]''<sup>[[w:IIIe_siècle|⏳]]</sup>'', en [[w:Rome_antique|Rome]])'' [[s:Auteur:Élien_le_sophiste|<sup>📚</sup>]] == === Histoires diverses === :On a vu des philosophes à la tête des affaires publiques : d'autres, se bornant à cultiver leur raison, ont passé leur vie dans le repos. Entre les premiers sont Zaleucus et Charondas qui réformèrent, l'un, le gouvernement des Locriens, l'autre, d'abord celui des Catanéens, puis, après qu'il eut été exilé de Catane, celui des Rhéginiens. Archytas servit utilement les Tarentins. Les Athéniens durent tout à Solon. Bias et Thalès rendirent les mêmes services à l'Ionie, Chilon à Lacédémone, Pittacus à Mitylène, Cléobule à Rhodes. <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Sextus_Empiricus|'''Sextus Empiricus''']] ''([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l'on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:IIe_siècle|II<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]])'' [[s:Auteur:Sextus_Empiricus|<sup>📚</sup>]] == Hypot III, 30, et Liv I contre les phys., sect. 319 https://gallica.bnf.fr/ark:/12148/bpt6k9796311p/f305.item.r=thales <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Lactance|'''Lactance''']] ''(vers [[w:250|250]]''<sup>[[w:IIIe_siècle|⏳]]</sup>'', à [[w:Henchir_Kssiba#Histoire|Civitas Popthensis]] — vers [[w:325|325]]''<sup>[[w:IVe_siècle|⏳]]</sup>'', en [[w:Gaule#La_Gaule_dans_l'Antiquité_tardive|Gaule]])'' == Épit. 4 (https://gallica.bnf.fr/ark:/12148/bpt6k282068z/f300.image.r=thales) Inst. 111, 16 (https://gallica.bnf.fr/ark:/12148/bpt6k282068z/f621.item.r=thales) <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Jamblique|'''Jamblique''']] ''(vers [[w:250|250]]''<sup>[[w:IIIe_siècle|⏳]]</sup>'', à [[w:Qinnasrīn|Chalcis ad Belum]] — vers [[w:333|333]]''<sup>[[w:IVe_siècle|⏳]]</sup>'')'' == === Vie de Pythagore === ==== chap. II ==== (https://web.archive.org/web/20110721184914/http://www.aurumsolis.info/index.php?option=com_phocadownload&view=category&download=1%3Aiamblichus-the-pythagorean-life&id=19%3Awritings-from-the-founders&Itemid=143&lang=en) <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Eusèbe_de_Césarée|'''Eusèbe''']] de [[w:Césarée#Césarée_au_début_du_christianisme|''Césarée'']] ''(vers [[w:265|265]]'' <sup>[[w:IIIe_siècle|⏳]]</sup>'', à Césarée — [[w:340|340]]'' <sup>[[w:IVe_siècle|⏳]]</sup>'', à Césarée)'' [[s:Auteur:Eusèbe_de_Césarée|<sup>📚</sup>]] == Preparation Évangélique, XI, 2 Prepar. évang. I, 8, page 22-25 https://gallica.bnf.fr/ark:/12148/bpt6k9796311p/f310.image.r=thales <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Diogène_Laërce|'''Diogène Laërce''']] ''([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l'on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:IIIe_siècle|III<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]])'' [[s:Auteur:Diogène_Laërce|<sup>📚</sup>]] == ''Ce texte est un extrait de la traduction de Robert Genaille (1933)'' Thalès[1], au dire d’Hérodote, de Douris et de Démocrite, était fils d’Examios et de Cléobuline, et membre de la famille des Thélides, Phéniciens descendant en droite ligne d’Agénor[2] et de Cadmus[3], s’il faut en croire Platon. Le premier, il porta le nom de sage, au temps où Damasias était archonte à Athènes[4]. C’est sous le même archontat que fut créée l’expression : « les sept sages » (cf. Démocrite de Phalère, Registre des Archontes). Thalès fut inscrit comme citoyen de Milet quand il vint dans cette ville avec Nélée chassé de Phénicie. Une autre tradition très courante veut qu’il soit natif de Milet et qu’il descende d’une bonne famille. Il s’occupa de politique avant d’étudier la nature. On croit qu’il ne laissa aucun écrit, car l’Astrologie nautique qu’on lui attribue est de Phocos de Samos. Callimaque[5] croit qu’il découvrit la Petite Ourse et le raconte en vers iambiques : Il mesura, dit-on, les étoiles du Chariot Sur quoi les Phéniciens règlent leur navigation. D’autres auteurs disent qu’il écrivit seulement deux ouvrages, un sur le solstice et un sur l’équinoxe, car il pensait le reste inaccessible. Il passe pour avoir le premier étudié l’astrologie et prédit les éclipses de soleil et les solstices (cf. Eudème, Histoire de l’astrologie)[6]. Xénophane et Hérodote le louent à ce propos, et leur témoignage est confirmé par celui d’Héraclite et de Démocrite. On dit encore (cf. le poète Choirilos) qu’il fut le premier à affirmer l’immortalité des âmes. Le premier il dessina la course du soleil d’un solstice à l’autre, et démontra que comparée au soleil, la lune en est la cent vingtième partie. C’est encore lui qui fixa à trente jours la durée du mois, et qui écrivit le premier traité sur la Nature. Aristote et Hippias disent aussi qu’il accordait une âme aux choses qu’on croit inanimées ; il en donnait pour preuve l’ambre et la pierre de Magnésie. Selon Pamphile[7], il apprit des Égyptiens la géométrie, inscrivit dans un cercle le triangle rectangle, et pour cette découverte immola un bœuf. D’autres, comme Apollodore le calculateur, attribuent cette invention à Pythagore. Thalès a encore développé et précisé l’invention du Phrygien Euphorbe citée par Callimaque dans ses Iambes et concernant le triangle scalène, et tout ce qui touche aux considérations sur les lignes. Il semble encore avoir été en politique un homme de bon conseil. Ainsi, quand Crésus[8] envoya une ambassade aux Milésiens pour demander leur alliance, il s’y opposa, et son intervention sauva la ville, puisque Cyrus l’emporta. Héraclite cite une opinion de Clytos selon laquelle Thalès aurait eu une vie retirée et solitaire. Les uns disent qu’il se maria et eut un fils nommé Kibissos. D’autres prétendent qu’il resta célibataire et adopta le fils de sa sœur, qu’on lui demanda un jour pourquoi il ne cherchait pas à avoir des enfants, et qu’il répondit : « Par amour pour les enfants. » Sa mère l’exhortait à se marier, il lui répondit : « Non, par Zeus, il n’est pas encore temps. » Elle l’y invita une nouvelle fois quand il eut pris de l’âge, mais il lui dit : « Il n’est plus temps. » D’après Hiéronyme de Rhodes (Notes, livre II), il voulut montrer combien il était facile de s’enrichir ayant prévu pour l’année une abondante récolte d’huile, il prit à loyer une oliveraie et gagna beaucoup d’argent[9]. Il soupçonna que l’eau était le principe des choses, que le monde était animé et rempli de démons. On dit qu’il découvrit les saisons de l’année, et qu’il la divisa en trois cent soixante-cinq jours. Il ne suivit les leçons d’aucun maître, sauf en Égypte, où il fréquenta les prêtres du pays. A ce propos, Hiéronyme dit qu’il mesura les Pyramides en calculant le rapport entre leur ombre et celle de notre corps. Si l’on en croit Minuès, il vivait au temps de Thrasybule, qui fut tyran de Milet[10]. L’histoire du trépied trouvé par des pêcheurs et dédié aux sages par le peuple de Milet est bien connue. Des jeunes gens d’Ionie achetèrent à des pêcheurs milésiens leur coup de filet. Ils tirèrent de l’eau un trépied. On se querella et les Milésiens envoyèrent une ambassade à Delphes. Voici quel fut l’oracle de la divinité : Race de Milet, tu interroges Phébus au sujet d’un trépied ? Au plus sage de tous, je donne ce trépied[11]. Ils le donnent alors à Thalès, qui le donne à un autre, et cet autre à un autre, et ainsi de suite jusqu’à Solon, qui, déclarant que seul le dieu était le plus sage de tous, rendit le trépied à Delphes. Callimaque, dans ses Iambes, rapporte cette histoire autrement ; il la tient de Léandre de Milet. Il dit qu’un certain Bathyclès d’Arcadie laissa en mourant une coupe pour qu’elle fût donnée à l’homme le plus sage. Elle fut donc donnée à Thalès, et après être passée de main en main et avoir fait le tour des sages, elle revint à Thalès. Celui-ci en fit don alors à Apollon de Didyme, en ces termes selon le poème de Callimaque : Thalès me donne au protecteur du peuple du Nil, Thalès qui a reçu deux fois ce présent, ce qui, en prose, se dit ainsi : « Thalès de Milet, fils d’Examios, à Apollon delphien, ce présent qu’il a reçu deux fois des Grecs. » Celui qui portait la coupe de sage en sage, le fils de Bathyclès, s’appelait Thyrion (cf. Éleusis, Livre sur Achille, et Alexon de Mynde, Fables, livre IX). Eudoxe de Cnide et Évanthès de Milet disent de leur côté qu’un ami de Crésus reçut du roi un vase d’or, pour le donner au plus sage des Grecs, qu’il le donna à Thalès et que ce vase parvint jusqu’à Chilon. Celui-ci consulta la Pythie, pour savoir qui était plus sage que lui. Elle répondit que c’était Myson (je parlerai de lui : Eudoxe le met parmi les sages à la place de Cléobule et Platon à la place de Périandre.) Voici la réponse que lui fit la Pythie : Il y a un habitant de l’Oeta, Myson, né à Chénée, Qui plus que toi est riche de sages pensées. L’homme qui consulta l’oracle pour Chilon s’appelait Anacharsis. Dédale le Platonicien et Cléarque disent que la coupe fut envoyée par Crésus à Pittacos, et que c’est ainsi qu’elle passa de main en main. D’après Andron, d’autre part (Livre du trépied), les Argiens décidèrent que le trépied serait attribué comme prix de vertu au plus sage des Grecs. Aristodème de Sparte fut choisi et c’est lui qui donna le trépied à Chilon. Alcée est aussi partisan d’Aristodème dont il parle dans les vers suivants : :Comme jadis Aristodème, dit-on, :Prononça à Sparte cette parole bien juste : :C’est de l’argent, un homme, oui de l’argent, :Car l’homme vertueux n’est jamais pauvre. D’autres disent encore que Périandre envoya à Thrasybule, tyran de Milet, un navire chargé, que ce navire fit naufrage dans la mer de Cos, et que quelque temps après le trépied fut trouvé par des pêcheurs. Phanodicos dit que le trépied fut trouvé dans la mer Attique, porté à la ville, et que l’assemblée du peuple s’étant réunie le fit porter à Bias. Pourquoi cela, je le dirai quand je parlerai de Bias. Selon d’autres auteurs, le trépied avait été fabriqué par Héphaïstos et donné en présent de la part de ce dieu à Pélops lors de son mariage. Il vint ensuite à Ménélas, fut enlevé avec Hélène par Alexandre, jeté dans la mer de Cos à l’instigation de la Spartiate qui prévoyait qu’il serait un sujet de querelle. Plus tard, en ce lieu, des Lébédiens achetèrent le produit d’un coup de filet et c’est le trépied qui fut tiré de l’eau. Il y eut querelle avec les pêcheurs, on vint jusqu’à Cos, et comme on ne s’accordait pas, on s’adressa à Milet, qui était la capitale. Les Milésiens envoyèrent des députés qui ne furent pas écoutés, aussi firent-ils la guerre aux gens de Cos. Comme de chaque côté il mourait beaucoup de gens, l’oracle déclara qu’il fallait donner le trépied au plus sage. Les deux camps s’entendirent alors pour l’attribuer à Thalès, qui par la suite le consacra à Apollon de Didyme. Pour en revenir à la réponse de l’oracle aux gens de Cos, elle disait ceci : La querelle entre Ioniens et Méropes ne cessera pas Avant que le trépied d’or qu’Héphaïstos jeta dans la mer N’ait quitté votre ville pour la maison de l’homme Qui connaît le présent, l’avenir et le passé. La réponse aux Milésiens fut la suivante : Race de Milet, tu interroges Phoebus au sujet d’un trépied... comme il a été dit plus haut. En voilà assez sur ce sujet[12]. Hermippe, dans ses Vies, rapporte à Thalès ce qui est dit par d’autres de Socrate : il aimait à dire qu’il remerciait la fortune de trois choses : d’être un humain et non une bête, d’être un homme et non une femme, enfin d’être un Grec, et non un barbare. On raconte encore qu’étant sorti de chez lui pour contempler les astres, il tomba dans un puits[13]. Une vieille femme survenant se moqua de lui en ces mots : « Comment, Thalès, toi qui n’es pas capable de voir ce qui est à tes pieds, t’imagines-tu pouvoir connaître ce qui est dans le ciel ? » Timon[14] a bien connu aussi la science de Thalès en astronomie, et dans ses Silles, il le loue en ces termes : Comme Thalès, un des sept sages, qui fut savant astronome. L’Argien Lobon dit que ses écrits font un total de quelque deux cents vers, et que sous sa statue on écrivit : Thalès de Milet repose ici dans le sol qui l’a nourri, Il fut un sage, et le premier des astrologues. Voici un de ses poèmes : Le trop parler n’est pas marque d’esprit. Trouvez une seule chose sage, Choisissez une seule chose belle, Et vous clouerez le bec à bien des bavards. On lui attribue encore les sentences suivantes : de tous les êtres, le plus ancien, c’est Dieu, car il n’a pas été engendré ; le plus beau, c’est le monde, car il est l’ouvrage du dieu ; le plus grand, c’est l’espace, car il contient tout ; le plus rapide, c’est l’esprit, car il court partout ; le plus fort, c’est la nécessité, car elle vient à bout de tout ; le plus sage, c’est le temps, parce qu’il découvre tout. La mort, dit-il, ne diffère en rien de la vie. On lui répond : « Pourquoi, alors, ne te donnes-tu pas la mort ? » ; « Parce que vie ou mort, c’est tout un », réplique-t-il. Quelqu’un lui demande ce qui du jour ou de la nuit fut créé d’abord ; il répond : « La nuit est en avance d’un jour. » On lui demande si les mauvaises actions d’un homme échappent au regard des dieux. Il répond : « Ils voient même les mauvaises pensées. » Un homme adultère lui demandait s’il pouvait jurer qu’il n’avait pas commis d’adultère. Il répondit : « Le parjure n’est pas pire que l’adultère. » On lui demandait ce qui était difficile : « Se connaître » dit-il ; ce qui était facile : donner un conseil à autrui ; ce qui était le plus doux : jouir ; ce que c’était que la divinité : un être sans commencement ni fin ; encore une chose difficile : voir un tyran âgé ; comment supporter aisément l’infortune : en voyant ses ennemis plus malheureux encore ; comment vivre vertueusement : en ne faisant pas ce que nous reprochons à autrui ; qui est heureux : l’homme bien portant, riche, courageux et instruit. Il disait encore que l’on doit penser à ses amis aussi bien en leur absence qu’en leur présence, que la beauté ne vient pas d’un beau visage, mais de belles actions. « Ne t’enrichis pas injustement, conseillait-il, et veille à ne pas être cité en justice pour de mauvaises paroles contre tes proches et tes amis. Comme tu traites tes parents, tes enfants te traiteront. » Du Nil[15] il disait qu’il débordait quand ses eaux étaient repoussées par les vents étésiens qui soufflent contre son cours. Apollodore dans ses Chroniques dit que Thalès naquit la première année de la trente-cinquième olympiade[16]. Il mourut dans sa soixante-dix-huitième année ou, comme le dit Sosicrate, dans sa quatre-vingt-dixième année, car ce fut dans la cinquante-huitième olympiade. Il vécut du temps de Crésus, auquel il promit de faire traverser l’Hallys[17] sans pont, en détournant le cours du fleuve. Il y eut cinq autres personnages du nom de Thalès (cf. Démétrios de Magnésie, Homonymes) : un rhéteur de Callatie, au style prétentieux, un peintre de Sicyone, de noble origine, un troisième, très ancien, du temps d’Hésiode, d’Homère et de Lycurgue, un quatrième, mentionné par Douris dans son traité de la peinture, un cinquième, plus jeune et peu connu, cité par Denys dans ses Critiques. Pour en revenir à notre sage, il mourut en regardant les jeux gymniques, pour avoir eu trop chaud et trop soif et par suite de sa fatigue et de son grand âge. Voici son épitaphe : :Ce tombeau, certes, est bien petit, :Mais la renommée de l’homme est allée au ciel. :C’est celui de Thalès le très sage. J’ai écrit sur lui les vers suivants dans le premier livre de mes épigrammes ou « vers de mètres divers[18] : :Tandis qu’il regardait les jeux, ô Zeus Hélios, :Tu as ravi du stade le sage Thalès. :Je te loue de l’avoir rapproché du ciel. Il était si vieux :Que de la terre il ne pouvait plus voir les astres. Thalès est l’auteur du fameux « connais-toi toi-même » qu’Antisthène (Livre des Filiations) attribue à Phémonoé, en déclarant que Chilon se l’appropria mensongèrement. Sur les sept sages, qu’il est juste de citer maintenant l’un après l’autre, voici la tradition. Damon de Cyrène, qui blâme tous les philosophes dans ses écrits, s’attaque surtout aux sept sages. Anaximène dit que tous étaient poètes. Dicéarque dit qu’ils n’étaient ni sages ni philosophes, mais hommes d’esprit et législateurs. Archétimos de Syracuse a décrit leurs assemblées chez Cypsélos[19] et dit qu’il y assista personnellement. Euphoros dit que tous, sauf Thalès, fréquentèrent Crésus. D’autres disent qu’ils se réunirent à Panionium, à Corinthe et à Delphes. On rapporte même leurs paroles, et qui a prononcé telle ou telle. Exemple : Le Spartiate Chilon fut sage, Lui qui dit : Rien de trop, Tout est bien qui vient en son temps ! On n’est pas d’accord sur leur nombre. Léandre, au lieu de Cléobule et de Myson, met Léophante, fils de Gorsias, ou Lébédios d’Éphèse et Épiménide de Crète. Platon, dans le Protagoras[20], met Myson à la place de Périandre. Éphoros met Anacharsis à la place de Myson et d’autres ajoutent Pythagore. Selon Dicéarque, il y en a quatre sur qui tout le monde est d’accord : Thalès, Bias, Pittacos et Solon. Le même auteur en nomme six autres, parmi lesquels il en choisit trois : Aristodème, Pamphile, le Lacédémonien Chilon, Cléobule, Anacharsis et Périandre. D’autres ajoutent Acousilaos, Caba ou Scala, un Argien. Hermippe, dans son livre sur les sages, dit qu’ils furent dix-sept et que chacun en choisit sept selon ses préférences. Ce sont Solon, Thalès, Pittacos, Bias, Chilon, Cléobule, Périandre, Anacharsis, Acousilaos, Épiménide, Léophante, Phérécyde, Aristodème, Pythagore, Lasos, fils de Charmantidas ou de Sisambrinos ou, selon Aristoxène, de Chabrinus, Hermonée, Anaxagore. Hippobotos (Catalogue des Philosophes) les inscrit ainsi : Orphée, Linos, Solon, Périandre, Anacharsis, Cléobule, Myson, Thalès, Bias, Pittacos, Épicharme et Pythagore. Voici des lettres attribuées à Thalès[21] : ==== Thalès à Phérécyde ==== « J’apprends que vous vous disposez à présenter aux Grecs le premier traité ionien des choses divines. Vous agiriez peut-être plus sagement en lisant votre ouvrage à vos amis, qu’en communiquant à n’importe quelles gens des écrits qui ne peuvent guère leur être utiles. « Si cela vous plaît, j’aimerais profiter de vos recherches et, si vous m’y invitez, je viendrai vous trouver au plus tôt. Car Solon d’Athènes et moi, qui avons déjà traversé deux fois la mer pour aller visiter la Crète, et pour aller en Égypte nous entretenir avec les prêtres et les astronomes du lieu, nous sommes assez sages pour ne pas hésiter à la traverser de nouveau pour aller vous voir. « Je parle de Solon, parce qu’il viendra avec moi si vous le permettez. Vous êtes un sédentaire, vous allez rarement en Ionie, vous n’aimez guère aller voir les étrangers, et vous ne songez, j’imagine, qu’à écrire. « Mais nous qui n’écrivons pas, nous parcourons volontiers la Grèce et l’Italie. » ==== Thalès à Solon ==== « Si vous quittez Athènes, vous aurez, je crois, tout avantage à venir vous établir à Milet, parmi les colons athéniens. Il n’y a là pour vous aucun danger. Si vous hésitez, sous prétexte que nous, Milésiens, sommes gouvernés par un tyran (je sais que vous haïssez tout pouvoir absolu), songez du moins que vous aurez plaisir à vivre avec nous qui sommes vos amis. Je sais que Bias vous a écrit et vous invite à aller à Priène. Si vous trouvez préférable d’habiter la ville de Priène, j’irai vivre là-bas avec vous. » <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Ausone|'''Ausone''']] ''([[w:309|309]]/[[w:310|310]], à [[w:Bazas|Bazas]] ou à [[w:Bordeaux#Burdigala,_cité_romaine_(Ier_siècle_-_Ve_siècle)|Bordeaux]] — [[w:394|394]]/[[w:395|395]], entre [[w:Langon_(Gironde)|Langon]] et [[w:La_Réole|La Réole]])'' <sup>[[w:IVe_siècle|⏳]]</sup> [[s:Auteur:Ausone|<sup>📚</sup>]] == === Le Jeu des Sept Sages === :Thalès a trouvé [texte grec] pour nous défendre de nous porter cautions, parce qu'il y a du danger à répondre ainsi pour d'autres[iv]. Nous donnons-là un avis qui ne plaira pas beaucoup aux emprunteurs. :THALÈS : Je suis Thalès de Milet ; j'ai dit, comme le poète Pindare, que l'eau est, le principe de toute chose. C'est à moi que des pêcheurs donnèrent autrefois [un trépied d'or] qu'ils avaient tiré de la mer : ils m'avaient choisi pour obéir au dieu de Délos, qui envoyait ce présent à un sage. Je refusai de le recevoir, je le leur rendis pour le porter à d'autres que je croyais plus dignes. Envoyé à tous les sept Sages, et renvoyé par eux, il nie fut rapporté. Je le reçus alors pour le consacrer à Apollon : car si Phébus a voulu qu'on choisit un sage, ce n'était pas d'un homme, mais d'un dieu qu'il fallait l'entendre. Je suis donc ce Thalès : mais un motif m'amène sur la scène. Comme les deux sages qui m'ont précédé, je viens défendre la sentence dont je suis l'auteur. Elle déplaira, mais non certes aux esprits prudents que l'expérience a instruits et rendus plus avisés. Nous avons dit : [texte grec], ou, en latin : Cautionne, mais tu t'en trouveras mal. Je pourrais parcourir mille exemples pour vous montrer des cautions et des répondants bien et dûment convaincus de repentir. Mais je ne veux nommer personne. Que chacun de, vous ré-fléchisse, et compte en lui-même combien de gens ont perdu ou souffert de s'être ainsi portés cautions pour d'autres. Toutefois, si un pareil service a du charme pour vous, n'y renoncez ni les uns ni les autres. :Alors que les uns applaudissent, et que les autres, si je les blesse, me sifflent. :THALÈS DE MILET. :AVANT d'oser une mauvaise action, à défaut de Témoin redoute ta conscience. La vie s'éteint, mais la gloire de la mort ne meurt point. Ce que tu veux faire, abstiens-toi de le dire. C'est un supplice de craindre ce qu'on ne peut empêcher. Si tu blâmes avec raison, ton hostilité même est profitable ; si tu loues mal à propos, ton amitié même est nuisible. Rien de trop. - Arrêtons-nous, et qu'ici même il n'y ait rien de trop. <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Proclus|'''Proclus''']] ''(le 7 ou 8 février [[w:412|412]], à [[w:Constantinople|Constantinople]] — le 17 avril [[w:485|485]], à [[w:Histoire_d%27Athènes#Antiquité_tardive|Athènes]])''<sup>[[w:Ve_siècle|⏳]]</sup> [[s:Auteur:Proclus|<sup>📚</sup>]] == === Commentaire sur le premier livre d'Euclide, 65, 3 === ὥσπερ οὖν παρὰ τοῖς Φοίνιξιν διὰ τὰς ἐμπορείας καὶ τὰ συναλλάγματα τὴν ἀρχὴν ἔλαβεν ἡ τῶν ἀριθμῶν ἀκριβὴς γνῶσις, οὕτω δὴ καὶ παρ' Αἰγυπτίοις ἡ γεωμετρία διὰ τὴν εἰρημένην αἰτίαν εὕρηται. Θαλῆς δὲ πρῶτον εἰς Αἴγυπτον ἐλθὼν μετήγαγεν εἰς τὴν Ἑλλάδα τὴν θεωρίαν ταύτην καὶ πολλὰ μὲν αὐτὸς εὗρεν, πολλῶν δὲ τὰς ἀρχὰς τοῖς μετ' αὐτὸν ὑφηγήσατο τοῖς μὲν καθολικώτερον ἐπιβάλλων, τοῖς δὲ αἰσθητικώτερον. <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == « [[w:Souda|'''Suidas''']] » ''([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l'on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] fin du [[w:IXe_siècle|IX<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]])'' [[s:Auteur:Suidas|<sup>📚</sup>]] == === La Souda === Θαλῆς, Ἐξαμύου καὶ Κλεοβουλίνης, Μιλήσιος, ὡς δὲ Ἡρόδοτος Φοῖνιξ: γεγονὼς πρὸ Κροίσου, ἐπὶ τῆς λε# ὀλυμπιάδος, κατὰ δὲ Φλέγοντα γνωριζόμενος ἤδη ἐπὶ τῆς ζ#. ἔγραψε περὶ μετεώρων ἐν ἔπεσι, Περὶ ἰσημερίας, καὶ ἄλλα πολλά. ἐτελεύτησε δὲ γηραιός, θεώμενος γυμνικὸν ἀγῶνα, πιληθεὶς δὲ ὑπὸ τοῦ ὄχλου καὶ ἐκλυθεὶς ὑπὸ τοῦ καύματος. πρῶτος δὲ Θαλῆς τὸ τοῦ σοφοῦ ἔσχεν ὄνομα καὶ πρῶτος τὴν ψυχὴν εἶπεν ἀθάνατον ἐκλείψεις τε καὶ ἰσημερίας κατείληφεν. ἀποφθέγματα δὲ αὐτοῦ πλεῖστα: καὶ τὸ θρυλλούμενον: γνῶθι σαυτόν. τὸ γάρ, ἐγγύα, πάρα δ' ἄτα, Χίλωνός ἐστι μᾶλλον, ἰδιοποιησαμένου αὐτό: καὶ τό, μηδὲν ἄγαν. ilz420foy3uibjfv15jlybmn9k5c2c2 773692 773691 2026-09-30T07:15:15Z Alex Mtlr 103840 /* Chapitre XVII. */ 773692 wikitext text/x-wiki {| border="0" cellpadding="0" width="100%" style="background: #f9f9f9" | colspan="3" height="25"|<div style="text-align: center;">[[Philosophie/Thalès de Milet|'''Thalès de Milet''']]</div> |- | width="33%"|'''[[Philosophie/Thalès de Milet/Textes_et_traductions_période_République_Romaine|Période République Romaine]]''' |- | width="33%"|'''[[Philosophie/Thalès de Milet/Textes_et_traductions_période_Grèce_Hellénistique|Période de la Grèce Hellénistique]]''' |- | width="33%"|'''[[Philosophie/Thalès de Milet/Textes_et_traductions_Ier_millénaire_AEC|Période de la Grèce Classique]]''' |} {{EnTravaux}} <span style="font-size:18pt;">Période du Principat de l’[[w:Empire_romain|''Empire'']] [[#Empire|<span id="Empire_back"><sup>'''I'''</sup></span>]] [[w:Rome_antique|''Romain'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Rome_back|<sup>🔄</sup>]]</span> <p style="text-align: right;">(16 janvier [[w:27_av._J.-C.|-27]] <sup>[[w:Ier_siècle_av._J.-C.|⏳]]</sup>, nomination de [[w:Auguste|'''Caius Iulius Caesar Octavianus''']] aux titres d’[[w:Auguste_(titre)|''Augustus'']] et de [[w:Princeps_senatus|''Princeps'']] par le [[w:Sénat_romain|''Sénat romain'']] — fin du [[w:IIIe_siècle|III<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]], création du système [[w:Tétrarchie|''tétrarchique'']] [[#tétrarchie|<span id="tétrarchie_back"><sup>'''II'''</sup></span>]] par [[w:Dioclétien|'''Dioclétien''']] [[#Dioclétien|<span id="Dioclétien_back"><sup>'''III'''</sup></span>]] pour faire face aux [[w:Invasions_barbares#Première_période_:_les_mouvements_migratoires_germaniques_du_IIIe_siècle|''incursions barbares'']]) {{Boîte déroulante début|titre=NdA Empire|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Empire_back|<span id="Empire"><sup>I</sup></span>]] Du nom commun latin imperium [[wikt:en:imperium#Latin|(en)]], « 1. L’empire, l’État, le gouvernement impérial, le royaume, la domination. 2. Le droit ou le pouvoir de commander ou d’avoir le contrôle ; domination. 3. Commandement ou autorité absolue sur l’empire (ou un autre régime politique) ; souveraineté ; domination. 4. (militaire) Autorité militaire, commandement (d’une armée). 5. L’exercice de l’autorité, de la règle, de la loi, du contrôle, de la souveraineté. 6. Un commandement, un ordre, une direction, une injonction.) »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ du verbe imperō, « 1. (avec datif) Commander, donner des ordres à, imposer, exiger. 2. Gouverner. »;<br /><p style="margin: 0 2em; text-indent: 30px;">➥ du préfixe prépositionnal in-, « 1. Dans, à l’intérieur. 2. Contre; dans; sur; vers. 3. (utiliser comme un intensifieur). 4. Attaché à des [[w:Aspect_inchoatif|''verbes inchoatifs'']], il peut exprimer le sens d’un changement en cours ou d’un achèvement partiel. »;<br /><p style="margin: 0 2em; text-indent: 30px;">➥ +‎ du verbe parō [[wikt:en:paro#Latin|(en)]], « 1. Arranger, ordonner, concevoir. 2. Fournir, meubler, préparer. 3. Résoudre, viser, décider. 4. Obtenir, acquérir, se procurer, se faire. »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ + du suffixe nominal abstractif‎ -ium [[wikt:en:-ium#Latin|(en)]], désignant parfois des offices et des groupes. »;<br /><p style="margin: 0 2em; text-indent: 15px;">L’historien spécialiste de l’[[w:Grèce_antique|''antiquité grecque'']] [[w:Moses_Finley|Moses Finley]] définit un empire par tout {{Info|''« exercice durable par un État d’une autorité, d’un pouvoir, ou d’un contrôle sur un ou plusieurs États, communautés ou peuples »''|Moses Finley, Économie et société en Grèce antique, La Découverte, 2007.}}. L’historien [[w:Jean_Tulard|Jean Tulard]], précise cette définition par {{Info|''cinq traits suivants''|Jean Tulard, Les Empires occidentaux de Rome à Berlin, PUF, 1997.}} : :::* '''Une volonté expansionniste ; :::* '''Une organisation centralisée ; :::* '''Des peuples encadrés par une armature politique et fiscale commune ; :::* '''La croyance en une supériorité d’essence ; :::* '''Un début et une fin clairement identifiés. <br /><p style="margin: 0 2em; text-indent: 15px;">'''[[#tétrarchie_back|<span id="tétrarchie"><sup>II</sup></span>]] Du nom commun grec ancien τετραρχία / tetrarkhía;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ du préfixe τετρα- / tétra- [[wikt:en:τετρα-#Ancient_Greek|(en)]], « quatre »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ + du suffixe -αρχία / -arkhía [[wikt:en:-αρχία#Ancient_Greek|(en)]], « -archie (forme de gouvernement ou de règle) »;<br /><p style="margin: 0 2em; text-indent: 15px;"> Système de gouvernement de l’Empire ''romain'' mis en place par Dioclétien à la fin du [[w:IIIe_siècle|III<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]], pour faire face aux invasions barbares. Il consiste en la division de la direction de l’empire entre, d’une part deux [[w:Empereur_romain|''empereurs'']] — les [[w:Auguste_(titre)|''augustes'']] —, d’autre part deux ''lieutenants'' (successeurs désignés des ''augustes'') — les [[w:C%C3%A9sar_(titre)|''césars'']]. <br /><br /><p style="margin: 0 2em; text-indent: 15px;">'''[[#Dioclétien_back|<span id="Dioclétien"><sup>III</sup></span>]] [[w:Nom_romain|Tria Nomina]] en latin {{Info|Gaius|praenomen, nom individuel du citoyen romain}} {{Info|Aurelius|nomen, nom de famille}} {{Info|Valerius|cognomen, surnom héréditaire, servant à distinguer les diverses branches d’une même gens}}, surnommé Dioclētiānus [[wikt:en:Diocletian#English|(en)]] lorsqu’il a été proclamé empereur par ses troupes;<br /><p style="margin: 0 2em; text-indent: 15px;"> Militaire et empereur, connu pour avoir séparé et élargi les services civils et militaires de l’empire, et réorganisé les divisions provinciales de l’empire, établissant le gouvernement le plus vaste et le plus bureaucratique de l’histoire de l’empire. En [[w:286|286]], il nomme son ''césar'', ou adjoint et successeur, [[w:Maximien_Hercule|Maximien]] ''Auguste'', co-empereur, et partage l’Empire entre l’Orient et l’Occident, puis en 293, y nomme respectivement [[w:Galère_(empereur_romain)|Maximien Galère]] et [[w:Constance_Chlore|Constance Chlore]] comme ''césar''.<br/><br/></div> ''' {{Boîte déroulante fin}} == [[w:Sénèque|'''Sénèque''']] [[#Sénèque|<span id="Sénèque_back"><sup>'''I'''</sup></span>]] == <p style="text-align: right;">([[w:5_av._J.-C.|-5]] <sup>[[w:Ier_siècle_av._J.-C.|⏳]]</sup> / [[w:1|1]] <sup>[[w:Ier_siècle|⏳]]</sup>, à [[w:Corduba|Corduba]] — 12 avril [[w:65|65]], à [[w:Rome_antique|''Rome'']], dans une maison de plaisance, la « quatrième pierre milliaire », contraint au [[w:Suicide_forcé|''suicide forcé'']] par l’empereur [[w:Néron|'''Néron''']] après avoir été dénoncé dans la [[w:Conjuration_de_Pison|''Conjuration de Pison'']], sans preuve selon [[w:Tacite|'''Tacite''']] [https://remacle.org/bloodwolf/historiens/tacite/annales15.htm <sup>Annales, l.V, §§LX-LXVI.</sup>]) [[s:Auteur:Sénèque_le_Jeune|<sup>📚</sup>]] [https://books.google.fr/books?id=_HZTvAxN7CIC&newbks=1&newbks_redir=0&lpg=PA3&dq=bibliogroup%3A%22Dictionnaire%20des%20philosophes%20antiques%22&hl=fr&pg=PA177#v=onepage&q&f=true {{Info|<sup>🔍</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume VI, §43 - Seneca (Lucius Annaeus –)}}] [[Fichier:Duble_herma_of_Socrates_and_Seneca_Antikensammlung_Berlin_03_.jpg|vignette|<p style="text-align: justify; text-indent: 15px;">Double-hermès du [[w:IIIe_siècle|III<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]], unique portrait de '''Sénèque''' nommé et authentifié, et associé à celui de '''Socrate''', dont le point commun est celui d’avoir été contraint de se donner la mort. Copie ''romaine'' d’un modèle fait du vivant même du philosophe [https://books.google.fr/books?id=_HZTvAxN7CIC&newbks=1&newbks_redir=0&lpg=PA3&dq=bibliogroup%3A%22Dictionnaire%20des%20philosophes%20antiques%22&hl=fr&pg=PA180#v=onepage&q&f=true {{Info|<sup>➕</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume VI, §43 - Seneca (Lucius Annaeus –), Iconographie}}] [https://books.google.fr/books?id=_HZTvAxN7CIC&newbks=1&newbks_redir=0&lpg=PA3&dq=bibliogroup%3A%22Dictionnaire%20des%20philosophes%20antiques%22&hl=fr&pg=PA201#v=onepage&q&f=true {{Info|<sup>➕➕</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume VI, §43 - Seneca (Lucius Annaeus –), Iconographie - contribution de J. Lang}}].<br /><p style="text-align: justify; text-indent: 15px;">Matériau : Marbre blanc-brunâtre, légèrement veiné, finement cristallin.<br /><p style="text-indent: 15px;">Provenance : ''Rome'', 1813.<br /><p style="text-align: justify; text-indent: 15px;">Exposition : Staatliche Museen zu Berlin, Antikensammlung, SK. 391 [https://recherche.smb.museum/detail/698814/doppelherme-des-sokrates-und-seneca-mit-namensbeischriften-der-dargestellten <sup>🔍</sup>].]] <div style="text-align: justify; margin: 0 1em; text-indent: 15px">Homme politique romain, philosophe stoïcien et dramaturge, il devient tour à tour conseiller à la cour impériale sous '''Caligula''' puis '''Claude''', est exilé en 41 en ''Corse'', où il écrit ses premiers traités philosophiques avant d’être rappelé comme tuteur du jeune '''Néron''' en 49, et enfin, lorsque ce dernier accède au pouvoir, en devient le conseiller et l’un des personnages les plus influents de l’Empire.</div> {{Boîte déroulante début|titre=NdA Sénèque|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Sénèque_back|<span id="Sénèque"><sup>I</sup></span>]] [[w:Nom_romain|Tria Nomina]] en latin {{Info|Lucius|praenomen, nom individuel du citoyen romain}} {{Info|Annaeus|nomen, nom de famille}} {{Info|Seneca|cognomen, surnom héréditaire, servant à distinguer les diverses branches d’une même gens}}'''<br/><br/></div> {{Boîte déroulante fin}} === [[w:Sénèque#Physique|Questions naturelles]] === <p style="text-align: right;">[[s:Questions_naturelles|📚]] <div style="text-align: justify; margin: 0 1em; text-indent: 15px">Ouvrage de philosophie naturelle écrit vers 65. Il ne s’agit pas d’une [[w:Encyclopédie|encyclopédie]] [[#encyclopédie|<span id="encyclopédie_back"><sup>'''I'''</sup></span>]] systématique comme l’[[w:Histoire_naturelle_(Pline_l'Ancien)|''Histoire naturelle'']] [[#Histoire_naturelle|<sup>⤵️</sup>]] de [[w:Pline_l'Ancien|'''Pline l’Ancien''']] [[#Pline_l’Ancien_I|<sup>⤵️</sup>]], bien que ces 2 œuvres représentent les rares ouvrages romains consacrés à l’étude du monde naturel. L’investigation de '''Sénèque''' se déroule principalement à travers la prise en compte des points de vue d’autres penseurs, ''grecs'' et ''romains'', bien qu’elle ne soit pas dénuée de pensées originales, dont éthiques conforment à la pensée ''stoïcienne''.</div> {{Boîte déroulante début|titre=NdA Questions naturelles|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#encyclopédie_back|<span id="encyclopédie"><sup>I</sup></span>]] Du nom commun [[w:Latin#Latin_humaniste|latin Renaissance]] encyclopaedīa [[wikt:en:encyclopaedia#Latin|(en)]]; de l’expression grec ancien ἐγκύκλῐος παιδείᾱ / enkúklios paideíā [https://dumas.ccsd.cnrs.fr/dumas-03927443/file/DONNADILLE-MR2-Pline-VERS-FINALE.pdf {{Info|<sup>🔍</sup>|Lisa Donnadille. Merveilles animalières dans les livres VIII à XI de l’Histoire naturelle de Pline l’Ancien. Littératures. 2020. ffdumas-03927443, p.21}}], « cercle de l’éducation ou des sciences, l’ensemble des sciences qui constituent une éducation complète »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ de l’adjectif ἐγκύκλιος / enkúklios, littéralement « qui est rond ou tourne en rond, circulaire », ou au sens figuré « qui revient en cercle sur soi-même, périodique », « qui embrasse un cercle entier »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ du nom commun παιδεία / paideía, « l’éducation »;'''<br /><p style="margin: 0 2em; text-align: center;">« ''Si à première vue la signification de cette expression semble être sans ambiguïté, sa portée réelle et la compréhension qu’en avaient les auteurs grecs puis latins font l’objet de débats parmi les spécialistes. En effet, deux interprétations sont possibles lorsqu’un auteur de l’Antiquité a recours à cette expression dans l’un de ses textes. Dans le premier cas, cela équivaudrait à parler d’une éducation ordinaire, commune à tous ; et dans le second cas, cela ferait référence à la quantité de connaissances et de sciences qu’il faudrait maîtriser au préalable avant de commencer l’étude d’un sujet précis, qui serait dans ce cas placé en haut d’une hiérarchie dans les savoirs.'' »<br /><p style="margin: 0 2em; text-align: right;">''' Lisa Donnadille. [https://dumas.ccsd.cnrs.fr/dumas-03927443/file/DONNADILLE-MR2-Pline-VERS-FINALE.pdf Merveilles animalières dans les livres VIII à XI de l’Histoire naturelle de Pline l’Ancien. Littératures. 2020. ffdumas-03927443], p.21'''<br/><br/></div> {{Boîte déroulante fin}} ==== Livre III — De l’eau ==== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">En prologue, Sénèque explique pourquoi il est plus important de s’intéresser à l’observation du monde, à sa connaissance et à sa compréhension plutôt qu’à sa conquête. Puis, il développe diverses théories sur la formation des rivières, les eaux souterraines et les propriétés de l’eau. Dans une critique morale aux chapitres XVII à XIX, il fustige la mauvaise pratique consistant à amener à table des poissons, notamment des rougets, vivants et à se délecter de leurs couleurs changeantes à l’agonie avant de les préparer devant les convives. En épilogue, il énonce son [[w:Eschatologie|''eschatologie'']], sa vision de la fin du monde où les êtres vivants seront anéantis par des raz-de-marée, marquant la fin d’un cycle du vivant et le début d’un autre.</div> ===== <div style="text-align: center;">Chapitre XIII.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage de la doctrine de '''Thalès''' faisant de l’eau l’élément à l’origine de la vie et critique d’une autre de la terre flottant dessus.</div> :'''Texte latin''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''13.''' Adiciam, ut '''Thales''' ait, «ualentissimum elementum est». Hoc fuisse primum putat, ex hoc surrexisse omnia. Sed nos quoque aut in eadem sententia, aut in uicinia eius sumus. Dicimus enim ignem esse qui occupet mundum et in se cuncta conuertat; hunc euanidum languentemque considere et nihil relinqui aliud in rerum natura igne restincto quam umoren; in hoc futuri mundi spem latere. Ita ignis exitus mundi est, umor primordium. Miraris ex hoc posse amnes semper exire qui pro omnibus fuit et ex quo sunt omnia? Hic umor in diductione rerum ad quartas redactus est, sic positus ut sufficere fluminibus edendis, ut riuis, ut fontibus posset.<br /><p style="text-indent: 15px;">'''14.''' Quae sequitur '''Thaletis''' inepta sententia est. Ait enim terrarum orbem aqua sustineri et uehi more nauigii mobilitateque eius fluctuare tunc cum dicitur tremere; non est ergo mirum si abundat umor ad flumina profundenda, cum in umore sit totus. Hanc ueterem et rudem sententiam explode. Nec est quod credas in hunc orbem aquam subire per rimas et facere sentinam.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/seneca.-cuestiones-naturales.-naturales-quaestiones.-vol.-i-1979/page/n1/mode/2up <u>L. Annaei Senecae, Natvrales Qvaestiones</u>], [https://archive.org/details/seneca.-cuestiones-naturales.-naturales-quaestiones.-vol.-i-1979/page/n261/mode/2up ''Liber Tertivs.''], [https://archive.org/details/seneca.-cuestiones-naturales.-naturales-quaestiones.-vol.-i-1979/page/n293/mode/2up ''chap. 13.-14.''], texte établi par Carmen Codoñer Merino [[w:es:Carmen_Codoñer_Merino|(es)]], Consejo Superior de Investigaciones Científicas, Madrid, 1979</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: justify; margin: 0 2em;">'''XIII.''' Aqua, ait '''Thales''', valentissimum elementum est : hoc fuisse primum putat, et hoc surrexisse omnia. Sed et nos quoque aut in eadem sententia, aut in ultima sumus. Dicimus enim ignem esse, qui occupet mundum, et in se cuncta convertat ; hunc evanidum considere, et nihil relinqui aliud in rerum natura, igne restincto, quam humorem : in hoc futuri mundi spem latere. Ita ignis exitus mundi est, humor primordium. Miraris amnes ex hoc posse exire semper, qui pro omnibus fuit, et ex quo sunt omnia? Hic humor in diductione rerum ad quartas redactus est, sic positus, ut fluminibus edendis sufficere, ut rivis, ut fontibus posset. Quæ sequitur, '''Thaletis''' inepta sententia est : ait enim , terrarum orbem aqua sustineri, et vehi more navigii, mobilitateque ejus fluctuare, tum quum dicitur tremere. Non est ergo mirum, si abundat humor ad flumina fundenda, quum mundus in humore sit totus. Hanc veterem et rudem sententiam explode : nec est quod credas, in hunc orbem aquam subire per rimas et facere sentiuam.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PP9#v=onepage&q&f=true <u>Œuvres Complètes de Sénèque, Tome Quatrième</u>], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA327#v=onepage&q&f=true ''Questions Naturelles, De Sénèque à Lucilius - Livre Troisième.''], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA342#v=onepage&q&f=true ''chap. XIII.''], traduction française de la collection Panckoucke, nouvelle édition très soigneusement revue par M. Charpentier et M. Félix Lemaistre, 1860</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''XIII.''' L’eau, dit '''Thalès''', est le plus puissant des éléments, le premier en date, celui par qui tout a pris vie. Nous pensons comme '''Thalès''', au moins sur le dernier point. En effet, nous prétendons que le feu doit s’emparer du monde entier et convertir tout en sa propre substance, puis s’évaporer, s’affaisser, s’éteindre et ne rien laisser autre chose dans la nature que l’eau ; qu’enfin l’eau recèle l’espoir du monde futur. Ainsi périra par le feu cette création dont l’eau fut le principe. Es-tu surpris que des fleuves sortent incessamment d’un élément qui a tenu lieu de tout, et duquel tout est sorti ? Quand les éléments furent séparés les uns des autres, l’eau fut réduite au quart de l’univers, et placée de manière à suffire à l’écoulement des fleuves, des ruisseaux, des fontaines. Mais voici une idée absurde de ce même '''Thalès'''. Il dit que la terre est soutenue par l’eau sur laquelle elle vogue comme un navire ; qu’à la mobilité d’un tel support sont dues les fluctuations qu’on appelle tremblements de terre. Ce ne sera donc pas merveille qu’il y ait assez d’eau pour entretenir les fleuves, si tout le globe est dans l’eau. Ce système grossier et suranné n’est que risible ; tu ne saurais admettre que l’eau pénètre notre globe par ses interstices, et que la cale est entr’ouverte.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[[s:Questions_naturelles_(trad._Baillard)|<u>Sénèque le Jeune</u>]], [[s:Questions_naturelles_(trad._Baillard)/Livre_3|''Livre III. chap. 13.'']], traduction par [[s:Auteur:Joseph_Baillard|Joseph Baillard]], Hachette, 1914<br />(également disponible [https://remacle.org/bloodwolf/philosophes/seneque/questionsnaturelles3.htm ici])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: justify; margin: 0 2em;">'''XIII.''' L’eau, dit '''Thalès''', est le plus puissant des éléments : elle existait avant tout, elle est le principe de tout. Nous pensons comme '''Thalès''', au moins sur le dernier point. En effet, nous croyons que le feu, s’emparant du monde entier, convertira tout en sa propre substance : mais il finira par cesser ses ravages, et quand il sera éteint, dans toute la nature il ne restera que l’eau, et cette eau renfermera le germe et l’espérance d’un monde futur. Ainsi par le feu s’accomplira la destruction de l’univers, et par l’eau sa réorganisation. Êtes-vous surpris, maintenant, qu’après avoir tenu lieu de tous les éléments, et les avoir produits tous, l’eau suffise à l’entretien perpétuel des fleuves ? Quand les éléments furent séparés les uns des autres, l’eau fut réduite au quart de l’univers, et dans une proportion convenable pour suffire à l’alimentation des fontaines, des ruisseaux et des rivières. Mais voici une idée absurde du même '''Thalès''' : il dit que la terre est soutenue par l’eau, et qu’elle flotte sur elle comme un navire ; que les tremblements de terre sont causés par les oscillations et les mouvements du fluide qui la soutient. Il n’est donc pas étonnant qu’il y ait assez d’eau pour alimenter les fleuves, puisque tout le globe est dans l’eau. Mais rejetons cette vieille et informe hypothèse, qui assimile les sources aux flots que la cale entr’ouverte laisse pénétrer dans le vaisseau.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PP9#v=onepage&q&f=true <u>Œuvres Complètes de Sénèque, Tome Quatrième</u>], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA327#v=onepage&q&f=true ''Questions Naturelles, De Sénèque à Lucilius - Livre Troisième.''], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA342#v=onepage&q&f=true ''chap. XIII.''], traduction française de la collection Panckoucke, nouvelle édition très soigneusement revue par M. Charpentier et M. Félix Lemaistre, 1860</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: justify; margin: 0 2em;">'''Chap. III.'''<br />''Opiniõ de Thales touchant l’eau.''<br /><p style="text-align: justify; text-indent: 15px;">L’eau , comme dit '''Thales''' , e[[w:S_long|{{Info|ſ|forme ancienne longue de la lettre s minuscule}}]]<nowiki>t</nowiki> le plus fort des Elemens. Il croit me{{Info|ſ|forme ancienne longue de la lettre s minuscule}}me qu’elle e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t le premier , & que toutes cho{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es en ont pris nai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ance. Pour moy ie {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uis de cette opinion , ou du moins de la derniere partie de cette opinion. Car nous [[#nous_stoiciens_NdT_dR|<span id="nous_stoiciens_NdT_dR_back"><sup>1</sup></span>]] di{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ons que c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t le feu qui enueloppera tout le monde , & qui conuertira en {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oy toutes cho{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es; qu’il deuiendra {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ans force quand il n’aura plus de nourriture , qu’apres que le feu {{Info|ſ|forme ancienne longue de la lettre s minuscule}}era e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}teint il ne demeurera rien de re{{Info|ſ|forme ancienne longue de la lettre s minuscule}}te à la nature que l’eau {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eulement , & que c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t en elle {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eule que con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i{{Info|ſ|forme ancienne longue de la lettre s minuscule}}te l’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}perance d’vn monde futur. Ain{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i le feu e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t la fin du monde , & l’eau en e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t le commencement. Vous e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tonnez-vous donc que les fleuues pui{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ent tou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iours {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ortir d’vn Element , qui e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t fait pour toutes cho{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es & dont toutes cho{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e font ? Lors que la nature fit le departement des Elemens , l’eau fut placée de telle {{Info|ſ|forme ancienne longue de la lettre s minuscule}}orte , qu’elle peut {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uffire pour les fleuues , pour les rui{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}eaux , pour les fontaines. Mais ce que '''Thales''' dit en {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uitte e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t ridicule , car il dit que le Globe de la terre e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tenu par les eaux ; qu’elles le portent comme vn vai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}eau , & qu’elles l’agitent de la me{{Info|ſ|forme ancienne longue de la lettre s minuscule}}me {{Info|ſ|forme ancienne longue de la lettre s minuscule}}orte , lors que nous croyons qu’il tremble. Il ne faut donc pas s’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tonner , s’il ya tou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iours a{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ez d’eau pour former de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i grands fleuues , puis que tout le monde nage fur l’eau. Mais me{{Info|ſ|forme ancienne longue de la lettre s minuscule}}pri{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ez cette vieille , & cette gro{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}iere opinion , & ne croyez pas que l’eau vienne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur la terre , comme par des fentes & par des creua{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}es , & qu’elle y {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oit {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eulement comme dans le fond d’vn vai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}eau.</div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#nous_stoiciens_NdT_dR_back|<span id="nous_stoiciens_NdT_dR"><sup>1.</sup></span>]] Les Stoïciens.''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=ktOcOg9lr54C&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles%20iii&hl=fr&pg=PA1#v=onepage&q&f=true <u>Seneque Des Qvestions Natvrelles</u>], [https://books.google.fr/books?id=ktOcOg9lr54C&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles%20iii&hl=fr&pg=PA202#v=onepage&q&f=true ''Livre Troisiesme. Des eaux.''], [https://books.google.fr/books?id=ktOcOg9lr54C&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles%20iii&hl=fr&pg=PA234#v=onepage&q&f=true ''chap. XIII.''], traduction par [[w:Pierre_Du_Ryer|Pierre Du Ryer]], A Lyon, Chez Christofle Fovrmy, 1663</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div> </div> <div style="text-align: center; margin: 0 auto;">― ● ―</div> ==== Livre IV — Du Nil ==== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">En prologue, '''Sénèque''' fait l’éloge de [[w:Lucilius_le_Jeune|'''Lucilius''']] [[#Lucilius|<span id="Lucilius_back"><sup>'''I'''</sup></span>]] avant de lui expliquer les dangers de la flatterie. Puis, il décrit la crue du [[w:Nil|''Nil'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Nil_back|<sup>🔄</sup>]], expose les théories tentant de l’expliquer et les réfute. En épilogue, il fait le procès du luxe, et plus particulièrement celui d’acheter de la neige, et donc de marchandiser l’eau, regrettant qu’on ne puisse faire de même avec l’air et le soleil.</div> {{Boîte déroulante début|titre=NdA Lucilius|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Lucilius_back|<span id="Lucilius"><sup>I</sup></span>]] Du nom propre latin Lucilius [[wikt:en:Lucilius#Latin|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;">Gouverneur ''romain'' de Sicile durant le règne de [[w:Néron|Néron]], ainsi qu’un ami et un correspondant de Sénèque.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:Ier_siècle_av._J.-C.|I<sup>er</sup> siècle {{Info|EC|de l’Ère Commune}}]], [[w:Campanie#Histoire|''Campanie'']], [[w:Quatorze_régions_de_la_Rome_augustéenne#Regio_I_:_Porte_Capène|''Regio I'']])'''<br/><br/></div> {{Boîte déroulante fin}} ===== <div style="text-align: center;">Chapitre II.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Réfutation par '''Sénèque''' d’une théorie explicite de '''Thalès''' sur la crue du ''Nil'' (théorie identique mais supposément implicite rapportée par [[w:Hérodote|'''Hérodote''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Chapitre_XX|<sup>🔄</sup>]]).</div> :'''Texte latin''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''2.''' [...] Si '''Thaleti''' credis, etesiae descendenti ''Nilo'' resistunt et cursum eius acto contra ostia mari sustinent. Ita reuerberatus in se recurrit, nec crescit, sed exitu prohibitus resistit et quacumque mox potuit ui congestus erumpit. '''Euthymenes''' ''Massiliensis'' testimonium dicit: «Nauigaui, inquit, ''Atlanticum'' mare. Inde ''Nilus'' fluit, maior, quamdiu etesiae tempus obseruant; tunc enim eicitur mare instantibus uentis. Cum resederunt, et pelagus conquiescit minorque descendenti inde uis ''Nilo'' est. Ceterum dulcis mari sapor est et similes ''Niloticis'' beluae». Quare ergo, si ''Nilum'' etesiae prouocant, et ante illos incipit incrementum eius et post eos durat? Praeterea non fit maior quo illi flauere uehementius, nec remittitur incitaturque, prout illis impetus fuit; quod fieret, si illorum uiribus cresceret. Quid quod etesiae litus ''Aegyptium'' uerberant et contra illos ''Nilus'' descendit, inde uenturus unde illi, si origo ab illis esset? Praeterea ex mari purus et caeruleus efflueret, non, ut nunc, turbidus ueniret. Adde quod testimonium eius testium turba coarguitur. Tunc erat mendacio locus; cum ignota essent externa, licebat illis fabulas mittere. Nunc uero tota exteri maris ora mercatorum nauibus stringitur, quorum nemo narrat initium ''Nili'' aut mare saporis alterius: quae natura credi uetat, quia dulcissimum quodque et leuissimum sol trahit. Praeterea quare hieme non crescit? Et tunc potest uentis concitari mare, aliquanto quidem majoribus; nam etesiae temperati sunt. Quod si e mari ferretur ''Atlantico'', semel oppleret ''Aegyptum''. At nunc per gradus crescit.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/seneca.-cuestiones-naturales.-naturales-quaestiones.-vol.-ii-1979/page/n1/mode/2up <u>L. Annaei Senecae, Natvrales Qvaestiones</u>], [https://archive.org/details/seneca.-cuestiones-naturales.-naturales-quaestiones.-vol.-ii-1979/page/n7/mode/2up ''Liber Qvartvs A.''], [https://archive.org/details/seneca.-cuestiones-naturales.-naturales-quaestiones.-vol.-ii-1979/page/n41/mode/2up ''chap. 2.''], texte établi par Carmen Codoñer Merino [[w:es:Carmen_Codoñer_Merino|(es)]], Consejo Superior de Investigaciones Científicas, Madrid, 1979</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: justify; margin: 0 2em;">'''II.''' [...] Si '''Thaleti''' credis, Etesiæ descendenti ''Nilo'' resistunt, et cursus ejus acto contra ostia mari sustinent : ita reverberatus in se recurrit : nec crescit, sed exitu prohibitus resistit, et quacumque mox potuit, inconcessus erumpit.<br /><p style="text-align: justify; text-indent: 15px;">'''Euthymenes''' ''Massiliensis'' testimonium dicit : « Navigavi, inquit, ''Atlanticum'' mare. Inde ''Nilus'' fluit major, quamdiu Etesiæ tempus observant : tunc enim ejicitur mare instantibus ventis. Quum resederint, et pelagus conquiescit, minorque descendenti inde vis ''Nilo'' est. Ceterum dulcis maris sapor est, et similes ''Niloticis'' belluæ. » Quare ergo, si ''Nilum'' Etesiæ provocant, et ante illos incipit incrementum ejus, et post eos durat ? Præterea non fit major, quo illi flavere vehementius. Nec remittitur, incitaturque, prout illis impetus fuit : quod fieret, si illorum viribus cresceret. Quid, quod Etesiæ littus ''ægyptium'' verberant, et contra illos ''Nilus'' descendit, inde venturus, unde illi, si origo ab illis esset ? Præterea ex mari purus et cæruleus efflueret, non ut nunc turbidus venit. Adde, quod testimonium ejus testium turba coarguitur. Tunc erat mendacio locus, quum ignota essent externa. Licebat illis fabulas mittere. Nunc vero tota exteri maris ora mercatorum navibus stringitur : quorum nemo narrat nunc cæruleum ''Nilum'', aut mare saporis alterius ; quod et natura credi vetat, quia dulcissimum quodque et levissimum sol trahit. Præterea quare hieme non crescit ? et tunc potest ventis concitari mare, aliquando quidem majoribus ; nam Etesiæ temperati sunt. Quod si e mari ferretur ''Atlantico'', semel oppleret ''Ægyptum''. At nunc per gradus crescit.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PP9#v=onepage&q&f=true <u>Œuvres Complètes de Sénèque, Tome Quatrième</u>], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA371#v=onepage&q&f=true ''Questions Naturelles, De Sénèque à Lucilius - Livre Quatrième.''], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA385#v=onepage&q&f=true ''chap. II.''], traduction française de la collection Panckoucke, nouvelle édition très soigneusement revue par M. Charpentier et M. Félix Lemaistre, 1860</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''II.''' [...] À en croire '''Thalès''', les vents étésiens repoussent le ''Nil'' à sa descente dans la mer, et suspendent son cours en poussant la mer contre ses embouchures. Ainsi refoulé, il revient sur lui-même, sans pour cela grossir ; mais l’issue lui étant barrée, il s’arrête, et bientôt, partout où il le peut, force le passage qui lui est refusé. [[w:Euthymènes|'''Euthymène''']] [[#Euthymènes|<span id="Euthymènes_back"><sup>'''I'''</sup></span>]], de ''Marseille'', en parle comme témoin : « J’ai navigué, dit-il, sur la mer ''Atlantique''. Elle cause le débordement du ''Nil'', tant que les vents étésiens se soutiennent ; car c’est leur souffle qui alors pousse cette mer hors de son lit. Dès qu’ils tombent, la mer aussi redevient calme, et le ''Nil'' à sa descente déploie moins de puissance. Du reste, l’eau de cette mer est douce, et nourrit des animaux semblables à ceux du ''Nil''. » Mais pourquoi, si les vents étésiens font gonfler le ''Nil'', la crue commence-t-elle avant la saison de ces vents, et dure-t-elle encore après ? D’ailleurs le fleuve ne grossit pas à mesure qu’ils soufflent plus violemment. Son plus ou moins de fougue n’est point réglé sur celle des vents étésiens, ce qui aurait lieu, si leur action le faisait hausser. Et puis ils battent la côte ''égyptienne'', le ''Nil'' descend à leur encontre : il faudrait qu’il vînt du même point qu’eux, si son accroissement était leur ouvrage. De plus, il sortirait pur et azuré de la mer, et non pas trouble comme il est. Ajoute que le témoignage d’'''Euthymène''' est réfuté par une foule d’autres. Le mensonge avait libre carrière, quand les plages étrangères étaient inconnues ; on pouvait de là nous envoyer des fables, À présent, la mer extérieure est côtoyée sur tous ses bords par des trafiquants dont pas un ne raconte qu’aujourd’hui le ''Nil'' soit azuré ou que l’eau de la mer soit douce. La nature elle-même repousse cette idée ; car les parties les plus douces et les plus légères sont pompées par le soleil. Et encore pourquoi le ''Nil'' ne croît-il pas en hiver ? Alors aussi la mer peut être agitée par des vents quelque peu plus forts que les étésiens, qui sont modérés. Si le mouvement venait de l’Atlantique, il couvrirait tout d’un coup l’Égypte : or l’inondation est graduelle.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[[s:Questions_naturelles_(trad._Baillard)|<u>Sénèque le Jeune</u>]], [[s:Questions_naturelles_(trad._Baillard)/Livre_4|''Livre IV.'']] ''chap. 2.'', traduction par [[s:Auteur:Joseph_Baillard|Joseph Baillard]], Hachette, 1914<br />(également disponible [https://remacle.org/bloodwolf/philosophes/seneque/questionsnaturelles4.htm ici])</div> {{Boîte déroulante début|titre=NdA trad. par Joseph Baillard de 1914|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Euthymènes_back|<span id="Euthymènes"><sup>I</sup></span>]] Du nom propre grec ancien Εὐθυμένης / Euthuménēs [[wikt:en:Εὐθυμένης#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;"> ➥ de l’adjectif εὐθύς / euthús, « 1. Droit, direct : (au sens moral) direct, ouvert, franc. »;<br /><p style="margin: 0 2em; text-indent: 15px;"> ➥ + du nom commun μενος / ménos, « 1. Esprit. 2. Désir, ardeur, souhait, but. 3. Colère. 4. Courage, esprit, vigueur. 5. Pouvoir, force. 6. Violence. »;<br /><p style="margin: 0 2em; text-indent: 15px;"> ➥ + du suffixe nominal‎ propre -ης / -ēs [[wikt:en:-ης#Suffix_2|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;"> Navigateur et explorateur de la mer Extérieure le long des côtes africaines (actuelle Atlantique sud).<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:VIeme_siècle_av._J.-C.|VI<sup>ème</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]], [[w:Marseille_antique#Massalia,_une_cité_grecque|''Massalia'']], actuelle Marseille)'''<br/><br/></div> {{Boîte déroulante fin}} <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: justify; margin: 0 2em;">'''II.''' [...] Selon '''Thalès''', le phénomène a pour cause les vents Étésiens, qui s’opposent au cours du ''Nil'' et font rebrousser ses eaux en sens inverse du mouvement qui le porte vers la mer. Refoulés sur eux-mêmes, les flots refluent sans pour cela grossir ; mais l’issue leur étant fermée, ils s’arrêtent, et bientôt ils s’ouvrent partout où ils peuvent le passage qui leur est refusé.<br /><p style="text-align: justify; text-indent: 15px;">'''Euthymène''' de ''Marseille'' en parle comme témoin : « J’ai navigué, dit-il, sur la mer ''Atlantique''. Le ''Nil'' roule des eaux plus abondantes, tant que durent les vents Étésiens ; car alors ils refoulent la mer sur le fleuve. Dès qu’ils se sont abattus et que la mer est devenue calme, le ''Nil'', qui peut redescendre vers celle-ci, diminue. Au reste, les eaux de cette mer sont douces et contiennent des animaux semblables à ceux du ''Nil''. » Dans cette hypothèse, qui donne les vents Étésiens pour cause des crues du ''Nil'', qu’on me dise pourquoi ces crues précèdent les vents, persistent quand les vents ne sont plus, enfin n’augmentent plus d’intensité et de violence, et ne diminuent pas selon la violence et l’impétuosité du vent même ; c’est pourtant ce qui devrait arriver, si les vents déterminaient la hausse des eaux. De plus, les vents Étésiens battent directement la côte ''égyptienne'' : pourquoi donc le ''Nil'' descend-il contre le souffle de ces vents, tandis qu’il devrait couler dans la même direction, s’il leur devait ses débordements ? Enfin, pourquoi, au lieu d’être diaphanes et azurés, ces flots, qu’on fait venir de la mer, sont-ils chargés de limon ? Ajoutez qu’une foule de témoignages réfutent '''Euthymène'''. On pouvait mentir, quand les plages étrangères étaient inconnues : c’était alors le temps des fables ; mais aujourd’hui mille vaisseaux marchands côtoient la mer extérieure ; personne ne dit que le ''Nil'' ait des flots d’azur ; personne ne donne à la mer une saveur douce, que la nature refuse à ses eaux : car le soleil en pompe sans cesse la partie la plus douce et la plus légère ; ensuite pourquoi le ''Nil'' ne croîtrait-il point pendant l’hiver ? la mer alors peut être battue par les vents, par des vents plus violents que les Étésiens, qui sont modérés. Enfin, si le mouvement venait de l’Atlantique, l’Égypte entière serait inondée tout d’un coup : or, l’inondation est graduelle.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PP9#v=onepage&q&f=true <u>Œuvres Complètes de Sénèque, Tome Quatrième</u>], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA371#v=onepage&q&f=true ''Questions Naturelles, De Sénèque à Lucilius - Livre Quatrième.''], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA385#v=onepage&q&f=true ''chap. II.''], traduction française de la collection Panckoucke, nouvelle édition très soigneusement revue par M. Charpentier et M. Félix Lemaistre, 1860</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: justify; margin: 0 2em;">'''Chap. II.'''<br />''En quelle fai[[w:S_long|{{Info|ſ|forme ancienne longue de la lettre s minuscule}}]]<nowiki>ó</nowiki> {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e fait l’accroi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ement du Nil.''<br /><p style="text-align: justify; text-indent: 15px;">[...] Si vous en croyez '''Thales''' , les vents Ethe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iens re{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tent au ''Nil'' en de{{Info|ſ|forme ancienne longue de la lettre s minuscule}}cendant dans la mer; & arre{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tent {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on cours, en pou{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ant la mer contre {{Info|ſ|forme ancienne longue de la lettre s minuscule}}es {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ept emboucheures. Si bien qu’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es {{Info|ſ|forme ancienne longue de la lettre s minuscule}}tant repou{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}é de la {{Info|ſ|forme ancienne longue de la lettre s minuscule}}orte il retourne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oy-me{{Info|ſ|forme ancienne longue de la lettre s minuscule}}me , & ne croi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t pas comme l’on pen{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e , mais par ce qu’il trouue vn ob{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tacle qui l’empe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}che de pa{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}er outre , il e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t contraint de s’arre{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ter , & ne pouuant plus pour{{Info|ſ|forme ancienne longue de la lettre s minuscule}}uiure {{Info|ſ|forme ancienne longue de la lettre s minuscule}}a cour{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e , il {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e re{{Info|ſ|forme ancienne longue de la lettre s minuscule}}pand par où il peut {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e répandre. '''Euthimenes''' de ''Mar{{Info|ſ|forme ancienne longue de la lettre s minuscule}}eille'' en rend ce te{{Info|ſ|forme ancienne longue de la lettre s minuscule}}moignage. I’ay nauigé, dit il, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur la mer ''Atlantique'' , & c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t par elle que le ''Nil'' deuient plus grand, lors que les vents Ethe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iens {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oufflent ; car alors cette mer {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ort pour ain{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i dire d’elle-me{{Info|ſ|forme ancienne longue de la lettre s minuscule}}me par la force & par la violence de ces vents. Mais lors qu’ils ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oufflent plus la mer demeure tranquille, & le Nil ne trouue plus rien qui l’empe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}che de de{{Info|ſ|forme ancienne longue de la lettre s minuscule}}cendre , Au re{{Info|ſ|forme ancienne longue de la lettre s minuscule}}te l’eau de la mer e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t douce en ce temps-là , & l’on y void des be{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tes {{Info|ſ|forme ancienne longue de la lettre s minuscule}}emblables à celles du Nil. Mais {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i les Ethe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iens {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont enfler le Nil, pourquoy {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on débordement commence il auant qu’ils {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oufflent & pourquoy dure - il encore lors qu’ils ont ce{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}é de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ouffler. Dauantage ils ne s’enfle pas plus que de cou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tume , quand ces vents {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oufflent auecque plus de violence qu’ils ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont ordinairement. Enfim il ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e hau{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}e & ne s’abai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}e pas {{Info|ſ|forme ancienne longue de la lettre s minuscule}}elon que leur impetuo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ité e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t plus ou moins grande , ce qui arriveroit {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ans doute s’il s’enfloit par la force de ces véts. Mais comme les Ete{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iens battent directement les bords de l’Egypte, & que le Nil de{{Info|ſ|forme ancienne longue de la lettre s minuscule}}cend contre eux ; il faudroit s’ils e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}toient cau{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on accroi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ement , qu’il commença{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t par l’endroit d’où ils viennent. Outre cela il {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ortiroit tout pur de la mer, & de la couleur de la mer, & ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eroit pas trouble & limonneux , comme il e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t. Et apres tout le te{{Info|ſ|forme ancienne longue de la lettre s minuscule}}moignage d’'''Euthimene''' , e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t condamné par le plus grand nombre. Il e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}toit permis de mentir quand on n’auoit point de connoi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ance des pays e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}trangers ; & alors on pouuoit facilement nous en enuoyer des fables. Mais aujourd’huy tous les riuages des mers les plus e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}loignées {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont remplis de vai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}eaux de marchands, & pas vn ne nous apporte que le ''Nil'' {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oit de la couleur de la mer, ou que la mer ait vn autre gou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t. Quand nous aurions des rai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ons pour nous la per{{Info|ſ|forme ancienne longue de la lettre s minuscule}}uader , la nature nous empe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}cheroit de le croire par ce que le Soleil en attire ce qu’il y a de plus leger & de plus doux. Dauantage pourquoy ne croi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t-il pas en Hyuer , puis que la met en ce temps là peut e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tre agitée par des vents plus violents, que les Ethe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iens qui {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont tou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iours moderez. Que {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i le ''Nil'' venoit de la mer ''Atlantique'' , il couuriroit l’Egypte tout d’vn coup, & neantmoins il ne la couure que peu à peu.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=gEzVYlz3c3cC&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles%20iii%20volume%202&hl=fr&pg=PA1#v=onepage&q&f=true <u>Seneque Des Qvestions Natvrelles</u>], [https://books.google.fr/books?id=gEzVYlz3c3cC&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles%20iii%20volume%202&hl=fr&pg=PA3#v=onepage&q&f=true ''Livre Qvatriesme. De la Nege, de la Greſle, & de la Pluye.''], [https://books.google.fr/books?id=gEzVYlz3c3cC&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles%20iii%20volume%202&hl=fr&pg=PA37#v=onepage&q&f=true ''chap. II.''], traduction par [[w:Pierre_Du_Ryer|Pierre Du Ryer]], A Lyon, Chez Christofle Fovrmy, 1663</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div> </div> <div style="text-align: center; margin: 0 auto;">― ● ―</div> ==== Livre VI — Des tremblements de terre ==== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">En prologue, '''Sénèque''' énonce le plan du livre, des causes des tremblements de terre et des peurs qu’ils provoquent, en s’appuyant sur celui de ''Campanie'' qui a récemment causé d’importants dégâts à ''Pompéi'' et à ''Herculanum''. Des chapitres IV à XX, de nombreuses théories sismiques sont présentées, la plupart liées au nom d’un philosophe qui les prône. Le feu, l’eau et l’air sont cités comme causes, et plusieurs d’entre-elles les combinent. À partir du chapitre XXIV, '''Sénèque''' développe sa propre opinion : l’air pénétrant, qui remplit complètement les cavités souterraines sous une forte pression, en est la cause. En épilogue, il explique à '''Lucilius''' quel comportement adopté en de telles situations, à savoir être courageux en ne craignant pas la mort</div> ===== <div style="text-align: center;">Chapitre VI.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Réfutation d’une théorie de '''Thalès''' de la Terre flottant sur l’eau, et témoignage d’une de ses preuves portant sur les tremblements de terre.</div> :'''Texte latin''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''6.''' In aqua causam esse nec ab uno dictum est nec uno modo. '''Thales''' ''Milesius'' totam terram subiecto iudicat umore portari et innare, siue illud oceanum uocas, siue magnum mare, siue alterius naturae simplicem adhuc aquam et umidum elementum. Hac, inquit, unda sustinetur orbis uelut aliquod grande nauigium et graue his aquis quas premit. Superuacuum est reddere causas propter quas existimat grauissimam partem mundi non posse spiritu tam tenui fugacique gestari; non enim nunc de situ terrarum sed de motu agitur. Illud argumenti loco ponit aquas esse in causa quibus hic orbis agitetur, quod in omni maiore motu erumpunt fere noui fontes, sicut in nauigiis quoque euenit ut, si inclinata sunt et abierunt in latus, aquam sorbeant, quae in omni eorum onere quae uehit, si immodice depressa sunt, aut superfunditur aut certe dextra sinistraque solito magis surgit. Hanc opinionem falsam esse non est diu colligendum. Nam, si terra aqua sustineretur et ea aliquando concuteretur, semper moueretur, nec agitari illam miraremur sed manere; deinde tota concuteretur, non ex parte; numquam enim nauis dimidia iactatur. Nunc uero terrarum non uniuersarum sed ex parte motus est. Quomodo ergo fieri potest ut, quod totum uehitur, totum non agitetur, si eo quo uehitur agitatum est? — At quare aquae erumpunt? — Primum omnium saepe tremuit terra et nihil umoris noui fluxit. Deinde, si ex hac causa unda prorumperet, a lateribus terrae circumfunderetur, sicut in fluminibus ac mari uidemus incidere ut incrementum aquarum, quotiens nauigia desidunt, in lateribus maxime appareat. Ad ultimum non tam exigua fieret quam tu dicis eruptio nec uelut per rimam sentina subreperet, sed fieret ingens inundatio ut ex infinito liquore et ferente uniuersa.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/seneca.-cuestiones-naturales.-naturales-quaestiones.-vol.-ii-1979/page/n1/mode/2up <u>L. Annaei Senecae, Natvrales Qvaestiones</u>], [https://archive.org/details/seneca.-cuestiones-naturales.-naturales-quaestiones.-vol.-ii-1979/page/n135/mode/2up ''Liber Qvintvs - De terrae motv''], [https://archive.org/details/seneca.-cuestiones-naturales.-naturales-quaestiones.-vol.-ii-1979/page/n155/mode/2up ''chap. 6.''], texte établi par Carmen Codoñer Merino [[w:es:Carmen_Codoñer_Merino|(es)]], Consejo Superior de Investigaciones Científicas, Madrid, 1979</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: justify; margin: 0 2em;">'''VI.''' In aqua causam esse, nec ab uno dictum est, nec uno modo. '''Thales''' ''Milesius'' totam terram subjecto judicat humore portari et innatare : sive illud Oceanum vocas, sive magnum mare, sive alterius naturæ simplicem adhuc aquam et humidum elementum. Hac, inquit, unda sustinetur orbis, velut aliquod grande navigium et grave his aquis, quas premit. Supervacuum est reddere causas, propter quas existimat, gravissimam partem mundi non posse spiritu tam tenui fugacique gestari ; non enim nunc de situ terrarum, sed de motu agitur. Illud argumenti loco ponit, aquas esse in causa, quibus hic orbis agitatur, quod in omui majore motu erumpunt fere novi fontes : sicut in navigiis quoque evenit, ut, si inclinata sunt et abiere in latus, aquam sorbeant, quæ in omni onere eorum quæ vehit, si immodice depressa sunt, aut superfunditur, aut certe dextra sinistraque solito magis surgit. Hanc opinionem falsam esse, non est diu colligendum ; nam, si terram aqua sustineret, et ea aliquando concuteretur : semper moveretur, nec agitari illam miraremur, sed manere. Tum tota concuteretur, non ex parte : nunquam enim navis dimidia jactatur. Nunc vero non terrarum universarum, sed ex parte motus est. Quomodo ergo fieri potest, ut quod totum vehitur, totum non agitetur, si eo quo vehitur, agitatum est ? At quare aquæ erumpunt ? Primum omnium sæpe tremuit terra, et nihil humoris novi fluxit. Deinde si ex hac causa unda prorumperet, a lateribus terræ circumfunderetur : sicut in fluminibus ac mari videmus accidere, ut incrementum aquarum, quoties navigia desidunt, in lateribus maxime appareat. Ad ultimum non tam exigua fieret quam dicit eruptio, nec velut per rimam sentina subreperet, sed fieret ingens inundatio, ut ex infinito liquore, et ferente universa.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PP9#v=onepage&q&f=true <u>Œuvres Complètes de Sénèque, Tome Quatrième</u>], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA420#v=onepage&q&f=true ''Questions Naturelles, De Sénèque à Lucilius - Livre Sixième.''], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA429#v=onepage&q&f=true ''chap. VI.''], traduction française de la collection Panckoucke, nouvelle édition très soigneusement revue par M. Charpentier et M. Félix Lemaistre, 1860</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''VI.''' Que l’eau soit cause des tremblements de terre, c’est ce qu’affirment divers auteurs et avec divers arguments. '''Thalès''' de ''Milet'' estime que le globe entier a pour support une masse d’eaux sur laquelle il flotte, et qu’on peut appeler Océan ou grande mer, ou élément jusqu’ici de nature simple, l’élément humide. Cette eau, dit-il, soutient la terre ; et l’immense navire pèse sur le liquide qu’il comprime. Il est superflu d’exposer les motifs qui font croire à '''Thalès''' que la partie de l’univers la plus pesante ne saurait porter sur une substance aussi ténue, aussi fugace que l’air : il ne s’agit pas maintenant de l’assiette du globe, mais de ses secousses. '''Thalès''' apporte en preuve de son système, que presque toujours les grandes secousses font jaillir des sources nouvelles, comme il arrive dans les navires qui, lorsqu’ils penchent et s’inclinent sur le flanc, sont envahis par l’eau ; toujours, s’il y a surcharge, l’eau vient couvrir le bâtiment, ou du moins s’élève à droite et à gauche plus que de coutume. La fausseté de cette opinion se démontre sans longs raisonnements. Si la terre était soutenue par l’eau, elle tremblerait quelquefois dans toute sa masse et toujours serait en mouvement ; ce ne serait pas son agitation qui étonnerait, mais son repos. Elle s’ébranlerait tout entière, non partiellement ; car ce n’est jamais la moitié seulement d’un navire qui est battue des flots. Or, les tremblements de notre terre ne sont pas universels, mais partiels. Comment serait-il possible qu’un corps porté tout entier par l’eau ne fût pas agité tout entier, quand ce fluide est agité ? « Mais d’où viennent les eaux qu’on a vues jaillir ? » D’abord, souvent la terre tremble, sans qu’il en sorte de nouvelles eaux. Ensuite, si telle était la cause de ces éruptions, elles n’auraient lieu qu’autour des flancs du globe ; ce que nous voyons arriver sur les fleuves et en mer : l’exhaussement de l’onde, à mesure que s’enfonce le navire, se remarque surtout aux flancs du bâtiment. Enfin l’éruption dont on parle ne serait pas si minime, et comme une voie d’eau qui s’infiltre par une fente légère ; l’inondation serait immense en raison de l’abîme infini sur lequel flotterait le monde.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[[s:Questions_naturelles_(trad._Baillard)|<u>Sénèque le Jeune</u>]], [[s:Questions_naturelles_(trad._Baillard)/Livre_6|''Livre VI.'']] ''chap. 6.'', traduction par [[s:Auteur:Joseph_Baillard|Joseph Baillard]], Hachette, 1914<br />(également disponible [https://remacle.org/bloodwolf/philosophes/seneque/questionsnaturelles6.htm ici])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: justify; margin: 0 2em;">'''VI.''' Plusieurs philosophes ont prétendu que l’eau est la cause de ces secousses : ce que chacun explique à sa manière. '''Thalès''' de ''Milet'' prétend que le globe entier a pour support une masse d’eau sur laquelle il flotte ; peu importe qu’on donne à cet amas le nom d’Océan, de grande mer ou d’eau élémentaire, eau simple. Cette eau, dit-il, soutient la terre comme un grand vaisseau pesant sur le liquide qu’il comprime. Il est inutile d’exposer les raisons qui font croire à '''Thalès''' que le corps le plus pesant de la nature ne peut être soutenu par un fluide aussi délié et aussi rare que l’air : car il s’agit ici des tremblements de terre et non de l’assiette du globe. La grande raison de '''Thales''' pour faire de l’eau la cause des secousses de la terre, c’est que, dans tout tremblement considérable, jaillissent des eaux nouvelles ainsi les vaisseaux se remplissent d’eau quand ils penchent d’un côté ; chargés à l’excès, ou ils sont submergés, ou ils s’enfoncent à droite et à gauche plus profondément dans la mer. Il ne faut pas longtemps discuter pour voir la fausseté de cette opinion. Si la terre était soutenue par les eaux, elle serait quelquefois fortement ébranlée, mais de plus elle serait toujours flottante, et il faudrait s’étonner non de son agitation , mais de son repos ; enfin, au lieu d’être ébranlée en partie, elle le serait tout entière : car jamais la moitié d’un vaisseau n’est battue des flots. Or, on sait que les secousses de la terre sont partielles et non universelles : comment se ferait-il donc que ce qui est entièrement porté par les eaux ne fût pas entièrement agité, tandis que les eaux mêmes le sont en totalité ? Mais, dit-on, qui fait jaillir les eaux ? D'abord, souvent la terre tremble sans qu’il se produise des eaux nouvelles ; ensuite, si telle était la cause de ces éruptions, les eaux se répandraient latéralement autour de la terre. Ainsi, par exemple, quand un vaisseau s’enfonce ou dans la mer ou dans les fleuves, c’est vers les bords surtout que l’accroissement devient sensible. Enfin les sources qui jaillissent ne seraient pas si peu considérables ; on ne pourrait pas les comparer à une voie d’eau qui pénètre par les fentes du fond de cale : ce serait une inondation immense comme l’abîme infini sur lequel flotterait le monde.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PP9#v=onepage&q&f=true <u>Œuvres Complètes de Sénèque, Tome Quatrième</u>], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA420#v=onepage&q&f=true ''Questions Naturelles, De Sénèque à Lucilius - Livre Sixième.''], [https://books.google.fr/books?id=xZtfAAAAcAAJ&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles&hl=fr&pg=PA429#v=onepage&q&f=true ''chap. VI.''], traduction française de la collection Panckoucke, nouvelle édition très soigneusement revue par M. Charpentier et M. Félix Lemaistre, 1860</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: justify; margin: 0 2em;">'''Chap. VI.'''<br />''Si l’eau e[[w:S_long|{{Info|ſ|forme ancienne longue de la lettre s minuscule}}]]<nowiki>t</nowiki> la cau{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e des tréblemés de terre.''<br /><p style="text-align: justify; text-indent: 15px;">Ce n'e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t pas vn homme {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eul qui a dit , que l’eau e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}toit cau{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e du tremblement de la terre ; & l’on ne l’a pas dit d’vne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eule façó. '''Thales''' ''Mile{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ien'' a crû que toute la terre e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}toit portée {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur l’eau , & qu’elle y nageoit, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oit que vous appelliez cette eau Ocean, ou que vous l’appelliez grade mer, ou vne eau d’vne autre nature , eau {{Info|ſ|forme ancienne longue de la lettre s minuscule}}imple , element humide. C’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur cette eau, dit-il, que le monde e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tenu, comme quelque vai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}eau d’vne grandeur deme{{Info|ſ|forme ancienne longue de la lettre s minuscule}}urée , qui charge les eaux qui le {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tiennent. Il {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eroit inutile de rapporter les rai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ons qui luy {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont croire que la plus pe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ante partie du móde ne peut e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tre {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tenuë par l’air qui e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ubtil, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i fluide & {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i delié ; & d’ailleurs, il ne s’agit pas icy de l’a{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}iete de la terre , mais du tremblement de la terre. Ain{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i pour preuue que les eaux {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont cau{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e que la terre tremble , il dit qu’il ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e fait pre{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que point de grands tremblemens de terre, qu’on n’en voye {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ortir en{{Info|ſ|forme ancienne longue de la lettre s minuscule}}uitte de nouuelles {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ources; que la terre re{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}emble en cela aux vai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}eaux qui ne peuuent pancher d’vn co{{Info|ſ|forme ancienne longue de la lettre s minuscule}}té, qu’ils ne pui{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ent de l’eau, qui {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e re{{Info|ſ|forme ancienne longue de la lettre s minuscule}}pand {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur toutes les cho{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es qu’ils portent , {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i elles {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont trop enfoncées; ou qui s’éleue de part & d’autre à la gauche , & à la droite. Il n’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t pas besoin d’vn long di{{Info|ſ|forme ancienne longue de la lettre s minuscule}}cours pour montrer la fau{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}eté de cette opinion ; car {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i l’eau {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tenoit la terre, quelquesfois elle trembleroit toute entiere, & {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eroit tou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iours en mouuement; & nous ne nous e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tonnerions point de la voir remuer, mais de la voir ferme & inébranlable. Elle trembleroit toute entiere , & non pas en partie , car vn vai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}eau n’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t iamais agité par vne moitié {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eulement ; & apres tout nous voyons que le tremblement ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e fait pas de toute la terre , mais {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eulement d’vne partie. Comment donc {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e peut-il faire que ce qui e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t porté tout entier ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oit pas entierement agité , {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i la cho{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e me{{Info|ſ|forme ancienne longue de la lettre s minuscule}}me qui porte e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}meuë & agitée ? Mais pourquoy {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ort-il de l’eau apres vn tremblement de terre ? Premierement la terre a {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ouuent tremblé {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ans qu’on en ayt veu {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ortir de nouuelles {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ources. D’ailleurs {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i l’eau {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ortoit par cette rai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}on elle {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e re{{Info|ſ|forme ancienne longue de la lettre s minuscule}}pandroit par les co{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tez de la terre , comme nous voyons dans les fleuues & dans la mer , où lors que le vai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}eau s’enfonce on remarque que l’eau s'éleue , principalement par les co{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tez. Enfin ces eaux ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ortiroient pas en {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i petite quantité, ny par vne fi petite ouuerture , mais il {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eroit vne grande inondation, comme procedant de cette abondance d’eaux qui {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tiennent tout l’vniuers.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=gEzVYlz3c3cC&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles%20iii%20volume%202&hl=fr&pg=PA1#v=onepage&q&f=true <u>Seneque Des Qvestions Natvrelles</u>], [https://books.google.fr/books?id=gEzVYlz3c3cC&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles%20iii%20volume%202&hl=fr&pg=PA141#v=onepage&q&f=true ''Livre Sixiesme. Des tremblemens de terre.''], [https://books.google.fr/books?id=gEzVYlz3c3cC&newbks=1&newbks_redir=0&dq=seneque%20questions%20naturelles%20iii%20volume%202&hl=fr&pg=PA164#v=onepage&q&f=true ''chap. VI.''], traduction par [[w:Pierre_Du_Ryer|Pierre Du Ryer]], A Lyon, Chez Christofle Fovrmy, 1663</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Pline_l%27Ancien|'''Pline l’Ancien''']] [[#Pline|<span id="Pline_back"><sup>'''I'''</sup></span>]] == <p style="text-align: right;">([[w:23|23]]/[[w:24|24]], à [[w:Côme|''Novum Comum'']] ou [[w:Vérone|Vérone]] — [[w:79|79]], à [[w:Stabies|Stabies]], [[w:Mort_de_Pline_l%27Ancien|mort]] par asphyxie près de [[w:Pompéi|Pompéi]], lors de l’éruption du [[w:Vésuve|Vésuve]], en voulant observer le phénomène au plus près et en désirant porter secours aux victimes, alors en poste à [[w:Misène|''Misène'']] en tant que Préfet commandant la flotte militaire ''romaine'') <sup>[[w:Ier_siècle|⏳]]</sup> [[s:Auteur:Pline_l’Ancien|<sup>📚</sup>]] [https://books.google.fr/books?id=tRsuD3WJT-UC&newbks=1&newbks_redir=0&lpg=PA3&dq=bibliogroup%3A%22Dictionnaire%20des%20philosophes%20antiques%22&hl=fr&pg=PA876#v=onepage&q&f=true {{Info|<sup>🔍</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume Va, §204 - Plinius Secundus (Caius —)}}] <div style="text-align: justify; margin: 0 1em; text-indent: 15px">Haut fonctionnaire militaire et civique, issu de l’[[w:Chevalier_romain|''orde équestre'']], et écrivain prolifique dans de très nombreux domaines.</div> {{Boîte déroulante début|titre=NdA Pline l’Ancien|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Pline_back|<span id="Pline"><sup>I</sup></span>]] [[w:Nom_romain|Tria Nomina]] en latin {{Info|Caius|praenomen, nom individuel du citoyen romain}} {{Info|Plinius|nomen, nom de famille}} {{Info|Secundus|cognomen, surnom héréditaire, servant à distinguer les diverses branches d’une même gens}}'''<br/><br/></div> {{Boîte déroulante fin}} === [[w:Histoire_naturelle_(Pline_l'Ancien)|Histoire naturelle]] === <p style="text-align: right;">[[s:Histoire_naturelle_(Pline)|📚]] <div style="text-align: justify; margin: 0 1em; text-indent: 15px">Ouvrage de 37 livres dédié à l’empereur [[w:Titus_(empereur_romain)|'''Titus''']] [[#Titus|<span id="Titus_back"><sup>'''I'''</sup></span>]], dont il a été le ''{{Lang|la|contubernium}}'' pendant son service en tant que commandant des armées du ''Rhin'' en ''Germanie'' en [[w:47|47]]. '''Pline''' définit lui-même son enquête [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Histoire/Enquête_I|<sup>🔄</sup>]] sur la nature comme une reproduction de la vie — ''{{Lang|la|rerum natura, hoc est uita narratur}}'' (Livre I, Préface, 10), qu’il inscrit dans la tradition encyclopédique [[#encyclopédie_back|<sup>⤴️</sup>]] grecque mais s’en différencie par son exhaustivité : ''{{Lang|la|Jam omnia attingenda, quæ Græci}}'' ''{{Lang|grc|τάς έγχυχλοπαιδείας}}'' ''{{Lang|la|vocant : et tamen ignota aut incerta ingeniis facta; alia vero ita multis prodita, ut in fastidium sint adducta}}'' (Préface, 11). Il a, dans ce but, compilé « vingt mille faits dignes d’intérêt, tirés de la lecture d’environ deux mille volumes, [...] provenant de cent auteurs de choix » — ''{{Lang|la|Viginti millia rerum dignarum cura ex lectione voluminum circiter duum millium, [...] ex exquisitis auctoribus centum}}'' (Préface, 13).</div> {{Boîte déroulante début|titre=NdA Titus|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Titus_back|<span id="Titus"><sup>I</sup></span>]] Du nom propre latin Titus [[wikt:en:Titus#Latin|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;">Commandant militaire, notamment pendant la [[w:Premi%C3%A8re_guerre_jud%C3%A9o-romaine|''première guerre judéo-romaine'']], au cours de laquelle il prend ''Jérusalem'' que ses troupes mettent à sac et fait détruire le [[w:Second_temple_de_Jérusalem#Destruction|''Second Temple'']], et empereur ''romain'', de la dynastie des [[w:Flaviens|''Flaviens'']], de [[w:79|79]] à [[w:81|81]].<br /><p style="text-align: right; margin: 0 2em;">(30 décembre [[w:39|39]] , ''Rome'' — 13 septembre [[w:81|81]], mort par fièvre selon [[w:Suétone|Suétone]] [http://remacle.org/bloodwolf/historiens/suetone/titus.htm <sup>VdDC, Titus</sup>] ou par empoisonnement avec du venin de [[w:Aplysia|''lièvre marin'']] par son propre frère [[w:Domitien|Domitien]] selon [[w:Philostrate_d%27Ath%C3%A8nes|Philostrate]] [https://remacle.org/bloodwolf/roman/philiostrate/apollonius6.htm <sup>AdT, l. VI, chap. 32</sup>])<sup>[[w:Ier_siècle|⏳]]</sup>'''<br/><br/></div> {{Boîte déroulante fin}} ==== Livre II ==== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Enquête sur l’astronomie et la physique du monde, basée sur les quatre éléments : air, terre, eau et feu.</div> ===== <div style="text-align: center;">Chapitre IX.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage de la première prédiction grecque d’une éclipse solaire (ou lunaire selon les traductions) par '''Thalès'''.</div> :'''Texte latin''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''IX.''' Et rationem quidem defectus utriusque primus ''Romani'' generis in vulgus extulit '''Sulpicius Gallus''', qui consul cum '''Marcello''' fuit, sed tum tribunus militum, sollicitudine exercitu liberato, pridie quam '''Perseus''' rex superatus a '''Paulo''' est, in concionem ab imperatore productus ad prædicendam eclipsim, mox et composito volumine. Apud Græcos autem investigavit primus omnium '''Thales''' ''Milesius'', Olympiadis XLVIII anno quarto, prædicto solis defectu, qui '''Alyatte''' rege factus est, Urbis conditæ; anno CLXX. Post eos utriusque sideris cursum in sexcentos annos præcinuit '''Hipparchus''', menses gentium, diesque et horas, ac situs locorum, et visus populorum complexus, ævo teste, haud alio modo, quam consiliorum naturæ particeps. Viri ingentes supraque mortalium naturam, tantorum numinum lege deprehensa, et misera hominum mente absoluta, in defectibus scelera aut mortem aliquam siderum pavente (quo in metu fuisse '''Stesichori''' et '''Pindari''' vatum sublimia ora palam est deliquio Solis), et in Luna veneficia arguente mortalitate, et ob id crepitu dissono auxiliante. Quo pavore, ignarus causæ, '''Nicias''' ''Atheniensium'' imperator, veritus classem portu educere, opes eorum afflixit. Macti ingenio este, cæli interpretes, rerumque naturæ capaces, argumenti repertores, quo deos hominesque vinxistis. Quis enim hæc cernens, et statos siderum (quoniam ita placuit appellare) labores, non suæ necessitati mortalis genitus ignoscat ? Nunc confessa de iisdem breviter atque capitulatim attingam, ratione admodum necessariis locis strictimque reddita : nam neque instituti operis talis argumentatio est : neque omnium rerum afferri posse causas, minus mirum est, quam consfare in aliquibus.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/b24875958_0001/page/n7/mode/2up <u>Histoire Naturelle de Pline.</u>], [https://archive.org/details/b24875958_0001/page/98/mode/2up ''Livre II.''], [https://archive.org/details/b24875958_0001/page/106/mode/2up ''chap. IX.''], texte corrigé par [[w:Émile_Littré|M. É. Littré]], à partir de celui de [[w:Jean_Hardouin|Hardouin]], Librairie de Firmin-Didot et C<sup>ie</sup>, Paris, 1883<br />(également disponible une édition 1848 [[s:Page:Pline_l'ancien_-_Histoire_naturelle,_Littré,_T1_-_1848.djvu/130|ici]] et 1829 [https://gallica.bnf.fr/ark:/12148/bpt6k5773334c/f45.item là])</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''IX.''' Le premier ''Romain'' qui exposa publiquement la théorie des éclipses du soleil et de la lune est [[w:Caius_Sulpicius_Gallus|'''Sulpicius Gallus''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Caius_Sulpicius_Gallus_back|<sup>🔄</sup>]], qui fut consul avec [[w:Marcus_Claudius_Marcellus_(consul_en_-166)|'''Marcellus''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Marcellus-166_back|<sup>🔄</sup>]], mais qui alors était tribun militaire. La veille du jour où [[w:Persée_(roi)|'''Persée''']] [[#Persée_(roi)|<span id="Persée_(roi)_back"><sup>'''I'''</sup></span>]] fut défait par [[w:Lucius_Æmilius_Paullus_Macedonicus|'''Paul-Emile''']] [[#Lucius_Æmilius_Paullus_Macedonicus|<span id="Lucius_Æmilius_Paullus_Macedonicus_back"><sup>'''II'''</sup></span>]] il parut par ordre du général, afin de prévenir les alarmes de l’armée, devant les troupes assemblées pour annoncer l’éclipse qui allait survenir; peu de temps après, il composa un livre sur ce sujet. Le premier qui s’en occupa chez les ''Grecs'' fut '''Thalès''' de ''Milet'', dans la quatrième année de la quarante-huitième olympiade (an 585 av. J. C. [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#éclipse_back|<sup>🔄</sup>]]), l’an 170 de la fondation de ''Rome'', et prédit une éclipse de lune qui arriva sous le roi [[w:Alyatte_II|'''Alyatte''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Alyatte_back|<sup>🔄</sup>]]. Après eux, [[w:Hipparque_(astronome)|'''Hipparque''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Hipparque_back|<sup>🔄</sup>]] dressa pour six cents ans la table du cours du soleil et de la lune, déterminant les mois des divers calendriers, les jours, les heures, les localités et les aspects, suivant les contrées. Le cours des ans ne lui a donné aucun démenti, et il semble avoir été admis aux conseils de la nature. Génies puissants et élevés au dessus de l’humanité, ils ont découvert la loi qui régit ces grandes divinités, et ils ont délivré de ses craintes l’esprit misérable des hommes, qui dans les éclipses, tantôt croyaient voir une influence malfaisante ou une espèce de mort des astres, crainte qui, comme on sait, a, pour l’éclipse du soleil, troublé [[w:Stésichore|'''Stésichore''']] [[#Stésichore|<span id="Stésichore_back"><sup>'''III'''</sup></span>]] et [[w:Pindare|'''Pindare''']] [[#Pindare|<span id="Pindare_back"><sup>'''IV'''</sup></span>]], poètes sublimes, et tantôt attribuaient l’obscurcissement de la lune à des maléfices, et lui venaient en aide par un bruit dissonnant. Redoutant ce phénomène, dont il ignorait la cause, [[w:Nicias|'''Nicias''']] [[#Nicias|<span id="Nicias_back"><sup>'''V'''</sup></span>]], général des ''Athéniens'', n’osa pas faire sortir la flotte du port de [[w:Syracuse#Antiquité|''Syracuse'']], et ruina la puissance de sa patrie. Redoublez de génie, interprètes du ciel, vous dont l’intelligence, embrassant la nature, a inventé des théories qui ont créé un lien entre les dieux et les hommes [[#Vicistis_JH|<span id="Vicistis_JH_back"><sup>'''1'''</sup></span>]] ! A la vue de ce spectacle, à la vue des labeurs (puisque c’est le nom qu’on a voulu donner aux éclipses), des labeurs réguliers auxquels les astres sont soumis, quel mortel ne pardonnerait à la nécessité sous laquelle il est né ? Maintenant je vais parler, d’une manière brève et sommaire, des points sur lesquels on est d’accord en cette matière. Je ne donnerai que de courtes explications, et là où il sera tout à fait nécessaire; car les explications n’entrent pas dans le plan de cet ouvrage, et il n’y a pas moins de mérite à énumérer les causes de toutes choses qu’à s’appesantir sur quelques-unes.</div> <table cellspacing=15 align=center style="margin: 0 4em; font-size:85%;"> <tr> <td style="text-align: justify; margin: 0 4em;">'''[[#Vicistis_JH_back|<span id="Vicistis_JH"><sup>1</sup></span>]] Vicistis Vulg. — Vinxistis cod. Dalech. — Vinxistis me parait meilleur. Comp. ce que dit Pline plus loin, ch. 24, sur l’affinité de l’esprit humain avec les astres.'''</td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/b24875958_0001/page/n7/mode/2up <u>Histoire Naturelle de Pline.</u>], [https://archive.org/details/b24875958_0001/page/98/mode/2up ''Livre II.''], [https://archive.org/details/b24875958_0001/page/106/mode/2up ''chap. IX.''], texte corrigé par [[w:Émile_Littré|M. É. Littré]], à partir de celui de [[w:Jean_Hardouin|Hardouin]], Librairie de Firmin-Didot et C<sup>ie</sup>, Paris, 1883<br />(édition 1848 également disponible [[s:Page:Pline_l'ancien_-_Histoire_naturelle,_Littré,_T1_-_1848.djvu/130|ici]])</div> {{Boîte déroulante début|titre=NdA de trad. Jean Hardouin 1883|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Persée_(roi)_back|<span id="Persée_(roi)"><sup>I</sup></span>]] Du nom propre grec ancien Περσεύς / Perseús[[wikt:en:Περσεύς#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px">Dernier roi de [[w:Royaume_de_Mac%C3%A9doine|''Macédoine'']] de la dynastie des [[w:Antigonides|''Antigonides'']], vaincu en [[w:-168|-168]] à la [[w:bataille de Pydna|bataille de ''Pydna'']] à l’issue de la [[w:troisième guerre macédonienne|''troisième guerre macédonienne'']], causant la disparition du ''Royaume de Macédoine''.<br /><p style="text-align: right; margin: 0 2em;">([[w:Années_212_av._J.-C.|-212]]<sup>[[w:IIIe_siècle_av._J.-C.|⏳]]</sup>, [[w:Pella_(cité_antique)|''Pella'']], au nord de l’actuelle ''Grèce'' — [[w:Années_166_av._J.-C.|-166]]<sup>[[w:IIe_siècle_av._J.-C.|⏳]]</sup>, [[w:Alba_Fucens|''Alba Fucens'']], au centre de l’actuelle ''Italie'') <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Lucius_Æmilius_Paullus_Macedonicus_back|<span id="Lucius_Æmilius_Paullus_Macedonicus"><sup>II</sup></span>]] [[w:Nom_romain|Tria Nomina]] en latin {{Info|Lucius|praenomen, nom individuel du citoyen romain}} {{Info|Æmilius|nomen, nom de famille}} {{Info|Paullus|cognomen, surnom héréditaire, servant à distinguer les diverses branches d’une même gens}}, surnommé [[wikt:Macedonicus#Latin|Macedonicus]] par le [[w:Sénat_romain|''Sénat'']] à la suite de sa victoire;<br /><p style="margin: 0 2em; text-indent: 15px">Homme politique ''romain'', consul à 2 reprises en [[w:Années_182_av._J.-C.|-182]] et [[w:Années_169_av._J.-C.|-169]]. Il remporta la victoire contre le ''royaume de Macédoine'' à ''Pydna'' en battant le roi Persée [[#Persée_(roi)|<sup>I</sup>]], ce qui mit fin à la dynastie des ''Antigonides''.<br /><p style="text-align: right; margin: 0 2em;">([[w:Circa|{{Info|''ca.''|Circa, locution latine que l’on emploie pour indiquer l’approximation d’une date}}]] [[w:Années_230_av._J.-C.|-230]]<sup>[[w:IIIe_siècle_av._J.-C.|⏳]]</sup>, ''Rome'' — ''ca.'' [[w:Années_160_av._J.-C.|-160]]<sup>[[w:IIe_siècle_av._J.-C.|⏳]]</sup>, ''Rome'') <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Stésichore_back|<span id="Stésichore"><sup>III</sup></span>]] Du nom propre grec ancien Στησίχορος /Stēsíkhoros [[wikt:en:Στησίχορος#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;">➥ du verbe ἵστημι /hístēmi, « 1. (voix transitive, active des temps présent, imparfait, futur et 1er aoriste) : • Faire se tenir debout, se tenir debout; • Arrêter, rester, vérifier; • Mettre en place : - Faire monter, élever, réveiller, remuer; - Nommer, désigner; - Établir, instituer; • Mettre dans la balance, peser. 2. (voix intransitive, moyenne et passive, voix active du 2e aoriste, parfait et plus-que-parfait) : • Se tenir debout; • Se tenir immobile : (au sens figuré) Rester ferme; • Être dressé ou debout, se lever, s’élever : - (en général) Se lever, commencer; - (en marquant le pas) Être; - Être désigné. »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ +‎ du nom commun χορός / khorós, « 1. Danse en rond. 2. Danse accompagnée de chant, danse chorale. 3. Chœur, chorale, groupe de chanteurs et de danseurs. 4. Groupe, troupe. 5. Rangée. 6. Lieu de danse. 7. (théâtre) Chœur »;<br /><p style="margin: 0 2em; text-indent: 15px">Poète lyrique grec, considéré comme l’un des [[w:Neuf_lyriques_grecs|''neuf poètes lyriques'']] de la Grèce antique.<br /><p style="text-align: right; margin: 0 2em;">([[w:Circa|{{Info|''ca.''|Circa, locution latine que l’on emploie pour indiquer l’approximation d’une date}}]] [[w:Années_630_av._J.-C.|-630]]<sup>[[w:VIIe_siècle_av._J.-C.|⏳]]</sup>, [[w:Metauria|''Metauria'']], colonie de la [[w:Grande-Grèce|''Grande-Grèce'']], au sud de la région de [[w:Calabre|''Calabre'']], au sud de l’Italie — ''ca.'' [[w:Années_555_av._J.-C.|-555]]<sup>[[w:VIe_siècle_av._J.-C.|⏳]]</sup>, [[w:Catane|''Catane'']], colonie de la ''Grande-Grèce'', à l’est de la [[w:Sicile|''Sicile'']]) <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Pindare_back|<span id="Pindare"><sup>IV</sup></span>]] Du nom propre grec ancien Πίνδᾰρος /Píndaros [[wikt:en:Πίνδαρος#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px">Poète lyrique grec, considéré comme l’un des [[w:Neuf_lyriques_grecs|''neuf poètes lyriques'']] de la Grèce antique.<br /><p style="text-align: right; margin: 0 2em;">([[w:Années_518_av._J.-C.|-518]]<sup>[[w:VIe_siècle_av._J.-C.|⏳]]</sup>, [[w:Cynocéphales|''Cynocéphales'']], cité grecque située près de [[w:Thèbes_(Grèce)|''Thèbes'']], en [[w:Béotie|''Béotie'']] — [[w:Années_438_av._J.-C.|-438]]<sup>[[w:Ve_siècle_av._J.-C.|⏳]]</sup>, [[w:Árgos|''Árgos'']], cité grecque de la région de l’[[w:Argolide|''Argolide'']], à l’est de la [[w:Péloponnèse|''péninsule du Péloponnèse'']]) <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Nicias_back|<span id="Nicias"><sup>V</sup></span>]] Du nom propre grec ancien Νῑκίᾱς /Nīkíās [[wikt:en:Νικίας#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;">➥ du nom commun νίκη / níkē [[wikt:en:νίκη#Ancient_Greek|(en)]], « 1. Le fait de gagner : la victoire, le succès [avec le génitif "sur, dans quelque chose"] : • Les choses gagnées dans la victoire, les fruits de la victoire; • La supériorité, l’avantage. »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ + du suffixe nominal masculin -ίας / -ías [[wikt:en:-ίας#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px">Homme politique et général ''athénien'' durant la [[w:Guerre_du_Péloponnèse|''guerre du Péloponnèse'']], qui oppose la [[w:Ligue_de_Délos|''ligue de Délos'']], menée par ''Athènes'', et la [[w:Ligue_du_Péloponnèse|''ligue du Péloponnèse'']], sous l’[[w:Hégémonie|hégémonie]] de ''Sparte'' de [[w:Années_431_av._J.-C.|-431]] à [[w:Années_404_av._J.-C.|-404]]. Sa supersition liée à une éclipse lunaire, s’étant produite lors de l’[[w:Expédition_de_Sicile|''expédition de Sicile'']], est également relatée par [[w:Thucydide|Thucydide]] [http://remacle.org/bloodwolf/historiens/thucydide/livre7.htm#L <sup>{{Info|HdlgdP|Histoire de la guerre du Péloponnèse}} l.VII, §.L</sup>] et [[w:Plutarque|Plutarque]] [[#Plutarque_back|<sup>⤵️</sup>]] [http://remacle.org/bloodwolf/historiens/Plutarque/supestition.htm#23 <sup>{{Info|DlS|De la Superstition}} l.I</sup>].<br /><p style="text-align: right; margin: 0 2em;">([[w:Circa|{{Info|''ca.''|Circa, locution latine que l’on emploie pour indiquer l’approximation d’une date}}]] [[w:Années_470_av._J.-C.|-470]], ''Athènes'' — ''ca.'' [[w:Années_413_av._J.-C.|-413]], ''Syracuse'')<sup>[[w:Ve_siècle_av._J.-C.|⏳]]</sup>'''<br/><br/></div> {{Boîte déroulante fin}} <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: center; margin: 0 2em;">Des découvertes astronomiques : part de chaque observateur dans la science.<br /><p style="text-align: justify; text-indent: 15px;">'''IX.''' '''Sulpicius Gallus''' [[#Sulpicius_Gallus_AdG|<span id="Sulpicius_Gallus_AdG_back"><sup>'''1'''</sup></span>]] fut le premier ''Romain'' qui expliqua au vulgaire la raison des éclipses de soleil et de lune. Il fut consul avec '''Marcus Marcellus''' ; mais il n’était que tribun militaire lorsque la veille de la victoire que '''Paul Emile''' remporta sur '''Persée''' [[#Pridie_quam_Perses_rex_AdG|<span id="Pridie_quam_Perses_rex_AdG_back"><sup>'''2'''</sup></span>]], son général le fit paraître devant l’armée assemblée, pour lui annoncer l’éclipse qui allait arriver, et la délivrer de l’alarme qu’elle aurait pu en concevoir. Il composa bientôt après un volume sur ce sujet. Parmi les ''Grecs'', '''Thalès''' de ''Milet'' [[#Primus_omnium_Thales_AdG|<span id="Primus_omnium_Thales_AdG_back"><sup>'''3'''</sup></span>]] dirigea le premier ses recherches sur ce phénomène, et la quatrième année de la 48e olympiade, qui répond à l’an 170 [[#Anno_CLXX_AdG|<span id="Anno_CLXX_AdG_back"><sup>'''4'''</sup></span>]] de ''Rome'', il prédit l’éclipse de soleil qui eut lieu sous le règne d’'''Alyatte''' [[#Alyatte_rege_AdG|<span id="Alyatte_rege_AdG_back"><sup>'''5'''</sup></span>]]. Après eux, '''Hipparque''' dressa des tables du cours de ces deux astres pour six cents ans [[#In_sexcentos_annos_AdG|<span id="In_sexcentos_annos_AdG_back"><sup>'''6'''</sup></span>]] : mois, heures, jours, situations respectives des lieux, aspects du ciel selon les diverses nations [[#Menses_gentium_etc_AdG|<span id="Menses_gentium_etc_AdG_back"><sup>'''7'''</sup></span>]], tout y est compris, tout a été vérifié par le temps [[#Aevo_teste_AdG|<span id="Aevo_teste_AdG_back"><sup>'''8'''</sup></span>]]; on croirait l’astronome admis au conseil de la nature. Génies vastes et plus qu’humains, d’avoir ainsi surpris la loi de ces deux grandes divinités [[#Numinum_AdG|<span id="Numinum_AdG_back"><sup>'''9'''</sup></span>]], et affranchi d’effroi la malheureuse espèce humaine, qui tremblait en voyant dans chaque éclipse l’annonce de quelque grand crime, ou craignait la mort des astres [[#In_defectibus_scelera_etc_AdG|<span id="In_defectibus_scelera_etc_AdG_back"><sup>'''10'''</sup></span>]] (effroi dont '''Stésichore''' et '''Pindare''' [[#Pindari_AdG|<span id="Pindari_AdG_back"><sup>'''11'''</sup></span>]], ces poètes sublimes, ne furent point exempts dans les éclipses de soleil), ou qui attribuait à des enchantemens celles de la lune, et venait à son secours en faisant un bruit discordant [[#Crepitu_dissono_AdG|<span id="Crepitu_dissono_AdG_back"><sup>'''12'''</sup></span>]]. C’est pour en avoir ignoré la cause, que, frappé de cette même terreur, '''Nicias''' [[#Nicias_AdG|<span id="Nicias_AdG_back"><sup>'''13'''</sup></span>]], général des ''Athéniens'', n’osa pas faire sortir sa flotte du port, et causa la ruine de leur puissance. Gloire à vous, interprètes du ciel, génies aussi étendus que la nature, inventeurs d’une science qui enchaîne à une même destinée les dieux et les mortels ! Quel est donc l’homme qui, voyant les astres en travail (pour me servir du nom qu’il a plu de donner aux crises qu’ils, subissent périodiquement), ne se soumettra pas à sa destinée?<br /><p style="text-align: justify; text-indent: 15px;">Je vais maintenant toucher brièvement et sommairement les points sur lesquels on est d’accord dans cette matière, et j’en rendrai raison en passant, lorsque cela sera tout-à-fait nécessaire; car un développement de preuves n’est pas le but de l’ouvrage que j’ai entrepris, et il n’y a pas, je pense, moins de mérite à pouvoir rendre raison de toutes choses, qu’à s’arrêter à en prouver quelques-unes.</div> {{Boîte déroulante début|titre=Notes du traducteur|alignT=center}} <div style="text-align: justify; border: 2px; border-radius:15px; font-size:85%;"><br/> <table cellspacing=15 align=center style="margin: 0 4em;"> <tr> <td style="text-align: justify; margin: 0 4em; text-indent: 15px">'''[[#Sulpicius_Gallus_AdG_back|<span id="Sulpicius_Gallus_AdG"><sup>1</sup></span>]] [[w:Tite-Live|Tite-Live]], XLIV, 37, [[w:Quintilien|Quintilien]], I, 10, [[w:Plutarque|Plutarque]] [[#Plutarque_back|<sup>⤵️</sup>]], [[w:Vies_parallèles|''Vie de Paul Emile'']], [[w:Frontin|Frontin]], I, etc., prétendent, comme Pline, que Sulpicius Gallus prédit l’éclipse anx soldats romains. [[w:Cicéron|'''Cicéron''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Cicéron_back|<sup>🔄</sup>]] ([[w:De_Republica|''Répub.'']], I, 15 , page 44, ''édit. Maj.'') dit au contraire que l’éclipse était déjà arrivée lorsque Sulpicius Gailus commençait à s’efforcer d’ôter aux soldats romains la terreur qu’ils avaient conçue de cet événement, en leur expliquant les causes des éclipses.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Pridie_quam_Perses_rex_AdG_back|<span id="Pridie_quam_Perses_rex_AdG"><sup>2</sup></span>]] Selon Tite-Live (XLIV, 37), l’éclipse eut lieu dans la soirée du 3 septembre, cent huit ans avant J.-C., entre sept et dix heures (''ab hora secunda usque ad quartam noctis, quam pridie nonas sept, secula est dies''). M. [[w:Christian_Ludwig_Ideler|Ideler]] (''Chronologie'', II, 104) a calculé cette éclipse. Il a trouvé, comme M. de Nauze, que, selon le calendrier Julien, elle arriva dans la soirée du 21 juin de l’an 168 avant J.-C. à Rome, la lune commença à s’éclipser vers 5h.44’ du soir ; depuis 6h.51’ jusqu’à 8h.18’, la lune fut totalement éclipsée, ; à 9h.,24’, la lune ne fut plus obscurcie du tout. En Macédoine, tous ces phénomènes arrivèrent 39 minutes plus tard. Le 21 juin, le soleil se coucha à Rome et en Macédoine vers 7h.33’, et s’y montra alors à 44 1/2’ h. équatoriales. Ainsi, la première heure de la nuit finissait vers 8h.17’, la seconde vers 9h.2’, la troisième vers 9h.46’, la quatrième vers 10h.31’. La lune fut donc éclipsée totalement au moment où elle se leva dans la Macédoine, et cette éclipse totale y finit dans la seconde heure de la nuit ; au milieu de la quatrième, la lune ne fut plus obscurcie du tout. S’il est vrai, que cette éclipse lunaire, comme Pline, Tite-Live et d’autres le disent, fut prédite par Sulpicius Gallus, l’on devrait avouer que ce Romain s’entendait très-bien au calcul des éclipses lunaires. Mais les récits de Cicéron et de [[w:Valère_Maxime|Valère-Maxime]] ne seraient-ils pas plus vrais que ceux de Pline et de Tite-Live ?''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Primus_omnium_Thales_AdG_back|<span id="Primus_omnium_Thales_AdG"><sup>3</sup></span>]] Le même fait est rapporté par [[w:Hérodote|Hérodote]] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Hérodote_back|<sup>🔄</sup>]], I, 74, par [[w:Diogène_Laërce|Diogène Laërce]] [[#Diogène_Laërce_back|<sup>⤵️</sup>]], I, 6 , par [[w:Clément_d'Alexandrie|Clément d’Alexandrie]] [[#Clément_d'Alexandrie_back|<sup>⤵️</sup>]], ''Strom.'', I, page 302 , par Plutarque, ''Opinions des Philosophes'', II, 24, par [[w:Jean_Tzétzès|Tzetzès]], ''Chil.'' II, v. 869, et par Hardouin.<br /><p style="text-align: justify; text-indent: 15px;">Oltmann a publié une dissertation dans laquelle, à l’aide des tables astronomiques les plus modernes, il est arrivé à ce résultat, que l’éclipse solaire dont il est question ici eut lieu le 3o septembre 610 ans avant J.-C. L’éclipse était totale pour les environs de la ville d’[[w:Erzurum|Érzerum]] sur le [[w:Kızılırmak_(fleuve)|Halys]] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Halys_back|<sup>🔄</sup>]], où [[w:Volney|Volney]] place le champ de bataille des rois [[w:Alyatte_II|Halyattes]] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Alyatte_back|<sup>🔄</sup>]] et [[w:Cyaxare|Cyaxare]] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Cyaxare_back|<sup>🔄</sup>]]. La quatre-vingtième partie du disque solaire seule ne fut pas éclipsée pour le lieu de la terre où Oltmann place le champ de bataille, qui est situé, selon lui, sous 36° long. à l’est de Terro et sous 40° lat. sept. Dans le pays des Ioniens où Thalès prédit l’éclipse, selon Hérodote, l’éclipse se monta à 11 1/2’. M. [[w:Alphonse_Des_Vignoles|Desvignolles]] (''Chronologie de l’histoire sainte'', t. II, pag. 245 et suiv.) fixe l’éclipsé prédite par Thales au 38 mai de l’an 585 avant J.-C. ; son opinion a été adoptée depuis par presque tous les chronologistes et historiens, et par [[w:Gabriel_Brotier|Brotier]] et M. Alexandre. Elle a été réfutée avec succès par Oltmann, qui s’est servi de tables astronomiques bien plus exactes que celles de M. Desvignolles ; en effet, celui-ci a démontré par ses calculs que l’éclipse totale du soleil du 28 mai de l’an 585 avant J.-C., ne fut pas totale dans les lieux où les troupes du roi lydien Halyatte combattirent contre celles du roi Cyaxare ; que, dans ces régions, elle ne se monta pas à plus de 7 1/2 pouces, et que, d’ailleurs, le soleil ne s’était pas encore levé lorsque Féclipse était le plus forte pour les habitans des pays nommés. Mais Hérodote dit positivement que l’éclipse prédite par Thalès fut totale dans ces contrées, et qu’elle eut lieu en plein jour. (Voyez IDELER, ''Chronologie'', t. I, pag. 209 et 210.) Nous remarquerons pourtant avant de finir cette note que la date de Desvignolles est plus conforme que celle d’Oltmann à l’année dans laquelle l’éclipse prédite par Thalès, arriva selon Pline. En effet, le naturaliste romain dit que cette année est la six cent quatre-vingt-cinquième avant J.—C., et c’est justement le 28 mai de cette année que l’éclipse prédite par Thalès arriva, selon M. Desvignolles.<br /><p style="text-align: justify; text-indent: 15px;">Volney pense que l’éclipse en question arriva le 3 février de de l’an 626. Oltman a démontré, dans son Mémoire sur l’éclipse de Thalès, que celle de Volney était déjà passée lorsque le soleil se leva sur le champ de bataille des rois Halyattes et Cyaxare.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Anno_CLXX_AdG_back|<span id="Anno_CLXX_AdG"><sup>4</sup></span>]] L’an 170. C’est ainsi que l’on doit lire, et non CLX, comme l’ont fait Hardouin et Poinsinet; la quatrième année de la quarante-huitième olympiade, correspondant à l’an 170 de Rome, si l’on suppose avec [[w:Varron_(écrivain)|Varron]] que cette ville a été fondée dans la deuxième année de la 6e olympiade.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Alyatte_rege_AdG_back|<span id="Alyatte_rege_AdG"><sup>5</sup></span>]] Le nom de ce roi est écrit avec un esprit rude dans Hérodote, ce qui a donné lieu à [[w:Louis_Poinsinet_de_Sivry|Poinsinet]] et à d’autres traducteurs de Pline de substituer le mot Halyatte à celui d’Alyatte.<br /><p style="text-align: justify; text-indent: 15px;">Alyatte ou Halyatte fut roi de la Lydie et père de Crésus. Il faisait la guerre à Cyaxare, roi des Mèdes, lorsque l’éclipse solaire en question interrompit le combat.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#In_sexcentos_annos_AdG_back|<span id="In_sexcentos_annos_AdG"><sup>6</sup></span>]] On lit dans [[w:Georges_le_Syncelle|le Syncelle]] (''Chronolog.'', pag. 17) que les Chaldéens ont connu une période de six cents années solaires. [[w:Flavius_Josèphe|Josèphe]] [[#Flavius_Josèphe_back|<sup>⤵️</sup>]] ([[w:Antiquités_judaïques|''Ant. jud.'']], I, page 17 et 18, édit. Havercamp) dit que Dieu donna une longue vie aux patriarches pour qu’ils pussent cultiver avec succès les sciences astronomiques et géométriques, ce qu’ils n’auraient pu faire s’ils n’avaient pas vécu au moins six cents ans ; car la grande année ne finit pas plus tôt. Ainsi, il est certain qu’avant Hipparque les Chaldéens et d’autres peuples asiatiques ont connu une période de six cents années solaires. Mais [[w:Jean-Dominique_Cassini|Cassini]] ([[w:Jean-Dominique_Cassini#Mémoires_de_l’Académie_royale_des_sciences|''Anciens mém. de l’Acad.'']], t. VIII, pag. 4 et 5) et [[w:Jean_Sylvain_Bailly|Bailly]] (''Hist. de l’astr. ancienne'', t. II, liv. 3, Eclairciss.) ont prouvé que tous les six cents ans les nouvelles et pleines lunes n’arrivent pas seulement au même jour et à la même heure qu’auparavant, mais encore à la même minute. Ne serait-il donc pas probable qu’Hipparque, comme le dit Ideler (''Historische untersuchungen uber die astronomischen beobachtungen der alten'', Berlin 1806, page 417) a connu cette période chaldéenne, et que delà résulte l’étendue de six cents ans donnée à son calendrier selon Pline.<br /><p style="text-align: justify; text-indent: 15px;">[[w:Abel_Burja|Abel-Burja]] de Leipzig a tâché d’expliquer d’une autre manière la durée du calendrier d’Hipparque (''Astronomisches Jahrbuch'', 1797, pag. 233 et 234). [[w:Claude_Ptolémée|Ptolémée]] et [[w:Censorin_(grammairien)|Censorin]] racontent qu’Hipparque est auteur d’une période soli-lunaire de trois cent quatre années solaires. En la prenant deux fois, on obtient une période de six cent huit ans. Celle-ci fut abrégée par Hipparque de huit ans, afin d’obtenir un nombre entier de siècles pour son calendrier. Ideler a fait une objection très-juste contre cette opinion de Burja ; c’est que la période de six cent huit ans n’a aucun avantage sur celle de trois cent quatre ans. On ne voit donc pas ce qui a pu engager Hipparque à préférer le nombre de six cents ans à celui de trois cents, lorsqu’il composait son calendrier.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Menses_gentium_etc_AdG_back|<span id="Menses_gentium_etc_AdG"><sup>7</sup></span>]] C’est-à-dire il écrivit des éphémérides dans lesquelles il avait calculé d’avance les néomenies et les pleines lunes. Il fit aussi entrer dans son calendrier les longueurs des jours et des heures variables, [[w:ὧραι|ὧραι]] καιρικαι, ainsi que les aspects du ciel, ''visus populorum'', tels qu’ils eurent lieu chez les habitans de différentes contrées de la terre. Il ajouta une table des longitudes et des latitudes des principaux pays et villes du globe. Ptolémée (''Géogr.'', I, ch. 4) en dit autant d’Hipparque.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Aevo_teste_AdG_back|<span id="Aevo_teste_AdG"><sup>8</sup></span>]] Les tables d’Hipparque étaient dressées pour six cents ans. Cet astronome florissait vers cent cinquante ans avant J.-C. Ainsi, du temps de Pline, on avait encore à jouir de ces tables pour quatre cents ans environ. POINSINET.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Numinum_AdG_back|<span id="Numinum_AdG"><sup>9</sup></span>]] Pline donne souvent l’épithète de divinités aux planètes, à la lune, au soleil, à la terre et aux étoiles fixes.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#In_defectibus_scelera_etc_AdG_back|<span id="In_defectibus_scelera_etc_AdG"><sup>10</sup></span>]] Nous transcrivons ici ce beau passage de l’Uranographie de M. [[w:Louis-Benjamin_Francœur|Francoeur]], qui mérite d’être mis en parallèle avec celui de Pline pour l’élégance du style et les pensées, et qui renferme le meilleur commentaire que nous puissions donner de tout ce que Pline dit des terreurs que les éclipses causaient autrefois aux hommes ignorans. « L’histoire, dit M. Francoeur (page 93), est pleine des exemples de l’effroi causé par les éclipses, et des dangers que produisent l’ignorance et la superstition. Nicias avait résolu de quitter la Sicile avec son armée ; effrayé par une éclipse de lune, et voulant temporiser plusieurs jours pour s’assurer si l’astre n’avait rien perdu après cet évènenement, il manqua ainsi l’occasion de sa retraite; son armée fut détruite ; Nicias périt, et ce malheur commença la ruine d’Athènes.<br /><p style="text-align: justify; text-indent: 15px;">« Souvent on a vu des hommes adroits tirer parti de la frayeur du peuple pour l’amener à remplir leurs desseins. Christophe Colomb, réduit à faire subsister ses soldats des dons volontaires d’une nation sauvage et indigente, était prêt à voir tarir cette ressource et à périr de faim ; il annonce qu’il va priver le monde de la lumière de la lune. L’éclipse commence et la terreur s’empare des Indiens, qui reviennent apporter aux pieds de Colomb les tributs accoutumés.<br /><p style="text-align: justify; text-indent: 15px;">« Drusus (TACITE , Annales, I, 28) apaisa une sédition dans son armée, en prédisant une éclipse de lune, et, selon Tite-Live, Sulpicius Gallus, dans la guerre de Paul-Emile contre Persée, usa du même stratagème. Periclès, [[w:Agathocle_de_Syracuse|Agathocles de Syracuse]], [[w:Dion_de_Syracuse|Dion]], roi de Sicile, ont failli être victimes de l’ignorance de leurs soldats. [[w:Alexandre_le_Grand|Alexandre]], près d’[[w:Bataille_de_Gaugamèles|Arbelles]], est réduit à user de toute son adresse pour calmer la terreur qu’une éclipse avait jetée parmi ses troupes. Les hommes supérieurs, plutôt que de plier sous les circonstances qui les maîtrisent, mettent leur art à les tourner à leur profit.<br /><p style="text-align: justify; text-indent: 15px;">« Combien de fables établies d’après l’opinion que les éclipses sont l’effet du courroux céleste qui se venge des iniquités de l’homme en le privant de la lumière! Tantôt [[w:Diane_(mythologie)|Diane]] va trouver [[w:Endymion|Endymion]] dans les montagnes de Carie; tantôt les magiciennes de Thessalie font descendre la lune sur les herbes qu’elles destinent aux enchantemens. »<br /><br /><p style="text-align: center;">''Carmina vel cælo possunt deducere lunam.''<br /><p style="text-align: right; text-indent: 15px;">Virg., ''Eclog.'' VIII.<br /><br /><p style="text-align: justify; text-indent: 15px;">« Ici c’est un dragon qui dévore l’astre, et qu’on cherche à épouvanter par des cris ; le dieu tient le soleil enfermé dans un tuyau, et nous ôte ou nous rend la vue de cet astre à l’aide d’un volet, etc. Les progrès des sciences ont fait connaître le ridicule de ces opinions et de ces craintes, depuis qu’on a vu qu’il était possible de calculer par les tables astronomiques, et de prévoir long-temps d’avance l’instant où la colère du ciel devait éclater.<br /><p style="text-align: justify; text-indent: 15px;">« Cependant, naguère encore, l’épouvante a causé les revers des armées de Louis XIV, près de Barcelone, lors de l’éclipse totale de l’an 1706 [[w:en:Solar_eclipse_of_May_12,_1706|(en)]], et la devise, ''nec pluribus impar'', a prêté aux allusions injurieuses ! »''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Pindari_AdG_back|<span id="Pindari_AdG"><sup>11</sup></span>]] Pindare était le plus fameux poète de la Grèce après Homère. Il vint au monde l’an 134 avant l’ère chrétienne. POINSINET.<br /><p style="text-align: justify; text-indent: 15px;">Plutarque (''De la face de la lune'', pag. 931) dit aussi que Stésichore et Pindare craignaient beaucoup les éclipses. Le dernier poète a peint les terreurs que lui causaient ces phénomènes dans son poëme sur le soleil. HARDOUIN et DALECHAMP.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Crepitu_dissono_AdG_back|<span id="Crepitu_dissono_AdG"><sup>12</sup></span>]] Cet usage superstitieux dont Plutarque parle au long dans sa vie de Paul-Émile, a fourni un vers fort plaisant à Juvénal, lorsqu’après avoir épuisé toute sorte d’exagération pour représenter le bruit qu’une femme fait en criant, il finit par dire :<br /><br /><p style="text-align: center;">''Una laboranti poterit succurrere lunæ.''<br /><br /><p style="text-align: justify; text-indent: 15px;">« Elle seule, au besoin, décharmerait la lune. » POINSINET.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Nicias_AdG_back|<span id="Nicias_AdG"><sup>13</sup></span>]] Le même fait est raconté par Plutarque dans la vie de Nicias, par Quintilien, I, 10, et par d’autres écrivains anciens. HARDOUIN.''' </td> </tr> </table><br/><br/></div>{{Boîte déroulante fin}} <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k5773334c/f10.item <u>Histoire Naturelle de Pline. Tome Second</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k5773334c/f14.item ''Livre II.''], [https://gallica.bnf.fr/ark:/12148/bpt6k5773334c/f46.item ''chap. IX.''], traduction nouvelle par M. [[w:Stéphane_Ajasson_de_Grandsagne|Ajasson de Grandsagne]] [https://gallica.bnf.fr/ark:/12148/bpt6k5773334c/f311.item <sup>NOTES</sup>], C. L. F. Panckoucke, Paris, 1829</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: center; margin: 0 2em;">''Des inventions a[[w:S_long|{{Info|ſ|forme ancienne longue de la lettre s minuscule}}]]<nowiki />tronomiques, & de leurs Auteurs.''<br /><p style="text-align: justify; text-indent: 15px;">'''L'''E PREMIER d’entre les ''Romains'' qui rendit publique la théorie des éclip{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oleil & de lune, fut '''Sulpicius Gallus''' [[#Sulpicius_Gallus_LPdS|<span id="Sulpicius_Gallus_LPdS_back"><sup>'''1'''</sup></span>]], celui que '''Marcus Marcellus''' eut pour Collegue au Con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ulat : mais il n’étoit que Tribun Militaire [[#Tribun_Militaire_LPdS|<span id="Tribun_Militaire_LPdS_back"><sup>'''2'''</sup></span>]], lor{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’il di{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ipa l’allarme qu’auroient pu prendre nos troupes la veille de la victoire remportée {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur '''Per{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ée''' par '''Paul Emile''' ; car ce Général l’ayant produit devant les {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oldats a{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}emblés, il leur prédit une éclip{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e qui devoit arriver [[#éclipse_LPdS|<span id="éclipse_LPdS_back"><sup>'''3'''</sup></span>]] ; il compo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}a même en{{Info|ſ|forme ancienne longue de la lettre s minuscule}}uite un Ouvrage {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur ce {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ujet. Parmi les ''Grecs'', '''Thalès''' de ''Milet'' prédit l’an quatrieme de la quarante-huitieme olympiade l’éclip{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oleil qui arriva {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous le regne de '''Halyattes''' [[#Halyattes_LPdS|<span id="Halyattes_LPdS_back"><sup>'''4'''</sup></span>]], l’an cent {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oixante de la fondation de [[#cent_soixante_LPdS|<span id="cent_soixante_LPdS_back"><sup>'''5'''</sup></span>]] ''Rome''. Après eux, Hipparque [[#Hipparque_LPdS|<span id="Hipparque_LPdS_back"><sup>'''6'''</sup></span>]] dre{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}a des Tables en vers [[#En_vers_LPdS|<span id="En_vers_LPdS_back"><sup>'''7'''</sup></span>]] du cours de ces deux aftres pour fix cents ans. Dans ces Tables , de l’exactitude deſquelles notre âge rend encore témoignage [[#témoignage_LPdS|<span id="témoignage_LPdS_back"><sup>'''8'''</sup></span>]], il embra{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}e les éphémérides propres à chaque nation [[#chaque_nation_LPdS|<span id="chaque_nation_LPdS_back"><sup>'''9'''</sup></span>]], les jours, les heures, le {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ite re{{Info|ſ|forme ancienne longue de la lettre s minuscule}}pectif de chaque lieu, & les divers a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}pects du ciel relativement aux divers peuples, comme {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i la Nature l’eût admis à {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}eil intime. Per{{Info|ſ|forme ancienne longue de la lettre s minuscule}}onnages vraiment grands! génies plus qu’humains, d’avoir ain{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i {{Info|ſ|forme ancienne longue de la lettre s minuscule}}urpris les loix qui font mouvoir ces va{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tes pui{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ances du ciel ; & d’avoir guéri de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}es allarmes l’imagination malade des hommes, qui ju{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’alors, ou avoient toujours vu dans les éclip{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es l’annonce effrayante de quelque grand crime & de quelque mort (terreur dont Sté{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ikhore [[#Stésikhore_LPdS|<span id="Stésikhore_LPdS_back"><sup>'''10'''</sup></span>]] & Pindare [[#Pindare_LPdS|<span id="Pindare_LPdS_back"><sup>'''11'''</sup></span>]], ces Poètes {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ublimes, ne furent point exempts à l’égard des éclip{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es {{Info|ſ|forme ancienne longue de la lettre s minuscule}}olaires), ou attribuoient les ténebres dont {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e couvre la lune à des maléfices opérés par le mêlange de certaines herbes magiques ; & croyoient devoir la {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ecourir par un bruit di{{Info|ſ|forme ancienne longue de la lettre s minuscule}}cordant [[#bruit_discordant_LPdS|<span id="bruit_discordant_LPdS_back"><sup>'''12'''</sup></span>]]. Cette même terreur fut cau{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e que le Général Nicias [[#Nicias_LPdS|<span id="Nicias_LPdS_back"><sup>'''13'''</sup></span>]], peu au fait des cau{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es phy{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iques, & n’o{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ant pas, par {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uper{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tition, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ortir {{Info|ſ|forme ancienne longue de la lettre s minuscule}}a flotte du Port, mit Athenes à deux doigts de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}a perte. Honneur [[#Honneur_LPdS|<span id="Honneur_LPdS_back"><sup>'''14'''</sup></span>]] à vous, Interpretes du Ciel ! E{{Info|ſ|forme ancienne longue de la lettre s minuscule}}prits [[#Esprits_LPdS|<span id="Esprits_LPdS_back"><sup>'''15'''</sup></span>]] dont l’étendue {{Info|ſ|forme ancienne longue de la lettre s minuscule}}urpa{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}e celle de la Nature ; Inventeurs d’une méthode qui a{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ujettit les dieux comme les hommes, à une même de{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tinée ! Eh! qui pourroit, en voyant les a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tres même ''en cri{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e'' (pour me {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ervir de l’expre{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ion commune), ne pas {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oumettre à la néce{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ité où {{Info|ſ|forme ancienne longue de la lettre s minuscule}}a condition mortelle l’enchaîne.<br /><p style="text-align: justify; text-indent: 15px;">Pré{{Info|ſ|forme ancienne longue de la lettre s minuscule}}entement je vais toucher par articles fort courts & fort précis les points {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur le{{Info|ſ|forme ancienne longue de la lettre s minuscule}}quels on s’accorde le plus. Je ré{{Info|ſ|forme ancienne longue de la lettre s minuscule}}oudrai, chemin fai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ant, quelques que{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tions, lor{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que le cas l’exigera, mais toujours d’une maniere très {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ommaire ; car une analy{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e en forme d’arguments {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uivis excéderoit le but de cet Ouvrage : & puis, je pen{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e qu’il n’y a pas moins de mérite à rendre une rai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}on plau{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ible de toutes cho{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es, qu’à rendre une rai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}on bien {{Info|ſ|forme ancienne longue de la lettre s minuscule}}olide de deux ou trois cho{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eulement.</div> {{Boîte déroulante début|titre=Notes du traducteur|alignT=center}} <div style="text-align: justify; border: 2px; border-radius:15px; font-size:85%;"><br/> <table cellspacing=15 align=center style="margin: 0 4em;"> <tr> <td style="text-align: justify; margin: 0 4em; text-indent: 15px">'''[[#Sulpicius_Gallus_LPdS_back|<span id="Sulpicius_Gallus_LPdS"><sup>1</sup></span>]] Son premier prénom étoit Caïus. Voyez à {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ujet Tite-Live, l. 44. Valere maxime, l. 8. Quintilien, l. I. ch. 10. Plutarque, vie de Paul-Emile, &c.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Tribun_Militaire_LPdS_back|<span id="Tribun_Militaire_LPdS"><sup>2</sup></span>]] Ce grade répond à celui de Major-général des Troupes.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#éclipse_LPdS_back|<span id="éclipse_LPdS"><sup>3</sup></span>]] Cette éclip{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}elon Tite-Live, fut annoncée aux {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oldats pour la nuit {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uivante. Sulpicius Gallus leur prédit que la lune s’éclip{{Info|ſ|forme ancienne longue de la lettre s minuscule}}eroit entre la {{Info|ſ|forme ancienne longue de la lettre s minuscule}}econde heure de la nuit & la quatrieme. Plutarque ajoute qu’on étoit alors à l’i{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ue de l’été (''{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ub exitum a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tatis''). [[w:Paulin_II_d'Aquilée|Paul d’Aquilée]] écrit que cette éclip{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e arriva aux nones de Septembre (''nonas Septembris''), c’est-à-dire au 4 Septembre : c’étoit l’an 168 avant J.C. {{Info|ſ|forme ancienne longue de la lettre s minuscule}}elon le calcul d’[[w:James_Ussher|U{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}erius]].''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Halyattes_LPdS_back|<span id="Halyattes_LPdS"><sup>4</sup></span>]] Il paroît que Ciceron & Eu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ebe {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e trompent lor{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’ils placent cet événement {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous ''A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tiages'' : [[w:Hermolaos_(Macédoine)|Hermolaüs]] s’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t trompé d’après eux, en {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ub{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tituant ''A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tiages'' à ''Halyattes'' dans le texte de Pline, contre la foi des manu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}crits, & contre le témoignage d’Herodote qui place cet événement dans une guerre entre Halyattes, Roi de Sardes, & Cyaxare, Roi des Medes, pere d’A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tiages.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#cent_soixante_LPdS_back|<span id="cent_soixante_LPdS"><sup>5</sup></span>]] Les deux manu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}crits royaux portent ''anno CLX'' : c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t la leçon qu’il faut {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uivre. En effet, Rome, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}elon Varron, fut fondée l’an 2 de la {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ixieme olympiade, c’est-à-dire, dans l’année olympiadique 22. Mais comme chaque olympiade, depuis leur premiere in{{Info|ſ|forme ancienne longue de la lettre s minuscule}}titution, commençoit après le {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ol{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tice d’été, & comme l’année Romaine avoit toujours commencé au plus tard en Mars {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous Romulus, & depuis en Janvier {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous Numa, il s’en{{Info|ſ|forme ancienne longue de la lettre s minuscule}}uit que la premiere année de Rome, qui répondoit à l’année olympiadique 22, répondoit en même-tems, de quatre mois au moins, à l’année olympíadique 23. Selon ce calcul, la quatrieme année de la quarante-huitieme olympiade, répond en partie à l’an 160, & en partie à l’an 161 de la fondation de Rome, pui{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que 48 olympiades font cent quatre-vingt-douze années, de{{Info|ſ|forme ancienne longue de la lettre s minuscule}}quelles {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i vous ôtez 22 ans écoulés, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}elon Varron, entre la premiere olympiade & la fondation de Rome, il re{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tera 160 ans, & 161 ans {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i l’on a égard à l’enjambement réciproque des années olympiadiques {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur les années Romaines, & des années Romaines {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur les années olympiadiques. Il e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t donc évident que le calcul de Pline (''anno CLX'') e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t ju{{Info|ſ|forme ancienne longue de la lettre s minuscule}}te, en admettant l’hypothe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e chronologique de Varron, à laquelle on voit bien que notre Auteur s’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t conformé en cette occa{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ion particuliere encore qu’en plu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ieurs autres rencontres il paroi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}e affecter de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uivre le {{Info|ſ|forme ancienne longue de la lettre s minuscule}}y{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tême de Caton : vici{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}itude pardonnable dans un ouvrage de compilation où Pline a dû, comme malgré lui, adopter tantôt le {{Info|ſ|forme ancienne longue de la lettre s minuscule}}tyle d’un Auteur, tantôt celui d’un autre, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}elon la {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ource où il pui{{Info|ſ|forme ancienne longue de la lettre s minuscule}}oit pour l’heure. Si Pline eût {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uivi l’hypothe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e de Caton qui place la fondation de Rome deux ans plus tard que Varron, il eût fait tomber le rapport {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur l’année 157 ou 158 de la fondation de Rome. C’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t le parti que prend le Pere Hardouin, & c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t de là qu’il part pour propo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}er une correction dans le texte. Mais encore une fois, c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t commettre {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oi-même une faute que d’en trouver une chez Pline en cette occa{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ion ; pui{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que cet Auteur a été en droit de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ervir du {{Info|ſ|forme ancienne longue de la lettre s minuscule}}y{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tème Varronien, ou ce qui revient au même, de con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}erver la date Varronienne dont s’étoit {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ervi l’Auteur de qui il emprunte le fait hi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}torique en que{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tion.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Hipparque_LPdS_back|<span id="Hipparque_LPdS"><sup>6</sup></span>]] Voyez les notes {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur le premier livre au mot ''Hipparque'' : HIPPARCHUS (de Nicée, en Bithinie comme l’ob{{Info|ſ|forme ancienne longue de la lettre s minuscule}}erve [[w:Souda|Suidas]]), flori{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}oit dans la quatre-vingt-quatorzieme olympiade. Nous avons {{Info|ſ|forme ancienne longue de la lettre s minuscule}}es trois livres d’Enarrations {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur les Phénomenes d’[[w:Aratos_de_Soles|Aratus]] & d’[[w:Eudoxe_de_Cnide|Eudoxe]], traduits par le [[w:Paul_Petau|P. Petau]]. Il avoit compo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}é un autre livre ''De {{Info|ſ|forme ancienne longue de la lettre s minuscule}}tellarum inerrantium Con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}titutione'', {{Info|ſ|forme ancienne longue de la lettre s minuscule}}elon Suidas. Son livre du mois lunaire e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t cité par [[w:Claude_Galien|Galien]].''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#En_vers_LPdS_back|<span id="En_vers_LPdS"><sup>7</sup></span>]] ''En Vers.'' Je préfume que c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t-là le {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ens de ''præcinere'', qui ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ignifie pas {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eulement prédire, mais prédire en chant, c’est-à-dire en Vers. Sur ce pied-là, ce {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eroit d’un Poëme dans le genre de celui d’[[w:Aratos_de_Soles|Aratus]], dont il {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eroit ici que{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tion. Si par hazard Pline n’a point prétendu parler d’un Poëme, au-moins s’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t-il {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ervi d’une expre{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ion propre à dé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}igner ce genre d’écrire. Pour décider la que{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tion, il faudroit avoir tous les ouvrages d’Hipparque, & {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur-tout celui-ci.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#témoignage_LPdS_back|<span id="témoignage_LPdS"><sup>8</sup></span>]] Ces tables étoient dre{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ées pour {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ix cents ans. Or Hipparque flori{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}oit 150 ans avant J.C. Ain{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i du tems de Pline, on avoit encore à jouir de ces tables pour quatre cents ans ou environ.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#chaque_nation_LPdS_back|<span id="chaque_nation_LPdS"><sup>9</sup></span>]] La lune ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e levant pas & ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e couchant pas à la même heure pour toutes les nations, les diver{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es époques & pha{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es qu’elle forme n’appartiennent pas non plus au même point de tems pour tous les peuples, pui{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que les uns ont la nuit quand les autres ont le jour; & que même lor{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que la lune s’éclip{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e, la partie de l’heure où ce phénomene e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t {{Info|ſ|forme ancienne longue de la lettre s minuscule}}en{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ible, n’a pas la même évaluation pour tous les climats qui l’apperçoivent. Hipparque avoit donc eu égard à cette différence d’époques, relativement aux diver{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es longitudes, &par-con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}équent aux diver{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es nations, tellement que les tables de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}es éphémérides étoient accommodées à l’u{{Info|ſ|forme ancienne longue de la lettre s minuscule}}age de tous les peuples : ouvrage dont on ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}auroit trop regretter la perte, & qui jetteroit le plus grand jour {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur l’ancienne géographie.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Stésikhore_LPdS_back|<span id="Stésikhore_LPdS"><sup>10</sup></span>]] Ste{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ikhore, l’un des plus fameux Poètes de la Grece, dont, par malheur, nous avons perdu tous les ouvrages, à l’exception d’une vingtaine de lignes décou{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ues. Il vivoit dans la quarante-deuxieme olympiade, c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t-à-dire, vers l’an {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ix cents dix avant J.C.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Pindare_LPdS_back|<span id="Pindare_LPdS"><sup>11</sup></span>]] Pindare, le plus fameux Poète de la Grece après Homere. Il vint au monde l’an 134 avant l’ere chrétienne.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#bruit_discordant_LPdS_back|<span id="bruit_discordant_LPdS"><sup>12</sup></span>]] Cet u{{Info|ſ|forme ancienne longue de la lettre s minuscule}}age {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uper{{Info|ſ|forme ancienne longue de la lettre s minuscule}}titieux a fourni un Vers fort plai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ant à Juvenal, lor{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’après avoir épui{{Info|ſ|forme ancienne longue de la lettre s minuscule}}é toute {{Info|ſ|forme ancienne longue de la lettre s minuscule}}orte d’exagération pour repré{{Info|ſ|forme ancienne longue de la lettre s minuscule}}enter le bruit qu’une femme fait en criant, il finit par dire :<br /><p style="text-align: justify; text-indent: 15px;">''Una laboranti poterit {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uccurrere luna.''<br /><p style="text-align: justify; text-indent: 15px;">Elle {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eule au be{{Info|ſ|forme ancienne longue de la lettre s minuscule}}oin décharmeroit la lune.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Nicias_LPdS_back|<span id="Nicias_LPdS"><sup>13</sup></span>]] C’étoit un Général Athénien, qui fut malheureux dans pre{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que toutes {{Info|ſ|forme ancienne longue de la lettre s minuscule}}es expéditions. Les Athéniens finirent par le condamner à mort. Il étoit contemporain d’[[w:Alcibiade|Alcibiade]] & de [[w:Lamachos|Lamachus]], & leur collegue dans le commandement. Voyez {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur le fait dont parle ici Pline, Quintilien, l. I. ch. 10, & Plutarque à l’article Nicias.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Honneur_LPdS_back|<span id="Honneur_LPdS"><sup>14</sup></span>]] Au lieu de ''macte ingenio'', le Pere Hardouin lit ''macti'' ; mais {{Info|ſ|forme ancienne longue de la lettre s minuscule}}elon les meilleurs Latini{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tes ''macte'' e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t indéclinable, ou pour mieux dire, c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t un adverbe qui répond au ''bravò'' des Italiens. Fe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tus prétend que ''macte'' e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t un compo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}é de ''magis auctus''.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Esprits_LPdS_back|<span id="Esprits_LPdS"><sup>15</sup></span>]] Cette apo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}trophe de Pline aux A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tronomes rappelle ces beaux Vers d'Ovide {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur le même {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ujet :<br />Felices animos quibus hæc cogno{{Info|ſ|forme ancienne longue de la lettre s minuscule}}cere primise<br /><p style="text-align: justify; text-indent: 15px;">Inque Domos {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uperas {{Info|ſ|forme ancienne longue de la lettre s minuscule}}candere cura fuit!<br />Credibile e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t illos pariter vitli{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que joci{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que<br /><p style="text-align: justify; text-indent: 15px;">Altius humanis ex{{Info|ſ|forme ancienne longue de la lettre s minuscule}}eruifle caput,<br />Non Venus aut Vinum {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ublimia pectora fregit<br /><p style="text-align: justify; text-indent: 15px;">Officiumve {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ori, militiæve labor :<br />Nec levis ambitio, perfu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}aque gloria fuco,<br /><p style="text-align: justify; text-indent: 15px;">Magnarumve fames {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ollicitavit opum.<br />Admovere oculis di{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tantia {{Info|ſ|forme ancienne longue de la lettre s minuscule}}idera no{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tris,<br /><p style="text-align: justify; text-indent: 15px;">Ætheraque ingenio {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uppo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}uere {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uo.<br />Sic petitur cœlum: non ut ferat O{{Info|ſ|forme ancienne longue de la lettre s minuscule}}lan Olympus<br /><p style="text-align: justify; text-indent: 15px;">Summaque Peliacus {{Info|ſ|forme ancienne longue de la lettre s minuscule}}idera tangat apex, &c.<br /><p style="text-align: right; text-indent: 15px;">Ovid. {{Info|ſ|forme ancienne longue de la lettre s minuscule}}a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t. l. I.''' </td> </tr> </table><br/><br/></div> {{Boîte déroulante fin}} <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=UnhluychtF8C&newbks=1&newbks_redir=0&dq=Histoire%20naturelle%20Pline&hl=fr&pg=PP7#v=onepage&q&f=true <u>Histoire Naturelle de Pline. Tome Premier</u>], [https://books.google.fr/books?id=UnhluychtF8C&newbks=1&newbks_redir=0&dq=Histoire%20naturelle%20Pline&hl=fr&pg=RA1-PA3#v=onepage&q&f=true ''Livre Second.''], [https://books.google.fr/books?id=UnhluychtF8C&newbks=1&newbks_redir=0&dq=Histoire%20naturelle%20Pline&hl=fr&pg=RA1-PA59#v=onepage&q&f=true ''Des inventions astronomiques, & de leurs Auteurs.''], traduction en françois, avec le texte latin rétabli d’après les meilleures leçons manu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}crites ; accompagnée de Notes critiques pour l’éclairci{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ement du texte, & d’Ob{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ervations {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur les connoi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ances des Anciens comparées avec les découvertes des Modernes, par M. [[w:Louis_Poinsinet_de_Sivry|Louis Poinsinet de Sivry]], Chez la veuve Desaint, Paris, 1771</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div> </div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ==== Livre XVIII ==== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Enquête sur l’agriculture</div> ===== <div style="text-align: center;">Chapitre LVII.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage d’une théorie astronomique de '''Thalès''', du [[w:Lever_héliaque|''coucher matinal'']] des [[w:Pléiades_(astronomie)|''Pléiades'']] 25 jours après l’[[w:Équinoxe_de_septembre|''équinoxe d’automne'']].</div> :'''Texte latin''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''LVII.''' Primum omnium dierum ipsorum anni solisque motus prope inexplicabilis ratio est. Ad CCCLXV adjiciunt etiamnum intercalarios diei noctisque quadrantes. Ita fit, ut tradi non possint certa siderum tempora. Accedit confessa rerum obscuritas, nunc præcurrenle, nec paucis diebus, tempestatum significatu, quod προϰειμασιν Græci vocant : nunc postveniente, quod ἐπιϰεἰμασιν : et plerumque alias citius, alias tardius cæli effectu ad terram deciduo : vulgo serenitate reddita, confectum sidus audimus. Præterea quum omnia hæc statis sideribus cæloque affixis constent, interveniunt motu stellarum grandines, imbres, et ipsi non levi effectu, ut docuimus, turbantque conceptæ spei ordinem. ldque ne nobis tantum putemus accidere, et reliqua fallit animalia sagaciora circa hoc, ut quo vita eorum constet : æstivasque alites præposteri aut præproperi rigores necant, hibernas æstus. Ideo '''Virgilius''' errantium quoque siderum rationem ediscendam præcipit, admonens observandum frigidæ Saturni stellæ transitum. Sunt qui certissimum veris indicium arbitrentur ob infirmitatem animalis, papilionis proventum. Id eo ipso anno, quum commentaremur hæc, notatum est, proventum eorum ter repetito frigore exstinctum, advenasque volucres a. d. VI kalendas februarii spem veris attulisse, mox sævissima hieme conflictatas. Res anceps : primum omnium a cælo peti legem : deinde eam argumentis esse quærendam. Super omnia est mundi convexitas, terrarumque globi differentia, eodem sidere alio tempore aliis aperiente se gentibus : quo fit ut causa ejus non lisdem diebus ubique valeat. Addidere difficultatem et auclores diversis in locis observando, mox etiam in iisdem diversa prodendo. Très autem fuere sectæ : ''Chaldæa'', ''Ægyptia'', ''Græca''. His addidit apud nos quartam Cæsar dictator, annos ad solis cursum redigens singulos, '''Sosigene''' perito scientiæ ejus adhibito. Et ea ipsa ratio postea comperto errore correcta est : ita ut XII annis continuis non intercalaretur, quia cœperat sidera annus morari, qui prius antecedebat. Et '''Sosigenes''' ipse trinis commentationibus, quanquam diligentior cæteris, non cessavit tamen addubitare, ipse semet corrigendo. Auctores prodidere ea, quos prætexuimus volumini huic, raro ullius sententia cum alio congruente. Minus hoc in reliquis mirum, quos diversi excusaverint tractus. Eorum qui in eadem regione dissedere, unam discordiam ponemus exempli gratia : occasum matutinum Vergiliarum '''Hesiodus''' (nam hujus quoque nomine exstat Astrologia) tradidit fieri, quum æquinoctium autumni conficeretur, '''Thales''' vigesimo quinto die ab æquinoctio, '''Anaximander''' vigesimo nono, '''Euctemon''' XLVIII. Nos sequemur observationem Cæsaris : maximeque hæc erit ''Italiæ'' ratio. Dicemus tamen et aliorum placita : quoniam non unius terræ, sed totius naturæ interpretes sumus, non auctoribus positis (id enim verbosum est), sed regionibus : legentes tantum meminerint, brevitatis gratia, quum ''Altica'' nominata fuerit, simul intelligere ''Cycladas'' insulas ; quum ''Macedonia'', ''Magnesiam'', ''Thraciam'' ; quum ''Ægyptus'', ''Phœnicen'', ''Cyprum'', ''Ciliciam'' ; quum ''Bœotia'', ''Locridem'', ''Phocidem'', et finitimos semper tractus ; quum ''Hellespontus'', ''Cherronesum'', et continentia usque ''Atho'' montem ; quum ''Ionia'', ''Asiam'', et insulas ''Asiæ'' ; quum ''Peloponnesus'', ''Achaiam'', et ad ''Hesperum'' jacentes terras. ''Chaldæi Assyriam'' et ''Babyloniam'' demonstrabunt. ''Africam'', ''Hispanias'', ''Gallias'' sileri non erit mirum. Nemo enim observavit in iis, qui siderum proderet exortus. Non tamen difficili ratione dignoscentur in illis quoque terris digestione circulorum, quam in sexto volumine fecimus : qua cognatio cæli, non gentium modo, verum urbium quoque singularum intelligitur, nota ex his terris, quas nominavimus, sumta convexitate circuli, pertinentis ad quas quisque quæret terras, et ad earum siderum exortus, per omnium circulorum pares umbras. Indicandum et illud, tempestates ipsas ardores suos habere quadrinis annis : et easdem non magna differentia reverti ratione solis : octonis vero augeri easdem, centesima revolvente se luna.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/b24875958_0001/page/n7/mode/2up <u>Histoire Naturelle de Pline.</u>], [https://archive.org/details/b24875958_0001/page/652/mode/2up ''Livre XVIII.''], [https://archive.org/details/b24875958_0001/page/684/mode/2up ''Chap. LVII.''], texte corrigé par [[w:Émile_Littré|M. É. Littré]], à partir de celui de [[w:Jean_Hardouin|Hardouin]], Librairie de Firmin-Didot et C<sup>ie</sup>, Paris, 1883<br />(également disponible une édition de 1831 [https://gallica.bnf.fr/ark:/12148/bpt6k5804072n/f339.item ici] et de 1848 [[s:Page:Pline_l'ancien_-_Histoire_naturelle,_Littré,_T1_-_1848.djvu/708|là]])</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''LVII.''' Avant tout, le calcul des jours même de l’année et du mouvement solaire est d’une difficulté presque insurmontable. Aux trois cent soixante-cinq jours on ajoute des jours intercalaires, produits de quarts de jour et de nuit ; de là vient qu’on ne peut indiquer des époques fixes pour les astres. Ajoutez une obscurité des choses avouée de tous : tantôt en effet la mauvaise saison, s’annonçant, anticipe même de plusieurs jours, ce que les Grecs appellent προϰεἰμασις (avant-hiver), et la belle saison retarde, ce qui est nommé ἐπιϰεἰμασις (arriere-hiver) : l’effet du ciel tombe sur la terre tantôt plus vite, tantôt plus tardivement ; et d’ordinaire c’est quand la sérénité est rétablie que nous entendons dire que l’action de l’astre est accomplie. En outre, car tous ces phénomènes dépendent d’astres réglés et fixés au ciel, le mouvement des étoiles amène intercurremment des grêles, des pluies qui ne sont pas non plus d’une faible action, comme nous l’avons enseigné (XVII, 2), et qui troublent l’ordre espéré. Et ne pensons pas que ces méprises n’arrivent qu’à nous; les autres animaux s’y trompent, bien que plus sagaces que nous sur ce point, vu que leur vie en dépend : l’on voit les oiseaux d’été tués par des froids hâtifs ou tardifs, et les oiseaux d’hiver par des chaleurs hâtives ou tardives. Aussi [[w:Virgile|'''Virgile''']] [[#Virgile|<span id="Virgile_back"><sup>'''I'''</sup></span>]] ([[w:Géorgiques|''Georg.'']], I, 335) recommande-t-il d’étudier encore le cours des astres errants, avertissant d’observer le passage de Saturne, planète froide. Il en est qui regardent comme l’indice le plus sûr du printemps l’apparition des papillons, à cause de la délicatesse de cet insecte. Or, l’année même où nous écrivions ceci (an 830 de ''Rome''), il a été noté que les papillons, ayant éclos, furent détruits à trois reprises par le froid, et que les oiseaux étrangers, ayant apporté l’espérance du printemps avant le 6 des calendes de février (27 janvier), eurent bientôt après à essuyer un hiver très-rigoureux. La double difficulté est d’abord d’avoir à demander au ciel la règle de toute chose, puis d’être obligé de contrôler cette règle par des faits apparents. Avant tout signalons la convexité du monde et les différences du globe terrestre, qui font que le même astre se montre à des temps divers suivant les nations, de sorte que l’influence ne s’en fait pas sentir partout aux mêmes jours. La difficulté a été encore accrue par les auteurs qui ont observé en des lieux différents, ou même qui, ayant observé dans les mêmes lieux, ont publié des résultats divergents. Il y a eu trois écoles, la ''Chaldéenne'', l’Égyptienne, la ''Grecque''. Une quatrième a été formée chez nous par le dictateur [[w:Jules_César|'''César''']], qui ramena l’année à la révolution solaire avec l’aide de [[w:Sosigène_d'Alexandrie|'''Sosigène''']] [[#Sosigène|<span id="Sosigène_back"><sup>'''II'''</sup></span>]], astronome habile. Et ce calcul même, où l’on découvrit une erreur, a été corrigé : pendant douze années consécutives on ne fit pas d’intercalation, attendu que l’année, qui auparavant anticipait, maintenant retardait sur les astres. '''Sosigène''' lui-même, quoique plus exact que les autres, n’a pas cessé, dans trois mémoires, de témoigner de ses doutes en se corrigeant lui-même. Les auteurs que nous avons indiqués au commencement de ce livre [[#auteurs_JH|<span id="auteurs_JH_back"><sup>'''1'''</sup></span>]] ont révélé ces discordances, l’avis de l’un s’accordant rarement avec l’avis de l’autre. Cela est moins étonnant dans ceux qui s’excuseront par la différence des lieux. Parmi ceux qui dans le même pays sont en désaccord, nous choisirons un exemple de dissidence : [[w:Hésiode|'''Hésiode''']] [[#Hésiode|<span id="Hésiode_back"><sup>'''III'''</sup></span>]] (car nous avons aussi sous son nom un livre sur les astres) a rapporté que le [[w:Lever_héliaque|''coucher matinal'']] des [[w:Pléiades_(astronomie)|''Pléiades'']] se faisait au moment de l’[[w:Équinoxe_de_septembre|''équinoxe d’automne'']] ; '''Thalès''', qu’il se faisait vingt-cinq jours après cet équinoxe; [[w:Anaximandre|'''Anaximandre''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Anaximandre_back|<sup>🔄</sup>]], vingt-neuf; [[w:Euctémon|'''Euctémon''']] [[#Euctémon|<span id="Euctémon_back"><sup>'''IV'''</sup></span>]], quarante-huit. Quant à nous, nous suivrons les calculs de '''César''' : ils se rapportent spécialement à l’Italie. Toutefois, nous relaterons aussi les opinions des autres ; car nous sommes les interprètes, non d’un seul pays, mais de la nature entière. Nous nommerons, non pas les auteurs, ce qui serait trop long, mais les pays. Les lecteurs auront seulement à se souvenir que, pour abréger, sous le nom d’[[w:Attique|''Attique'']] nous entendons aussi les [[w:Cyclades|''Cyclades'']]; sous celui de [[w:Macédoine_(province_romaine)|''Macédoine'']], la [[w:Magnésie_antique|''Magnésie'']] et la [[w:Thrace_(province_romaine)|''Thrace'']]; sous celui d’[[w:Égypte_romaine_et_byzantine|''Égypte'']], la [[w:Syrie-Phénicie_(province_romaine)|''Phénicie'']], [[w:Chypre_(province_romaine)|''Chypre'']] et la [[w:Cilicie|''Cilicie'']]; sous celui de [[w:Béotie#Antiquité|''Béotie'']], la [[w:Locride_(Grèce)|''Locride'']], la [[w:Phocide#Antiquité_et_période_byzantine|''Phocide'']] et les contrées limitrophes ; sous celui d’[[w:Hellespontique|''Hellespont'']], la [[w:Chersonèse_(cité_grecque)|''Chersonèse'']] et le continent jusqu’au [[w:Mont_Athos|''mont Athos'']]; sous celui d’[[w:Ionie|''Ionie'']], l’Asie et les îles ''Asiatiques'' ; sous celui de [[w:Péloponnèse#Antiquité|''Péloponnèse'']], l’[[w:Achaïe|''Achaïe'']] et les terres situées à l’occident; la [[w:Chaldée|''Chaldée'']] indiquera la [[w:Histoire_de_la_Syrie#Antiquité|''Syrie'']] et la [[w:Babylone_(civilisation)|''Babylonie'']]. On ne s’étonnera pas que je passe sous silence l’[[w:Afrique_romaine|''Afrique'']], l’[[w:Hispanie_romaine|''Espagne'']] et les [[w:Gaule|''Gaules'']], car personne dans ces contrées n’a laissé d’observations sur le lever des astres. Toutefois, il ne sera pas difficile de le calculer, même dans ces contrées, en étudiant la disposition des cercles que nous avons présentés dans le sixième livre (VI, 39). Grâce à cette étude, on connaît les relations astronomiques nou-seulement des nations, mais encore des villes en particulier : étant donnés les cercles déterminés par l’égalité des ombres, on choisit, dans les terres que nous avons nommées, le cercle qui a rapport à la localité objet du problème, et qui détermine en même temps le lever des astres pour cette localité. Il faut encore remarquer (II, 48) que tous les quatre ans les saisons ont leurs excès, et qu’elles reviennent les mêmes sans grande différence, en raison du soleil ; mais que tous les huit ans elles ont un redoublement, à la révolution de la centième lune.</div> <table cellspacing=15 align=center style="margin: 0 4em; font-size:85%;"> <tr> <td style="text-align: justify; margin: 0 4em;">'''[[#auteurs_JH_back|<span id="auteurs_JH"><sup>1</sup></span>]] Ce passage porte à croire que les auteurs dont Pline s’était servi pour composer chacun des livres de son ouvrage avaient été placés en tête du livre auquel ils se rapportaient. Les éditions mettent cette liste d’auteurs à la suite de la table de chaque livre, dans la table générale dressée par Pline lui-même.'''</td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/b24875958_0001/page/n7/mode/2up <u>Histoire Naturelle de Pline.</u>], [https://archive.org/details/b24875958_0001/page/652/mode/2up ''Livre XVIII.''], [https://archive.org/details/b24875958_0001/page/684/mode/2up ''Chap. LVII.''], texte corrigé par [[w:Émile_Littré|M. É. Littré]], à partir de celui de [[w:Jean_Hardouin|Hardouin]] [https://archive.org/details/b24875958_0001/page/708/mode/2up <sup>NOTES</sup>], Librairie de Firmin-Didot et C<sup>ie</sup>, Paris, 1883<br />(également disponible une édition 1848 [[s:Page:Pline_l'ancien_-_Histoire_naturelle,_Littré,_T1_-_1848.djvu/708|ici]])</div> {{Boîte déroulante début|titre=NdA de trad. Jean Hardouin 1883|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Virgile_back|<span id="Virgile"><sup>I</sup></span>]] [[w:Nom_romain|Tria Nomina]] en latin {{Info|Publius|praenomen, nom individuel du citoyen romain}} {{Info|Vergilius|nomen, nom de famille}} {{Info|Maro|cognomen, surnom héréditaire, servant à distinguer les diverses branches d’une même gens}};<br /><p style="margin: 0 2em; text-indent: 15px">Poète latin renommé dans les styles [[w:Épopée|''épique'']] (l’[[w:Énéide|''Énéide'']]), [[w:Poésie_pastorale|''pastorale'']] (les [[w:Bucoliques|''Bucoliques'']]) et [[w:Poésie_didactique|''didactique'']] (les [[w:Géorgiques|''Géorgiques'']]).<br /><p style="text-align: right; margin: 0 2em;">(15 octobre [[w:Années_70_av._J.-C.|-70]], [[w:Virgilio_(Lombardie)#Histoire|''Andes'']], au sud-est de l’actuelle [[w:Lombardie#Histoire|''Lombardie'']], au nord de l’Italie — 21 septembre [[w:Années_19_av._J.-C.|-19]], [[w:Brindisi#Histoire|''Brundisium'']], au sud-est des actuelles [[w:Pouilles#Domination_romaine|''Pouilles'']], au sud-est de l’Italie)<sup>[[w:Ier_siècle_av._J.-C.|⏳]]</sup> <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Sosigène_back|<span id="Sosigène"><sup>II</sup></span>]] Du nom propre grec ancien Σωσῐγένης / Sōsigénēs [[wikt:en:Σωσιγένης#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;">➥ du verbe σῴζω / sṓizō, « 1. Sauver : • Guérir ; • (rare chez Homère) Garder en sécurité, préserver ; • Garder, observer, maintenir ; • (généralement au milieu) Garder à l’esprit, se souvenir ; • Conduire en toute sécurité (à) ; • Secourir ; • Conserver pour. »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ + du nom commun‎ γένος / génos [[wikt:en:γένος#Ancient_Greek|(en)]], « 1. Race, souche, parenté : Descendance directe, par opposition à une relation collatérale. 2. Progéniture, descendant : (collectif) progéniture, postérité. 3. (en général) Race d’êtres : • Famille, clan, maison ; • Tribu, nation, race, en tant que subdivision de ἔθνος / éthnos [[wikt:en:ἔθνος#Ancient_Greek|(en)]] ; • Caste ; • Race d’animaux. 4. Âge, génération, période de la vie. 5. Sexe, genre : (grammaire) Genre grammatical. 6. Classe, sorte, genre : • (logique) L’opposé de εἶδος / eîdos [[wikt:en:εἶδος#Ancient_Greek|(en)]] ; • (taxonomie) Classe : • (taxonomie) Genre ; • Espèce de plante ; culture, produit ; matériau ; • Élément. »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ +‎ du suffixe nominal propre -ης / -ēs [[wikt:en:-ης#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;"> Astronome grec, connu pour avoir participer à la conception du [[w:Calendrier_julien|''calendrier julien'']] (instauré par Jules César en [[w:Années_46_av._J.-C.|-46]]/[[w:Années_45_av._J.-C.|-45]], lorsqu’il était [[w:Pontifex_maximus|''pontifex maximus'']]), avec une année commune de 365 jours divisée en 12 mois, et un jour intercalaire ajouté tous les 4 ans, lors des années bissextiles.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:Ier_siècle_av._J.-C.|I<sup>er</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]]) <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Hésiode_back|<span id="Hésiode"><sup>III</sup></span>]] Du nom propre grec ancien Ἡσῐ́οδος / Hēsíodos;<br /><p style="margin: 0 2em; text-indent: 15px">Poète ''grec'', renommé pour 2 ouvrages :<br /><p style="margin: 0 2em; text-indent: 15px;">• [[w:Théogonie_(Hésiode)|''la Théogonie'']], une généalogie des dieux (dans laquelle il présente la multitude des dieux célébrés par les mythes grecs où trois générations divines se succèdent : celle d’Ouranos, celle de Cronos, celle de Zeus qui sort triomphant) et une cosmogonie (qui retrace la création du monde à partir du Chaos) ;<br /><p style="margin: 0 2em; text-indent: 15px;">• et [[w:Les_Travaux_et_les_Jours|''les Travaux et les Jours'']], un almanac sur l’agriculture à destination de son frère Perses.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:VIIIe_siècle_av._J.-C.|VIII<sup>ème</sup>]] — [[w:VIIe_siècle_av._J.-C.|VII<sup>ème</sup>]] siècles {{Info|AEC|Avant l’Ère Commune}}) <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Euctémon_back|<span id="Euctémon"><sup>IV</sup></span>]] Du nom propre grec ancien Ευκτήμων / Euktémōn;<br /><p style="margin: 0 2em; text-indent: 15px;">Astronome ''athénien'', contemporain et collègue de l’astronome [[w:Méton|Méton]], avec qui, il a fait une série d’observations des [[w:Solstice|''solstices'']] afin de déterminer la durée de l’[[w:Année_tropique|''année tropique'']] [https://ecliptiqc.ca/Almageste_Livre3.php#III1 <sup>Ptolémée, Almageste, liv. III, chap. 1</sup>].<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:Ve_siècle_av._J.-C.|V<sup>ème</sup>]] siècle {{Info|AEC|Avant l’Ère Commune}})'''<br/><br/></div> {{Boîte déroulante fin}} <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: center; margin: 0 2em;">Des découvertes astronomiques : part de chaque observateur dans la science.<br /><p style="text-align: justify; text-indent: 15px;">'''LVII.''' D’abord, il est presque impossible de déterminer d’une manière précise le nombre des jours de l’année et le cours du soleil [[#Primum_omnium_dierum_AdG|<span id="Primum_omnium_dierum_AdG_back"><sup>'''1'''</sup></span>]]. Aux trois cent soixante-cinq jours qui composent l’année, on ajoute le quart d’un jour et d’une nuit, pour en faire ensuite un jour intercalaire ; de là il suit qu’on ne saurait indiquer avec précision le moment du lever et du coucher des astres. On convient qu’il y a encore dans cette théorie beaucoup d’obscurité ; en effet, les saisons quelquefois commencent plusieurs jours avant le terme qui leur a été fixé, ce que les ''Grecs'' appellent ''procheimasis'' ; d’autres fois, plusieurs jours après, ce qu’ils appellent ''épicheimasis'' [[#Accedit_confessa_rerum_obscuritas_AdG|<span id="Accedit_confessa_rerum_obscuritas_AdG_back"><sup>'''2'''</sup></span>]]. Presque toujours l’action des astres se fait sentir sur la terre ou plus tôt ou plus tard qu’il ne devrait ; aussi dit-on communément, lorsque le beau temps est revenu, que tel astre a produit son effet. Ces phénomènes dépendent des astres fixés à la voûte des cieux, ainsi que des étoiles, dont les mouvemens particuliers excitent des grêles et des pluies qui sont d’une très-grande conséquence pour les biens de la terre, comme nous l’avons observé, et amènent dans la température des changemens sur lesquels le laboureur ne pouvait compter. Non-seulement les hommes y sont trompés, mais aussi les animaux, bien plus habiles que nous à prévoir ces vicissitudes, puisque d’ailleurs leur vie en dépend ; en effet, on a vu des oiseaux d’été périr par des froids arrivés trop tôt ou trop tard, et des oiseaux d’hiver par des chaleurs également imprévues. Aussi '''Virgile''' veut-il qu’on étudie aussi le cours des ''planètes'', et qu’on observe avec soin le passage du froid ''Saturne'' [[#Ideo_Virgilius_errantium_quoque_siderum_rationem_ediscendam_prœcipit_AdG|<span id="Ideo_Virgilius_errantium_quoque_siderum_rationem_ediscendam_prœcipit_AdG_back"><sup>'''3'''</sup></span>]].<br /><p style="text-align: justify; text-indent: 15px;">Quelques-uns fixent le commencement du printemps à l’apparition des papillons, parce que ces insectes sont fort délicats. Néanmoins on a observé, dans l’année même où j’écris cette partie de mon ouvrage, que le froid, ayant repris trois fois, a fait périr autant de fois les papillons, et que les hirondelles qui, s’étaient montrées dès le 6 des [[w:Calendes|''kalendes'']] de février, et semblaient annoncer le retour du printemps, ont eu à essuyer un rigoureux hiver.<br /><p style="text-align: justify; text-indent: 15px;">C’est donc une science très-problématique que celle de l’influence des astres, et les inductions qu’elle fournit sont fort douteuses [[#Res_anceps_AdG|<span id="Res_anceps_AdG_back"><sup>'''4'''</sup></span>]]. Ce qui augmente la difficulté, c’est la convexité du ciel et la différence des climats de la terre : le même astre se montre ici dans un temps, et là dans un autre ; d’où il suit que son influence ne se fait pas sentir en même temps partout. Pour surcroît d’embarras, les observations recueillies par les auteurs ont été faites dans des lieux différens, et ceux du même pays ne s’accordent pas même entre eux. On compte trois écoles astronomiques, la ''chaldéenne'', l’égyptienne et la ''grecque''. Le dictateur '''César''' en a fondé, chez les ''Romains'', une quatrième, lorsqu’aidé de '''Sosigène''', habile astronome, il fixa la longueur de l’année à une révolution du soleil. On trouva dans la suite que son calendrier était défectueux, parce que l’année, auparavant plus courte, se trouvait alors plus longue que le cours du soleil. Pour y remédier, il fallut, pour douze années consécutives, supprimer les jours intercalaires. '''Sosigène''' lui-même, le mathématicien le plus exact de son temps, après avoir revu jusqu’à trois fois ses calculs, sembla toujours douter de leur justesse, et ne cessa jamais de se corriger lui-même. De tous les auteurs qui ont traité ce sujet, et que nous avons cités au commencement de ce livre, il en est rarement deux qui soient de même avis. Cette divergence d’opinions est moins surprenante et plus excusable chez ceux qui écrivaient en des pays différens. Mais que dire de ceux qui, habitant le même pays, sont néanmoins d’avis différens ? En voici un exemple : '''Hésiode''', qui nous a laissé aussi un ouvrage sur le cours des astres, fixe le coucher matutinal des ''Pléiades'' au moment de l’équinoxe d’automne ; '''Thales''' prétend qu’il n’arrive que vingt-cinq jours après ; '''Anaximandre''' en met vingt-neuf ; '''Euctémon''', quarante-huit.<br /><p style="text-align: justify; text-indent: 15px;">Quant à nous, nous suivrons les calculs de '''César''', qui se rapportent spécialement à l’Italie ; mais nous rapporterons aussi les observations étrangères, car notre plan n’est pas de traiter d’un seul pays, mais de la nature entière. Pour être moins longs, nous citerons les pays, et non les auteurs ; et, pour abréger davantage encore, les lecteurs se souviendront que, sous le nom d’Attique, il faut aussi entendre les ''Cyclades'' ; sous le nom de ''Macédoine'', la ''Magnésie'' et la ''Thrace'' ; sous le nom d’Égypte , la ''Phénicie'', l’île de ''Cypre'' et la ''Cilicie'' ; sous celui de ''Béotie'', la ''Locride'', la ''Phocide'' et les contrées voisines ; sous le nom d’Hellespont, la ''Chersonèse'' et partie du continent jusqu’au mont ''Athos'' ; sous le nom de l’Ionie, l’Asie et les îles ''Asiatiques'' ; sous le nom du ''Péloponnèse'', l’Achaïe et les pays adjacens au couchant ; enfin sous le nom de ''Chaldée'', l’Assyrie et la ''Babylonie''. On ne sera pas étonné que nous ne parlions ni de l’Afrique, ni de l’Espagne, ni des ''Gaules''. Aucun auteur dans ces contrées n’a laissé d’observations sur le lever ou le coucher des astres. Il ne sera pas difficile néanmoins de déterminer l’époque de ces phénomènes dans ces contrées, en étudiant la disposition des cercles, telle que nous l’avons présentée dans le sixième livre. Par ce moyen, on déterminera la position astronomique, non-seulement de chaque pays, mais encore de chaque ville dont nous avons pu parler, en prenant par les ombres égales de tous les cercles, une portion du cercle de telle contrée qu’on voudra choisir, et en calculant son rapport avec le lever des astres. Il faut faire observer encore que tous les quatre ans les chaleurs reviennent à peu près les mêmes pour chaque saison, en raison du mouvement du soleil, et que toutes les huitièmes années elles sont plus fortes, à cause de la centième lunaison.</div> <table cellspacing=15 align=center style="margin: 0 4em; font-size:85%;"> <tr> <td style="text-align: justify; margin: 0 4em;">'''[[#Primum_omnium_dierum_AdG_back|<span id="Primum_omnium_dierum_AdG"><sup>1</sup></span>]] Cf. sur la plupart des difficultés que le texte de notre auteur révèle, les notes relatives à l’astronomie, au livre II. L’année romaine fut d’abord celle des [[w:Albe_la_Longue|''Albains'']], c’est-à-dire lunaire ; dix mois la composaient, mars en était le premier : elle avait cinquante jours de moins que l’année lunaire réelle, et soixante-un de moins que l’année solaire, c’est-à-dire trois cent quatre jours seulement ; c’était là l’[[w:Calendrier_romain|{{Info|''année de Romulus''|le calendrier dit romuléen}}]]. [[w:Calendrier_romain|{{Info|''Numa''|le calendrier dit pompilien}}]] ajouta deux mois à cette année, janvier et février, et elle se trouva être composée de trois cent cinquante-cinq jours. Elle demeura ainsi jusqu’à Jules César, où commence l’[[w:Calendrier_julien|''année julienne'']], qui se compose de trois cent soixante-cinq jours, huit heures, auxquels [[w:Calendrier_grégorien|''Grégoire le Grand'']] ajouta onze minutes, pour arriver à la plus grande exactitude possible.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Accedit_confessa_rerum_obscuritas_AdG_back|<span id="Accedit_confessa_rerum_obscuritas_AdG"><sup>2</sup></span>]] L’entrée du soleil dans tel ou tel signe du zodiaque, son passage à l’équateur, etc., ne sont pas toujours le signal d’un changement dans la température. [[w:Végèce|Végèce]] a parlé des jours prokéimasiques et épikéiniasiques :''' {{Info|''Aut enim circa diem statutum, aut ante, vel postea, tempestates fieri, compertum est : unde præcedentes, ωροϰεἰμασιν : nascentes die solenni, επιϰεἰμασιν : subsequentes, μεταϰεἰμασιν, græco vocabulo nuncuperaverunt''|Car on a constaté que les tempêtes se produisent soit vers le jour fixé, soit avant, soit après : d’où les précédents, ωροϰεἰμασιν : nés le jour solennel, επιϰεἰμασιν : les suivants, μεταϰεἰμασιν, étaient appelés par le mot grec. TdA.}} '''(IV, 40).''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Ideo_Virgilius_errantium_quoque_siderum_rationem_ediscendam_prœcipit_AdG_back|<span id="Ideo_Virgilius_errantium_quoque_siderum_rationem_ediscendam_prœcipit_AdG"><sup>3</sup></span>]] <p style="margin: 0 6em; text-indent: 0px">'''{{Info|Hoc metuens, cæli menses et sidera serva,<br />Frigida Saturni sese quo stella receptet.|Craignant cela, gardez les lunes et les étoiles du ciel, le froid de Saturne lui-même, où l’étoile les recevra. TdA.}}'''<p style="text-align: right; margin: 0 6em; text-indent: 0px">''Georg.'', I, 335.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Res_anceps_AdG_back|<span id="Res_anceps_AdG"><sup>4</sup></span>]] Voici enfin quelques idées philosophiques qui se trouvent sous la plume de Pline ; malheureusement la cause par laquelle notre auteur explique l’influence des astres est problématique, et montre que les sciences astronomiques des anciens laissaient beaucoup à désirer. Les Grecs croyaient qu’il y avait autant de cieux que de planètes ; le huitième ciel, ou le firmament, était celui dès étoiles fixés.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Occasum_matutinum_Vergiliarum_Hesiodus_AdG_back|<span id="Occasum_matutinum_Vergiliarum_Hesiodus_AdG"><sup>5</sup></span>]] L’ouvrage auquel Pline fait allusion a été mentionné par [[w:Théon_d'Alexandrie|Théon]] qui le nomme Αστριϰὴ βίϐλος [[w:en:Astronomia_(poem)|(en)]]. Cet ouvrage est perdu.'''</td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k5804072n <u>Histoire Naturelle de Pline. Tome Onzième</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k5804072n/f196.item ''Livre XVIII.''], [https://gallica.bnf.fr/ark:/12148/bpt6k5804072n/f340.item ''chap. LVII.''], traduction nouvelle par M. [[w:Stéphane_Ajasson_de_Grandsagne|Ajasson de Grandsagne]] [https://gallica.bnf.fr/ark:/12148/bpt6k5804072n/f453.item <sup>NOTES</sup>], C. L. F. Panckoucke, Paris, 1829</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: center; margin: 0 2em;">''Divi[[w:S_long|{{Info|ſ|forme ancienne longue de la lettre s minuscule}}]]<nowiki />ion des jours & des nuits [[w:S_long|{{Info|ſ|forme ancienne longue de la lettre s minuscule}}]]<nowiki />uivant le cours du Soleil ; lever & coucher des étoiles ; ordre des [[w:S_long|{{Info|ſ|forme ancienne longue de la lettre s minuscule}}]]<nowiki />ai[[w:S_long|{{Info|ſ|forme ancienne longue de la lettre s minuscule}}]]<nowiki />ons ; tems où l’on [[w:S_long|{{Info|ſ|forme ancienne longue de la lettre s minuscule}}]]<nowiki />eme les bleds d’hiver.''<br /><p style="text-align: justify; text-indent: 15px;">'''D'''’ABORD il e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t pre{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que impo{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ible de déterminer au ju{{Info|ſ|forme ancienne longue de la lettre s minuscule}}te le nombre des jours de l’année, & le cours du Soleil ; car comme aux trois cents {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oixante & cinq jours dont l’année e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t compo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ée, on ajoute le quart d’un jour & d’une nuit, autrement {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ix heures, qui, au bout de quatre ans, font un jour intercalaire [[#jour_intercalaire_LPdS|<span id="jour_intercalaire_LPdS_back"><sup>'''1'''</sup></span>]], il arrive qu’on ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}auroit a{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}igner avec certitude le tems du lever & du coucher des a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tres. En {{Info|ſ|forme ancienne longue de la lettre s minuscule}}econd lieu, l’on convient qu’il y a dans cette théorie beaucoup d’ob{{Info|ſ|forme ancienne longue de la lettre s minuscule}}curité ; car quelquefois les {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ons [[#quelques_les_saisons_LPdS|<span id="quelques_les_saisons_LPdS_back"><sup>'''2'''</sup></span>]] commencent plu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ieurs jours avant le terme qui leur a été fixé, ce que les Grecs appellent ''prokheïma{{Info|ſ|forme ancienne longue de la lettre s minuscule}}is'' ; & d’autres fois plu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ieurs jours après, ce que ces mêmes Grecs expriment par le mot ''epikheïma{{Info|ſ|forme ancienne longue de la lettre s minuscule}}is'' : & l’on éprouve très {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ouvent que l’action des a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tres {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ait {{Info|ſ|forme ancienne longue de la lettre s minuscule}}entir {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur la terre, tantôt plutôt, tantôt plus tard. Au{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}i dit-on communément, lor{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que le beau tems e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t revenu, que tel a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tre a produit {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on effet. D’ailleurs comme tout cela dépend des globes céle{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tes, leur mouvement relatif excite quelquefois des grêles & des pluies, qui, comme nous l’avons déja [[#déjà_fait_observer_LPdS|<span id="déjà_fait_observer_LPdS_back"><sup>'''3'''</sup></span>]] fait ob{{Info|ſ|forme ancienne longue de la lettre s minuscule}}erver, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont de la plus grande con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}équence pour les biens de la terre, & qui renver{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ent l’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}pérance qu’on avoit du beau tems. Et non {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eulement les hommes y {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont trompés, mais au{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}i les animaux, quoiqu’ils aient bien plus de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}agacité que nous pour pre{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}entir ces vici{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}itudes du ciel, d’autant que leur vie en dépend. En effet, on voit quelquefois les oi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}eaux d’été mourir par des froids qui viennent trop tard ou trop tôt, & les oi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}eaux d’hiver par des chaleurs qui arrivent de même. C’est pourquoi '''Virgile''' veut qu’on étudie au{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}i le cours des planetes, & qu’on ob{{Info|ſ|forme ancienne longue de la lettre s minuscule}}erve à quelle partie du zodiaque répond la planete du froid Saturne [[#Saturne_LPdS|<span id="Saturne_LPdS_back"><sup>'''4'''</sup></span>]]. Quelques-uns croient que le {{Info|ſ|forme ancienne longue de la lettre s minuscule}}igne le plus certain du printems commencé, c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t lor{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’on voit des papillons, & cela parceque ces in{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ectes {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont fort délicats. Néanmoins on a remarqué que dans l’année même [[#lAnnée_dÉcriture_LPdS|<span id="lAnnée_dÉcriture_LPdS_back"><sup>'''5'''</sup></span>]] où j’écris ceci, le froid ayant recommencé ju{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’à trois fois, a fait mourir autant de fois les papillons ; & que les hirondelles, qui, s’étant montrées dès le vingt-{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ept de Janvier, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}embloient annoncer le retour du printems, ont en{{Info|ſ|forme ancienne longue de la lettre s minuscule}}uite e{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}uyé un très cruel hiver.<br /><p style="text-align: justify; text-indent: 15px;">C’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t donc une {{Info|ſ|forme ancienne longue de la lettre s minuscule}}cience très problématique que celle de l’influence des a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tres, & les inductions que l’on en tire {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont fort douteuses. Mais ce qui cau{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e le plus d’incertitude, c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t cette convexité du ciel & la différence des climats de la terre, parceque le même a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tre {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e montre ici dans un tems, & là dans un autre, d’où il ré{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ulte que {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on influence ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e fait pas {{Info|ſ|forme ancienne longue de la lettre s minuscule}}entir en même tems par-tout. Un autre {{Info|ſ|forme ancienne longue de la lettre s minuscule}}urcroît de difficulté, c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t que les ob{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ervations recueillies par les Auteurs ont été faites en différents lieux, & que ceux même qui ont écrit dans le même endroit ne s’accordent nullement entre eux dans ce qu’ils écrivent. On compte ju{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’à trois différentes {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ortes de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ectes en A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tronomie ; {{Info|ſ|forme ancienne longue de la lettre s minuscule}}avoir, celle des Chaldéens [[#secte_des_Chaldéens_LPdS|<span id="secte_des_Chaldéens_LPdS_back"><sup>'''5*'''</sup></span>]], celle des Egyptiens & celle des Grecs. On peut même dire que le Dictateur Cé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ar [[#Dictateur_César_LPdS|<span id="Dictateur_César_LPdS_back"><sup>'''6'''</sup></span>]] en produi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}it, chez les Romains, une quatrieme, lor{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’il rédui{{Info|ſ|forme ancienne longue de la lettre s minuscule}}it chaque année au cours du {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oleil, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ervant à cet effet du travail de So{{Info|ſ|forme ancienne longue de la lettre s minuscule}}igene, très habile A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tronome. Néanmoins on découvrit en{{Info|ſ|forme ancienne longue de la lettre s minuscule}}uite que le calendrier de Cé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ar étoit défectueux [[#calendrier_César_défectueux_LPdS|<span id="calendrier_César_défectueux_LPdS_back"><sup>'''7'''</sup></span>]], parceque l’année qui auparavant étoit plus courte que le cours du {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oleil, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e trouvoit alors plus longue : & pour corriger cette erreur, on ordonna que pendant douze années de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uite, il n’y auroit point de jour intercalaire [[#correction_erreur_LPdS|<span id="correction_erreur_LPdS_back"><sup>'''8'''</sup></span>]]. So{{Info|ſ|forme ancienne longue de la lettre s minuscule}}igene lui-même, quoique Mathématicien plus exact que les autres, ne lai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}a pas de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e conduire con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tamment en homme qui doutoit de la ju{{Info|ſ|forme ancienne longue de la lettre s minuscule}}te{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}e de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on propre calcul, pui{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’il en fit ju{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’à trois différentes corrections. De tous les Auteurs [[#Auteurs_calendrier_LPdS|<span id="Auteurs_calendrier_LPdS_back"><sup>'''9'''</sup></span>]] qui ont écrit {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur cette matiere, & que nous avons allégués au commencement de ce livre, il s’en trouve rarement deux qui {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oient de même {{Info|ſ|forme ancienne longue de la lettre s minuscule}}entiment. Cette variété e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t moins {{Info|ſ|forme ancienne longue de la lettre s minuscule}}urprenante, comme au{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}i plus excu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}able, chez ceux qui écrivoient en des pays différents. Mais que dire de ceux qui, écrivant dans le même pays, n’ont pas lai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}é d’être partagés d’opinion ? En voici un exemple. '''Hé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iode''', dont il y a au{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}i un ouvrage [[#ouvrage_astronomique_Hésiode_LPdS|<span id="ouvrage_astronomique_Hésiode_LPdS_back"><sup>'''10'''</sup></span>]] {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur le cours des a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tres, dit que les Pléiades {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e couchent le matin dans le tems même de l’équinoxe d’automne. '''Thalès''' [[#opinion_Thalès_Hésiode_Anaximandre_LPdS|<span id="opinion_Thalès_Hésiode_Anaximandre_LPdS_back"><sup>'''11'''</sup></span>]] dit que cela arrive vingt-cinq jours après. '''Anaximandre''' en met vingt-neuf ; '''Euctémon''' [[#Euctémon_LPdS|<span id="Euctémon_LPdS_back"><sup>'''12'''</sup></span>]] quarante-huit.<br /><p style="text-align: justify; text-indent: 15px;">Quant à nous, nous {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uivrons le calcul de Cé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ar, ayant principalement égard à l’Italie. Nous ne lai{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}erons néanmoins de rapporter les opinions étrangeres, parceque notre objet n’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t pas de traiter d’un {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eul pays, mais de la Nature entiere. Seulement, pour éviter les longueurs, nous n’indiquerons que les pays où chaque opinion a lieu, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ans faire mention des auteurs de ces a{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ertions : & pour abréger encore davantage, les Lecteurs voudront bien {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ouvenir que quand il e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t parlé de l’Attique, il faut, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous ce nom, entendre au{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}i les Cyclades ; que {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous le nom de Macédoine, il faut entendre au{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}i la Magné{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ie & la Thrace ; {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous le nom de l’Egypte, la Phénicie, l’i{{Info|ſ|forme ancienne longue de la lettre s minuscule}}le de Chypre & la Cilicie; {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous celui de la Béotie, la Locride, la Phocide & les contrées voi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ines ; {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous le nom de l’Hel le{{Info|ſ|forme ancienne longue de la lettre s minuscule}}pont, la pre{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’i{{Info|ſ|forme ancienne longue de la lettre s minuscule}}le de Thrace & le pays de terre ferme, ju{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’au mont Athos ; {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous le nom de l’Ionie, l’A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ie & les i{{Info|ſ|forme ancienne longue de la lettre s minuscule}}les A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iatiques ; {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous le nom du Péloponne{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e, l’Achaïe & les contrées [[#contrées_adjacentes_ouest_Péloponnese_LPdS|<span id="contrées_adjacentes_ouest_Péloponnese_LPdS_back"><sup>'''13'''</sup></span>]] adjacentes qu’elle a à {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on couchant ; {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous le nom des Chaldéens, l’Assyrie & la Babylonie. Il ne faudra pas s’étonner {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i je ne parle ici ni de l’Afrique, ni de l’Espagne, ni des Gaules, pui{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que ces pays n’ont eu aucun Auteur qui ait écrit du cours des a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tres, ni de leur lever. Toutefois il ne {{Info|ſ|forme ancienne longue de la lettre s minuscule}}era pas difficile de connoître le tems où ils {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e levent dans ces pays-là même, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i l’on e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t in{{Info|ſ|forme ancienne longue de la lettre s minuscule}}truit de l’arrangement des cercles céle{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tes, tel que nous l’avons expliqué au {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ixieme livre de cet ouvrage ; car, par ce moyen, & par les {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eules notions que nous avons expo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ées en donnant une nomenclature des lieux, on {{Info|ſ|forme ancienne longue de la lettre s minuscule}}aura la po{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ition, non {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eulement de chaque pays, mais encore de chaque ville, en prenant par les ombres égales de tous les cercles, un {{Info|ſ|forme ancienne longue de la lettre s minuscule}}egment du cercle de tel pays qu’on voudra choi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ir, & en cherchant {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on rapport avec le lever des a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tres. Il faut remarquer au{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}i que de quatre [[#Columelle_LPdS|<span id="Columelle_LPdS_back"><sup>'''14'''</sup></span>]] en quatre ans les {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ons & les chaleurs reviennent à peu près les mêmes, & cela à cau{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e du mouvement du Soleil ; & que de huit en huit ans ces mêmes chaleurs reviennent plus con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}idérables, en vertu de la centieme lunai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}on.</div> {{Boîte déroulante début|titre=Notes du traducteur|alignT=center}} <div style="text-align: justify; border: 2px; border-radius:15px; font-size:85%;"><br/> <table cellspacing=15 align=center style="margin: 0 4em;"> <tr> <td style="text-align: justify; margin: 0 4em; text-indent: 15px">'''[[#jour_intercalaire_LPdS_back|<span id="jour_intercalaire_LPdS"><sup>1</sup></span>]] Con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ultez, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur toute cette que{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tion, nos notes 13 & 14 {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur le huitieme chapitre du {{Info|ſ|forme ancienne longue de la lettre s minuscule}}econd livre de Pline, tome 1, p. 41 & 42 :<br /><p style="text-align: justify; text-indent: 15px; margin: 0 5em;">(13) [[w:Suétone|Suétone]] s’exprime mieux, lor{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’il écrit : chaque quatrieme année ''quarto quoque anno''. Il est vrai que, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}elon le [[w:Jean_Hardouin|Pere Hardouin]], il faut comprendre dans la période de cinq ans, dont parle Pline, la premiere & la cinquieme année comme Bi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}extiles ; ce qui revient aux quatre années de Suétone, dont la quatrieme avoit un ''bi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ex'' ; mais en vérité cette explication est des plus forcées. Je {{Info|ſ|forme ancienne longue de la lettre s minuscule}}erois donc d’avis qu’il faudroit lire dans Pline comme dans Suétone, ''quarto anno'', {{Info|ſ|forme ancienne longue de la lettre s minuscule}}i nous n’apprenions d’ailleurs de cet Hi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}torien, que dès le regne d’Augu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}te il s’étoit déja gli{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}é plu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ieurs abus & altérations dans l’année Julienne. On voit du moins qu’il y réforma plu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ieurs cho{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es, sous prétexte de la remettre {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur le pied où Cé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ar l’avoit in{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tituée. Cela me donneroit à pen{{Info|ſ|forme ancienne longue de la lettre s minuscule}}er qu’on fit dès-lors attention à la fau{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}eté & à l’excédence du calcul Julien ; mais qu’Augu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}te, par respect pour la mémoire de Cé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ar, affecta d’imputer la faute à la négligence des Prêtres chargés à Rome de l’in{{Info|ſ|forme ancienne longue de la lettre s minuscule}}pection du Calendrier ; qu’au demeurant, on découvrit l’abus, & qu’on e{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}aya d’y remédier, en n’ajoûtant un jour entier à l’année ordinaire que chaque ''cinquieme année'' comme Pline paroît l’articuler ici expre{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ement. Mais d’ailleurs il e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t évident qu’à la longue le période bi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}extile de quatre années en quatre années prévalut {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur celui de chaque cinquieme année, dont parle Pline ; & même il paroît que ceux qui, par la {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uite, voulurent {{Info|ſ|forme ancienne longue de la lettre s minuscule}}upputer les tems, récapitulerent, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ans exception, toutes les bi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}extiles quartenaires écoulées depuis l’in{{Info|ſ|forme ancienne longue de la lettre s minuscule}}titution Julienne ; car en 1582, on trouva par ce moyen que l’année étoit reculée de dix jours & plus; d’autant que l’excédence du calcul Julien, qui {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uppo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e à l’année révolue 365 jours & {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ix heures, au lieu de 365 jours 5 heures 49 minutes, 8 {{Info|ſ|forme ancienne longue de la lettre s minuscule}}econdes 17 tierces & 13 quarts qu’elle a réellement, forme tous les ans environ 11 minutes de trop, & tous les cent trente-quatre ans un jour entier d’excès. Le Pape Grégoire XIII trouvant donc l’année reculée de plus de dix jours ; ce qui dérangeoit l’économie annuelle des {{Info|ſ|forme ancienne longue de la lettre s minuscule}}olemnités, remédia à cet inconvénient en retranchant de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on autorité dix jours au mois d’Octobre de l’année 1582, où l’on étoit alors ; & en réglant qu’à l’avenir tous les quatre cents ans on omettroit trois années bi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}extiles. Ce réglement devint une loi pour pre{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que toute l’Europe chrétienne. L’autre maniere de compter fut appellée l’ancien {{Info|ſ|forme ancienne longue de la lettre s minuscule}}tyle. La Grande-Bretagne a long-tems per{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i{{Info|ſ|forme ancienne longue de la lettre s minuscule}}té à s’en {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ervir malgré {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on abus manife{{Info|ſ|forme ancienne longue de la lettre s minuscule}}te. Enfin le Parlement d’Angleterre, par acte du mois de Septembre 1752, a adopté la réforme Grégorienne.<br /><p style="text-align: justify; text-indent: 15px; margin: 0 4em;">(14) Le {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oleil, en fai{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ant le tour du cercle oblique, parcourt réellement 360 degrés ou {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ections ; pui{{Info|ſ|forme ancienne longue de la lettre s minuscule}}que tout cercle {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e divi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e en 360 parties appellées degrés : mais la me{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ure de chaque degré du cercle parcouru annuellement par le {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oleil, excede tant {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oit peu, c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t-à-dire de quelques légeres fractions de tems, la durée de chacun de nos jours révolus ; durée qui n’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t, comme on {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ait, que de 24 heures préci{{Info|ſ|forme ancienne longue de la lettre s minuscule}}es ; le{{Info|ſ|forme ancienne longue de la lettre s minuscule}}quelles, comparées à un degré, en produi{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ent, au bout de l’année, 365 & plus pour le cercle, au lieu de 360 {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eulement que le cercle requerroit. D’après une connoi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ance con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}u{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e de ces principes, Jules Cé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ar {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e voyant Dictateur, Grand-Pontife, & maître du monde, entreprit, l’an 140 avant J. C. de réformer les abus qui s’étoient gli{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}és, tant dans l’année Pompilienne, ou de Numa, que dans celle des Pontifes, encore plus irréguliere que celle de Numa. A cet effet, il fit venir d’Alexandrie le Philo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ophe So{{Info|ſ|forme ancienne longue de la lettre s minuscule}}igenes. Celui-ci décida fau{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ement que le cercle des jours de l’année révolue excédoit du nombres 5 joint au quart de 1 les 360 degrés du cercle oblique parcouru par le {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oleil : expo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}é faux, auquel le Dictateur, occupé d’autres {{Info|ſ|forme ancienne longue de la lettre s minuscule}}oins, déféra {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ans autre examen. Jules Cé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ar régla donc, de l’avis de {{Info|ſ|forme ancienne longue de la lettre s minuscule}}on A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tronome, que l’année {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eroit divisée en 365 jours ; & quant au quart de jour re{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tant, qui produit {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ix heures, il ordonna qu’on n’y auroit aucun égard pour chaque année particuliere ; mais que chaque quatrieme année on réuniroit la totalité de quatre fois {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ix heures, qui en font vingt-quatre, pour en compo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}er un jour entier; & qu’ain{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i cette quatrieme année auroit 366 jours. Il régla de plus, que ce jour intercalaire, ou ajoûté à chaque quatrieme année, seroit le 24 Février. Les Romains nommoient ce jour-là ''bis {{Info|ſ|forme ancienne longue de la lettre s minuscule}}exto calendas Martii'', c’est-à-dire, le ''{{Info|ſ|forme ancienne longue de la lettre s minuscule}}econd {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ixieme avant les calendes de Mars'' ; d’où il arriva que l’année où tomboit ce jour intercalaire fut appellée bis-{{Info|ſ|forme ancienne longue de la lettre s minuscule}}extile.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#quelques_les_saisons_LPdS_back|<span id="quelques_les_saisons_LPdS"><sup>2</sup></span>]] Végece dit pareillement, liv. 4, chap. 40 : ''Aut enim circa diem {{Info|ſ|forme ancienne longue de la lettre s minuscule}}tatutum, aut ante, vel po{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tea, tempe{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tates fieri compertum e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t : unde præcedentes, ωροϰεἰμασιν : na{{Info|ſ|forme ancienne longue de la lettre s minuscule}}centes die {{Info|ſ|forme ancienne longue de la lettre s minuscule}}olenni, επιϰεἰμασιν : {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ub{{Info|ſ|forme ancienne longue de la lettre s minuscule}}equentes, μεταϰεἰμασιν, Græco vocabulo nuncuperaverunt'' [[#Accedit_confessa_rerum_obscuritas_AdG_back|<sup>⤴️</sup>]]. On lit au{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}i chez [[w:Columelle|Columelle]], dans {{Info|ſ|forme ancienne longue de la lettre s minuscule}}a Préface :''' {{Info|''Neque enim ſemper eumdem, cælum & annus, velut ex præſcripto habitum gerunt : nec omnibus annis eodem vultu venit aſtas, aut hyems, &c.''|Car le ciel et l’année ne portent pas toujours le même habit, comme par un précepte : ni l’automne n’arrive chaque année avec la même apparence, ni l’hiver, etc. TdA}} </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#déjà_fait_observer_LPdS_back|<span id="déjà_fait_observer_LPdS"><sup>3</sup></span>]] Au liv. 17, chap. 2.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Saturne_LPdS_back|<span id="Saturne_LPdS"><sup>4</sup></span>]] Ain{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i qu’il l’in{{Info|ſ|forme ancienne longue de la lettre s minuscule}}inue dans {{Info|ſ|forme ancienne longue de la lettre s minuscule}}es ''Géorg.'' liv. I, v. 335 :'''<br /><p style="margin: 0 6em; text-indent: 0px">{{Info|Hoc metuens, cæli menses et sidera serva,<br />Frigida Saturni sese quo stella receptet.|Craignant cela, gardez les lunes et les étoiles du ciel, le froid de Saturne lui-même, où l’étoile les recevra. TdA.}} </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#lAnnée_dÉcriture_LPdS_back|<span id="lAnnée_dÉcriture_LPdS"><sup>5</sup></span>]] Pline, au quatorzieme livre, chap. 4, comptoit deux cents trente ans depuis la mort de [[w:Cicéron|Cicéron]] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Cicéron_I|<sup>🔄</sup>]], arrivée l’an de Rome 600. L’année qu’il indique ici, & où il {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e trouvoit avoir compo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}é quatre livres de plus, e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t probablement la {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uivante, c’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t-à-dire l’année 831 de la fondation de Rome.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#secte_des_Chaldéens_LPdS_back|<span id="secte_des_Chaldéens_LPdS"><sup>5*</sup></span>]] Sur l’année Chaldéenne, qui étoit la même que la Judaïque, con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ultez [[w:Eusèbe_de_Césarée|Eu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ebe]], ''Præpar. Evang.'' liv. 9, chap. 17, où il fait Abraham inventeur de l’a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tronomie chez les Chaldéens. Les A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}trologues Chaldéens étoient ordinairement des Prêtres des Dieux, tels que [[w:Bérose|Béro{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e]], auquel les Athéniens éleverent dans leur Gymna{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e une {{Info|ſ|forme ancienne longue de la lettre s minuscule}}tatue à langue dorée. Sur quoi voyez Pline, liv. 7, chap. 37. Ce Béro{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e étoit un Prêtre de [[w:Bēl|Belus]] ; il e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}t cité par [[w:Clément_d'Alexandrie|Clément d’Alexandrie]], & par [[w:Flavius_Josèphe|Jo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}eph]] [[#Flavius_Josèphe_I|<sup>⤵️</sup>]], contre Apion, liv. 1. Sur l’année Egyptienne, & {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur l’ancienne année Grecque, con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ultez [[w:Hérodote|Hérodote]] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Hérodote_I|<sup>🔄</sup>]] liv. 2, n°. 4. Cicéron rend ju{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tice à l’étude que firent des a{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tres les Egyptiens & les Babyloniens, liv. 1, de ''Divinat.'' n°. 16 :''' {{Info|''Ægyptii, & Babylonii, in camporum patentium aquoribus habitantes, cùm ex terra nihil emineret, quod contemplationi cæli officere poſſet, omnem curam in ſiderum cognitione poſuerunt''|Les Égyptiens et les Babyloniens, vivant dans les eaux des plaines découvertes, alors que rien ne dépassait de la terre qui pût gêner la contemplation du ciel, mettaient tous leurs soins dans la connaissance des étoiles. TdA}}. </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Dictateur_César_LPdS_back|<span id="Dictateur_César_LPdS"><sup>6</sup></span>]] Voyez les notes 13 & 14 {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur le chap. 8 du liv. 2, tome 1, p. 41 & 42.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#calendrier_César_défectueux_LPdS_back|<span id="calendrier_César_défectueux_LPdS"><sup>7</sup></span>]] Voyez les notes indiquées dans la note précédente ; & joignez-y les ob{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ervations {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uivantes, qui {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont de M. De{{Info|ſ|forme ancienne longue de la lettre s minuscule}}places, p. 339 : « Le calendrier chrétien, ayant {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uivi la réformation de Jules Cé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ar, il {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e trouva qu’en l’année 1582, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ous le Pape Grégoire XIII, l’équinoxe étoit remontée ju{{Info|ſ|forme ancienne longue de la lettre s minuscule}}qu’au 11 de Mars, au lieu du 21, où elle devoit être. Ce Pape, après avoir con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ulté Clavius & Ciaconius, les plus habiles A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tronomes du tems, ordonna qu’en cette même année 1582, on compteroit le 5 du mois d’Octobre, au lieu du 15, afin de retrancher les dix jours qui s’étoient gli{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}és de trop, en {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uivant la {{Info|ſ|forme ancienne longue de la lettre s minuscule}}upputation Julienne, depuis le Concile de Nicée, tenu en 325 : on convint encore de continuer l’intercalation d’un jour tous les quatre ans ; & qu’en outre, pour éviter dans la {{Info|ſ|forme ancienne longue de la lettre s minuscule}}uite pareille erreur, il {{Info|ſ|forme ancienne longue de la lettre s minuscule}}eroit fait un retranchement de trois jours intercalaires, dans l’e{{Info|ſ|forme ancienne longue de la lettre s minuscule}}pace de quatre {{Info|ſ|forme ancienne longue de la lettre s minuscule}}iecles, à cau{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e des onze minutes qui manquent aux {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ix heures des années, dont on compo{{Info|ſ|forme ancienne longue de la lettre s minuscule}}e l’année intercalaire, ou bi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}extile ; ces trois jours {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e retranchent en l’année qui finit les trois premiers {{Info|ſ|forme ancienne longue de la lettre s minuscule}}iecles. De célebres A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}tronomes modernes ont fait voir que, malgré cette précaution, il y auroit encore, au bout de quatre cents ans, plu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ieurs jours de variation dans l’équinoxe ».''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#correction_erreur_LPdS_back|<span id="correction_erreur_LPdS"><sup>8</sup></span>]] Etabli par Jules Cé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ar, & qui revenoit tous les quatre ans. Ecoutons Suétone, vie de ce Dictateur, chap. 40 : {{Info|''Faſtos correxit, jampridem vitio Pontiſicum, per intercalandi licentiam adeo turbatos, ut neque meſſium feria aſtati, neque vindemiarum autumno competerent, annumque ad curſum ſolis accommodevit, ut CCCLXV dierum eſſet, & intercalario menſe ſublato, unus dies quarto quoque anno intercalaretur, &c''|Il corrigea les jeûnes, qui avaient toujours été une faute pontique, si perturbés par la permission de l’intercalation, que ni les fêtes du mois ne tenaient, ni les récoltes ne correspondaient à l’automne, et il ajusta l’année à la course du soleil, de sorte que c’était 365 jours, et après le mois intercalaire, un jour était intercalé tous les quatre ans, etc. TdA}}. On s’apperçut que cette correction de Jules Cé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ar étoit elle-même fautive. On tenta de nouveau de remédier au vice du calendrier ; {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur quoi con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ultez Solin, chapitre 1, p. 5 ; le P. Petau, ''de Doctr. temp.'' chap. 3 ; mais {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur-tout [[w:Macrobe|Macrobe]], qui s’exprime ain{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i, liv. 1, ''Saturn.'' chap. 14, p. 255 :''' {{Info|''Sacerdotes ſibi errorem novum ex ipſa emendatione ſecerunt. Nam cùm oporteret diem, qui ex quadrantibus conſit, quarto quoque anno conſecto, antequam quintus inciperet, intercalare, illi quarto non peracto ſed incipiente, intercalabant. Hic error ſex & triginta annis permanſit : quibus annis intercalati ſunt dies duodecim, cùm deberent intercalari novem. Sed hunc quoque errorem ſerò deprehenſum correxit Auguſtus, qui annos duodecim ſine intercalari die tranſigi juſſit : ut illi tres dies, qui per annos triginta & ſex vitio ſacerdotalis ſeſtinationis excreverant, ſequentibus annis duodecim, nullo die intercalato, devorarentur. Poſt hoc unum diem, ſecundùm ordinationem Caſaris, quinto quoque incipiente anno intercalari juſſit : & omnem hunc ordinem area tabula ad aternam cuſtodiam inciſione mandavit.''|Les prêtres retranchèrent une nouvelle erreur de leur correction. Car lorsqu’il fallait intercaler le jour qui est composé de quadrants, la quatrième année consécutive, avant que la cinquième ne commence, on intercalait ceux lorsque la quatrième n’était pas terminée mais commençait. Cette erreur a duré trente-six ans : années au cours desquelles douze jours ont été intercalés, alors qu’il aurait fallu en intercaler neuf. Mais cette erreur fut également détectée par Auguste, qui ordonna que douze années s’écoulèrent sans jour intercalaire : afin que ces trois jours, qui avaient été excrétés pendant les trente-six années du vice sacerdotal de cessation, soient dévorés dans le douze années suivantes, sans jour intercalaire. Après ce jour, selon l’ordonnance de César, il décréta que la cinquième année serait également intercalée : et tout l’ordre fut ordonné d’être gravé par le conseil du domaine pour la garde éternelle. TdA}}. </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Auteurs_calendrier_LPdS_back|<span id="Auteurs_calendrier_LPdS"><sup>9</sup></span>]] Ces Auteurs {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ont Hiéron, Philomêtor, Attale, Archelaüs, Xénophon, Magon, Caton, Silanus, Varron, &c. dont Pline a fait mention {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur la fin du chapitre 3.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#ouvrage_astronomique_Hésiode_LPdS_back|<span id="ouvrage_astronomique_Hésiode_LPdS"><sup>10</sup></span>]] Nous apprenons de Théon que cet ouvrage {{Info|ſ|forme ancienne longue de la lettre s minuscule}}e nommoit l’A{{Info|ſ|forme ancienne longue de la lettre s minuscule}}trique, Ἀςριϰὴ ϐίϐλος. Voyez au{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}i {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur ce même ouvrage, une Epigramme de [[w:Callimaque_de_Cyr%C3%A8ne|Callimaque]] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Callimaque_I_de_Cyrène_II|<sup>🔄</sup>]], citée dans la vie d’Aratus, qui fait partie de l’Uranologie de [[w:Denis_Pétau|Petau]], liv. 2, ''Var. Di{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ert.'' chap. 9, p. 97.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#opinion_Thalès_Hésiode_Anaximandre_LPdS_back|<span id="opinion_Thalès_Hésiode_Anaximandre_LPdS"><sup>11</sup></span>]] Con{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ultez, {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur cette opinion de Thalès, ain{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i que {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur celles d’Hé{{Info|ſ|forme ancienne longue de la lettre s minuscule}}iode & d’Anaximandre, l’Uranologie citée note précédente.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Euctémon_LPdS_back|<span id="Euctémon_LPdS"><sup>12</sup></span>]] ''Euctemon'' ; ain{{Info|ſ|forme ancienne longue de la lettre s minuscule}}i portent les manu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}crits, & non pas ''Eudemon''. J’ai traité d’Euctêmon (en Grec Εὐϰτημον) dans les notes alphabétiques du premier livre, & plus récemment dans la note 21 du chapitre précédent.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#contrées_adjacentes_ouest_Péloponnese_LPdS_back|<span id="contrées_adjacentes_ouest_Péloponnese_LPdS"><sup>13</sup></span>]] Telles que l’Elide, l’Arcadie, la Me{{Info|ſ|forme ancienne longue de la lettre s minuscule}}lénie.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Columelle_LPdS_back|<span id="Columelle_LPdS"><sup>14</sup></span>]] Columelle, liv. 3, chap. 6 :''' {{Info|''Quo tempore ſol in eamdem partem ſigniſeri per eoſdem numeros redit, per quos cursus ſui principium cæperat : quem circuitum meatus dierum integrorum mille quadringentorum ſexaginta unius [[w:Apocatastase|ὰ τοκατάςασιν]] vocant ſtudioſi rerum cæleſtium''|A ce moment-là, le soleil revient dans la même direction au moyen des mêmes nombres par lesquels il a commencé sa course : laquelle course de mille quatre cent soixante et un jours entiers est appelée ὰ τοκατάςασιν par ceux qui étudient les choses célestes. TdA}}.</td> </tr> </table><br/><br/></div> {{Boîte déroulante fin}} <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=JeyFTzG771cC&newbks=1&newbks_redir=0&dq=Louis%20Poinsinet%20de%20Sivry%20Pline%20l'ancien&hl=fr&pg=PP9#v=onepage&q&f=true <u>Histoire Naturelle de Pline. Tome Sixieme</u>], [https://books.google.fr/books?id=JeyFTzG771cC&newbks=1&newbks_redir=0&dq=Louis%20Poinsinet%20de%20Sivry%20Pline%20l'ancien&hl=fr&pg=PA257#v=onepage&q&f=true ''Livre Dix-huitieme.''], [https://books.google.fr/books?id=JeyFTzG771cC&newbks=1&newbks_redir=0&dq=Louis%20Poinsinet%20de%20Sivry%20Pline%20l'ancien&hl=fr&pg=PA455#v=onepage&q&f=true ''Diviſion des jours & des nuits ſuivant le cours du Soleil ; lever & coucher des étoiles ; ordre des ſaiſons ; tems où l’on ſeme les bleds d’hiver.''], traduction en françois, avec le texte latin rétabli d’après les meilleures leçons manu{{Info|ſ|forme ancienne longue de la lettre s minuscule}}crites ; accompagnée de Notes critiques pour l’éclairci{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ement du texte, & d’Ob{{Info|ſ|forme ancienne longue de la lettre s minuscule}}ervations {{Info|ſ|forme ancienne longue de la lettre s minuscule}}ur les connoi{{Info|ſſ|forme ancienne longue de la lettre s minuscule}}ances des Anciens comparées avec les découvertes des Modernes, par M. [[w:Louis_Poinsinet_de_Sivry|Louis Poinsinet de Sivry]], Chez la veuve Desaint, Paris, 1771</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div> </div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ==== Livre XXXVI ==== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Enquête sur la nature des pierres.</div> ===== <div style="text-align: center;">Chapitre XVII.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage de la mesure de la hauteur des pyramides et autres édifices semblables par comparaison des longueurs d'ombre, par '''Thalès'''.</div> :'''Texte latin''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''XVII.''' [...] Mensuram altitudinis earum omniumque similium deprehendere, invenit '''Thales''' ''Milesius'' umbram metiendo, qua hora par esse corpori solet.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=L249AAAAcAAJ&hl=fr&pg=PP11#v=onepage&q&f=false <u>Histoire Naturelle de Pline ― Tome Second</u>], [https://books.google.fr/books?id=L249AAAAcAAJ&hl=fr&pg=PA500#v=onepage&q&f=false ''Livre XXXVI.''], [https://books.google.fr/books?id=L249AAAAcAAJ&hl=fr&pg=PA513#v=onepage&q&f=false ''Chap. XVII.''], texte corrigé par [[w:Émile_Littré|M. É. Littré]], à partir de celui de [[w:Jean_Hardouin|Hardouin]], Librairie de Firmin-Didot et C<sup>ie</sup>, Paris, 1850<br />(également disponible une édition de 1877 sur [https://gallica.bnf.fr/ark:/12148/bpt6k282082c/f517.image ''Gallica''], ainsi qu’une édition de 1838 par [[w:Stéphane_Ajasson_de_Grandsagne|Ajasson de Grandsagne]] également sur [https://gallica.bnf.fr/ark:/12148/bpt6k1522394n/f179.item ''Gallica''])</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''XVII.''' [...] Le moyen de mesurer la hauteur des pyramides et autres édifices semblables, fut trouvé par '''Thalès''' de ''Milet'' : il mesura l’ombre à l’heure où elle est égale aux corps.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://books.google.fr/books?id=L249AAAAcAAJ&hl=fr&pg=PP11#v=onepage&q&f=false <u>Histoire Naturelle de Pline ― Tome Second</u>], [https://books.google.fr/books?id=L249AAAAcAAJ&hl=fr&pg=PA500#v=onepage&q&f=false ''Livre XXXVI.''], [https://books.google.fr/books?id=L249AAAAcAAJ&hl=fr&pg=PA513#v=onepage&q&f=false ''Chap. XVII.''], texte corrigé par [[w:Émile_Littré|M. É. Littré]], à partir de celui de [[w:Jean_Hardouin|Hardouin]], Librairie de Firmin-Didot et C<sup>ie</sup>, Paris, 1850<br />(également disponible une édition de 1848 sur [https://remacle.org/bloodwolf/erudits/plineancien/livre36.htm ''Remacle''], sur [[s:Histoire_naturelle_(trad._Littré)/XXXVI|''wikisource'']] et une édition de 1877 sur [https://gallica.bnf.fr/ark:/12148/bpt6k282082c/f517.image ''Gallica''])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: justify; text-indent: 15px; margin: 0 2em;">'''XVII.''' [...] '''Thalès''' découvrit le moyen de mesurer et les pyramides et toutes les hauteurs semblables par la mesure de l’ombre à l’instant où elle est égale au corps.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k1522394n/f9.item <u>Histoire Naturelle de Pline. Tome Vingtième</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k1522394n/f127.item ''Livre XXXVI.''], [https://gallica.bnf.fr/ark:/12148/bpt6k1522394n/f179.item ''chap. XVII.''], traduction nouvelle par M. [[w:Stéphane_Ajasson_de_Grandsagne|Ajasson de Grandsagne]], C. L. F. Panckoucke, Paris, 1838</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Flavius_Josèphe|'''Flavius Josèphe''']] [[#Flavius_Josèphe|<span id="Flavius_Josèphe_back"><sup>'''I'''</sup></span>]] == <p style="text-align: right;">([[w:37|37]]/[[w:38|38]], à [[w:Histoire_de_Jérusalem#Période_romaine_et_byzantine_(63_av._J.-C._-_638)|''Jérusalem'']] — vers [[w:100|100]], à [[w:Rome_antique|''Rome'']]) [[w:Ier_siècle|<sup>⏳</sup>]] [[s:Auteur:Flavius_Josèphe|<sup>📚</sup>]] <div style="text-align: justify; margin: 0 1em; text-indent: 15px">[[w:historiographe|Historiographe]] ''romain'' [[w:Juifs|''juif'']] d’origine [[w:Judée_(province romaine)|''judéenne'']], il participe activement au début de la ''première guerre judéo-romaine'' en tant que commandant militaire de ''Galilée'' contre les Romains, avant de se rendre à [[w:Vespasien|'''Vespasien''']] [[#Vespasien|<span id="Vespasien_back"><sup>'''II'''</sup></span>]] lors de la prise de la garnison juive de la forteresse de [[w:Jotapata|''Jotapata'']] en juillet 67, et de devenir intermédiaire, interprète et négociateur entre les ''romains'' et les ''Juifs'' lors du siège de ''Jérusalem'' conduit par '''Titus''' [[#Titus_back|<sup>⤴️</sup>]] en 70. Après la fin de la grande révolte ''judéenne'', en 71, il s’établit auprès de son protecteur à ''Rome'' où il obtient la [[w:citoyenneté_romaine|''citoyenneté romaine'']].</div> {{Boîte déroulante début|titre=NdA Flavius Josèphe|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Flavius_Josèphe_back|<span id="Flavius_Josèphe"><sup>I</sup></span>]] De son nom de naissance Joseph ben (fils de) Matthatias, de l’hébreu יוסף בן מתתיהו / Yossef [[wikt:en:יוסף#Hebrew|(en)]] ben [[wikt:en:בן#Noun|(en)]] Matityahou [[wikt:en:מתתיהו#Hebrew|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;">• de la troisième personne du singulier [[w:Jussif|''jussive'']], signifiant ainsi « peut-il ajouter », du verbe הוֹסִיף / hosíf [[wikt:en:הוסיף#Hebrew|(en)]], « 1. Ajouter (quelque chose) à (quelque chose d'autre). 2. (littéraire) Continuer (à faire quelque chose). 3. (archaïque) Coordonné avec un autre verbe pour indiquer que l’action de ce verbe "ajoute" d’une manière ou d’une autre. »;<br /><p style="margin: 0 2em; text-indent: 15px;">• du nom commun בֵּן / bén, « 1. Fils. 2. (ne produit plus de mot ou d’expression) Un descendant mâle direct. 3. Un mec, un garçon. 4. (n’est plus productif, état de construction) Possesseur de (connaissance, capacité, etc.). 5. (État construit) Utilisé pour exprimer l’âge d’un homme, d’un garçon ou le référent d’un nom masculin : âge, âgé. »;<br /><p style="margin: 0 2em; text-indent: 15px;">• de la contraction du nom commun מַתָּנַת / mataná [[wikt:en:מתנה#Hebrew|(en)]], « cadeau, présent, don »;<br /><p style="margin: 0 2em; text-indent: 30px;">➥ du verbe נתן / natán [[wikt:en:נתן#Verb|(en)]], « 1. Donner. 2. Autoriser, permettre, laisser. 3. (archaïque) Mettre, placer. 4. (archaïque, hébreu biblique) Se transformer en. »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ et du nom propre יהוה / YHWH [[wikt:en:יהוה#Hebrew|(en)]], « (Judaïsme) Tétragramme : mot en quatre lettres hébraïques utilisé comme nom [[wikt:ineffable#Français|''ineffable'']] de Dieu dans la Bible hébraïque, diversement rendu par Yahweh ou Jéhovah. »;<br /><p style="margin: 0 2em; text-indent: 15px;">Son tria nomina à l’obtention de sa ''citoyenneté romaine'' est {{Info|Titus|praenomen, nom individuel du citoyen romain}} {{Info|Flavius|nomen, nom de famille}} {{Info|Josephus|cognomen, surnom héréditaire, servant à distinguer les diverses branches d’une même gens}}, prenant ainsi le nom de son bienfaiteur :<br /><br /><p style="margin: 0 2em; text-indent: 15px;">[[#Vespasien_back|<span id="Vespasien"><sup>II</sup></span>]] [[w:Nom_romain|Tria Nomina]] en latin {{Info|Titus|praenomen, nom individuel du citoyen romain}} {{Info|Flavius|nomen, nom de famille}} {{Info|Vespasianus|cognomen, surnom héréditaire, servant à distinguer les diverses branches d’une même gens}};<br /><p style="margin: 0 2em; text-indent: 15px;">[[w:L%C3%A9gat_(Rome_antique)|''Légat'']] lors de la [[w:Conqu%C3%AAte_romaine_de_la_Grande-Bretagne|''conquête de la Bretagne en 43'']] et lors de la [[w:Premi%C3%A8re_guerre_jud%C3%A9o-romaine|''rébellion juive de 66'']] en [[w:Jud%C3%A9e_(province_romaine)|''Judée'']]. Fin décembre 69, il est couronné empereur par le [[w:S%C3%A9nat_romain|''Sénat'']] après la guerre civile de l’[[w:Ann%C3%A9e_des_quatre_empereurs|''année des quatre empereurs'']], et fonde la dynastie des [[w:Flaviens|''Flaviens'']].<br /><p style="text-align: right; margin: 0 2em;">(17 novembre [[w:9|9]], près de [[w:Reate|''Reate'']] dans la région centrale italienne du [[w:Latium|''Latium'']] — 23/24 juin [[w:79|79]], à la station thermale de [[w:Aquae_Cutiliae|''Aquae Cutiliae'']], à l’est de ''Reate'')<sup>[[w:Ier_siècle|⏳]]</sup><br/><br/></div> ''' {{Boîte déroulante fin}} === [[w:Contre_Apion|Contre Apion]] === <p style="text-align: right;">[[s:Contre_Apion|📚]] {| cellpadding="0" align="{{{align|right}}}" style="margin-left: 2em; width:40%; border-spacing:3px; text-align:center; background-color:#F8F9FA; border:2px solid #C8CCD1" |- | style="border:solid 1px #F8F9FA" | [https://archive.org/details/contreapiontexte0000jose/page/n156/mode/1up {{Info|'''Éditions & Manuscrits'''|Flavius Josèphe Contre Apion, Théodore Reinach & Léon Blum, 1930}}] |- style="font-size:8pt; line-height:10pt; vertical-align:middle" | align="center" | <div style="margin-right: 1em; padding:0 0 4px 0; text-align:justify;">{{{légende| * La traduction ''latine'' a été imprimée dès 1480 à [[w:Vérone#Époque_moderne|''Vérone'']] par '''Pierre Maufer''' [[w:en:Petrus_Maufer|(en)]]. L’édition de cette traduction, due à [[w:Sigismund_Gelenius|'''Sigismond Gelenius''']] (''Paris'', 1535), qui constitue la « [[w:Vulgate|Vulgate]] », présente un texte souvent « amélioré » de façon arbitraire. La seule édition critique est celle de '''Ch. Boysen''' (''Vienne'', 1898) qui fait partie du [[w:Corpus_scriptorum_ecclesiasticorum_latinorum|{{Info|''Corpus scriptorum ecclesiasticorum latinorum''|Le corpus des écrits ecclésiastiques latins}}]]. Elle repose principalement sur les manuscrits L(aurentianus LXVI, 2), B(odleianus Canonicianus 148), R(egius Parisinus 5049) de la I<sup>re</sup> classe, C(heltenhamensis Phillipicus 12311), P(arisinus 1615), Pa(rsinus 5054) de la seconde. * Le texte grec est édité pour la première fois dans l’édition complète de '''Josèphe''' à [[w:Bâle#XVIe_siècle|''Bâle'']], chez [[w:Johann_Froben|''Froben'']], en 1544 par [[w:Arnoldus_Arlenius|'''Arlenius''']] qui a peut-être fait usage du ''Schleusingensis'' (un des fils du Laurentianus), mais a introduit grand nombre de corrections tantôt heureuses, et tantôt arbitraires. Par la suite notre traité n’a guère été imprimé que comme partie intégrante d’éditions complètes des œuvres de '''Josèphe'''. Les plus importantes sont celles de '''E. Bernard''' (1700), de [[w:John_Hudson_(classiciste)|'''Hudson''']] (1720) — le premier qui ait utilisé L —, de [[w:Sigebert_Havercamp|'''Havercamp''']] (1726), simple compilateur, de [[w:Karl_Wilhelm_Dindorf|'''L. Dindorf''']] (1847), de [[w:Immanuel_Bekker|'''Imm. Bekker''']] (1856), tout à fait manquée. L’édition critique de '''Niese''' [[w:en:Benedikt_Niese|(en)]] (1889) est la base de tous les travaux ultérieurs, notamment des éditions de '''Naber''' (1896) et de [[w:Henry_St._John_Thackeray|'''H. St. J. Thackeray''']] (coll. Loeb, 1926 : il n’a encore paru que le ''C. Apion'', la ''Vita'' et le commencement de la ''Guerre'') qui ont pu profiter aussi des conjectures de '''Cobet''', de '''Holwerda''', et de '''Herwerden'''.}}}</div> |} <div style="text-align: justify; margin: 0 1em; text-indent: 15px">Dernière œuvre écrite par '''Flavius Josèphe''', vers [[w:93|93]], dont l’objectif est de répondre aux critiques qu’ont soulevées ses [[w:Antiquit%C3%A9s_juda%C3%AFques|''Antiquités judaïques'']], de défendre l’ancienneté du peuple ''juif'' et du [[w:Judaïsme#Judaïsme_antique|''judaïsme'']] (Livre I) et les accusations d’[[w:Apion_(grammairien)|'''Apion''']] [[#Apion|<span id="Apion_back"><sup>'''I'''</sup></span>]] (Livre II).</div> {{Boîte déroulante début|titre=NdA Apion|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Apion_back|<span id="Apion"><sup>I</sup></span>]] Du nom propre grec ancien [[wikt:Apion#Latin|Ἀπίων / Apíôn]]; <br/><br /><p style="margin: 0 2em; text-indent: 15px;">'''[[w:Grammaticus|''Grammairien'']] [[#grammairien|<span id="grammairien_back"><sup>II</sup></span>]] et [[w:Polygraphe_(auteur)|''polygraphe'']] [[#polygraphe|<span id="Grammairien_back"><sup>III</sup></span>]] ''grec'' d’Alexandrie.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] seconde moitié du [[w:Ier_siècle_av._J.-C.|I<sup>er</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]] — première moitié du [[w:Ier_siècle|I<sup>er</sup> siècle {{Info|EC|de l’Ère Commune}}]]) <br /><br /><p style="margin: 0 2em; text-indent: 15px;">'''[[#grammairien_back|<span id="grammairien"><sup>II</sup></span>]] Du nom commun latin grammaticus [[wikt:en:grammaticus#Latin|(en)]]; du nom commun grec ancien γραμματικός / grammatikós [[wikt:en:γραμματικός#Noun|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px">➥ du nom commun γρᾰ́μμᾰ / grámma [[wikt:en:γράμμα#Noun|(en)]], « 1. Ce qui est écrit, ce qui est dessiné. 2. Lettre. 3. (au pluriel) Alphabet. 4. Écriture, livre. »;<br /><p style="margin: 0 2em; text-indent: 30px">➥ du verbe γράφω / gráphō [[wikt:en:γράφω#Ancient_Greek|(en)]], « 1. (Homérique) égratigner, couper en dedans. 2. Dessiner, esquisser, peindre. 3. Écrire. 4. Écrire, proposer une loi. 5. ([[w:Diathèse#Moyen|''voix moyenne'']]) : • (''[[w:Réflexivité_(grammaire)|réflexif]] indirect'') Écrire pour soi, noter ; • Accuser, poursuivre. 6. ([[w:Conjugaison_latine|''passif parfait'']]) Être écrit, être sous forme écrite. »;<br /><p style="margin: 0 2em; text-indent: 30px">➥ + du suffixe nominal de résultat‎ -μα / -ma [[wikt:en:-μα#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px">➥ +‎ du suffixe adjectival -ῐκός / -ikós, de ou se rapportant à, de la manière de ; « -ique »;<br /><p style="margin: 0 2em; text-indent: 15px">Enseignant responsable de la deuxième étape du système éducatif traditionnel, après l’apprentissage de l’alphabet, la lecture et l’écriture, et l’initiation au calcul avec un abaque chez un ''magister ludi'' [[w:en:Ludi_magister|(en)]] et avant celle de l’art du discours chez un [[w:Rhétorique#Rhétorique_dans_l'Antiquité_grecque|''rhéteur'']]. Le travail du grammairien était d’enseigner la lecture, l’analyse de textes des poètes antiques tels qu’Homère, Tite-Live et Virgile, et la grammaire [https://archive.wikiwix.com/cache/index2.php?url=http%3A%2F%2Fwww.antiquite.ac-versailles.fr%2Feducatio%2Fedrom2.htm#federation=archive.wikiwix.com&tab=url {{Info|<sup>➕</sup>|« L’école du grammaticus », ac-Versailles}}] [https://philo-lettres.fr/latin/rome_vie-quotidienne/ecole-romaine/ {{Info|<sup>➕➕</sup>|« L’École dans l’antiquité romaine, philo-lettres}}]. <br /><br /><p style="margin: 0 2em; text-indent: 15px;">'''[[#polygraphe_back|<span id="polygraphe"><sup>III</sup></span>]] Du nom commun grec ancien [[wikt:polygraphe|πολύγραφος / polýgraphos]], « qui écrit beaucoup de sujets »;<br /><p style="margin: 0 2em; text-indent: 15px">➥ de l’adjectif πολῠ́ς / polús [[wikt:en:πολύς#Ancient_Greek|(en)]], « (de nombre, au pluriel) Beaucoup de : • (avec des noms de multitude) Grand ; • (de quantité, avec des noms de masse) beaucoup de ; • (rare, d'une personne) Grand, puissant ; • (de son) Fort ; • (attributivement, adverbial) Fortement, pleinement ; • (d'espace) Large, grand ; • (de distance) Loin ; • (de temps) Long, en retard. »;<br /><p style="margin: 0 2em; text-indent: 15px">➥ +‎ du verbe γράφω / gráphō [[wikt:en:γράφω#Ancient_Greek|(en)]], « 1. (Homérique) égratigner, couper en dedans. 2. Dessiner, esquisser, peindre. 3. Écrire. 4. Écrire, proposer une loi. 5. (''voix moyenne'') : • (''réflexif indirect'') Écrire pour soi, noter ; • Accuser, poursuivre. 6. (''passif parfait'') Être écrit, être sous forme écrite. »;<br /><p style="margin: 0 2em; text-indent: 15px;">Le terme semble avoir été employé au cours de l’Antiquité dans un sens différent de celui que nous l’entendons aujourd’hui, pas dans le sens de diversité mais, de façon restreinte, le fait de composer un grand nombre de textes [https://eriac.univ-rouen.fr/la-polygraphie-comme-norme/ {{Info|<sup>➕</sup>|Isabelle Gassino, Université de Rouen et Dimitri Kasprzyk, université de Brest, « Colloque "La polygraphie comme norme" », 16 et 17 novembre 2017.}}].'''<br/><br/></div> {{Boîte déroulante fin}} ==== Livre I ==== ===== <div style="text-align: center;">Chapitre II.</div> ===== <div style="text-align: justify; margin: 0 1em;">Témoignage de '''Thales''' comme : * l’un des premiers ''philosophes grecs'' ayant traité des choses célestes et divines ; * disciple des ''Égyptiens'' et des ''Chaldéens'' (premier témoignage) ; * auteur de court(s)/rare(s) ouvrages (supposément unanimement admis), que les ''Grecs'' considéreraient comme les plus anciens, et douteraient, selon '''Flavius Josèphe''', de leur authenticité.</div> :'''Texte latin''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">qui autem historias apud eos conscribere temptauerunt, id est hi, qui circa '''Cadmum''' ''Milesium'', et '''Acusilaus''' ''Argiuus'' et post hunc quicumque alii fuisse referuntur, paululum tempus ''Persicam'' apud ''Helladium'' militiam praecesserunt. sed etiam eos, qui de caelestibus et diuinis primitus apud ''Graecos philosophati'' sund, id est '''Pherecydem''' ''Syrum'' et '''Pythagoram''' et '''Thaletem''' omnes concorditer confidentur ''Aegyptiorum'' et ''Chaldaeorum'' fuisse discipulos et breuiter conscripsisse quae a ''Graecis'' omnium antiquissima iudicantur ita ut uix ea credant ab illis fuisse conscripta.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[[w:Corpus_scriptorum_ecclesiasticorum_latinorum|<u>Corpus scriptorum ecclesiasticorum latinorum</u>]], [https://verlag.oeaw.ac.at/produkt/flavii-iosephi-opera-ex-versione-latina-antiqua-pars-vi-de-iudaeorum-vetustate-sive-contra-apionem-libri-ii/601067?name=flavii-iosephi-opera-ex-versione-latina-antiqua-pars-vi-de-iudaeorum-vetustate-sive-contra-apionem-libri-ii&product_form=5107 <u>Tome XXXVII, Flavius Iosephus, Contra Apionem</u>], ''Livre I'', ''chap. II.'', ''l.13, 14'', p.64, 1898</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">Οἱ μέντοι τὰς ἱστορίας ἐπιχειρήσαντες συγγράφειν παρ' αὐτοῖς, λέγω δὲ τοὺς περὶ '''Κάδμον''' τε τὸν ''Μιλήσιον'' καὶ τὸν ''Ἀργεῖον'' '''Ἀκουσίλαον''' καὶ μετὰ τοῦτον εἴ τινες ἄλλοι λέγονται γενέσθαι, βραχὺ τῆς ''Περσῶν'' ἐπὶ τὴν ''Ἑλλάδα'' στρατείας τῷ χρόνῳ προύλαβον. Ἀλλὰ μὴν καὶ τοὺς περὶ τῶν οὐρανίων τε καὶ θείων πρώτους παρ' ''Ἕλλησι φιλοσοφήσαντας'', οἷον '''Φερεκύδην''' τε τὸν ''Σύριον'' καὶ '''Πυθαγόραν''' καὶ '''Θάλητα''', πάντες συμφώνως ὁμολογοῦσιν ''Αἰγυπτίων'' καὶ ''Χαλδαίων'' γενομένους μαθητὰς ὀλίγα συγγράψαι, καὶ ταῦτα τοῖς ''Ἕλλησιν'' εἶναι δοκεῖ πάντων ἀρχαιότατα καὶ μόλις αὐτὰ πιστεύουσιν ὑπ' ἐκείνων γεγράφθαι.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://remacle.org/bloodwolf/historiens/Flajose/Apion1gr.htm <u>Φλαίίου Ἰωσήπου, περὶ ἀρχαιότητος Ἰουδαίων</u>, ''λόγος α''], ''chap. II.'', ''l.13, 14'', 1898</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">Quant aux Grecs qui ont entrepris d’écrire l’histoire, comme [[w:Cadmos_de_Milet|'''Cadmos''' de ''Milet'']], [[w:Acousilaos|'''Acousilaos''' d’Argos]] et ceux qu’on cite après lui, ils n’ont vécu que peu de temps [[#Cadmos_NdT_LB|<span id="Cadmos_NdT_LB_back"><sup>1</sup></span>]] avant [[w:Guerres_médiques|''l’expédition des Perses contre la Grèce'']]. Mais bien certainement les premiers ''philosophes grecs'' qui aient traité des choses célestes et divines, comme [[w:Phérécyde_de_Syros|'''Phérécyde''' de ''Syros'']] [[#Phérécyde_de_Syros_NdT_LB|<span id="Phérécyde_de_Syros_NdT_LB_back"><sup>2</sup></span>]], '''Pythagore''' et '''Thalès'''[[#Thales_NdT_LB|<span id="Thales_NdT_LB_back"><sup>3</sup></span>]] furent, tout le monde s’accorde là-dessus, les disciples des ''Égyptiens'' et des ''Chaldéens'' avant de composer leurs courts ouvrages, et ces écrits sont aux yeux des ''Grecs'' les plus anciens de tous ; à peine même les croient-ils authentiques.</div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Cadmos_NdT_LB_back|<span id="Cadmos_NdT_LB"><sup>1.</sup></span>]] En réalité, Cadmos paraît avoir fleuri vers le milieu [[w:VIe_siècle_av._J.-C.|VI<sup>ème</sup> siècle]] [{{Info|AEC|Avant l’Ère Commune}}].''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Phérécyde_de_Syros_NdT_LB_back|<span id="Phérécyde_de_Syros_NdT_LB"><sup>2</sup></span>]] Seul texte qui attribue une origine égyptienne ou chaldéenne aux doctrines de Phérécyde de Syros. Cependant [[w:Theodor_Gomperz|Gompers]], [https://archive.org/details/bub_gb_QrfVAAAAMAAJ/page/n434/mode/1up Griechische Denker, I, 430], identifie ᾿Ογηνός avec l’Ouginna babylonien.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Thales_NdT_LB_back|<span id="Thales_NdT_LB"><sup>3</sup></span>]] On retrouve chez [[w:Apollonios_de_Tyane|Apollonios de Tyane]] ([[w:Jamblique|Jamblique]] [[#Jamblique_back|<sup>⤵️</sup>]], Vit. Pyth. [[#Vie_de_Pythagore_back|<sup>⤵️</sup>]], 12) et [[w:Plutarque|Plutarque]] [[#Plutarque_back|<sup>⤵️</sup>]] l’idée que Thalès de Milet fut disciple des Égyptiens ; l’adjonction des Chaldéens est propre Josèphe.''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/contreapiontexte0000jose/page/n6/mode/1up?view=theater <u>Flavius Josèphe, Contre Apion</u>], ''Livre I'', [https://archive.org/details/contreapiontexte0000jose/page/n49/mode/1up?view=theater&q=Thales ''chap. 2''], traduction du grec ancien par Léon Blum, agrégé des Lettres, professeur au lycée Janson-de-Sailly, texte établi et annotée par [[w:Théodore_Reinach|Théodore Reinach]] Membre de l’[[w:Institut_de_France|Institut]], professeur au Collège de France, 1930<br />(édition bilingue de 1911 également disponible [https://remacle.org/bloodwolf/historiens/Flajose/Apion1.htm ici])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-align: justify; margin: 0 2em;">Quant aux Grecs qui ont entrepris d’écrire l’histoire, comme '''Cadmos''' de ''Milet'', '''Acousilaos''' d’''Argos'' et ceux qu’on nomme après lui, ils n’ont vécu que peu de temps[2] avant l’expédition des ''Perses'' contre la ''Grèce''. [14]. De même, les premiers ''philosophes grecs'' qui aient traité des choses célestes et divines, comme '''Phérécyde''' de ''Syros''[3], '''Pythagore''' et '''Thalès'''[4] furent, tout le monde s’accorde là dessus, les disciples des ''Égyptiens'' et des ''Chaldéens'' avant de composer leurs rares ouvrages, et ces écrits sont aux yeux des ''Grecs'' les plus anciens de tous ; à peine même les croient-ils authentiques.</div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Cadmos_NdT_LB_back|<span id="Cadmos_NdT_LB"><sup>1.</sup></span>]] En réalité, Cadmos paraît avoir fleuri vers le milieu [[w:VIe_siècle_av._J.-C.|VI<sup>ème</sup> siècle]] [{{Info|AEC|Avant l’Ère Commune}}].''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Phérécyde_de_Syros_NdT_LB_back|<span id="Phérécyde_de_Syros_NdT_LB"><sup>2</sup></span>]] Seul texte qui attribue une origine égyptienne ou chaldéenne aux doctrines de Phérécyde de Syros. Cependant [[w:Theodor_Gomperz|Gompers]], [https://archive.org/details/bub_gb_QrfVAAAAMAAJ/page/n434/mode/1up Griechische Denker, I, 430], identifie ᾿Ογηνός avec l’Ouginna babylonien.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Thales_NdT_LB_back|<span id="Thales_NdT_LB"><sup>3</sup></span>]] On retrouve chez [[w:Apollonios_de_Tyane|Apollonios de Tyane]] ([[w:Jamblique|Jamblique]] [[#Jamblique_back|<sup>⤵️</sup>]], Vit. Pyth. [[#Vie_de_Pythagore_back|<sup>⤵️</sup>]], 12) et [[w:Plutarque|Plutarque]] [[#Plutarque_back|<sup>⤵️</sup>]] l’idée que Thalès de Milet fut disciple des Égyptiens ; l’adjonction des Chaldéens est propre Josèphe.''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Flavius Josèphe, De l’ancienneté du peuple juif (Contre Apion)</u>, ''Livre I'', [[s:Page:Flavius_Josephe_-_Leon_Blum_-_Contre_Apion,_Leroux,_Paris,_1902.djvu/17|''Chap. 2'']], traduction de Léon Blum, agrégé des lettres, professeur au lycée du Havre, sous la direction de [[w:Théodore_Reinach|Théodore Reinach]], 1902.</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div> </div> <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Plutarque|'''Plutarque''']] [[#Plutarque|<span id="Plutarque_back"><sup>'''I'''</sup></span>]] == <p style="text-align: right;">([[w:Circa|{{Info|''ca.''|Circa, locution latine que l’on emploie pour indiquer l’approximation d’une date}}]] [[w:45|45]]'' <sup>[[w:Ier_siècle|⏳]]</sup>'', à [[w:Chéronée|''Chéronée'']] en [[w:Béotie|''Béotie'']] — {{Info|''ca.''|Circa, locution latine que l’on emploie pour indiquer l’approximation d’une date}} [[w:125|125]]'' <sup>[[w:IIe_siècle|⏳]]</sup>)[[s:Auteur:Plutarque|<sup>📚</sup>]] [https://books.google.fr/books?id=qfl1xwEACAAJ&lpg=PA1067&hl=fr&pg=PA1097#v=onepage&q&f=false {{Info|<sup>🔍</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume Vb, §210 - Plutarque de Chéronée}}] [[Fichier:Plutarch at Delphi.jpg|vignette|<p style="text-align: justify; text-indent: 15px;">Buste probable de Plutarque du [[w:IIe_siècle|II<sup>ème</sup>]] ou [[w:IIIe_siècle|III<sup>ème</sup>]] siècles {{Info|EC|de l’Ère Commune}}, en marbre de [[w:Marbre_de_Paros|''Paros'']].<br /><p style="text-align: justify; text-indent: 15px;">Provenance : découvert lors de fouilles près de l’angle sud-est du [[w:Temple d'Apollon (Delphes)|''temple d’Apollon'']] de [[w:Delphes|''Delphes'']], au côté d'une [[w:Fichier:Plutarch_stele_inscription_100_AD,_AM_of_Delphi_4070060092.jpg|''stèle'']] portant une inscription gravée : ΔΕΛΦΟΙ ΧΑΙΡΩΝΕΥΣΙΝ ΟΜΟΥ ΠΛΟΥΤΑΡΧΟΝ ΕΘΗΚΑΝ ΤΟΙΣ ΑΜΦΙΚΤΥΟΝΩΝ ΔΟΓΜΑΣΙ ΠΕΙΘΟΜΕΝΟΙ — Les ''Delphiens'', avec les ''Chéronéens'', dédièrent ce(tte image de) Plutarque, suivant les préceptes de l’[[w:Amphictyonie|''Amphictyonie'']].<br /><p style="text-align: justify; text-indent: 15px;">Exposition : Salle XIV, [[w:Mus%C3%A9e_arch%C3%A9ologique_de_Delphes|''Musée archéologique de Delphes'']].]] <div style="text-align: justify; margin: 0 1em; text-indent: 15px">Biographe, philosophe et moraliste grec, auteur d’une œuvre importante, comportant un ensemble varié de traités et de dialogues consacrés à des questions de philosophie morale, mais abordant aussi des sujets littéraires, politiques, scientifiques, religieux.</div> {{Boîte déroulante début|titre=NdA Plutarque|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Plutarque_back|<span id="Plutarque"><sup>I</sup></span>]] Du nom propre grec ancien πλούταρχος / ploútarkhos [[wikt:en:Πλούταρχος#Ancient_Greek|(en)]], « maître des richesses » ; <br /><p style="margin: 0 2em; text-indent: 15px">➥ du nom commun πλοῦτος / ploûtos [[wikt:en:πλοῦτος#Ancient_Greek|(en)]], « richesses » ;<br /><p style="margin: 0 2em; text-indent: 15px">➥ +‎ du nom commun ἀρχός / arkhós, « souverain, chef, prince »)'''<br/><br/></div> {{Boîte déroulante fin}} {{Boîte déroulante début|titre=Remarque|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>''' Dans la ''Vie de [[w:Lycurgue_(législateur)|Lycurgue]]'' et la ''Vie d’Agis et Cléomène'' (''Vies parallèles''), et le traité ''Un philosophe doit surtout converser avec les princes'' (''Œuvres morales''), il est fait mention d’un Thalès : il s’agit de [[w:Thalétas|Thalétas]], aussi appelé Thalès de [[w:Crète|''Crète'']], un musicien et poète, originaire de la cité de [[w:Gortyne|''Gortyne'']] en ''Crète'', et actif à la fin du [[w:VIIIe_siècle_av._J.-C.|VIII<sup>ème</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]] et au début du siècle suivant.'''<br/><br/></div> {{Boîte déroulante fin}} === [[w:Vies_parallèles|Vies parallèles]] [[#Vies_parallèles|<span id="Vies_parallèles_back"><sup>'''I'''</sup></span>]] === <div style="text-align: center; margin: 0 1em;">Recueil de 50 biographies de grands hommes de l’histoire, dont 46 présentées par paires : un ''Grec'' mis en parallèle avec un ''Romain'' [https://books.google.fr/books?id=qfl1xwEACAAJ&lpg=PA1059&hl=fr&pg=PA1115#v=onepage&f=false {{info|<sup>🔍</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume Vb, §210 - Plutarque de Chéronée, pp.1115 - 1119, (7) Le Moraliste et l’entreprise des Vies Parallèles}}]. {{Boîte déroulante début|titre=NdA Vies parallèles|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Vies_parallèles_back|<span id="Vies_parallèles"><sup>I</sup></span>]] En grec ancien Βίοι Παράλληλοι / Bíoi Parállêloi :<br /><p style="margin: 0 2em; text-indent: 15px;">➥ Du nom commun βῐ́ος / bĭ́os [[wikt:en:βίος#Ancient_Greek|(en)]], « Vie (souvent avec une connotation positive : la vie heureuse) » ;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ De l’adjectif πᾰρᾰ́λληλος / părắllēlos [[wikt:en:παράλληλος#Ancient_Greek|(en)]], « 1. À côté l’un de l’autre, côte à côte. 2. Parallèle à ou avec. 3. Pléonastique, redondant.<br /><p style="margin: 0 2em; text-indent: 30px;">➥ du préfixe παρα- / para- [[wikt:en:παρα-#Ancient_Greek|(en)]], « 1. À côté. 2. Contrairement à. » ;<br /><p style="margin: 0 2em; text-indent: 45px;">➥ de la préposition πᾰρᾰ́ / părắ [[wikt:en:παρά#Ancient_Greek|(en)]], « 1. [avec génitif] : • De ; • À cause de. 2. [avec datif] : • À, à côté de, près de. 3. [avec accusatif] : • Contraire à ; • À côté de, près de (avec les verbes de venir ou d’aller ; avec les verbes de mouvement passé ; avec les verbes de frapper ou de blesser) » ;<br /><p style="margin: 0 2em; text-indent: 30px;">➥ +‎ du pronom ᾰ̓λλήλων / ăllḗlōn [[wikt:en:ἀλλήλων#Ancient_Greek|(en)]], « Se rapportant à un sujet pluriel et exprimant une action bilatérale : l’un de l’autre, l’un à l’autre, l’un l’autre, l’un l’autre, mutuellement, réciproquement. » ;<br /><p style="margin: 0 2em; text-indent: 45px;">➥ À partir d’expressions telles que ᾰ̓́λλος ᾰ̓́λλον / ắllos ắllon, ᾰ̓́λλοι ᾰ̓́λλους / ắlloi ắllous, « les uns les autres », avec perte de λ soit par dissimilation, soit par allongement de α, ainsi que restauration de la deuxième voyelle initiale ή / ḗ.'''<br/><br/></div> {{Boîte déroulante fin}} ==== Vie de [[w:Solon|'''Solon''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Solon|<sup>🔄</sup>]] ==== <div style="text-align: center; margin: 0 1em;">Biographie de '''Solon''', qui précède celle de [[w:Publius_Valerius_Publicola_(consul_en_-509)|'''Publicola''']] [[#Publicola|<span id="Publicola_back"><sup>'''I'''</sup></span>]], et avec laquelle '''Plutarque''' la compare.</div> {{Boîte déroulante début|titre=NdA Vie de Solon|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Publicola_back|<span id="Publicola"><sup>I</sup></span>]] [[w:Nom_romain|Tria Nomina]] en latin {{Info|Publius|praenomen, nom individuel du citoyen romain}} {{Info|Valerius|nomen, nom de famille}} {{Info|Publicola ou Poplicola|cognomen, surnom héréditaire, servant à distinguer les diverses branches d’une même gens}}, « celui qui prend soin de l’armée. »[https://academic.oup.com/bics/advance-article/doi/10.1093/bics/qbaf002/8117642?login=false {{Info|<sup>🔍</sup>|M. Gallo, « Misinterpreting a compound name. The origin of the agnomen Publicola in Dionysius of Halicarnassus and Plutarch », Bulletin of the Institute of Classical Studies,‎ 22 avril 2025}}].<br /><p style="margin: 0 2em; text-indent: 15px">[[w:Consul_(Rome_antique)|Consul]] de la [[w:république_romaine|''République Romaine'']], à quatre reprises : en [[w:-509|-509]], [[w:-508|-508]], [[w:-507|-507]] et [[w:-504|-504]], et l’un des instaurateurs légendaires de la ''République Romaine'' en -509, suite au viol et au suicide de [[w:Lucrèce_(dame_romaine)|Lucrèce]], une femme aristocratique ''romaine'', par [[w:Sextus_Tarquin|Sextus Tarquin]], le fils du dernier [[w:Roi_de_Rome|roi de ''Rome'']] [[w:Tarquin_le_Superbe|Tarquin le Superbe]].<br /><p style="text-align: right; margin: 0 2em;">(date et lieu de naissance inconnu.e.s — [[w:-503|-503]], soit sur le champ de bataille pendant les [[w:Guerres_romano-sabelliennes|''guerres romano-sabelliennes'']], soit de maladie)<sup>[[w:VIe_siècle_av._J.-C.|⏳]]</sup> '''<br/><br/></div> {{Boîte déroulante fin}} ===== <div style="text-align: center;">Chapitre II.</div> ===== ====== <div style="text-align: center;">Paragraphe III.</div> ====== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage de '''Thalès''' ''commerçant''.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''III.''' Κωλύει δὲ οὐδὲν τὸν ἀγαθὸν καὶ πολιτικὸν ἄνδρα μήτε τῶν περιττῶν τὴν κτῆσιν ἐν σπουδῇ τίθεσθαι μήτε τῆς χρείας τῶν ἀναγκαίων καὶ ἱκανῶν καταφρονεῖν. Ἐν δὲ τοῖς τότε χρόνοις, καθ' Ἡσίοδον, ἔργον οὐδὲν ἦν ὄνειδος, οὐδὲ τέχνη διαφορὰν ἔφερεν, ἐμπορία δὲ καὶ δόξαν εἶχεν οἰκειουμένη τὰ βαρβαρικὰ καὶ προξενοῦσα φιλίας βασιλέων καὶ πραγμάτων ἐμπείρους ποιοῦσα πολλῶν. Ἔνιοι δὲ καὶ πόλεων οἰκισταὶ γεγόνασι μεγάλων, ὡς καὶ Μασσαλίας Πρῶτις ὑπὸ Κελτῶν τῶν περὶ τὸν Ῥοδανὸν ἀγαπηθείς. Καὶ Θαλῆν δέ φασιν ἐμπορίᾳ χρήσασθαι καὶ Ἱπποκράτην τὸν μαθηματικόν, καὶ Πλάτωνι τῆς ἀποδημίας ἐφόδιον ἐλαίου τινὸς ἐν Αἰγύπτῳ διάθεσιν γενέσθαι.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://remacle.org/bloodwolf/historiens/Plutarque/solon.htm <u>Plutarque, Vie de Solon</u>], ''chap. II'', ''§3'', traduction par [[w:Dominique_Ricard|Dominique Ricard]], 1844<br />(également disponible une édition de 1853 [https://remacle.org/bloodwolf/historiens/Plutarque/solonpierrron.htm ici] et de 1862 [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f16.item là])</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 390px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''III.''' Mais rien n’empêche l’homme de bien, le citoyen dévoué à son pays, de garder un juste milieu : il peut ne point s’attacher à la poursuite du superflu, sans pour cela mépriser le nécessaire et ce qui suffit à ses besoins.<br />Dans ce temps-là, pour parler comme [[w:Hésiode|'''Hésiode''']] [[#Hésiode|<span id="Hésiode_back"><sup>'''I'''</sup></span>]] [[#Hésiode_NdT_AP|<span id="Hésiode_NdT_AP_back"><sup>1</sup></span>]], il n’y avait pas de travail qui fût honteux; aucun art ne mettait de différence entre les hommes : le négoce surtout était honoré, qui met en possession des avantages dont jouissent les étrangers, gagne l’amitié des rois, et donne une grande expérience. On a même vu des trafiquants fonder de grandes villes : ainsi [[w:Mythe_fondateur_de_Marseille|'''Protis''']] bâtit [[w:Marseille_antique|''Marseille'']], après s'être concilié l’amitié des ''Gaulois'' qui habitent les bords du [[w:Rhône#Histoire|''Rhône'']]. '''Thales''' se livra, dit-on, au négoce, ainsi qu’[[w:Hippocrate_de_Chios|'''Hippocrate''']] [[#Hippocrate|<span id="Hippocrate_back"><sup>'''II'''</sup></span>]] le mathématicien[[#Hippocrate_NdT_AP|<span id="Hippocrate_NdT_AP_back"><sup>2</sup></span>]] ; et [[w:Platon|'''Platon''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Platon|<sup>🔄</sup>]] vendit de l’huile en [[w:Basse_Époque|''Égypte'']] , pour fournir aux frais de son voyage.</div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Hésiode_NdT_AP_back|<span id="Hésiode_NdT_AP"><sup>1.</sup></span>]] Œuvres et Jours, vers 309.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Hippocrate_NdT_AP_back|<span id="Hippocrate_NdT_AP"><sup>2</sup></span>]] Cet Hippocrate n’est point connu d’ailleurs.''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/viesdeshommesill01plut/page/n6/mode/1up?view=theater <u>Vie des Hommes Illustres de Plutarque</u>], [https://archive.org/details/viesdeshommesill01plut/page/182/mode/1up?view=theater ''Solon''], ''Chap. II'', ''§3'', [https://archive.org/details/viesdeshommesill01plut/page/184/mode/1up?view=theater p.184], traduit par [[w:Alexis_Pierron|Alexis Pierron]], professeur au lycée Louis-le-Grand, 1877<br />(également disponible une édition de 1853 [[s:Vies_des_hommes_illustres/Solon|ici]])</div> {{Boîte déroulante début|titre=NdA trad. par Alexis Pierron de 1877|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Hésiode_back|<span id="Hésiode"><sup>I</sup></span>]] Du nom propre grec ancien Ἡσῐ́οδος / Hēsĭ́odos [[wikt:en:Ἡσίοδος#Ancient_Greek|(en)]].<br /><p style="margin: 0 2em; text-indent: 15px">Berger sur les pentes du Mont [[w:Mont_Hélicon|Hélicon]] et un des plus grands poètes grecs. Il s’agit plus précisément d’un ''aède'' (il « chante » ses vers avec sa lyre) et un ''rhapsode'' (il « coud » des chants entre eux)[https://odysseum.eduscol.education.fr/hesiode-un-des-premiers-poetes-grecs {{Info|<sup>🔍</sup>|Hésiode, un des premiers poètes grecs - Odysseum, la maison numérique des Humanités}}]. <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Hippocrate_back|<span id="Hippocrate"><sup>II</sup></span>]] Du nom propre grec ancien Ῐ̔πποκρᾰ́της / Hĭppokrắtēs [[wikt:en:Ἱπποκράτης#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px">➥ du nom commun ῐ̔́ππος / hĭ́ppos [[wikt:en:ἵππος#Ancient_Greek|(en)]], « cheval »;<br /><p style="margin: 0 2em; text-indent: 15px">➥ + du nom commun‎ κρᾰ́τος / krắtos [[wikt:en:κράτος#Ancient_Greek|(en)]], « 1. Puissance, force. 2. Acte de force, acte de bravoure. 3. (au pluriel) Actes de violence. 4. Domination, pouvoir. »;<br /><p style="margin: 0 2em; text-indent: 15px">➥ +‎ du suffixe nominal -ης / -ēs.<br /><p style="margin: 0 2em; text-indent: 15px"> Mathématicien (géomètre) et astronome « para-pythagoricien », dont l’œuvre ne nous est pas parvenue.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] milieu du [[w:Ve_siècle_av._J.-C.|V<sup>ème</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]]) [https://books.google.fr/books?id=DrvWAAAAMAAJ&newbks=1&newbks_redir=0&lpg=PA764&vq=Hippocrate&dq=bibliogroup%3A%22Dictionnaire%20des%20philosophes%20antiques%22&hl=fr&pg=PA764#v=onepage&q&f=true {{Info|<sup>🔍</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume III, §151 - Hippocrate de Chios}}]'''<br/><br/></div> {{Boîte déroulante fin}} <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: center; margin: 0 2em;">'''II. Dans sa jeunesse il se livre au commerce maritime; la modicité de sa fortune et son goût pour la sagesse l’y décident. Faveur du commerce à cette époque ; grands noms qui l’ont illustré.'''<br /><br /><p style="text-align: justify; text-indent: 15px;">Mais rien n’empêche qu’un homme de bien, un sage politique tienne à cet égard un juste milieu, et que sans rechercher des richesses superflues, il ne méprise pas celles qui sont nécessaires et qui suffisent. Dans ce temps-là, comme dit [[w:Hésiode|'''Hésiode''']], aucun travail n’était regardé comme honteux; aucun art ne mettait de différence entre les hommes. Le commerce maritime surtout était honorable; il ouvrait des communications utiles avec les nations étrangères, procurait des alliances avec les rois, et donnait une grande expérience. On a même vu des commerçants fonder de grandes villes. Ainsi '''Protus''' gagna l’amitié des Gaulois qui habitaient les bords du ''Rhône'', et bâtit ''Marseille''. '''Thalès''' et '''Hippocrate''' le mathématicien firent aussi le commerce ; et '''Platon''' vendit de l’huile en ''Égypte'' pour fournir aux frais de son voyage.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f7.item <u>Plutarque, Vie de Solon</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f16.item ''chap. II''], traduction correcte et précédée du texte grec, par une société de professeurs et d’helléniste, 1862<br />(également disponible une édition de 1844 [https://remacle.org/bloodwolf/historiens/Plutarque/solon.htm#1a ici] et de 1829 [[s:Les_Vies_des_hommes_illustres/Vie_de_Solon|là]])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Mais rien n’empêche l’homme de-bien et l’homme politique ni se mettre en souci (rechercher) l’acquisition des choses superflues, ni mépriser l’usage des choses nécessaires et suffisantes. Or dans les temps d’alors, selon '''Hésiode''', aucun travail n’était sujet-de-honte, ni aucun métier n’apportait de différence entre les citoyens mais même le commerce-maritime avait de la gloire, rendant-amies les nations-barbares, et procurant des amitiés de rois, et faisant les hommes expérimentés d’affaires nombreuses. Et quelques-uns aussi sont devenus fondateurs de grandes villes, comme aussi le '''Protus''' de ''Marseille'' ayant été aimé par les ''Celtes'' ceux autour du ''Rhône''. Et on dit aussi '''Thalès''', avoir fait-usage du commerce-maritime et '''Hippocrate''' le mathématicien, et la vente d'une certaine huile en ''Égypte'' avoir été pour '''Platon''' ressource du voyage.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f7.item <u>Plutarque, Vie de Solon</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f16.item ''chap. II''], traduction littérale et juxtalinéaire présentant le mot à mot français en regard des mots grecs correspondants, par une société de professeurs et d’helléniste, 1862</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ====== <div style="text-align: center;">Paragraphe IV.</div> ====== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage de la sagesse de '''Thalès''' en ''philosophie naturelle''</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''IV.''' Φιλοσοφίας δὲ τοῦ ἠθικοῦ μάλιστα τὸ πολιτικόν, ὥσπερ οἱ πλεῖστοι τῶν σοφῶν, ἠγάπησεν. Ἐν δὲ τοῖς φυσικοῖς ἁπλοῦς ἐστι λίαν καὶ ἀρχαῖος, ὡς δῆλον ἐκ τούτων· [...].<br /><p style="text-indent: 15px">Καὶ ὅλως ἔοικεν ἡ Θάλεω μόνου σοφία τότε περαιτέρω τῆς χρείας ἐξικέσθαι τῇ θεωρίᾳ· τοῖς δὲ ἄλλοις ἀπὸ τῆς πολιτικῆς ἀρετῆς τοὔνομα τῆς σοφίας ὑπῆρξε.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://remacle.org/bloodwolf/historiens/Plutarque/solon.htm <u>Plutarque, Vie de Solon</u>], ''chap. II'', ''§4'', traduction par [[w:Dominique_Ricard|Dominique Ricard]], 1844<br />(également disponible une édition de 1853 [https://remacle.org/bloodwolf/historiens/Plutarque/solonpierrron.htm ici] et de 1862 [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f20.item là])</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 390px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''IV.''' Il s’attacha, comme presque tous les sages d’alors, à cette partie de la philosophie morale qui traite de la politique. Pour la philosophie naturelle, il en était aux rudiments, et aux notions du vieux temps sans plus; [...].<br /><p style="text-indent: 15px;">Aussi bien n’y eut-il, en somme, que '''Thalès''' dont la science dépassât alors les notions d’un usage vulgaire : tous les autres ne durent qu’à leurs connaissances politiques leur réputation de sagesse.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/viesdeshommesill01plut/page/n6/mode/1up?view=theater <u>Vie des Hommes Illustres de Plutarque</u>], [https://archive.org/details/viesdeshommesill01plut/page/182/mode/1up?view=theater ''Solon''], ''Chap. II'', ''§4'', [https://archive.org/details/viesdeshommesill01plut/page/185/mode/1up?view=theater p.185], traduit par [[w:Alexis_Pierron|Alexis Pierron]], professeur au lycée Louis-le-Grand, 1877<br />(également disponible une édition de 1853 [[s:Vies_des_hommes_illustres/Solon|ici]])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">A l’exemple des sages de son temps, il cultiva principalement cette partie de la morale qui traite de la politique. Il n’avait en physique que des connaissances très-superficielles, et en était aux premiers éléments de cette science, [...].<br/><p style="text-indent: 15px">En général '''Thalès''' fut, de tous les sages d’alors, le seul qui porta au delà des besoins de la vie la théorie des sciences ; tous les autres ne durent qu’à leurs connaissances politiques leur réputation de sagesse.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f7.item <u>Plutarque, Vie de Solon</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f20.item ''chap. II''], traduction correcte et précédée du texte grec, par une société de professeurs et d’helléniste, 1862<br />(également disponible une édition de 1844 [https://remacle.org/bloodwolf/historiens/Plutarque/solon.htm#1a ici] et de 1829 [[s:Les_Vies_des_hommes_illustres/Vie_de_Solon|là]])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Mais de la partie morale de la philosophie il embrassa surtout la partie politique, comme la plupart des sages d’alors. Mais dans les sciences physiques il est extrêmement simple (ignorant) et primitif, [...]. Et en-un-mot la science de '''Thalès''' seul paraît s’être avancée alors par la théorie plus loin que le besoin ; et le nom de la science a appartenu aux autres par-suite des qualités politiques.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f7.item <u>Plutarque, Vie de Solon</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f21.item ''chap. II''], traduction littérale et juxtalinéaire présentant le mot à mot français en regard des mots grecs correspondants, par une société de professeurs et d’helléniste, 1862</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ====== <div style="text-align: center;">Paragraphe V.</div> ====== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Version alternative du récit de la coupe de [[w:Bathyclès_de_Magnésie|'''Bathyclès''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Bathyclès_back|<sup>🔄</sup>]] par [[w:Callimaque_de_Cyrène|'''Callimaque''']] de [[w:Cyrène|''Cyrène'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Callimaque_back|<sup>🔄</sup>]].</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''V.''' Γενέσθαι δὲ μετ' ἀλλήλων ἔν τε Δελφοῖς ὁμοῦ λέγονται καὶ πάλιν ἐν Κορίνθῳ, Περιάνδρου σύλλογόν τινα κοινὸν αὐτῶν καὶ συμπόσιον κατασκευάσαντος. Ἔτι δὲ μᾶλλον εἰς ἀξίωμα καὶ δόξαν αὐτοὺς κατέστησεν ἡ τοῦ [[w:τρίπους#Grec_ancien|'''τρίποδος''']] περίοδος καὶ διὰ πάντων ἀνακύκλησις καὶ ἀνθύπειξις μετ' εὐμενείας φιλοτίμου γενομένη. Κῴων γάρ, ὥς φασι, καταγόντων σαγήνην, καὶ ξένων ἐκ Μιλήτου πριαμένων τὸν βόλον οὔπω φανερὸν ὄντα, χρυσοῦς ἐφάνη τρίπους ἑλκόμενος, ὃν λέγουσιν Ἑλένην πλέουσαν ἐκ Τροίας αὐτόθι καθεῖναι χρησμοῦ τινος ἀναμνησθεῖσαν παλαιοῦ. Γενομένης δὲ τοῖς ξένοις πρῶτον ἀντιλογίας πρὸς τοὺς ἁλιέας περὶ τοῦ τρίποδος, εἶτα τῶν πόλεων ἀναδεξαμένων τὴν διαφορὰν ἄχρι πολέμου προελθοῦσαν, ἀνεῖλεν ἀμφοτέροις ἡ Πυθία τῷ σοφωτάτῳ τὸν τρίποδα ἀποδοῦναι. Καὶ πρῶτον μὲν ἀπεστάλη πρὸς Θαλῆν εἰς Μίλητον, ἑκουσίως τῶν Κῴων ἑνὶ δωρουμένων ἐκείνῳ περὶ οὗ πρὸς ἅπαντας ὁμοῦ Μιλησίους ἐπολέμησαν. Θάλεω δὲ Βίαντα σοφώτερον ἀποφαίνοντος αὑτοῦ πρὸς ἐκεῖνον ἧκεν· ἀπ' ἐκείνου δ' αὖθις ἀπεστάλη πρὸς ἄλλον ὡς σοφώτερον. Εἶτα περιϊὼν καὶ ἀναπεμπόμενος οὕτως ἐπὶ Θαλῆν τὸ δεύτερον ἀφίκετο, καὶ τέλος εἰς Θήβας ἐκ Μιλήτου κομισθεὶς τῷ Ἰσμηνίῳ Ἀπόλλωνι καθιερώθη. Θεόφραστος δέ φησι,πρῶτον μὲν εἰς Πριήνην Βίαντι τὸν τρίποδα πεμφθῆναι, δεύτερον δ' εἰς Μίλητον Θαλῇ Βίαντος ἀποπέμψαντος· οὕτω δὲ διὰ πάντων πάλιν εἰς Βίαντα περιελθεῖν, τέλος δὲ εἰς Δελφοὺς ἀποσταλῆναι. Ταῦτα μὲν οὖν ὑπὸ πλειόνων τεθρύληται, πλὴν ὅτι τὸ δῶρον ἀντὶ τοῦ τρίποδος οἱ μὲν φιάλην ὑπὸ Κροίσου πεμφθεῖσαν, οἱ δὲ ποτήριον Βαθυκλέους ἀπολιπόντος εἶναι λέγουσιν.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://remacle.org/bloodwolf/historiens/Plutarque/solon.htm <u>Plutarque, Vie de Solon</u>], ''chap. II'', ''§5'', traduction par [[w:Dominique_Ricard|Dominique Ricard]], 1844<br />(également disponible une édition de 1853 [https://remacle.org/bloodwolf/historiens/Plutarque/solonpierrron.htm ici] et de 1862 [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f22.item là])</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 390px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''V.''' On raconte que les sept sages se réunirent une fois à [[w:Delphes|''Delphes'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Delphes_back|<sup>🔄</sup>]], et une autre fois à [[w:Histoire_de_Corinthe_dans_l%27Antiquité|''Corinthe'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Corinthe_back|<sup>🔄</sup>]], où [[w:Périandre|'''Périandre''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Périandre_back|<sup>🔄</sup>]] les avait convoqués pour leur offrir un banquet. Rien ne contribua tant à leur réputation et à leur gloire, que le renvoi qu’ils se firent successivement l’un à l’autre du trépied d’or, et l’honorable humilité avec laquelle ils refusèrent le prix tour à tour. Des hommes de [[w:Kos_(Dodécanèse)#Kos_à_l'époque_hellénistique|''Cos'']] [[#Cos|<span id="Cos_back"><sup>'''I'''</sup></span>]] venaient, dit-on, de jeter leur filet en mer : des étrangers de ''Milet'' achetèrent le coup, avant que les pêcheurs y eussent regardé. Il se trouva, dans le filet, un trépied d’or qu’[[w:Hélène_(mythologie)|'''Hélène''']] [[#Hélène|<span id="Hélène_back"><sup>'''II'''</sup></span>]], à ce qu’on prétend, pour obéir à un ancien oracle, avait jeté dans la mer à son retour de [[w:Troie|''Troie'']] [[#Troie|<span id="Troie_back"><sup>'''III'''</sup></span>]]. Ce fut un sujet de débat, d’abord entre les pêcheurs et les étrangers, ensuite entre les deux villes, qui prirent parti dans la querelle : la guerre allait s’allumer, lorsque la [[w:Pythie|''Pythie'']] [[#Pythie|<span id="Pythie_back"><sup>'''IV'''</sup></span>]], que les deux partis avaient consultée, commanda de donner le trépied au plus sage. On l’envoya d’abord à ''Milet'', pour '''Thalès''', et ceux de ''Cos'' cédèrent sans peine à un seul particulier ce qu’ils allaient disputer par les armes à tous les ''Milésiens'' ensemble. '''Thalès''' déclara que [[w:Bias_de_Priène|'''Bias''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Bias_back|<sup>🔄</sup>]] était plus sage que lui, et le lui fit passer. '''Bias''', avec la même modestie, le fit passer à un autre; et le trépied, après avoir été envoyé successivement à tous les sept, revint une seconde fois à '''Thalès'''. Enfin, il fut transporté de ''Milet'' à [[w:Thèbes_(Grèce)|''Thèbes'']] [[#Thèbes|<span id="Thèbes_back"><sup>'''V'''</sup></span>]], et consacré à Apollon [[w:en:Ismenus|''Isménien'']]. Cependant [[w:Théophaste|'''Théophaste''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Théophaste_back|<sup>🔄</sup>]] dit qu’on envoya le trépied d’abord à '''Bias''', dans ''Priène'' ; que '''Bias''' le fit porter à '''Thalès''' ; qu’après avoir passé alternativement chez tous les sages, il revint à '''Bias''', et qu’il finit par être envoyé à ''Delphes''. Telle est la tradition commune : seulement quelques-uns prétendent qu’il s’agissait de décerner non point un trépied, mais un vase que [[w:Crésus|'''Crésus''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Crésus_back|<sup>🔄</sup>]] avait envoyé ; et, suivant d’autres, c’était une coupe, héritage de '''Bathyclès'''.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/viesdeshommesill01plut/page/n6/mode/1up?view=theater <u>Vie des Hommes Illustres de Plutarque</u>], [https://archive.org/details/viesdeshommesill01plut/page/182/mode/1up?view=theater ''Solon''], ''Chap. II'', ''§5'', [https://archive.org/details/viesdeshommesill01plut/page/185/mode/1up?view=theater p.185], traduit par [[w:Alexis_Pierron|Alexis Pierron]], professeur au lycée Louis-le-Grand, 1877<br />(également disponible une édition de 1853 [[s:Vies_des_hommes_illustres/Solon|ici]])</div> {{Boîte déroulante début|titre=NdA trad. par Alexis Pierron de 1877|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Cos_back|<span id="Cos"><sup>I</sup></span>]] Du nom propre grec ancien Κῶς / Kôs [[wikt:en:Κῶς#Ancient_Greek|(en)]] ;<br /><p style="margin: 0 2em; text-indent: 15px">Île grecque l’archipel du [[w:Dodécanèse|''Dodécanèse'']], au Sud-Est de la [[w:Mer_Égée|''mer Égée'']], au large des côtes ''turques''. <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Hélène_back|<span id="Hélène"><sup>II</sup></span>]] Du nom propre grec ancien Ἑλένη / Helénē [[wikt:en:Ἑλένη#Ancient_Greek|(en)]] ;<br /><p style="margin: 0 2em; text-indent: 15px">Fille de [[w:Zeus|Zeus]] et de [[w:Léda (mythologie)|Léda]], considérée comme la plus belle femme du monde, uniquement surpassée par la déesse [[w:Aphrodite|Aphrodite]]. Elle est mariée à [[w:Ménélas|Ménélas]], roi de [[w:Sparte|Sparte]], et est enlevée par [[w:Pâris|Pâris]], prince [[w:Troie|''troyen'']] [[#Troie|<sup>'''III'''</sup>]], ce qui déclencha la [[w:guerre de Troie|guerre de Troie]] qui opposa ''Grecs'' et ''Troyens''. <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Troie_back|<span id="Troie"><sup>III</sup></span>]] Du nom propre grec ancien Τροίᾱ / Troíā [[wikt:en:Τροία#Ancient_Greek|(en)]] ; [[w:Troie#Toponymie|''toponymie incertaine'']] ;<br /><p style="margin: 0 2em; text-indent: 15px"> Cité semi-légendaire, située sur la colline d’''[[w:site archéologique de Troie|{{lang|tr|Hisarlık}}]]'', à l’entrée de l’''[[w:Hellespont|Hellespont]]'', non loin de la ''[[w:mer Égée|mer Égée]]'', au nord-ouest de la ''péninsule anatolienne'', dans la région ''[[w:Troade|Troade]]'' en ''[[w:Asie Mineure|Asie Mineure]]''.<br /><p style="margin: 0 2em; text-indent: 15px"> Le site a fait l’objet de nombreuses campagnes de fouilles, à la suite de celles entreprises par [[w:Heinrich Schliemann|Heinrich Schliemann]] en 1870, ponctuées par des découvertes fortement médiatisées, qui ont popularisé son identification avec la Troie homérique (qui reste un sujet de débat en l’absence de preuve décisive), le lieu principal des événements du ''[[w:cycle troyen|cycle troyen]]'' rapportés dans les ''[[w:Épopée|poèmes épiques]]'' ''[[w:Homère|homériques]]'' l’''[[w:Iliade|Iliade]]'' et l’''[[w:Odyssée|Odyssée]]''. <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Pythie_back|<span id="Pythie"><sup>IV</sup></span>]] Du nom commun grec ancien Πῡθῐ́ᾱ / Pūthĭ́ā,<br /><p style="margin: 0 2em; text-indent: 15px">➥ du nom propre Πῡθώ / Pūthṓ, « [[w:Delphes#Histoire_du_site|''Pythô'']], ancien nom de ''Delphes'' » ;<br /><p style="margin: 0 2em; text-indent: 15px">➥ +‎ du suffixe adjectival féminin -ῐος / -ĭos [[wikt:en:-ιος#Ancient_Greek|(en)]], « relatif à, appartenant à (de) ».<br /><p style="margin: 0 2em; text-indent: 15px">[[w:Divination_dans_la_Grèce_antique|''Oracle'']] du [[w:Temple_d%27Apollon_(Delphes)|''temple d’Apollon'']] à ''Delphes''.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:XIVe_siècle_av._J.-C.|XIV<sup>ème</sup>]]/[[w:VIIIe_siècle_av._J.-C.|VIII<sup>ème</sup>]] siècles {{Info|AEC|Avant l’Ère Commune}} — [[w:IVe_siècle_av._J.-C.|IV<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]]) <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Thèbes_back|<span id="Thèbes"><sup>V</sup></span>]] Du nom propre grec ancien Θῆβαι / Thêbai [[wikt:en:Θῆβαι#Ancient_Greek|(en)]], désigne indistinctement la cité ''grecque'' comme [[w:Thèbes_(Égypte)|celle ''égyptienne'']] ; mais leur étymologie diffère :<br /><p style="margin: 0 2em; text-indent: 15px;">➥ pour celle de la cité grecque, de l’[[w:Ionien-attique|''ionien-attique'']] Θήβη / Thḗbē ; du grec mycénien 𐀳𐀣 / te-qa (/Tʰēgʷā/) ;<br /><p style="margin: 0 2em; text-indent: 15px;">(➥ pour celle de la cité égyptienne, de l’égyptien démotique tꜣ-jpy, « Thèbes, littéralement "le temple" » ;<br /><p style="margin: 0 2em; text-indent: 30px;">➥ de l’article défini tꜣ [[wikt:en:tꜣ#Demotic_Egyptian|(en)]], « le/la » ;<br /><p style="margin: 0 2em; text-indent: 30px;">➥ + du nom propre et commun jpt [[wikt:en:jpt#Etymology_3|(en)]], « Louxor, littéralement "sanctuaire intérieur" »).<br /><p style="margin: 0 2em; text-indent: 15px">Cité grecque de la région de [[w:Béotie#Antiquité|''Béotie'']], au centre de la ''Grèce''.'''<br/><br/></div> {{Boîte déroulante fin}} <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">On raconte que les sept sages se trouvèrent un jour ensemble à ''Delphes'', et une autre fois à ''Corinthe'', chez '''Périandre''', qui les avait réunis pour un banquet. Rien ne contribua autant à leur réputation et à leur gloire, que la modestie empressée avec laquelle ils se renvoyèrent l’un à l’autre le trépied d’or. Des ''Milésiens'' qui se trouvaient à l’île de ''Cos'', avaient acheté d’avance de quelques pêcheurs ce que retirerait de l’eau le filet qu’ils allaient y jeter. Quand on l’eut tiré, il s’y trouva un trépied d’or qu’'''Hélène''', à ce qu’on prétend, pour obéir à un oracle, avait jeté dans la mer, à son retour de ''Troie''. Cet incident donna lieu à une vive dispute d’abord entre les pêcheurs et les étrangers, ensuite entre les deux villes, qui prirent parti dans la querelle et étaient près d’en venir aux mains, lorsque la ''Pythie'' consultée leur ordonna de porter ce trépied au plus sage. On l’envoya d’abord à '''Thalès''', et ceux de ''Cos'' cédèrent sans peine à un seul particulier ce qu’ils allaient disputer par les armes à tous les ''Milésiens'' ensemble. '''Thalès''' le renvoya à '''Bias''', qui, disait-il, était plus sage que lui ; '''Bias''', avec la même modestie, le fit passer à un autre ; et après avoir été envoyé successivement à tous les sept, il revint une seconde fois à '''Thalès''' : enfin il fut porté à ''Thèbes'', et consacré à ''Apollon Isménien''. '''Théophraste''' dit qu’on l’envoya d’abord à '''Bias''', qui demeurait à ''Priène'' ; que '''Bias''' le fit porter à '''Thalès''' ; qu’après avoir été envoyé alternativement à tous les sages, il revint à '''Bias''', et qu’enfin il fut porté à ''Delphes''. Telle est la tradition la plus commune sur ce fait ; seulement quelques auteurs disent que ce n’était pas un trépied, mais un vase que '''Crésus''' envoyait à ''Delphes''; suivant d’autres, c’était une coupe que '''Bathyclès''' avait laissée.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f7.item <u>Plutarque, Vie de Solon</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f22.item ''chap. II''], traduction correcte et précédée du texte grec, par une société de professeurs et d’helléniste, 1862<br />(également disponible une édition de 1844 [https://remacle.org/bloodwolf/historiens/Plutarque/solon.htm#1a ici] et de 1829 [[s:Les_Vies_des_hommes_illustres/Vie_de_Solon|là]])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Or ils (les sept sages) sont dits s’être trouvés aussi ensemble les uns avec les autres et à ''Delphes'' et de nouveau à ''Corinthe'', '''Périandre''' ayant préparé une certaine réunion commune d’eux et un banquet. Or le tour du trépied, et sa circulation à travers tous et sa cession se faisant avec une bienveillance pleine-d’émulation mit eux encore davantage en considération et renommée. Car des ''habitants-de-Cos'', comme on dit, jetant le filet, et des hôtes venus de ''Milet'' ayant acheté le coup qui n’était pas encore apparent, un trépied d’-or apparut étant retiré, lequel on dit '''Hélène''' naviguant pour revenir de ''Troie'' avoir jeté là, s’étant souvenue d’un certain oracle ancien. Mais une contestation ayant eu lieu d’abord aux hôtes vis-à-vis des pécheurs au sujet du trépied, ensuite les villes ayant pris-sur-elles le différend qui alla jusqu'à une guerre, la ''Pythie'' répondit aux-uns-et-aux-autres de donner le trépied au plus sage des hommes. Et d’abord il fut envoyé à '''Thalès''' à ''Milet'', les ''habitants-de-Cos'' donnant volontairement à celui-là seul le trépied, au sujet duquel ils avaient fait-la-guerre contre tous les ''Milésiens'' à-la-fois. Mais '''Thalès''' déclarant '''Bias''' plus sage que lui-même, il renvoya vers celui-là. Et de nouveau il fut envoyé par celui-là vers un autre, comme plus sage. Ensuite faisant-le-tour et étant envoyé-successivement ainsi il arriva pour la seconde fois à '''Thalès''' ; et à la fin transporté de ''Milet'' à ''Thèbes'', il fut consacré à ''Apollon Isménien''. Mais '''Théophraste''' dit le trépied avoir été envoyé d’abord à la vérité à ''Priène'' à '''Bias''', mais en-second-lieu à ''Milet'' à '''Thalès''', '''Bias''' l’ayant renvoyé ; et ainsi à travers tous (de l’un à l’autre) être venu-en-faisant-le-tour de nouveau à '''Bias''', et à la fin avoir été envoyé à ''Delphes''. Ces choses donc ont été répandues par plusieurs, excepté qu’ils disent le présent au lieu du trépied les uns être un vase à boire envoyé par '''Crésus''', les autres une coupe. '''Bathyclès''' rayant laissée (laissée par '''Bathyclès'''). </div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f7.item <u>Plutarque, Vie de Solon</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f23.item ''chap. II''], traduction littérale et juxtalinéaire présentant le mot à mot français en regard des mots grecs correspondants, par une société de professeurs et d’helléniste, 1862</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Chapitre VI.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;"> Récit d’une entrevue de '''Thalès''' avec '''Solon''', de son stoïcisme, de son célibat et de l’adoption du fils de sa sœur, '''Cybistus'''.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;"> '''VI.''' Ἰδίᾳ δ' Ἀναχάρσεώς τε πρὸς Σόλωνα καὶ πάλιν Θάλεω συνουσίαν τινὰ καὶ λόγους ἀναγράφουσι τοιούτους. [...]<br /><p style="text-indent: 15px"> '''VII.''' Πρὸς Θαλῆν δ' εἰς Μίλητον ἐλθόντα τὸν Σόλωνα θαυμάζειν ὅτι γάμου καὶ παιδοποιΐας τὸ παράπαν ἠμέληκε. Καὶ τὸν Θαλῆν τότε μὲν σιωπῆσαι, διαλιπόντα δ' ὀλίγας ἡμέρας ἄνδρα παρασκευάσαι ξένον, ἀρτίως ἥκειν φάσκοντα δεκαταῖον ἐξ Ἀθηνῶν. Πυθομένου δὲ τοῦ Σόλωνος εἰ δή τι καινὸν ἐν ταῖς Ἀθήναις, δεδιδαγμένον ἃ χρὴ λέγειν τὸν ἄνθρωπον, « οὐδέν,» εἰπεῖν, « ἕτερον, εἰ μὴ νὴ Δία νεανίσκου τινὸς ἦν ἐκφορὰ καὶ προὔπεμπεν ἡ πόλις. Ἦν γὰρ υἱός, ὡς ἔφασαν, ἀνδρὸς ἐνδόξου καὶ πρωτεύοντος ἀρετῇ τῶν πολιτῶν· οὐ παρῆν δέ, ἀλλ' ἀποδημεῖν ἔφασαν αὐτὸν ἤδη πολὺν χρόνον.» « Ὡς δυστυχὴς ἐκεῖνος,» φάναι τὸν Σόλωνα. « Τίνα δὲ ὠνόμαζον αὐτόν;» « ἤκουσα,» φάναι, « τοὔνομα,» τὸν ἄνθρωπον, « ἀλλ' οὐ μνημονεύω· πλὴν ὅτι πολὺς λόγος ἦν αὐτοῦ σοφίας καὶ δικαιοσύνης.» Οὕτω δὴ καθ' ἑκάστην ἀπόκρισιν τῷ φόβῳ προσαγόμενον τὸν Σόλωνα καὶ τέλος ἤδη συντεταραγμένον αὐτὸν ὑποβάλλειν τοὔνομα τῷ ξένῳ, πυνθανόμενον μὴ Σόλωνος ὁ τεθνηκὼς υἱὸς ὠνομάζετο. Φήσαντος δὲ τοῦ ἀνθρώπου, τὸν μὲν ὁρμῆσαι παίειν τὴν κεφαλὴν καὶ τἆλλα ποιεῖν καὶ λέγειν ἃ συμβαίνει τοῖς περιπαθοῦσι, τὸν δὲ Θαλῆν ἐπιλαβόμενον αὐτοῦ καὶ γελάσαντα, « ταῦτά τοι,» φάναι, « ὦ Σόλων, ἐμὲ γάμου καὶ παιδοποιΐας ἀφίστησιν, ἃ καὶ σὲ κατερείπει τὸν ἐρρωμενέστατον. Ἀλλὰ θάρρει τῶν λόγων ἕνεκα τούτων· οὐ γάρ εἰσιν ἀληθεῖς.» ταῦτα μὲν οὖν Ἕρμιππος ἱστορεῖν φησι Πάταικον, ὃς ἔφασκε τὴν Αἰσώπου ψυχὴν ἔχειν.<br /><p style="text-indent: 15px">'''VIII.''' Ἄτοπος δὲ καὶ ἀγεννὴς ὁ τῷ φόβῳ τῆς ἀποβολῆς τὴν κτῆσιν ὧν χρὴ προϊέμενος· οὕτω γὰρ ἄν τις οὐ πλοῦτον, οὐ δόξαν, οὐ σοφίαν ἀγαπήσειε παραγενομένην, δεδιὼς στέρεσθαι. Καὶ γὰρ ἀρετήν, ἧς κτῆμα μεῖζον οὐδὲν οὐδ' ἥδιον, ἐξισταμένην ὑπὸ νόσων καὶ φαρμάκων ὁρῶμεν· αὐτῷ τε '''Θαλῇ''' μὴ γήμαντι πλέον οὐδὲν εἰς ἀφοβίαν, εἰ μὴ καὶ φίλων κτῆσιν ἔφυγε καὶ οἰκείων καὶ πατρίδος. Ἀλλὰ καὶ παῖδα θετὸν ἔσχε ποιησάμενος αὐτὸς τὸν τῆς ἀδελφῆς, ὥς φασι, '''Κύβισθον'''.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://remacle.org/bloodwolf/historiens/Plutarque/solon.htm <u>Plutarque, Vie de Solon</u>], ''chap. II'', ''§§6-8'', traduction par [[w:Dominique_Ricard|Dominique Ricard]], 1844<br />(également disponible une édition de 1853 [https://remacle.org/bloodwolf/historiens/Plutarque/solonpierrron.htm ici] et de 1862 [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f26.item là])</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 390px; border: 2px solid; text-indent: 15px"><br /><div style="margin: 0 2em; text-align: justify; direction: ltr;">'''VI.''' '''Solon''' connut [[w:Anacharsis|'''Anacharsis''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Anacharsis_back|<sup>🔄</sup>]] et '''Thalès''', et l’on cite des mots qui s’étaient dits dans leurs entrevues. <br /><p style="text-align: center"> [...]<br /><p style="text-indent: 15px; text-align: justify;">'''Solon''' alla à ''Milet'', pour voir '''Thalès''' : là, il lui témoigna sa surprise dans ce qu’il n’avait jamais voulu se marier et avoir des enfants. '''Thalès''' ne répondit rien sur l’heure; mais, quelques jours après, il fit paraître un étranger, qui disait arriver d’''Athènes'', et qu’il n’en était parti que depuis dix jours. '''Solon''' demanda à cet homme s’il n’y avait rien de nouveau à ''Athènes''. Celui-ci, à qui '''Thalès''' avait fait la leçon, répondit qu’il n’y avait rien de nouveau , sinon la mort d’un jeune homme dont toute la ville menait les funérailles. C’était, en effet, à ce qu’on disait, le fils d’un personnage considérable, d’une vertu éprouvée : le père n’était pas alors à ''Athènes'', et il voyageait depuis longtemps. « L’infortuné père! s’écria '''Solon'''. Mais comment s’appelait-il? — Je l’ai entendu nommer, répondit l’étranger, mais j’ai oublié son nom ; je me souviens seulement qu’on ne parlait que de sa sagesse et de sa justice. » A chacune de ces réponses, '''Solon''' sentait augmenter ses craintes; enfin, ne se possédant plus , il suggéra le nom à l’étranger, et lui demanda si le mort n’était pas le fils de '''Solon'''. « Oui. » répondit l’étranger. A cette parole, '''Solon''' se frappa la tête, et il se mit à faire et à dire tout ce qu’inspire une douleur violente. Alors '''Thalès''' lui prit la main, et lui dit en riant : « Voilà, '''Solon''', ce qui m’éloigne de me marier et d’avoir des enfants. J’ai redouté le coup sous lequel tu fléchis, toi le plus ferme des hommes. Mais rassure-toi; car il n’y a rien de vrai dans tout ce qu’on vient de te dire. » [[w:Hermippe_de_Smyrne|'''Hermippus''']] [[#Hermippe|<span id="Hermippe_back"><sup>'''I'''</sup></span>]] rapporte cette histoire d’après '''Patécus''', celui qui prétendait avoir hérité de l’âme d’[[w:Ésope|'''Ésope''']] [[#Ésope|<span id="Ésope_back"><sup>'''II'''</sup></span>]].<br /><p style="text-indent: 15px">Pourtant il y a faute de sens et de cœur à refuser d’acquérir les choses nécessaires, par la crainte de les perdre. A ce compte, on devra n’aimer ni la richesse, ni la gloire, ni la sagesse, quand on les possède, de peur d’en être privé. En effet, la vertu, le plus grand des biens et le plus doux, nous quitte quelquefois par l’action de certaines maladies ou de certains breuvages. '''Thalès''' lui-même, en ne se mariant point, n’était pas pour cela à l’abri de la crainte, à moins qu’il n'eût renoncé aussi à ses parents, à ses amis, à sa patrie. Mais il n’en était rien : il avait adopté, dit-on, '''Cybisthus''', le fils de sa sœur. </div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/viesdeshommesill01plut/page/n6/mode/1up?view=theater <u>Vie des Hommes Illustres de Plutarque</u>], [https://archive.org/details/viesdeshommesill01plut/page/182/mode/1up?view=theater ''Solon''], ''Chap. II'', ''§6'', [https://archive.org/details/viesdeshommesill01plut/page/185/mode/1up?view=theater p.185], traduit par [[w:Alexis_Pierron|Alexis Pierron]], professeur au lycée Louis-le-Grand, 1877<br />(également disponible une édition de 1853 [[s:Vies_des_hommes_illustres/Solon|ici]])</div> {{Boîte déroulante début|titre=NdA trad. par Alexis Pierron de 1877|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Hermippe_back|<span id="Hermippe"><sup>I</sup></span>]] Du nom propre [[w:Nom_théophore|''théophore'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#théophore_back|<sup>🔄</sup>]] grec ancien Ἕρμιππος / Hérmippos [[wikt:en:Ἕρμιππος#Ancient_Greek|(en)]] ;<br /><p style="margin: 0 2em; text-indent: 15px">➥ du nom propre Ἑρμῆς / Hermês [[wikt:en:Ἑρμῆς#Ancient_Greek|(en)]], « Hermès » ;<br /><p style="margin: 0 2em; text-indent: 15px">➥ +‎ du nom commun ἵππος / híppos [[wikt:en:ἵππος#Ancient_Greek|(en)]], « cheval » ;<br /><p style="margin: 0 2em; text-indent: 15px">« Péripatéticien » grec, disciple de [[w:Callimaque_de_Cyr%C3%A8ne|Callimaque de ''Cyrène'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Callimaque_back|<sup>🔄</sup>]], auteur de nombreuses biographies toutes perdues, mais listées par plusieurs auteurs.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] seconde moitié du [[w:IIIe_siècle_av._J.-C.|III<sup>ème</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]]) [https://books.google.fr/books?id=DrvWAAAAMAAJ&newbks=1&newbks_redir=0&lpg=PA497&dq=bibliogroup%3A%22Dictionnaire%20des%20philosophes%20antiques%22&hl=fr&pg=PA655#v=onepage&q&f=false {{Info|<sup>🔍</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume III, §86 - Hermippe de Smyrne}}] <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Ésope_back|<span id="Ésope"><sup>II</sup></span>]] Du nom propre grec ancien Αἴσωπος / Aísōpos [[wikt:en:Αἴσωπος#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px">➥ du nom commun αἶσα / aîsa, « destin »;<br /><p style="margin: 0 2em; text-indent: 15px">➥ +‎ du nom commun ὄψ / óps, « voix »;<br /><br /><p style="margin: 0 2em; text-indent: 15px">Auteur grec de fable.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] seconde moitié du [[w:VIe_siècle_av._J.-C.|VI<sup>ème</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]]) [https://books.google.fr/books?id=DrvWAAAAMAAJ&newbks=1&newbks_redir=0&lpg=PA497&dq=bibliogroup%3A%22Dictionnaire%20des%20philosophes%20antiques%22&hl=fr&pg=PA240#v=onepage&q&f=false {{Info|<sup>🔍</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume III, §60 - Ésope(Αἴσωπος)}}]'''<br/><br/></div> {{Boîte déroulante fin}} <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">'''V.''' Voici les particularités qu’on raconte d’une entrevue de '''Solon''' avec '''Anacharsis''', et d’un entretien qu’il eut avec '''Thalès'''.<br /><p style="text-align: center"> [...]<br /><p style="text-indent: 15px; text-align: justify;">'''VI.''' '''Solon''', étant allé à ''Milet'' pour voir '''Thalès''', lui témoigna sa surprise de ce qu’il n’avait jamais voulu se marier et avoir des enfants. '''Thalès''' ne lui répondit rien dans le moment; mais ayant laissé passer quelques jours, il fit paraître un étranger qui disait arriver d’''Athènes'', d’où il était parti depuis dix jours. '''Solon''' lui demanda s’il n’y avait rien de nouveau, lorsqu’il en était parti. Cet homme, à qui '''Thalès''' avait fait la leçon, lui répondit qu’il n’y avait autre chose que la mort d’un jeune homme dont toute la ville accompagnait le convoi. C’était, disait-on, le fils d’un des premiers et des plus vertueux citoyens, qui n'’était pas alors à ''Athènes'' et qui voyageait depuis longtemps, « Le malheureux père! s’écria Solon. Comment s’appelle-t-il? ― Je l’ai entendu nommer, répondit l’étranger; mais j’ai oublié son nom; je me souviens seulement qu’on ne parlait que de sa sagesse et de sa justice. » A chacune de ces réponses, les craintes de '''Solon''' augmentaient; enfin, troublé, hors de lui-même, il suggéra le nom à l’étranger, et lui demanda si ce jeune homme n’était pas le fils de '''Solon'''. « C’est lui-même, » dit l’autre. A cette parole, '''Solon''', se frappant la tête, se mit à faire et à dire tout ce que la douleur la plus violente peut inspirer. Alors '''Thalès''' l’arrêta et lui dit en souriant : « Voilà, '''Solon''', ce qui m’a éloigné de me marier et d’avoir des enfants; j’ai redouté le coup qui vous accable aujourd’hui, et contre lequel toute votre fermeté est impuissante. Mais rassurez-vous ; il n’y a rien de vrai dans tout ce qu’on vient de vous dire. » '''Hermippus''' rapporte cette histoire d’après le récit qu’en fait '''Patécus''', qui prétendait avoir hérité de l’âme d’'''Ésope'''.<br /><p style="text-indent: 15px; text-align: justify;">'''VII.''' Cependant c’est manquer de sens et de courage que de renoncer à acquérir des choses nécessaires par la crainte de les perdre. A ce compte, il ne faudrait aimer ni la richesse, ni la gloire, ni la sagesse, quand on les possède, de peur d’en être privé. La vertu même, le plus grand et le plus agréable des biens, se perd souvent par l’effet. de quelques maladies ou de certains breuvages. '''Thalès''' lui-même, en ne se mariant point, n’était pas à l’abri de toute crainte, à moins qu’il ne renonçât aussi à ses parents, à ses amis et à sa patrie. Mais au contraire, il avait adopté '''Cybistus''', le fils de sa sœur. </div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f7.item <u>Plutarque, Vie de Solon</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f26.item ''chap. II''], traduction correcte et précédée du texte grec, par une société de professeurs et d’helléniste, 1862<br />(également disponible une édition de 1844 [https://remacle.org/bloodwolf/historiens/Plutarque/solon.htm#1a ici] et de 1829 [[s:Les_Vies_des_hommes_illustres/Vie_de_Solon|là]])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">'''V.''' Mais en particulier on rapporte une certaine entrevue et de tels discours et d’'''Anacharsis''' à '''Solon''' et une-autre-fois de '''Thalès'''.<br /><p style="text-align: center"> [...]<br /><p style="text-indent: 15px; text-align: justify;">'''VI.''' Et on raconte '''Solon''' étant venu vers '''Thalès''' à ''Milet'' s’étonner de ce qu’il avait négligé absolument le mariage et la création-d’enfants. Et '''Thalès''' alors à la vérité s’être tu, mais ayant laissé-d’intervalle peu-de jours, avoir aposté un homme étranger, disant être arrivé récemment parti-depuis-dix-jours d’''Athènes''. Et '''Solon''' s’étant informé si donc il y a quelque chose de nouveau à ''Athènes'', l’homme instruit des choses qu’il faut dire n’avoir dit aucune autre chose, si ce n’est :<br /><p style="text-indent: 15px"> « Par '''Jupiter''', il y avait le convoi d’un certain jeune-homme, et la ville l’accompagnait. Car il était fils, comme on disait, d’un homme illustre et étant-le-premier des citoyens par la vertu; mais il n’était-pas-présent, mais on disait lui être-en-voyage depuis un temps déjà long.<br /><p style="text-align: left; text-indent: 15px">― Combien cet homme-là est malheureux! avoir dit '''Solon'''. Mais quel (comment) appelaient-ils lui ?<br /><p style="text-align: left; text-indent: 15px">― J’ai entendu le nom, avoir dit l’homme (répondit l’étranger), mais je ne me le rappelle pas; excepté qu’un discours fréquent était de la sagesse et de la justice de lui. »<br /><p style="text-indent: 15px">'''Solon''' donc étant-approché ainsi de-la crainte à chaque réponse, et à la fin déjà étant tout-troublé, lui-même avoir suggéré le nom à l’étranger, demandant si le mort n’était pas nommé fils de '''Solon'''. Et l’homme ayant dit-oui, celui-ci ('''Solon''') avoir commencé à frapper sa tête, et à faire et à dire les autres choses, qu’il arrive de faire et de dire à ceux affligés-à-l’excès. Mais '''Thalès''' ayant arrêté lui, et ayant ri, avoir dit :<br /><p style="text-indent: 15px">« Ces choses donc, ô '''Solon''', écartent moi du mariage et de la création-d’enfants, lesquelles abattent même toi le très-fort. Mais aie-confiance quant-à ces discours: car ils ne sont pas vrais. »<br /><p style="text-indent: 15px">'''Hermippe''' donc dit '''Patécus''', qui disait-souvent avoir l’âme d’'''Ésope''', raconter ces choses. <br /><p style="text-indent: 15px">'''VII.''' Or il est absurde et dépourvu de courage celui rejetant par la crainte de la perte l’acquisition des choses qu’il faut; car ainsi quelqu’un n’aimerait pas la richesse, n’aimerait pas la gloire, n’aimerait pas la sagesse étant survenue à lui, craignant (par crainte) d’en être privé. Et en effet nous voyons la vertu, au prix de laquelle aucune possession n’est plus grande, ni plus agréable, déplacée (chassée) par des maladies et des breuvages; et rien de plus n’être pour l’exemption-de-crainte à '''Thalès''' lui-même ne s’étant pas marié, s’il n’avait pas évité la possession et d’amis et de parents et de patrie. Mais même il eut un fils adoptif se l’étant fait tel lui-même, celui de sa sœur, comme on dit '''Cybisthe'''.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f7.item <u>Plutarque, Vie de Solon</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f27.item ''chap. II''], traduction littérale et juxtalinéaire présentant le mot à mot français en regard des mots grecs correspondants, par une société de professeurs et d’helléniste, 1862</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ====== <div style="text-align: center;">Paragraphe XV.</div> ====== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;"> Testament d’inhumation de '''Thalès'''.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">'''XV.''' Καὶ φόβοι τινὲς ἐκ δεισιδαιμονίας ἅμα καὶ φάσματα κατεῖχε τὴν πόλιν, οἵ τε μάντεις ἄγη καὶ μιασμοὺς δεομένους καθαρμῶν προφαίνεσθαι διὰ τῶν ἱερῶν ἠγόρευον. Οὕτω δὴ μετάπεμπτος αὐτοῖς ἧκεν ἐκ Κρήτης Ἐπιμενίδης ὁ Φαίστιος, ὃν ἕβδομον ἐν τοῖς σοφοῖς καταριθμοῦσιν ἔνιοι τῶν οὐ προσιεμένων τὸν Περίανδρον. Ἐδόκει δέ τις εἶναι θεοφιλὴς καὶ σοφὸς περὶ τὰ θεῖα τὴν ἐνθουσιαστικὴν καὶ τελεστικὴν σοφίαν, διὸ καὶ παῖδα νύμφης ὄνομα Βάλτης καὶ Κούρητα νέον αὐτὸν οἱ τότε ἄνθρωποι προσηγόρευον. <br /><p style="text-align: center">[...]<br /><p style="text-indent: 15px; text-align: justify;">Τὸ δὲ μέγιστον, ἱλασμοῖς τισι καὶ καθαρμοῖς καὶ ἱδρύσεσι κατοργιάσας καὶ καθοσιώσας τὴν πόλιν ὑπήκοον τοῦ δικαίου καὶ μᾶλλον εὐπειθῆ πρὸς ὁμόνοιαν κατέστησε. Λέγεται δὲ τὴν Μουνυχίαν ἰδὼν καὶ καταμαθὼν πολὺν χρόνον, εἰπεῖν πρὸς τοὺς παρόντας ὡς τυφλόν ἐστι τοῦ μέλλοντος ἄνθρωπος· ἐκφαγεῖν γὰρ ἂν Ἀθηναίους τοῖς αὑτῶν ὀδοῦσιν, εἰ προῄδεσαν ὅσα τὴν πόλιν ἀνιάσει τὸ χωρίον· ὅμοιον δέ τι καὶ Θαλῆν εἰκάσαι λέγουσι· κελεῦσαι γὰρ αὐτὸν ἔν τινι τόπῳ τῆς Μιλησίας φαύλῳ καὶ παρορωμένῳ τελευτήσαντα θεῖναι, προειπὼν ὡς ἀγορά ποτε τοῦτο Μιλησίων ἔσται τὸ χωρίον. Ἐπιμενίδης μὲν οὖν μάλιστα θαυμασθείς, καὶ χρήματα διδόντων πολλὰ καὶ τιμὰς μεγάλας τῶν Ἀθηναίων, οὐδὲν ἢ θαλλὸν ἀπὸ τῆς ἱερᾶς ἐλαίας αἰτησάμενος καὶ λαβὼν ἀπῆλθεν. </div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://remacle.org/bloodwolf/historiens/Plutarque/solon.htm <u>Plutarque, Vie de Solon</u>], ''chap. II'', ''§15'', traduction par [[w:Dominique_Ricard|Dominique Ricard]], 1844<br />(également disponible une édition de 1853 [https://remacle.org/bloodwolf/historiens/Plutarque/solonpierrron.htm ici] et de 1862 [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f26.item là])</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 390px; border: 2px solid; text-indent: 15px"><br /><div style="margin: 0 2em; text-align: justify; direction: ltr;">'''XV.''' Au chagrin que ces pertes causèrent à ceux-ci [les ''Athéniens''], se joignirent des craintes superstitieuses dont la ville [''Athènes''] fut frappée, et qui venaient d’apparitions de spectres et de fantômes. Les devins déclarèrent aussi que l’état des victimes qu’ils avaient offertes annonçait des crimes et des profanations qu’il fallait expier. On fit donc venir de ''Crète'' [[w:Épiménide|'''Épiménide''']] [[#Épiménide|<span id="Épiménide_back"><sup>'''I'''</sup></span>]] le [[w:Phaistos|''Phestien'']] [[#Phaistos|<span id="Phaistos_back"><sup>'''II'''</sup></span>]], qui est mis au nombre des sept sages par ceux qui n’y comptent pas '''Périandre'''. Il passait pour un homme chéri des dieux, doué d’une grande sagesse, fort instruit des choses divines, surtout versé dans la science des inspirations et dans la connaissance des mystères; on l’appelait, même de son vivant, le nouveau [[w:Curètes|'''Curète''']], le fils de la nymphe '''Balté'''.<br /><p style="text-align: center">[...]<br /><p style="text-indent: 15px; text-align: justify;">Mais ce qui était plus important, il fit un grand nombre d’expiations et de sacrifices, il fonda plusieurs temples; et par ces différentes cérémonies il purifia entièrement la ville, en bannit l’impiété et l’injustice, et la rendit plus soumise, plus disposée à l’union et à la paix. On rapporte aussi que lorsqu’il vit le fort de [[w:Munichie|''Munychium'']] [[#Munichie|<span id="Munichie_back"><sup>'''III'''</sup></span>]], il le considéra longtemps, et dit à ceux qui l’accompagnaient : Que les hommes sont aveugles sur l’avenir ! Si les ''Athéniens'' pouvaient prévoir tous les maux que ce lieu doit un jour causer à leur ville, ils l’emporteraient à belles dents ». '''Thalès''' eut aussi, dit-on, un pressentiment à peu près semblable. Il ordonna qu’on l’enterrât dans le lieu le plus sauvage et le plus désert du territoire de ''Milet''; et il prédit aux ''Milésiens'' qu’un jour leur marché public y serait transporté. Les ''Athéniens'', pleins de reconnaissance et d’admiration pour '''Épiménide''', voulurent le combler d’honneurs et de présents; mais il ne demanda qu’une branche de l’olivier sacré, qui lui fut accordée, et il s’en retourna en ''Crète''.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://archive.org/details/viesdeshommesill01plut/page/n6/mode/1up?view=theater <u>Vie des Hommes Illustres de Plutarque</u>], [https://archive.org/details/viesdeshommesill01plut/page/182/mode/1up?view=theater ''Solon''], ''Chap. II'', ''§15'',[https://archive.org/details/viesdeshommesill01plut/page/185/mode/1up?view=theater p.185], traduit par [[w:Alexis_Pierron|Alexis Pierron]], professeur au lycée Louis-le-Grand, 1877<br />(également disponible une édition de 1853 [[s:Vies_des_hommes_illustres/Solon|ici]])</div> {{Boîte déroulante début|titre=NdA trad. par Alexis Pierron de 1877|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Épiménide_back|<span id="Épiménide"><sup>I</sup></span>]] Du nom propre grec ancien Ἐπιμενίδης / Epimenídēs [[wikt:en:Ἐπιμενίδης#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px">Poète, philosophe et [[w:Iatromante|''iatromante'']] crétois.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] milieu du [[w:VIe_siècle_av._J.-C.|VI<sup>ème</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]]) <br /><br /><p style="margin: 0 2em; text-indent: 15px">'''[[#Phaistos_back|<span id="Phaistos"><sup>II</sup></span>]] Du nom propre grec ancien Φαιστός / Phaistós [[wikt:en:Φαιστός#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px">Ancienne ville du Sud de la [[w:Histoire_de_la_Crète#Antiquité|''Crète'']].<br /><br /><p style="margin: 0 2em; text-indent: 15px">[[#Munichie_back|<span id="Munichie"><sup>III</sup></span>]] Du nom propre grec ancien Μουνιχία / Mounikhia [[wikt:en:Μουνυχία#Grec_ancien|(en)]] ;<br /><p style="margin: 0 2em; text-indent: 15px">Nom d’une colline du [[w:Le_Pirée|''Pirée'']] et de l’[[w:Port_de_Munichie|un des ports du ''Pirée'']].'''<br/><br/></div> {{Boîte déroulante fin}} <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">'''XII.''' Au chagrin que ces pertes causèrent à ceux-ci, se joignirent des craintes superstitieuses dont la ville fut frappée, et qui venaient d’apparitions de spectres et de fantômes. Les devins déclarèrent aussi que l’état des victimes annonçait des crimes et des profanations qu’il fallait expier. On fit donc venir de ''Crète'' '''Épiménide''' le ''Phestien'' qui est mis au nombre des sept sages par ceux qui n’y comptent pas '''Périandre'''. Il passait pour un homme chéri des dieux, doué d’une grande sagesse, fort instruit des choses divines, surtout versé dans la science des inspirations et dans la connaissance des mystères; on l’appelait, même de son vivant, le nouveau '''Curète''', le fils de la nymphe '''Balté'''.<br /><p style="text-align: center">[...]<br /><p style="text-indent: 15px; text-align: justify;">Mais ce qui était plus important, il fit un grand nombre d’expiations et de sacrifices; il fonda plusieurs temples; et par ces différentes cérémonies, il purifia entièrement la ville, en bannit l’impiété et l’injustice, et la rendit plus soumise, plus disposée à l’union et à la paix. On rapporte aussi que lorsqu’il vit ''Munychie'', il la considéra longtemps, et dit à ceux qui l’accompagnaient :<br /><p style="text-align: justify; text-indent: 15px"> « Que les hommes sont aveugles sur l’avenir! Si les ''Athéniens'' pouvaient prévoir tous les maux que ce lieu doit un jour causer à leur ville, il l’emporteraient à belles dents. »<br /><p style="text-align: justify; text-indent: 15px"> '''Thalès''' eut aussi, dit-on, un pressentiment à peu près semblable. Il ordonna qu’on l’enterrât dans le lieu le plus sauvage et le plus désert du territoire de ''Milet''; et il prédit aux ''Milésiens'' qu’un jour leur marché public y serait transporté. Les ''Athéniens'', pleins de reconnaissance et d’admiration pour '''Épiménide''', voulurent le combler d’honneurs et de présents; mais il ne demanda qu’une branche de l’olivier sacré, qui lui fut accordée, et il s’en retourna en ''Crète''.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f7.item <u>Plutarque, Vie de Solon</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f58.item ''chap. II''], traduction correcte et précédée du texte grec, par une société de professeurs et d’helléniste, 1862<br />(également disponible une édition de 1844 [https://remacle.org/bloodwolf/historiens/Plutarque/solon.htm#1a ici] et de 1829 [[s:Les_Vies_des_hommes_illustres/Vie_de_Solon|là]])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Et certaines craintes nées de la superstition en-même-temps aussi des apparitions occupaient la ville; et les devins disaient des impiétés et des souillures ayant-besoin de purifications être indiquées par les victimes. Et ainsi vint à eux mandé (ils firent venir) de ''Crète'' '''Épiménide''' le ''Phestien'', que quelques-uns de ceux n’admettant pas '''Périandre''' comptent le septième parmi les sages. Or il avait-la-réputation d’être un homme ami-des-dieux, et habile dans la science de-l’inspiration et des-mystères. C’est-pourquoi les hommes d’alors appelaient lui et fils de la nymphe de nom (nommée) '''Balté''', et nouveau '''Curète'''.<br /><p style="text-align: center">[...]<br /><p style="text-indent: 15px; text-align: justify;">Mais le plus grand (le plus important), ayant initié-aux-mystères et ayant purifié la ville par certaines expiations et purifications et fondations, il la rendit prêtant-l’oreille à la justice et plus obéissante pour la concorde. Et il est dit, ayant vu ''Munychie'' et l’ayant examinée un temps long, avoir dit à ceux présents, que l’homme est un être aveugle sur l’avenir ; car les ''Athéniens'' avoir dû manger ''Munychie'' avec les dents d’eux-mêmes, s’ils avaient prévu en combien de choses cette place affligera la ville. Et on dit aussi '''Thalès''' avoir conjecturé quelque chose de semblable; lui avoir ordonné en effet de placer lui ayant cessé de vivre dans un certain lieu de la ''Milésie'' méprisé et dédaigné, ayant prédit que cet endroit sera (serait) un jour le marché des ''Milésiens''. '''Épiménide''' donc ayant été admiré très-grandement, et les ''Athéniens'' lui donnant des sommes nombreuses et des honneurs grands, n’ayant demandé rien qu’un rameau détaché de l’olivier sacré et l’ayant pris (reçu) s’en alla.</div> <div style="text-align: right; margin: 0 2em 0 1em;">[https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f7.item <u>Plutarque, Vie de Solon</u>], [https://gallica.bnf.fr/ark:/12148/bpt6k6226675w/f59.item ''chap. II''], traduction littérale et juxtalinéaire présentant le mot à mot français en regard des mots grecs correspondants, par une société de professeurs et d’helléniste, 1862</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto; color: #3366BB">═✳═</div> === [[w:Œuvres_morales|Œuvres morales]] [[#Œuvres_morales|<span id="Œuvres_morales_back"><sup>'''I'''</sup></span>]] === <div style="text-align: center; margin: 0 1em;">Ensemble de 78 textes de traitant de sujets extrêmement variés (religieux, éthiques, politiques, philosophiques, littéraires, historiques), et s'inscrivant dans des genres littéraires également divers (traité, différentes sortes de dialogues, lettres, réponses à des Questions ([[wikt:ζήτημα#Grec_ancien|''zetemata'']]), « dits » ([[w:Apophtegme|''apophtegmes'']])).</div> {{Boîte déroulante début|titre=NdA Le Banquet des Septs Sages|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Cléobuline_back|<span id="Cléobuline"><sup>I</sup></span>]] En grec ancien Ἠθικὰ / Ethikà [[wikt:en:ἠθικός#Ancient_Greek|(en)]], «1. Relatif au caractère ou au tempérament : • (d’une personne) Qui exprime ou manifeste sa nature ; • (théâtre) Conforme au personnage. 2. Éthique moral (relatif à la moralité) : (philosophie) Relatif à l’éthique (l’étude des principes régissant la conduite juste ou injuste) ; (d’un texte) qui traite de la conduite et de la vertu. 3. (rhétorique) Empreint de tact. » ; <br /><p style="margin: 0 2em; text-indent: 15px;">➥ du nom commun ἦθος / êthos [[wikt:en:ἦθος#Ancient_Greek|(en)]], « 1. Le lieu habituel ou coutumier (de quelque chose) : • Le domicile ou le lieu de résidence (d’une personne) ; • Le territoire (d’un animal). 2. Le caractère ; le tempérament : • (théâtre) Personnage (dramatique). 3. La coutume ; l’habitude : • (au pluriel) Les manières ; l’étiquette. » ;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ +‎ du suffixe adjectival -ῐκός/-ĭkós, « relatif à, à la manière de ; -ique ».<br /><br /><p style="margin: 0 2em; text-indent: 15px;">En latin Moralia ; de l’adjectif mōrālis [[wikt:en:moralis#Latin|(en)]], « Qui a trait aux mœurs ou à l'éthique ; moral. » ;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ du nom commun mōs [[wikt:en:mos#Latin|(en)]], « 1. Manière d’agir ; comportement ; conduite. 2. Coutume ; habitude ; pratique ; usage. 3. (surtout au pluriel) Caractère ; disposition ; inclination ; tempérament. 4. Volonté ; obstination ; humeur ; caprice. 5. (sens dérivé) Qualité ; nature ; mode ; façon. 6. (sens dérivé) Précepte ; loi ; règle. 7. (au pluriel uniquement) mœurs ; principes »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ + du suffixe adjectival -ālis [[wikt:en:-alis#Latin|(en)]]. Utilisé pour la première fois par Cicéron pour traduire le terme grec ancien ēthikós, « moral ». <br /><br /><p style="margin: 0 2em; text-indent: 15px;">En retraçant l’usage de l’adjectif ἠθικός à partir de la Rhétorique d’Aristote, le professeur de littérature latine [https://cv.hal.science/charles-guerin Charles Guérin] démontre que Cicéron l’utilise dans son dernier traité rhétorique non comme un équivalent du style moyen, mais comme une catégorie nouvelle permettant d’opposer éloquence du ''mouere'' [[wikt:en:movere#Latin|(en)]] et éloquence du ''conciliare'' [[wikt:en:conciliare#Latin|(en)]]. Cicéron réintroduit ainsi dans son traité la notion de conciliation du public qu’il avait tout d’abord éliminée de son architecture théorique (au profit de la notion de ''delectare'' [[wikt:en:delectare#Latin|(en)]]) afin de garantir la cohérence conceptuelle de sa doctrine. L’ἠθικόν correspond ainsi à l’idée d’une adaptation du style à l’orateur, non sur le mode pragmatique défendu par Aristote (chez qui la λέξις ἠθική désigne l’adaptation du style aux caractéristiques concrètes de l’orateur), mais sur un mode idéalisant : l’ἠθικόν est une catégorie stylistique prescriptive, celle du style de l’orateur accompli [https://hal.science/hal-03189440 {{Info|<sup>🔍</sup>|Charles Guérin. Orator 128: Cicéron et la catégorie rhétorique de l’ethikon. Pierre Chiron; Carlos Lévy. Les noms du style, Peeters, pp.143-164, 2010. ⟨hal-03189440⟩}}].<br /><br /></div> {{Boîte déroulante fin}} ==== Le Banquet des Sept Sages ==== {| cellpadding="0" align="{{{align|right}}}" style="margin-left: 2em; width:40%; border-spacing:3px; text-align:center; background-color:#F8F9FA; border:2px solid #C8CCD1" |- | style="border:solid 1px #F8F9FA" | '''Manuscrit''' [https://archive.org/details/p.-oxy.-16/Oxyrhynchus%20Papyri/P.%20Oxy.%2052/page/n66/mode/1up {{info|<sup>➕</sup>|The Oxyrhynchus Papyri, Volume LII, 1984}}] [https://books.google.fr/books?id=qfl1xwEACAAJ&lpg=PA1059&hl=fr&pg=PA1171#v=onepage&q=Plutarque&f=false {{info|<sup>➕➕</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume Vb, §210 - Plutarque de Chéronée, p.1171}}] |- style="font-size:8pt; line-height:10pt; vertical-align:middle" | align="center" | <div style="margin-right: 1em; padding:0 0 4px 0; text-align:justify;">{{{légende| Le P. Oxy. 3685 conserve les vestiges assez détériorés de deux colonnes du Banquet des Sept Sages, datant de la première moitié du [[w:IIe_siècle|II<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]], c’est-à-dire presque contemporain de '''Plutarque'''. Ce petit fragment de papyrus (9,6 x 8 cm) présente un intérêt à deux titres : * d’une part, sa datation étant proche de l’époque de '''Plutarque''', il apporte des éléments sur l’authenticité de l’œuvre ; * d’autre part, une partie du texte se retrouve également chez '''Stobée'''. Les doutes quant à l'attribution du Banquet des Sept Sages à Plutarque ne semblent être apparus qu'à une époque relativement récente ; en effet, l'ouvrage figure dans ce que l'on appelle le « Catalogue de Lamprias », une liste des œuvres de Plutarque dressée au [[w:IIIe_siècle|III<sup>ème</sup>]] ou au [[w:IVe_siècle|IV<sup>ème</sup>]] siècle {{Info|EC|de l’Ère Commune}}. Toutefois, ces réserves ont désormais été levées de manière convaincante par J. Defradas pp.7-12 de l’édition de la Budé de 1985. NB : Les [[w:Papyrus_d%27Oxyrhynque|''papyrus d’Oxyrhynque'']] constituent un ensemble de manuscrits découverts à la fin du [[w:XIXe_siècle|XIX<sup>ème</sup>]] et au début du [[w:XXe_siècle|XX<sup>ème</sup>]] siècles {{Info|EC|de l’Ère Commune}} par les papyrologues [[w:Bernard_Pyne_Grenfell|'''Bernard Pyne Grenfell''']] et [[w:Arthur_Surridge_Hunt|'''Arthur Surridge Hunt''']], dans une ancienne décharge située près d’[[w:Oxyrhynque|''Oxyrhynque'']], en ''Égypte''.}}}</div> |} <div style="text-align: center; margin: 0 1em;">Dialogue faisant intervenir 20 personnages, dont une liste des sept sages : '''Thalès''', [[w:Solon|'''Solon''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Solon_back|<sup>🔄</sup>]], [[w:Bias_de_Priène|'''Bias''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Bias_back|<sup>🔄</sup>]], [[w:Chilon|'''Chilon''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Chilon_back|<sup>🔄</sup>]], [[w:Cléobule|'''Cléobule''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Cléobule_back|<sup>🔄</sup>]], [[w:Pittacos_de_Mytil%C3%A8ne|'''Pittacos''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Pittacos_back|<sup>🔄</sup>]], [[w:Périandre|'''Périandre''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Périandre_back|<sup>🔄</sup>]].</div> <div style="text-align: left; margin: 0 1em;">À ceux-ci se rajoutent : * [[w:Anacharsis|'''Anacharsis''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Anacharsis_back|<sup>🔄</sup>]], * '''[[w:Ésope|Ésope]]''' [[#Ésope|<span id="Ésope_back"><sup>'''I'''</sup></span>]], * '''Dioclès''' le ''devin'' et narrateur (possiblement fictif) [[#Dioclès_Cléodème_Chersias|<span id="Dioclès_Cléodème_Chersias_back"><sup>'''II'''</sup></span>]], * '''Nicarque''' le destinataire du récit (possiblement fictif), * [[w:Cléobuline|'''Cléobuline''']] [[#Cléobuline|<span id="Cléobuline_back"><sup>'''III'''</sup></span>]], * '''Mélissa''' la conjointe de '''Périandre''', * '''Niloxène''', * '''Alexidème''' un bâtard du ''tyran'' [[w:Thrasybule_de_Milet|'''Thrasybule''' de ''Milet'']], * '''Ardalus''' le joueur de flûte [[w:Trézène_(ville)|''trézénien'']] [[#Trézène|<span id="Trézène_back"><sup>'''IV'''</sup></span>]], * '''Cléodème''' le ''médecin'' (possiblement fictif) [[#Dioclès_Cléodème_Chersias|<sup>'''II'''</sup>]], * '''Mnésiphile''' un disciple de '''Solon''', * '''Chersias''' le ''poète'' (possiblement fictif) [[#Dioclès_Cléodème_Chersias|<sup>'''II'''</sup>]], * [[w:Gorgias|'''Gorgias''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Gorgias_back|<sup>🔄</sup>]].</div> {{Boîte déroulante début|titre=NdA Le Banquet des Septs Sages|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Ésope_back|<span id="Ésope"><sup>I</sup></span>]] Du nom propre grec ancien Αἴσωπος / Aísōpos ;<br /><p style="margin: 0 2em; text-indent: 15px;">Sous le nom d’Ésope ont circulé dans l’antiquité différents recueils de fables qui ont connu un succès universel et ont été traduites et imitées dans toute la tradition littéraire postérieure. On peut y voir l’expression d’une éthique populaire, rationaliste et cosmopolite, qui n’est pas sans intérêt pour l’histoire de la philosophie. Selon Hérodote, (livre II, chap. 134), il serait un ancien esclave d’Iadmon de ''Samos''.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] seconde moitié du [[w:VIe_siècle_av._J.-C.|VI<sup>ème</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]], selon la Souda, ({{Info|s.v.|Abréviation du latin sub verbo, « À l’article, à l’entrée, au mot. »}} Αἴσωπος, Αι 334), il aurait été précipité du haut des [[w:Phédriades|''Roches Phédriades'']] à ''Delphes'' en la 54<sup>ème</sup> Olympiade (564/561))[https://books.google.fr/books?id=DrvWAAAAMAAJ&newbks=1&newbks_redir=0&lpg=PA5&dq=bibliogroup%3A%22Dictionnaire%20des%20philosophes%20antiques%22&hl=fr&pg=PA240#v=onepage&q&f=false {{Info|<sup>🔍</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume III, §60 - Ésope (Αἴσωπος)}}] <br /><br /><p style="margin: 0 2em; text-indent: 15px;">'''[[#Dioclès_Cléodème_Chersias_back|<span id="Dioclès_Cléodème_Chersias"><sup>II</sup></span>]] D’après l’historienne [https://research-bulletin.chs.harvard.edu/authors/zoe-stamatopoulou/ Zoe Stamatopoulou] [https://research-bulletin.chs.harvard.edu/2017/04/17/periander-plutarch-symposium/ {{info|<sup>🔍</sup>|Stamatopoulou, Zoe. “Constructing Periander in Plutarch’s Symposium of the Seven Sages.” CHS Research Bulletin 5, no. 1 (2016). http://nrs.harvard.edu/urn-3:hlnc.essay:StamatopoulouZ.Constructing_Periander.2016.}}], il s’agit de non-Sages individualisés par leur profession. <br /><br /><p style="margin: 0 2em; text-indent: 15px;">'''[[#Cléobuline_back|<span id="Cléobuline"><sup>III</sup></span>]] Du nom propre grec ancien Κλεοβουλίνη / Kleoboulinè ;<br /><p style="margin: 0 2em; text-indent: 15px">➥ de Κλεόβουλος / Kleóboulos [[wikt:en:Κλεόβουλος#Ancient_Greek|(en)]], « Cléobule, le père de Cléobuline » <br /><p style="margin: 0 2em; text-indent: 15px">➥ du suffixe adjectival féminin -ῑ́νη / -ī́nē [[wikt:en:-ίνη#Ancient_Greek|(en)]], relatif à la matière, au temps, etc. : « fait de, pendant la durée de » ;<br /><p style="margin: 0 2em; text-indent: 15px">Philosophe et poétesse grecque, célèbre pour ses énigmes, fille du [[w:Tyran|''tyran'']] de [[w:Rhodes|''Rhodes'']], Cléobule, qui la surnommerait Εὔμητις / Eúmētis, « la Prudente » selon Plutarque.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:VIe_siècle_av._J.-C.|VI<sup>ème</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]], originaire de [[w:Lindos|''Lindos'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Lindos_back|<sup>🔄</sup>]] sur l’île de ''Rhodes'') <br /><br /><p style="margin: 0 2em; text-indent: 15px;">'''[[#Trézène_back|<span id="Trézène"><sup>IV</sup></span>]] Du nom propre grec ancien Τροιζήν / Troizḗn [[wikt:en:Τροιζήν#Ancient_Greek|(en)]] ;<br /><p style="margin: 0 2em; text-indent: 15px">[[w:polis|Cité grecque]] du [[w:Péloponnèse|''Péloponnèse'']], sur la côte nord de l’[[w:Argolide|''Argolide'']]. '''<br/><br/></div> {{Boîte déroulante fin}} ===== <div style="text-align: center;">Paragraphe I.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">'''Dioclès''' raconte le Banquet des Sept Sages organisé par '''Périandre''', pendant lequel il fût l’hôte de '''Thalès'''.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§1. Ἦ που προϊὼν ὁ χρόνος, ὦ '''Νίκαρχε''', πολὺ σκότος ἐπάξει τοῖς πράγμασι καὶ πᾶσαν ἀσάφειαν, εἰ νῦν ἐπὶ προσφάτοις οὕτω καὶ νεαροῖς λόγοι ψευδεῖς συντεθέντες ἔχουσι πίστιν. οὔτε γὰρ μόνων, ὡς ὑμεῖς ἀκηκόατε, τῶν ἑπτὰ γέγονε τὸ συμπόσιον, ἀλλὰ πλειόνων ἢ δὶς τοσούτων (ἐν οἷς καὶ αὐτὸς ἤμην, συνήθης μὲν ὢν '''Περιάνδρῳ''' διὰ τὴν τέχνην, ξένος δὲ '''Θάλεω'''· παρ´ ἐμοὶ γὰρ κατέλυσεν ὁ ἀνὴρ '''Περιάνδρου''' κελεύσαντος), οὔτε τοὺς λόγους ὀρθῶς ἀπεμνημόνευσεν ὅστις ἦν ὑμῖν ὁ διηγούμενος· ἦν δ´ ὡς ἔοικεν οὐδεὶς τῶν παραγεγονότων. ἀλλ´ ἐπεὶ σχολή τε πάρεστι πολλὴ καὶ τὸ γῆρας οὐκ ἀξιόπιστον ἐγγυήσασθαι τὴν ἀναβολὴν τοῦ λόγου, προθυμουμένοις ὑμῖν ἀπ´ ἀρχῆς ἅπαντα διηγήσομαι. </div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §1'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§1. '''D<span style ="font-size:85%;">IOCLÈS</span>'''. Certainement le long cours des âges, mon cher '''Nicarque''', jettera sur les faits d’épaisses ténèbres et une complète incertitude, puisque dès aujourd’hui, à propos de choses si récentes et si nouvelles, des relations mensongères et controuvées obtiennent crédit. Car d’abord le banquet en question ne se composait pas seulement des sept sages, comme vous autres l’avez ouï dire. Les convives étaient plus du double de ce nombre. J’en faisais moi-même partie, comme familier de '''Périandre''' en raison de notre profession commune, et comme hôte de '''Thalès''' : ce dernier était en effet descendu chez moi sur la recommandation de '''Périandre'''. Ensuite, on ne vous en a pas rapporté fidèlement les entretiens lorsqu’on vous a fait ce récit. Il faut que celui de qui vous le tenez n’ait pas été un des convives. Mais puisque nous avons un ample loisir et que la vieillesse est un garant trop peu sûr pour nous autoriser à remettre cet entretien, je vais, suivant votre désir unanime, vous en raconter tous les détails à partir du commencement. </div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §1'', traduction par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870<br/>(également disponible [[s:Page:Plutarque_-_Œuvres_complètes_de_Plutarque_-_Œuvres_morales_et_œuvres_diverses,_tome_1,_1870.djvu/424|ici]])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">'''D<span style ="font-size:85%;">IOCLÈS</span>'''. Quelle incertitude et quelle obscurité la succession des temps ne doit-elle pas répandre sur l’histoire, mon cher '''Nicarque''', puisque, dans des faits récents, et qui se sont passés presque sous nos yeux, le faux prend la place du vrai ? Ce banquet n’était pas, comme on vous l’a dit, composé seulement des sept sages ; les convives étaient plus du double de ce nombre. J’y assistai moi-même, et comme ami de '''Périandre''', avec qui ma profession ma lié depuis longtemps [[#Dioclès_NdT_DR|<span id="Dioclès_NdT_DR_back"><sup>1</sup></span>]], et comme hôte de '''Thalès''', à qui '''Périandre''' avait fait marquer son logement chez moi. Celui qui vous a fait le récit de ce qui s’y est passé n’en était sûrement pas, et vous a trompé sur presque tous les points. Mais, puisque nous en avons le loisir, et que notre âge avancé ne nous permet guère de différer, je vais vous satisfaire et vous en raconter tous les détails.</div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Dioclès_NdT_DR_back|<span id="Dioclès_NdT_DR"><sup>1.</sup></span>]] Dioclès était devin.''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' pp.325, 326, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe II.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage de la simplicité de '''Thalès''', de sa mesure de la pyramide d’''Égypte'' [[#mesure_pyramide|<span id="mesure_pyramide_back"><sup>'''I'''</sup></span>]], et de son aversion des [[w:Tyran|''tyrans'']] et des rois.</div> {{Boîte déroulante début|titre=NdA Mesure de la Pyramide d’Égypte|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#mesure_pyramide_back|<span id="mesure_pyramide"><sup>I</sup></span>]]'''<br/><br/></div> {{Boîte déroulante fin}} :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§2. Παρεσκευάκει μὲν γὰρ οὐκ ἐν τῇ πόλει τὴν ὑποδοχὴν ὁ Περίανδρος, ἀλλ´ ἐν τῷ περὶ τὸ Λέχαιον ἑστιατορίῳ παρὰ τὸ τῆς Ἀφροδίτης ἱερόν, ἧς ἦν καὶ ἡ θυσία. μετὰ γὰρ τὸν ἔρωτα τῆς μητρὸς αὐτοῦ προεμένης τὸν βίον ἑκουσίως οὐ τεθυκὼς τῇ Ἀφροδίτῃ, τότε πρῶτον ἔκ τινων ἐνυπνίων τῆς Μελίσσης ὥρμησε τιμᾶν καὶ θεραπεύειν τὴν θεόν. Τῶν δὲ κεκλημένων ἑκάστῳ συνωρὶς ἱκανῶς κεκοσμημένη προσήχθη· καὶ γὰρ ὥρα θέρους ἦν, καὶ τὴν ὁδὸν ἅπασαν ὑπὸ πλήθους ἁμαξῶν καὶ ἀνθρώπων ἄχρι θαλάττης κονιορτὸς καὶ θόρυβος κατεῖχεν. ὁ μέντοι Θαλῆς τὸ ζεῦγος ἐπὶ ταῖς θύραις ἰδὼν καὶ μειδιάσας ἀφῆκεν. ἐβαδίζομεν οὖν ἐκτραπόμενοι διὰ τῶν χωρίων, καθ´ ἡσυχίαν, καὶ μεθ´ ἡμῶν τρίτος ὁ Ναυκρατίτης Νειλόξενος, ἀνὴρ ἐπιεικὴς καὶ τοῖς περὶ Σόλωνα καὶ Θαλῆν γεγονὼς ἐν Αἰγύπτῳ συνήθης. ἐτύγχανε δὲ πρὸς Βίαντα πάλιν ἀπεσταλμένος· ὧν δὲ χάριν οὐδ´ αὐτὸς ᾔδει, πλὴν ὑπενόει πρόβλημα δεύτερον αὐτῷ κομίζειν ἐν βιβλίῳ κατασεσημασμένον· εἴρητο γάρ, εἰ Βίας ἀπαγορεύσειεν, ἐπιδεῖξαι τοῖς σοφωτάτοις Ἑλλήνων τὸ βιβλίον. « Ἕρμαιον » ὁ Νειλόξενος ἔφη « μοι γέγονεν ἐνταῦθα λαβεῖν ἅπαντας ὑμᾶς, καὶ κομίζω τὸ βιβλίον ὡς ὁρᾷς ἐπὶ τὸ δεῖπνον. » ἅμα δ´ ἡμῖν ἐπεδείκνυε. Καὶ ὁ Θαλῆς γελάσας « εἴ τι κακόν, » εἶπεν, « αὖθις εἰς Πριήνην· διαλύσει γὰρ ὁ Βίας, ὡς διέλυσεν αὐτὸς τὸ πρῶτον. » « Τί δ´ ἦν, » ἔφην ἐγώ, « τὸ πρῶτον; » « Ἱερεῖον, » εἶπεν, « ἔπεμψεν αὐτῷ, κελεύσας τὸ πονηρότατον ἐξελόντα καὶ χρηστότατον ἀποπέμψαι κρέας. ὁ δ´ ἡμέτερος εὖ καὶ καλῶς τὴν γλῶτταν ἐξελὼν ἔπεμψεν· ὅθεν εὐδοκιμῶν δῆλός ἐστι καὶ θαυμαζόμενος. » « Οὐ διὰ ταῦτ´ » ἔφη « μόνον » ὁ Νειλόξενος, « ἀλλ´ οὐ φεύγει τὸ φίλος εἶναι καὶ λέγεσθαι βασιλέων καθάπερ ὑμεῖς, ἐπεὶ σοῦ γε καὶ τἄλλα θαυμάζει, καὶ τῆς [[wikt:en:πυραμίδος#Ancient_Greek|πυραμίδος]] τὴν μέτρησιν ὑπερφυῶς ἠγάπησεν, ὅτι πάσης ἄνευ πραγματείας καὶ μηδενὸς ὀργάνου δεηθεὶς ἀλλὰ τὴν βακτηρίαν στήσας ἐπὶ τῷ πέρατι τῆς σκιᾶς ἣν ἡ πυραμὶς ἐποίει, γενομένων τῇ ἐπαφῇ τῆς ἀκτῖνος δυεῖν τριγώνων, ἔδειξας ὃν ἡ σκιὰ πρὸς τὴν σκιὰν λόγον εἶχε τὴν πυραμίδα πρὸς τὴν βακτηρίαν ἔχουσαν. ἀλλ´, ὅπερ ἔφην, διεβλήθης μισοβασιλεὺς εἶναι, καί τινες ὑβριστικαί σου περὶ τυράννων ἀποφάσεις ἀνεφέροντο πρὸς αὐτόν, ὡς ἐρωτηθεὶς ὑπὸ Μολπαγόρου τοῦ Ἴωνος τί παραδοξότατον εἴης ἑωρακώς, ἀποκρίναιο ‘τύραννον γέροντα,’ καὶ πάλιν ἔν τινι πότῳ, περὶ τῶν θηρίων λόγου γενομένου, φαίης κάκιστον εἶναι τῶν μὲν ἀγρίων θηρίων τὸν τύραννον, τῶν δ´ ἡμέρων τὸν κόλακα· ταῦτα γάρ, εἰ καὶ πάνυ προσποιοῦνται διαφέρειν οἱ βασιλεῖς τῶν τυράννων, οὐκ εὐμενῶς ἀκούουσιν. » « Ἀλλὰ τοῦτο μέν, » εἶπεν ὁ Θαλῆς, « Πιττακοῦ ἐστιν, εἰρημένον ἐν παιδιᾷ ποτε πρὸς Μυρσίλον· ἐγὼ δὲ θαυμάσαιμ´ ἄν, » ἔφη, « οὐ τύραννον ἀλλὰ [[wikt:κυβερνήτης#Grec_ancien|'''κυβερνήτην''']] γέροντα θεασάμενος. πρὸς δὲ τὴν μετάθεσιν τὸ τοῦ νεανίσκου πέπονθα τοῦ βαλόντος μὲν ἐπὶ τὴν κύνα πατάξαντος δὲ τὴν μητρυιὰν καὶ εἰπόντος ‘οὐδ´ οὕτω κακῶς.’ διὸ καὶ Σόλωνα σοφώτατον ἡγησάμην οὐ δεξάμενον τυραννεῖν. καὶ Πιττακὸς οὗτος εἰ μοναρχίᾳ μὴ προσῆλθεν, οὐκ ἂν εἶπεν ὡς ‘χαλεπὸν ἐσθλὸν ἔμμεναι.’ Περίανδρος δ´ ἔοικεν ὥσπερ ἐν νοσήματι πατρῴῳ τῇ τυραννίδι κατειλημμένος οὐ φαύλως ἐξαναφέρειν, χρώμενος ὁμιλίαις ὑγιειναῖς ἄχρι γε νῦν καὶ συνουσίας ἀνδρῶν νοῦν ἐχόντων ἐπαγόμενος, ἃς δὲ '''Θρασύβουλος''' αὐτῷ κολούσεις τῶν ἄκρων οὑμὸς πολίτης ὑφηγεῖται μὴ προσιέμενος. γεωργοῦ γὰρ [[wikt:en:αἶρα#Ancient_Greek|αἴρας]] καὶ [[wikt:ononis|ὀνώνιδας]] ἀντὶ [[wikt:πυρός#Grec_ancien|πυρῶν]] καὶ [[wikt:κριθή#Grec_ancien|κριθῶν]] συγκομίζειν ἐθέλοντος οὐδὲν διαφέρει τύραννος ἀνδραπόδων μᾶλλον ἄρχειν ἢ ἀνδρῶν βουλόμενος· ἓν γὰρ ἀντὶ πολλῶν κακῶν ἀγαθὸν αἱ δυναστεῖαι τὴν τιμὴν ἔχουσι καὶ τὴν δόξαν, ἄνπερ ἀγαθῶν ὡς κρείττονες ἄρχωσι καὶ μεγάλων μείζονες εἶναι δοκῶσι· τὴν δ´ ἀσφάλειαν ἀγαπῶντας ἄνευ τοῦ καλοῦ προβάτων ἔδει πολλῶν καὶ ἵππων καὶ βοῶν ἄρχειν, μὴ ἀνθρώπων. ἀλλὰ γὰρ εἰς οὐδὲν προσήκοντας ἐμβέβληκεν ἡμᾶς, » ἔφη, « ὁ ξένος οὑτοσὶ λόγους, ἀμελήσας λέγειν τε καὶ ζητεῖν ἃ ἁρμόττει ἐπὶ δεῖπνον βαδίζουσιν. ἦ γὰρ οὐκ οἴει, καθάπερ ἑστιάσοντος ἔστι τις παρασκευή, καὶ δειπνήσοντος εἶναι; Συβαρῖται μὲν γὰρ ὡς ἔοικε πρὸ ἐνιαυτοῦ τὰς κλήσεις ποιοῦνται τῶν γυναικῶν, ὅπως ἐκγένοιτο κατὰ σχολὴν παρασκευασαμέναις ἐσθῆτι καὶ χρυσῷ φοιτᾶν ἐπὶ τὸ δεῖπνον· ἐγὼ δὲ πλείονος οἶμαι χρόνου δεῖσθαι τὴν ἀληθινὴν τοῦ δειπνήσοντος ὀρθῶς παρασκευήν, ὅσῳ χαλεπώτερόν ἐστιν ἤθει τὸν πρέποντα κόσμον ἢ σώματι τὸν περιττὸν ἐξευρεῖν καὶ ἄχρηστον. οὐ γὰρ ὡς ἀγγεῖον ἥκει κομίζων ἑαυτὸν ἐμπλῆσαι πρὸς τὸ δεῖπνον ὁ νοῦν ἔχων, ἀλλὰ καὶ σπουδάσαι τι καὶ παῖξαι καὶ ἀκοῦσαι καὶ εἰπεῖν ὡς ὁ καιρὸς παρακαλεῖ τοὺς συνόντας, εἰ μέλλουσι μετ´ ἀλλήλων ἡδέως ἔσεσθαι. καὶ γὰρ καὶ ὄψον πονηρὸν ἔστι παρώσασθαι, κἂν οἶνος ᾖ φαῦλος, ἐπὶ τὰς νύμφας καταφυγεῖν· σύνδειπνος δὲ κεφαλαλγὴς καὶ βαρὺς καὶ ἀνάγωγος παντὸς μὲν οἴνου καὶ ὄψου πάσης δὲ μουσουργοῦ χάριν ἀπόλλυσι καὶ λυμαίνεται, καὶ οὐδ´ ἀπεμέσαι τὴν τοιαύτην ἀηδίαν ἕτοιμόν ἐστιν, ἀλλ´ ἐνίοις εἰς ἅπαντα τὸν βίον ἐμμένει τὸ πρὸς ἀλλήλους δυσάρεστον, ὥσπερ ἑωλοκρασία τις ὕβρεως ἢ ὀργῆς ἐν οἴνῳ γενομένης. ὅθεν ἄριστα Χίλων, καλούμενος ἐχθές, οὐ πρότερον ὡμολόγησεν ἢ πυθέσθαι τῶν κεκλημένων ἕκαστον. ἔφη γὰρ ὅτι σύμπλουν ἀγνώμονα δεῖ φέρειν καὶ σύσκηνον οἷς πλεῖν ἀνάγκη καὶ στρατεύεσθαι· τὸ δὲ συμπόταις ἑαυτὸν ὡς ἔτυχε καταμιγνύειν οὐ νοῦν ἔχοντος ἀνδρός ἐστιν. ὁ δ´ Αἰγύπτιος σκελετός, ὃν ἐπιεικῶς εἰσφέροντες εἰς τὰ συμπόσια προτίθενται καὶ παρακαλοῦσι μεμνῆσθαι τάχα δὴ τοιούτους ἐσομένους, καίπερ ἄχαρις καὶ ἄωρος ἐπίκωμος ἥκων, ὅμως ἔχει τινὰ καιρόν, καὶ εἰ μὴ πρὸς τὸ πίνειν καὶ ἡδυπαθεῖν ἀλλὰ πρὸς φιλίαν καὶ ἀγάπησιν ἀλλήλων προτρέπεται, καὶ παρακαλεῖ τὸν βίον μὴ τῷ χρόνῳ βραχὺν ὄντα πράγμασι κακοῖς μακρὸν ποιεῖν. » </div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §2'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§2. La réception avait été préparée par '''Périandre''', non pas dans la ville même, mais dans son [[w:Cénacle|''cénacle'']] du port de [[w:Léchaion|''Léchée'']], près du temple de '''Vénus''' en l’honneur de laquelle il y avait même un sacrifice. Car depuis l’incestueux amour à la suite duquel sa mère avait volontairement abandonné la vie, '''Périandre''' n’avait pas sacrifié à '''Vénus''' ; et c’était alors la première fois que, d’après certains songes de '''Mélissa''' il s’était décidé à honorer la déesse et à lui rendre des hommages. Pour chacun des invités on avait amené un attelage approprié convenablement. Nous étions en été, et tout le long de la route, en raison du grand nombre de chariots et de piétons, ce n’était jusqu’à la mer que poussière et que bruit. Pourtant '''Thalès''', ayant vu l’attelage à notre porte, se mit à sourire et le renvoya. Nous partîmes donc à pied en faisant un détour, et à travers champs nous cheminâmes à loisir. Un troisième compagnon s’était joint à nous, '''Niloxène''' de ''Naucratie'', homme plein de mérite, que '''Thalès''' et '''Solon''' avaient autrefois beaucoup connu en ''Égypte''. Il se trouvait envoyé de nouveau vers '''Bias''' ; mais pour quelle mission ? Il n’en savait rien lui-même, hormis qu’il se soupçonnait porteur d’une seconde question à résoudre, contenue dans un pli cacheté; et il lui avait été dit, au cas où '''Bias''' renoncerait, de la présenter aux plus sages d’entre les Grecs. « C’est », dit '''Niloxène''', « une chance heureuse que de vous trouver ici tous, et j’apporte, comme vous voyez, cette lettre pour le banquet. » En même temps, il nous la faisait voir. '''Thalès''' se mit à rire : « Si c’est une question épineuse », dit-il, « qu’on aille encore à ''Priène'' : '''Bias''' la résoudra comme il a résolu la première. » — « Quelle était donc cette première question ? » lui demandai-je. — « Le roi d’Égypte », dit '''Thalès''', « avait envoyé à '''Bias''' une victime, en lui faisant dire d’en couper ce qu’il y avait de plus mauvais et de meilleur, et de le lui renvoyer. Notre sage, avec un discernement merveilleux, en ôta la langue et la fit porter au Roi. Voilà ce qui lui a valu une estime et une admiration si déclarée ». — « Cette raison n’est pas la seule », ajouta '''Niloxène''' ; « c’est encore, que '''Bias''' ne fuit pas, comme vous autres, l’amitié des rois eux-mêmes. Ainsi, vous, '''Thalès''', le roi d’Égypte vous admire beaucoup, et, entre autres choses, il a été, au-delà de ce qu’on peut dire, ravi de la manière dont vous avez mesuré la pyramide sans le moindre embarras et sans avoir eu besoin d’aucun instrument. Après avoir dressé votre bâton à l’extrémité de l’ombre que projetait la pyramide, vous construisîtes deux triangles par la tangence d’un rayon, et vous démontrâtes qu’il y avait la même proportion entre la hauteur du bâton et la hauteur de la pyramide qu’entre la longueur des deux ombres. Mais, comme j’ai dit, on vous accuse de détester les rois ; quelques boutades injurieuses prononcées par vous contre des ''tyrans'' ont été rapportées à [[w:Ahmôsis_II|'''Amasis''']]. Par exemple, l’Ionien '''Molpagore''' vous ayant demandé ce que vous aviez jamais vu de plus extraordinaire, vous lui auriez répondu : « C’est un tyran parvenu à la vieillesse. » Une autre fois, dans un festin, la conversation étant venue à tomber sur les bêtes féroces, vous auriez dit : « La plus méchante bête parmi les animaux sauvages, c’est le tyran, et parmi les animaux apprivoisés le flatteur. » De tels propos ne sont pas de ceux que les rois entendent avec plaisir, lors même qu’ils affectent de n’avoir rien de commun avec les tyrans. » Pour cette dernière réponse, dit '''Thalès''', elle est de '''Pittacus''' : il l’avait adressée un jour en plaisantant à '''Myrsile'''. Quant au premier propos, ce n’était pas « un tyran » que j’avais dit, mais « un [[wikt:κυβερνήτης#Grec_ancien|''pilote'']] », qui soit parvenu à la vieillesse. Toutefois, puisqu’on a changé la destination du mot, je fais comme le jeune homme qui, ayant jeté une pierre à un chien, atteignit sa belle-mère et s’écria : Même ainsi, ce n’est pas mal. » C’est pourquoi je regardai '''Solon''' comme éminemment sage lorsqu’il n’accepta pas la tyrannie ; et '''Pittacus''', s’il n’eût approché de la monarchie, n’aurait pas eu à dire : « Il est difficile d’être homme de bien. » Quant à '''Périandre''', il semble qu’ayant été saisi par le souverain pouvoir comme par une maladie de famille, il ne s’en tire pas trop mal. Il use, au moins jusqu’à présent, de sociétés salutaires. Il réunit, pour entretenir commerce avec eux, ses hommes remplis de sens ; et le conseil que lui a donné mon compatriote [[w:Thrasybule_de_Milet|'''Thrasybule''']] [[#Thrasybule|<span id="Thrasybule_back"><sup>'''I'''</sup></span>]], de décapiter l’aristocratie, il ne l’a pas accepté. Entre un laboureur qui aimerait mieux voir dans son champ de l’[[w:Ivraie|''ivraie'']] ou de l’[[w:Orobanche|''orobanche'']] que de l’orge ou du blé, et un tyran qui veut régner sur des esclaves plutôt que sur des hommes de coeur, je ne vois aucune différence. Un seul bien compense les maux nombreux attachés au pouvoir des tyrans : c’est la gloire et l’honneur qui leur sont réservés lorsque, commandant à des hommes vertueux, ils sont plus vertueux eux-mêmes, et qu’au milieu de grands ils se montrent plus grands. Ceux qui préfèrent leur sûreté en renonçant à ce beau rôle, étaient faits pour réunir sous leur main beaucoup de moutons, de chevaux et de boeufs, mais non des hommes. » « Du reste », continua '''Thalès''', « ce sont propos sans portée aucune que ceux où nous a jetés cet étranger, et nous avons omis de dire et de chercher les choses qui conviennent bien à des gens partis pour un banquet. Ne croyez-vous pas, '''Nicarque''', qu’il y ait des préparatifs à faire quand on vient prendre place à un festin, comme il y en a pour celui qui doit le donner ? Les [[w:Sybaris|''Sybarites'']] [[#Sybaris|<span id="Sybaris_back"><sup>'''II'''</sup></span>]], à ce qu’il paraît, s’y prennent un an d’avance pour adresser leurs invitations aux femmes, afin qu’elles puissent à loisir préparer leur toilette et leurs bijoux en or avant de se rendre au festin; et, selon moi, il faut plus de temps encore à un convive pour les préparatifs vraiment nécessaires, parce qu’il est plus difficile de trouver un ajustement convenable pour son moral que la vaine et inutile parure dont on s’inquiète pour son corps. Un homme sensé ne se transporte pas à un festin comme un bocal qu’il s’agit d’y remplir. Il songe à trouver là une occasion de passer tour à tour du sérieux au badinage, d’entendre et de tenir lui-même ces propos auxquels la circonstance invite les convives s’ils veulent se rendre la réunion agréable les uns aux autres. En effet on est libre de repousser un mauvais ragoût, et si le vin ne vaut rien on peut « recourir aux [[w:Naïades|''Naïades'']] »; mais un convive qui vous donne mal à la tête, qui est lourd, qui ne sait pas se conduire, vous fait perdre et vous gâte le plaisir de tout vin, de toute bonne chère, de toute musique. On n’est même pas le maître de se débarrasser aussi complétement qu’on le voudrait d’un tel désagrément. Quelques-uns en gardent tant qu’ils vivent du mécontentement les uns contre les autres : il leur semble qu’il leur reste comme un arrière-goût de viandes mal digérées, parce qu’ils conservent le souvenir d’injures ou de colères échangées dans le vin. C’est pour cela que '''Chilon''', invité hier, n’a pas voulu promettre avant d’avoir su le nom de chacun des convives : « Car on est bien obligé, a-t-il dit, de supporter un désagréable compagnon de traversée, de tente, quand il faut être sur terre ou à l’armée ; mais se mêler indifféremment à table avec les premiers venus, n’est pas le propre d’un homme sensé. » Le squelette des ''Égyptiens'', qu’ils ont la sage coutume de produire et de placer dans la salle du festin afin d’engager à se souvenir que l’on sera bientôt comme lui, survient là comme un convive assez désagréable et intempestif, mais enfin la présence s’en explique. Si cette vue n’excite pas à boire et à se réjouir, elle engage du moins à s’aimer, à se chérir les uns les autres, et elle exhorte à ne pas allonger par des tracas pénibles une existence dont la durée est si courte. </div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §2'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> {{Boîte déroulante début|titre=NdA trad. par Victor Bétolaud de 1870|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Thrasybule_back|<span id="Thrasybule"><sup>I</sup></span>]] Du nom propre grec ancien Θρᾰσῠ́βουλος / Thrăsŭ́boulos [[wikt:en:Θρασύβουλος#Ancient_Greek|(en)]] ;<br /><p style="margin: 0 2em; text-indent: 15px">➥ de l’adjectif [[wikt:θρασύς#Grec_ancien|θρᾰσύς / thrăsús]], « confiant, audacieux » ;<br /><p style="margin: 0 2em; text-indent: 15px">➥ +‎ du nom commun [[wikt:βουλή#Grec_ancien|βουλή / boulế]], « Volonté. Décision, conseil. Conseil, sénat athénien. »; du verbe [[wikt:βούλομαι#Grec_ancien|βούλομαι / boúlomai]], « Vouloir, désirer, souhaiter. Vouloir bien, consentir à. » ;<br /><p style="margin: 0 2em; text-indent: 15px">➥ +‎ -ος (-os).<br /><br /><p style="margin: 0 2em; text-indent: 15px">[[#Sybaris_back|<span id="Sybaris"><sup>II</sup></span>]] Du nom propre grec ancien Σῠ́βᾰρῐς / Sŭ́bărĭs [[wikt:en:Σύβαρις#Ancient_Greek|(en)]] ;<br /><p style="margin: 0 2em; text-indent: 15px">[[w:Colonisation grecque|Colonie grecque]] du sud de l’Italie (en [[w:Calabre|Calabre]] actuelle), fondée au [[w:VIIIe_siècle_av._J.-C.|VIII<sup>ème</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]] dans le cadre du mouvement d’établissement et d’[[w:Colonisation_grecque|''essaimage'']] des Grecs vers l’Occident, particulièrement en [[w:Grande-Grèce|''Grande-Grèce'']]. Réputée dès l’Antiquité pour sa richesse devenue proverbiale, ainsi que pour son emprise sur les peuples voisins et différentes cités grecques de son voisinage, elle est détruite à l’issue d’une [[w:Guerre entre Sybaris et Crotone|guerre]] qui l’oppose à [[w:Crotone|''Crotone'']] à la fin du [[w:VIe_siècle_av._J.-C.|VI<sup>ème</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]], et enfouie sous les eaux du fleuve ''Crathis'' (aujourd’hui [[Crati]]), avant de voir son site réoccupé, soixante ans plus tard, par la colonie [[w:Panhellénisme|''panhellénique'']] de [[w:Thourioï|''Thourioï'']].'''<br/><br/></div> {{Boîte déroulante fin}} <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">'''Périandre''' avait fait préparer le banquet, non à la ville même, mais au ''port de Léchée'' [[#Léchée_NdT_DR|<span id="Léchée_NdT_DR_back"><sup>1</sup></span>]], dans une salle voisine du ''temple de Vénus'', à qui l’on devait offrir un sacrifice. Depuis que sa mère, victime d’un malheureux amour [[#Cratée_NdT_DR|<span id="Cratée_NdT_DR_back"><sup>2</sup></span>]], s’était donné la mort, il n’avait pas encore sacrifié à cette déesse, et c’était la première fois qu’il y pensait, d’après un songe de '''Mélisse''' [[#Mélisse_NdT_DR|<span id="Mélisse_NdT_DR_back"><sup>3</sup></span>]]. Nous étions dans les plus grandes chaleurs de l’été. Le grand nombre des voitures et des gens de pied qui fréquentaient le chemin qui conduit à la mer, l’avaient couvert de poussière et le rendaient fort incommode pour les voyageurs. On avait amené, pour chaque convive, un char commode et proprement orné. '''Thalès''', en voyant le sien à ma porte, se mit à sourire et le refusa. Nous primes donc, à travers les champs, un sentier détourné, et nous allâmes, en nous promenant, suivis de '''Niloxène''' de ''Naucrate'' [[#Niloxène_NdT_DR|<span id="Niloxène_NdT_DR_back"><sup>4</sup></span>]], homme du plus grand mérite, que '''Thalès''' et '''Solon''' avaient autrefois beaucoup connu en ''Égypte''. Il était envoyé, pour la seconde fois, vers '''Bias''', sans savoir lui-même quel était l’objet de sa mission. Il se doutait seulement que la lettre dont '''Amasis''' l’avait chargé contenait une seconde question à résoudre. Il avait ordre, en cas que '''Bias''' refusât d’y répondre, de la proposer aux plus sages d’entre les ''Grecs''. Dès qu’il m’eut aperçu, il me dit en me montrant sa lettre : « J’ai du bonheur aujourd’hui. Cette lettre vous trouve tous réunis. Je la porte au banquet, comme vous voyez. - Si c’est une question épineuse, dit '''Thalès''' en souriant, retournez à ''Priene'' [[#Priene_NdT_DR|<span id="Priene_NdT_DR_back"><sup>5</sup></span>]], '''Bias''' la résoudra, comme il a résolu la première. - Quelle était cette première question, demandai-je à '''Thalès''' ? - Le roi d’Égypte, me répondit-il, avait envoyé une victime à '''Bias''', en lui faisant dire d’en couper ce qu’il y avait de meilleur et de plus mauvais, et de le lui renvoyer. Notre sage, fort habilement en ôta la langue, qu’il lui fit porter. Voilà ce qui lui a mérité l’estime et l’admiration de ce prince. - Ajoutez encore à cette première raison, dit '''Niloxène''', que '''Bias''' ne dédaigne pas, comme vous, l’amitié des rois ; car '''Amasis''' n’a pas moins d’estime pour vous ; il admire surtout la manière dont vous mesurâtes, avec la plus grande facilité et sans aucun instrument mathématique, la hauteur de la pyramide. En dressant votre bâton à l’extrémité de l’ombre qu’elle faisait sur la terre, le rayon solaire qui touchait le sommet de la pyramide et l’extrémité du bâton forma deux triangles ; et vous démontrâtes qu’il y avait la même proportion entre la hauteur du bâton et celle de la pyramide qu’entre la longueur des ombres projetées par l’une et par l’autre. Mais, comme je viens de le dire, on vous accuse, auprès de lui, d’être l’ennemi des rois, et on lui a rapporté plusieurs propos injurieux que vous avez tenus contre les tyrans [[#tyrans_NdT_DR|<span id="tyrans_NdT_DR_back"><sup>6</sup></span>]] ; entre autres que l’''Ionien'' '''Molpagore''' [[#Molpagore_NdT_DR|<span id="Molpagore_NdT_DR_back"><sup>7</sup></span>]] vous ayant demandé ce qui vous paraîtrait plus extraordinaire dans la vie, vous lui répondîtes : de voir vieillir un tyran. Une autre fois, comme on vint à parler, dans un repas, du naturel des animaux, vous dîtes que le plus méchant des animaux sauvages était le tyran, et des animaux domestiques, le flatteur. Les rois, quoiqu’ils affectent de ne rien avoir de commun avec les tyrans, n’aiment pas cependant ces sortes de discours. Cette dernière réponse, dit '''Thalès''', est de '''Pittacus''' ; il la fit un jour, en plaisantant, à ''Myrsile'' [[#Myrsile_NdT_DR|<span id="Myrsile_NdT_DR_back"><sup>8</sup></span>]]. Dans la première, je parlais d’un pilote, et non pas d’un tyran. Mais puisqu’on en a fait application au tyran, je dirai comme ce jeune homme qui, jetant une pierre à son chien, en avait atteint sa belle-mère : « Le coup n’est pas perdu. » Aussi jamais '''Solon''' ne montra-t-il plus de sagesse, à mon gré, que lorsqu’il refusa la tyrannie ; et si '''Pittacus''' n’eût pas été contraint de l’accepter, il n’eût point dit qu’il est à charge d’être vertueux [[#Pittacus_NdT_DR|<span id="Pittacus_NdT_DR_back"><sup>9</sup></span>]]. Il est vrai que '''Périandre''', qui a succédé à l’autorité des tyrans, paraît jusqu’ici opposer à ce mal héréditaire un remède puissant, par le soin qu’il a de rechercher les entretiens et les avis salutaires des hommes vertueux , et par l’horreur qu’il a témoignée pour le conseil barbare que notre compatriote '''Thrasybule''' lui donnait de faire mourir les grands. Un tyran qui veut commander à des esclaves, plutôt qu’à des hommes, ressemble à un laboureur qui aimerait mieux voir son champ couvert de passereaux et de sauterelles que d’orge et de froment. Le seul bien qui puisse compenser tant de maux attachés au pouvoir des tyrans, c’est d’avoir, même sur les plus grands et les plus vertueux de leurs sujets, la supériorité de l’honneur et de la vertu. Ceux qui préfèrent la sûreté à la gloire sont faits pour commander à des troupeaux, et non pour gouverner des hommes. « Mais '''Niloxène''' nous a jetés dans une conversation absolument étrangère à notre objet, et nous a fait négliger ce qui devait nous occuper en allant au banquet. Ne pensez-vous pas que les conviés ont, aussi bien que leur hôte, des apprêts à faire. Les ''Sybarites'', dit-on, prient les femmes à souper un an d’avance, afin qu’elles puissent préparer à loisir leurs habits et leurs bijoux [[#Sybarites_NdT_DR|<span id="Sybarites_NdT_DR_back"><sup>10</sup></span>]]. Pour moi, je pense qu’il faut encore plus de temps à un convive pour faire tous les préparatifs convenables, parcequ’il est bien plus difficile d’orner son esprit comme il faut, que de donner à son corps une parure vaine et superflue. Un homme sensé doit aller à un festin, non pour y remplir son estomac, comme un vase, mais pour écouter et tenir à son tour des propos utiles ou amusants, suivant les circonstances. C’est le seul moyen de rendre le repas agréable aux convives. En effet, on peut laisser un mauvais ragoût, et recourir à l’eau quand le vin n’est pas bon ; mais un convive désagréable, importun et fatigant, fait perdre tout le plaisir de la bonne chère et de la musique. On ne peut se délivrer de l’ennui qu’il cause, et souvent même une parole vive ou offensante qu’il se sera permise dans la liberté de la table, fait naître des aversions et des ressentiments qui ne finissent qu’avec la vie. Aussi '''Chilon''', invité hier à ce banquet, ne voulut-il accepter qu’après qu’on lui eut nommé tous les convives. Il disait avec raison, que quand on est sur mer ou dans un camp, il faut nécessairement supporter les compagnons qui nous sont associés, quelque fâcheux qu’ils soient ; mais dans un festin, il n’est pas d’un homme sensé de se mêler indifféremment avec toutes sortes de personnes. Le squelette que les ''Égyptiens'' placent ordinairement à côté d’eux dans leurs repas, en s’exhortant à penser qu’ils seront bientôt dans le même état, est, à la vérité, un compagnon de table assez triste et assez déplacé. Il est néanmoins utile, sinon pour les exciter au plaisir, du moins pour les porter à la bienveillance et à l’amitié réciproque, et pour les avertir de ne pas remplir d’aigreur et de querelles le temps si court de la vie [[#squelette_NdT_DR|<span id="squelette_NdT_DR_back"><sup>11</sup></span>]]. » </div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Léchée_NdT_DR_back|<span id="Léchée_NdT_DR"><sup>1</sup></span>]] L’isthme de ''Corinthe'' avait deux ports, l’un sur la côte orientale, appelé ''Cenchrées'' ; et l’autre sur la côte occidentale, nommé ''Léchée''. Pausanias, qui a donné une description si détaillée de la ''Grèce'', parle d’un ''temple de Vénus'', bâti sur le port de ''Cenchrées'', et dont la statue était de marbre ; mais il ne fait pas mention de celui que cite Plutarque, et qu’il place près du port occidental. ''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Cratée_NdT_DR_back|<span id="Cratée_NdT_DR"><sup>2</sup></span>]] La mère de Périandre se nommait Cratée. On peut voir dans Parthenius la manière dont elle conçut et nourrit une passion incestueuse pour son fils, les moyens qu'elle prit pour la satisfaire sans être connue, et comment elle fut découverte. Les remords qu’elle en eut l’obligèrent de se donner la mort.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Mélisse_NdT_DR_back|<span id="Mélisse_NdT_DR"><sup>3</sup></span>]] Mélisse était fille de Proclès, roi d’[[w:Épidaure_(cité_antique)|''Épidaure'']]. On prétend que Périandre en devint éperdument amoureux pour l’avoir vue dans l’habillement ordinaire aux femmes du ''Péloponnèse''. Cette passion toutefois ne l’empêcha pas de partager son cœur entre elle et plusieurs concubines. Elles parvinrent à l’irriter contre elle au point qu’un jour, par un mouvement de jalousie, il la frappa d’un coup de pied, sans songer qu’elle était enceinte, et la fit mourir.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Niloxène_NdT_DR_back|<span id="Niloxène_NdT_DR"><sup>4</sup></span>]] Niloxène signifie hôte du ''Nil'' : ce nom semble indiquer que c’est un personnage supposé.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Priene_NdT_DR_back|<span id="Priene_NdT_DR"><sup>5</sup></span>]] Ville d’''Ionie'', colonie des ''Thébains'' et patrie de Bias.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#tyrans_NdT_DR_back|<span id="tyrans_NdT_DR"><sup>6</sup></span>]] Par le mot [[wikt:τύραννος#Grec_ancien|τύραννος]], que nous ne pouvons rendre en français que par celui de tyran, les ''Grecs'' entendaient, non pas seulement, comme nous, un prince injuste et cruel ; mais, en général, tout homme qui s’était emparé de l’autorité monarchique dans un état libre, sans qu’elle lui fût légitimement acquise.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Molpagore_NdT_DR_back|<span id="Molpagore_NdT_DR"><sup>7</sup></span>]] Ce Molpagore est peut-être le père d’Aristagore, que Darius établit tyran à ''Milet''.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Myrsile_NdT_DR_back|<span id="Myrsile_NdT_DR"><sup>8</sup></span>]] Myrsile n’est guère mieux connu que Molpagore. Strabon le met au nombre de ces ''Lesbiens'' ambitieux, qui, du temps de Pittacus, s’étaient emparés de l’autorité souveraine à ''Lesbos'', et dont le poète [[w:Alcée_de_Mytilène|Alcée]] avait flétri la mémoire.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Pittacus_NdT_DR_back|<span id="Pittacus_NdT_DR"><sup>9</sup></span>]] Pittacus en se voyant forcé, dans sa vieillesse, de reprendre le gouvernement des affaires, prononça cette maxime.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Sybarites_NdT_DR_back|<span id="Sybarites_NdT_DR"><sup>10</sup></span>]] Cet usage des ''Sybarites'' n’avait lieu que dans les festins publics.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#squelette_NdT_DR_back|<span id="squelette_NdT_DR"><sup>11</sup></span>]] Cet usage, d’abord particulier aux ''Egyptiens'', avait ensuite passé chez les ''Grecs'', de qui les ''Romains'' l’empruntèrent. ''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' pp.326-330, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe III.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage de la reconnaissance de la sagesse de '''Cléobuline''' ''« Eumétis »'' par '''Thalès''', de l’humilité de ce dernier et de son [[w:Cynisme|''cynisme'']], en particulier à la vue d’un ''centaure'' [[#centaure|<span id="centaure_back"><sup>'''I'''</sup></span>]]. </div> {{Boîte déroulante début|titre=NdA centaure|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#centaure_back|<span id="centaure"><sup>I</sup></span>]] Il s’agit d’une adaptation d’une fable de [[w:Phèdre_(fabuliste)|Phèdre]] [[#Phèdre|<span id="Phèdre_back"><sup>II</sup></span>]], où Ésope [[#Ésope_back|<sup>⤴️</sup>]] remplace Thalès [https://books.openedition.org/pur/12177 {{info|<sup>🔍</sup>|Gourmelen, Laurent. « Imposture ou dualité : que faut-il penser de la naissance d’un centaure ? Sur un curieux passage du Banquet des Sept Sages (Plutarque, Moralia, 149 C-F) ». L’imposture dans la littérature, édité par Arlette Bouloumié, Presses universitaires de Rennes, 2011, https://doi.org/10.4000/books.pur.12177.}}] :'''<br /><br /><p style="margin: 0 2em; text-align: center;">« Un homme d’expérience en sait plus long qu’un devin. C’est un proverbe; d’où vient-il? on ne le dit pas. Ma fable, la première, va l’apprendre.<br /><br />Un fermier avait des brebis qui lui donnaient des agneaux à tête humaine. Épouvanté d’une monstruosité pareille, il court tout affligé consulter les devins. L’un répond que la vie du maître est menacée, et qu’il faut conjurer le péril par une victime. L’autre assure au fermier que sa femme lui est infidèle, et que cela signifie l’illégitimité des enfants; mais qu’un sacrifice important peut tout expier. Enfin, tous diffèrent d’opinion et ne font qu’aggraver le souci du paysan. '''Ésope''', vieillard plein de finesse et de sagacité, et que la nature ne put jamais tromper, se trouvait là par hasard : "Villageois, lui dit-il, si tu veux faire cesser ce prodige, donne des femmes tes bergers." » <br /><br /><p style="text-align: right; margin: 0 2em 0 1em;">'''[https://remacle.org/bloodwolf/fabulistes/phedre/livre3.htm <u>Fables de Phèdre</u>, livre III], §3 - Ésope et le paysan, traduites par M. E. Panckoucke, 1864.<br /><br /><p style="margin: 0 2em; text-indent: 15px;">[[#Phèdre_back|<span id="Phèdre"><sup>II</sup></span>]] [[w:Nom_romain|Tria Nomina]] en latin {{Info|Caius|praenomen, nom individuel du citoyen romain}} {{Info|Iulius|nomen, nom de famille}} {{Info|Phaedrus ou Phaeder|cognomen, surnom héréditaire, servant à distinguer les diverses branches d’une même gens}} ;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ du grec ancien Φαῖδρος / Phaîdros [[wikt:en:Φαῖδρος#Ancient_Greek|(en)]] ; de l’adjectif phaidrós / phaidrós [[wikt:en:φαιδρός#Ancient_Greek|(en)]], « 1. Lumineux, rayonnant. 2. (au sens figuré) Rayonnant de joie, brillant, joyeux. » ;<br /><p style="margin: 0 2em; text-indent: 15px;">Fabuliste latin d’origine ''[[w:thrace|thrace]]'', esclave à son arrivée à ''Rome'' et affranchi par un décret d’[[w:Auguste|Auguste]]. Près d’un tiers de son œuvre est repris d’Ésope dont il adapte les fables ; les deux autres tiers sont issus de son imagination. Tout comme son prédécesseur, Phèdre raconte des histoires d’animaux, mais il met en scène aussi des personnages humains et parmi ceux-ci Ésope :'''<br /><br /><p style="margin: 0 2em; text-align: center;">« C’est '''Ésope''' qui, le premier, a trouvé la matière : moi, je l’ai polie en vers [[w:Sénaire iambique|''sénaires'']]. Ce petit livre a un double mérite : il fait rire et il donne de sages conseils pour la conduite de la vie. À celui qui viendrait me reprocher injustement de faire parler non seulement les animaux, mais même les arbres, je rappellerai que je m’amuse ici à de pures fictions. »<br /><p style="margin: 0 2em; text-align: right;">'''Phèdre, ''Fables'', I, prologue'''<br /><br /><p style="margin: 0 2em; text-align: center;">« Le genre d’'''Ésope''' est tout en exemples, et on ne doit y chercher que le but de ses fables : corriger les erreurs des hommes, et exciter en eux une vive émulation. Quelle que soit donc la nature d’un récit, s’il captive, et remplit son objet, il se recommande de lui-même, sans aucun nom d’auteur. Aussi suivrai-je scrupuleusement les traces du vieillard. »<br /><p style="margin: 0 2em; text-align: right;">'''Phèdre, ''Fables'', II, prologue'''<br /><br /><p style="margin: 0 2em; text-indent: 15px;">'''Au total, il composera cent-vingt-trois fables, divisées en cinq livres.<br /><p style="text-align: right; margin: 0 2em;">(vers [[w:-14|-14]] <sup>[[w:Ier_siècle_av._J.-C.|⏳]]</sup>, en ''Thrace'' ― vers [[w:50|50]] <sup>[[w:Ier_siècle|⏳]]</sup>, lieu de décès inconnu)'''<br /><br /> </div>{{Boîte déroulante fin}} :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§3. Ἐν τοιούτοις λόγοις γενόμενοι κατὰ τὴν ὁδὸν ἀφικόμεθα πρὸς τὴν οἰκίαν, καὶ λούσασθαι μὲν ὁ Θαλῆς οὐκ ἠθέλησεν, ἀληλιμμένοι γὰρ ἦμεν· ἐπιὼν δὲ τούς τε δρόμους ἐθεᾶτο καὶ τὰς παλαίστρας καὶ τὸ ἄλσος τὸ παρὰ τὴν θάλατταν ἱκανῶς διακεκοσμημένον, ὑπ´ οὐδενὸς ἐκπληττόμενος τῶν τοιούτων, ἀλλ´ ὅπως μὴ καταφρονεῖν δοκοίη μηδ´ ὑπερορᾶν τοῦ Περιάνδρου τῆς φιλοτιμίας. τῶν δ´ ἄλλων τὸν ἀλειψάμενον ἢ λουσάμενον οἱ θεράποντες εἰσῆγον εἰς τὸν ἀνδρῶνα διὰ τῆς στοᾶς. Ὁ δ´ Ἀνάχαρσις ἐν τῇ στοᾷ καθῆστο, καὶ παιδίσκη προειστήκει τὴν κόμην ταῖς χερσὶ διακρίνουσα. ταύτην ὁ Θαλῆς ἐλευθεριώτατά πως αὐτῷ προσδραμοῦσαν ἐφίλησε καὶ γελάσας « οὕτως, » ἔφη, « ποίει καλὸν τὸν ξένον, ὅπως ἡμερώτατος ὢν μὴ φοβερὸς ᾖ τὴν ὄψιν ἡμῖν μηδ´ ἄγριος. » Ἐμοῦ δ´ ἐρομένου περὶ τῆς παιδὸς ἥτις εἴη, « τὴν σοφήν, » ἔφη, « καὶ περιβόητον ἀγνοεῖς Εὔμητιν; οὕτω γὰρ ταύτην ὁ πατὴρ αὐτός, οἱ δὲ πολλοὶ πατρόθεν ὀνομάζουσι Κλεοβουλίνην. » Καὶ ὁ Νειλόξενος εἶπεν « ἦ που τὴν περὶ τὰ αἰνίγματα δεινότητα καὶ σοφίαν, » ἔφη, « τῆς κόρης ἐπαινεῖς· καὶ γὰρ εἰς Αἴγυπτον ἔνια τῶν προβαλλομένων ὑπ´ αὐτῆς διῖκται. » « Οὐκ ἔγωγ´, » εἶπεν ὁ Θαλῆς· « τούτοις γὰρ ὥσπερ ἀστραγάλοις, ὅταν τύχῃ, παίζουσα χρῆται καὶ διαβάλλεται πρὸς τοὺς ἐντυχόντας. ἀλλὰ καὶ φρόνημα θαυμαστὸν καὶ νοῦς ἔνεστι πολιτικὸς καὶ φιλάνθρωπον ἦθος, καὶ τὸν πατέρα τοῖς πολίταις πραότερον ἄρχοντα παρέχει καὶ δημοτικώτερον. » « Εἶεν, » ὁ Νειλόξενος ἔφη, « καὶ φαίνεται βλέποντι πρὸς τὴν λιτότητα καὶ ἀφέλειαν αὐτῆς· Ἀνάχαρσιν δὲ πόθεν οὕτω τημελεῖ φιλοστόργως; » « Ὅτι, » ἔφη, « σώφρων ἀνήρ ἐστι καὶ πολυμαθής, καὶ τὴν δίαιταν αὐτῇ καὶ τὸν καθαρμόν, ᾧ χρῶνται Σκύθαι περὶ τοὺς κάμνοντας, ἀφθόνως καὶ προθύμως παραδέδωκε. καὶ νῦν οἶμαι περιέπειν αὐτὴν τὸν ἄνδρα καὶ φιλοφρονεῖσθαι, μανθάνουσάν τι καὶ προσδιαλεγομένην. » Ἤδη δὲ πλησίον οὖσιν ἡμῖν τοῦ ἀνδρῶνος ἀπήντησεν Ἀλεξίδημος ὁ Μιλήσιος (ἦν δὲ Θρασυβούλου τοῦ τυράννου νόθος) καὶ ἐξῄει τεταραγμένος καὶ σὺν ὀργῇ τινι πρὸς αὑτὸν οὐδὲν ἡμῖν γε σαφὲς διαλεγόμενος. ὡς δὲ τὸν Θαλῆν εἶδε, μικρὸν ἀνενεγκὼν καὶ καταστάς « οἵαν ὕβριν, » εἶπεν, « εἰς ἡμᾶς Περίανδρος ὕβρικεν, ἐκπλεῦσαι μὲν οὐκ ἐάσας ὡρμημένον ἀλλὰ προσμεῖναι δεηθεὶς τὸ δεῖπνον, ἐλθόντι δὲ νέμων κλισίαν ἄτιμον, Αἰολεῖς δὲ καὶ νησιώτας (καὶ τίνας γὰρ οὐχί;) Θρασυβούλου προτιμῶν· Θρασύβουλον γὰρ ἐν ἐμοὶ τὸν πέμψαντα προπηλακίσαι βουλόμενος καὶ καταβαλεῖν ὡς δὴ περιορῶν δῆλός ἐστιν. » « Εἶτ´, » ἔφη, « σὺ δέδιας μὴ καθάπερ Αἰγύπτιοι τοὺς ἀστέρας ὑψώματα καὶ ταπεινώματα λαμβάνοντας ἐν τοῖς τόποις οὓς διεξίασι γίγνεσθαι βελτίονας ἢ χείρονας ἑαυτῶν λέγουσιν, οὕτως ἡ περὶ σὲ διὰ τὸν τόπον ἀμαύρωσις ἢ ταπείνωσις γένηται; καὶ τοῦ Λάκωνος ἔσῃ φαυλότερος, ὃς ἐν χορῷ τινι κατασταθεὶς εἰς τὴν ἐσχάτην χώραν ὑπὸ τοῦ ἄρχοντος ‘εὖ γ´,’ εἶπεν, ‘ἐξεῦρες, ὡς καὶ αὕτα ἔντιμος γένηται.’ οὐ καταλαβόντας, » ἔφη, « τόπον μετὰ τίνας κατακείμεθα δεῖ ζητεῖν, μᾶλλον δ´ ὅπως εὐάρμοστοι τοῖς συγκατακειμένοις ὦμεν, ἀρχὴν καὶ λαβὴν φιλίας εὐθὺς ἐν αὐτοῖς ζητοῦντες, μᾶλλον δ´ ἔχοντες τὸ μὴ δυσκολαίνειν ἀλλ´ ἐπαινεῖν ὅτι τοιούτοις συγκατεκλίθημεν· ὡς ὅ γε τόπῳ κλισίας δυσχεραίνων δυσχεραίνει τῷ συγκλίτῃ μᾶλλον ἢ τῷ κεκληκότι, καὶ πρὸς ἀμφοτέρους ἀπεχθάνεται. » « Λόγος, » ἔφη, « ταῦτ´ ἄλλως ἐστίν » ὁ Ἀλεξίδημος, « ἔργῳ δὲ καὶ τοὺς σοφοὺς ὑμᾶς ὁρῶ τὸ τιμᾶσθαι διώκοντας, » καὶ ἅμα παραμειψάμενος ἡμᾶς ἀπῆλθε. Καὶ ὁ Θαλῆς πρὸς ἡμᾶς τὴν ἀτοπίαν τοῦ ἀνθρώπου θαυμάζοντας, « ἔμπληκτος, » ἔφη, « καὶ ἀλλόκοτος φύσει, ἐπεὶ καὶ μειράκιον ὢν ἔτι, μύρου σπουδαίου Θρασυβούλῳ κομισθέντος, εἰς ψυκτῆρα κατεράσας μέγαν καὶ προσεγχέας ἄκρατον ἐξέπιεν, ἔχθραν ἀντὶ φιλίας Θρασυβούλῳ διαπεπραγμένος. » Ἐκ τούτου περιελθὼν ὑπηρέτης « κελεύει σε Περίανδρος, » ἔφη, « καὶ Θαλῆν παραλαβόντα τοῦτον ἐπισκέψασθαι τὸ κεκομισμένον ἀρτίως αὐτῷ πότερον ἄλλως γέγονεν ἤ τι σημεῖόν ἐστι καὶ τέρας· αὐτὸς μὲν γὰρ ἔοικε τεταράχθαι σφόδρα, μίασμα καὶ κηλῖδα τῆς θυσίας ἡγούμενος. » ἅμα δ´ ἀπῆγεν ἡμᾶς εἴς τι οἴκημα τῶν περὶ τὸν κῆπον. ἐνταῦθα νεανίσκος ὡς ἐφαίνετο νομευτικός, οὔπω γενειῶν ἄλλως τε τὸ εἶδος οὐκ ἀγεννής, ἀναπτύξας τινὰ διφθέραν ἔδειξεν ἡμῖν βρέφος ὡς ἔφη γεγονὸς ἐξ ἵππου, τὰ μὲν ἄνω μέχρι τοῦ τραχήλου καὶ τῶν χειρῶν ἀνθρωπόμορφον, τὰ λοιπὰ δ´ ἔχον ἵππου, τῇ δὲ φωνῇ καθάπερ τὰ νεογνὰ παιδάρια κλαυθμυριζόμενον. ὁ μὲν οὖν Νειλόξενος, « Ἀλεξίκακε » εἰπών, ἀπεστράφη τὴν ὄψιν, ὁ δὲ Θαλῆς προσέβλεπε τῷ νεανίσκῳ πολὺν χρόνον, εἶτα μειδιάσας (εἰώθει δ´ ἀεὶ παίζειν πρὸς ἐμὲ περὶ τῆς τέχνης) « ἦ που τὸν καθαρμόν, ὦ Διόκλεις, » ἔφη, « κινεῖν διανοῇ καὶ παρέχειν πράγματα τοῖς ἀποτροπαίοις, ὥς τινος δεινοῦ καὶ μεγάλου συμβάντος; » « Τί δ´, » εἶπον, « οὐ μέλλω; στάσεως γάρ, ὦ Θαλῆ, καὶ διαφορᾶς τὸ σημεῖόν ἐστι, καὶ δέδια μὴ μέχρι γάμου καὶ γενεᾶς ἐξίκηται, πρὶν ἢ τὸ πρῶτον ἐξιλάσασθαι μήνιμα, τῆς θεοῦ δεύτερον ὡς ὁρᾷς προφαινούσης. » Πρὸς τοῦτο μηδὲν ἀποκρινάμενος ὁ Θαλῆς ἀλλὰ γελῶν ἀπηλλάττετο. καὶ τοῦ Περιάνδρου πρὸς τὰς θύρας ἀπαντήσαντος ἡμῖν καὶ διαπυθομένου περὶ ὧν εἴδομεν, ἀφεὶς ὁ Θαλῆς με καὶ λαβόμενος τῆς ἐκείνου χειρὸς ἔφη, « ἃ μὲν Διοκλῆς κελεύει δράσεις καθ´ ἡσυχίαν· ἐγὼ δέ σοι παραινῶ νέοις οὕτω μὴ χρῆσθαι νομεῦσιν ἵππων, ἢ διδόναι γυναῖκας αὐτοῖς. » Ἔδοξε μὲν οὖν μοι τῶν λόγων ἀκούσας ὁ Περίανδρος ἡσθῆναι σφόδρα· καὶ γὰρ ἐξεγέλασε καὶ τὸν Θαλῆν περιβαλὼν κατησπάσατο. κἀκεῖνος « οἶμαι δ´, » εἶπεν, « ὦ Διόκλεις, καὶ πέρας ἔσχε τὸ σημεῖον· ὁρᾷς γὰρ ἡλίκον κακὸν γέγονεν ἡμῖν, Ἀλεξιδήμου συνδειπνεῖν μὴ θελήσαντος. » </div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §3'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§3. Ce fut en tenant de tels propos chemin faisant, que nous arrivâmes à la maison. '''Thalès''' ne voulut pas se baigner : « Je me suis frotté d’huile. » dit-il. Il se promena donc de côté et d’autre, regardant les champs de course, les palestres, et le bois sacré, voisin de la mer, que l’on avait bien convenablement disposé. Ce n’était pas qu’il fût frappé par aucun de ces préparatifs, mais il voulait ne pas avoir l’air de mépriser '''Périandre''' et de faire peu de cas de l’empressement avec lequel celui-ci honorait ses hôtes. Pour les autres convives, à mesure qu’ils s’étaient parfumés ou baignés, les serviteurs les introduisaient par la galerie dans la salle du banquet. Or '''Anacharsis''' s’était installé dans cette galerie, et devant lui une jeune fille se tenait, lui séparant les cheveux avec ses mains. Lorsqu’entra '''Thalès''', elle s’élança très librement à sa rencontre, et '''Thalès''', après l’avoir embrassée, lui dit en riant : « Continue à rendre bien beau notre étranger, afin qu’étant devenu la douceur même il ne conserve pas au milieu de nous une mine à faire peur et un aspect sauvage. » Je lui demandai quelle était cette jeune enfant : « Quoi ! » me dit-il, « vous ne connaissez pas la savante et célèbre '''Eumétis''' ! car c’est ainsi que son père la nomme : le plus communément on l’appelle '''Cléobuline''', du nom paternel. » Et '''Niloxène''' : « C’est sans doute à cause de son talent et de son habileté pour les énigmes, que vous faites l’éloge de cette jeune fille : car quelques-unes de celles qu’elle a proposées sont parvenues jusqu’en ''Égypte''. » — « Ce n’est pas à cause de cela », répondit '''Thalès''' : « les énigmes sont pour elle des joujoux dont elle s’amuse à l’occasion pour faire sa partie avec ceux qui se rencontrent. Mais ce qui est admirable en elle c’est sa profondeur d’esprit, son sens politique, l’aménité de son caractère, et le talent qu’elle a de rendre plus douce l’autorité de son père et d’inspirer à celui-ci des sentiments plus humains à l’égard du peuple. » — « Soit », dit '''Niloxène''' ; « et cela se reconnaît à voir sa modestie et sa simplicité. Mais d’où vient qu’elle prend un soin si amoureux de la toilette d’'''Anacharsis''' ? » — Parce que c’est, répondit '''Thalès''', « un sage, un homme des plus instruits, et parce qu’il lui a communiqué, avec de nombreux détails et de grand coeur, l’ensemble des pratiques sanitaires et des purifications que les ''Scythes'' appliquent au traitement des malades. Et dans ce moment je suppose qu’elle l’entoure de soins et d’amitiés parce qu’elle s’instruit de quelque chose en conversant avec lui. » Comme nous étions déjà près de la salle, '''Alexidème''' le ''Milésien'' vint à notre rencontre. C’était un bâtard du tyran '''Thrasybule'''. Il était sorti tout troublé, et avec une sorte de fureur il se parlait à lui-même, mais ses paroles n’avaient rien de clair pour nous. Quand il eut vu '''Thalès''', il se remit un peu ; puis, s’arrêtant tout court : « Quel affront '''Périandre''' vient de nous faire ! Je voulais mettre à la voile : il ne l’a pas permis ; il m’a supplié de rester à son festin, et quand j’arrive, il me donne une des dernières places, faisant passer des [[w:Éoliens|''Éoliens'']], des insulaires (je ne sais qui il ne me préfère pas), les faisant passer, dis je, avant '''Thrasybule''', car c’est '''Thrasybule''' en ma personne, c’est celui par lequel je suis envoyé qu’il a l’intention de traîner dans la boue et de ravaler comme le méprisant : la chose est bien claire. » — « Eh quoi ! » lui dit '''Thalès''', « êtes-vous comme les ''Égyptiens'', qui prétendent que les astres, suivant qu’ils prennent une position élevée ou basse en parcourant leur orbite, ont une condition meilleure ou pire qu’ils ne l’avaient ? Craignez-vous, pareillement, qu’autour de vous, en raison de la place où vous serez, il ne se produise obscurité ou dépression ? Serez-vous moins résigné que certain ''Spartiate'' ? À je ne sais quelle représentation il avait été placé au dernier rang par le maître des cérémonies : « Voilà qui va bien », lui dit-il : « tu as trouvé moyen de rendre honorable ce lieu même. Quand nous avons pris une place nous ne devons pas chercher au-dessous de qui nous sommes installés, mais plutôt comment nous nous mettrons en bon accord avec nos voisins. À leur occasion nous ferons voir tout d’abord, ou plutôt nous l’éprouverons réellement, un désir d’initiative et de prise de possession en matière d’amitié, et nous manifesterons ce désir en nous félicitant, loin d’en montrer du dépit, de ce que l’on nous a placés en une telle compagnie. Mais celui qui se plaint du rang qu’on lui donne à table montre plus de mécontentement contre son commensal que contre son hôte, et il se rend odieux à l’un et à l’autre. » — « Paroles que tout cela, » dit '''Alexidème''', « et paroles sans portée ! Mais je vois que de fait, vous autres sages, vous recherchez aussi les honneurs. » En même temps il s’éloigna de nous et disparut. Une conduite si étrange nous semblait étonnante. « C’est », nous dit '''Thalès''', « un homme écervelé et naturellement bizarre. Vous allez en juger. Il était encore tout jeune ; on avait apporté à '''Thrasybule''' un parfum d’un très haut prix. '''Alexidème''' le versa dans un grand vase à rafraîchir, y mêla du vin pur, et avala le tout, rendant son père odieux au lieu de le faire aimer. » Au même moment parut un serviteur : « Vous êtes invité par '''Périandre''' », me dit-il, « à venir, en vous faisant accompagner de '''Thalès''' que voici, examiner l’objet qu’on lui a récemment apporté, afin que vous disiez si c’est une création toute fortuite, ou bien un présage et une monstruosité; car, pour ce qui est de '''Périandre''', il a l’air grandement troublé, pensant que c’est une souillure et une profanation pour son sacrifice. » En même temps, il nous emmena vers une des salles qui donnaient sur le jardin. Là un jeune homme paraissant appartenir à la classe des bergers, qui n’avait pas encore de barbe et dont la physionomie ne manquait pas de noblesse, déploya une espèce de couverture en cuir, et nous montra un petit enfant né, disait-il, d’une cavale. Par le haut, jusqu’au cou et aux mains, cette créature était de forme humaine ; mais le reste était d’un cheval, et sa voix avait quelque chose des vagissements poussés par les petits enfants qui viennent de naître. « Dieu préservateur ! » s’écria '''Niloxène''', et il détourna les yeux. Mais '''Thalès''' fixa longtemps son regard sur le jeune pâtre; puis s’étant mis à sourire, (car il avait l’habitude de plaisanter toujours avec moi sur ma profession) : « Eh bien, '''Dioclès''', » dit-il, « songez-vous à préparer quelque expiation, et à donner de la besogne aux dieux préservateurs, comme vous trouvant en présence de quelque événement grave et considérable ? » — « Pourquoi non ? » répondis-je : « j’y vois le présage de troubles et de discordes qui s’étendront, j’en ai peur, jusqu’à un mariage et une génération avant que le courroux de la déesse ait été apaisé, puisqu’elle fait, vous le savez, une seconde manifestation ». À ces paroles '''Thalès''' ne répondit rien : il se contenta de rire et de s’en aller. Et comme '''Périandre''' était à la porte, s’avançant pour nous interroger sur ce que nous venions de voir, '''Thalès''' me quitta et le prit par la main : « Ce que '''Dioclès''' prescrira, vous l’exécuterez à loisir », lui dit-il ; « mais moi j’ai un conseil à vous donner : pour faire paître vos juments ne prenez pas de jeunes garçons, ou bien à ceux-ci donnez des femmes. » Ces paroles me semblèrent causer, des qu’il les eut entendues, une vive satisfaction à '''Périandre''', car il éclata de rire et serra très affectueusement '''Thalès''' dans ses bras. '''Thalès''' alors : « '''Dioclès''' », me dit-il, « si je conjecture bien, le prodige reçoit déjà son accomplissement. Car vous voyez quel grand malheur nous est arrivé, '''Alexidème''' n’ayant pas voulu souper avec nous. »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §3'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Après avoir ainsi conversé pendant le chemin, nous arrivâmes au lieu destiné pour le banquet. '''Thalès''' ne voulut point entrer dans le bain, parcequ’il s’était déja parfumé, mais il se promena dans les dehors, s’arrêta à voir les luttes et les courses ; il alla voir le bocage voisin de la mer, qu’on avait décoré avec beaucoup de soin, non qu’il fût frappé de tout cet appareil, mais pour ne point paraître mépriser '''Périandre''' et dédaigner sa magnificence. Tous les autres convives, à mesure qu’ils sortaient du bain, étaient introduits par des esclaves dans la salle du banquet. '''Anacharsis''' seul était assis sous le portique, une jeune fille, debout, lui arrangeait les cheveux. Dès qu’elle vit '''Thalès''', elle accourut très librement au-devant de lui ; ce philosophe l’embrassa, et lui dit en riant : « Parez cet hôte du mieux que vous pourrez, afin que le plus doux des hommes n'’ait plus un extérieur sauvage et effrayant. » Je lui demandai quelle était cette jeune personne : « Eh quoi ! me répondit-il, vous ne connaissez pas la sage et fameuse '''Eumétis''' ? C’est le nom que '''Cléobule''' lui donne, mais les autres l’appellent '''Cléobuline''', du nom de son père. - Est-ce, dit '''Niloxène''', à cause de sa subtilité et de son adresse à composer des énigmes, que vous faites ainsi son éloge ? Quelques unes de celles qu’on lui attribue ont pénétré jusqu’en ''Egypte''. - Non, répliqua '''Thalès''' ; ces énigmes ne sont que des jouets dont elle s’amuse dans l’occasion pour éprouver la perspicacité de ceux qu’elle rencontre. Ce qu’elle a de vraiment admirable, c’est sa grande prudence, sa capacité pour les affaires, son humanité, et l’attention qu’elle a de rendre le gouvernement de son père doux et bienfaisant. - Il est vrai, reprit '''Niloxène''', que sa modestie et sa simplicité annoncent combien elle est populaire. Mais d’où viennent ces soins et cet intérêt pour '''Anacharsis''' ? - Parceque c’est un homme sensé et très instruit, répondit '''Thalès''', qu’il s’est fait un plaisir de lui apprendre en détail le régime et le traitement que les ''Scythes'' emploient dans les maladies. Je suis sûr que dans ce moment même où elle le pare avec tant de soin, elle s’entretient utilement avec lui, et cherche à s’instruire. » Nous approchions de la salle, lorsque nous rencontrâmes '''Alexidème''' de ''Milet'', fils naturel du tyran '''Thrasybule'''. Il sortait tout troublé, et d’un ton de colère murmurait quelques mots que nous ne pûmes entendre. Dès qu’il vit '''Thalès''', il se remit un peu ; et en lui adressant la parole, il lui dit : « Quel indigne affront '''Périandre''' vient de nous faire ! J’allais partir, il me retient, il me prie de rester à son festin ; et quand j’arrive, il m’y donne la dernière place : il préfère un ''éolien'', un insulaire, enfin je ne sais qui, à '''Thrasybule''', car il est évident que c’est '''Thrasybule''' que '''Périandre''' méprise, et brave ouvertement dans la personne de son envoyé [[#Thrasybule_NdT_DR|<span id="Thrasybule_NdT_DR_back"><sup>1</sup></span>]]. - Eh quoi ! lui dit '''Thalès''', craignez-vous que la place que vous occuperez à table ne vous rende plus grand ou plus petit, comme les ''Égyptiens'' disent que les astres brillent plus ou moins, suivant que le cercle qu’ils parcourent est plus ou moins élevé ? Et vous estimeriez-vous moins que ce ''Lacédémonien'', qui, dans une assemblée publique, placé par le magistrat au dernier rang, lui dit : Vous avez trouvé le moyen de rendre cette place honorable [[#place_honorable_NdT_DR|<span id="place_honorable_NdT_DR_back"><sup>2</sup></span>]] ? Doit-on en effet examiner après qui l’on est placé ? Ne faut-il pas plutôt s’accommoder de ceux qu’on a pour voisins, afin d’avoir une occasion naturelle de se lier avec eux, et loin de se fâcher du rang qu’on occupe, témoigner sa satisfaction de se trouver auprès d’eux ? Celui qui se plaint de la place qu’on lui assigne semble plus mécontent de son voisin que de son hôte, et se rend odieux à l’un et à l’autre . - Belles paroles que cela, repartit '''Alexidème'''. Mais, dans le fait, je vois que vous autres sages, vous recherchez les honneurs aussi bien que nous. » En même temps, il nous quitte brusquement, et s’en va. Une conduite si étrange nous étonna tous : « Ce jeune et homme, nous dit '''Thalès''', a montré dès l’enfance un caractère dur et emporté. Un jour qu’on avait fait présent à '''Thrasybule''' d’un parfum de grand prix, il le versa dans une coupe mêlé avec du vin, et l’avala, payant ainsi d’ingratitude la tendresse de son père. » Au même instant, un des gens de '''Périandre''' vint me prier d’aller avec '''Thalès''' voir quelque chose d’extraordinaire qu’on venait de lui apporter, afin de juger si c’était un jeu de la nature ou un prodige menaçant ; il nous dit qu’il en était tout troublé, et qu’il craignait que son sacrifice n’en fût souillé. En même temps, il nous conduit dans une salle qui donnait sur le jardin. Nous y trouvâmes un jeune homme sans barbe, d’une figure intéressante, qui avait l’air d’un berger. Il lève une espèce de peau, et nous fait voir un enfant qu’il disait être né d’une cavale, qui avait la tête, le cou et les mains d’un homme, et dans tout le reste, était fait comme un cheval. Sa voix ressemblait à celle d’un enfant qui vient de naître : « Dieu préservateur ! s’écria '''Niloxène''', en détournant la vue. » Mais '''Thalès''', qui a coutume de plaisanter avec moi sur mon art, après avoir longtemps considéré ce jeune homme, me dit en souriant : « Ne pensez-vous pas déja, '''Dioclès''', à faire des expiations ? Et pour détourner un présage si terrible, n’allez-vous pas donner bien de l’ouvrage aux dieux préservateurs ? - Pourquoi non ? lui répondis-je. Ce prodige, '''Thalès''', est un signe menaçant de troubles et de discorde ; et je crains bien que l’épouse et les enfants de '''Périandre''' n’en éprouvent les tristes suites, puisque enfin, comme vous voyez, avant que la déesse soit apaisée, elle donne une nouvelle marque de son courroux. » A ces mots, '''Thalès''' sourit et sortit sans rien répondre. Il vit, à la porte de la salle, '''Périandre''' venir au-devant de nous, pour savoir notre sentiment. Il me quitta, lui prit la main, et lui dit : « '''Dioclès''' vous parlera ; vous ferez à loisir ce qu’il vous dira. Pour moi, je pense que vous ne devez pas avoir, pour garder vos juments, des bergers aussi jeunes, ou que vous devez les marier. » Ce discours parut faire grand plaisir à '''Périandre''', car il en rit beaucoup, et embrassa affectueusement '''Thalès'''. Celui-ci s’adressant à moi : « Je crois, '''Dioclès''', me dit-il, que le prodige a déja eu son accomplissement. Vous voyez le malheur qui vient de nous arriver ; '''Alexidème''' a refusé de souper avec nous. » </div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Thrasybule_NdT_DR_back|<span id="Thrasybule_NdT_DR"><sup>1</sup></span>]]Dans les ''Propos de table'', on trouve une aventure pareille, arrivée chez Timon, frère de Plutarque ; mais le personnage n’est pas nommé. ''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#place_honorable_NdT_DR_back|<span id="place_honorable_NdT_DR"><sup>2</sup></span>]] Plutarque, dans les ''apophthegmes des Lacédémoniens'', nomme ce ''Spartiate'' Dæmonidas, et attribue un mot semblable au fameux Agésilas. ''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' pp.330-334, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe IV.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage du caractère désinvolte de '''Thalès'''.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§4. Ἐπεὶ δ´ εἰσήλθομεν, ἤδη μεῖζον ὁ Θαλῆς φθεγξάμενος « ποῦ δ´ » εἶπεν « ὁ ἀνὴρ κατακλινάμενος ἐδυσχέρανεν; » ἀποδειχθείσης δὲ τῆς χώρας περιελθὼν ἐκεῖ κατέκλινεν ἑαυτὸν καὶ ἡμᾶς « ἀλλὰ κἂν ἐπριάμην » εἰπών « Ἀρδάλῳ κοινωνεῖν μιᾶς τραπέζης. » ἦν δὲ Τροιζήνιος ὁ Ἄρδαλος, αὐλῳδὸς καὶ ἱερεὺς τῶν Ἀρδαλείων Μουσῶν, ἃς ὁ παλαιὸς Ἄρδαλος ἱδρύσατο ὁ Τροιζήνιος.<br /><p style="text-align: centre">[...]<br /><p style="text-align: justify; text-indent: 15px">καὶ ὁ Θαλῆς ἐμὲ προσαγορεύσας ἐπάνω τοῦ Βίαντος κατακείμενον « τί οὐκ ἔφρασας, » εἶπεν, « ὦ Διόκλεις, Βίαντι τὸν Ναυκρατίτην ξένον ἥκοντα μετὰ προβλημάτων βασιλικῶν αὖθις ἐπ´ αὐτόν, ὅπως νήφων καὶ προσέχων ἑαυτῷ τὸν λόγον δέχηται; » Καὶ ὁ Βίας « ἀλλ´ οὗτος μέν, » ἔφη, « πάλαι δεδίττεται ταῦτα παρακελευόμενος, ἐγὼ δὲ τὸν Διόνυσον οἶδα τά τ´ ἄλλα δεινὸν ὄντα καὶ Λύσιον ἀπὸ σοφίας προσαγορευόμενον, ὥστ´ οὐ δέδια τοῦ θεοῦ μεστὸς γενόμενος μὴ ἀθαρσέστερον ἀγωνίσωμαι. » Τοιαῦτα μὲν ἐκεῖνοι πρὸς ἀλλήλους ἅμα δειπνοῦντες ἔπαιζον·</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §4'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§4. Après que nous fûmes entrés, '''Thalès''' ayant déjà élevé plus haut la voix: « Où donc », dit-il, « l’avait-on placé, cet homme qui s’en est formalisé ? » Quand on lui eut montré l’endroit il fit le tour de la salle, et ce fut là-même qu’il se plaça et nous installa. « En vérité », ajouta-t-il, « j’aurais payé pour partager la même table qu’'''Ardalus'''. » Cet '''Ardalus''' était un joueur de flûte ''Trézénien'', prêtre des ''muses Ardalides'' auxquelles l’antique [[w:Ardalos|'''Ardalus''']] de ''Trézène'' avait dressé des statues.<br /><p style="text-align: center">[...]<br /><p style="text-indent: 15px">Moi, j’étais au-dessus de '''Bias''', et '''Thalès''' m’ayant interpellé : « '''Dioclès''' », me dit-il, « pourquoi n’avez-vous pas dit à '''Bias''' que l’étranger de ''Naucratie'' est venu une seconde fois le trouver avec des questions de la part de son prince, afin que ce soit à jeun qu’il reçoive ces communications et qu’il y applique son esprit ? » Et '''Bias''' : « Il y a longtemps », dit-il, « que '''Dioclès''' me menace de m’y contraindre ; mais je sais que '''Bacchus''', entre autres attributions merveilleuses, possède une sagacité qui l’a fait surnommer le dieu qui délie, de sorte que je ne crains pas, étant rempli de la divinité, que la confiance m’abandonne au moment de la lutte. » C’est ainsi que, pendant le repas, ils échangeaient entre eux des plaisanteries.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §4'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Quand nous fûmes dans la salle, il demanda, en élevant la voix : « Où est donc cette place qui a tant fâché notre homme ? » Quand on la lui eut montrée, il alla s’y placer avec nous : « Certes, ajouta-t-il, j’aurais payé pour être à la même table qu’'''Ardalus'''. » Cet '''Ardalus''' était un joueur de flûte ''træzenien'', prêtre du temple des muses ''Ardalides'', que l’ancien '''Ardalus''' avait fait bâtir à ''Træzène'' [[#Ardalus_NdT_DR|<span id="Ardalus_NdT_DR_back"><sup>1</sup></span>]].<br /><p style="text-align: center">[...]<br /><p style="text-indent: 15px">Comme j’étais au-dessus de '''Bias''', '''Thalès''' m’adressant la parole : « Pourquoi, me dit-il, ne pas avertir '''Bias''' que '''Niloxène''' vient une seconde fois de la part de son prince lui proposer des problèmes à résoudre ? Il y penserait plus librement, tandis qu’il est à jeun. - Il y a longtemps, répondit '''Bias''', que '''Dioclès''' me menace de le faire. Mais je connais la puissance de '''Bacchus''', et surtout cette sagesse qui lui a fait donner le surnom de [[wikt:λύσις#Grec_ancien|''Lysien'']] ou Dieu qui délie. Ainsi, quand je serai plein de ce dieu, je ne crains pas de combattre avec moins d'avantage. ». Ce ton de gaieté régna pendant le repas. </div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Ardalus_NdT_DR_back|<span id="Ardalus_NdT_DR"><sup>1</sup></span>]] Plutarque, dans son traité de la musique, dit qu’Ardalus, fils de Vulcain, selon la Fable, passait pour l’inventeur de la flûte.''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' pp.334, 335, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe VII.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Réflexions de '''Thalès''' sur le défi de sagacité posé par le roi des ''Éthiopiens'' au roi d’''Égypte'', [[w:Ahmôsis_II|'''Amasis''']], consistant à boire la mer. Ce dernier fait appel à '''Bias''' pour la résoudre, et celui-ci souhaite l’examiner en commun avec les sages. '''Chilon''' explique qu’il ne s’agit pas de faire disparaître tant d’eau salée, mais de rendre la domination d’'''Amasis''' potable et douce à ses sujets (§6).</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§7. [...] Ἐπὶ τούτῳ δ´ ὁ '''Θαλῆς''' ἔφησεν, εὐδαιμονίαν ἄρχοντος νομίζειν, εἰ τελευτήσειε γηράσας κατὰ φύσιν.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §7'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§7. [...] Après lui '''Thalès''' prit la parole : « J’estime que le bonheur pour un souverain, c’est s’il meurt de vieillesse et naturellement. ».</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §7'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Après lui, '''Thalès''' dit que le plus grand bonheur d’un prince serait ''de mourir de vieillesse''.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' p.339, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe IX.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Réflexions de '''Thalès''' sur le défi de sagacité posé par le roi d’''Égypte'', [[w:Ahmôsis_II|'''Amasis''']], au roi des ''Éthiopiens'', consistant en une série de questions : « Qu’y a-t-il de plus ancien ? Le temps. — De plus grand ? Le monde. — De plus habile/sage ? La vérité. — De plus beau ? La lumière. — De plus commun ? La mort. — De plus utile ? Dieu. — De plus nuisible ? Le mauvais Génie/démon. — De plus puissant/fort ? La Fortune. — De plus facile ? Le plaisir. ». '''Amasis''' fait encore appel à '''Bias''' pour analyser les réponses du roi des ''Éthiopiens'', qui les examinent également en commun avec les sages.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§9. Τούτων πάλιν ἀναγνωσθέντων, ὦ Νίκαρχε, γενομένης σιωπῆς Θαλῆς ἠρώτησε τὸν Νειλόξενον εἰ προσήκατο τὰς λύσεις ὁ Ἄμασις. ἐκείνου δ´ εἰπόντος ὅτι τὰς μὲν ἀπεδέξατο ταῖς δ´ ἐδυσκόλαινε, « καὶ μὴν οὐδέν, » εἶπεν ὁ Θαλῆς, « ἀνεπίληπτόν ἐστιν, ἀλλ´ ἔχει πάντα διαμαρτίας μεγάλας καὶ ἀγνοίας. οἷον εὐθὺς ὁ χρόνος πῶς ἂν εἴη πρεσβύτατον, εἰ τὸ μὲν αὐτοῦ γεγονὸς τὸ δ´ ἐνεστώς ἐστι τὸ δὲ μέλλον; ὁ γὰρ μεθ´ ἡμᾶς ἐσόμενος χρόνος καὶ πραγμάτων τῶν νῦν καὶ ἀνθρώπων νεώτερος ἂν φανείη. τὸ δὲ τὴν ἀλήθειαν ἡγεῖσθαι σοφίαν οὐδὲν ἐμοὶ δοκεῖ διαφέρειν τοῦ τὸ φῶς ὀφθαλμὸν ἀποφαίνειν. εἰ δὲ τὸ φῶς καλόν, ὥσπερ ἐστὶν, ἐνόμιζε, πῶς τὸν ἥλιον αὐτὸν παρεῖδε; τῶν δ´ ἄλλων ἡ μὲν περὶ θεῶν καὶ δαιμόνων ἀπόκρισις θράσος ἔχει καὶ κίνδυνον, ἀλογίαν δὲ καὶ πολλὴν ἡ περὶ τῆς τύχης· οὐ γὰρ ἂν μετέπιπτε ῥᾳδίως οὕτως, ἰσχυρότατον οὖσα τῶν ὄντων καὶ ῥωμαλεώτατον. οὐ μὴν οὐδ´ ὁ θάνατος κοινότατόν ἐστιν· οὐ γάρ ἐστι πρὸς τοὺς ζῶντας. ἀλλ´ ἵνα μὴ δοκῶμεν εὐθύνειν τὰς τῶν ἑτέρων ἀποφάσεις, ἰδίας ταῖς ἐκείνου παραβάλωμεν· ἐμαυτὸν δὲ παρέχω πρῶτον, εἰ βούλεται Νειλόξενος, ἐρωτᾶν καθ´ ἕκαστον. ὡς οὖν ἐγένοντο τότε, κἀγὼ νῦν διηγήσομαι τὰς ἐρωτήσεις καὶ τὰς ἀποκρίσεις· ‘Τί πρεσβύτατον;’ [[wikt:en:θεός#Ancient_Greek|‘θεός,’]] » ἔφη Θαλῆς· « ‘ἀγέν νητον γάρ ἐστι.’ ‘Τί μέγιστον;’ ‘τόπος· τἄλλα μὲν γὰρ ὁ κόσμος, τὸν δὲ κόσμον οὗτος περιέχει.’ ‘Τί κάλλιστον;’ ‘κόσμος· πᾶν γὰρ τὸ κατὰ τάξιν τούτου μέρος ἐστί.’ ‘Τί σοφώτατον;’ ‘χρόνος· τὰ μὲν γὰρ εὕρηκεν οὗτος ἤδη, τὰ δ´ εὑρήσει.’ ‘Τί κοινότατον;’ ‘ἐλπίς· καὶ γὰρ οἷς ἄλλο μηδέν, αὕτη πάρεστι.’ ‘Τί ὠφελιμώτατον;’ ‘ἀρετή· καὶ γὰρ τἄλλα τῷ χρῆσθαι καλῶς ὠφέλιμα ποιεῖ.’ ‘Τί βλαβερώτατον;’ ‘κακία· καὶ γὰρ τὰ πλεῖστα βλάπτει παραγενομένη.’ ‘Τί ἰσχυρότατον;’ ‘ἀνάγκη· μόνον γὰρ ἀνίκητον.’ ‘Τί ῥᾷστον;’ ‘τὸ κατὰ φύσιν, ἐπεὶ πρὸς ἡδονάς γε πολλάκις ἀπαγορεύουσιν.’ » <br /><br /><p style="text-indent: 15px;">§10. Ἀποδεξαμένων δὲ πάντων τὸν Θαλῆν, ὁ Κλεόδωρος εἶπε, « τοιαῦτ´ ἐρωτᾶν καὶ ἀποκρίνεσθαι βασιλεῦσιν, ὦ Νειλόξενε, προσῆκόν ἐστιν· ὁ δὲ προπίνων τὴν θάλατταν Ἀμάσιδι βάρβαρος ἐδεῖτο τῆς Πιττακοῦ βραχυλογίας, ᾗ πρὸς Ἀλυάττην ἐχρήσατο προστάττοντά τι καὶ γράφοντα Λεσβίοις ὑπερήφανον, ἀποκρινάμενος οὐδὲν ἀλλ´ ἢ μόνον κελεύσας κρόμμυα καὶ θερμὸν ἄρτον ἐσθίειν. »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §9'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§9. Cette lecture ainsi reproduite, mon cher '''Nicarque''', il se fit un moment de silence. Après quoi '''Thalès''' demanda à '''Niloxène''' si '''Amasis''' avait accepté de telles solutions. Il répondit que ce monarque avait accepté les unes et qu’il avait été mécontent des autres. « C’est qu’en effet », dit '''Thalès''', « il n’en est aucune qui soit irréprochable, et toutes sont grandement entachées d’erreur et d’ignorance. Ainsi, d’abord, comment le temps pourrait-il être ce qu’il y a de plus ancien, puisque, une partie étant écoulée, je le veux bien, une autre est le présent, une autre est l’avenir ? Le temps qui doit venir après nous est évidemment plus jeune que les hommes d’aujourd’hui, que les événements actuels. Croire que ce qu’il y a de plus habile, ce soit la vérité, c’est, à mon avis, ne pas émettre une autre opinion que celle-ci : l’oeil et la lumière sont tout un. Si du reste l’''Éthiopien'' a cru, ce qui est réel, la lumière plus belle que tout, pourquoi a-t-il négligé de nommer le soleil lui-même ? Des autres réponses, celle qui concerne la Divinité et le Génie est aussi téméraire que dangereuse ; et ce qu’il dit de la Fortune est tout à fait déraisonnable : car elle ne changerait pas avec tant de facilité, si elle était ce qu’il y a de plus puissant et de plus fort au monde. De même, la mort n’est pas ce qu’il y a de plus commun, puisqu’elle n’est pas commune aux vivants. Mais pour que nous ne semblions pas nous borner à redresser les réponses des autres, il faut y opposer nos propres solutions. Je m’y offre le premier, si '''Niloxène''' veut reprendre chaque question ». Telles que furent faites alors et les demandes et les réponses, je vais vous les reproduire aujourd’hui : Qu’y a-t-il de plus ancien ? C’est dieu, répondit '''Thalès''', attendu qu’il est incréé. — De plus grand ? L’espace : car si le monde contient le reste, à son tour il est contenu dans l’espace. — De plus beau ? Le monde : car tout ce qui est bien ordonné en fait partie. ― De plus habile ? Le temps : car c’est lui qui a découvert et qui découvrira tout. — De plus commun ? L’espérance : car ceux même qui n’ont rien autre chose la possèdent. — De plus utile ? La vertu : car elle rend toutes les autres choses utiles par le bon usage qu’elle en fait. — De plus nuisible ? Le vice : car il corrompt tout par sa présence. — De plus puissant ? La nécessité : car elle est seule invincible. De plus facile ? Ce qui est selon la nature : car, pour ce qui est du plaisir, il amène souvent la lassitude.<br /><br /><p style="text-indent: 15px;">§10. Tout le monde ayant accueilli ces réponses de '''Thalès''', '''Cléodème''' prit la parole : « Voilà », dit-il, « ô '''Niloxène''', les questions et les réponses qu’il est convenable de faire à des rois. Mais le barbare qui veut faire boire la mer à '''Amasis''' aurait besoin de la concision employée par '''Pittacus''' à l’égard d’[[w:Alyatte_II|'''Alyatte''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Alyatte_back|<sup>🔄</sup>]], quand celui-ci enjoignait aux ''Lesbiens'' un ordre des plus insolents. Il se contenta, pour toute réponse, de l’engager « à manger des oignons et du pain chaud. »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §9'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Cette lecture étant finie, il se fit un moment de silence ; après quoi, '''Thalès''' demanda si le roi d’''Égypte'' avait approuvé toutes ces solutions. '''Niloxène''' lui répondit qu’il avait adopté les unes et rejeté les autres : « Mais, reprit '''Thalès''', il n’en est aucune d’admissible, et qui ne soit marquée au coin de l’erreur et de l’ignorance. D'abord, comment le temps peut-il être ce qu’il y a de plus ancien, puisqu’on le divise en passé, présent et avenir ? Ce dernier est certainement moins ancien que les hommes et que les événements actuels. Dire que la vérité est la sagesse, c’est, ce me semble, confondre l’œil avec la lumière. Si d’ailleurs la lumière est, selon lui, ce qu'’il y a de plus beau, pourquoi ne pas nommer le soleil lui-même ? Quant aux autres réponses, celles qu’il a faites sur les dieux et les démons sont aussi hardies que dangereuses. Ce qu’il dit de la fortune est tout à fait déraisonnable. Si elle est réellement si forte et si puissante, comment change-t-elle avec tant de facilité ? Enfin la mort n’est pas ce qu’il y a de plus commun, puisqu’elle n’existe point parmi les vivants. Mais pour qu’on ne croie pas que nous voulons seulement critiquer, opposons à ces réponses nos solutions. Je m’offre le premier pour répondre , si '''Niloxène''' veut reprendre les questions . »<br /><br /><p style="text-indent: 15px;">'''Niloxène''' le fit, et '''Thalès''' donna ses réponses, que je vais vous répéter. Qu’y a-t-il de plus ancien ? Dieu ; car il est éternel. De plus grand ? l’espace ; il contient le monde, qui lui-même renferme tout le reste. De plus beau ? le monde ; tout ce qui est dans l’ordre en fait partie. De plus sage ? le temps ; il a découvert ou découvrira tout. De plus commun ? l’espérance ; elle reste à ceux mêmes qui n’ont rien. De plus utile ? la vertu; elle fait bien user de tout. De plus nuisible ? le vice ; il corrompt tout par sa présence. De plus fort ? la nécessité ; elle seule est invincible. De plus facile ? ce qui est selon la nature ; on se lasse souvent du plaisir même.<br /><br /><p style="text-indent: 15px;">Tout le monde applaudit aux solutions de '''Thalès''' : « Voilà, dit '''Cléodème''', les questions et les réponses qu’il convient à des rois de faire. Pour ce barbare, qui propose à votre prince de boire toute la mer, il lui fallait une réponse aussi courte que celle de '''Pittacus''' au roi de ''Lydie'' '''Alyatte''', qui , dans une lettre, donnait aux ''Lesbiens'' un ordre très impérieux. '''Pittacus''' se contenta de lui récrire : ''Mangez des ognons et du pain chaud'' [[#expression_proverbiale_mépris_NdT_DR|<span id="expression_proverbiale_mépris_NdT_DR_back"><sup>1</sup></span>]].</div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#expression_proverbiale_mépris_NdT_DR_back|<span id="expression_proverbiale_mépris_NdT_DR"><sup>1</sup></span>]] C’est-à-dire : pleurez ; expression proverbiale, pour témoigner du mépris à quelqu’un.''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' pp.341, 342, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe XI.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Réflexion de '''Thalès''' sur les gouvernements où la loi est égale pour tous.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§11. Ἐπὶ τούτῳ '''Θαλῆς''' τὴν μήτε πλουσίους ἄγαν μήτε πένητας ἔχουσαν πολίτας.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §11'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§11. Après lui '''Thalès''' : « que c’est celle qui n’a ni des citoyens trop riches, ni des citoyens trop pauvres. »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §11'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">'''Thalès''' : ''celle dont les citoyens ne sont ni trop riches ni trop pauvres''.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' p.345, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe XII.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Réflexion de '''Thalès''' sur la maison la mieux réglée.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§12. Ὁ δὲ '''Θαλῆς''' ἐν ᾧ πλείστην ἄγειν τῷ δεσπότῃ σχολὴν ἔξεστιν.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §12'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§12. '''Thalès''' : « celle où le maître peut avoir un très grand loisir. »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §12'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">'''Thalès''' : ''celle qui donne le moins d’affaires à son maître''.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' p.346, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe XIII.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Référence à l’anecdote de la coupe de [[w:Bathyclès_de_Magnésie|'''Bathyclès''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_période_Grèce_Hellénistique#Bathyclès_back|<sup>🔄</sup>]] par [[w:Callimaque_de_Cyrène|'''Callimaque''']] de [[w:Cyrène|''Cyrène'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_période_Grèce_Hellénistique#Callimaque_back|<sup>🔄</sup>]].</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§13. Ἐπεὶ δὲ καὶ οὗτος ἔσχεν ὁ λόγος τέλος, ἡ μὲν Εὔμητις ἐξῆλθε μετὰ τῆς Μελίσσης, τοῦ δὲ Περιάνδρου τῷ Χίλωνι προπιόντος εὐμεγέθη κύλικα, τῷ δὲ Βίαντι τοῦ Χίλωνος, Ἄρδαλος ἐπαναστὰς καὶ προσαγορεύσας τὸν Αἴσωπον, « σὺ δ´ οὐκ ἄν, » ἔφη, « διαπέμψαιο δεῦρο τὸ ποτήριον πρὸς ἡμᾶς, ὁρῶν τούτους ὥσπερ τὴν Βαθυκλέους κύλικα διαπεμπομένους ἀλλήλοις, ἑτέρῳ δὲ μὴ μεταδιδόντας; » Καὶ ὁ Αἴσωπος, « ἀλλ´ οὐδὲ τοῦτ´, » ἔφη, « τὸ ποτήριον δημοτικόν ἐστι· Σόλωνι γὰρ ἔκπαλαι παράκειται μόνῳ. »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §13'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§13. Ce texte de conversation se trouvant à son tour épuisé, et '''Eumétis''' étant sortie avec '''Mélissa''', '''Périandre''' but une grande coupe à '''Chilon''', et '''Chilon''', à '''Bias'''. '''Ardalus''' alors se leva, et interpellant '''Ésope''' : « Ne feras-tu pas, dit-il, circuler la coupe jusqu’à nous, quand tu vois qu’ils se la passent mutuellement comme s’il s’agissait de celle de '''Bathycle''' et qu’ils ne la partagent pas avec un autre ? » Et '''Esope''' : « Mais ce vase non plus, dit-il, n’est pas une propriété populaire : car voilà longtemps qu’il reste devant '''Solon''' tout seul ».</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §13'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Après tous ces propos, '''Mélisse''' sortit avec '''Eumétis'''. '''Périandre''' alors boit le premier dans une grande coupe, la présente à '''Chilon''' [[#Chilon_NdT_DR|<span id="Chilon_NdT_DR_back"><sup>1</sup></span>]], et celui-ci à '''Bias''', qui la remit à '''Solon'''. Comme ce dernier la gardait, '''Ardalus''' se lève , et s’adressant à '''Esope''' : « Ne nous ferez-vous point, lui dit-il, passer ce vase, que nos sages, comme vous voyez, se renvoient l’un à l’autre, ainsi que la coupe de '''Bathycle''', sans le faire parvenir jusqu’à nous [[#Bathycle_NdT_DR|<span id="Bathycle_NdT_DR_back"><sup>2</sup></span>]] ? ― Ce vase, lui répondit '''Esope''', n’est sûrement pas populaire, puisqu’il reste si longtemps devant '''Solon'''. »</div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Chilon_NdT_DR_back|<span id="Chilon_NdT_DR"><sup>1</sup></span>]] Cet usage était constant chez les anciens. A la fin du repas, on remplissait de vin une grande coupe. Le principal personnage de l’assemblée en buvait le premier, et la coupe passait ainsi de main en main.''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Bathycle_NdT_DR_back|<span id="Bathycle_NdT_DR"><sup>2</sup></span>]] Tout le monde sait l’histoire du fameux trépied d’or, trouvé par des pêcheurs, qui, pour terminer leurs débats, ayant eu recours à l’oracle de ''Delphes'', reçurent ordre d’en faire présent au plus sage, et l’envoyèrent à Thalès. Après avoir passé successivement par les mains des sept sages, il revint à Thalès, qui le consacra dans un temple d’Apollon. Selon Léandre de ''Milet'', cité par Diogène Laërce, c’était une coupe d’or que l’''Arcadien'' Bathycle avait laissée, par son testament, au plus sage, et c’est ce dernier récit que Plutarque semble préférer.''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' p.347, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe XIV.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage de l’''espièglerie'' de '''Thalès'''.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§14. [...] '''Ἐπιστήσαντος''' δὲ τοῦ λόγου τὸ συμπόσιον ὁ μὲν '''Θαλῆς''' ἐπισκώπτων εὖ φρονεῖν ἔφη τὸν '''Ἐπιμενίδην''' ὅτι μὴ βούλεται πράγματα ἔχειν ἀλῶν τὰ σιτία καὶ πέττων ἑαυτῷ, καθάπερ '''Πιττακός'''. « ἐγὼ γάρ, » εἶπε, « τῆς ξένης ἤκουον ᾀδούσης πρὸς τὴν μύλην, ἐν [[w:Eresós|''Ἐρέσῳ'']] γενόμενος, ἄλει, μύλα, ἄλει· καὶ γὰρ '''Πιττακὸς''' ἄλει μεγάλας ''Μυτιλάνας'' βασιλεύων. »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §14'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§14. [...] Ces paroles ayant mis en arrêt les convives, '''Thalès''' dit en raillant qu’'''Epiménide''' avait bien raison de ne pas vouloir se donner l’embarras de moudre et de cuire lui-même son manger, comme faisait '''Pittacus''' : « Car je me souviens », ajouta-t-il, « qu’étant à ''Lesbos'', j’entendis mon hôtesse chanter à sa meule : Va ton train, meule, va ton train, puisque '''Pittacus''', le roi de la grande ''Mitylène'', s’occupe bien à moudre. »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §14'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Ce discours ayant frappé tout le monde, '''Thalès''' dit en plaisantant qu’il approuvait '''Epiménides''' [[#Epiménides_NdT_DR|<span id="Epiménides_NdT_DR_back"><sup>1</sup></span>]] de s’épargner la peine de moudre et de cuire lui-même son pain, comme faisait '''Pittacus'''. « Je me souviens , ajouta-t-il, qu’étant à ''Lesbos'', j’ai entendu une meunière qui chantait : ''Moulez, meule, moulez ; '''Pittacus''', qui règne dans la superbe Mitylène, s’occupe aussi à moudre'' [[#Pittacus_NdT_DR|<span id="Pittacus_NdT_DR_back"><sup>2</sup></span>]]. »</div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Epiménides_NdT_DR_back|<span id="Epiménides_NdT_DR"><sup>1</sup></span>]] Epiménides était un poète de l’île de ''Crète''. Les nymphes, disait-on, lui avaient donné un aliment miraculeux, qu’il conservait dans une corne de bœuf, et dont une très petite quantité suffisait pour le nourrir. ''' </td> <tr> </tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Pittacus_NdT_DR_back|<span id="Pittacus_NdT_DR"><sup>2</sup></span>]] Pittacus, au rapport de différents historiens, s’exerçait à moudre du blé. Il faisait un grand éloge de l’utilité des moulins, et insistait sur l’avantage qu’a le moulin de fournir, dans un très petit espace, le moyen de prendre différents exercices. ''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' p.351, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe XV.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage d’une doctrine de '''Thalès''' sur l’importance vitale de l’agriculture.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§15. [...] « Οὐδαμῶς, » ὁ '''Κλεόδωρος''', « ἔμοιγ´, » εἶπεν, « εἰ δεῖ τὸ φαινόμενον εἰπεῖν, καὶ μάλιστα παρακειμένης τραπέζης, ἣν ἀναιροῦσιν αἰρομένης τροφῆς φιλίων θεῶν βωμὸν οὖσαν καὶ ξενίων. ὡς δὲ '''Θαλῆς''' λέγει τῆς γῆς ἀναιρεθείσης σύγχυσιν τὸν ὅλον ἕξειν κόσμον, οὕτως οἴκου διάλυσις ἐστι· συναναιρεῖται γὰρ αὐτῇ πῦρ ἑστιοῦχον ἑστία κρατῆρες ὑποδοχαὶ ξενισμοί, φιλανθρωπότατα καὶ πρῶτα κοινωνήματα πρὸς ἀλλήλους, μᾶλλον δὲ σύμπας ὁ βίος, εἴ γε διαγωγή τίς ἐστιν ἀνθρώπου πράξεων ἔχουσα διέξοδον, ὧν ἡ τῆς τροφῆς χρεία καὶ παρασκευὴ τὰς πλείστας παρακαλεῖ. [...] »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §15'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§15. [...] « S’il faut dire ce que je pense », reprit '''Cléodème''', « ce n’est nullement mon avis, et surtout quand est dressée la table, que l’on supprime si la nourriture est supprimée et qui est l’autel des dieux amis et hospitaliers. Et s’il est vrai, comme dit '''Thalès''', que la suppression de la terre dût entraîner le désordre et la ruine du monde entier, de même anéantir la table ce serait anéantir la maison. Avec la table disparaîtraient le feu qui consacre le foyer, le foyer lui-même, les coupes, les réceptions, les hospitalités, qui sont les plus affectueux et les premiers rapports de communauté entre les hommes; ou plutôt disparaîtrait la vie entière, s’il est vrai que la vie soit une sorte de courant formé par la série des actes de l’homme, actes dont le plus grand nombre est commandé par le besoin et la préparation de la nourriture.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §15'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">S’il faut, reprit '''Cléodème''', que je dise mon sentiment, je ne suis point du tout de cet avis-là, surtout quand la table est dressée. Nous ôter le besoin de nourriture, c’est détruire cet autel des dieux hospitaliers. Et comme la destruction de la terre, selon '''Thalès''', entraînerait la ruine de l’univers, ainsi la chute de la table causerait celle de la maison. Avec elle, on détruirait le feu sacré de nos foyers, les dieux pénates, les libations, le plaisir si touchant de recevoir et de traiter ses amis, tous ces usages respectables qui sont les premiers fondements et les plus doux liens de la société ; disons mieux, on détruirait la vie entière, puisqu’elle est remplie par des occupations et des soins successifs, dont la plupart ont pour objet la nourriture et sa préparation.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' pp.353, 354, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe XVII.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage d’une parole sage de '''Thalès''' : Ne croire ni ses ennemis sur les choses croyables, ni ses amis sur les choses incroyables.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§17. τέλος δὲ γελάσας πρὸς ἡμᾶς « βούλομαι μέν, » ἔφη, « πρὸς τὸ παρὸν φράσαι τὸ προσηγγελμένον· ὀκνῶ δ´ ἀκούσας '''Θαλέω''' ποτ´ εἰπόντος ὅτι δεῖ τὰ μὲν εἰκότα λέγειν, τὰ δ´ ἀμήχανα σιωπᾶν. » Ὑπολαβὼν οὖν ὁ '''Βίας''' « ἀλλὰ καὶ τοῦτ´, » ἔφη, « '''Θαλέω''' τὸ σοφόν ἐστιν, ὅτι δεῖ τοῖς μὲν ἐχθροῖς καὶ περὶ τῶν πιστῶν ἀπιστεῖν, τοῖς δὲ φίλοις καὶ τὰ ἄπιστα πιστεύειν, ἐχθροὺς μέν, ἔγωγ´ ἡγοῦμαι, τοὺς πονηροὺς καὶ ἀνοήτους, φίλους δὲ τοὺς χρηστοὺς καὶ φρονίμους αὐτοῦ καλοῦντος. οὐκοῦν, »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §17'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§17. [...] A la fin il s’adressa à nous en éclatant de rire : « Je voudrais vous faire connaître, sans plus attendre, ce que '''Gorgias''' vient de me conter; et pourtant j’hésite, parce que j’ai autrefois entendu dire à '''Thalès''' qu’il faut dire les choses vraisemblables et taire les impossibles. « Mais, reprit '''Bias''', « c’est à '''Thalès''' aussi qu’appartient cette sage parole : qu’il faut ne pas croire ses ennemis même sur les choses croyables, et croire ses amis même sur celles qui ne le sont pas : par ennemis il entendait, je suppose, les méchants et les sots, par amis, les gens vertueux et sensés. »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §17'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Mais quand '''Gorgias''' [[#Gorgias_NdT_DR|<span id="Gorgias_NdT_DR_back"><sup>1</sup></span>]] eut achevé, il nous dit en riant : « Je voudrais vous répéter ce que je viens d’entendre ; mais je n’ose le faire après ce mot de '''Thalès''' : qu’il faut dire les choses vraisemblables, et taire celles qui paraissent impossibles. - Mais, repartit '''Bias''' , n’est-ce pas aussi '''Thalès''' qui a dit cette autre maxime si sage, qu’il faut ne pas croire ses ennemis même sur les choses croyables, et croire ses amis sur les choses même les moins vraisemblables. Par les ennemis, il entend, sans doute, les méchants et les insensés ; par les amis, les bons et les sages.</div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#Gorgias_NdT_DR_back|<span id="Gorgias_NdT_DR"><sup>1</sup></span>]] Tout ce qu’on sait de ce frère de Périandre, c’est qu’il fonda une colonie dans l’''[[w:Ambracie|Ambracie]]'', et qu’il mourut vraisemblablement avant son frère, puisque son fils [[w:Psammétique_(Corinthe)|Psammétique]] succéda à Périandre, et fut le dernier tyran de ''Corinthe'' de la race de [[w:Cypsélos|Cypsèle]]. ''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' p.358, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe XXI.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage d’une doctrine de '''Thalès''' sur la résidence de l'âme dans toutes les parties du monde les plus essentielles.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§21. Μετὰ δὲ τοῦτον ὁ '''Ἀνάχαρσις''' εἶπεν ὅτι τοῦ '''Θαλέω''' καλῶς ὑπολαμβάνοντος ἐν πᾶσιν εἶναι τοῖς κυριωτάτοις μέρεσι τοῦ κόσμου καὶ μεγίστοις ψυχήν, [...].</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §21'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§21. Après '''Pittacus''', '''Anacharsis''' prit la parole : « Puisque, comme '''Thalès''' l’a magnifiquement établi, une âme réside dans toutes les parties du monde les plus essentielles, [...].</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://remacle.org/bloodwolf/historiens/Plutarque/banquet.htm Των επτα σοφων συμποσιον - Le banquet des sept sages], §21'', texte établi par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">'''Pittacus''' ayant cessé de parler, '''Anacharsis''' prit la parole : « S’il est vrai, dit-il, comme '''Thalès''' le croit avec raison, que les plus grandes et les principales parties du monde ont une ame, [...].</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome I, [https://www.google.fr/books/edition/Oeuvres_morales_de_Plutarque/QnRQAAAAcAAJ?hl=fr&gbpv=0 Le banquet des sept sages]'' p.365, traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto; color: #3366BB">― ✳ ―</div> ==== Du démon de '''Socrate''' ==== <div style="text-align: center; margin: 0 1em;">Discussion autour de la libération de [[w:Thèbes (Grèce)|''Thèbes'']] de ''[[w:Sparte|Sparte]]'' grâce à une conjuration de '''[[w:Pélopidas|Pélopidas]]''' [[#Pélopidas|<span id="Pélopidas_back"><sup>'''I'''</sup></span>]] en [[w:-379|-379]]. Le récit est ici plus ample que lors de la biographie de Pélopidas dans les ''[[w:Vies parallèles|Vies parallèles]]''. La source de '''Plutarque''' est d’origine ''thébaine'', la même que '''[[w:Cornélius Népos|Cornélius Népos]]''' [[#Cornélius_Népos|<span id="Cornélius_Népos_back"><sup>'''II'''</sup></span>]]. Le traité porte sur la ''[[w:démonologie|démonologie]]'', le démon de '''Socrate''' peut-être une voix intérieure ou ses capacités [[w:divinatoires|divinatoires]]'', la légende étant d’origine [[w:pythagoricienne|pythagoricienne]] et évoque l’oracle '''[[w:Trophonios|Trophonios]]'''.</div> {{Boîte déroulante début|titre=NdA du Démon de Socrate|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Pélopidas_back|<span id="Pélopidas"><sup>I</sup></span>]] Du nom propre grec ancien Πελοπῐ́δᾱς / Pelopĭ́dās [[wikt:en:Πελοπίδας#Ancient_Greek|(en)]] ;<br /><p style="margin: 0 2em; text-indent: 15px;">Stratège [[w:Thèbes (Grèce)|''thébain'']]. Chassé en [[w:-382|-382]] de ''Thèbes'' après la prise de la [[w:Cadmée_(Thèbes)|Cadmée]], la citadelle située au sommet de son ''[[w:acropole|acropole]]'', par [[w:Phébidas|Phébidas]] avec l’aide des ''[[w:Sparte|Spartiates]]'', il renverse le gouvernement pro-spartiate d’[[w:Archias de Thèbes|Archias]] et de Léontidas en [[w:-379|-379]], qu’il tue, et rétablit la ''[[w:démocratie|démocratie]]''.<br /><p style="text-align: right; margin: 0 2em;">(date de naissance inconnue, à ''Thèbes'' — [[w:364_av._J.-C.|-364]]<sup>[[w:IVe_siècle_av._J.-C.|⏳]]</sup>, mort lors de la [[w:Bataille_de_Cynoscéphales_(364_av._J.-C.)|''bataille de Cynoscéphales'']], dans le cadre d’une vengeance pour sa captivité par le ''tyran'' de [[w:Thessalie|''Thessalie'']], [[w:Alexandre_de_Phères|Alexandre]] de [[w:Phères|''Phères'']], alors qu’il était en ambassade chez lui)<br /><br /><p style="margin: 0 2em; text-indent: 15px;">[[#Cornélius_Népos|<span id="Cornélius_Népos"><sup>II</sup></span>]] [[w:Nom_romain|Tria Nomina]] en latin ''{{Info|<nowiki>[praenomen inconnu]</nowiki>|praenomen, nom individuel du citoyen romain}}'' {{Info|Cornélius|nomen, nom de famille}} {{Info|Népos|cognomen, surnom héréditaire, servant à distinguer les diverses branches d’une même gens}}<br /><p style="margin: 0 2em; text-indent: 15px;">Auteur ''latin''. On sait par les lettres de Cicéron que Cornelius Népos n’aimait pas les écrits moraux, leur préférant la description de la nature et l’étude de l’histoire. Aucun des ouvrages qu’il avait composés dans ce genre n’est parvenu en entier jusqu’à nous. Les « Vies des grands capitaines de l’antiquité » qui subsistent aujourd’hui, et qui ont connu de multiples éditions, lui ont été attribuées jusqu'au XVIIIe siècle ; mais l'analyse de ce court recueil montre qu'il ne serait qu'un abrégé (attribué à Æmilius Probus), de l’ouvrage original de Cornelius Népos.<br /><p style="text-align: right; margin: 0 2em;">(vers [[w:-100|-100]], au pays des [[w:Insubres|Insubres]] à [[w:Mantoue|Mantoue]] ou à [[w:Pavie|''Ticinum'']], dans le nord de l’''Italie'' — vers [[w:-29|-29]]/[[w:-25|-25]], à ''Rome'')<sup>[[w:Ier_siècle_av._J.-C.|⏳]]</sup>'''<br /><br /> </div>{{Boîte déroulante fin}} ===== <div style="text-align: center;">Paragraphe VI.</div> ===== <div style="text-align: center; margin: 0 1em;">Témoignage de l’aversion de '''Thalès''' pour les [[w:Tyran|''tyrans'']].</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid;"><br /><div style="text-align: justify; margin: 0 2em; text-indent: 15px">§6. Ταῦτα τοῦ '''Θεοκρίτου''' λέγοντος ὁ '''Λεοντίδης''' ἐξῄει μετὰ τῶν φίλων, ἡμεῖς δ´ εἰσελθόντες ἠσπαζόμεθα τὸν '''Σιμμίαν''' ἐπὶ τῆς κλίνης καθεζόμενον οὐ κατατετευχότα τῆς δεήσεως, οἶμαι, μάλα σύννουν καὶ διαλελυπημένον· ἀποβλέψας δὲ πρὸς ἅπαντας ἡμᾶς ‘ὦ '''Ἡράκλεις''',’ εἶπεν ‘ἀγρίων καὶ βαρβάρων ἠθῶν· εἶτ´ οὐχ ὑπέρευ '''Θαλῆς''' ὁ παλαιὸς ἀπὸ ξένης ἐλθὼν διὰ χρόνου τῶν φίλων ἐρωτώντων ὅ τι καινότατον ἱστορήκοι ’τύραννον‘ ἔφη ’γέροντα.‘ καὶ γὰρ ᾧ μηδὲν ἰδίᾳ συμβέβηκεν ἀδικεῖσθαι, τὸ βάρος αὐτὸ καὶ τὴν σκληρότητα τῆς ὁμιλίας δυσχεραίνων ἐχθρός ἐστι τῶν ἀνόμων καὶ ἀνυπευθύνων δυναστειῶν.[...]</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome II, [https://remacle.org/bloodwolf/historiens/Plutarque/demonsocrategr.htm Περι του Σωκρατους Δαιμονιου - Le Démon de Socrate], §6'', traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§6. Pendant que [[w:Théocrite|'''Théocritos''']] [[#Théocrite|<span id="Théocrite_back"><sup>'''I'''</sup></span>]] parlait, '''Léontidas''' sortit avec ses amis, et nous entrâmes chez [[w:Simmias_de_Thèbes|'''Simmias''']] [[#Simmias_de_Thèbes|<span id="Simmias_de_Thèbes_back"><sup>'''II'''</sup></span>]], que nous saluâmes affectueusement. Il était assis sur son lit, et j’attribuai à l’insuccès de sa demande son air pensif et affligé. Après nous avoir regardés tous : « Par '''Hercule''' ! s’écria-t-il, quelles mœurs sauvages et barbares ! Eh bien ! n’avait-il pas cent fois raison le '''Thalès''' des anciens jours ? Comme il était revenu d’un long voyage à l’étranger, ses amis lui demandaient ce qu’il avait vu de plus curieux : « Un tyran parvenu à la vieillesse », répondit-il. Car ceux même qui n’ont pas éprouvé de la part d’un despote une injustice personnelle, supportent avec peine le poids et la dureté d’un semblable régime. On déteste tout pouvoir qui est en dehors de la loi et qui ne veut rendre de comptes à personne. [...]</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome III, [[s:Page:Plutarque_-_Œuvres_complètes_de_Plutarque_-_Œuvres_morales_et_œuvres_diverses,_tome_3,_1870.djvu/74|Περι του Σωκρατους Δαιμονιου - Le Démon de Socrate]], [[s:Page:Plutarque_-_Œuvres_complètes_de_Plutarque_-_Œuvres_morales_et_œuvres_diverses,_tome_3,_1870.djvu/83|§6]]'', traduites par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> {{Boîte déroulante début|titre=NdA de trad. Victor Bétolaud de 1870|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Théocrite_back|<span id="Théocrite"><sup>I</sup></span>]] Du nom propre [[w:Nom_théophore|''théophore'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_période_Grèce_Classique#théophore_back|<sup>🔄</sup>]] grec ancien Θεόκριτος / Theókritos [[wikt:en:Θεόκριτος#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;">➥ de l’adjectif et du nom commun θεός / theós [[wikt:en:θεός#Ancient_Greek|(en)]], « divin, dieu, divinité »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ +‎ du verbe κρίνω / krínō, « 1. (transitif) Séparer, diviser, distinguer entre deux choses ou personnes ou parmi un groupe de choses ou de personnes. 2. (transitif) Commander, organiser. 3. S’enquérir, enquêter. 4. Sélectionner, choisir, préférer. 5. (transitif) Trancher un différend ou un concours ; (intransitif) Porter un jugement, prendre une décision : • (voix moyenne, voix passive) Décider d’un concours ; (voix moyenne et voix passive) Se disputer, se disputer, se quereller. 6. Décider ou juger [+accusatif et infinitif = que quelque chose fait quelque chose], [+accusatif et accusatif = que quelque chose est quelque chose]. 7. Discerner entre le bien et le mal. 8. Juger, prononcer. 9. Traduire en justice, accuser. 10. Condamner, critiquer. 11. Sécréter, cacher, dissimuler. »;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ + le suffixe adjectival récessif‎ -τος / -tos [[wikt:en:-τος#Ancient_Greek|(en)]];<br /><p style="margin: 0 2em; text-indent: 15px;">''Poète'', auteur de [[w:Mime|''mimes'']] (imitations comiques du langage ou des gestes), d’[[w:Poésie_pastorale|''idylles pastorales'']] et de [[w:Épopée|''contes épiques'']].<br /><p style="text-align: right; margin: 0 2em;">([[w:Circa|{{Info|''ca.''|Circa, locution latine que l’on emploie pour indiquer l’approximation d’une date}}]] [[w:310_av._J.-C.|-310]]<sup>[[w:IVe_siècle_av._J.-C.|⏳]]</sup>, à [[w:Théocrite#cite_ref-2|''Syracuse'']] — {{Info|''ca.''|Circa, locution latine que l’on emploie pour indiquer l’approximation d’une date}} [[w:250_av._J.-C.|-250]]<sup>[[w:IIIe_siècle_av._J.-C.|⏳]]</sup>) <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Simmias_de_Thèbes_back|<span id="Simmias_de_Thèbes"><sup>II</sup></span>]] Du grec ancien Σιμμίας ο Θηβαίος / Simmías o Thēbaíos ;<br /><p style="margin: 0 2em; text-indent: 15px;">Philosophe grec et disciple de [[w:Socrate|Socrate]] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Socrate_back|<sup>🔄</sup>]].<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:Ve_siècle_av._J.-C.|V<sup>ème</sup>]] et [[w:IVe_siècle_av._J.-C.|IV<sup>ème</sup>]] siècles {{Info|AEC|Avant l’Ère Commune}}, ''Thèbes'')'''<br /><br /> </div>{{Boîte déroulante fin}} <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">§6. Pendant que '''Théocritos''' discourait ainsi, '''Léontidas''' sortit avec ses amis ; nous entrâmes et saluâmes '''Simmias''', qui était assis sur son lit, tout soucieux et triste, parce que sa demande avait été rejetée sans doute. En nous regardant tous, il s’écria : « '''Héraclès''' ! les moeurs sauvages et barbares ! Ah ! que '''Thalès''' l’ancien avait raison de répondre, lorsqu’après un long voyage à l’étranger ses amis lui demandaient ce qu’il avait remarqué de plus extraordinaire : « Un tyran âgé ». Même un homme qui a eu la chance de n’être pour son compte victime d’aucune injustice exècre déjà le poids et la dureté de ce commerce et est ennemi des dictatures, des dominations arbitraires.[...]</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome II, [https://remacle.org/bloodwolf/historiens/Plutarque/demonsocrate.htm Περι του Σωκρατους Δαιμονιου - Le Démon de Socrate], §6'', traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto; color: #3366BB">― ✳ ―</div> ==== Les [[w:Alimentation_en_Grèce_antique#Banquets|''Symposiaques'']] [[#Symposiaques|<span id="Symposiaques_back"><sup>'''I'''</sup></span>]], ou questions de table ==== <div style="text-align: center; margin: 0 1em;"></div> {{Boîte déroulante début|titre=NdA Les Symposiaques|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Symposiaques_back|<span id="Symposiaques"><sup>I</sup></span>]] Du nom commun grec ancien συμπόσιον / sympósion [[wikt:en:συμπόσιον#Ancient_Greek|(en)]], « Seconde partie d’un repas pendant laquelle un groupe restreint de convives buvaient et discutaient sur un sujet. » ; <br /><p style="margin: 0 2em; text-indent: 15px;">➥ du nom commun σῠμπότης / sŭmpótēs [[wikt:en:συμπότης#Ancient_Greek|(en)]], « compagnon de boisson » ; <br /><p style="margin: 0 4em; text-indent: 15px;">➥ du préfixe σῠν- / sŭn- [[wikt:en:συν-#Ancient_Greek|(en)]], « avec, ensemble » ;<br /><p style="margin: 0 4em; text-indent: 15px;">➥ +‎ du nom commun ποτής / potḗs [[wikt:en:ποτής#Ancient_Greek|(en)]], « boisson » ;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ +‎ du suffixe -ῐον / -ĭon [[wikt:en:-ιον#Ancient_Greek|(en)]] ;<br /><p style="margin: 0 2em; text-indent: 15px;">Entretiens dans un banquet, propos de table. '''<br /><br /> </div>{{Boîte déroulante fin}} ===== <div style="text-align: center;">Livre III</div> ===== <div style="text-align: center; margin: 0 1em;"></div> ====== <div style="text-align: center;">Question VI. Sur le temps où il est à propos de se rapprocher d’une femme.</div> ====== <div style="text-align: center; margin: 0 1em;">Témoignage du statut marital de '''Thalès''' et de sa relation avec sa mère</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid;"><br /><div style="text-align: justify; margin: 0 2em; text-indent: 15px">Καθάπερ οὖν '''Θαλῆς''' ὁ σοφὸς ὑπὸ τῆς μητρὸς ἐνοχλούμενος γῆμαι κελευούσης πῶς ὑπεξέφυγε παρήγαγε λέγων πρὸς αὐτὴν ἐν ἀρχῇ μέν « οὔπω καιρὸς ὦ μῆτερ, » ὕστερον δ´ « οὐκέτι καιρὸς ὦ μῆτερ », οὕτως ἄρα καὶ πρὸς ἀφροδίσια κράτιστον {ἔσται} ἔχειν ἕκαστον, ὥστε κατακλινόμενον λέγειν «οὔπω καιρός», ἀνιστάμενον δ´ « οὐκέτι καιρός ».</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome III, [https://remacle.org/bloodwolf/historiens/Plutarque/sympos3.htm#VI Προβλημα Ϛ. Περὶ καιροῦ συνουσίας. - Question VI. Quel est le temps le plus propre à l'amour?]'', traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div></div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§3. Ainsi donc, comme le sage '''Thalès''', fatigué par sa mère qui l’engageait à se marier, trouva le moyen de lui échapper et de lui donner le change en lui disant une première fois : « Il n’est pas encore temps, ma mère », et, lorsqu’elle insistait encore après qu’il avait passé l’âge : « Il n’est plus temps » ; de même, pour ce qui regarde les plaisirs de l’amour, le mieux sera que chacun se détermine à dire, en se mettant au lit : « Il n’est pas temps encore », et, en sortant du lit : « il n’est plus temps ».</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome III, [[s:Page:Plutarque_-_Œuvres_complètes_de_Plutarque_-_Œuvres_morales_et_œuvres_diverses,_tome_3,_1870.djvu/268|Question VI. Sur le temps où il est à propos de se rapprocher d’une femme]], [[s:Page:Plutarque_-_Œuvres_complètes_de_Plutarque_-_Œuvres_morales_et_œuvres_diverses,_tome_3,_1870.djvu/271|§3]]'', traduites par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Le sage '''Thalès''', pressé par sa mère de se marier, lui répondit avec beaucoup d’adresse. Au commencement, il lui dit : Ma mère, il n’est pas encore temps. Quand il eut passé la fleur de son âge, et qu’elle lui fit de nouvelles instances, il lui répondit : Il n’est plus temps. De même, par rapport à la question proposée, le mieux serait que chacun pût se dire le soir en se couchant : Il n’est pas encore temps ; et le matin, quand il se lève : Il n’est plus temps. »</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome III, [https://remacle.org/bloodwolf/historiens/Plutarque/sympos3.htm#VI Προβλημα Ϛ. Περὶ καιροῦ συνουσίας. - Question VI. Quel est le temps le plus propre à l’amour?]'', traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto; color: #3366BB">― ✳ ―</div> ==== De la malignité d’[[w:Hérodote|'''Hérodote''']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Chapitre_XX|<sup>🔄</sup>]] ==== <div style="text-align: center; margin: 0 1em;">Ouvrage critique contre l’impartialité d’'''Hérodote''', ses contre-vérités face à la dévaluation des héros et peuples ''grecs''. Le ton critique surprend de la part de '''Plutarque''' au point que l’on contesta l’authenticité du traité, sans succès.</div> ===== Paragraphe XV ===== <div style="text-align: center; margin: 0 1em;">Remise en question de l’origine phénicienne de '''Thalès''' donnée par '''Hérodote'''.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid;"><br /><div style="text-align: justify; margin: 0 2em; text-indent: 15px">Καὶ μὴν τῶν ἑπτὰ σοφῶν, οὓς αὐτὸς σοφιστὰς προσεῖπε, τὸν μὲν '''Θάλητα''' Φοίνικα τῷ γένει τὸ ἀνέκαθεν ἀποφαίνεται βάρβαρον·</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome IV, [https://remacle.org/bloodwolf/historiens/Plutarque/malignhero.htm Περι της Ηροδοτου κακοηθειας]'' traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§15. Quand il parle des sept sages, il les appelle des ''sophistes''. Il prétend démontrer que '''Thalès''' est d’origine ''phénicienne''[[#phénicienne_NdT_DR|<span id="phénicienne_NdT_DR_back"><sup>1</sup></span>]], et qu’à remonter en arrière ce personnage appartient aux Barbares.</div> <table cellspacing=15 style="margin: 0 4em; font-size:85%;"> <tr> <td valign=top style="text-align: justify; text-indent: 15px">'''[[#phénicienne_NdT_DR_back|<span id="phénicienne_NdT_DR"><sup>1</sup></span>]] I, 170.''' </td> </tr> </table> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome III, [[s:Page:Plutarque_-_Œuvres_complètes_de_Plutarque_-_Œuvres_morales_et_œuvres_diverses,_tome_3,_1870.djvu/773|De la malignité d’Hérodote]], [[s:Page:Plutarque_-_Œuvres_complètes_de_Plutarque_-_Œuvres_morales_et_œuvres_diverses,_tome_3,_1870.djvu/782|§15]]'', traduites par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">Entre les sept sages qu’il appelle ''sophistes'', il enlève '''Thalès''' à la ''Grèce'' pour le donner aux Barbares, en le faisant descendre d’une famille ''phénicienne''.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome IV, [https://remacle.org/bloodwolf/historiens/Plutarque/malignhero.htm De la malignité d’Hérodote]'' traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto; color: #3366BB">― ✳ ―</div> ==== Les opinions des Philosophes ==== <div style="text-align: center; margin: 0 1em;">Ouvrage [[w:doxographe|'''doxographe''']], à la manière de [[w:Diogène Laërce|'''Diogène Laërce''']] [[#Diogène_Laërce_back|<sup>⤵️</sup>]] et [[w:Alcinoos_(philosophe)|'''Alcinoos''']] [[#Alcinoos|<span id="Alcinoos_back"><sup>'''I'''</sup></span>]], qui cite un nombre important de [[w:présocratiques|''présocratiques'']].</div> {{Boîte déroulante début|titre=NdA Les opinions des Philosophes|fondtitre=#ffffff|alignT=right|styleTitre=color:#3366BB;|styleFrame=border-color:white}} <div style="text-align: justify; border: 2px solid #3366BB; text-indent: 15px; border-radius:15px; font-size:85%;"> <p style="margin: 0 2em; text-indent: 15px;"><br/>'''[[#Alcinoos_back|<span id="Alcinoos"><sup>I</sup></span>]] Du grec ancien Ἀλκίνοος / Alkínoos [[wikt:en:Ἀλκίνοος#Ancient_Greek|(en)]] ; <br /><p style="margin: 0 2em; text-indent: 15px;">➥ du nom commun ἀλκή / alkḗ [[wikt:en:ἀλκή#Ancient_Greek|(en)]], « 1. Prouesse; force. 2. Défense; garde. 3. Bataille; combat. » ;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ +‎ du nom commun νόος / nóos [[wikt:en:νόος#Ancient_Greek|(en)]], « 1. Esprit : • Perception, sens ; • L’esprit en tant que siège des sentiments, le cœur, l’âme ; • L’esprit en tant que faculté de décision et d’intention, la volonté. 2. Un acte de l’esprit : • Pensée ; • Intention, dessein. 3. Le sens ou la signification d’un mot. 4. (philosophie) Intelligence, intellect, raison. 5. (métaphysique) Le principe agissant sur les particules élémentaires de la matière (tel que décrit par [[w:Anaxagore|Anaxagore]] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#Anaxagore_back|<sup>🔄</sup>]]) » ;<br /><p style="margin: 0 2em; text-indent: 15px;">Philosophe de l’époque [[w:Moyen-platonisme|''médio-platonicienne'']] [[#moyen-platonisme|<span id="moyen-platonisme_back"><sup>II</sup></span>]], auteur du Διδασκαλικὸς τῶν Πλάτωνος δογμάτων / Didaskalikòs tō̃n Plátōnos dogmátōn, « Enseignement des doctrines de Platon » [[#Didaskalikos|<span id="Didaskalikos_back"><sup>III</sup></span>]].<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:IIe_siècle|II<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]])<br /><br /><p style="margin: 0 2em; text-indent: 15px;">[[#moyen-platonisme_back|<span id="moyen-platonisme"><sup>II</sup></span>]] Le ''moyen-platonisme'' ou ''médio-platonisme'' est un courant philosophique regroupant des penseurs qui se réclament de Platon, depuis le [[w:Ier_siècle_av._J.-C.|I<sup>er</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]] jusqu'au [[w:IIe_siècle|II<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]].<br /><br /><p style="margin: 0 2em; text-indent: 15px;">[[#Didaskalikos_back|<span id="Didaskalikos"><sup>III</sup></span>]] Le ''Didaskalikos'' se rattache étroitement à la branche du ''moyen-platonisme'' qui interprétait Platon à la lumière surtout d’Aristote. On constate en plus une certaine influence du ''stoïcisme'', en particulier l’emprunt d’un extrait conséquent au ''stoïcien'' Arius Didyme [[#Arius_Didyme|<span id="Arius_Didyme_back"><sup>'''IV'''</sup></span>]]. Souvent pourtant les doctrines du ''stoïcisme'' sont combattues, avant tout, mais pas exclusivement, en ce qui concerne la morale : il est donc impossible que l’auteur du ''Didaskalikos'' fût ''stoïcien orthodoxe'', dont la persistance au [[w:IIe_siècle|II<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]] est sujet à débat. Pour autant, l’auteur veut maintenir une certaine réserve à l’égard des doctrines dont il fait l’exposé : d’où l’emploi de la troisième personne à propos des ''platoniciens''. Enfin, il ne se comptait pas non plus parmi les grands du ''moyen-platonisme''.<br /><p style="margin: 0 2em; text-indent: 15px;">Le Didaskalikos ne peut donc pas être antérieur à Arius Didyme, contemporain de l’empereur Auguste. Il est impossible d’établir un [[wikt:terminus_ad_quem|''terminus ante quem'']] précis. L’ouvrage présente en effet des coïncidences frappantes avec une gamme d’auteurs s’échelonnant de Philon d’Alexandrie jusqu’à Plotin. Depuis fin [[w:XIXe_siècle|XIX<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]], l’habitude a été prise de dater le ''Didaskalikos'' des environs de l’an [[w:150|150]] EC ; et même si cela semble raisonnable, il y a d’autres possibilités à prendre en considération, en l’absence de tout renseignement biographique.<br /><br /><p style="margin: 0 2em; text-indent: 15px;">[[#Arius_Didyme_back|<span id="Arius_Didyme"><sup>IV</sup></span>]] Du nom propre grec ancien Ἄρειος Δίδυμος / Areios Didymos ;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ du nom propre [[w:Nom_théophore|''théophore'']] [[Philosophie/Thalès_de_Milet/Textes_et_traductions_Ier_millénaire_AEC#théophore_back|<sup>🔄</sup>]] Ἄρειος / Áreios [[wikt:en:Ἄρειος#Ancient_Greek|(en)]], « Relatif à Ares »; <br /><p style="margin: 0 2em; text-indent: 30px;">➥ du nom propre Ἄρης / Árēs [[wikt:Ἄρης#Ancient_Greek|(en)]], « 1. (mythologie grecque) La divinité Arès. 2. (par transfert) La planète Mars. 3. (par antonomase) Rencontre ou situation hostile entre groupes de personnes : bataille, affrontement, combat, escarmouche, guerre. 4. (par antonomase) Événements ou conséquences liés aux hostilités : boucherie, carnage, embrasement, massacre, tuerie. 5. (par antonomase, avec synecdoque comme substantif désignant une qualité) Esprit guerrier ou esprit combatif. 6. Épithète de Zeus, « le vengeur » »;<br /><p style="margin: 0 2em; text-indent: 30px;">➥ +‎ du suffixe adjectival -ιος / -ios [[wikt:en:-ιος#Ancient_Greek|(en)]], « Relatif à, appartenant à : "de" » ;<br /><p style="margin: 0 2em; text-indent: 15px;">➥ de l’adjectif δῐ́δῠμος / dĭ́dŭmos [[wikt:en:δίδυμος#Ancient_Greek|(en)]], « 1. Double. 2. Jumeaux. » ;<br /><p style="margin: 0 2em; text-indent: 30px;">➥ [[wikt:en:réduplication|''Réduplication'']] de δύο / dúo [[wikt:en:δύο#Ancient_Greek|(en)]], « deux » ; <br /><p style="margin: 0 2em; text-indent: 30px;">➥ + du suffixe -μος / -mos [[wikt:en:-μος#Ancient_Greek|(en)]] ; forme alternative du suffixe adjectival -ιμος / -imos [[wikt:en:-ιμος#Ancient_Greek|(en)]] de possibilité ou de capacité, « -able » ;<br /><p style="margin: 0 2em; text-indent: 15px;">Philosophe ''alexandrin'' et doxographe de tendance éclectique, il est ami et conseiller d’Auguste, au moins de [[w:-30|-30]] (date fondée sur des références à Auguste et à Arius dans le contexte de la prise d’Alexandrie, épargnée par Auguste - entre autres raisons – grâce à Arius) à [[w:9|9]]. Bien que nous ne connaissions pas de façon certaine l’école à laquelle il se rattachait, il était probablement ''stoïcien'' : il manifeste des affinités avec la ''philosophie académicienne'' telle qu’elle est présentée par Antiochus d’''Ascalon'', de la sympathie pour l’''académicien'' Eudore, une grande précision dans le traitement du matériel ''stoïcien'' et une ouverture à la pensée ''péripatéticienne''.<br /><p style="text-align: right; margin: 0 2em;">([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l’on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:Ier_siècle_av._J.-C.|I<sup>er</sup> siècle {{Info|AEC|Avant l’Ère Commune}}]]) [https://books.google.fr/books?id=crnWAAAAMAAJ&newbks=1&newbks_redir=0&lpg=PA3&dq=Richard%20Goulet%20dictionnaire%20des%20auteurs%20antiques&hl=fr&pg=PA345#v=onepage&q&f=false {{Info|<sup>🔍</sup>|Dictionnaire des Philosophes Antiques, publié sous la direction de Richard Goulet, Volume I, §324 - Areios Didymos}}]'''<br/><br/></div> {{Boîte déroulante fin}} ===== <div style="text-align: center;">Livre I</div> ===== <div style="text-align: center; margin: 0 1em;"></div> <div style="text-align: center; margin: 0 auto;">― ● ―</div> ===== <div style="text-align: center;">Livre II</div> ===== <div style="text-align: center; margin: 0 1em;"></div> <div style="text-align: center; margin: 0 auto;">― ● ―</div> ===== <div style="text-align: center;">Livre III</div> ===== <div style="text-align: center; margin: 0 1em;"></div> <div style="text-align: center; margin: 0 auto;">― ● ―</div> ===== <div style="text-align: center;">Livre IV</div> ===== <div style="text-align: center; margin: 0 1em;"></div> <div style="text-align: center; margin: 0 auto; color: #3366BB">― ✳ ―</div> ==== Les animaux de terre ont-ils plus d'adresse que ceux de mer? ==== <div style="text-align: center; margin: 0 1em;"></div> <div style="text-align: center; margin: 0 auto; color: #3366BB">― ✳ ―</div> ==== D’'''Isis''' et d’'''Osiris'''==== <div style="text-align: center; margin: 0 1em;">[[w:Diatribe|Diatribe]] ''[[w:Isis|Isiaque]]'', avec une interprétation ''platonique'' pour intéresser '''Cléa''', admiratrice du mystère d’'''Isis''' à la [[w:Religion_%C3%A9gyptienne|religion ''égyptienne'']]. C’est un plaidoyer, exégèse, avec '''[[w:Osiris|Osiris]]''' qui évoque '''[[w:Dionysos|Dionysos]]''' et '''[[w:Hadès|Hadès]]''', ainsi que des notions de ''[[w:démonologie|démonologie]]'', ''[[w:Dualisme (philosophie)|dualisme]]'' et ''[[w:didactique|didactique]]''. Il contient le premier récit suivi et cohérent du [[w:Mythe_d'Osiris|mythe d’'''Osiris''']]. L’une de ses sources est probablement '''[[w:Hérodote|Hérodote]]'''. mais on croit qu’il s’est rendu lui-même à ''Alexandrie'' pour suivre des cours de médecine.</div> ===== <div style="text-align: center;">Paragraphe IX.</div> ===== <div style="text-align: center; margin: 0 1em;">Témoignage d’un voyage de '''Thalès''' en ''Égypte'', de rencontres avec des prêtres et de récit sur leur divinités.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid;"><br /><div style="text-align: justify; margin: 0 2em; text-indent: 15px">§9. [...] '''Ἑκαταῖος''' δ´ ὁ ''Ἀβδηρίτης'' φησὶ τούτῳ καὶ πρὸς ἀλλήλους τῷ ῥήματι χρῆσθαι τοὺς ''Αἰγυπτίους'', ὅταν τινὰ προσκαλῶνται· προσκλητικὴν γὰρ εἶναι τὴν φωνήν. Διὸ τὸν πρῶτον θεόν, ὃν τῷ παντὶ τὸν αὐτὸν νομίζουσιν, ὡς ἀφανῆ καὶ κεκρυμμένον ὄντα προσκαλούμενοι καὶ παρακαλοῦντες ἐμφανῆ γενέσθαι καὶ δῆλον αὐτοῖς ''Ἀμοῦν'' λέγουσιν.<br /><p style="text-indent: 15px">§10. Ἡ μὲν οὖν εὐλάβεια τῆς περὶ τὰ θεῖα σοφίας '''Αἰγυπτίων''' τοσαύτη {ἦν}, μαρτυροῦσι δὲ καὶ τῶν ''Ἑλλήνων'' οἱ σοφώτατοι, '''Σόλων''' '''Θαλῆς''' '''Πλάτων''' '''Εὔδοξος''' '''Πυθαγόρας''', ὡς δ´ ἔνιοί φασι, καὶ '''Λυκοῦργος''' εἰς ''Αἴγυπτον'' ἀφικόμενοι καὶ συγγενόμενοι τοῖς ἱερεῦσιν.[...]</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome V, [https://remacle.org/bloodwolf/historiens/Plutarque/isisetosiris.htm Περι Ισιδος και Οσιριδος - Traité d’Isis et d’Osiris], §34'', traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1870<br />(également disponible une édition de 1844 [https://remacle.org/bloodwolf/historiens/Plutarque/isisetosiris1.htm ici])</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§9. [...] '''Hécatée''' d’''Abdère'' dit que les ''Égyptiens'' emploient ce mot pour s’appeler les uns les autres, attendu qu’il est essentiellement appellatif. C’est pourquoi, s’adressant au premier Dieu, le même, selon eux, que l’Univers, comme à un être invisible et caché, ils l’exhortent avec supplications, en l’appelant "Amoun", à se faire voir et à se découvrir à eux. Voilà jusqu’à quel point était grande la réserve qui caractérisait la philosophie religieuse des ''Égyptiens''.<br /><p style="text-indent: 15px">§10. C’est ce que témoignent les plus éclairés d’entre les ''Grecs'': '''Solon''', '''Thalès''', '''Platon''', '''Eudoxe''', '''Pythagore''', et aussi, d’après quelques-uns, '''Lycurgue'''. Ils étaient allés en ''Égypte'' et avaient eu des conférences avec les prêtres. [...]</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome V, [https://remacle.org/bloodwolf/historiens/Plutarque/isisetosiris.htm Περι Ισιδος και Οσιριδος - Traité d’Isis et d’Osiris], §§9, 10'', traduites par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870<br/>(également disponible [[s:Sur_Isis_et_Osiris|ici]])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">§9. [...] '''Hécatée''' d’''Abdère'' dit que les ''Egyptiens'' s’en servent pour s’appeler les uns les autres; que ce nom est de sa nature appellatif ; que ce peuple , qui croit que le premier des dieux, qu’il confond avec l’univers, est un dieu caché et inconnu, l’invoque et le prie de se découvrir à eux, en lui disant ''Amoun'' ;<br /><p style="text-indent: 15px">§10. tant ce peuple portait de retenue et de réserve dans sa philosophie religieuse ! C’est ce qu'attestent unanimement les plus sages d’entre les ''Grecs'', '''Solon''', '''Thalès''', '''Platon''', '''Eudoxe''', '''Pythagore''', et, suivant quelques uns, '''Lycurgue''' lui-même, qui tous voyagèrent en ''Egypte'', et y conférèrent avec les prêtres du pays.[...]</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome V, [https://remacle.org/bloodwolf/historiens/Plutarque/isisetosiris1.htm Περι Ισιδος και Οσιριδος - Traité d’Isis et d’Osiris], §§9, 10'', traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto;">― • ―</div> ===== <div style="text-align: center;">Paragraphe XXXIV.</div> ===== <div style="text-align: justify; text-indent: 15px; margin: 0 1em;">Témoignage de la théorie de '''Thalès''' de l’eau principe de tous les êtres.</div> :'''Texte grec''' <div style="text-align: justify; margin-top: 2em; overflow: auto; height: 270px; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§34. Ἥλιον δὲ καὶ Σελήνην οὐχ ἅρμασιν ἀλλὰ πλοίοις ὀχήμασι χρωμένους περιπολεῖν φασιν αἰνιττόμενοι τὴν ἀφ´ ὑγροῦ τροφὴν αὐτῶν καὶ γένεσιν. Οἴονται δὲ καὶ '''Ὅμηρον''' ὥσπερ '''Θαλῆν''' μαθόντα παρ´ ''Αἰγυπτίων'' ὕδωρ ἀρχὴν ἁπάντων καὶ γένεσιν τίθεσθαι· τὸν γὰρ '''Ὠκεανὸν''' '''Ὄσιριν''' εἶναι, τὴν δὲ '''Τηθὺν''' '''Ἶσιν''' ὡς τιθηνουμένην πάντα καὶ συνεκτρέφουσαν. [...]</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome V, [https://remacle.org/bloodwolf/historiens/Plutarque/isisetosiris.htm Περι Ισιδος και Οσιριδος - Traité d’Isis et d’Osiris], §34'', traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1870<br />(également disponible une édition de 1844 [https://remacle.org/bloodwolf/historiens/Plutarque/isisetosiris1.htm ici])</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> :'''Traductions''' <div style="text-align: justify; margin-top: 2em; height: 520px; overflow: auto; border: 2px solid; text-indent: 15px"><br /><div style="text-align: justify; margin: 0 2em;">§34. Ils disent que le soleil et la lune parcourent leur route perpétuelle non pas sur des chars, mais sur des bâtiments de navigation: signifiant par là, que c’est le principe humide qui les entretient et qui leur a donné naissance. Ils croient aussi que c’est des ''Egyptiens'' qu’'''Homère''', et après lui '''Thalès''', ont appris à établir l’eau comme principe générateur de tous les êtres. Ils veulent qu’'''Osiris''' soit l’'''Océan''', qu’'''Isis''' soit '''Téthys''', laquelle nourrit et entretient tout ce qui existe.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome V, [https://remacle.org/bloodwolf/historiens/Plutarque/isisetosiris1.htm Περι Ισιδος και Οσιριδος - Traité d’Isis et d’Osiris], §34'', traduites par [[w:Victor_Bétolaud|Victor Bétolaud]], 1870<br/>(également disponible [[s:Sur_Isis_et_Osiris|ici]])</div> <div class="center" style="border-bottom: 1px solid #444; width: 30%; margin: 0 auto;"></div> <div style="text-indent: 15px; text-align: justify; margin: 0 2em;">§34. Ils disent que le soleil et la lune parcourent les cieux, portés, non sur des chars, mais sur des vaisseaux, pour signifier que tout est nourri et mis en mouvement par l’eau. Ils pensent que c’est des ''Egyptiens'' qu’'''Homère''' et '''Thalès''' avaient pris cette opinion, que l’eau est le principe de tous les êtres, qu’'''Osiris''' est l’'''Océan''', et qu’'''Isis''' est '''Thétis''', qui nourrit et alimente toutes les substances.</div> <div style="text-align: right; margin: 0 2em 0 1em;"><u>Œuvres complètes de Plutarque, Œuvres Morales</u>, ''Tome V, [https://remacle.org/bloodwolf/historiens/Plutarque/isisetosiris1.htm Περι Ισιδος και Οσιριδος - Traité d’Isis et d’Osiris], §34'', traduites par [[w:Dominique_Ricard|Dominique Ricard]], 1844</div> <div class="center" style="border-bottom: 1px solid #FFF; width: 30%; margin: 0 auto;"></div></div> <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Valère_Maxime|'''Valère Maxime''']] ''([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l'on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:Ier_siècle|I<sup>er</sup> siècle {{Info|EC|de l’Ère Commune}}]])'' [[s:Auteur:Valère_Maxime|<sup>📚</sup>]] == === Actions et paroles mémorables, VII, § 2 === :8. Il y a aussi un mot admirable de Thalès. On lui demandait si les actions des hommes échappaient à la connaissance des dieux. "Leurs pensées non plus", répondit-il. Aussi faut-il nous appliquer à avoir, je ne dis pas seulement les mains, mais encore le cœur pur, dans la persuasion que la divinité est témoin des mouvements les plus secrets de nos âmes. <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Tatien_le_Syrien|'''Tatien''']] le [[w:Assyrie_(province_romaine)|''Syrien'']] ''(vers [[w:120|120]], en [[w:Halicarnasse|''Halicarnasse'']] en [[w:Assyrie_(province_romaine)|Assyrie]] — vers [[w:173|173]], en Assyrie)'' <sup>[[w:IIe_siècle|⏳]]</sup> [[s:Auteur:Tatien_le_Syrien|<sup>📚</sup>]] == === Discours aux Grecs, 41 === == [[w:Lucien_de_Samosate|'''Lucien de Samosate''']] ''(vers [[w:120|120]], à [[w:Samosate|Samosate]] — vers [[w:180|180]], en [[w:Égypte_romaine_et_byzantine|Égypte]])'' <sup>[[w:IIe_siècle|⏳]]</sup> [[s:Auteur:Lucien_de_Samosate|<sup>📚</sup>]] == === Dialogues des morts === https://gallica.bnf.fr/ark:/12148/bpt6k6227866x/f7.item https://gallica.bnf.fr/ark:/12148/bpt6k6227866x/f103.double === Hippias ou le bain === :(2) Mon but est de prouver que les constructeurs de machines qui méritent le plus notre admiration sont ceux qui, distingués par leur science théorique, ont laissé en outre à la postérité des monuments de leur art et des œuvres de leur génie, tandis que les hommes, qui se sont seulement exercés dans la parole méritent plutôt le nom de sophistes que celui de savants. C'est sur la liste traditionnelle de ces artistes que nous voyons figurer Archimède et Socrate de Cnide, qui inventèrent, l'un les moyens de soumettre à Ptolémée la ville de Memphis, sans recourir à un siège, mais en détournant et en divisant le cours du Nil ; l'autre, ceux d'incendier les galères des ennemis. Avant eux, Thalès de Milet, ayant promis à Crésus de faire passer à pied sec à son armée les eaux du fleuve Halys, imagina de les détourner en une seule nuit derrière le camp ; et pourtant ce n'était pas un mécanicien de profession, mais un sage d'un esprit inventif et à l'intelligence duquel on pouvait s'en rapporter. === Exemples de longévité === :(18) Solon, Thalès et Pittacus, que l'on compte au nombre des Sept sages, vécurent chacun cent années. <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Athénée_de_Naucratis|'''Athénée''' de ''Naucratis'']] == [[w:https://remacle.org/bloodwolf/erudits/athenee/livre11.htm|''Le Livre XI des Deipnosophistes'']] [781d] « Alcmène reçoit le vase d'or, et le contemple aussitôt avec admiration. » Stésichore dit qu'Hercule traverse l'Océan dans son vase à boire (poteerioo) ; qu'il s'en servit même pour le franchir et aller enlever les bœufs de Géryon. Nous connaissons aussi par l'histoire le vase à boire (poteerion) de l'arcadien Bathyclès, qui le laissa pour présent à celui qui fut appelé le sage par excellence entre les Sept de la Grèce; mais nombre de potiers de terre font le vase de Nestor, car plusieurs écrivains en ont donné des détails. <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Clément_d%27Alexandrie|'''Clément''']] d'[[w:Histoire_d%27Alexandrie#Annexion|''Alexandrie'']] ''(vers [[w:150|150]]'' <sup>[[w:IIe_siècle|⏳]]</sup>'', à [[w:Athènes#Antiquité|Athènes]] — vers [[w:215|215]]'' <sup>[[w:IIIe_siècle|⏳]]</sup>'', à [[w:Kayseri|Kayseri]])'' [[s:Auteur:Clément_d’Alexandrie|<sup>📚</sup>]] == === Stromates, I, 65 === <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Claude_Élien|'''Claude Élien''']] ''(vers [[w:175|175]]''<sup>[[w:IIe_siècle|⏳]]</sup>'', à [[w:Préneste|Préneste]] — vers [[w:235|235]]''<sup>[[w:IIIe_siècle|⏳]]</sup>'', en [[w:Rome_antique|Rome]])'' [[s:Auteur:Élien_le_sophiste|<sup>📚</sup>]] == === Histoires diverses === :On a vu des philosophes à la tête des affaires publiques : d'autres, se bornant à cultiver leur raison, ont passé leur vie dans le repos. Entre les premiers sont Zaleucus et Charondas qui réformèrent, l'un, le gouvernement des Locriens, l'autre, d'abord celui des Catanéens, puis, après qu'il eut été exilé de Catane, celui des Rhéginiens. Archytas servit utilement les Tarentins. Les Athéniens durent tout à Solon. Bias et Thalès rendirent les mêmes services à l'Ionie, Chilon à Lacédémone, Pittacus à Mitylène, Cléobule à Rhodes. <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Sextus_Empiricus|'''Sextus Empiricus''']] ''([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l'on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:IIe_siècle|II<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]])'' [[s:Auteur:Sextus_Empiricus|<sup>📚</sup>]] == Hypot III, 30, et Liv I contre les phys., sect. 319 https://gallica.bnf.fr/ark:/12148/bpt6k9796311p/f305.item.r=thales <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Lactance|'''Lactance''']] ''(vers [[w:250|250]]''<sup>[[w:IIIe_siècle|⏳]]</sup>'', à [[w:Henchir_Kssiba#Histoire|Civitas Popthensis]] — vers [[w:325|325]]''<sup>[[w:IVe_siècle|⏳]]</sup>'', en [[w:Gaule#La_Gaule_dans_l'Antiquité_tardive|Gaule]])'' == Épit. 4 (https://gallica.bnf.fr/ark:/12148/bpt6k282068z/f300.image.r=thales) Inst. 111, 16 (https://gallica.bnf.fr/ark:/12148/bpt6k282068z/f621.item.r=thales) <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Jamblique|'''Jamblique''']] ''(vers [[w:250|250]]''<sup>[[w:IIIe_siècle|⏳]]</sup>'', à [[w:Qinnasrīn|Chalcis ad Belum]] — vers [[w:333|333]]''<sup>[[w:IVe_siècle|⏳]]</sup>'')'' == === Vie de Pythagore === ==== chap. II ==== (https://web.archive.org/web/20110721184914/http://www.aurumsolis.info/index.php?option=com_phocadownload&view=category&download=1%3Aiamblichus-the-pythagorean-life&id=19%3Awritings-from-the-founders&Itemid=143&lang=en) <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Eusèbe_de_Césarée|'''Eusèbe''']] de [[w:Césarée#Césarée_au_début_du_christianisme|''Césarée'']] ''(vers [[w:265|265]]'' <sup>[[w:IIIe_siècle|⏳]]</sup>'', à Césarée — [[w:340|340]]'' <sup>[[w:IVe_siècle|⏳]]</sup>'', à Césarée)'' [[s:Auteur:Eusèbe_de_Césarée|<sup>📚</sup>]] == Preparation Évangélique, XI, 2 Prepar. évang. I, 8, page 22-25 https://gallica.bnf.fr/ark:/12148/bpt6k9796311p/f310.image.r=thales <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Diogène_Laërce|'''Diogène Laërce''']] ''([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l'on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] [[w:IIIe_siècle|III<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]])'' [[s:Auteur:Diogène_Laërce|<sup>📚</sup>]] == ''Ce texte est un extrait de la traduction de Robert Genaille (1933)'' Thalès[1], au dire d’Hérodote, de Douris et de Démocrite, était fils d’Examios et de Cléobuline, et membre de la famille des Thélides, Phéniciens descendant en droite ligne d’Agénor[2] et de Cadmus[3], s’il faut en croire Platon. Le premier, il porta le nom de sage, au temps où Damasias était archonte à Athènes[4]. C’est sous le même archontat que fut créée l’expression : « les sept sages » (cf. Démocrite de Phalère, Registre des Archontes). Thalès fut inscrit comme citoyen de Milet quand il vint dans cette ville avec Nélée chassé de Phénicie. Une autre tradition très courante veut qu’il soit natif de Milet et qu’il descende d’une bonne famille. Il s’occupa de politique avant d’étudier la nature. On croit qu’il ne laissa aucun écrit, car l’Astrologie nautique qu’on lui attribue est de Phocos de Samos. Callimaque[5] croit qu’il découvrit la Petite Ourse et le raconte en vers iambiques : Il mesura, dit-on, les étoiles du Chariot Sur quoi les Phéniciens règlent leur navigation. D’autres auteurs disent qu’il écrivit seulement deux ouvrages, un sur le solstice et un sur l’équinoxe, car il pensait le reste inaccessible. Il passe pour avoir le premier étudié l’astrologie et prédit les éclipses de soleil et les solstices (cf. Eudème, Histoire de l’astrologie)[6]. Xénophane et Hérodote le louent à ce propos, et leur témoignage est confirmé par celui d’Héraclite et de Démocrite. On dit encore (cf. le poète Choirilos) qu’il fut le premier à affirmer l’immortalité des âmes. Le premier il dessina la course du soleil d’un solstice à l’autre, et démontra que comparée au soleil, la lune en est la cent vingtième partie. C’est encore lui qui fixa à trente jours la durée du mois, et qui écrivit le premier traité sur la Nature. Aristote et Hippias disent aussi qu’il accordait une âme aux choses qu’on croit inanimées ; il en donnait pour preuve l’ambre et la pierre de Magnésie. Selon Pamphile[7], il apprit des Égyptiens la géométrie, inscrivit dans un cercle le triangle rectangle, et pour cette découverte immola un bœuf. D’autres, comme Apollodore le calculateur, attribuent cette invention à Pythagore. Thalès a encore développé et précisé l’invention du Phrygien Euphorbe citée par Callimaque dans ses Iambes et concernant le triangle scalène, et tout ce qui touche aux considérations sur les lignes. Il semble encore avoir été en politique un homme de bon conseil. Ainsi, quand Crésus[8] envoya une ambassade aux Milésiens pour demander leur alliance, il s’y opposa, et son intervention sauva la ville, puisque Cyrus l’emporta. Héraclite cite une opinion de Clytos selon laquelle Thalès aurait eu une vie retirée et solitaire. Les uns disent qu’il se maria et eut un fils nommé Kibissos. D’autres prétendent qu’il resta célibataire et adopta le fils de sa sœur, qu’on lui demanda un jour pourquoi il ne cherchait pas à avoir des enfants, et qu’il répondit : « Par amour pour les enfants. » Sa mère l’exhortait à se marier, il lui répondit : « Non, par Zeus, il n’est pas encore temps. » Elle l’y invita une nouvelle fois quand il eut pris de l’âge, mais il lui dit : « Il n’est plus temps. » D’après Hiéronyme de Rhodes (Notes, livre II), il voulut montrer combien il était facile de s’enrichir ayant prévu pour l’année une abondante récolte d’huile, il prit à loyer une oliveraie et gagna beaucoup d’argent[9]. Il soupçonna que l’eau était le principe des choses, que le monde était animé et rempli de démons. On dit qu’il découvrit les saisons de l’année, et qu’il la divisa en trois cent soixante-cinq jours. Il ne suivit les leçons d’aucun maître, sauf en Égypte, où il fréquenta les prêtres du pays. A ce propos, Hiéronyme dit qu’il mesura les Pyramides en calculant le rapport entre leur ombre et celle de notre corps. Si l’on en croit Minuès, il vivait au temps de Thrasybule, qui fut tyran de Milet[10]. L’histoire du trépied trouvé par des pêcheurs et dédié aux sages par le peuple de Milet est bien connue. Des jeunes gens d’Ionie achetèrent à des pêcheurs milésiens leur coup de filet. Ils tirèrent de l’eau un trépied. On se querella et les Milésiens envoyèrent une ambassade à Delphes. Voici quel fut l’oracle de la divinité : Race de Milet, tu interroges Phébus au sujet d’un trépied ? Au plus sage de tous, je donne ce trépied[11]. Ils le donnent alors à Thalès, qui le donne à un autre, et cet autre à un autre, et ainsi de suite jusqu’à Solon, qui, déclarant que seul le dieu était le plus sage de tous, rendit le trépied à Delphes. Callimaque, dans ses Iambes, rapporte cette histoire autrement ; il la tient de Léandre de Milet. Il dit qu’un certain Bathyclès d’Arcadie laissa en mourant une coupe pour qu’elle fût donnée à l’homme le plus sage. Elle fut donc donnée à Thalès, et après être passée de main en main et avoir fait le tour des sages, elle revint à Thalès. Celui-ci en fit don alors à Apollon de Didyme, en ces termes selon le poème de Callimaque : Thalès me donne au protecteur du peuple du Nil, Thalès qui a reçu deux fois ce présent, ce qui, en prose, se dit ainsi : « Thalès de Milet, fils d’Examios, à Apollon delphien, ce présent qu’il a reçu deux fois des Grecs. » Celui qui portait la coupe de sage en sage, le fils de Bathyclès, s’appelait Thyrion (cf. Éleusis, Livre sur Achille, et Alexon de Mynde, Fables, livre IX). Eudoxe de Cnide et Évanthès de Milet disent de leur côté qu’un ami de Crésus reçut du roi un vase d’or, pour le donner au plus sage des Grecs, qu’il le donna à Thalès et que ce vase parvint jusqu’à Chilon. Celui-ci consulta la Pythie, pour savoir qui était plus sage que lui. Elle répondit que c’était Myson (je parlerai de lui : Eudoxe le met parmi les sages à la place de Cléobule et Platon à la place de Périandre.) Voici la réponse que lui fit la Pythie : Il y a un habitant de l’Oeta, Myson, né à Chénée, Qui plus que toi est riche de sages pensées. L’homme qui consulta l’oracle pour Chilon s’appelait Anacharsis. Dédale le Platonicien et Cléarque disent que la coupe fut envoyée par Crésus à Pittacos, et que c’est ainsi qu’elle passa de main en main. D’après Andron, d’autre part (Livre du trépied), les Argiens décidèrent que le trépied serait attribué comme prix de vertu au plus sage des Grecs. Aristodème de Sparte fut choisi et c’est lui qui donna le trépied à Chilon. Alcée est aussi partisan d’Aristodème dont il parle dans les vers suivants : :Comme jadis Aristodème, dit-on, :Prononça à Sparte cette parole bien juste : :C’est de l’argent, un homme, oui de l’argent, :Car l’homme vertueux n’est jamais pauvre. D’autres disent encore que Périandre envoya à Thrasybule, tyran de Milet, un navire chargé, que ce navire fit naufrage dans la mer de Cos, et que quelque temps après le trépied fut trouvé par des pêcheurs. Phanodicos dit que le trépied fut trouvé dans la mer Attique, porté à la ville, et que l’assemblée du peuple s’étant réunie le fit porter à Bias. Pourquoi cela, je le dirai quand je parlerai de Bias. Selon d’autres auteurs, le trépied avait été fabriqué par Héphaïstos et donné en présent de la part de ce dieu à Pélops lors de son mariage. Il vint ensuite à Ménélas, fut enlevé avec Hélène par Alexandre, jeté dans la mer de Cos à l’instigation de la Spartiate qui prévoyait qu’il serait un sujet de querelle. Plus tard, en ce lieu, des Lébédiens achetèrent le produit d’un coup de filet et c’est le trépied qui fut tiré de l’eau. Il y eut querelle avec les pêcheurs, on vint jusqu’à Cos, et comme on ne s’accordait pas, on s’adressa à Milet, qui était la capitale. Les Milésiens envoyèrent des députés qui ne furent pas écoutés, aussi firent-ils la guerre aux gens de Cos. Comme de chaque côté il mourait beaucoup de gens, l’oracle déclara qu’il fallait donner le trépied au plus sage. Les deux camps s’entendirent alors pour l’attribuer à Thalès, qui par la suite le consacra à Apollon de Didyme. Pour en revenir à la réponse de l’oracle aux gens de Cos, elle disait ceci : La querelle entre Ioniens et Méropes ne cessera pas Avant que le trépied d’or qu’Héphaïstos jeta dans la mer N’ait quitté votre ville pour la maison de l’homme Qui connaît le présent, l’avenir et le passé. La réponse aux Milésiens fut la suivante : Race de Milet, tu interroges Phoebus au sujet d’un trépied... comme il a été dit plus haut. En voilà assez sur ce sujet[12]. Hermippe, dans ses Vies, rapporte à Thalès ce qui est dit par d’autres de Socrate : il aimait à dire qu’il remerciait la fortune de trois choses : d’être un humain et non une bête, d’être un homme et non une femme, enfin d’être un Grec, et non un barbare. On raconte encore qu’étant sorti de chez lui pour contempler les astres, il tomba dans un puits[13]. Une vieille femme survenant se moqua de lui en ces mots : « Comment, Thalès, toi qui n’es pas capable de voir ce qui est à tes pieds, t’imagines-tu pouvoir connaître ce qui est dans le ciel ? » Timon[14] a bien connu aussi la science de Thalès en astronomie, et dans ses Silles, il le loue en ces termes : Comme Thalès, un des sept sages, qui fut savant astronome. L’Argien Lobon dit que ses écrits font un total de quelque deux cents vers, et que sous sa statue on écrivit : Thalès de Milet repose ici dans le sol qui l’a nourri, Il fut un sage, et le premier des astrologues. Voici un de ses poèmes : Le trop parler n’est pas marque d’esprit. Trouvez une seule chose sage, Choisissez une seule chose belle, Et vous clouerez le bec à bien des bavards. On lui attribue encore les sentences suivantes : de tous les êtres, le plus ancien, c’est Dieu, car il n’a pas été engendré ; le plus beau, c’est le monde, car il est l’ouvrage du dieu ; le plus grand, c’est l’espace, car il contient tout ; le plus rapide, c’est l’esprit, car il court partout ; le plus fort, c’est la nécessité, car elle vient à bout de tout ; le plus sage, c’est le temps, parce qu’il découvre tout. La mort, dit-il, ne diffère en rien de la vie. On lui répond : « Pourquoi, alors, ne te donnes-tu pas la mort ? » ; « Parce que vie ou mort, c’est tout un », réplique-t-il. Quelqu’un lui demande ce qui du jour ou de la nuit fut créé d’abord ; il répond : « La nuit est en avance d’un jour. » On lui demande si les mauvaises actions d’un homme échappent au regard des dieux. Il répond : « Ils voient même les mauvaises pensées. » Un homme adultère lui demandait s’il pouvait jurer qu’il n’avait pas commis d’adultère. Il répondit : « Le parjure n’est pas pire que l’adultère. » On lui demandait ce qui était difficile : « Se connaître » dit-il ; ce qui était facile : donner un conseil à autrui ; ce qui était le plus doux : jouir ; ce que c’était que la divinité : un être sans commencement ni fin ; encore une chose difficile : voir un tyran âgé ; comment supporter aisément l’infortune : en voyant ses ennemis plus malheureux encore ; comment vivre vertueusement : en ne faisant pas ce que nous reprochons à autrui ; qui est heureux : l’homme bien portant, riche, courageux et instruit. Il disait encore que l’on doit penser à ses amis aussi bien en leur absence qu’en leur présence, que la beauté ne vient pas d’un beau visage, mais de belles actions. « Ne t’enrichis pas injustement, conseillait-il, et veille à ne pas être cité en justice pour de mauvaises paroles contre tes proches et tes amis. Comme tu traites tes parents, tes enfants te traiteront. » Du Nil[15] il disait qu’il débordait quand ses eaux étaient repoussées par les vents étésiens qui soufflent contre son cours. Apollodore dans ses Chroniques dit que Thalès naquit la première année de la trente-cinquième olympiade[16]. Il mourut dans sa soixante-dix-huitième année ou, comme le dit Sosicrate, dans sa quatre-vingt-dixième année, car ce fut dans la cinquante-huitième olympiade. Il vécut du temps de Crésus, auquel il promit de faire traverser l’Hallys[17] sans pont, en détournant le cours du fleuve. Il y eut cinq autres personnages du nom de Thalès (cf. Démétrios de Magnésie, Homonymes) : un rhéteur de Callatie, au style prétentieux, un peintre de Sicyone, de noble origine, un troisième, très ancien, du temps d’Hésiode, d’Homère et de Lycurgue, un quatrième, mentionné par Douris dans son traité de la peinture, un cinquième, plus jeune et peu connu, cité par Denys dans ses Critiques. Pour en revenir à notre sage, il mourut en regardant les jeux gymniques, pour avoir eu trop chaud et trop soif et par suite de sa fatigue et de son grand âge. Voici son épitaphe : :Ce tombeau, certes, est bien petit, :Mais la renommée de l’homme est allée au ciel. :C’est celui de Thalès le très sage. J’ai écrit sur lui les vers suivants dans le premier livre de mes épigrammes ou « vers de mètres divers[18] : :Tandis qu’il regardait les jeux, ô Zeus Hélios, :Tu as ravi du stade le sage Thalès. :Je te loue de l’avoir rapproché du ciel. Il était si vieux :Que de la terre il ne pouvait plus voir les astres. Thalès est l’auteur du fameux « connais-toi toi-même » qu’Antisthène (Livre des Filiations) attribue à Phémonoé, en déclarant que Chilon se l’appropria mensongèrement. Sur les sept sages, qu’il est juste de citer maintenant l’un après l’autre, voici la tradition. Damon de Cyrène, qui blâme tous les philosophes dans ses écrits, s’attaque surtout aux sept sages. Anaximène dit que tous étaient poètes. Dicéarque dit qu’ils n’étaient ni sages ni philosophes, mais hommes d’esprit et législateurs. Archétimos de Syracuse a décrit leurs assemblées chez Cypsélos[19] et dit qu’il y assista personnellement. Euphoros dit que tous, sauf Thalès, fréquentèrent Crésus. D’autres disent qu’ils se réunirent à Panionium, à Corinthe et à Delphes. On rapporte même leurs paroles, et qui a prononcé telle ou telle. Exemple : Le Spartiate Chilon fut sage, Lui qui dit : Rien de trop, Tout est bien qui vient en son temps ! On n’est pas d’accord sur leur nombre. Léandre, au lieu de Cléobule et de Myson, met Léophante, fils de Gorsias, ou Lébédios d’Éphèse et Épiménide de Crète. Platon, dans le Protagoras[20], met Myson à la place de Périandre. Éphoros met Anacharsis à la place de Myson et d’autres ajoutent Pythagore. Selon Dicéarque, il y en a quatre sur qui tout le monde est d’accord : Thalès, Bias, Pittacos et Solon. Le même auteur en nomme six autres, parmi lesquels il en choisit trois : Aristodème, Pamphile, le Lacédémonien Chilon, Cléobule, Anacharsis et Périandre. D’autres ajoutent Acousilaos, Caba ou Scala, un Argien. Hermippe, dans son livre sur les sages, dit qu’ils furent dix-sept et que chacun en choisit sept selon ses préférences. Ce sont Solon, Thalès, Pittacos, Bias, Chilon, Cléobule, Périandre, Anacharsis, Acousilaos, Épiménide, Léophante, Phérécyde, Aristodème, Pythagore, Lasos, fils de Charmantidas ou de Sisambrinos ou, selon Aristoxène, de Chabrinus, Hermonée, Anaxagore. Hippobotos (Catalogue des Philosophes) les inscrit ainsi : Orphée, Linos, Solon, Périandre, Anacharsis, Cléobule, Myson, Thalès, Bias, Pittacos, Épicharme et Pythagore. Voici des lettres attribuées à Thalès[21] : ==== Thalès à Phérécyde ==== « J’apprends que vous vous disposez à présenter aux Grecs le premier traité ionien des choses divines. Vous agiriez peut-être plus sagement en lisant votre ouvrage à vos amis, qu’en communiquant à n’importe quelles gens des écrits qui ne peuvent guère leur être utiles. « Si cela vous plaît, j’aimerais profiter de vos recherches et, si vous m’y invitez, je viendrai vous trouver au plus tôt. Car Solon d’Athènes et moi, qui avons déjà traversé deux fois la mer pour aller visiter la Crète, et pour aller en Égypte nous entretenir avec les prêtres et les astronomes du lieu, nous sommes assez sages pour ne pas hésiter à la traverser de nouveau pour aller vous voir. « Je parle de Solon, parce qu’il viendra avec moi si vous le permettez. Vous êtes un sédentaire, vous allez rarement en Ionie, vous n’aimez guère aller voir les étrangers, et vous ne songez, j’imagine, qu’à écrire. « Mais nous qui n’écrivons pas, nous parcourons volontiers la Grèce et l’Italie. » ==== Thalès à Solon ==== « Si vous quittez Athènes, vous aurez, je crois, tout avantage à venir vous établir à Milet, parmi les colons athéniens. Il n’y a là pour vous aucun danger. Si vous hésitez, sous prétexte que nous, Milésiens, sommes gouvernés par un tyran (je sais que vous haïssez tout pouvoir absolu), songez du moins que vous aurez plaisir à vivre avec nous qui sommes vos amis. Je sais que Bias vous a écrit et vous invite à aller à Priène. Si vous trouvez préférable d’habiter la ville de Priène, j’irai vivre là-bas avec vous. » <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Ausone|'''Ausone''']] ''([[w:309|309]]/[[w:310|310]], à [[w:Bazas|Bazas]] ou à [[w:Bordeaux#Burdigala,_cité_romaine_(Ier_siècle_-_Ve_siècle)|Bordeaux]] — [[w:394|394]]/[[w:395|395]], entre [[w:Langon_(Gironde)|Langon]] et [[w:La_Réole|La Réole]])'' <sup>[[w:IVe_siècle|⏳]]</sup> [[s:Auteur:Ausone|<sup>📚</sup>]] == === Le Jeu des Sept Sages === :Thalès a trouvé [texte grec] pour nous défendre de nous porter cautions, parce qu'il y a du danger à répondre ainsi pour d'autres[iv]. Nous donnons-là un avis qui ne plaira pas beaucoup aux emprunteurs. :THALÈS : Je suis Thalès de Milet ; j'ai dit, comme le poète Pindare, que l'eau est, le principe de toute chose. C'est à moi que des pêcheurs donnèrent autrefois [un trépied d'or] qu'ils avaient tiré de la mer : ils m'avaient choisi pour obéir au dieu de Délos, qui envoyait ce présent à un sage. Je refusai de le recevoir, je le leur rendis pour le porter à d'autres que je croyais plus dignes. Envoyé à tous les sept Sages, et renvoyé par eux, il nie fut rapporté. Je le reçus alors pour le consacrer à Apollon : car si Phébus a voulu qu'on choisit un sage, ce n'était pas d'un homme, mais d'un dieu qu'il fallait l'entendre. Je suis donc ce Thalès : mais un motif m'amène sur la scène. Comme les deux sages qui m'ont précédé, je viens défendre la sentence dont je suis l'auteur. Elle déplaira, mais non certes aux esprits prudents que l'expérience a instruits et rendus plus avisés. Nous avons dit : [texte grec], ou, en latin : Cautionne, mais tu t'en trouveras mal. Je pourrais parcourir mille exemples pour vous montrer des cautions et des répondants bien et dûment convaincus de repentir. Mais je ne veux nommer personne. Que chacun de, vous ré-fléchisse, et compte en lui-même combien de gens ont perdu ou souffert de s'être ainsi portés cautions pour d'autres. Toutefois, si un pareil service a du charme pour vous, n'y renoncez ni les uns ni les autres. :Alors que les uns applaudissent, et que les autres, si je les blesse, me sifflent. :THALÈS DE MILET. :AVANT d'oser une mauvaise action, à défaut de Témoin redoute ta conscience. La vie s'éteint, mais la gloire de la mort ne meurt point. Ce que tu veux faire, abstiens-toi de le dire. C'est un supplice de craindre ce qu'on ne peut empêcher. Si tu blâmes avec raison, ton hostilité même est profitable ; si tu loues mal à propos, ton amitié même est nuisible. Rien de trop. - Arrêtons-nous, et qu'ici même il n'y ait rien de trop. <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == [[w:Proclus|'''Proclus''']] ''(le 7 ou 8 février [[w:412|412]], à [[w:Constantinople|Constantinople]] — le 17 avril [[w:485|485]], à [[w:Histoire_d%27Athènes#Antiquité_tardive|Athènes]])''<sup>[[w:Ve_siècle|⏳]]</sup> [[s:Auteur:Proclus|<sup>📚</sup>]] == === Commentaire sur le premier livre d'Euclide, 65, 3 === ὥσπερ οὖν παρὰ τοῖς Φοίνιξιν διὰ τὰς ἐμπορείας καὶ τὰ συναλλάγματα τὴν ἀρχὴν ἔλαβεν ἡ τῶν ἀριθμῶν ἀκριβὴς γνῶσις, οὕτω δὴ καὶ παρ' Αἰγυπτίοις ἡ γεωμετρία διὰ τὴν εἰρημένην αἰτίαν εὕρηται. Θαλῆς δὲ πρῶτον εἰς Αἴγυπτον ἐλθὼν μετήγαγεν εἰς τὴν Ἑλλάδα τὴν θεωρίαν ταύτην καὶ πολλὰ μὲν αὐτὸς εὗρεν, πολλῶν δὲ τὰς ἀρχὰς τοῖς μετ' αὐτὸν ὑφηγήσατο τοῖς μὲν καθολικώτερον ἐπιβάλλων, τοῖς δὲ αἰσθητικώτερον. <div style="text-align: center; margin: 0 auto; color: #3366BB">⁂</div> == « [[w:Souda|'''Suidas''']] » ''([[w:Floruit|{{Info|''fl.''|Floruit, locution latine que l'on emploie pour indiquer la période au cours de laquelle une personne a été active}}]] fin du [[w:IXe_siècle|IX<sup>ème</sup> siècle {{Info|EC|de l’Ère Commune}}]])'' [[s:Auteur:Suidas|<sup>📚</sup>]] == === La Souda === Θαλῆς, Ἐξαμύου καὶ Κλεοβουλίνης, Μιλήσιος, ὡς δὲ Ἡρόδοτος Φοῖνιξ: γεγονὼς πρὸ Κροίσου, ἐπὶ τῆς λε# ὀλυμπιάδος, κατὰ δὲ Φλέγοντα γνωριζόμενος ἤδη ἐπὶ τῆς ζ#. ἔγραψε περὶ μετεώρων ἐν ἔπεσι, Περὶ ἰσημερίας, καὶ ἄλλα πολλά. ἐτελεύτησε δὲ γηραιός, θεώμενος γυμνικὸν ἀγῶνα, πιληθεὶς δὲ ὑπὸ τοῦ ὄχλου καὶ ἐκλυθεὶς ὑπὸ τοῦ καύματος. πρῶτος δὲ Θαλῆς τὸ τοῦ σοφοῦ ἔσχεν ὄνομα καὶ πρῶτος τὴν ψυχὴν εἶπεν ἀθάνατον ἐκλείψεις τε καὶ ἰσημερίας κατείληφεν. ἀποφθέγματα δὲ αὐτοῦ πλεῖστα: καὶ τὸ θρυλλούμενον: γνῶθι σαυτόν. τὸ γάρ, ἐγγύα, πάρα δ' ἄτα, Χίλωνός ἐστι μᾶλλον, ἰδιοποιησαμένου αὐτό: καὶ τό, μηδὲν ἄγαν. jqjie6p806ty17u32yyewh2hbok4mou Mathc complexes/a277 0 81080 773572 773567 2026-09-29T12:48:13Z Xhungab 23827 773572 wikitext text/x-wiki __NOTOC__ [[Catégorie:Mathc complexes (livre)]] [[Mathc complexes/Sommaire#Utilitaires Matrices| Sommaire]] '''L'étude de ce chapitre peut ce faire à l'aide de cette [[https://youtube.com/playlist?list=PLi6peGpf8EPNHUnib_ehtvFhNxJMWqn5Y&si=KIbSRJw_xjHl815R Playlist]].''' {{Partie{{{type|}}}| Matrices pour la transformée de Fourier discrète :}} La transformée de Fourier discrète d'un signal numérique s de N échantillons (s(0), s(1),..., s(N-1) est un vecteur (S(0),S(1), ..., S(N-1)) défini par : _ N-1_ \ S(k) = | s(n) exp(-i 2kPI/N)^n pour 0 <= k < N /_n=0_ On obtient ainsi une représentation spectrale discrète du signal échantillonné s(n). Notre étude  nous a permis de comprendre que l'on pouvait utiliser le calcul matriciel pour effectuer ce travail. Dans un premier temps nous construirons manuellement cette matrice. Dans un deuxième temps, nous demanderons au langage C de construire cette matrice. Nous verrons qu'en prenant le conjugué de cette matrice, multiplié par l'inverse de N, (le nombre d'échantillons), nous allons obtenir '''la transformée de Fourier discrète inverse'''. ==Copier ces fichier avec la bibliothèque sur les matrices complexes :== *[[Mathc complexes/a278| dft.h]] *[[Mathc complexes/a279| f.h]] ==Le fichier principal :== *[[Mathc complexes/a280| c03a.c]] Une matrice 3x3 *[[Mathc complexes/a281| c04a.c]] Une matrice 4x4 *[[Mathc complexes/09y| c04b.c]] Une matrice 4x4 ... [https://fr.wikipedia.org/wiki/Transformation_de_Fourier_discr%C3%A8te#Exemple_d'application_à_un_signal Wikipédia] *[[Mathc complexes/a282| c0na.c]] Une matrice nxn *[[Mathc complexes/09z| c0nb.c]] Une matrice nxn ... [https://fr.wikipedia.org/wiki/Transformation_de_Fourier_discr%C3%A8te#Exemple_d'application_à_un_signal Wikipédia] ==Propriétés :== *[[Mathc complexes/a283| c0bna.c]] La formule de Bessel (Une matrice nxn) {{AutoCat}} e5fersqqkp0gj9mbndh40i7mkeof6bm 773694 773572 2026-09-30T08:38:59Z Xhungab 23827 773694 wikitext text/x-wiki __NOTOC__ [[Catégorie:Mathc complexes (livre)]] [[Mathc complexes/Sommaire#Utilitaires Matrices| Sommaire]] '''L'étude de ce chapitre peut ce faire à l'aide de cette [[https://youtube.com/playlist?list=PLi6peGpf8EPNHUnib_ehtvFhNxJMWqn5Y&si=KIbSRJw_xjHl815R Playlist]].''' {{Partie{{{type|}}}| Matrices pour la transformée de Fourier discrète :}} La transformée de Fourier discrète d'un signal numérique s de N échantillons (s(0), s(1),..., s(N-1) est un vecteur (S(0),S(1), ..., S(N-1)) défini par : _ N-1 \ S(k) = | s(n) exp(-2ikPI n/N) pour 0 <= k < N /_n=0 On obtient ainsi une représentation spectrale discrète du signal échantillonné s(n). Notre étude  nous a permis de comprendre que l'on pouvait utiliser le calcul matriciel pour effectuer ce travail. Dans un premier temps nous construirons manuellement cette matrice. Dans un deuxième temps, nous demanderons au langage C de construire cette matrice. Nous verrons qu'en prenant le conjugué de cette matrice, multiplié par l'inverse de N, (le nombre d'échantillons), nous allons obtenir '''la transformée de Fourier discrète inverse'''. ==Copier ces fichier avec la bibliothèque sur les matrices complexes :== *[[Mathc complexes/a278| dft.h]] *[[Mathc complexes/a279| f.h]] ==Le fichier principal :== *[[Mathc complexes/a280| c03a.c]] Une matrice 3x3 *[[Mathc complexes/a281| c04a.c]] Une matrice 4x4 *[[Mathc complexes/09y| c04b.c]] Une matrice 4x4 ... [https://fr.wikipedia.org/wiki/Transformation_de_Fourier_discr%C3%A8te#Exemple_d'application_à_un_signal Wikipédia] *[[Mathc complexes/a282| c0na.c]] Une matrice nxn *[[Mathc complexes/09z| c0nb.c]] Une matrice nxn ... [https://fr.wikipedia.org/wiki/Transformation_de_Fourier_discr%C3%A8te#Exemple_d'application_à_un_signal Wikipédia] ==Propriétés :== *[[Mathc complexes/a283| c0bna.c]] La formule de Bessel (Une matrice nxn) {{AutoCat}} pjxacidzzqepgt0yewtlvvifznsfd40 773695 773694 2026-09-30T08:40:51Z Xhungab 23827 773695 wikitext text/x-wiki __NOTOC__ [[Catégorie:Mathc complexes (livre)]] [[Mathc complexes/Sommaire#Utilitaires Matrices| Sommaire]] '''L'étude de ce chapitre peut ce faire à l'aide de cette [[https://youtube.com/playlist?list=PLi6peGpf8EPNHUnib_ehtvFhNxJMWqn5Y&si=KIbSRJw_xjHl815R Playlist]].''' {{Partie{{{type|}}}| Matrices pour la transformée de Fourier discrète :}} La transformée de Fourier discrète d'un signal numérique s de N échantillons (s(0), s(1),..., s(N-1) est un vecteur (S(0),S(1), ..., S(N-1)) défini par : _ N-1 \ S(k) = | s(n) exp(-2ikPI n/N) pour 0 <= k < N /_n=0 On obtient ainsi une représentation spectrale discrète du signal échantillonné s(n). Notre étude  nous a permis de comprendre que l'on pouvait utiliser le calcul matriciel pour effectuer ce travail. * Dans un premier temps nous construirons manuellement cette matrice. * Dans un deuxième temps, nous demanderons au langage C de construire cette matrice. Nous verrons qu'en prenant le conjugué de cette matrice, multiplié par l'inverse de N, (le nombre d'échantillons), nous allons obtenir '''la transformée de Fourier discrète inverse'''. ==Copier ces fichier avec la bibliothèque sur les matrices complexes :== *[[Mathc complexes/a278| dft.h]] *[[Mathc complexes/a279| f.h]] ==Le fichier principal :== *[[Mathc complexes/a280| c03a.c]] Une matrice 3x3 *[[Mathc complexes/a281| c04a.c]] Une matrice 4x4 *[[Mathc complexes/09y| c04b.c]] Une matrice 4x4 ... [https://fr.wikipedia.org/wiki/Transformation_de_Fourier_discr%C3%A8te#Exemple_d'application_à_un_signal Wikipédia] *[[Mathc complexes/a282| c0na.c]] Une matrice nxn *[[Mathc complexes/09z| c0nb.c]] Une matrice nxn ... [https://fr.wikipedia.org/wiki/Transformation_de_Fourier_discr%C3%A8te#Exemple_d'application_à_un_signal Wikipédia] ==Propriétés :== *[[Mathc complexes/a283| c0bna.c]] La formule de Bessel (Une matrice nxn) {{AutoCat}} aiprp083bbes8wix9v2iohx9ntys5as 773697 773695 2026-09-30T10:34:24Z Xhungab 23827 773697 wikitext text/x-wiki __NOTOC__ [[Catégorie:Mathc complexes (livre)]] [[Mathc complexes/Sommaire#Utilitaires Matrices| Sommaire]] '''L'étude de ce chapitre peut ce faire à l'aide de cette [[https://youtube.com/playlist?list=PLi6peGpf8EPNHUnib_ehtvFhNxJMWqn5Y&si=KIbSRJw_xjHl815R Playlist]].''' {{Partie{{{type|}}}| Matrices pour la transformée de Fourier discrète :}} La transformée de Fourier discrète d'un signal numérique s de N échantillons (s(0), s(1),..., s(N-1) est un vecteur (S(0),S(1), ..., S(N-1)) défini par : _ N-1 \ S(k) = | s(n) exp(-2ikPI n/N) pour 0 <= k < N /_n=0 On obtient ainsi une représentation spectrale discrète du signal échantillonné s(n). Notre étude  nous a permis de comprendre que l'on pouvait utiliser le calcul matriciel pour effectuer ce travail. * Dans un premier temps nous construirons manuellement cette matrice. * Dans un deuxième temps, nous demanderons au langage C de construire cette matrice. Nous verrons qu'en prenant le conjugué de cette matrice, multiplié par l'inverse de N, (le nombre d'échantillons), nous allons obtenir '''la transformée de Fourier discrète inverse'''. ==Copier ces fichier avec la bibliothèque sur les matrices complexes :== *[[Mathc complexes/a278| dft.h]] *[[Mathc complexes/a279| f.h]] ==Le fichier principal :== *[[Mathc complexes/a280| c03a.c]] Une matrice 3x3 *[[Mathc complexes/a281| c04a.c]] Une matrice 4x4 *[[Mathc complexes/09y| c04b.c]] Une matrice 4x4 ... [https://fr.wikipedia.org/wiki/Transformation_de_Fourier_discr%C3%A8te#Exemple_d'application_à_un_signal Wikipédia] * [https://en.wikipedia.org/wiki/Discrete_Fourier_transform#Example Wikipédia] *[[Mathc complexes/a282| c0na.c]] Une matrice nxn *[[Mathc complexes/09z| c0nb.c]] Une matrice nxn ... [https://fr.wikipedia.org/wiki/Transformation_de_Fourier_discr%C3%A8te#Exemple_d'application_à_un_signal Wikipédia] ==Propriétés :== *[[Mathc complexes/a283| c0bna.c]] La formule de Bessel (Une matrice nxn) {{AutoCat}} q1059ihfcqnwuzw9e5hte3u4qzwn2cm 773698 773697 2026-09-30T10:34:54Z Xhungab 23827 773698 wikitext text/x-wiki __NOTOC__ [[Catégorie:Mathc complexes (livre)]] [[Mathc complexes/Sommaire#Utilitaires Matrices| Sommaire]] '''L'étude de ce chapitre peut ce faire à l'aide de cette [[https://youtube.com/playlist?list=PLi6peGpf8EPNHUnib_ehtvFhNxJMWqn5Y&si=KIbSRJw_xjHl815R Playlist]].''' {{Partie{{{type|}}}| Matrices pour la transformée de Fourier discrète :}} La transformée de Fourier discrète d'un signal numérique s de N échantillons (s(0), s(1),..., s(N-1) est un vecteur (S(0),S(1), ..., S(N-1)) défini par : _ N-1 \ S(k) = | s(n) exp(-2ikPI n/N) pour 0 <= k < N /_n=0 On obtient ainsi une représentation spectrale discrète du signal échantillonné s(n). Notre étude  nous a permis de comprendre que l'on pouvait utiliser le calcul matriciel pour effectuer ce travail. * Dans un premier temps nous construirons manuellement cette matrice. * Dans un deuxième temps, nous demanderons au langage C de construire cette matrice. Nous verrons qu'en prenant le conjugué de cette matrice, multiplié par l'inverse de N, (le nombre d'échantillons), nous allons obtenir '''la transformée de Fourier discrète inverse'''. ==Copier ces fichier avec la bibliothèque sur les matrices complexes :== *[[Mathc complexes/a278| dft.h]] *[[Mathc complexes/a279| f.h]] ==Le fichier principal :== *[[Mathc complexes/a280| c03a.c]] Une matrice 3x3 *[[Mathc complexes/a281| c04a.c]] Une matrice 4x4 *[[Mathc complexes/09y| c04b.c]] Une matrice 4x4 ... [https://fr.wikipedia.org/wiki/Transformation_de_Fourier_discr%C3%A8te#Exemple_d'application_à_un_signal Wikipédia] * [https://en.wikipedia.org/wiki/Discrete_Fourier_transform#Example Wikipédia] *[[Mathc complexes/a282| c0na.c]] Une matrice nxn *[[Mathc complexes/09z| c0nb.c]] Une matrice nxn ... [https://fr.wikipedia.org/wiki/Transformation_de_Fourier_discr%C3%A8te#Exemple_d'application_à_un_signal Wikipédia] * [https://en.wikipedia.org/wiki/Discrete_Fourier_transform#Example Wikipédia] ==Propriétés :== *[[Mathc complexes/a283| c0bna.c]] La formule de Bessel (Une matrice nxn) {{AutoCat}} kcn5h7s6xxxp5zgneqk7c8sekfmdwy7 773699 773698 2026-09-30T10:37:55Z Xhungab 23827 773699 wikitext text/x-wiki __NOTOC__ [[Catégorie:Mathc complexes (livre)]] [[Mathc complexes/Sommaire#Utilitaires Matrices| Sommaire]] '''L'étude de ce chapitre peut ce faire à l'aide de cette [[https://youtube.com/playlist?list=PLi6peGpf8EPNHUnib_ehtvFhNxJMWqn5Y&si=KIbSRJw_xjHl815R Playlist]].''' {{Partie{{{type|}}}| Matrices pour la transformée de Fourier discrète :}} La transformée de Fourier discrète d'un signal numérique s de N échantillons (s(0), s(1),..., s(N-1) est un vecteur (S(0),S(1), ..., S(N-1)) défini par : _ N-1 \ S(k) = | s(n) exp(-2ikPI n/N) pour 0 <= k < N /_n=0 On obtient ainsi une représentation spectrale discrète du signal échantillonné s(n). Notre étude  nous a permis de comprendre que l'on pouvait utiliser le calcul matriciel pour effectuer ce travail. * Dans un premier temps nous construirons manuellement cette matrice. * Dans un deuxième temps, nous demanderons au langage C de construire cette matrice. Nous verrons qu'en prenant le conjugué de cette matrice, multiplié par l'inverse de N, (le nombre d'échantillons), nous allons obtenir '''la transformée de Fourier discrète inverse'''. ==Copier ces fichier avec la bibliothèque sur les matrices complexes :== *[[Mathc complexes/a278| dft.h]] *[[Mathc complexes/a279| f.h]] ==Le fichier principal :== *[[Mathc complexes/a280| c03a.c]] Une matrice 3x3 *[[Mathc complexes/a281| c04a.c]] Une matrice 4x4 *[[Mathc complexes/09y| c04b.c]] Une matrice 4x4 ... [https://fr.wikipedia.org/wiki/Transformation_de_Fourier_discr%C3%A8te#Exemple_d'application_à_un_signal Wikipédia] *[[Mathc complexes/0a0| c04c.c]] Une matrice 4x4 ... [https://en.wikipedia.org/wiki/Discrete_Fourier_transform#Example Wikipédia] *[[Mathc complexes/a282| c0na.c]] Une matrice nxn *[[Mathc complexes/09z| c0nb.c]] Une matrice nxn ... [https://fr.wikipedia.org/wiki/Transformation_de_Fourier_discr%C3%A8te#Exemple_d'application_à_un_signal Wikipédia] *[[Mathc complexes/0a1| c0nc.c]] Une matrice nxn ... [https://en.wikipedia.org/wiki/Discrete_Fourier_transform#Example Wikipédia] ==Propriétés :== *[[Mathc complexes/a283| c0bna.c]] La formule de Bessel (Une matrice nxn) {{AutoCat}} bzy7jp0inwd9q8nropfde164b49l4hq Mathc complexes/a280 0 81083 773700 773555 2026-09-30T11:03:10Z Xhungab 23827 773700 wikitext text/x-wiki [[Catégorie:Mathc complexes (livre)]] [[Mathc complexes/a277#Le fichier principal :| Application]] Installer et compiler ce fichier dans votre répertoire de travail. {{Fichier|c03a.c|largeur=70%|info=|icon=Crystal128-source-c.svg}} <syntaxhighlight lang="c"> /* ------------------------------------ */ /* Save as : c03a.c */ /* ------------------------------------ */ #include "w_a.h" /* ------------------------------------ */ #include "f.h" /* ------------------------------------ */ int main(void) { double dft3[R3*(C3*C2)] = {1,0, 1,0., 1,0, 1,0, f(1,3).r,f(1,3).i, f(2,3).r,f(2,3).i, 1,0, f(2,3).r,f(2,3).i, f(4,3).r,f(4,3).i }; double Ts[R3*(C1*C2)] = { 1,0, 1,0, 2,0 }; double **DFT3 = ca_A_mZ(dft3, i_mZ(R3,C3)); double **cDFT3 = conj_mZ(DFT3, i_mZ(R3,C3)); double **cDFT3div3 = smul_mZ(1./3.,cDFT3, i_mZ(R3,C3)); double **s = ca_A_mZ(Ts, i_mZ(R3,C1)); double **S = i_mZ(R3,C1) ; clrscrn(); printf(" DFT3 : "); p_mZ(DFT3,S4,P3,S3,P3,C6); printf(" s : "); p_mZ(s,S4,P3,S3,P3,C6); mul_mZ(DFT3,s,S); printf(" S = DFT3 * s "); p_mZ(S,S4,P3,S3,P3,C6); stop(); clrscrn(); printf(" s : "); p_mZ(m0_mZ(s),S4,P3,S3,P3,C6); printf(" 1/3 cDFT3 : "); p_mZ(cDFT3div3,S4,P3,S3,P3,C6); mul_mZ(cDFT3div3,S,s); printf(" s = 1/3 cDFT3 * S : "); p_mZ(s,S4,P3,S3,P3,C6); stop(); f_mZ(DFT3); f_mZ(cDFT3); f_mZ(cDFT3div3); f_mZ(s); f_mZ(S); return 0; } /* ------------------------------------ */ /* ------------------------------------ */ </syntaxhighlight> '''Exemple de sortie écran :''' <syntaxhighlight lang="C"> DFT3 : +1.000+0.000i +1.000+0.000i +1.000+0.000i +1.000+0.000i -0.500-0.866i -0.500+0.866i +1.000+0.000i -0.500+0.866i -0.500-0.866i s : +1.000+0.000i +1.000+0.000i +2.000+0.000i S = DFT3 * s +4.000+0.000i -0.500+0.866i -0.500-0.867i Press return to continue. s : +0.000+0.000i +0.000+0.000i +0.000+0.000i 1/3 cDFT3 : +0.333-0.000i +0.333-0.000i +0.333-0.000i +0.333-0.000i -0.167+0.289i -0.167-0.289i +0.333-0.000i -0.167-0.289i -0.167+0.289i s = 1/3 cDFT3 * S : +1.000-0.000i +1.000+0.000i +2.000+0.000i Press return to continue. </syntaxhighlight> {{AutoCat}} 3z0ng9rzfz0i6ygxwkz18s11ph95hgd Mathc complexes/a281 0 81084 773701 773556 2026-09-30T11:04:51Z Xhungab 23827 773701 wikitext text/x-wiki [[Catégorie:Mathc complexes (livre)]] [[Mathc complexes/a277#Le fichier principal :| Application]] Installer et compiler ce fichier dans votre répertoire de travail. {{Fichier|c04a.c|largeur=70%|info=|icon=Crystal128-source-c.svg}} <syntaxhighlight lang="c"> /* ------------------------------------ */ /* Save as : c04a.c */ /* ------------------------------------ */ #include "w_a.h" /* ------------------------------------ */ #include "f.h" /* ------------------------------------ */ int main(void) { double dft4[R4*(C4*C2)] = { 1,0, 1,0, 1,0, 1,0, 1,0, f(1,4).r,f(1,4).i, f(2,4).r,f(2,4).i, f(3,4).r,f(3,4).i, 1,0, f(2,4).r,f(2,4).i, f(4,4).r,f(4,4).i, f(6,4).r,f(6,4).i, 1,0, f(3,4).r,f(3,4).i, f(6,4).r,f(6,4).i, f(9,4).r,f(9,4).i }; double Ts[R4*(C1*C2)] = { 1,0, 0,0, 2,0, 0,0 }; double **DFT4 = ca_A_mZ(dft4, i_mZ(R4,C4)); double **cDFT4 = conj_mZ(DFT4, i_mZ(R4,C4)); double **cDFT4div4 = smul_mZ(1/4.,cDFT4,i_mZ(R4,C4)); double **s = ca_A_mZ(Ts, i_mZ(R4,C1)); double **S = i_mZ(R4,C1) ; clrscrn(); printf(" DFT4 : "); p_mZ(DFT4,S4,P3,S3,P3,C6); printf(" s : "); p_mZ(s,S4,P3,S3,P3,C6); mul_mZ(DFT4,s,S); printf(" S = DFT4 * s : "); p_mZ(S,S4,P3,S3,P3,C6); stop(); clrscrn(); printf(" s : "); p_mZ(m0_mZ(s),S4,P0,S3,P0,C6); printf(" 1/4 cDFT4 : "); p_mZ(cDFT4div4,S4,P3,S3,P3,C6); mul_mZ(cDFT4div4,S,s); printf(" s = 1/4 cDFT4 * S : "); p_mZ(s,S4,P3,S3,P3,C6); stop(); f_mZ(DFT4); f_mZ(cDFT4); f_mZ(cDFT4div4); f_mZ(s); f_mZ(S); return 0; } /* ------------------------------------ */ /* ------------------------------------ */ </syntaxhighlight> '''Exemple de sortie écran :''' <syntaxhighlight lang="C"> DFT4 : +1.000+0.000i +1.000+0.000i +1.000+0.000i +1.000+0.000i +1.000+0.000i -0.000-1.000i -1.000+0.000i +0.000+1.000i +1.000+0.000i -1.000+0.000i +1.000-0.000i -1.000+0.000i +1.000+0.000i +0.000+1.000i -1.000+0.000i -0.000-1.000i s : +1.000+0.000i +0.000+0.000i +2.000+0.000i +0.000+0.000i S = DFT4 * s : +3.000+0.000i -1.000+0.000i +3.000-0.000i -1.000+0.000i Press return to continue. s : +0 +0i +0 +0i +0 +0i +0 +0i 1/4 cDFT4 : +0.250-0.000i +0.250-0.000i +0.250-0.000i +0.250-0.000i +0.250-0.000i -0.000+0.250i -0.250-0.000i +0.000-0.250i +0.250-0.000i -0.250-0.000i +0.250+0.000i -0.250-0.000i +0.250-0.000i +0.000-0.250i -0.250-0.000i -0.000+0.250i s = 1/4 cDFT4 * S : +1.000+0.000i -0.000+0.000i +2.000-0.000i -0.000-0.000i Press return to continue. </syntaxhighlight> {{AutoCat}} 9vhwlccpzgmwf273wbkrbveh668erbr Mathc complexes/a282 0 81085 773704 773568 2026-09-30T11:11:47Z Xhungab 23827 773704 wikitext text/x-wiki [[Catégorie:Mathc complexes (livre)]] [[Mathc complexes/a277#Le fichier principal :| Application]] Installer et compiler ce fichier dans votre répertoire de travail. {{Fichier|c0na.c|largeur=70%|info=|icon=Crystal128-source-c.svg}} <syntaxhighlight lang="c"> /* ------------------------------------ */ /* Save as : c0na.c */ /* ------------------------------------ */ #define CR 6. /* ------------------------------------ */ #include "w_a.h" /* ------------------------------------ */ #include "f.h" #include "dft.h" /* ------------------------------------ */ int main(void) { time_t t; srand(time(&t)); double **DFT = dft_mZ( i_mZ(CR,CR),CR); double **cDFT = conj_mZ(DFT, i_mZ(CR,CR) ); double **cDFTdivN = smul_mZ(1./CR,cDFT, i_mZ(CR,CR) ); double **s = r_mRZ( i_mZ(CR,C1),9 ); double **S = i_mZ(CR,C1) ; clrscrn(); printf(" DFT :"); p_mZ(DFT, S8,P3, S8,P3, C4); stop(); clrscrn(); printf(" s :"); p_mZ(s,S8,P3,S8,P3,C4); stop(); clrscrn(); mul_mZ(DFT,s,S); printf(" S = DFT * s"); p_mZ(S,S8,P3,S8,P3,C4); stop(); clrscrn(); printf(" 1/%.0f cDFT :",CR); p_mZ(cDFTdivN,S8,P3,S8,P3,C4); stop(); clrscrn(); mul_mZ(cDFTdivN,S,s); printf(" s = 1/%.0f cDFT * S :",CR); p_mZ(s, S8,P3, S8,P3, C4); stop(); f_mZ(DFT); f_mZ(cDFT); f_mZ(cDFTdivN); f_mZ(s); f_mZ(S); return 0; } /* ------------------------------------ */ /* ------------------------------------ */ </syntaxhighlight> '''Exemple de sortie écran : ''' <syntaxhighlight lang="C"> DFT : +1.000 +0.000i +1.000 +0.000i +1.000 +0.000i +1.000 +0.000i +1.000 +0.000i +0.500 -0.866i -0.500 -0.866i -1.000 +0.000i +1.000 +0.000i -0.500 -0.866i -0.500 +0.866i +1.000 -0.000i +1.000 +0.000i -1.000 +0.000i +1.000 -0.000i -1.000 +0.000i +1.000 +0.000i -0.500 +0.866i -0.500 -0.866i +1.000 -0.000i +1.000 +0.000i +0.500 +0.866i -0.500 +0.866i -1.000 +0.000i +1.000 +0.000i +1.000 +0.000i -0.500 +0.866i +0.500 +0.866i -0.500 -0.866i -0.500 +0.866i +1.000 -0.000i -1.000 +0.000i -0.500 +0.866i -0.500 -0.866i -0.500 -0.866i +0.500 -0.866i Press return to continue. s : -6.000 +0.000i +2.000 +0.000i -9.000 +0.000i -5.000 +0.000i -4.000 +0.000i +7.000 +0.000i Press return to continue. S = DFT * s -15.000 +0.000i +10.000 +8.660i -9.000 +0.000i -23.000 +0.000i -9.000 -0.000i +10.000 -8.660i Press return to continue. 1/6 cDFT : +0.167 -0.000i +0.167 -0.000i +0.167 -0.000i +0.167 -0.000i +0.167 -0.000i +0.083 +0.144i -0.083 +0.144i -0.167 -0.000i +0.167 -0.000i -0.083 +0.144i -0.083 -0.144i +0.167 +0.000i +0.167 -0.000i -0.167 -0.000i +0.167 +0.000i -0.167 -0.000i +0.167 -0.000i -0.083 -0.144i -0.083 +0.144i +0.167 +0.000i +0.167 -0.000i +0.083 -0.144i -0.083 -0.144i -0.167 -0.000i +0.167 -0.000i +0.167 -0.000i -0.083 -0.144i +0.083 -0.144i -0.083 +0.144i -0.083 -0.144i +0.167 +0.000i -0.167 -0.000i -0.083 -0.144i -0.083 +0.144i -0.083 +0.144i +0.083 +0.144i Press return to continue. s = 1/6 cDFT * S : -6.000 -0.000i +2.000 -0.000i -9.000 -0.000i -5.000 +0.000i -4.000 +0.000i +7.000 +0.000i Press return to continue. </syntaxhighlight> {{AutoCat}} pk8no7q3ta8p533a8zzfryfbhs17230 773713 773704 2026-09-30T11:58:33Z Xhungab 23827 773713 wikitext text/x-wiki [[Catégorie:Mathc complexes (livre)]] [[Mathc complexes/a277#Le fichier principal :| Application]] Installer et compiler ce fichier dans votre répertoire de travail. {{Fichier|c0na.c|largeur=70%|info=|icon=Crystal128-source-c.svg}} <syntaxhighlight lang="c"> /* ------------------------------------ */ /* Save as : c0na.c */ /* ------------------------------------ */ #define RC 6. /* ------------------------------------ */ #include "w_a.h" /* ------------------------------------ */ #include "f.h" #include "dft.h" /* ------------------------------------ */ int main(void) { time_t t; srand(time(&t)); double **DFT = dft_mZ( i_mZ(RC,RC),RC); double **cDFT = conj_mZ(DFT, i_mZ(RC,RC) ); double **cDFTdivN = smul_mZ(1./RC,cDFT, i_mZ(RC,RC) ); double **s = r_mRZ( i_mZ(RC,C1),9 ); double **S = i_mZ(RC,C1) ; clrscrn(); printf(" DFT :"); p_mZ(DFT, S8,P3, S8,P3, C4); stop(); clrscrn(); printf(" s :"); p_mZ(s,S8,P3,S8,P3,C4); stop(); clrscrn(); mul_mZ(DFT,s,S); printf(" S = DFT * s"); p_mZ(S,S8,P3,S8,P3,C4); stop(); clrscrn(); printf(" 1/%.0f cDFT :",RC); p_mZ(cDFTdivN,S8,P3,S8,P3,C4); stop(); clrscrn(); mul_mZ(cDFTdivN,S,s); printf(" s = 1/%.0f cDFT * S :",RC); p_mZ(s, S8,P3, S8,P3, C4); stop(); f_mZ(DFT); f_mZ(cDFT); f_mZ(cDFTdivN); f_mZ(s); f_mZ(S); return 0; } /* ------------------------------------ */ /* ------------------------------------ */ </syntaxhighlight> '''Exemple de sortie écran : ''' <syntaxhighlight lang="C"> DFT : +1.000 +0.000i +1.000 +0.000i +1.000 +0.000i +1.000 +0.000i +1.000 +0.000i +0.500 -0.866i -0.500 -0.866i -1.000 +0.000i +1.000 +0.000i -0.500 -0.866i -0.500 +0.866i +1.000 -0.000i +1.000 +0.000i -1.000 +0.000i +1.000 -0.000i -1.000 +0.000i +1.000 +0.000i -0.500 +0.866i -0.500 -0.866i +1.000 -0.000i +1.000 +0.000i +0.500 +0.866i -0.500 +0.866i -1.000 +0.000i +1.000 +0.000i +1.000 +0.000i -0.500 +0.866i +0.500 +0.866i -0.500 -0.866i -0.500 +0.866i +1.000 -0.000i -1.000 +0.000i -0.500 +0.866i -0.500 -0.866i -0.500 -0.866i +0.500 -0.866i Press return to continue. s : -6.000 +0.000i +2.000 +0.000i -9.000 +0.000i -5.000 +0.000i -4.000 +0.000i +7.000 +0.000i Press return to continue. S = DFT * s -15.000 +0.000i +10.000 +8.660i -9.000 +0.000i -23.000 +0.000i -9.000 -0.000i +10.000 -8.660i Press return to continue. 1/6 cDFT : +0.167 -0.000i +0.167 -0.000i +0.167 -0.000i +0.167 -0.000i +0.167 -0.000i +0.083 +0.144i -0.083 +0.144i -0.167 -0.000i +0.167 -0.000i -0.083 +0.144i -0.083 -0.144i +0.167 +0.000i +0.167 -0.000i -0.167 -0.000i +0.167 +0.000i -0.167 -0.000i +0.167 -0.000i -0.083 -0.144i -0.083 +0.144i +0.167 +0.000i +0.167 -0.000i +0.083 -0.144i -0.083 -0.144i -0.167 -0.000i +0.167 -0.000i +0.167 -0.000i -0.083 -0.144i +0.083 -0.144i -0.083 +0.144i -0.083 -0.144i +0.167 +0.000i -0.167 -0.000i -0.083 -0.144i -0.083 +0.144i -0.083 +0.144i +0.083 +0.144i Press return to continue. s = 1/6 cDFT * S : -6.000 -0.000i +2.000 -0.000i -9.000 -0.000i -5.000 +0.000i -4.000 +0.000i +7.000 +0.000i Press return to continue. </syntaxhighlight> {{AutoCat}} rligcbf4sz1d8v5mac29aihxbulk6ix Mathc initiation/a592 0 81086 773569 772070 2026-09-29T12:45:19Z Xhungab 23827 773569 wikitext text/x-wiki __NOTOC__ [[Catégorie:Mathc initiation (livre)]] [[Mathc initiation/a522#Analyse IV : Les équations différentielles|Sommaire]] '''L'étude de ce chapitre peut ce faire à l'aide de cette [[https://youtube.com/playlist?list=PLi6peGpf8EPNHUnib_ehtvFhNxJMWqn5Y&si=KIbSRJw_xjHl815R Playlist]].''' {{Partie{{{type|}}}| Se familiariser avec la transformée de Fourier discrète :}} En mathématiques, la transformée de Fourier discrète (TFD, Eng. DFT) sert à traiter un signal numérique. Elle constitue un équivalent discret (c'est-à-dire pour un signal défini à partir d'un nombre fini d'échantillons) de la transformée de Fourier (continue) utilisée pour traiter un signal analogique. Plus précisément, la TFD est la représentation spectrale discrète dans le domaine des fréquences d'un signal échantillonné. [https://fr.wikipedia.org/wiki/Transformation_de_Fourier_discr%C3%A8te Wikipédia] La transformée de Fourier discrète d'un signal s de N échantillons (s(0), s(1),..., s(N-1) est un vecteur (S(0),S(1), ..., S(N-1)) défini par : _ N-1_ \ S(k) = | s(n) exp(-i 2kPI/N)^n pour 0 <= k < N /_n=0_ On obtient ainsi une représentation spectrale discrète du signal échantillonné s(n). Notre étude  nous a permis de comprendre que l'on pouvait utiliser le calcul matriciel pour effectuer ce travail. Dans un premier temps nous construirons manuellement cette matrice. Dans un deuxième temps, nous demanderons au langage C de construire cette matrice. Nous verrons qu'en prenant le conjugué de cette matrice, multiplié par l'inverse de N, (le nombre d'échantillons), nous allons obtenir '''la transformée de Fourier discrete inverse'''. Pour ce travail, nous utiliserons le livre [[Mathc complexes/a277|Mathc complexes]]. : {{AutoCat}} 97x0pg1f3fkew7x0rj38vbqx13mt1ao 773570 773569 2026-09-29T12:45:55Z Xhungab 23827 773570 wikitext text/x-wiki __NOTOC__ [[Catégorie:Mathc initiation (livre)]] [[Mathc initiation/a522#Analyse IV : Les équations différentielles|Sommaire]] '''L'étude de ce chapitre peut ce faire à l'aide de cette [[https://youtube.com/playlist?list=PLi6peGpf8EPNHUnib_ehtvFhNxJMWqn5Y&si=KIbSRJw_xjHl815R Playlist]].''' {{Partie{{{type|}}}| Se familiariser avec la transformée de Fourier discrète :}} En mathématiques, la transformée de Fourier discrète (TFD, Eng. DFT) sert à traiter un signal numérique. Elle constitue un équivalent discret (c'est-à-dire pour un signal défini à partir d'un nombre fini d'échantillons) de la transformée de Fourier (continue) utilisée pour traiter un signal analogique. Plus précisément, la TFD est la représentation spectrale discrète dans le domaine des fréquences d'un signal échantillonné. [https://fr.wikipedia.org/wiki/Transformation_de_Fourier_discr%C3%A8te Wikipédia] La transformée de Fourier discrète d'un signal s de N échantillons (s(0), s(1),..., s(N-1) est un vecteur (S(0),S(1), ..., S(N-1)) défini par : _ N-1_ \ S(k) = | s(n) exp(-i 2kPI/N)^n pour 0 <= k < N /_n=0_ On obtient ainsi une représentation spectrale discrète du signal échantillonné s(n). Notre étude  nous a permis de comprendre que l'on pouvait utiliser le calcul matriciel pour effectuer ce travail. Dans un premier temps nous construirons manuellement cette matrice. Dans un deuxième temps, nous demanderons au langage C de construire cette matrice. Nous verrons qu'en prenant le conjugué de cette matrice, multiplié par l'inverse de N, (le nombre d'échantillons), nous allons obtenir '''la transformée de Fourier discrete inverse'''. '''Pour ce travail, nous utiliserons le livre [[Mathc complexes/a277|Mathc complexes]].''' {{AutoCat}} dmdpwlw4rnp6sb2azq71mw36qegwhhc 773571 773570 2026-09-29T12:47:54Z Xhungab 23827 773571 wikitext text/x-wiki __NOTOC__ [[Catégorie:Mathc initiation (livre)]] [[Mathc initiation/a522#Analyse IV : Les équations différentielles|Sommaire]] '''L'étude de ce chapitre peut ce faire à l'aide de cette [[https://youtube.com/playlist?list=PLi6peGpf8EPNHUnib_ehtvFhNxJMWqn5Y&si=KIbSRJw_xjHl815R Playlist]].''' {{Partie{{{type|}}}| Se familiariser avec la transformée de Fourier discrète :}} En mathématiques, la transformée de Fourier discrète (TFD, Eng. DFT) sert à traiter un signal numérique. Elle constitue un équivalent discret (c'est-à-dire pour un signal défini à partir d'un nombre fini d'échantillons) de la transformée de Fourier (continue) utilisée pour traiter un signal analogique. Plus précisément, la TFD est la représentation spectrale discrète dans le domaine des fréquences d'un signal échantillonné. [https://fr.wikipedia.org/wiki/Transformation_de_Fourier_discr%C3%A8te Wikipédia] La transformée de Fourier discrète d'un signal s de N échantillons (s(0), s(1),..., s(N-1) est un vecteur (S(0),S(1), ..., S(N-1)) défini par : _ N-1_ \ S(k) = | s(n) exp(-i 2kPI/N)^n pour 0 <= k < N /_n=0_ On obtient ainsi une représentation spectrale discrète du signal échantillonné s(n). Notre étude  nous a permis de comprendre que l'on pouvait utiliser le calcul matriciel pour effectuer ce travail. Dans un premier temps nous construirons manuellement cette matrice. Dans un deuxième temps, nous demanderons au langage C de construire cette matrice. Nous verrons qu'en prenant le conjugué de cette matrice, multiplié par l'inverse de N, (le nombre d'échantillons), nous allons obtenir '''la transformée de Fourier discrète inverse'''. '''Pour ce travail, nous utiliserons le livre [[Mathc complexes/a277|Mathc complexes]].''' {{AutoCat}} 98ptpksjimyb3aswzbyrck93iuyywc1 773573 773571 2026-09-29T13:04:34Z Xhungab 23827 773573 wikitext text/x-wiki __NOTOC__ [[Catégorie:Mathc initiation (livre)]] [[Mathc initiation/a522#Analyse IV : Les équations différentielles|Sommaire]] '''L'étude de ce chapitre peut ce faire à l'aide de cette [[https://youtube.com/playlist?list=PLi6peGpf8EPNHUnib_ehtvFhNxJMWqn5Y&si=KIbSRJw_xjHl815R Playlist]].''' {{Partie{{{type|}}}| Se familiariser avec la transformée de Fourier discrète :}} En mathématiques, la transformée de Fourier discrète (TFD, Eng. DFT) sert à traiter un signal numérique. Elle constitue un équivalent discret (c'est-à-dire pour un signal défini à partir d'un nombre fini d'échantillons) de la transformée de Fourier (continue) utilisée pour traiter un signal analogique. Plus précisément, la TFD est la représentation spectrale discrète dans le domaine des fréquences d'un signal échantillonné. [https://fr.wikipedia.org/wiki/Transformation_de_Fourier_discr%C3%A8te Wikipédia] La transformée de Fourier discrète d'un signal s de N échantillons (s(0), s(1),..., s(N-1) est un vecteur (S(0),S(1), ..., S(N-1)) défini par : _ N-1_ \ S(k) = | s(n) exp(-i 2kPI/N)^n pour 0 <= k < N /_n=0_ On obtient ainsi une représentation spectrale discrète du signal échantillonné s(n). Notre étude  nous a permis de comprendre que l'on pouvait utiliser le calcul matriciel pour effectuer ce travail. * Dans un premier temps nous construirons manuellement cette matrice. * Dans un deuxième temps, nous demanderons au langage C de construire cette matrice. Nous verrons qu'en prenant le conjugué de cette matrice, multiplié par l'inverse de N, (le nombre d'échantillons), nous allons obtenir '''la transformée de Fourier discrète inverse'''. '''Pour ce travail, nous utiliserons le livre [[Mathc complexes/a277|Mathc complexes]].''' {{AutoCat}} m179ci2vzumwq621u2d06ce3qnuvhcb 773693 773573 2026-09-30T08:38:09Z Xhungab 23827 773693 wikitext text/x-wiki __NOTOC__ [[Catégorie:Mathc initiation (livre)]] [[Mathc initiation/a522#Analyse IV : Les équations différentielles|Sommaire]] '''L'étude de ce chapitre peut ce faire à l'aide de cette [[https://youtube.com/playlist?list=PLi6peGpf8EPNHUnib_ehtvFhNxJMWqn5Y&si=KIbSRJw_xjHl815R Playlist]].''' {{Partie{{{type|}}}| Se familiariser avec la transformée de Fourier discrète :}} En mathématiques, la transformée de Fourier discrète (TFD, Eng. DFT) sert à traiter un signal numérique. Elle constitue un équivalent discret (c'est-à-dire pour un signal défini à partir d'un nombre fini d'échantillons) de la transformée de Fourier (continue) utilisée pour traiter un signal analogique. Plus précisément, la TFD est la représentation spectrale discrète dans le domaine des fréquences d'un signal échantillonné. [https://fr.wikipedia.org/wiki/Transformation_de_Fourier_discr%C3%A8te Wikipédia] La transformée de Fourier discrète d'un signal s de N échantillons (s(0), s(1),..., s(N-1) est un vecteur (S(0),S(1), ..., S(N-1)) défini par : _ N-1 \ S(k) = | s(n) exp(-2ikPI n/N) pour 0 <= k < N /_n=0 On obtient ainsi une représentation spectrale discrète du signal échantillonné s(n). Notre étude  nous a permis de comprendre que l'on pouvait utiliser le calcul matriciel pour effectuer ce travail. * Dans un premier temps nous construirons manuellement cette matrice. * Dans un deuxième temps, nous demanderons au langage C de construire cette matrice. Nous verrons qu'en prenant le conjugué de cette matrice, multiplié par l'inverse de N, (le nombre d'échantillons), nous allons obtenir '''la transformée de Fourier discrète inverse'''. '''Pour ce travail, nous utiliserons le livre [[Mathc complexes/a277|Mathc complexes]].''' {{AutoCat}} ottok6w437i8m9rtt777epsrdv9jyb8 Mathc complexes/a283 0 81087 773707 773565 2026-09-30T11:17:57Z Xhungab 23827 773707 wikitext text/x-wiki [[Catégorie:Mathc complexes (livre)]] [[Mathc complexes/a277#Le fichier principal :| Application]] Installer et compiler ce fichier dans votre répertoire de travail. {{Fichier|c0bna.c|largeur=70%|info=|icon=Crystal128-source-c.svg}} <syntaxhighlight lang="c"> /* ------------------------------------ */ /* Save as : c0bna.c */ /* ------------------------------------ */ #define CR 8. /* ------------------------------------ */ #include "w_a.h" /* ------------------------------------ */ #include "f.h" #include "dft.h" /* ------------------------------------ */ int main(void) { time_t t; srand(time(&t)); double **DFT = dft_mZ( i_mZ(CR,CR),CR); double **s = r_mRZ( i_mZ(CR,C1), 9); double **S = i_mZ(CR,C1) ; clrscrn(); printf(" DFT : \n"); p_mZ(DFT, S8,P3, S8,P3, C4); stop(); clrscrn(); printf(" s : \n"); p_mZ(s,S8,P3,S8,P3,C4); mul_mZ(DFT,s,S); printf(" S = DFT * s \n"); p_mZ(S,S8,P3,S8,P3,C4); stop(); clrscrn(); printf(" Bessel's formula: \n\n"); printf(" ||s||**2 = %.3f \n", pow(norm_Z(s),2)); printf(" 1/%.0f ||S||**2 = %.3f \n\n", CR, (1./CR)*pow(norm_Z(S),2)); stop(); f_mZ(DFT); f_mZ(s); f_mZ(S); return 0; } /* ------------------------------------ */ /* ------------------------------------ */ </syntaxhighlight> '''Exemple de sortie écran :''' <syntaxhighlight lang="C"> DFT : +1.000 +0.000i +1.000 +0.000i +1.000 +0.000i +1.000 +0.000i +1.000 +0.000i +0.707 -0.707i -0.000 -1.000i -0.707 -0.707i +1.000 +0.000i -0.000 -1.000i -1.000 +0.000i +0.000 +1.000i +1.000 +0.000i -0.707 -0.707i +0.000 +1.000i +0.707 -0.707i +1.000 +0.000i -1.000 +0.000i +1.000 -0.000i -1.000 +0.000i +1.000 +0.000i -0.707 +0.707i -0.000 -1.000i +0.707 +0.707i +1.000 +0.000i +0.000 +1.000i -1.000 +0.000i -0.000 -1.000i +1.000 +0.000i +0.707 +0.707i +0.000 +1.000i -0.707 +0.707i +1.000 +0.000i +1.000 +0.000i +1.000 +0.000i +1.000 +0.000i -1.000 +0.000i -0.707 +0.707i +0.000 +1.000i +0.707 +0.707i +1.000 -0.000i -0.000 -1.000i -1.000 +0.000i +0.000 +1.000i -1.000 +0.000i +0.707 +0.707i -0.000 -1.000i -0.707 +0.707i +1.000 -0.000i -1.000 +0.000i +1.000 -0.000i -1.000 +0.000i -1.000 +0.000i +0.707 -0.707i +0.000 +1.000i -0.707 -0.707i +1.000 -0.000i +0.000 +1.000i -1.000 +0.000i -0.000 -1.000i -1.000 +0.000i -0.707 -0.707i -0.000 -1.000i +0.707 -0.707i Press return to continue. </syntaxhighlight> '''Exemple de sortie écran :''' <syntaxhighlight lang="C"> DFT : +1.000 +0.000i +1.000 +0.000i +1.000 +0.000i +1.000 +0.000i +1.000 +0.000i +0.707 -0.707i -0.000 -1.000i -0.707 -0.707i +1.000 +0.000i -0.000 -1.000i -1.000 +0.000i +0.000 +1.000i +1.000 +0.000i -0.707 -0.707i +0.000 +1.000i +0.707 -0.707i +1.000 +0.000i -1.000 +0.000i +1.000 -0.000i -1.000 +0.000i +1.000 +0.000i -0.707 +0.707i -0.000 -1.000i +0.707 +0.707i +1.000 +0.000i +0.000 +1.000i -1.000 +0.000i -0.000 -1.000i +1.000 +0.000i +0.707 +0.707i +0.000 +1.000i -0.707 +0.707i +1.000 +0.000i +1.000 +0.000i +1.000 +0.000i +1.000 +0.000i -1.000 +0.000i -0.707 +0.707i +0.000 +1.000i +0.707 +0.707i +1.000 -0.000i -0.000 -1.000i -1.000 +0.000i +0.000 +1.000i -1.000 +0.000i +0.707 +0.707i -0.000 -1.000i -0.707 +0.707i +1.000 -0.000i -1.000 +0.000i +1.000 -0.000i -1.000 +0.000i -1.000 +0.000i +0.707 -0.707i +0.000 +1.000i -0.707 -0.707i +1.000 -0.000i +0.000 +1.000i -1.000 +0.000i -0.000 -1.000i -1.000 +0.000i -0.707 -0.707i -0.000 -1.000i +0.707 -0.707i Press return to continue. s : -7.000 +0.000i +5.000 +0.000i -9.000 +0.000i +9.000 +0.000i +8.000 +0.000i +5.000 +0.000i -9.000 +0.000i +9.000 +0.000i S = DFT * s +11.000 +0.000i -15.000 +0.000i +19.000 +8.000i -15.000 +0.000i -45.000 +0.000i -15.000 -0.000i +19.000 -8.000i -15.000 +0.000i Press return to continue. Bessel's formula: ||s||**2 = 487.000 1/8 ||S||**2 = 487.000 Press return to continue. </syntaxhighlight> {{AutoCat}} aoil0n2k5xafnwj0ir6wq7bwk66i3wa 773708 773707 2026-09-30T11:18:36Z Xhungab 23827 773708 wikitext text/x-wiki [[Catégorie:Mathc complexes (livre)]] [[Mathc complexes/a277#Le fichier principal :| Application]] Installer et compiler ce fichier dans votre répertoire de travail. {{Fichier|c0bna.c|largeur=70%|info=|icon=Crystal128-source-c.svg}} <syntaxhighlight lang="c"> /* ------------------------------------ */ /* Save as : c0bna.c */ /* ------------------------------------ */ #define CR 8. /* ------------------------------------ */ #include "w_a.h" /* ------------------------------------ */ #include "f.h" #include "dft.h" /* ------------------------------------ */ int main(void) { time_t t; srand(time(&t)); double **DFT = dft_mZ( i_mZ(CR,CR),CR); double **s = r_mRZ( i_mZ(CR,C1), 9); double **S = i_mZ(CR,C1) ; clrscrn(); printf(" DFT : \n"); p_mZ(DFT, S8,P3, S8,P3, C4); stop(); clrscrn(); printf(" s : \n"); p_mZ(s,S8,P3,S8,P3,C4); mul_mZ(DFT,s,S); printf(" S = DFT * s \n"); p_mZ(S,S8,P3,S8,P3,C4); stop(); clrscrn(); printf(" Bessel's formula: \n\n"); printf(" ||s||**2 = %.3f \n", pow(norm_Z(s),2)); printf(" 1/%.0f ||S||**2 = %.3f \n\n", CR, (1./CR)*pow(norm_Z(S),2)); stop(); f_mZ(DFT); f_mZ(s); f_mZ(S); return 0; } /* ------------------------------------ */ /* ------------------------------------ */ </syntaxhighlight> '''Exemple de sortie écran :''' <syntaxhighlight lang="C"> DFT : +1.000 +0.000i +1.000 +0.000i +1.000 +0.000i +1.000 +0.000i +1.000 +0.000i +0.707 -0.707i -0.000 -1.000i -0.707 -0.707i +1.000 +0.000i -0.000 -1.000i -1.000 +0.000i +0.000 +1.000i +1.000 +0.000i -0.707 -0.707i +0.000 +1.000i +0.707 -0.707i +1.000 +0.000i -1.000 +0.000i +1.000 -0.000i -1.000 +0.000i +1.000 +0.000i -0.707 +0.707i -0.000 -1.000i +0.707 +0.707i +1.000 +0.000i +0.000 +1.000i -1.000 +0.000i -0.000 -1.000i +1.000 +0.000i +0.707 +0.707i +0.000 +1.000i -0.707 +0.707i +1.000 +0.000i +1.000 +0.000i +1.000 +0.000i +1.000 +0.000i -1.000 +0.000i -0.707 +0.707i +0.000 +1.000i +0.707 +0.707i +1.000 -0.000i -0.000 -1.000i -1.000 +0.000i +0.000 +1.000i -1.000 +0.000i +0.707 +0.707i -0.000 -1.000i -0.707 +0.707i +1.000 -0.000i -1.000 +0.000i +1.000 -0.000i -1.000 +0.000i -1.000 +0.000i +0.707 -0.707i +0.000 +1.000i -0.707 -0.707i +1.000 -0.000i +0.000 +1.000i -1.000 +0.000i -0.000 -1.000i -1.000 +0.000i -0.707 -0.707i -0.000 -1.000i +0.707 -0.707i Press return to continue. s : -7.000 +0.000i +5.000 +0.000i -9.000 +0.000i +9.000 +0.000i +8.000 +0.000i +5.000 +0.000i -9.000 +0.000i +9.000 +0.000i S = DFT * s +11.000 +0.000i -15.000 +0.000i +19.000 +8.000i -15.000 +0.000i -45.000 +0.000i -15.000 -0.000i +19.000 -8.000i -15.000 +0.000i Press return to continue. Bessel's formula: ||s||**2 = 487.000 1/8 ||S||**2 = 487.000 Press return to continue. </syntaxhighlight> {{AutoCat}} 9fb7cnegbzdzorgrjieog07biglyebh 773709 773708 2026-09-30T11:19:25Z Xhungab 23827 773709 wikitext text/x-wiki [[Catégorie:Mathc complexes (livre)]] [[Mathc complexes/a277#Le fichier principal :| Application]] Installer et compiler ce fichier dans votre répertoire de travail. {{Fichier|c0bna.c|largeur=70%|info=|icon=Crystal128-source-c.svg}} <syntaxhighlight lang="c"> /* ------------------------------------ */ /* Save as : c0bna.c */ /* ------------------------------------ */ #define CR 8. /* ------------------------------------ */ #include "w_a.h" /* ------------------------------------ */ #include "f.h" #include "dft.h" /* ------------------------------------ */ int main(void) { time_t t; srand(time(&t)); double **DFT = dft_mZ( i_mZ(CR,CR),CR); double **s = r_mRZ( i_mZ(CR,C1), 9); double **S = i_mZ(CR,C1) ; clrscrn(); printf(" DFT :"); p_mZ(DFT, S8,P3, S8,P3, C4); stop(); clrscrn(); printf(" s :"); p_mZ(s,S8,P3,S8,P3,C4); mul_mZ(DFT,s,S); printf(" S = DFT * s"); p_mZ(S,S8,P3,S8,P3,C4); stop(); clrscrn(); printf(" Bessel's formula: \n\n"); printf(" ||s||**2 = %.3f \n", pow(norm_Z(s),2)); printf(" 1/%.0f ||S||**2 = %.3f \n\n", CR, (1./CR)*pow(norm_Z(S),2)); stop(); f_mZ(DFT); f_mZ(s); f_mZ(S); return 0; } /* ------------------------------------ */ /* ------------------------------------ */ </syntaxhighlight> '''Exemple de sortie écran :''' <syntaxhighlight lang="C"> DFT : +1.000 +0.000i +1.000 +0.000i +1.000 +0.000i +1.000 +0.000i +1.000 +0.000i +0.707 -0.707i -0.000 -1.000i -0.707 -0.707i +1.000 +0.000i -0.000 -1.000i -1.000 +0.000i +0.000 +1.000i +1.000 +0.000i -0.707 -0.707i +0.000 +1.000i +0.707 -0.707i +1.000 +0.000i -1.000 +0.000i +1.000 -0.000i -1.000 +0.000i +1.000 +0.000i -0.707 +0.707i -0.000 -1.000i +0.707 +0.707i +1.000 +0.000i +0.000 +1.000i -1.000 +0.000i -0.000 -1.000i +1.000 +0.000i +0.707 +0.707i +0.000 +1.000i -0.707 +0.707i +1.000 +0.000i +1.000 +0.000i +1.000 +0.000i +1.000 +0.000i -1.000 +0.000i -0.707 +0.707i +0.000 +1.000i +0.707 +0.707i +1.000 -0.000i -0.000 -1.000i -1.000 +0.000i +0.000 +1.000i -1.000 +0.000i +0.707 +0.707i -0.000 -1.000i -0.707 +0.707i +1.000 -0.000i -1.000 +0.000i +1.000 -0.000i -1.000 +0.000i -1.000 +0.000i +0.707 -0.707i +0.000 +1.000i -0.707 -0.707i +1.000 -0.000i +0.000 +1.000i -1.000 +0.000i -0.000 -1.000i -1.000 +0.000i -0.707 -0.707i -0.000 -1.000i +0.707 -0.707i Press return to continue. s : -7.000 +0.000i +5.000 +0.000i -9.000 +0.000i +9.000 +0.000i +8.000 +0.000i +5.000 +0.000i -9.000 +0.000i +9.000 +0.000i S = DFT * s +11.000 +0.000i -15.000 +0.000i +19.000 +8.000i -15.000 +0.000i -45.000 +0.000i -15.000 -0.000i +19.000 -8.000i -15.000 +0.000i Press return to continue. Bessel's formula: ||s||**2 = 487.000 1/8 ||S||**2 = 487.000 Press return to continue. </syntaxhighlight> {{AutoCat}} eawqkqzkkx7a5ri4kouegjytsmzol2v Fonctionnement d'un ordinateur/Les microarchitectures pour le x86 : haute performance 0 82608 773636 773540 2026-09-29T21:19:43Z Mewtow 31375 773636 wikitext text/x-wiki Dans ce chapitre, nous allons étudier des exemples de processeurs x86, ceux présents dans nos PC. Nous n'allons pas voir les anciens processeurs comme le 286, le 386 ou le 486. Nous allons commencer avec le Pentium 1, et les processeurs commerciaux qui ont suivis. Tous les processeurs que nous allons voir dans ce chapitre sont des processeurs superscalaires. De fait, ce n'est pas pour rien si ce chapitre se situe après le chapitre sur les processeurs superscalaires. Par contre, nous allons voir que certains n'ont pas d'exécution dans le désordre, car elle est arrivée après la superscalarité. Le jeu d'instruction x86 pose quelques problèmes pour la superscalarité, car c'est un jeu d'instruction CISC, avec tous les défauts que ça implique. Un jeu d'instruction CISC a en effet de nombreuses propriétés qui collent mal avec l'émission multiple, avec la '''superscalarité'''. Il y en a plusieurs, certaines impactent le chargement des instructions, d'autres leur décodage, d'autres l'exécution, etc. Premièrement, les instructions sont de longueur variable, entre 1 et 15 octets, ce qui complique leur chargement et leur décodage. En pratique, les processeurs chargent un bloc de 32 à 64 octets, et découpent celui-ci en plusieurs instructions. La conséquence est que l'usage d'instructions trop longues peut poser problème. Imaginez qu'un processeur charge un bloc de 16 octets et que celui-ci ne contienne qu'une seule instruction : on ne profite pas de la superscalarité. Deuxièmement, une partie des instructions est microcodée, faute de mieux. Et cela pose de sérieux challenges pour l'implémentation des décodeurs. Dupliquer le microcode demanderait trop de transistors, ce qui fait que ce n'est pas fait. À la place, il n'y a qu'un seul microcode, ce qui fait que l'on ne peut pas décoder plusieurs instructions microcodées en même temps. Il est cependant possible de profiter de la superscalarité, en décodant une instruction microcodée en parallèle d'autres instructions non-microcodées. Et heureusement, ce cas est de loin le plus fréquent, il est rare que plusieurs instructions microcodées se suivent.' Troisièmement, la présence d'instructions ''load-up'', qui lisent un opérande en mémoire, peut poser problème, mais est aussi source d'optimisations assez intéressantes. En théorie, une instruction ''load-op'' est décodée en deux micro-opération : une pour lire d'opérande en RAM, l'autre pour faire l'opération arithmétique. Sauf que les processeurs x86 modernes optimisent la gestion des instructions ''load-up''. Par exemple, les premiers processeurs Atom géraient des micro-opérations de type ''load-up'', directement dans le chemin de données ! D'autres processeurs utilisent la technique de la '''micro-fusion''' pour retarder le décodage réel des instructions ''load-up'' assez loin dans le pipeline. Avec eux, une instruction ''load-op'' est décodée en une seule "macro-opération", qui est propagée dans le pipeline, pour être scindée en deux micro-opérations un peu avant les ALU et l'unité mémoire. L'avantage est qu'une macro-opération ne prend qu'une seule entrée dans le tampon de ré-ordonnancement, le ''scheduler'', la file de micro-opération, et les autres structures similaires. Il faut cependant noter qu'avoir des instructions complexes peut avoir des avantages sur les processeurs superscalaires à exécution dans le désordre. Les avantages sont liés au fait que certaines instructions complexes peuvent être implémentées avec des circuits dédiés, plutot qu'avec une suite de µops ou d'instructions. Les performances sont alors meilleures car une grosse instruction complexe devient une seule µops, ce qui aide le renommage de registres, prend moins de place dans le ROB ou les stations de réservation, etc. : Pour avoir une petite idée des avantages et inconvénients, je conseille la lecture de cet articles de blog : [https://chipsandcheese.com/p/why-x86-doesnt-need-to-die Why x86 Doesn’t Need to Die]. Il s'agit d'une réponse à cet autre article, plus court : [https://hackaday.com/2024/03/21/why-x86-needs-to-die/ Why X86 Needs To Die]. ==Introduction : généralités et historique== Avant de voir les processeurs dans un ordre chronologique, il est bon de faire quelques généralités, histoire de bien cadrer ce qui va suivre. Les architectures Intel et AMD se classent en deux types : une classe de microarchitectures pour la haute performance, une classe de microarchitectures moins performante mais plus économe. La première est utilisée sur les PC fixes et parfois sur les serveurs, les processeurs pour ''desktop'' et serveur pouvant être différents. Les microarchitectures pour serveurs sont souvent des variantes des microarchitectures pour ''desktop''. Les serveurs ont surtout besoin d'exécuter un grand nombre d programmes/processus en même temps, ce qui fait qu'elles ont besoin d'un grand nombre de cœurs moins de cœurs performants individuellement. Pour les applications ''desktop'', c'est l'inverse : elles ont besoin de cœurs performants, quitte à en avoir moins. Pour la seconde catégorie, parler de microarchitecture basse consommation serait peu-être un peu exagéré, car elles ne visent pas non les smartphones et autres appareils embarqué. Mais elles le sont suffisamment pour entrer dans un ordinateur portable, où l'autonomie de la batterie est très importante. Dan ce chapitre, nous allons parler exclusivement des processeurs haute performance, les microarchitectures "basse consommation" seront pour le prochain chapitre. ===Les différences et points communs entre µarchs d'Intel et d'AMD=== Les microarchitectures Intel et AMD ne sont pas très différentes quand on regarde de loin. Elles ont évoluées dans la même direction, avec une introduction précoce de la superscalarité, puis de l'exécution dans le désordre, du renommage de registre, de la prédiction de branchement, d'un cache de µops, etc. Néanmoins, il y a des différences entre les deux qui relèvent de la tendance générale, avec de nombreuses exceptions : * Intel préfère utiliser un ''scheduler'' centralisée, alors qu'AMD préfère des stations des ''schedulers'' décentralisées. * AMD sépare les unités flottantes/SIMD des unités entières, elles ont des ports d'émission bien séparés. Intel, en comparaison, préfère mettre une ALU et une unité FPU/SIMD sur le même port d'émission. Mais il s'agit là de tendance, avec de nombreuses exceptions. Par exemple, les microarchitectures K6 et Bulldozer d'AMD utilisaient une station de réservation centralisée. De même, les micraorchitectures récentes d'Intel tendent de plus en plus à scinder le ''scheduler''s, de plus en plus avec le temps. Le fait est qu'elle a dû grossir avec le temps, au point de devoir être scindée tellement elle prenait de circuits. La microarchitecture Skylake l'a scindée en une station de réservation pour les µops mémoire et une autre pour le reste. La microarchitecture ''Sunny Cove'' a ensuite scindée la station de réservation mémoire en deux : une pour les lectures et une pour les écritures. Dans ce chapitre, nous ne parlerons pas des unités de prédiction de branchement, ni de la hiérarchie des caches. Et les raisons sont différentes entre les eux. Les unités de prédiction de branchement ont été discutées dans le chapitre sur la prédiction de branchement. De plus, de nombreux processeurs différents utilisent des unités de prédiction de branchement qui ont des algorithmes similaires. Mais la raison principale est que l'unité de prédiction de branchement est complétement détachée du reste du pipeline, cache d'instruction excepté sur certaines microarchitectures. N'importe quelle unité de branchement peut s'adapter à n'importe quel pipeline/microarchitecture, tant que ses ''itmings'' et délais en cycles d'horloge tiennent la route. Il en est plus ou moins de même pour la hiérarchie de caches. Me système mémoire est assez indépendant du reste de la microarchitecture. Dans ce qui va suivre, vous allez rapidement remarquer quelque chose d'assez évident. Les processeurs x86 ont en quelque sorte deux "pipelines" séparés, assez différents les unes des autres, qui ont évolués en parallèle. D'un côté, il y a le "pipeline" entier/mémoire, qui exécute les opérations entières et les µops mémoire. Il regroupe des ALU entières, des AGU (unité de calcul d'adresse) et les unités mémoire LOAD/STORE. Il communique directement avec la ''Load/Store Queue'', car c'est là dedans que se font les calculs d'adresse. A l'opposé, les calculs flottants sont réalisés dans des pipelines séparés, sauf sur quelques processeurs qui font exception, comme les microarchitectures Core. Nous verrons pourquoi dans la section suivante. Pour ce qui est des accès mémoire, les microarchitectures Intel et AMD ont évolué différemment. Intel a suivi cette progression : * Le Pentium 1 utilisait une unité mémoire intégrée dans le pipeline entier. * Le Pentium 3 a séparé l'unité mémoire du pipeline entier, mais ne restait capable que d'émettre un accès mémoire par cycle. * La microarchitectures Core a ajouté la possibilité de faire deux émissions mémoire simultanées : une lecture avec une écriture. * Par la suite, de nouveaux ports de lectures ont été rajoutés. ===Un aparté sur la FPU des processeurs x86=== Les processeurs x86 oint acquis une FPU assez rapidement dans l'histoire. Les processeurs 286 et 386 n'avaient pas de FPU, mais pouvaient faire appel à un coprocesseur spécialisé dans les calculs flottants : le '''coprocesseur x87'''. Le coprocesseur x87 intégrait 8 registres flottants et supportait 8quelques instructions flottante, comme FADD pour l'addition, FSUB pour la soustraction, FMUL pour la multiplication, FDIV pour la division, etc. Le coprocesseur x87 a été intégré dans le processeur assez rapidement, dès le 486. Pour cela, le 486 intégrait une FPU et les 8 registres flottants. Les instructions FADD, SUB, FMUL, et quelques autres, ont aussi été ajoutées au jeu d'instruction de base du 486. Elles formaient une '''extension du jeu d'instruction x86''', à savoir des paquets d'instructions qui n'étaient pas dans le jeu d’instruction de base, mais qui ont été rajoutés par la suite et sont devenus des standards. Détail extraordinairement important : le coprocesseur x87 intégrait aussi 8 registres, avec une organisation très spéciale. Les registres n'étaient pas "adressables" avec des noms de registres, ils étaient à la place organisé en pile d'opérande. Vous vous rappelez peut-être que, dans le chapitre "les machines à pile et mémoire-mémoire", j'ai parlé des processeurs avec une pile d'opérande. Le coprocesseur x87 en était un. Et cela posait pas mal de problème pour rendre les opérations flottantes performantes. Notamment, cela posait problème pour le renommage de registres. Le fait que les registres flottants et généraux soient séparés fait qu'ils sont souvent renommés à part, dans deux unités e renommage différentes. Les registres flottants ont été les premiers à être renommés. De nombreux processeurs renommaient les registres flottants, alors que les registres généraux n'étaient pas renommés. La raison est que quand on un budget en transistor limité, on ne peut pas renommer les deux. Et autant c'est utile de renommer les registres généraux, autant la pile de registre du x87 rendait cela quasiment nécessaire pour avoir des performances convenables. un autre détail est que les optimisations du renommages sont d'abord arrivées sur le pipeline flottant, avant d'être portées sur le pipeline entier. Un exemple est celui des techniques d'élimination des MOV (''MOV elimination''), qui traitent les instructions MOV entre registres directement dans l'unité de renommage. Ou encore, les techniques avec des idiomes pour mettre à zéro un registre en le Xorant avec lui-même. Elles ont été utilisées d'abord sur les registres flottants/SIMD, avant d'arriver sur les registres généraux. Quelques processeurs les utilsaient pour les registres flottants, mais pas les registres généraux. Il en est de même avec le renommage dans le ROB versus à banc de registre physique. Quelques CPU renommaient les registres flottants avec un renommage à banc de registre physique, avec que le pipeline entier utilisait encore le renommage dans le ROB. Les processeurs Athlon et Phenom d'AMD étaient dans ce cas, par exemple. Chez Intel, le renommage à banc de registre physique est apparu sur le Pentium 4 et a été appliqué sur tous les registres. En général, la FPU est précédée par une station de réservation unique (ou par un ''scheduler'' sur certains CPU). Il y a souvent un port d'émission pour l'additionneur flottant et un autre pour le multiplieurs, sauf pour les tout premiers modèles d'Intel et AMD. Il y aussi souvent un port pour les instructions FSTORE, les écritures flottantes. Les ports en question servent à transmettre les données à écrire vers l'unité mémoire, ainsi que l'adresse mémoire associée. {|class="wikitable" |+ Station de réservation flottante |- ! Station de réservation 1 !! Station de réservation 2 !! Station de réservation 3 |- | FADD (additionneur flottant) || FMUL (multiplication flottante || FSTORE |} ===Un aparté sur les instructions SIMD des processeurs x86=== L'extension flottante x87 est resté la norme pendant une bonne décennie, sur les CPU 32 bits. Mais par la suite, les choses ont changées avec l'introduction des '''instructions SIMD'''. Je ne vais pas rentrer dans le détail, un chapitre ultérieur détaillera les instructions SIMD. Mais je dois cependant parler des bases de ces instructions, car elles ont remplacé les instructions flottantes progressivement. Mais avant toute chose, un petit historique,pour vous faire comprendre le vocabulaire utilisé dans ce qui suit. Les premières instructions SIMD ont été introduites en 1996, sur le Pentium MMX. Les instructions en question étaient regroupées dans une '''extension x86''' (un ajout au jeu d'instruction de base), appelé le MMX. Il ne contenait que des instructions SIMD pour des opérandes entiers. Mais par la suite, les extensions '''''Streaming SIMD Extensions''''' (SSE) ont ajouté des opérations flottantes. Les ''Streaming SIMD Extensions'', qu'on va abrévier SSE dans ce qui suit, ont été déclinées en plusieurs versions : SSE1, SSE2, SEE3, SSE4, et quelques intermédiaires. Puis, vint le '''AVX''' (''Advanced Vector eXtensions''). Les instructions SIMD regroupent plusieurs opérations identiques en une seule instruction, la seule contrainte étant que les opérandes soient différentes. Par exemple, une instruction d'addition SIMD regroupe quatre additions séparées, chacun travaillant sur des opérandes différentes. [[File:Instructions SIMD.png|centre|vignette|upright=3|Instructions SIMD]] J'ai donné l'exemple d'une addition SIMD qui regroupe quatre additions flottantes, travaillant chacune sur ses opérandes rien qu'à elle. Les opérandes en question ne sont pas lues depuis les registres généraux ou flottants. A la place, les instructions utilisent un banc de registre dédié, qui contient des registres assez larges. Les instructions SIMD utilisent donc des '''registres SIMD''', qui mémorisent des paquets d'opérandes. Par exemple, l'extension SSE a ajouté 16 registres XMM, de 128 bits chacun. un registre de 128 bits peut mémoriser : 2 entiers/flottants 64 bits, 4 entiers/flottants 32 bits, 8 entiers 16 bits, 16 entiers 8 bits. [[File:Vector register.png|centre|vignette|upright=2|Contenu d'un vecteur en fonction du type de données utilisé.]] L'AVX, quant à elle, donne accès à 16 registres de 256 bits chacun. Pour faire des économies de circuits, ils ont été fusionnés avec les registres XMM du SSE. Les 128 bits de poids faible de ces registres ne sont autre que les registres du SSE. [[File:AVX registers.svg|centre|vignette|upright=1.5|Registres AVX.]] Si je parle de ces instructions et registres SIMD, c'est parce qu'ils ont remplacé les instructions/registres flottants d'antan. Le x87 a disparu, les instructions SIMD font office d'instructions flottantes. Le remplacement a eu lieu avec le passage au 64 bits. Les raisons à cela sont multiples, mais la principale est que le x87 était très mal fait, avec une architecture obsolète. Une annexe en parle en détail, mais le x87 utilisait une pile de registre totalement inhabituelle, que les compilateurs ne pouvaient pas utiliser convenablement. Aussi, lors du passage au 64 bits, Intel et AMD en ont profité pour se débarrasser du x87 et le remplacer par quelque chose de plus moderne. Vu que les extensions SIMD faisaient déjà des calculs flottants, elles l'ont remplacé. Et même dans le processeur, dans sa microarchitecture, le remplacement a été total. Le processeur intègre une ou plusieurs unités de calcul spécialisées dans les instructions SIMD. Et elles remplacent la FPU, totalement. Typiquement, il y a au minimum : * une unité SIMD spécialisée dans les additions entières ; * une unité SIMD spécialisée dans les multiplications entières ; * une unité SIMD spécialisée dans les additions flottantes ; * une unité SIMD spécialisée dans les multiplications flottantes. * éventuellement une unité SIMD annexe pour les autres instructions SIMD, et elles sont nombreuses. Les unités SIMD étaient parfois mutualisées avec la FPU, c'est à dire que la FPU x87 était en réalité une sous-partie de l'unité SIMD. Après tout, l'unité SIMD contient plusieurs additionneurs flottants 32/64 bits, idem pour les multiplieurs flottants. Alors autant en profiter pour leur faire faire des calculs flottants normaux, ceux de la FPU x87. ==Les processeurs x86 d'Intel== Nous allons voir les processeurs Intel à part des processeurs AMD. La raison à cela est que les architectures Intel et AMD ont progressivement évolué, chacune se basant sur la précédente et l'améliorant. Il n'y a pas eu de cassure entre microarchitectures AMD, qui sont chacune la suite de la précédente. Il est donc préférable de voir les architectures AMD dans l'ordre chronologique. Par contre, Intel a eu une gigantesque cassure, avec le processeur Pentium 4. Son architecture se démarquait fortement du Pentium 3, mais elle n'a pas convaincu et a été abandonnée avec les processeurs suivants. Ce qui fait nous verrons l'architecture du Pentium 4 à part. Nous allons commencer avec les processeurs Intel. N'y voyez pas du favoritisme derrière ce choix, la justification est toute autre. Si je commence par Intel, c'est pour commencer avec les Pentium 1 et 2, qui sont superscalaires, mais sans exécution dans le désordre. L'absence d'exécution dans le désordre les rend bien plus simples à étudier que les autres, ce qui en fait un bon point de départ pour ce chapitre. Les autres processeurs x86 sont tous avec à exécution dans le désordre, à une exception qu'on verra dans le chapitre suivant. AMD n'a pas produit de processeurs ''in-order'', tous les processeurs produits par AMD intègrent l'exécution dans le désordre. Le Pentium 1 et 2 utilisaient la même architecture, qu'on détaillera dans ce qui suit. Les seules différences importantes étaient la fréquence, le cache, et quelques détails dans le genre. Le Pentium 3 était une nouvelle microarchitecture qui ajoutait l'exécution dans le désordre. Un an et demi plus tard, le Pentium 4 est sorti et a été un échec. Ses performances étaient peu convaincantes face au Pentium 3, et sa consommation énergétique était très importante. La conséquence est que le Pentium 4 et le Pentium 3 ont survécu pendant un long moment, beaucoup de monde préférait acheter un Pentium 3. Intel a alors amélioré les microarchitectures du Pentium 3 et du 4, indépendamment, pendant environ 7 ans. La microarchitecture du Pentium 3 a subit plusieurs micro-évolutions, chacune avec une finesse de gravure différente, afin de satisfaire les consomateurs. Les premeirs Pentium 3 avaient une finesse de gravure de 250 nm, elle a chuté à 65 sur les derniers modèles. L'architecture du Pentium 4 a fait la même chose, pour tenter de corriger ses problèmes de performance et de consommation d'énergie. Les premiers Pentium 4 avaient uen finesse de gravure de 180 nm, elle a elle aussi chutée à 65 sur les derniers modèles. Après l'échec du Pentium 4, les ingénieurs d'Intel ont repris l'architecture P6 et l'ont améliorée fortement, pour donner l'architecture Core. Les micro-processeurs suivants ont fait évoluer cette architecture progressivement, au point où elle ne ressemble plus à l'originale. L'architecture Core a laissé la place à l'architecture Nehalem, puis Sandy Bridge, puis Haswell, puis Skylake, puis Ice Lake, et Golden Cove. Il s'agit de la lignée principale, partant du Pentium 3 et continuant jusqu'à nos jours. Ces microarchitectures ont suivi un motif assez simple, appelé modèle '''tick-tock'''. Chaque microarchitecture était déclinée en deux versions, la seconde ayant une finesse de gravure réduite. En parallèle, Intel a travaillé sur des processeurs basse performance et basse consommation, avec une microarchitecture très différente. Les processeurs Atom de microarchitecture Bonnel, pour être ensuite remplacés par les microarchitectures Silvermont, puis Goldmont et Gracemont. Ces microarchitectures ont évolué en parallèle de la lignée principale, il s'agit d'une lignée secondaire. Le tout est résumé dans ce schéma ci-dessous. [[File:IntelProcessorRoadmap-4v.svg|centre|vignette|upright=2.5|Roadmap des processeurs Intel, qui servira de structure pour la suite du chapitre]] De nos jours, les processeurs Intel utilisent les deux types de micro-architectures en même temps. Les CPU Intel modernes disposent de deux types de coeurs : les coeurs P et le coeurs E. Leur nom signifie "Performance" et "Efficient", qui trahissent leur but. Les coeurs P utilisent la microarchitecture de la lignée principale, qui est conçue pour la performance. Les coeurs E, quant à eux, utilisent les micro-architectures basse consommation de la lignée secondaire. Ceci étant dit, commençons par le commencement, avec le Pentium 1. ===Le Pentium 1/MMX : la double émission entière avec deux pipelines=== Le processeur Pentium d'Intel avait un pipeline de 5 étages : un étage de chargement/prédiction de branchement, deux étages de décodage, un étage d'exécution et un dernier étage pour l'écriture dans les registres. Le Pentium 1 était un processeur double émission, intégrant deux pipelines nommés U et V. Chose importante, les deux pipelines n'étaient pas identiques. Le pipeline U pouvait exécuter toutes les instructions, mais le pipeline V était beaucoup plus limité. Par exemple, seul le pipeline U peut faire des calculs flottants, le pipeline V ne fait que des calculs entiers et des branchements. Les deux pipelines disposaient d'une unité de calcul entière, identique dans les deux pipelines. Mais le pipeline U incorporait un circuit multiplieur/diviseur et d'un ''barrel shifter''. L'unité flottante était sur le port d'émission du pipeline U, idem pour l'unité de calcul vectoriel MMX sur le Pentium MMX. Les deux pipelines avaient chacun une unité de calcul d'adresse, mais ils n'étaient pas identiques : celle du pipeline V ne gérait que l’instruction LEA, celle du pipeline U gérait tous les calculs d'adresse. {|class="wikitable" |- ! Pipeline U ! Pipeline V |- | ALU entière | ALU entière |- | Multiplieur/diviseur | |- | ''Barrel Shifter'' | |- | AGU complexe | AGU simple (opération LEA) |- | FPU | |- | Unité SIMD | |} Les deux pipelines géraient les opérations bit à bit, les additions, les soustractions et les comparaisons. Les autres instructions ne sont exécutables que dans le pipeline U. Pour être plus précis, les deux pipelines supportaient les instructions suivantes, ce qui fait qu'on pouvait en faire deux en même temps : * Les instructions arithmétiques INC, DEC, ADD, SUB ; * l'instruction de comparaison CMP ; * les instructions bit à bit AND, OR, XOR ; * l'instruction de calcul d'adresse LEA ; * l'instruction MOV (dépend du mode d'adressage) ; * les instructions de gestion de la pile PUSH et POP (dépend du mode d'adressage) ; * l'instruction NOP, qui ne fait rien. Il faut noter qu'il y a cependant quelques restrictions, beaucoup de paires d'instructions sont interdites. La plupart interdisent au pipeline V de faire quoique ce soit quand une opération particulière est émise dans le pipeline U. Par exemple, si le pipeline U exécute une multiplication ou une division, le processeur ne peut pas exécuter une opération dans le pipeline V. Et c'est pareil avec les branchements : si un branchement est émis dans le pipeline U, l'instruction suivant le branchement n'est pas émise dans le pipeline V, pour éliminer les dépendances de contrôle. De même, si le pipeline U exécute une opération flottante, le pipeline V ne pourra rien exécuter. La seule exception est l'instruction FCXH, qui échange deux registres flottants. [[File:Intel Pentium arch.svg|centre|vignette|upright=2.5|Microarchitecture de l'Intel Pentium MMX. On voit que certaines unités de calcul sont dupliquées.]] Un choix assez intéressant a été fait pour le cache de données. Nous avions vu dans le chapitre sur les CPU superscalaires que la superscalarité a un impact sur l'unité mémoire. Il y a alors deux implémentations. La première ne fait rien, l'unité mémoire ne change pas, et le processeur ne peut pas faire deux accès mémoire simultanés. La seconde duplique l'unité mémoire et les ports de lecture/écriture du cache, ce qui autorise des accès mémoire simultanés. Le Pentium 1 utilise une solution intermédiaire. Les ingénieurs d'Intel étaient partis à la base sur un cache totalement double port, pour obtenir des performances maximales. Mais diverses simulations et observations les ont fait changer d'avis. Les simulations ont montré qu'il est "rare" que les deux pipelines aient besoin de lire/écrire dans le cache en même temps. Et ils ont optimisé le cache de donnée pour en tenir compte. Le cache de données est partiellement multiport : simple port sur certains aspects, double port sur d'autres. Le cache est un cache splité, à savoir que les données et les ''tags'' sont séparés dans des mémoires séparées. La mémoire pour les ''tags'' est multiport, ce qui permet d'interroger les ''tags'' du cache deux fois par cycle. Un port est relié au pipeline u, un autre au pipeline V. Mais pour les données, le cache n'a qu'un seul port pour lire/écrire des données. Impossible donc de lire deux données en même temps, pour alimenter les deux pipelines. Il utilise cependant 8 banques permet d'accélérer des accès mémoire proches dans le temps, mais dans des cycles d'horloge différents. Entre les deux mémoires, il y a un circuit qui détecte les conflits, à savoir les situations où les deux pipelines accèdent en même temps au cache. S'ils veulent lire/écrire une donnée dans le même cycle, ce qui est impossible avec un seul port, le pipeline U a la priorité et le pipeline V attend le cycle suivant. Le circuit détecte aussi les conflits de banque, à savoir quand un pipeline accède à une banque en cours d'accès par l'autre pipeline (on rappelle qu'un accès au cache prend plusieurs cycles). Le circuit détecte aussi certaines dépendances mémoires, à savoir des accès consécutifs à la même adresse. : La TLB du processeur est aussi totalement double port. ===La microarchitecture P6 (Pentium 3) : l'exécution dans le désordre=== Le Pentium 3 utilisait la '''microarchitecture P6''', qui a été dérivée dans de nombreuses variantes, dont les finesses de gravure n'étaient pas les mêmes. Il introduit une exécution dans le désordre simple, avec un ''scheduler'' centralisée, avec renommage dans le désordre dans le ROB (tampon de ré-ordonnancement), commandé par une table d'alias. C'était un processeur triple émission, soit une instruction de plus que la double émission du Pentium 1. [[File:P6 func diag.png|centre|vignette|upright=2|P6 func diag]] Le pipeline passe de 5 étage sur le Pentium à 14 - 12 étages, dont le détail est le suivant : * Prédiction de branchement, deux cycles ; * Chargement des instructions, trois cycles ; * Décodage de l'instruction, deux cycles ; * Renommage de registre, un cycle ; * Copie des opérandes dans le tampon de ré-ordonnancement (lié au renommage de registre dans le ROB) ; * Dispath dans ou depuis la station de réservation. * Exécution de l'instruction ; * Écriture du résultat dans le ROB ; * Écriture dans le banc de registre physique. Les instructions sont chargées par blocs de 16 octets, avec un système de fusion de blocs pour gérer les instructions à cheval sur deux blocs. Lors d'un branchement, deux blocs doivent être chargés si l'instruction de destination n'est pas alignée sur 16 octets et cela cause un délai de un cycle d'horloge. Le décodage des instructions x86 était géré par plusieurs décodeurs. Il y avait trois décodeurs : deux décodeurs simples, et un décodeur complexe. Les décodeurs simples décodaient les instructions les plus fréquentes, mais aussi les plus simples, qui étaient décodées en une seule micro-opération. Les instructions CISC complexes étaient gérées uniquement par le décodeur complexe, basé sur un microcode, qui pouvait fournir jusqu'à 4 micro-opérations par cycle. Le tout est résumé avec la règle 4-1-1. La toute première instruction chargée depuis la file d'instruction va dans le premier décodeur simple. Si jamais le décodeur ne peut pas décoder l'instruction, l'instruction est redirigée dans un autre décodeur, avec un délai d'un cycle d'horloge. Les stations de réservations étaient regroupées dans une structure centralisée, en sortie de l'unité de renommage. Elles avaient 4 ports d'émission. En réalité, 5 dont deux pour les écritures (un pour l'adresse à transmettre, un pour la donnée). Le tout avait une répartition moitié-moitié pour les calculs et les accès mémoire. Chaque port d'émission pour les calculs était relié à une ALU et une FPU/unité SIMD. Le tableau suivant résume tout. Vous remarquerez la présence de plusieurs additionneurs flottants. Le premier exécute les opérations x87, l'autre les opérations SIMD. Les opérations SIMD se font sur des registres de 128 bits, mais elles sont en réalité cassées en deux µops, chacune travaillant sur 64 bits. {|class="wikitable" |+ Pentium 3 |- ! !! Port d'émission 1 !! Port d'émission 2 !! Port d'émission 3 !! Port d'émission 4 !! Port d'émission 5 |- ! rowspan="3" | µops entières | ALU entière || ALU entière || LOAD || STORE adresse || STORE donnée |- | LEA || ALU SIMD MMX || || || |- | Multiplieur entier || || || || |- ! rowspan="3" | µops flottantes | x87 FADD || FADD 64 bits (SIMD) || || |- | FMUL (x87 et 64 bits) || || || |- | FDIV || || || |} Les premiers Pentium 3 n'avaient pas de cache L2 dans le processeur, celui-ci était sur la carte mère. Mais il a été intégré dans le processeur sur la seconde version du Pentium 3, la version Coppermine. Le Pentium 3 a servi de base aux microarchitectures d'Intel qui ont suivi. Les changements à chaque nouvelle génération sont assez mineurs : la prédiction de branchement est améliorée, la taille des stations de réservation et du ROB augmente, idem avec les autres structures liées à l'exécution dans le désordre. Les processeurs Intel ont conservé un ''scheduler'' centralisée, alors qu'AMD utilise une autre méthode, comme nous allons le voir dans ce qui suit. Les seuls changements notables sont est le passage à un renommage dans le ROB à un renommage à banc de registre physique, ainsi que l'introduction du cache de micro-opération. Et ce sont des modifications qu'AMD a aussi faites, celle-ci étant clairement une bonne idée pour toutes les micro-architectures avec un budget en transistor suffisant. Il est intéressant de garder cela en tête, car une bonne partie des améliorations de chaque micro-architecture proviendra de là. ===La microarchitecture Core : désambiguïsation mémoire, macro-fusion, ''stack engine'', ''Fetch Input Queue''=== La '''microarchitecture Core''' fait suite au Pentium 4, mais reprend en fait beaucoup d’éléments du Pentium 2 et 3. Elle utilise la station de réservation unique avec renommage dans le ROB, provenant du Pentium 2/3. A part ça, les améliorations sont assez diverses : un cache L2, l'arrivé de la désambiguïsation mémoire, une ''Fetch Input Queue'' et un ''stack engine'' primitif. Le processeur introduit aussi la macro-fusion qui fusionne une instruction de test et le branchement qui suit en une seule micro-opération. beaucoup d'optimisations importantes, donc. [[Image:Intel Core2 arch.svg|centre|vignette|upright=2|Intel Core microarchitecture]] Il y a quelques modifications au niveau de l'unité de chargement. La file d'instruction a toujours ce système de fusion de blocs, sauf que les branchements ne causent plus de délai d'un cycle lors du chargement. La file d'instruction est suivie par un circuit de prédécodage qui détermine la taille des instructions et leurs frontières, avant de mémoriser le tout dans une file de 40 instructions. La station de réservation dispose de 5 ports d'émission, dont un pour les lectures et un pour les écritures. Les deux sont reliées à une ''Load/Store Queue'', appelée ''Memory Ordering Buffer'', elle-même reliée au cache de données par un port de lecture et un port d'écriture. Les ports de lecture/écriture du cache font 128 bits, pour gérer naturellement les instructions LOAD/STORE dans les registres SIMD. Les trois ports restants sont chacun reliés à des ALU entières et des unités flottantes/SIMD (pour l'extension SSE). Le multiplieur entier est relié au second port d'émission. L'additionneur flottant SIMD/SSE est connecté au port 1, le multiplieur/diviseur flottant SIMD/SSE est connecté au port 0, une unité SIMD annexe est connectée sur chaque port. {|class="wikitable" |+ Microarchitecture Core (Penryn et Merom) |- ! !! Port d'émission 1 !! Port d'émission 2 !! Port d'émission 3 !! Port d'émission 4 !! Port d'émission 5 |- ! rowspan="3 | µops entières/mémoire | ALU entière || ALU entière || ALU entière || LOAD || STORE |- | ''Barrel shifter'' || Multiplieur entier || ''Barrel shifter'' || || |- |- | || || ALU branchements || || |- ! rowspan="3 | µops flottantes et SIMD | FMUL et FDIV || FADD || || |- | ALU SIMD entière (128 bits) || ALU SIMD entière (128 bits) || ALU SIMD entière (128 bits) || || |- | || MUL SIMD entière (128 bits) || || || |} Le résultat que le processeur peut émettre un mix d'opérations flottantes et entière assez varié, avec un mix allant de trois opérations entières à trois opérations flottantes, avec tous les intermédiaires. Le fait de mettre les ALU SIMD sur des ports différents permet d'émettre une addition et une multiplication flottante/SIMD simultanément. ===La microarchitecture Nehalem : un vrai ''Loop Stream Detector''=== Les microarchitectures '''Nehalem''' et '''Westmere''' n'introduisent pas d'optimisation majeure. A la rigueur, ils introduisent une prédiction de branchement à deux niveaux, et une macro-fusion plus complète. Les unités de calcul sont assez semblables, de même que leur répartition sur les ports d'émission. Elle a introduit cependant un vrai ''Loop Stream Detector'' (LSD). Pour rappel, le LSD qui permet d'exécuter les boucles directement depuis la file de µops. Le LSD reconnait les petites boucles, qui tiennent dans la file de µops, et lit les µops adéquates depuis celle-ci. Les instructions de la boucle n'ont donc pas à être chargée et décodées. La microarchitecture Core avait une sorte de pseudo-''Loop Stream Detector'', mais il était localisé dans la file d'instruction. Il était donc moins performant. Ce pseudo-''Loop Stream Detector'' permettait de ne pas charger les instruction x86, mais elles devaient quand même être décodées et passer par la file de µops. Avec Nehalem, ce n'est plus le cas. [[File:Intel Nehalem arch.svg|centre|vignette|upright=2.5|Intel Nehalem.]] ===La microarchitecture Sandy Bridge : le cache de µops=== Les microarchitectures '''Sandy Bridge''' and '''Ivy Bridge''' ont introduit le renommage à banc de registre physique et l'ajout d'un cache de micro-opérations. L'ajout du cache de micro-opérations est une optimisation particulièrement rentable, particulièrement pour le complexe jeu d’instruction x86. Avec ce cache, les décodeurs servent surtout à alimenter le cache de micro-opérations, parfois décoder des instructions en-dehors de boucles, pas plus. Intel a d'ailleurs reflété ce fait dans sa terminologie. Intel distingue deux voies de chargement : le ''legacy pipeline'' et le cache de micro-opérations. L'unité de chargement et les décodeurs sont regroupés dans la voie du ''legacy pipeline''. Sur les processeurs modernes, les décodeurs ne servent que pour 10 à 20% des micro-opérations exécutées, le reste est lu depuis le cache de µops. Cependant, Sandy Bridge a un cache de µops assez limité, qui ne permet pas d’atteindre ces chiffres. De nombreuses instructions ne peuvent pas être mémorisées dans le cache de µops, les limitations quand à son utilisation sont assez importantes. Par exemple, le processeur ne consulte pas le cache de µops à chaque cycle, il ne démarre son utilisation qu'après un branchement (donc une boucle potentielle) et cesse de l'utiliser au premier défaut de cache (dans le cache de µops). Le cache de micro-opérations est complété avec un ''Loop Stream Detector'', placé après le cache en question. Les décodeurs et le cache de micro-opérations alimentent une file de micro-opérations, située juste avant l'étage de renommage de registres. La file de micro-opérations sert en quelque sorte de tampon entre l'étage de "décodage" et celui de renommage. Le ''Loop Stream Detector'' utilise cette file de micro-opérations comme d'un cache lorsqu'une boucle est détectée. Les micro-opérations de la boucle sont lue depuis la file de micro-opérations, pour être envoyée au renommeur de registres. L'avantage est que le cache de micro-opérations et/ou les décodeurs sont mis en pause et clock-gatés lorsqu'une boucle s'exécute, ce qui réduit la consommation du processeur. Le ''Loop Stream Detector'' et le cache de micro-opération ont globalement le même effet : désactiver tout ce qui est avant, le ''Loop Stream Detector'' appliquant cette méthode au cache de micro-opération lui-même. Pour le reste, ''Sandy Bridge'' n'innove pas trop. Les unités d'exécution sont globalement les mêmes, leur répartition sur les port est peu changée. LA seule différence intéressante est que ''Sandy Bridge'' n'a plus une unité mémoire dédiée aux LOAD et une aux STORE. Elle en a deux qui peuvent faire indifféremment LOAD et STORE. Le processeur peut donc émettre deux LOAD simultanément, ce qui entraine un gain en performance appréciable. ===Les microarchitectures Haswell et Broadwell=== Les architectures '''Haswell''' et '''Broadwell''' ont ajouté quelques unités de calcul, élargit la sortie du cache de micro-opérations. Un port d'émission pour opération entières a été ajouté, de même qu'un port pour les accès mémoire. Le processeur passe donc à 8 ports d'émission, ce qui permet d'émettre jusqu'à 8 micro-opérations, à condition que le cache de micro-opération suive. Pour le reste, le processeur est similaire aux architectures précédentes, si ce n'est que certaines structures grossissent. {|class="wikitable" |+ Microarchitecture Haswell et Broadwell |- ! !! Port d'émission 1 !! Port d'émission 2 !! Port d'émission 3 !! Port d'émission 4 !! Port d'émission 5 !! Port d'émission 6 |- ! rowspan="3" | µops entières/mémoire | ALU entière || ALU entière || ALU entière || ALU entière || LOAD/STORE || LOAD/STORE |- | ''Barrel shifter'' || Manipulation de bits || ''Barrel shifter'' || Manipulation de bits || || |- | || Multiplieur entier || ALU branchements || || || |- ! rowspan="4" | µops flottantes et SIMD | SIMD bit à bit (256 bits) || SIMD bit à bit (256 bits) || SIMD bit à bit (256 bits) || || || |- | || ALU SIMD entière (256 bits) || ALU SIMD entière (256 bits) || || || |- | FMUL + FMA (256 bits) || FMUL + FMA (256 bits) || || || || |- | FDIV || FADD || || || || |} ===La microarchitecture Skylake : la fin de la station de réservation centralisée=== L'architecture '''Skylake''' a eu une longévité hors du commun, avec près de 6 ans d’utilisation ininterrompue. Elle a été la concurrentes des microarchitectures Zen 1, Zen 2 et Zen 3 d'AMD. La microarchitecture ''Skylake'' est une microarchitecture capable de décoder/renommer 4 instructions par cycle, elle peut émettre 6 µops par cycle grâce au cache de µops. Elle a été déclinée en plusieurs microarchitectures légèrement différentes les unes des autres, nommés '''''Kaby Lake''''', '''''Coffee Lake''''', '''''Comet Lake'''''. Un changement extrêmement important concerne la station de réservation centralisée, qui ne l'est plus sur Skylake. Elle est scindée en deux stations de réservations : une pour les µops mémoire, et une autre pour le reste. Mien de rien, c'est à ce moment que la tendance "Intel = station de réservation centralisée " a commencée à s'adoucir. Intel est longtemps resté sur cette organisation avec un '''''Math Scheduler''''' d'un côté, et un '''''MEM scheduler''''' de l'autre. Pour le reste, les améliorations sont mineures. A la rigueur, l'unité de renommage de registre ajoute des optimisations comme l'élimination des MOV, les idiomes liés aux opérations avec zéro, etc. ===La microarchitecture ''Sunny Cove'' : la station de réservation mémoire est scindée=== Après Skylake, les microarchitecture d'Intel ont changé de dénomination. Elles sont maintenant nommées non pas avec des noms de lacs, mais ont un nom qui finit par Cove : ''Sunny Cove'', ''Golden Cove'', etc. La seule exception à cette règle est la microarchitecture '''''Palm Cove''''' était un ''die shrink'' de Skylake, ce qui fait qu'elle est à part de celles qui vont suivre, qui sont vraiment des microarchitectures différentes. La microarchitecture qui suit immédiatement skylake était la microarchitecture '''''Sunny Cove'''''. La microarchitecture''Sunny Cove'' suit la tendance entamée avec Skylake de casser la station de réservation principale en plusieurs stations de réservations plus petites. Cette fois-ci c'est la station de réservation pour les µops mémoire qui est scindée en deux une pour les lectures et une pour les écritures. La microarchitecture ''Sunny Cove'' passe de quadruple émission à la pentuple émission. Précisément, l'unité de renommage de registres est maintenant capable de renommer 5 µops par cycle. De plus, l'unité de renommage devient plus performante. Ses capacités de ''MOV elimination'' ont été améliorées, et elle devient capable de reconnaitre certains idiomes, comme celui qui met à zéro un registre en le XORant avec lui-même. ''Sunny Cove'' était au départ prévue pour les PC ''desktop'', mais sa production a eu de nombreux problèmes. Elle était censée être produite avec une technologie de gravure 10nm d'Intel lui-même, qui a cependant eu de nombreux problèmes de production. Au final, ''Sunny Cove'' et ses variantes n'ont existées que dans des CPU mobile, basse performance et basse consommation. Elle a été déclinée en deux versions : '''''Willow Cove''''' a un cache retravaillé, alors que '''''Cypress Cove''''' est l'équivalent de ''Sunny Cove'' mais repassé à une technologie de gravure de 14nm. Les deux microarchitecture ont été utilisées sur les plateformes dites '''''Ice Lake''''' et '''''Tiger Lake'''''. ===La microarchitecture ''Golden Cove'' : un ''Fetch'' doublé=== La microarchitecture '''Golden Cove''' a suivi ''Sunny Cove''. Les microarchitectures suivantes, ''Redwood Cove'' et ''Raptor Cove'', sont des modifications mineures de ''Golden Cove''. ''Golden Cove'' altère les décodeurs et l'unité de chargement. Sur toutes les générations précédentes, on reste sur une unité de chargement qui charge 16 octets à la fois. Une telle stagnation sur les unités de chargement et de décodage s'explique encore une fois par la présence du cache de micro-opération fait que ce n'est pas trop un problème. Tout ce qui précède le cache de micro-opérations n'a pas de raison d'évoluer, car ce cache est très puissant. Mais cela change avec ''Golden Cove''. Golden Cove double la taille du chargement qui passe à 32 octets. Le processeur peut décoder 6 instructions par cycle, et en émettre 6 à destination des ''schedulers''s. Il s'agit donc de processeurs superscalaires très larges, ce qui est la norme de nos jours et le restera pendant longtemps. ''Golden Cove'' conserve les trois ''schedulers'' séparées de ''Sunny Cove'', savoir : pour les instructions entières/flottantes, pour les lectures, pour les écritures. [[File:Golden Cove.png|centre|vignette|upright=3|Golden Cove]] Niveau unités de calcul, peu de changements avec ''Sunny Cove'', si ce n'est une ALU entière en plus. {|class="wikitable" |- ! Port d'émission n°1 !! Port d'émission n°2 !! Port d'émission n°3 !! Port d'émission n°4 !! Port d'émission n°5 |- | ALU entière || ALU entière || ALU entière || ALU entière || ALU entière |- | ''Barrel shifter'' || Multiplieur || Multiplieur || ''Barrel shifter'' || |- | Branchements || Diviseur || || Branchements || |} ===La microarchitecture ''Lion Cove'' : la scission du ''math scheduler''=== La microarchitecture '''''Lion Cove''''' poursuit la tendance à scinder la station de réservation. La station de réservation pour les opérations entières/flottantes est maintenant scindée en deux : une pour les µops entières, une autre pour les µops SIMD/flottantes. Une autre modification, très liée à la précédente, est que le renommage de registre est lui aussi scindé. Les registres SIMD/flottants sont maintenant renommé indépendamment des registres généraux/entiers. Les raisons sont certainement que cela simplifie grandement la conception du processeur, en séparant les pipelines entiers et SIMD, surtout que les opérations entières et SIMD sont forts différentes : instructions 2-opérandes d'un côté, 2 à 3-opérandes pour le SIMD ; présence de techniques de ''masking'' pour le SIMD, mais pas pour les opérations entières, etc. Pour le reste, le processeur de 6 à 8 voies d'émission, et l'unité de chargement peut maintenant charger 48 octets, au lieu de 32 auparavant. Des ALU entières et SIMD ont été rajoutés. L'unité d'émission pour les opérations entières dispose de 6 ports d'émission, alors que celle pour les opérations SIMD n'en a que 4. {|class="wikitable" |+ Microarchitecture Haswell et Broadwell |- ! !! Port d'émission 1 !! Port d'émission 2 !! Port d'émission 3 !! Port d'émission 4 !! Port d'émission 5 !! Port d'émission 6 |- ! rowspan="3" | µops entières/mémoire | ALU entière || ALU entière || ALU entière || ALU entière || ALU entière || ALU entière |- | Branchements || ''Barrel shifter'' || Branchements || ''Barrel shifter'' || Branchements || ''Barrel shifter'' |- | || Multiplieur entier || || Multiplieur entier || || Multiplieur entier |} ==Les processeurs x86 d'AMD== Les architectures Intel ont évolué progressivement, sans grandes cassure. Il y a une continuité presque ininterrompue entre l'architecture du Pentium 2 et les architectures modernes. Intel a fait des améliorations mineures à chaque nouvelle micro-architecture, si on omet le passage à un renommage à banc de registre physique et l'ajout du cache de micro-opération. A l'opposé, les architectures AMD ont eu de nombreuses cassures dans la continuité où AMD a revu sa copie de fond en comble. Étudier ces architectures demande de voir trois choses séparément : le ''front-end'' qui regroupe l'unité de chargement et les décodeurs, le ''back-end'' qui gère l'exécution dans le désordre et les unités de calcul, et le sous-système mémoire avec les caches et la ''Load Store Queue''. Leur étude sera plus ou moins séparée dans ce qui suit, pour chaque classe d'architecture. ===La première génération de CPU AMD : les architectures K5, K6, K7, K8 et K10=== La première génération de processeurs AMD est celle des architectures K5, K6, K7, K8 et K10. Il n'y a pas de K9, qui a été abandonné en cours de développement. Les processeurs K5 et K6 portent ce nom au niveau commercial. Par contre, les processeurs d'architecture K7 sont aussi connus sous le nom d''''AMD Athlon''', les AMD K8 sont connus sous le nom d''''AMD Athlon 64''', et les architecture K10 sont appelées les '''AMD Phenom'''. Comme le nom l'indique, l'architecture K8 a introduit le 64 bits chez les processeurs AMD. Elles ont une architecture assez similaire pour ce qui est du chargement et des caches. Toutes disposent d'au minimum un cache L1 d'instruction et d'un cache L1 de données. Le K5 n'avait que ces caches, mais un cache L2 a été ajouté avec le K7, puis un L3 avec le K10. L'AMD K5 avait une TLB unique, mais les processeurs suivants avaient une TLB pour le L1 d'instruction et une autre pour le L1 de données. Idem pour le cache L2, avec deux TLB : une pour les données, une pour les instructions. Les caches L1/L2 sont de type exclusifs, à savoir que les données dans le L1 ne sont pas recopiées dans le L2. Le cache L2 est précisément un cache de victime, qui mémorise les données/instructions, évincées des caches L1 lors du remplacement des lignes de cache. L'introduction du cache L2 a entrainé l'ajout de deux TLB de second niveau : une L2 TLB pour les données et une autre pour les instructions. Les architectures K8 et K10 ont ajouté un cache L3, avec un accès indirect à travers l'interface avec le bus. : L'AMD K7 originel, aussi appelée Athlon classique, n'avait pas de cache L2, mais celui-ci était placé sur la carte mère et fonctionnait à une fréquence moitié moindre de celle du CPU. L'Athlon Thunderbird, puis l'Athlon XP, ont intégré le cache L2 dans le processeur. {|class="wikitable" |- ! Architecture AMD ! colspan="5" | Caches |- | rowspan="2" | K5 | L1 instruction || L1 données || colspan="3" | |- | colspan="2" | TLB unique || colspan="3" | |- | colspan="4" | |- | rowspan="2" | K6 | L1 instruction || L1 données || colspan="3" | L2 unifié |- | TLB L1 instruction || TLB L1 données || colspan="3" | |- | colspan="6" | |- | rowspan="2" | K7, K8 | L1 instruction || L1 données || colspan="2" | L2 unifié || |- | TLB L1 instruction || TLB L1 données || TLB L2 instruction || TLB L2 données || |- | colspan="6" | |- | rowspan="2" | K10 | L1 instruction || L1 données || colspan="2" | L2 unifié || L3 |- | TLB L1 instruction || TLB L1 données || TLB L2 instruction || TLB L2 données || |} Fait important, les architectures K5 à K10 utilisent la technique du '''prédécodage''', où les instructions sont partiellement décodées avant d'entrer dans le cache d'instruction. Le prédécodage facilite grandement le travail des décodeurs d'instruction proprement dit. Par contre, le prédécodage prend de la place dans le cache L1 d'instruction, une partie de sa capacité est utilisé pour mémoriser les informations prédécodées. C'est donc un compromis entre taille du cache et taille/rapidité des décodeurs d'instruction. Sur les architectures K5 et K6, le prédécodage précise, pour chaque octet, si c'est le début ou la fin d'une instruction, si c'est un octet d'opcode, en combien de micro-opérations sera décodée l'instruction, etc. A partir de l'AMD K7, le prédécodage reconnait les branchements inconditionnels. Lorsqu'un branchement inconditionnel est pré-décodé, le pré-décodage tient compte du branchement et continue le pré-décodage des instructions à partir de la destination du branchement. Le système de prédécodage est abandonnée à partir de l'architecture Bulldozer, qui suit l'architecture K10. La prédiction de branchement de ces CPU tire partie de ce système de pré-décodage, à savoir que les prédictions de branchement sont partiellement mémorisées dans les lignes de cache du L1 d'instruction. Par exemple, l'AMD K5 se passe de ''Branch Target Buffer'' grâce à cela. Si une ligne de cache contient un branchement, elle mémorise l'adresse de destination de ce branchement, en plus des bits de pré-décodage. Si il y a plusieurs branchements dans une ligne de cache, c'est l'adresse de destination du premier branchement pris dans cette ligne de cache qui est mémorisée. Un défaut de cette approche est que si le branchement n'est pas dans le L1 d'instruction, aucune prédiction de branchement ne peut être faite et le préchargement ne peut pas fonctionner. C'est une limitation que n'ont pas les BTB découplées du cache L1 : elles peuvent prédire un branchement qui a été évincé dans le L2 ou le L3, tant que l'entrée associée est dans le BTB. Les prédictions peuvent même servir à précharger les instructions utiles. [[File:Comparaison du chargement de l'AMD K5 et K6.png|centre|vignette|upright=2|Comparaison du chargement de l'AMD K5 et K6]] Au niveau du décodage, on trouve de nombreuses différences entre les premières architectures AMD. L'AMD K5 contient 4 décodeurs hybrides, afin de décoder 4 instructions par cycles. Le K5 a quatre décodeurs simples couplés à 4 décodeurs complexes avec chacun un accès au micro-code. Une instruction peut donc passer par a donc deux voies de décodage : un décodage rapide et simple pour les instructions simples, un décodage lent et passant par le microcode pour les instructions complexes. Pour décoder 4 instructions, les deux voies sont dupliquées en 4 exemplaires, ce qui a un cout en circuits non-négligeable. L'AMD K6 utilise moins de décodeurs et ne peut que décoder deux instructions à la fois maximum. Par contre, il fournit en sortie 4 micro-opérations. Il intègre pour cela deux décodeurs simples, un décodeur complexe et un décodeur micro-codé. Un décodeur simple transforme une instruction simple en une ou deux micro-opérations. Il est possible d'utiliser les deux décodeurs simples en même temps, afin de fournir 4 micro-opérations en sortie du décodeur. Les deux autres décodent une instruction complexe en 1 à 4 micro-opérations. Si jamais la ou les deux instructions sont décodées en 1, 2 ou 3 micro-opérations, les micro-opérations manquantes pour atteindre 4 sont remplies par des NOPs. Pour le K7 et au-delà, le processeur dispose de décodeurs séparées pour les instructions micro-codées de celles qui ne le sont pas. Le processeur peut décoder jusqu’à 3 instructions par cycle. Le décodage d'une instruction microcodée ne peut pas se faire en parallèle du décodage non-microcodé. C'est soit le décodeur microcodé qui est utilisé, soit les décodeurs câblés, pas les deux en même temps. Le décodage d'une instruction prend 4 cycles. Les instructions non-microcodées sont décodées en une seule micro-opération, à un détail près : le CPU optimise la prise en charge des instructions ''load-up''. La différence entre le K6 et le K7 s'explique par des optimisations des instructions ''load-up''. Sur le K6, les instructions ''load-up'' sont décodées en deux micro-opération : la lecture en RAM, l'opération proprement dite. Mais sur le K7, une instruction ''load-up'' est décodée en une seule micro-opération. En conséquence, les décodeurs simples sont fortement simplifiés et le décodeur complexe disparait au profit d'un microcode unique. [[File:Décodage sur le K5 et le K5.png|centre|vignette|upright=3|Décodage sur le K5 et le K5]] ====Les micro-architectures K5 et K6 d'AMD==== Les deux premières architectures étaient les architectures K5 et K6, l'architecture K6 ayant été déclinée en quatre versions, nommées K6-1, K6-2, et K-3, avec une version K6-3 bis. Elles sont regroupées ensemble car elles ont beaucoup de points communs. Par exemple, tout ce qui a trait au chargement et au cache était similaire, de même que les unités de calcul. Les deux architectures avaient n'avaient pas de cache L2 et devaient se contenter d'un cache L1 d'instruction et d'un cache L1 de données. L'AMD K5 incorpore une TLB unique, alors que le K6 utilise des TLB séparées pour le cache d'instruction et le cache de données. Une différence entre l'architecture K5 et K6 est que la première utilise des caches normaux, alors que la seconde utilise des ''sector caches''. Les deux architectures disposaient des unités de calcul suivantes : deux ALU entières, une FPU, deux unités LOAD/STORE pour les accès mémoire, une unité de branchement et une ou plusieurs unités SIMD. Une organisation classique, donc. Pour les unités entières, il y avait deux ALU simples, un ''barrel shifter'' et un diviseur. Il n'y a pas d'erreur, le processeur incorpore un circuit diviseur, mais pas de circuit multiplieur. La raison est que la multiplication est réalisée par la FPU ! En effet, le multiplieur flottant de la FPU intègre un multiplieur entier pour multiplier les mantisses, qui est utilisé pour les multiplications entières. La même technique a été utilisée sur l'Atom, comme vu plus haut. Le tout était alimenté par deux ports d'émission, appelés ports X et Y. Sur l'architecture K5, le ''barrel shifter'' et le diviseur sont des ports différents. {|class="wikitable" |+ AMD K5 |- ! Port X ! Port Y |- | ALU simple | ALU simple |- | ''Barrel Shifter'' | Diviseur |} Sur l'architecture K6, le ''barrel shifter'' et le diviseur sont sur le même port. {|class="wikitable" |+ AMD K6 |- ! Port X ! Port Y |- | ALU simple | ALU simple |- | | ''Barrel Shifter'' |- | | Diviseur |} Niveau unités mémoire, le K5 avait deux unités LOAD/STORE, chacune capable de faire lecture et écriture. Par contre, la ''store queue'' n'a qu'un seul port d'entrée, ce qui fait que le processeur peut seulement accepter une écriture par cycle. Le processeur peut donc émettre soit deux lectures simultanées, soit une lecture accompagnée d'une écriture. Impossible d'émettre deux écritures simultanées, ce qui est de toute façon très rare. L'architecture K6 utilise quant à elle une unité LOAD pour les lectures et une unité STORE pour les écritures. Ce qui permet de faire une lecture et une écriture par cycle, pas autre chose. Niveau unités SIMD, l'architecture K7 n'avait qu'une seule unité SIMD, placée sur le port d'émission X. L'architecture K8 ajouta une seconde unité SIMD, sur l'autre port d'émission entier. De plus, trois ALU SIMD ont été ajoutées : un décaleur MMX, une unité 3DNow!, une unité mixte MMX/3DNow. Elles sont reliées aux deux ports d'émission entier X et Y ! Elles ne sont pas représentées ci-dessous, par souci de simplicité. [[File:Unité de calcul des processeurs AMD K5 et K6.png|centre|vignette|upright=2|Unité de calcul des processeurs AMD K5 et K6. les unités sur la même colonnes sont reliées au même port d'émission.]] Si les unités de calcul et le chargement sont globalement les mêmes, les deux architectures se différencient sur l'exécution dans le désordre. L'AMD K5 utilise du renommage de registre dans le ROB avec des stations de réservation. Par contre, l'AMD K6 utilise un ''scheduler'' centralisée. De plus, son renommage de registre se fait avec un banc de registre physique. L'architecture AMD K5 utilisait de deux stations de réservation par unité de calcul, sauf pour les deux unités mémoire partageaient une station de réservation unique (deux fois plus grande). Les stations de réservation sont cependant mal nommées, vu que ce sont en réalité des mémoire FIFO. Une micro-opération n'est émise que si elle est la plus ancienne dans la FIFO/station de réservation. Le renommage de registres se faisait dans le tampon de ré-ordonnancement, il n'y avait pas encore de banc de registre physique. Le tampon de ré-ordonnancement faisait seulement 16 instructions. [[File:AMD K5.jpg|centre|vignette|upright=3|AMDK5 Diagramme.]] L'architecture K6 remplace les stations de réservations par un ''scheduler'' centralisée. Les 4 micro-opérations renommées sont écrites dans le ''scheduler'' par groupe de 4, NOP de ''padding'' inclus. le ''scheduler'' centralisé contient 24 micro-opérations, groupées en 6 groupes de 4 micro-opérations, avec potentiellement des NOP dedans suivant le résultat du décodage. L'avantage est que l'implémentation de le ''scheduler'' est simple. le ''scheduler'' centralisée permettait d'émettre 6 micro-opérations en même temps (une par unité de calcul/mémoire). Le renommage de registres se faisait dans le tampon de ré-ordonnancement, il n'y avait pas encore de banc de registre physique. Le processeur utilisait un renommage avec un banc de registre physique. Le banc de registre physique pour les entiers contenait 48 registres, dont 24 étaient des registres architecturaux et 24 étaient des registres renommés. Sur les 24 registres architecturaux, 16 avaient une fonction de ''scratchpad'' que les ''datasheets'' d'AMD ne détaillent pas, les 8 restants étaient les registres généraux EAX, EBX, etc. [[File:AMD K6 Little foot & Modl 6.png|centre|vignette|upright=3|AMD K6 original.]] ====Les micro-architectures K7, K8 et K10 d'AMD==== Les micro-architectures suivantes sont les architectures K7, K8 et K10. Les architectures K7, K8 et K10 sont assez similaires. La différence principale entre le K7 et le K8 est le support du 64 bits. Les apports du K10 sont la présence d'un cache L3, d'une unité de calcul supplémentaire et d'améliorations de la prédiction de branchement. La taille de certains caches a été augmentée, de même que la largeur de certaines interconnexions/bus. L'architecture K7 des processeurs Athlon utilisait le renommage de registre, mais seulement pour les registres flottants, pas pour les registres entiers. Le ranommeg des registres flottants étaient réalisé via un banc de registres physique, ne contenant que des registres flottants. Les architectures K8 et K10 utilisent le renommage de registres pour tous les registres, entiers comme flottants. Par contre, le renommage de registre n'est pas réalisé de la même manière pour les registres entiers et flottants. Les registres entiers sont renommés dans le tampon de ré-ordonnancement, comme c'était le cas sur les architectures Intel avant le Pentium 4. Par contre, les registres flottants sont renommés grâce à un banc de registre physique. Le K8 est donc un processeur au renommage hybride, qui utilise les deux solutions de renommage principales. A partir du K7, le CPU optimise la prise en charge des instructions ''load-up''. Les instructions ''load-op'' sont appelées des macro-opérations dans la terminologie d'AMD, et aussi d'Intel. L'idée est que les instructions ''load-up'' sont décodées en micro-opérations intermédiaires. Elles sont propagées dans le pipeline comme étant une seule micro-opération, jusqu'à l'étage d'émission. Lors de l'émission, les instructions ''load-up'' sont scindées en deux micro-opérations : la lecture de l'opérande, puis l'opération proprement dite. Faire ainsi économise des ressources et optimise le remplissage du tampon de ré-ordonnancement, des ''schedulers''s, des stations de réservation, etc. Le tampon de réordonnancement est combiné avec divers circuits en charge de l'exécution dans le désordre, dans ce qui s'appelle l'''instruction control unit''. Il contient de 72 à, 84 instructions, qui sont regroupées en groupes de 3. Là encore, comme pour le K5 et le K6, le tampon de réordonnancement tient compte de la sortie des décodeurs. Les décodeurs fournissent toujours trois micro-opérations par cycle, quitte à remplir les vides par des NOP. Le tampon de réordonnancement reçoit les micro-opérations, NOP inclus, par groupes de 3, et est structuré autour de ces triplets de micro-opération, y compris en interne. Pour ce qui est de l'unité mémoire, elle est précédée par une file de µops mémoire, qui émet les accès mémoire dans l'ordre du programme. Elle est souvent qualifiée de ''Load-Store Queue'', mais ce n'est pas la terminologie que nous utilisons dans ce cours. La file de micro-opération lire/écrire 64 bits par cycle depuis le cache L1, ce qui fait un seul accès au cache par cycle. La file de µops mémoire est appelée la ''Pre-Cache Queue''. Si au vu de son nom, vous avez deviné qu'il y avait une ''Post-Cache Queue''. Elle mémorise les lectures/écritures émises, mais qui ont levé un défaut de cache L1. Elle ne fait pas partie de la file de µops mémoire proprement dite. Les architectures K7, K8 et K10 ont des unités de calcul très similaires. Concrètement, il y a trois ALU entières, trois unités de calcul d'adresse, et une FPU. Le processeur incorpore, aussi un multiplieur entier, relié sur le port d'émission de la première ALU. La FPU regroupe un additionneur flottant, un multiplieur flottant, et une troisième unité LOAD/STORE pour les lectures/écritures pour les nombres flottants. L'architecture K8 ajoute une unité de manipulation de bit, la K10 un diviseur entier. [[File:Unité de calcul des processeurs AMD K7, K8 et K10.png|centre|vignette|upright=2|Unité de calcul des processeurs AMD K7, K8 et K10]] La manière d'alimenter les ALU en micro-opérations varie un petit peu entre les architectures K7, K8 et K10. Il y a cependant quelques constantes entre les trois. La première est qu'il y a un ''scheduler'' séparée pour les flottants, de 36 à 42 entrées, avec renommage de registre. le ''scheduler'' flottante a trois ports d'émission : un pour l'additionneur flottant, un autre pour le multiplieur, et un troisième pour la troisième unité flottante qui s'occupe du reste. La seconde est que chaque ALU entière est couplée avec une unité de calcul d'adresse. Par contre, la méthode de couplage varie d'un processeur à l'autre. : Les stations de réservation sont nommées des ''schedulers'' dans les schémas qui suivent. La micro-architecture K7 avait deux ''schedulers'' : une pour les opérations flottantes, une autre pour les instructions entières et les accès mémoire. le ''scheduler'' entière était reliée à 3 ALU entières et à 3 AGU. Elle pouvait émettre trois micro-opérations en même temps : trois micro-opérations entières, trois micro-opérations mémoire. Les AGU étaient reliées à la file de µops mémoire mentionnée plus haut, ce qui permet d'émettre trois µops mémoire par cycle. Par contre, la file de µops mémoire ne pouvait exécuter qu'une lecture de 64 bits ou une écriture de 64 bits. En clair, trois micro-opérations mémoire peuvent être émises par cycle, cela entraine trois calculs d'adresse simultanés, mais les trois lectures/écritures sont mises en attente dans la file de µops mémoire. Elles s'exécutent alors l'une après l'autre. le ''scheduler'' entière contenait 5 à 6 groupes de 3 macro-opérations. Vous noterez que j'ai parlé de macro-opérations et pas de micro-opérations, car les instructions ''load-up'' sont considérées comme une seule "micro-opération" dans le ''scheduler'' entière. Et cela se marie bien avec un ''scheduler'' unique partagée entre pipeline entier et pipeline mémoire. Une macro-opération était scindée en deux micro-opérations : une micro-opération mémoire et une micro-opération entière. Il est donc avantageux de regrouper unités mémoire et unités entières au même ''scheduler'' pour ce faire. [[File:AMD K7.png|centre|vignette|upright=3|AMD K7]] Sur les architectures K8 et K10, la station de réservation unique de 15 micro-opérations est remplacée par trois stations de réservations, de 8 micro-opérations chacune pour le K8, de 10 pour le K10. Chaque station de réservation entière alimente une unité de calcul entière et une unité de calcul d'adresse. l'unité de calcul d'adresse est reliée à la file de µops mémoire, qui n’exécute toujours qu'un seul accès mémoire par cycle. Le multiplieur est relié à la première station de réservation, sur le même port d'émission que l'ALU. [[File:AMD Husky microarchitecture.png|centre|vignette|upright=3|AMD Husky micro-architecture]] La micro-architecture K10 a été déclinée en plusieurs versions, nommées Grayhound, Grayhound+ et Husky, Husky étant une architecture gravée en 32 nm dédiée aux processeurs A-3000. L'architecture Grayhound a plus de cache et un ROB plus grand, la Husky est quand à elle un peu plus différente. Elle n'a pas de cache L3, contrairement aux autres architectures K10, ce qui simplifie fortement son sous-système mémoire. Par contre, les ''schedulers''s/stations de réservation et le ROB sont plus grands, pareil pour les files dans l'unité mémoire. Une ALU pour les divisions entières a aussi été ajoutée. Pour résumer, les architectures K7, K8 et K10 séparent les pipelines entiers et flottants : trois pipelines entiers avec chacun son unité de calcul, et un pipeline flottant avec plusieurs unités de calcul. Les raisons à cela sont assez diverses. Disons que dupliquer des ALU entières simples prend peu de transistors, là où les gros circuits comme le multiplieur ou la FPU ne sont pas dupliqués. Et cela a un autre avantage : le renommage, ''dispatch'' et l'émission sont plus simples. Les pipelines entiers ont une exécution dans le désordre peu complexe, grâce au grand nombre d'unités de calcul, ce qui fait que le pipeline entier est de seulement 15 cycles au total (chargement et décodage inclus). A l'opposé, la FPU est alimentée par une exécution dans le désordre très complexe, avec banc de registre physique et beaucoup de ressources, mais au prix d'un pipeline flottant plus long de 3 cycles, soit 18 cycles au total. ===La micro-architecture Bulldozer et ses dérivés=== Viennent ensuite les '''micro-architectures Bulldozer''', avec trois révisions ultérieures nommées Piledriver, Steamroller et Excavator. Un détail très important de Bulldozer est que de nombreux circuits sont partagés entre deux cœurs, à un point qui mérite de nombreuses explications. Les processeurs Bulldozer peuvent exécuter deux programmes "en même temps", sur deux cœurs partiellement fusionnés. Cette technique de partage d'unités de calcul entre coeurs s'appelle le '''cluster multithreading''', ou encore les '''architectures à cœurs conjoints''' (''Conjoined Core Architectures''). Les deux cœurs sont séparés pour ce qui est du chemin de données, du ''back-end''. Ils disposent de deux bancs de registres généraux et les ALU entières sont dupliquées. Toute la logique d'exécution dans le désordre est aussi dupliquée, avec deux ROBs, des stations de réservations séparées, etc. L'unité mémoire est aussi dupliquée, chaque cœur dispose de ses propres ''load queue'' et ''store queue'', ainsi de que son propre cache L1 de données. En clair, les chemins de données sont totalement séparés, sauf sur deux points : la FPU et les unités SIMD. La FPU est partagée entre deux coeurs, les unités SIMD sont aussi dans ce cas. Le partage de la FPU permet d'éviter de dupliquer trop de circuits et donc d'économiser des transistors. Le problème est que ce partage est source de dépendances structurelles, ce qui peut entraîner des pertes de performances. Par contre, le ''front-end'' est presque totalement partagé entre deux cœurs. Il n'y a qu'un seul cache d'instruction pour les deux cœurs, la TLB du cache d'instruction est unique, l'unité de prédiction de branchement est partagée entre deux cœurs, les décodeurs d'instruction aussi sont partagés, même la file de µops ! Les seules unités qui sont dupliquées sont la file d'instruction et l'unité de renommage, présentes en deux exemplaires. Concrètement, les deux programmes ont accès au cache à tour de rôle. Un programme a accès au cache à un instant t, mais le cycle suivant pourra être alloué à l'autre programme. Une unité décide de quel programme peut charger ses données, idem pour le décodage. [[File:AMD Bulldozer microarchitecture.png|centre|vignette|upright=3|Microarchitecture Bulldozer d'AMD.]] Au-delà de ce partage entre cœurs, Bulldozer a eu un changement assez important : les stations de réservation sont passées de stations de réservation très décentralisées à une station de réservation unique (pour les µops entières/mémoire), d'environ 40 entrées. L’implémentation de la station de réservation a aussi changée. Car 40 entrées, c'est beaucoup pour l'époque. Elle subit quelques simplifications pour la rendre plus rapide et plus économe en transistors. Les autres processeurs de l'époque utilisaient une station de réservation qui détectait à chaque instant quelle était l'instruction la plus ancienne, qui soit prête pour l’exécution. Mais Bulldozer n'utilisait pas cette technique. A la place, il mémorisait la place de l'instruction la plus ancienne gra^ce à une ''ancestry table''. Et l'instruction la plus ancienne est privilégiée sur toute les autres. Mais si elle n'est pas prête à s'exécuter, la station de réservation choisit une instruction suivant sa position dans la station de réservation (qui reste une mémoire RAM/associative, ne l'oublions pas). Bulldozer utilise aussi les optimisations du contournement et du banc de registre, vues dans le chapitre sur les CPU superscalaires. Le banc de registres généraux est dupliqué, afin de garder des bancs de registres avec peu de ports de lecture/écriture. Chaque banc de registre généraux a 4 ports de lecture et deux d'écriture, ce qui permet d'alimenter 2 ALU entières. En tout, cela permet d'alimenter 4 ALU entières, avec 8 ports de lecture et 4 d'écriture. Le tout alimente 2 ALU entières, et 2 AGUs/unités mémoire. Vu que la FPU est partagée entre deux programmes, sa station de réservation a une taille doublée comparé à la normale. Jugez plutôt : 60 entrées pour la station de réservation, là où les microarchitectures concurrentes d'Intel (''Sandy bridge'') utilisait une station de réservation de 54 entrées pour toutes les instructions entières/flottante/mémoire ! Idem pour le banc de registres flottants, qui n'a pas moins de 160 registres flottants ! Pour ce qui est des instructions SIMD, Bulldozer supporte l'extension AVX, qui fait des calculs du des registres de 256 bits, découpés en entiers/flottants de 64 bits, 32 bits, 16 bits, 8 bits, etc. L'unité SIMD ne gére cependant que des calculs sur 128 bits. Les instructions AVX sont donc découpées en deux µops, chacune traitant la moitié d'un registre SIMD. La performance n'est donc pas améliorée par rapport au SSE. Par contre, les unités SIMD gérent nativement l'opération FMA (une multiplication suivie d'une addition). {|class="wikitable" |- |+ Bulldozer |- ! Station de réservation 1 !! Station de réservation 2 !! Station de réservation 3 !! Station de réservation 4 |- | FMA - 128 bits || FMA - 128 bits || ALU - 128 bits || ALU - 128 bits |- | FMA opérandes entiers - 128 bits || Suffle et permutations || || FSTORE (x87) |} La révision Steamroller sépara le ''front-end'' en deux voies distinctes, une par ''thread''. Concrètement, le processeur se contente maintenant de partager la FPU et les unités SIMD entre deux coeurs, pas plus. Pour cela, elle ajouta un second décodeur d'instruction, une seconde file de micro-opération et une seconde unité de renommage de registres, afin d'améliorer les performances. Niveaux optimisations mineures, les stations de réservation ont été augmentées, elles peuvent mémoriser plus de micro-opérations, idem pour les bancs de registre et les files de lecture/écriture. Un cache de micro-opérations a été ajouté, de même que des optimisations quant au renommage de registre. Des ALU ont aussi été ajoutées, des FPU retirées. [[File:AMD excavator microarchitecture.png|centre|vignette|upright=3|Microarchitecture Excavator d'AMD.]] ===Les micro-architectures ZEN d'AMD=== Les micro-architectures suivantes sont les '''architectures ZEN 1/2/3/4'''. Elles se ressemblent beaucoup, le cœur de l'architecture reste plus ou moins le même. En passant à la suivante, le nombre de registre virtuel augmente, le ''branch target buffer'' augmente en taille, le ROB et les files d'attente grossissent, les caches de micro-opération aussi, les caches grossissent, etc. Une optimisation intéressante est l'ajout d'un cache de micro-opération, qui améliore grandement les performances du ''front-end'', notamment pour les boucles. La micro-architecture Zen 1 est illustrée ci-dessous. Comme on le voit, les registres flottants ont une unité de renommage séparée de celle pour les entiers, mais les deux utilisent du renommage à banc de registre physique. Il y a par contre une différence au niveau des ''schedulers'', notées ''scheduler'' dans le schéma. Les µops flottantes utilisent une station de réservation unique, alors qu'il y a une station de réservation par ALU entière. La raison de ce choix est que les opérations flottantes ont un nombre de cycle plus élevé, sans compter que les codes flottants mélangent bien additions et multiplication. [[File:Zen microarchitecture.svg|centre|vignette|upright=3|Micro-architecture Zen 1 d'AMD.]] La micro-architecture Zen 5 se distingue fortement des 4 microarchitectures précédentes. Premièrement, elle passe à une station de réservation centralisée pour les µops entières, une seconde pour els µops mémoire, et une troisième pour les µops SIMD/flottantes. Le retour à une station de réservation aussi peu décentralisée n'avait pas été vu depuis la microarchitecture Bulldozer. Une autre différence est qu'elle utilise un décodeur ''clustered'', tel que vu dans le chapitre sur les processeurs superscalaires, dans la section "Le décodage superscalaire large". ==La microarchitecture Netburst du Pentium 4== Dans cette section, nous allons voir l'architecture du processeur Pentium 4, qu'on a volontairement laissée de côté précédemment. Pourquoi un tel saut dans le temps ? Parce que le Pentium est complément à part des autres architectures Intel. Le Pentium 4 a représenté une rupture en termes de microarchitecture, qui a été un échec tellement retentissant que les processeurs suivants sont repartis sur la base du Pentium 3. Il introduisait de nombreuses nouveautés architecturales qui étaient très innovantes. Par exemple, il introduisait le renommage avec un banc de registre physique, qui a été utilisé sur tous les processeurs Intel suivants. Mais la plupart de ces innovations étaient en réalité de fausses bonnes idées, ou du moins des idées difficiles à exploiter. Par exemple, le système de pipeline à ''replay'' n'a été utilisé que sur le Pentium 4 et aucun autre processeur ne l'a implémenté. ===Un focus sur la fréquence d'horloge=== La microarchitecture du Pentium 4 a été déclinée en plusieurs versions, dont les finesses de gravure n'étaient pas les mêmes. La microarchitecture Netburst, utilisée sur le Pentium 4, utilisait un pipeline à 20 étage, augmenté à 32 sur une révision ultérieure. Il a existé quatre révisions de l'architecture : Willamette (180 nm), Northwood (130 nm), Prescott (90 nm) et Cedar Mill (65 nm). Un point important est que le Pentium 4 était prévu pour fonctionner à haute fréquence. Ses 1,5 GHz étaient impressionnants pour l'époque, les autres processeurs tournant à une fréquence proche du GigaHertzs. Pour cela, la solution retenue par Intel a été un pipeline très long, avec beaucoup d'étages. Le Pentium 4 a été décliné en plusieurs versions assez proches, chacune avec sa propre finesse de gravure qui n'ont pas toute le même pipeline. Les micro-architectures ''Willamette'' et ''Northwood'' avaient un pipeline de 20 étages, alors que les autres processeurs de l'époque avaient entre 10 et 15 étages maximum. Les micro-architectures ''Prescott'' et ''Cedar Mill'' étaient une refonte qui a fait grimper le nombre d'étages à 31 ! Du jamais vu, il s'agit d'un record pour un processeur commercial. Un pipeline aussi long permet d'exécuter beaucoup d’instructions en même temps, chacune dans un étage, mais aussi d'atteindre de hautes fréquences facilement. Le problème est qu'un pipeline avec autant d'étages a beaucoup de problèmes. Un point important est que la prédiction de branchement est cruciale. Pour rappel, la pénalité en cas de mauvaise prédiction dépend du nombre d'étages avant que le branchement soit résolu. Et les branchements sont résolus soit en fin de décodage, soit dans l'unité de calcul. C'est à dire au milieu du pipeline, soit en fin de pipeline. La pénalité en cas de mauvaise prédiction de branchement était énorme sur le Pentium 4, elle atteignait facilement 30 cycles Pour compenser, le Pentium 4 avait une prédiction de branchement très performante, pour l'époque. J'insiste sur le pour l'époque. Il utilisait un prédicteur qu'on a déjà abordé dans le chapitre sur la prédiction de branchement, précisément un prédicteur adaptatif à deux niveaux avec un historique global de 16 bits. Il avait aussi un ''Branch Target Buffer'' de 4096 entrées. Mais surtout, il intégrait une sorte de précurseur du cache de micro-opération, appelé le cache de traces, qui est détaillé dans la section suivante. ===Le cache de trace du Pentium 4=== Les décodeurs du Pentium 4 ne font pas décoder les instructions, ils mémorisent le résultat dans un cache de micro-opération un peu particulier, appelé le '''cache de trace'''. Une ligne de cache peut mémoriser 6 micro-opérations, ce qui peu sembler peu mais a été repris sur les micro-architectures suivantes. Mais le cache de trace a une grande différence avec un cache de micro-opération normal. Un cache de micro-opération normal mémorise une instruction par ligne de cache. Une instruction est décodée en plusieurs micro-instructions, qui sont enregistrées dans une ligne de cache. Si l'instruction n'utilise par les 6 micro-opérations disponibles, le reste de la ligne de cache n'est pas utilisé. Mais le Pentium 4 optimise le tout de manière ce à ce que ne soit pas le cas. Sur le Pentium 4, la contrainte du "une instruction par ligne de cache" est abandonnée. Une ligne de cache mémorise 6 micro-opérations consécutives, qui peuvent appartenir à plusieurs instructions. Par exemple, si le décodeur décode 4 instructions consécutives en 6 micro-opérations au total, alors le tout prendra une seule ligne de cache sur le Pentium 4. Et les 4 instructions consécutives n'ont même pas à être consécutives en mémoire : il peut y avoir des branchements pris entre ces instructions ! {|class="wikitable" |+ Cache de trace |- ! Ligne de cache | ADD || SUB || ADD || MOV || MUL || ''shift'' |- ! Ligne de cache | colspan="3" | ADD ''load-up'' || MUL || colspan="2" | Branch if Equal |- ! Ligne de cache | XOR || colspan="4" | POP || SUB |- ! ... | colspan="6" | ... |} Pour expliquer cela plus concrètement, nous allons devoir introduire les concepts de trace et de bloc de base. Un '''bloc de base''' (''basic block'') est une suite d'instructions sans branchement, qui est séparé par deux branchements. Le début d'un bloc de base est la destination d'un branchement, un bloc de base se termine avec un branchement. Une '''trace''' est formée en concaténant plusieurs blocs de base. Pour donner un exemple, regardez le code illustré ci-contre. Il est composé d'un bloc de base A, suivi par un bloc de base B, qui peut faire appel soit au bloc C, soit un bloc D. Un tel code peut donner deux traces : ABC ou ABD. La trace exécutée dépend du résultat du branchement qui choisit entre C et D. Le cache de trace mémorise des traces de 6 micro-opérations consécutives. Les traces sont formées en sortie des décodeurs d'instruction, par de subtiles opérations mélangeant mémorisation, décalage et concaténation. Les circuits qui construisent les traces ne sont pas connus, mais ils doivent certainement être très compliqués. toujours est-il qu'un cache de trace peut mémoriser des traces différentes, même si leur début est le même. Par exemple, prenons deux traces, composées des blocs de base A, B, C et D. La première trace est la trace ABC, la seconde est la trace ABD. Les deux traces auront chacune une ligne de cache dédiée. Une trace est réutilisable quand le premier bloc de base est identique et que les prédictions de branchement restent identiques. Pour vérifier cela, le tag du cache de traces contient l'adresse du premier bloc de base, la position des branchements dans la trace et le résultat des prédictions utilisées pour construire la trace. Le résultat des prédictions de branchement de la trace est stocké sous la forme d'une suite de bits : si la trace contient n branchements, le n-ième bit vaut 1 si ce branchement a été pris, et 0 sinon. Même chose pour la position des branchements dans la trace : le bit numéro n indique si la n-ième instruction de la trace est un branchement : si c'est le cas, il vaut 1, et 0 sinon. Si la trace est réutilisée par la suite, elle est lue depuis le cache de traces. Pour savoir si une trace est réutilisable, l'unité de chargement envoie le ''program counter'' au cache de traces, l'unité de prédiction de branchement fournit le reste des informations. Si on a un succès de cache de traces, et la trace est envoyée directement au décodeur. Sinon, la trace est chargée depuis le cache d'instructions et assemblée. Il faut signaler que le cache de trace avait sa propre unité de prédiction de branchement séparée de l'unité de prédiction de branchement normale. [[File:TraceCache.png|centre|vignette|upright=2|Cache de traces.]] Le cache de traces réduisait la longueur du pipeline en cas de succès de cache de trace. Quand les instructions étaient lues depuis le cache de trace, les étages avant le cache de trace ne sont pas utilisés, tout se passe comme s'ils étaient retirés du pipeline. C'est la même chose avec le cache de micro-opération des processeurs modernes, mais l'idée n'existait pas encore à l'époque. Le cache de trace mémorise des traces décodées, ce qui fait qu'un succès de cache de trace contournait non seulement le cache d'instruction, mais aussi les décodeurs. Le temps d'accès au cache de trace pouvait être assez élevé, même s'il était comparable au temps d'accès du cache d'instruction. Le cache de traces a depuis été remplacé par une alternative bien plus intéressante, le cache de micro-opérations, plus flexible et plus performant. Comparé à un cache de trace, la contrainte "une instruction par ligne de cache" simplifie grandement l'implémentation d'un cache de micro-opération. Ne parlons pas de la détection des succès de cache, qui demande d'utiliser les prédictions de branchement. Mais le vrai problème avec le cache de trace est tout autre. Il arrive souvent qu'une micro-opération soit présente dans plusieurs lignes de cache en raison du processus de construction des traces, chose impossible avec un cache de micro-opération. Et c'est un problème, qui réduit la capacité effective du cache de trace. Alors certes, une ligne de cache est plus remplie que sur un cache de micro-opération, on est certain que les 6 micro-opération par ligne de cache sont remplies. Mais la redondance réduit grandement cet avantage. ===L'exécution dans le désordre et le chemin de données du P4=== Le renommage de registres se fait avec un banc de registres physiques avec une table d'alias. Le Pentium 4 avait une exécution dans le désordre très limitée, basée sur la présence de deux files de micro-opération : une pour les accès mémoire, une autre pour les autres instructions. La seconde file regroupait opérations entières et flottantes, elles n'étaient pas séparées. Avec ces deux files, les instructions mémoire étaient exécutées dans l'ordre du programme, les instructions arithmétiques s'exécutaient aussi dans l'ordre du programme, mais une instruction arithmétique pouvait passer avant une instruction mémoire et inversement. L'avantage est que cela permettait de faire des lectures en avance, c'était une forme limitée de lecture non-bloquantes. Il s'agit bel et bien de deux files d'instructions, pas de ''schedulers'' ni de stations de réservation. Le Pentium 4 est le seul processeur commercial qui a utilisé des files de micro-opération séparées, tous les autres utilisent des ''schedulers'' : centralisées pour Intel, décentralisées pour AMD (en général). Le Pentium 2 et 3, bien qu'antérieurs, utilisait une station de réservation unique. Cela peut sembler être un retour en arrière, mais les files d'instructions sont bien plus larges : de 42 micro-opérations pour le Pentium 3, on passe à 120 micro-opérations pour le Pentium 4. Et vu la longueur du pipeline, qui fait qu'il y a plus d'instructions en vol, c'était une nécessité. Mais cela n'aurait pas été possible en utilisant des stations de réservation, pour des raisons de consommation électrique et/ou de budget en transistors, ce qui fait que passer à une file de micro-opération été la solution retenue. Pour les accès mémoire, le Pentium 4 utilisait donc une file de µops mémoire unique, couplée à une file d'écriture (non-représentée sur les schémas qui suivent). La file d'écriture du Pentium 4 était de 24 écritures maximum et gérait le ''Store-to-load forwarding''. Le processeur pouvait émettre une lecture et une écriture à chaque cycle. Il y avait un port d'émission pour les lectures et un autre pour les écritures, tous deux ayant chacun leur propre unité de calcul d'adresse. Le processeur contenait 3 ALU entières, 2 unités de calcul d'adresse et une FPU. La FPU était complétée par une unité pour faire des copies entre registres flottants, des opérations MOV. Pour les AGU, il y en avait une dédiée aux lectures, une autre pour les écritures. Le tout était relié aux ports d'émissions comme suit : [[File:Ports d'émission du Pentium 4.png|centre|vignette|upright=2.5|Ports d'émission du Pentium 4]] Le processeur utilisait deux réseaux de contournement séparés : un pour les opérations flottantes, un pour les opérations entières. Le réseau de contournement pour les opérations entières est aussi relié aux unités de calcul d'adresse. Jusque là, rien de surprenant, le chemin de données du processeur est assez classique. [[File:Architettura Pentium 4.png|centre|vignette|upright=3|Microarchitecture du Pentium 4.]] ===Les unités de calcul entières du Pentium 4=== Sur le Pentium 4, les ALU entières étaient cadencées à une fréquence double de celle du processeur. Les ALU entières pouvaient exécuter deux micro-opérations par cycle, ce qui fait que les ports d'émissions reliés aux ALU devaient eux aussi fonctionner à double fréquence. Pour faire la différence entre les deux fréquences, nous parlerons de fréquence/cycle processeur et de fréquence/cycle de l'ALU. Précisons que seules les ALU entières étaient à double fréquence, pas le multiplieur, pas le ''barrel shifter''. Pour simplifier, nous allons parler d'additionneur plutôt que de l'ALU entière, ce qui sera plus proche de la réalité. Et l'implémentation de l'additionneur du Pentium 4 était très innovante. L'additionneur pouvait exécuter deux additions par cycle, même si les deux additions ont une dépendance. Mais n'allez pas croire que l'implémentation était intuitive, avec un additionneur 32 bit basique très rapide. Non seulement l'additionneur fonctionnait à double fréquence, mais il était aussi pipeliné, avec un système de contournement interne ! Les additionneurs étaient pipelinées, d'une manière très simple. Une addition 32 bits était découpée en trois étapes : deux additions de 16 bits, une dernière étape pour mettre à jour le registre d'état. Pour cela, chaque additionneur était composé de deux additionneur 16 bits chacune, placées l'une après l'autre, avec un registre de pipeline entre les deux. L'additionneur prenait deux cycles d'horloge pour faire son travail : le premier cycle calculait les 16 bits de poids faible, le second calculait les 16 bits de poids fort lors du second cycle. Le tout est appelé '''addition étagée''' (''staggered add'') dans la documentation Intel. Une addition se fait donc en deux étapes, sauf que c'est compensé par le fait que l'additionneur fonctionnait à une fréquence double de celle du processeur ! Le résultat de ce fonctionnement franchement bizarre, est que les 16 bits de poids faible étaient calculés en une moitié de cycle processeur, alors que l'opération complète prenait un cycle. Deux additions consécutives s'exécutaient donc en 1 cycle et demi, alors qu'on aurait cru au premier abord que cela prendrait seulement un cycle. Si on fait les calculs, on s'apercoit que le rythme de croisière est cependant proche de 2 additions par cycle, bien qu'inférieur. 3 additions consécutives se font en deux cycles, 5 additions en 3 cycles, 7 en 4 cycles, etc. Et le Pentium 4 ajoutait un système de contournement interne à l'ALU. En clair, si une addition utilise le résultat de l'addition précédente, les deux peuvent s'exécuter en un cycle d'horloge et demi. Les 16 bits de poids faible de la première addition sont disponibles après un cycle ALU, ce qui permet de démarrer le calcul de la seconde addition au cycle suivant. ===Le ''replay pipeline''=== Le processeur est un processeur triple émission : il peut charger et décoder 3 µops par cycle, le ROB peut terminer 3 µops par cycle, etc. Pourtant, les ports d'émission peuvent émettre 6 instructions par cycle : 4 ports, dont deux à double fréquence. Une telle différence s'explique par l'usage d'un ''replay pipeline'', dont nous avons déjà parlé dans ce cours. Pour rappel, le Pentium 4 suppose que les lectures font tous un succès de cache L1. Si une opération arithmétique utilise la donnée lue comme opérande, le processeur l'émet immédiatement, l'opérande sera disponible une fois l'opération en entrée de l'ALU entière. Mais s'il s'est trompé, le processeur ré-exécute l'instruction après un temps d'attente de quelques cycles, pour se caler sur la latence du cache L2. Et si il y a un défaut de cache L2, l’instruction attend encore. Cela demande de ré-exécuter des instructions émises à tord, ce qui fait que le processeur doit avoir la capacité d'exécution pour. Ce pourquoi le processeur peut émettre 6 µops dans les unités de calcul : 3 µops normales et 3 µops ré-exécutées. ==Les microarchitectures x86 de Cyrix et Via== Les processeurs x86 grand public sont actuellement conçus et commercialisé par deux acteurs : Intel et AMD. Il faut dire que le jeu d'instruction x86 demande une licence pour être utilisée, qu'Intel et AMD refusent de dsitribuer à leurs concurrents, sauf en de très rares occasions. Cependant, il y a eu dans le passé un troisième acteur, qui a reussit à acquérir les droits de la licence x86 : Cyrix, qui a ensuite été racheté par National Semiconductor, lui-même acquis par Via. ===Les architectures compatibles 386 et 486 de Cyrix=== Cyrix a produits plusieurs CPUs et même des co-processeurs x87, avant d'être racheté. Sa carrière commence avec le Cyrix FasMath, un co-processeur arithmétique pour calculs flottants, compatible avec le x87 d'Intel. Il a ensuite produits plusieurs clones du processeur 386 d'Intel, nommés 486SLC et 486DLC. Une dénomination assez trompeuse, vous en conviendrez, mais qui n'est heureusement pas passée inaperçue et leur a valu de nombreuses critiques. Néanmoins, leurs processeurs étaient plus performants que le 386 de base, ce qui fait qu'ils étaient des upgrades corrects pour les PC avec un 386 (les cartes mères compatibles avec le i386 n’étaient pas compatibles avec le i486). Le 486SRX2 et le 486DRX2, sortis plus tard, étaient des versions avec une fréquence encore plus élevée, ce qui augmentait leurs performances. Cyrix récidiva avec le 5x86, un processeur offrant des performances s'approchant du Pentium, mais pour la plateforme 486. Le processeur supportait seulement les instructions du 486, pas les instructions ajoutées sur le Pentium. Son bus était similaire à celui du 486. Mais sa microarchitecture se rapprochait du Pentium, bien que n'étant pas aussi complexe. Il y avait une file d'instruction capable de mettre en attente 3 instructions, un cache unifié, une unité de prédiction de branchement. Malheureusement, la prédiction de branchements avait été désactivée en raisons de bugs matériels qui faisaient crasher le processeur. Niveau ALU, mais il y avait une FPU, une ALU entière et une unité mémoire. Mais il n'y avait pas de double émission. [[File:Cy5x86 arch (cropped).png|centre|vignette|upright=2.5|Cy5x86 arch (cropped).]] ===Le Cyrix 6x86 : une architecture superscalaire avancée=== Le '''Cyrix 6x86''' est là où la superscalarité apparait dans la gamme Cyrix. Le processeur était non pas une upgrade pour des cartes mères existantes, mais un concurrent direct du Pentium. C'était un processeur à double émission, avec exécution dans le désordre et renommage de registre. L'organisation de ses caches est assez originale. Il avait un cache principal de 16 kibioctets, qui mémorisait à la fois données et instructions, couplé à un cache d'instruction de 256 octets. En termes modernes, on dirait qu'il disposait d'un cache L2, couplé à un cache L1 d'instructions, mais sans cache L1 pour les données. Le cache unifié/L2 était un cache double port. Le cache d'instruction était totalement associatif. [[File:Cy6x86 arch.png|centre|vignette|upright=2.5|Cy6x86 microarchitecture.]] Le processeur supportait une double émission bien plus complète que celle du Pentium. Il disposait de deux pipelines entiers, nommés X et Y. Le pipeline X était le seul à pouvoir exécuter branchements et opérations flottantes, c'était le seul connecté à la FPU. Par contre, il était possible d'émettre un branchement ou une opération flottante dans le pipeline X, tout en émettant une seconde instruction dans le pipeline Y. Ce que le Pentium ne pouvait pas faire. Certaines instructions ne pouvaient cependant pas être appariées avec une autre : les multiplications/divisions, les ''string instruction'', les ''far jumps'', les accès aux entrées-sorties, et des instructions systèmes. La FPU pouvait exécuter des instructions en parallèle de l'ALU entière. Elle avait une file de µops de 4 µops flottantes. Elle avait aussi sa propre ''Store queue'', spécifiquement dédiée aux écritures flottantes, séparée de la ''Store Queue'' pour les écritures "normales", celles des registres généraux. Cette séparation est possible du fit que les registres flottants et généraux sont séparés sur le jeu d'instruction x86. [[File:Cyrix 6x86 arch.svg|centre|vignette|upright=2.5|Cy6x86 microarchitecture.]] Le Cyrix 6x86 avait de nombreux avantages sur le Pentium. Il intégrait notamment du renommage de registres pour les registres entiers, ainsi que le contournement, ce que ne faisait pas le Pentium. Et il pouvait faire de la double émission entière-flottante, alors que le Pentium ne pouvait pas émettre de seconde µop en parallèle avec une opération flottante. Tout cela le rendait bien plus performant que le Pentium, sur le papier. Sauf que sa FPU était peu performante, proche de celle du 5x86. Les concepteurs du processeur avaient mis le paquet sur les opérations entières, en délaissant les opérations flottantes. Les applications développées pour le Pentium, qui répartissaient au mieux leurs calculs entre FPU et ALU entière, marchaient donc moins bien sur le 6x86. Le successeur du 6x86, le '''Cyrix Jalapeno''', était un concurrent du Pentium 2/3. Son pipeline passait de 7 à 11 étages, ce qui permettait des augmentation de fréquence importante. Son cache était quadruplé en taille et passait à 8 voies. Et pour ce qui de la superscalarité, il était maintenant capable d'émettre deux µops flottantes par cycle : une partait dans l'additionneur flottant, l'autre dans un multiplieur flottant. ===Les processeurs de marque Via=== Après deux rachats, la licence x86 de Cyrix est passée dans les main de Via. Via avait racheté Cyrix, mais aussi Centaur, un autre concepteur de processeur. Via produisit plusieurs processeurs x86, basés sur des design provenant non pas de Cyrix, mais de Centaur, pour leur microarchitecture. Le premier processeur de cette lignée, le mal-nommé Cyrix III, a d'ailleurs été renommé en C3, parce qu'il n'avait aucun lien avec les microarchitectures de Cyrix et n'utilisait pas leurs technologies. Les '''processeurs Via C3''' et '''Via C7''' étaient des processeurs 32 bits. Ils étaient prévus pour des ordinateurs portables et ciblainet une faible consommation d'énergie, plutôt que des hautes performances. Ils n'avaient pas d'exécution dans le désordre, mais utilisaient une superscalarité limitée à la double émission. Le C3 regroupe en réalité deux microarchitecture semblables. Les modèles Samuel 2 et Ezra utilisaient la première version de la microarchitecture, alors que les processeurs Nehemiah avaient une version améliorée de celle-ci. Le pipeline passait de 12 à 16 étages, sa FPU est améliorée, les extensions SIMD sont revues (passage au SSE, abandon du 3DNow!). Les processeurs C7 utilisent cette même microarchitecture, bien qu'améliorée sur quelques détails. [[File:VIA Nano Architecture Blockdiagram.jpg|vignette|upright=1.5|VIA Nano Architecture.]] Par la suite, Via sortit le '''Via Nano''' en 2008 . C'était le premier CPU 64 bits de la marque. Il avait tout d'un design moderne, avec exécution dans le désordre, prédiction de branchement complexe, hiérarchie de cache classique, préchargement, etc. Il implémentait la superscalarité en triple émission. Pour cela, son ''front-end'' chargeait 16 octets par cycle, qui étaient accumulés dans une file d'instruction. Trois décodeurs lisaient les instructions dans cette file, puis envoyaient trois µops dans une file de µops de taille inconnue. Le renommage de registre pouvait lui aussi renommer trois µops par cycle. Niveaux unités, il avait deux ALU entières, une unité LOAD, une unité STORE, deux unités SIMD (une pour les additions SIMD, une pour les multiplications SIMD). Chaque unité avait sa propre file de µops, qui faisait entre 8 et 12 entrées. Les unités LOAD et STORE avaient chacune leur propre file de µops, il n'y avait pas de file de µops partagée entre les deux. L'unité LOAD alimentait une ''load queue'' de 16 lectures, alors que l'unité STORE alimentait une ''store queue'' de 16 écritures. Les unités de calcul sont décrites dans le tableau ci-dessous : {|class="wikitable" |- ! !! ALU 1 !! ALU 2 !! FPU/SIMD 1 !! FPU/SIMD 2 !! LOAD !! STORE |- ! File de µops | 12 entrées || 11 entrées || 8 entrées || 24 entrées || 8 entrées || 8 à 13 entrées, selon les sources |- ! rowspan="5" | Opérations | Opérations entières de base || Opérations entières de base || || || LOAD || STORE |- | Décalages et rotations || Multiplication entière 32 bits || Multiplication entière 64 bits || || || |- | CMOV || CMOV || Division entière 64 bits || Division entière 64 bits || || |- | ''Add With Carry'' || Branchements || Division flottante || || || |- | || || SIMD opérations entières + FMUL 128 bits || SIMD opérations entières + FADD 128 bits || || |} Les processeurs qui ont suivis sont des processeurs commercialisés uniquement en Chine, à destination du marché chinois et subventionnés (si ce n'est plus), par l'administration chinoise.Le peu d'informations qui sont disponibles dessus sont disponibles sur le substack ''Chips and cheese'', qui a notamment quelques articles sur les processeurs Longsoon. Pour une histoire complète et une review en profondeur des architectures de Via, je conseille les articles du blog ''Chips and cheese'' : * [https://chipsandcheese.com/p/the-weird-and-wacky-world-of-via-the-3rd-player-in-the-modern-x86-market The Weird and Wacky World of VIA, the 3rd player in the “Modern” x86 market] * [https://chipsandcheese.com/p/the-weird-and-wacky-world-of-via-part-2-zhaoxins-not-quite-electric-boogaloo The Weird and Wacky World of VIA Part 2: Zhaoxin’s not quite Electric Boogaloo] * [https://chipsandcheese.com/p/zhaoxin-part-3-a-sort-of-anti-climax Zhaoxin Part 3: A Sort of Anti-Climax] * [https://chipsandcheese.com/p/via-part-4-a-deep-dive-into-centaurs-last-cpu-core-cns VIA Part 4 – A Deep Dive into Centaur’s Last CPU Core: CNS] * [https://chipsandcheese.com/p/examining-centaur-chas-die-and-implementation-goals Examining Centaur CHA’s Die and Implementation Goals] <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les processeurs superscalaires | prevText=Les processeurs superscalaires | next=Les processeurs VLIW et EPIC | nextText=Les processeurs VLIW et EPIC }} </noinclude> 1jav125mxpcs4uggi2n548h3pw19y85 773637 773636 2026-09-29T21:20:06Z Mewtow 31375 /* Les différences et points communs entre µarchs d'Intel et d'AMD */ 773637 wikitext text/x-wiki Dans ce chapitre, nous allons étudier des exemples de processeurs x86, ceux présents dans nos PC. Nous n'allons pas voir les anciens processeurs comme le 286, le 386 ou le 486. Nous allons commencer avec le Pentium 1, et les processeurs commerciaux qui ont suivis. Tous les processeurs que nous allons voir dans ce chapitre sont des processeurs superscalaires. De fait, ce n'est pas pour rien si ce chapitre se situe après le chapitre sur les processeurs superscalaires. Par contre, nous allons voir que certains n'ont pas d'exécution dans le désordre, car elle est arrivée après la superscalarité. Le jeu d'instruction x86 pose quelques problèmes pour la superscalarité, car c'est un jeu d'instruction CISC, avec tous les défauts que ça implique. Un jeu d'instruction CISC a en effet de nombreuses propriétés qui collent mal avec l'émission multiple, avec la '''superscalarité'''. Il y en a plusieurs, certaines impactent le chargement des instructions, d'autres leur décodage, d'autres l'exécution, etc. Premièrement, les instructions sont de longueur variable, entre 1 et 15 octets, ce qui complique leur chargement et leur décodage. En pratique, les processeurs chargent un bloc de 32 à 64 octets, et découpent celui-ci en plusieurs instructions. La conséquence est que l'usage d'instructions trop longues peut poser problème. Imaginez qu'un processeur charge un bloc de 16 octets et que celui-ci ne contienne qu'une seule instruction : on ne profite pas de la superscalarité. Deuxièmement, une partie des instructions est microcodée, faute de mieux. Et cela pose de sérieux challenges pour l'implémentation des décodeurs. Dupliquer le microcode demanderait trop de transistors, ce qui fait que ce n'est pas fait. À la place, il n'y a qu'un seul microcode, ce qui fait que l'on ne peut pas décoder plusieurs instructions microcodées en même temps. Il est cependant possible de profiter de la superscalarité, en décodant une instruction microcodée en parallèle d'autres instructions non-microcodées. Et heureusement, ce cas est de loin le plus fréquent, il est rare que plusieurs instructions microcodées se suivent.' Troisièmement, la présence d'instructions ''load-up'', qui lisent un opérande en mémoire, peut poser problème, mais est aussi source d'optimisations assez intéressantes. En théorie, une instruction ''load-op'' est décodée en deux micro-opération : une pour lire d'opérande en RAM, l'autre pour faire l'opération arithmétique. Sauf que les processeurs x86 modernes optimisent la gestion des instructions ''load-up''. Par exemple, les premiers processeurs Atom géraient des micro-opérations de type ''load-up'', directement dans le chemin de données ! D'autres processeurs utilisent la technique de la '''micro-fusion''' pour retarder le décodage réel des instructions ''load-up'' assez loin dans le pipeline. Avec eux, une instruction ''load-op'' est décodée en une seule "macro-opération", qui est propagée dans le pipeline, pour être scindée en deux micro-opérations un peu avant les ALU et l'unité mémoire. L'avantage est qu'une macro-opération ne prend qu'une seule entrée dans le tampon de ré-ordonnancement, le ''scheduler'', la file de micro-opération, et les autres structures similaires. Il faut cependant noter qu'avoir des instructions complexes peut avoir des avantages sur les processeurs superscalaires à exécution dans le désordre. Les avantages sont liés au fait que certaines instructions complexes peuvent être implémentées avec des circuits dédiés, plutot qu'avec une suite de µops ou d'instructions. Les performances sont alors meilleures car une grosse instruction complexe devient une seule µops, ce qui aide le renommage de registres, prend moins de place dans le ROB ou les stations de réservation, etc. : Pour avoir une petite idée des avantages et inconvénients, je conseille la lecture de cet articles de blog : [https://chipsandcheese.com/p/why-x86-doesnt-need-to-die Why x86 Doesn’t Need to Die]. Il s'agit d'une réponse à cet autre article, plus court : [https://hackaday.com/2024/03/21/why-x86-needs-to-die/ Why X86 Needs To Die]. ==Introduction : généralités et historique== Avant de voir les processeurs dans un ordre chronologique, il est bon de faire quelques généralités, histoire de bien cadrer ce qui va suivre. Les architectures Intel et AMD se classent en deux types : une classe de microarchitectures pour la haute performance, une classe de microarchitectures moins performante mais plus économe. La première est utilisée sur les PC fixes et parfois sur les serveurs, les processeurs pour ''desktop'' et serveur pouvant être différents. Les microarchitectures pour serveurs sont souvent des variantes des microarchitectures pour ''desktop''. Les serveurs ont surtout besoin d'exécuter un grand nombre d programmes/processus en même temps, ce qui fait qu'elles ont besoin d'un grand nombre de cœurs moins de cœurs performants individuellement. Pour les applications ''desktop'', c'est l'inverse : elles ont besoin de cœurs performants, quitte à en avoir moins. Pour la seconde catégorie, parler de microarchitecture basse consommation serait peu-être un peu exagéré, car elles ne visent pas non les smartphones et autres appareils embarqué. Mais elles le sont suffisamment pour entrer dans un ordinateur portable, où l'autonomie de la batterie est très importante. Dan ce chapitre, nous allons parler exclusivement des processeurs haute performance, les microarchitectures "basse consommation" seront pour le prochain chapitre. ===Les différences et points communs entre µarchs d'Intel et d'AMD=== Les microarchitectures Intel et AMD ne sont pas très différentes quand on regarde de loin. Elles ont évoluées dans la même direction, avec une introduction précoce de la superscalarité, puis de l'exécution dans le désordre, du renommage de registre, de la prédiction de branchement, d'un cache de µops, etc. Néanmoins, il y a des différences entre les deux qui relèvent de la tendance générale, avec de nombreuses exceptions : * Intel préfère utiliser un ''scheduler'' centralisé, alors qu'AMD préfère des stations des ''schedulers'' décentralisés. * AMD sépare les unités flottantes/SIMD des unités entières, elles ont des ports d'émission bien séparés. Intel, en comparaison, préfère mettre une ALU et une unité FPU/SIMD sur le même port d'émission. Mais il s'agit là de tendance, avec de nombreuses exceptions. Par exemple, les microarchitectures K6 et Bulldozer d'AMD utilisaient une station de réservation centralisée. De même, les micraorchitectures récentes d'Intel tendent de plus en plus à scinder le ''scheduler''s, de plus en plus avec le temps. Le fait est qu'elle a dû grossir avec le temps, au point de devoir être scindée tellement elle prenait de circuits. La microarchitecture Skylake l'a scindée en une station de réservation pour les µops mémoire et une autre pour le reste. La microarchitecture ''Sunny Cove'' a ensuite scindée la station de réservation mémoire en deux : une pour les lectures et une pour les écritures. Dans ce chapitre, nous ne parlerons pas des unités de prédiction de branchement, ni de la hiérarchie des caches. Et les raisons sont différentes entre les eux. Les unités de prédiction de branchement ont été discutées dans le chapitre sur la prédiction de branchement. De plus, de nombreux processeurs différents utilisent des unités de prédiction de branchement qui ont des algorithmes similaires. Mais la raison principale est que l'unité de prédiction de branchement est complétement détachée du reste du pipeline, cache d'instruction excepté sur certaines microarchitectures. N'importe quelle unité de branchement peut s'adapter à n'importe quel pipeline/microarchitecture, tant que ses ''itmings'' et délais en cycles d'horloge tiennent la route. Il en est plus ou moins de même pour la hiérarchie de caches. Me système mémoire est assez indépendant du reste de la microarchitecture. Dans ce qui va suivre, vous allez rapidement remarquer quelque chose d'assez évident. Les processeurs x86 ont en quelque sorte deux "pipelines" séparés, assez différents les unes des autres, qui ont évolués en parallèle. D'un côté, il y a le "pipeline" entier/mémoire, qui exécute les opérations entières et les µops mémoire. Il regroupe des ALU entières, des AGU (unité de calcul d'adresse) et les unités mémoire LOAD/STORE. Il communique directement avec la ''Load/Store Queue'', car c'est là dedans que se font les calculs d'adresse. A l'opposé, les calculs flottants sont réalisés dans des pipelines séparés, sauf sur quelques processeurs qui font exception, comme les microarchitectures Core. Nous verrons pourquoi dans la section suivante. Pour ce qui est des accès mémoire, les microarchitectures Intel et AMD ont évolué différemment. Intel a suivi cette progression : * Le Pentium 1 utilisait une unité mémoire intégrée dans le pipeline entier. * Le Pentium 3 a séparé l'unité mémoire du pipeline entier, mais ne restait capable que d'émettre un accès mémoire par cycle. * La microarchitectures Core a ajouté la possibilité de faire deux émissions mémoire simultanées : une lecture avec une écriture. * Par la suite, de nouveaux ports de lectures ont été rajoutés. ===Un aparté sur la FPU des processeurs x86=== Les processeurs x86 oint acquis une FPU assez rapidement dans l'histoire. Les processeurs 286 et 386 n'avaient pas de FPU, mais pouvaient faire appel à un coprocesseur spécialisé dans les calculs flottants : le '''coprocesseur x87'''. Le coprocesseur x87 intégrait 8 registres flottants et supportait 8quelques instructions flottante, comme FADD pour l'addition, FSUB pour la soustraction, FMUL pour la multiplication, FDIV pour la division, etc. Le coprocesseur x87 a été intégré dans le processeur assez rapidement, dès le 486. Pour cela, le 486 intégrait une FPU et les 8 registres flottants. Les instructions FADD, SUB, FMUL, et quelques autres, ont aussi été ajoutées au jeu d'instruction de base du 486. Elles formaient une '''extension du jeu d'instruction x86''', à savoir des paquets d'instructions qui n'étaient pas dans le jeu d’instruction de base, mais qui ont été rajoutés par la suite et sont devenus des standards. Détail extraordinairement important : le coprocesseur x87 intégrait aussi 8 registres, avec une organisation très spéciale. Les registres n'étaient pas "adressables" avec des noms de registres, ils étaient à la place organisé en pile d'opérande. Vous vous rappelez peut-être que, dans le chapitre "les machines à pile et mémoire-mémoire", j'ai parlé des processeurs avec une pile d'opérande. Le coprocesseur x87 en était un. Et cela posait pas mal de problème pour rendre les opérations flottantes performantes. Notamment, cela posait problème pour le renommage de registres. Le fait que les registres flottants et généraux soient séparés fait qu'ils sont souvent renommés à part, dans deux unités e renommage différentes. Les registres flottants ont été les premiers à être renommés. De nombreux processeurs renommaient les registres flottants, alors que les registres généraux n'étaient pas renommés. La raison est que quand on un budget en transistor limité, on ne peut pas renommer les deux. Et autant c'est utile de renommer les registres généraux, autant la pile de registre du x87 rendait cela quasiment nécessaire pour avoir des performances convenables. un autre détail est que les optimisations du renommages sont d'abord arrivées sur le pipeline flottant, avant d'être portées sur le pipeline entier. Un exemple est celui des techniques d'élimination des MOV (''MOV elimination''), qui traitent les instructions MOV entre registres directement dans l'unité de renommage. Ou encore, les techniques avec des idiomes pour mettre à zéro un registre en le Xorant avec lui-même. Elles ont été utilisées d'abord sur les registres flottants/SIMD, avant d'arriver sur les registres généraux. Quelques processeurs les utilsaient pour les registres flottants, mais pas les registres généraux. Il en est de même avec le renommage dans le ROB versus à banc de registre physique. Quelques CPU renommaient les registres flottants avec un renommage à banc de registre physique, avec que le pipeline entier utilisait encore le renommage dans le ROB. Les processeurs Athlon et Phenom d'AMD étaient dans ce cas, par exemple. Chez Intel, le renommage à banc de registre physique est apparu sur le Pentium 4 et a été appliqué sur tous les registres. En général, la FPU est précédée par une station de réservation unique (ou par un ''scheduler'' sur certains CPU). Il y a souvent un port d'émission pour l'additionneur flottant et un autre pour le multiplieurs, sauf pour les tout premiers modèles d'Intel et AMD. Il y aussi souvent un port pour les instructions FSTORE, les écritures flottantes. Les ports en question servent à transmettre les données à écrire vers l'unité mémoire, ainsi que l'adresse mémoire associée. {|class="wikitable" |+ Station de réservation flottante |- ! Station de réservation 1 !! Station de réservation 2 !! Station de réservation 3 |- | FADD (additionneur flottant) || FMUL (multiplication flottante || FSTORE |} ===Un aparté sur les instructions SIMD des processeurs x86=== L'extension flottante x87 est resté la norme pendant une bonne décennie, sur les CPU 32 bits. Mais par la suite, les choses ont changées avec l'introduction des '''instructions SIMD'''. Je ne vais pas rentrer dans le détail, un chapitre ultérieur détaillera les instructions SIMD. Mais je dois cependant parler des bases de ces instructions, car elles ont remplacé les instructions flottantes progressivement. Mais avant toute chose, un petit historique,pour vous faire comprendre le vocabulaire utilisé dans ce qui suit. Les premières instructions SIMD ont été introduites en 1996, sur le Pentium MMX. Les instructions en question étaient regroupées dans une '''extension x86''' (un ajout au jeu d'instruction de base), appelé le MMX. Il ne contenait que des instructions SIMD pour des opérandes entiers. Mais par la suite, les extensions '''''Streaming SIMD Extensions''''' (SSE) ont ajouté des opérations flottantes. Les ''Streaming SIMD Extensions'', qu'on va abrévier SSE dans ce qui suit, ont été déclinées en plusieurs versions : SSE1, SSE2, SEE3, SSE4, et quelques intermédiaires. Puis, vint le '''AVX''' (''Advanced Vector eXtensions''). Les instructions SIMD regroupent plusieurs opérations identiques en une seule instruction, la seule contrainte étant que les opérandes soient différentes. Par exemple, une instruction d'addition SIMD regroupe quatre additions séparées, chacun travaillant sur des opérandes différentes. [[File:Instructions SIMD.png|centre|vignette|upright=3|Instructions SIMD]] J'ai donné l'exemple d'une addition SIMD qui regroupe quatre additions flottantes, travaillant chacune sur ses opérandes rien qu'à elle. Les opérandes en question ne sont pas lues depuis les registres généraux ou flottants. A la place, les instructions utilisent un banc de registre dédié, qui contient des registres assez larges. Les instructions SIMD utilisent donc des '''registres SIMD''', qui mémorisent des paquets d'opérandes. Par exemple, l'extension SSE a ajouté 16 registres XMM, de 128 bits chacun. un registre de 128 bits peut mémoriser : 2 entiers/flottants 64 bits, 4 entiers/flottants 32 bits, 8 entiers 16 bits, 16 entiers 8 bits. [[File:Vector register.png|centre|vignette|upright=2|Contenu d'un vecteur en fonction du type de données utilisé.]] L'AVX, quant à elle, donne accès à 16 registres de 256 bits chacun. Pour faire des économies de circuits, ils ont été fusionnés avec les registres XMM du SSE. Les 128 bits de poids faible de ces registres ne sont autre que les registres du SSE. [[File:AVX registers.svg|centre|vignette|upright=1.5|Registres AVX.]] Si je parle de ces instructions et registres SIMD, c'est parce qu'ils ont remplacé les instructions/registres flottants d'antan. Le x87 a disparu, les instructions SIMD font office d'instructions flottantes. Le remplacement a eu lieu avec le passage au 64 bits. Les raisons à cela sont multiples, mais la principale est que le x87 était très mal fait, avec une architecture obsolète. Une annexe en parle en détail, mais le x87 utilisait une pile de registre totalement inhabituelle, que les compilateurs ne pouvaient pas utiliser convenablement. Aussi, lors du passage au 64 bits, Intel et AMD en ont profité pour se débarrasser du x87 et le remplacer par quelque chose de plus moderne. Vu que les extensions SIMD faisaient déjà des calculs flottants, elles l'ont remplacé. Et même dans le processeur, dans sa microarchitecture, le remplacement a été total. Le processeur intègre une ou plusieurs unités de calcul spécialisées dans les instructions SIMD. Et elles remplacent la FPU, totalement. Typiquement, il y a au minimum : * une unité SIMD spécialisée dans les additions entières ; * une unité SIMD spécialisée dans les multiplications entières ; * une unité SIMD spécialisée dans les additions flottantes ; * une unité SIMD spécialisée dans les multiplications flottantes. * éventuellement une unité SIMD annexe pour les autres instructions SIMD, et elles sont nombreuses. Les unités SIMD étaient parfois mutualisées avec la FPU, c'est à dire que la FPU x87 était en réalité une sous-partie de l'unité SIMD. Après tout, l'unité SIMD contient plusieurs additionneurs flottants 32/64 bits, idem pour les multiplieurs flottants. Alors autant en profiter pour leur faire faire des calculs flottants normaux, ceux de la FPU x87. ==Les processeurs x86 d'Intel== Nous allons voir les processeurs Intel à part des processeurs AMD. La raison à cela est que les architectures Intel et AMD ont progressivement évolué, chacune se basant sur la précédente et l'améliorant. Il n'y a pas eu de cassure entre microarchitectures AMD, qui sont chacune la suite de la précédente. Il est donc préférable de voir les architectures AMD dans l'ordre chronologique. Par contre, Intel a eu une gigantesque cassure, avec le processeur Pentium 4. Son architecture se démarquait fortement du Pentium 3, mais elle n'a pas convaincu et a été abandonnée avec les processeurs suivants. Ce qui fait nous verrons l'architecture du Pentium 4 à part. Nous allons commencer avec les processeurs Intel. N'y voyez pas du favoritisme derrière ce choix, la justification est toute autre. Si je commence par Intel, c'est pour commencer avec les Pentium 1 et 2, qui sont superscalaires, mais sans exécution dans le désordre. L'absence d'exécution dans le désordre les rend bien plus simples à étudier que les autres, ce qui en fait un bon point de départ pour ce chapitre. Les autres processeurs x86 sont tous avec à exécution dans le désordre, à une exception qu'on verra dans le chapitre suivant. AMD n'a pas produit de processeurs ''in-order'', tous les processeurs produits par AMD intègrent l'exécution dans le désordre. Le Pentium 1 et 2 utilisaient la même architecture, qu'on détaillera dans ce qui suit. Les seules différences importantes étaient la fréquence, le cache, et quelques détails dans le genre. Le Pentium 3 était une nouvelle microarchitecture qui ajoutait l'exécution dans le désordre. Un an et demi plus tard, le Pentium 4 est sorti et a été un échec. Ses performances étaient peu convaincantes face au Pentium 3, et sa consommation énergétique était très importante. La conséquence est que le Pentium 4 et le Pentium 3 ont survécu pendant un long moment, beaucoup de monde préférait acheter un Pentium 3. Intel a alors amélioré les microarchitectures du Pentium 3 et du 4, indépendamment, pendant environ 7 ans. La microarchitecture du Pentium 3 a subit plusieurs micro-évolutions, chacune avec une finesse de gravure différente, afin de satisfaire les consomateurs. Les premeirs Pentium 3 avaient une finesse de gravure de 250 nm, elle a chuté à 65 sur les derniers modèles. L'architecture du Pentium 4 a fait la même chose, pour tenter de corriger ses problèmes de performance et de consommation d'énergie. Les premiers Pentium 4 avaient uen finesse de gravure de 180 nm, elle a elle aussi chutée à 65 sur les derniers modèles. Après l'échec du Pentium 4, les ingénieurs d'Intel ont repris l'architecture P6 et l'ont améliorée fortement, pour donner l'architecture Core. Les micro-processeurs suivants ont fait évoluer cette architecture progressivement, au point où elle ne ressemble plus à l'originale. L'architecture Core a laissé la place à l'architecture Nehalem, puis Sandy Bridge, puis Haswell, puis Skylake, puis Ice Lake, et Golden Cove. Il s'agit de la lignée principale, partant du Pentium 3 et continuant jusqu'à nos jours. Ces microarchitectures ont suivi un motif assez simple, appelé modèle '''tick-tock'''. Chaque microarchitecture était déclinée en deux versions, la seconde ayant une finesse de gravure réduite. En parallèle, Intel a travaillé sur des processeurs basse performance et basse consommation, avec une microarchitecture très différente. Les processeurs Atom de microarchitecture Bonnel, pour être ensuite remplacés par les microarchitectures Silvermont, puis Goldmont et Gracemont. Ces microarchitectures ont évolué en parallèle de la lignée principale, il s'agit d'une lignée secondaire. Le tout est résumé dans ce schéma ci-dessous. [[File:IntelProcessorRoadmap-4v.svg|centre|vignette|upright=2.5|Roadmap des processeurs Intel, qui servira de structure pour la suite du chapitre]] De nos jours, les processeurs Intel utilisent les deux types de micro-architectures en même temps. Les CPU Intel modernes disposent de deux types de coeurs : les coeurs P et le coeurs E. Leur nom signifie "Performance" et "Efficient", qui trahissent leur but. Les coeurs P utilisent la microarchitecture de la lignée principale, qui est conçue pour la performance. Les coeurs E, quant à eux, utilisent les micro-architectures basse consommation de la lignée secondaire. Ceci étant dit, commençons par le commencement, avec le Pentium 1. ===Le Pentium 1/MMX : la double émission entière avec deux pipelines=== Le processeur Pentium d'Intel avait un pipeline de 5 étages : un étage de chargement/prédiction de branchement, deux étages de décodage, un étage d'exécution et un dernier étage pour l'écriture dans les registres. Le Pentium 1 était un processeur double émission, intégrant deux pipelines nommés U et V. Chose importante, les deux pipelines n'étaient pas identiques. Le pipeline U pouvait exécuter toutes les instructions, mais le pipeline V était beaucoup plus limité. Par exemple, seul le pipeline U peut faire des calculs flottants, le pipeline V ne fait que des calculs entiers et des branchements. Les deux pipelines disposaient d'une unité de calcul entière, identique dans les deux pipelines. Mais le pipeline U incorporait un circuit multiplieur/diviseur et d'un ''barrel shifter''. L'unité flottante était sur le port d'émission du pipeline U, idem pour l'unité de calcul vectoriel MMX sur le Pentium MMX. Les deux pipelines avaient chacun une unité de calcul d'adresse, mais ils n'étaient pas identiques : celle du pipeline V ne gérait que l’instruction LEA, celle du pipeline U gérait tous les calculs d'adresse. {|class="wikitable" |- ! Pipeline U ! Pipeline V |- | ALU entière | ALU entière |- | Multiplieur/diviseur | |- | ''Barrel Shifter'' | |- | AGU complexe | AGU simple (opération LEA) |- | FPU | |- | Unité SIMD | |} Les deux pipelines géraient les opérations bit à bit, les additions, les soustractions et les comparaisons. Les autres instructions ne sont exécutables que dans le pipeline U. Pour être plus précis, les deux pipelines supportaient les instructions suivantes, ce qui fait qu'on pouvait en faire deux en même temps : * Les instructions arithmétiques INC, DEC, ADD, SUB ; * l'instruction de comparaison CMP ; * les instructions bit à bit AND, OR, XOR ; * l'instruction de calcul d'adresse LEA ; * l'instruction MOV (dépend du mode d'adressage) ; * les instructions de gestion de la pile PUSH et POP (dépend du mode d'adressage) ; * l'instruction NOP, qui ne fait rien. Il faut noter qu'il y a cependant quelques restrictions, beaucoup de paires d'instructions sont interdites. La plupart interdisent au pipeline V de faire quoique ce soit quand une opération particulière est émise dans le pipeline U. Par exemple, si le pipeline U exécute une multiplication ou une division, le processeur ne peut pas exécuter une opération dans le pipeline V. Et c'est pareil avec les branchements : si un branchement est émis dans le pipeline U, l'instruction suivant le branchement n'est pas émise dans le pipeline V, pour éliminer les dépendances de contrôle. De même, si le pipeline U exécute une opération flottante, le pipeline V ne pourra rien exécuter. La seule exception est l'instruction FCXH, qui échange deux registres flottants. [[File:Intel Pentium arch.svg|centre|vignette|upright=2.5|Microarchitecture de l'Intel Pentium MMX. On voit que certaines unités de calcul sont dupliquées.]] Un choix assez intéressant a été fait pour le cache de données. Nous avions vu dans le chapitre sur les CPU superscalaires que la superscalarité a un impact sur l'unité mémoire. Il y a alors deux implémentations. La première ne fait rien, l'unité mémoire ne change pas, et le processeur ne peut pas faire deux accès mémoire simultanés. La seconde duplique l'unité mémoire et les ports de lecture/écriture du cache, ce qui autorise des accès mémoire simultanés. Le Pentium 1 utilise une solution intermédiaire. Les ingénieurs d'Intel étaient partis à la base sur un cache totalement double port, pour obtenir des performances maximales. Mais diverses simulations et observations les ont fait changer d'avis. Les simulations ont montré qu'il est "rare" que les deux pipelines aient besoin de lire/écrire dans le cache en même temps. Et ils ont optimisé le cache de donnée pour en tenir compte. Le cache de données est partiellement multiport : simple port sur certains aspects, double port sur d'autres. Le cache est un cache splité, à savoir que les données et les ''tags'' sont séparés dans des mémoires séparées. La mémoire pour les ''tags'' est multiport, ce qui permet d'interroger les ''tags'' du cache deux fois par cycle. Un port est relié au pipeline u, un autre au pipeline V. Mais pour les données, le cache n'a qu'un seul port pour lire/écrire des données. Impossible donc de lire deux données en même temps, pour alimenter les deux pipelines. Il utilise cependant 8 banques permet d'accélérer des accès mémoire proches dans le temps, mais dans des cycles d'horloge différents. Entre les deux mémoires, il y a un circuit qui détecte les conflits, à savoir les situations où les deux pipelines accèdent en même temps au cache. S'ils veulent lire/écrire une donnée dans le même cycle, ce qui est impossible avec un seul port, le pipeline U a la priorité et le pipeline V attend le cycle suivant. Le circuit détecte aussi les conflits de banque, à savoir quand un pipeline accède à une banque en cours d'accès par l'autre pipeline (on rappelle qu'un accès au cache prend plusieurs cycles). Le circuit détecte aussi certaines dépendances mémoires, à savoir des accès consécutifs à la même adresse. : La TLB du processeur est aussi totalement double port. ===La microarchitecture P6 (Pentium 3) : l'exécution dans le désordre=== Le Pentium 3 utilisait la '''microarchitecture P6''', qui a été dérivée dans de nombreuses variantes, dont les finesses de gravure n'étaient pas les mêmes. Il introduit une exécution dans le désordre simple, avec un ''scheduler'' centralisée, avec renommage dans le désordre dans le ROB (tampon de ré-ordonnancement), commandé par une table d'alias. C'était un processeur triple émission, soit une instruction de plus que la double émission du Pentium 1. [[File:P6 func diag.png|centre|vignette|upright=2|P6 func diag]] Le pipeline passe de 5 étage sur le Pentium à 14 - 12 étages, dont le détail est le suivant : * Prédiction de branchement, deux cycles ; * Chargement des instructions, trois cycles ; * Décodage de l'instruction, deux cycles ; * Renommage de registre, un cycle ; * Copie des opérandes dans le tampon de ré-ordonnancement (lié au renommage de registre dans le ROB) ; * Dispath dans ou depuis la station de réservation. * Exécution de l'instruction ; * Écriture du résultat dans le ROB ; * Écriture dans le banc de registre physique. Les instructions sont chargées par blocs de 16 octets, avec un système de fusion de blocs pour gérer les instructions à cheval sur deux blocs. Lors d'un branchement, deux blocs doivent être chargés si l'instruction de destination n'est pas alignée sur 16 octets et cela cause un délai de un cycle d'horloge. Le décodage des instructions x86 était géré par plusieurs décodeurs. Il y avait trois décodeurs : deux décodeurs simples, et un décodeur complexe. Les décodeurs simples décodaient les instructions les plus fréquentes, mais aussi les plus simples, qui étaient décodées en une seule micro-opération. Les instructions CISC complexes étaient gérées uniquement par le décodeur complexe, basé sur un microcode, qui pouvait fournir jusqu'à 4 micro-opérations par cycle. Le tout est résumé avec la règle 4-1-1. La toute première instruction chargée depuis la file d'instruction va dans le premier décodeur simple. Si jamais le décodeur ne peut pas décoder l'instruction, l'instruction est redirigée dans un autre décodeur, avec un délai d'un cycle d'horloge. Les stations de réservations étaient regroupées dans une structure centralisée, en sortie de l'unité de renommage. Elles avaient 4 ports d'émission. En réalité, 5 dont deux pour les écritures (un pour l'adresse à transmettre, un pour la donnée). Le tout avait une répartition moitié-moitié pour les calculs et les accès mémoire. Chaque port d'émission pour les calculs était relié à une ALU et une FPU/unité SIMD. Le tableau suivant résume tout. Vous remarquerez la présence de plusieurs additionneurs flottants. Le premier exécute les opérations x87, l'autre les opérations SIMD. Les opérations SIMD se font sur des registres de 128 bits, mais elles sont en réalité cassées en deux µops, chacune travaillant sur 64 bits. {|class="wikitable" |+ Pentium 3 |- ! !! Port d'émission 1 !! Port d'émission 2 !! Port d'émission 3 !! Port d'émission 4 !! Port d'émission 5 |- ! rowspan="3" | µops entières | ALU entière || ALU entière || LOAD || STORE adresse || STORE donnée |- | LEA || ALU SIMD MMX || || || |- | Multiplieur entier || || || || |- ! rowspan="3" | µops flottantes | x87 FADD || FADD 64 bits (SIMD) || || |- | FMUL (x87 et 64 bits) || || || |- | FDIV || || || |} Les premiers Pentium 3 n'avaient pas de cache L2 dans le processeur, celui-ci était sur la carte mère. Mais il a été intégré dans le processeur sur la seconde version du Pentium 3, la version Coppermine. Le Pentium 3 a servi de base aux microarchitectures d'Intel qui ont suivi. Les changements à chaque nouvelle génération sont assez mineurs : la prédiction de branchement est améliorée, la taille des stations de réservation et du ROB augmente, idem avec les autres structures liées à l'exécution dans le désordre. Les processeurs Intel ont conservé un ''scheduler'' centralisée, alors qu'AMD utilise une autre méthode, comme nous allons le voir dans ce qui suit. Les seuls changements notables sont est le passage à un renommage dans le ROB à un renommage à banc de registre physique, ainsi que l'introduction du cache de micro-opération. Et ce sont des modifications qu'AMD a aussi faites, celle-ci étant clairement une bonne idée pour toutes les micro-architectures avec un budget en transistor suffisant. Il est intéressant de garder cela en tête, car une bonne partie des améliorations de chaque micro-architecture proviendra de là. ===La microarchitecture Core : désambiguïsation mémoire, macro-fusion, ''stack engine'', ''Fetch Input Queue''=== La '''microarchitecture Core''' fait suite au Pentium 4, mais reprend en fait beaucoup d’éléments du Pentium 2 et 3. Elle utilise la station de réservation unique avec renommage dans le ROB, provenant du Pentium 2/3. A part ça, les améliorations sont assez diverses : un cache L2, l'arrivé de la désambiguïsation mémoire, une ''Fetch Input Queue'' et un ''stack engine'' primitif. Le processeur introduit aussi la macro-fusion qui fusionne une instruction de test et le branchement qui suit en une seule micro-opération. beaucoup d'optimisations importantes, donc. [[Image:Intel Core2 arch.svg|centre|vignette|upright=2|Intel Core microarchitecture]] Il y a quelques modifications au niveau de l'unité de chargement. La file d'instruction a toujours ce système de fusion de blocs, sauf que les branchements ne causent plus de délai d'un cycle lors du chargement. La file d'instruction est suivie par un circuit de prédécodage qui détermine la taille des instructions et leurs frontières, avant de mémoriser le tout dans une file de 40 instructions. La station de réservation dispose de 5 ports d'émission, dont un pour les lectures et un pour les écritures. Les deux sont reliées à une ''Load/Store Queue'', appelée ''Memory Ordering Buffer'', elle-même reliée au cache de données par un port de lecture et un port d'écriture. Les ports de lecture/écriture du cache font 128 bits, pour gérer naturellement les instructions LOAD/STORE dans les registres SIMD. Les trois ports restants sont chacun reliés à des ALU entières et des unités flottantes/SIMD (pour l'extension SSE). Le multiplieur entier est relié au second port d'émission. L'additionneur flottant SIMD/SSE est connecté au port 1, le multiplieur/diviseur flottant SIMD/SSE est connecté au port 0, une unité SIMD annexe est connectée sur chaque port. {|class="wikitable" |+ Microarchitecture Core (Penryn et Merom) |- ! !! Port d'émission 1 !! Port d'émission 2 !! Port d'émission 3 !! Port d'émission 4 !! Port d'émission 5 |- ! rowspan="3 | µops entières/mémoire | ALU entière || ALU entière || ALU entière || LOAD || STORE |- | ''Barrel shifter'' || Multiplieur entier || ''Barrel shifter'' || || |- |- | || || ALU branchements || || |- ! rowspan="3 | µops flottantes et SIMD | FMUL et FDIV || FADD || || |- | ALU SIMD entière (128 bits) || ALU SIMD entière (128 bits) || ALU SIMD entière (128 bits) || || |- | || MUL SIMD entière (128 bits) || || || |} Le résultat que le processeur peut émettre un mix d'opérations flottantes et entière assez varié, avec un mix allant de trois opérations entières à trois opérations flottantes, avec tous les intermédiaires. Le fait de mettre les ALU SIMD sur des ports différents permet d'émettre une addition et une multiplication flottante/SIMD simultanément. ===La microarchitecture Nehalem : un vrai ''Loop Stream Detector''=== Les microarchitectures '''Nehalem''' et '''Westmere''' n'introduisent pas d'optimisation majeure. A la rigueur, ils introduisent une prédiction de branchement à deux niveaux, et une macro-fusion plus complète. Les unités de calcul sont assez semblables, de même que leur répartition sur les ports d'émission. Elle a introduit cependant un vrai ''Loop Stream Detector'' (LSD). Pour rappel, le LSD qui permet d'exécuter les boucles directement depuis la file de µops. Le LSD reconnait les petites boucles, qui tiennent dans la file de µops, et lit les µops adéquates depuis celle-ci. Les instructions de la boucle n'ont donc pas à être chargée et décodées. La microarchitecture Core avait une sorte de pseudo-''Loop Stream Detector'', mais il était localisé dans la file d'instruction. Il était donc moins performant. Ce pseudo-''Loop Stream Detector'' permettait de ne pas charger les instruction x86, mais elles devaient quand même être décodées et passer par la file de µops. Avec Nehalem, ce n'est plus le cas. [[File:Intel Nehalem arch.svg|centre|vignette|upright=2.5|Intel Nehalem.]] ===La microarchitecture Sandy Bridge : le cache de µops=== Les microarchitectures '''Sandy Bridge''' and '''Ivy Bridge''' ont introduit le renommage à banc de registre physique et l'ajout d'un cache de micro-opérations. L'ajout du cache de micro-opérations est une optimisation particulièrement rentable, particulièrement pour le complexe jeu d’instruction x86. Avec ce cache, les décodeurs servent surtout à alimenter le cache de micro-opérations, parfois décoder des instructions en-dehors de boucles, pas plus. Intel a d'ailleurs reflété ce fait dans sa terminologie. Intel distingue deux voies de chargement : le ''legacy pipeline'' et le cache de micro-opérations. L'unité de chargement et les décodeurs sont regroupés dans la voie du ''legacy pipeline''. Sur les processeurs modernes, les décodeurs ne servent que pour 10 à 20% des micro-opérations exécutées, le reste est lu depuis le cache de µops. Cependant, Sandy Bridge a un cache de µops assez limité, qui ne permet pas d’atteindre ces chiffres. De nombreuses instructions ne peuvent pas être mémorisées dans le cache de µops, les limitations quand à son utilisation sont assez importantes. Par exemple, le processeur ne consulte pas le cache de µops à chaque cycle, il ne démarre son utilisation qu'après un branchement (donc une boucle potentielle) et cesse de l'utiliser au premier défaut de cache (dans le cache de µops). Le cache de micro-opérations est complété avec un ''Loop Stream Detector'', placé après le cache en question. Les décodeurs et le cache de micro-opérations alimentent une file de micro-opérations, située juste avant l'étage de renommage de registres. La file de micro-opérations sert en quelque sorte de tampon entre l'étage de "décodage" et celui de renommage. Le ''Loop Stream Detector'' utilise cette file de micro-opérations comme d'un cache lorsqu'une boucle est détectée. Les micro-opérations de la boucle sont lue depuis la file de micro-opérations, pour être envoyée au renommeur de registres. L'avantage est que le cache de micro-opérations et/ou les décodeurs sont mis en pause et clock-gatés lorsqu'une boucle s'exécute, ce qui réduit la consommation du processeur. Le ''Loop Stream Detector'' et le cache de micro-opération ont globalement le même effet : désactiver tout ce qui est avant, le ''Loop Stream Detector'' appliquant cette méthode au cache de micro-opération lui-même. Pour le reste, ''Sandy Bridge'' n'innove pas trop. Les unités d'exécution sont globalement les mêmes, leur répartition sur les port est peu changée. LA seule différence intéressante est que ''Sandy Bridge'' n'a plus une unité mémoire dédiée aux LOAD et une aux STORE. Elle en a deux qui peuvent faire indifféremment LOAD et STORE. Le processeur peut donc émettre deux LOAD simultanément, ce qui entraine un gain en performance appréciable. ===Les microarchitectures Haswell et Broadwell=== Les architectures '''Haswell''' et '''Broadwell''' ont ajouté quelques unités de calcul, élargit la sortie du cache de micro-opérations. Un port d'émission pour opération entières a été ajouté, de même qu'un port pour les accès mémoire. Le processeur passe donc à 8 ports d'émission, ce qui permet d'émettre jusqu'à 8 micro-opérations, à condition que le cache de micro-opération suive. Pour le reste, le processeur est similaire aux architectures précédentes, si ce n'est que certaines structures grossissent. {|class="wikitable" |+ Microarchitecture Haswell et Broadwell |- ! !! Port d'émission 1 !! Port d'émission 2 !! Port d'émission 3 !! Port d'émission 4 !! Port d'émission 5 !! Port d'émission 6 |- ! rowspan="3" | µops entières/mémoire | ALU entière || ALU entière || ALU entière || ALU entière || LOAD/STORE || LOAD/STORE |- | ''Barrel shifter'' || Manipulation de bits || ''Barrel shifter'' || Manipulation de bits || || |- | || Multiplieur entier || ALU branchements || || || |- ! rowspan="4" | µops flottantes et SIMD | SIMD bit à bit (256 bits) || SIMD bit à bit (256 bits) || SIMD bit à bit (256 bits) || || || |- | || ALU SIMD entière (256 bits) || ALU SIMD entière (256 bits) || || || |- | FMUL + FMA (256 bits) || FMUL + FMA (256 bits) || || || || |- | FDIV || FADD || || || || |} ===La microarchitecture Skylake : la fin de la station de réservation centralisée=== L'architecture '''Skylake''' a eu une longévité hors du commun, avec près de 6 ans d’utilisation ininterrompue. Elle a été la concurrentes des microarchitectures Zen 1, Zen 2 et Zen 3 d'AMD. La microarchitecture ''Skylake'' est une microarchitecture capable de décoder/renommer 4 instructions par cycle, elle peut émettre 6 µops par cycle grâce au cache de µops. Elle a été déclinée en plusieurs microarchitectures légèrement différentes les unes des autres, nommés '''''Kaby Lake''''', '''''Coffee Lake''''', '''''Comet Lake'''''. Un changement extrêmement important concerne la station de réservation centralisée, qui ne l'est plus sur Skylake. Elle est scindée en deux stations de réservations : une pour les µops mémoire, et une autre pour le reste. Mien de rien, c'est à ce moment que la tendance "Intel = station de réservation centralisée " a commencée à s'adoucir. Intel est longtemps resté sur cette organisation avec un '''''Math Scheduler''''' d'un côté, et un '''''MEM scheduler''''' de l'autre. Pour le reste, les améliorations sont mineures. A la rigueur, l'unité de renommage de registre ajoute des optimisations comme l'élimination des MOV, les idiomes liés aux opérations avec zéro, etc. ===La microarchitecture ''Sunny Cove'' : la station de réservation mémoire est scindée=== Après Skylake, les microarchitecture d'Intel ont changé de dénomination. Elles sont maintenant nommées non pas avec des noms de lacs, mais ont un nom qui finit par Cove : ''Sunny Cove'', ''Golden Cove'', etc. La seule exception à cette règle est la microarchitecture '''''Palm Cove''''' était un ''die shrink'' de Skylake, ce qui fait qu'elle est à part de celles qui vont suivre, qui sont vraiment des microarchitectures différentes. La microarchitecture qui suit immédiatement skylake était la microarchitecture '''''Sunny Cove'''''. La microarchitecture''Sunny Cove'' suit la tendance entamée avec Skylake de casser la station de réservation principale en plusieurs stations de réservations plus petites. Cette fois-ci c'est la station de réservation pour les µops mémoire qui est scindée en deux une pour les lectures et une pour les écritures. La microarchitecture ''Sunny Cove'' passe de quadruple émission à la pentuple émission. Précisément, l'unité de renommage de registres est maintenant capable de renommer 5 µops par cycle. De plus, l'unité de renommage devient plus performante. Ses capacités de ''MOV elimination'' ont été améliorées, et elle devient capable de reconnaitre certains idiomes, comme celui qui met à zéro un registre en le XORant avec lui-même. ''Sunny Cove'' était au départ prévue pour les PC ''desktop'', mais sa production a eu de nombreux problèmes. Elle était censée être produite avec une technologie de gravure 10nm d'Intel lui-même, qui a cependant eu de nombreux problèmes de production. Au final, ''Sunny Cove'' et ses variantes n'ont existées que dans des CPU mobile, basse performance et basse consommation. Elle a été déclinée en deux versions : '''''Willow Cove''''' a un cache retravaillé, alors que '''''Cypress Cove''''' est l'équivalent de ''Sunny Cove'' mais repassé à une technologie de gravure de 14nm. Les deux microarchitecture ont été utilisées sur les plateformes dites '''''Ice Lake''''' et '''''Tiger Lake'''''. ===La microarchitecture ''Golden Cove'' : un ''Fetch'' doublé=== La microarchitecture '''Golden Cove''' a suivi ''Sunny Cove''. Les microarchitectures suivantes, ''Redwood Cove'' et ''Raptor Cove'', sont des modifications mineures de ''Golden Cove''. ''Golden Cove'' altère les décodeurs et l'unité de chargement. Sur toutes les générations précédentes, on reste sur une unité de chargement qui charge 16 octets à la fois. Une telle stagnation sur les unités de chargement et de décodage s'explique encore une fois par la présence du cache de micro-opération fait que ce n'est pas trop un problème. Tout ce qui précède le cache de micro-opérations n'a pas de raison d'évoluer, car ce cache est très puissant. Mais cela change avec ''Golden Cove''. Golden Cove double la taille du chargement qui passe à 32 octets. Le processeur peut décoder 6 instructions par cycle, et en émettre 6 à destination des ''schedulers''s. Il s'agit donc de processeurs superscalaires très larges, ce qui est la norme de nos jours et le restera pendant longtemps. ''Golden Cove'' conserve les trois ''schedulers'' séparées de ''Sunny Cove'', savoir : pour les instructions entières/flottantes, pour les lectures, pour les écritures. [[File:Golden Cove.png|centre|vignette|upright=3|Golden Cove]] Niveau unités de calcul, peu de changements avec ''Sunny Cove'', si ce n'est une ALU entière en plus. {|class="wikitable" |- ! Port d'émission n°1 !! Port d'émission n°2 !! Port d'émission n°3 !! Port d'émission n°4 !! Port d'émission n°5 |- | ALU entière || ALU entière || ALU entière || ALU entière || ALU entière |- | ''Barrel shifter'' || Multiplieur || Multiplieur || ''Barrel shifter'' || |- | Branchements || Diviseur || || Branchements || |} ===La microarchitecture ''Lion Cove'' : la scission du ''math scheduler''=== La microarchitecture '''''Lion Cove''''' poursuit la tendance à scinder la station de réservation. La station de réservation pour les opérations entières/flottantes est maintenant scindée en deux : une pour les µops entières, une autre pour les µops SIMD/flottantes. Une autre modification, très liée à la précédente, est que le renommage de registre est lui aussi scindé. Les registres SIMD/flottants sont maintenant renommé indépendamment des registres généraux/entiers. Les raisons sont certainement que cela simplifie grandement la conception du processeur, en séparant les pipelines entiers et SIMD, surtout que les opérations entières et SIMD sont forts différentes : instructions 2-opérandes d'un côté, 2 à 3-opérandes pour le SIMD ; présence de techniques de ''masking'' pour le SIMD, mais pas pour les opérations entières, etc. Pour le reste, le processeur de 6 à 8 voies d'émission, et l'unité de chargement peut maintenant charger 48 octets, au lieu de 32 auparavant. Des ALU entières et SIMD ont été rajoutés. L'unité d'émission pour les opérations entières dispose de 6 ports d'émission, alors que celle pour les opérations SIMD n'en a que 4. {|class="wikitable" |+ Microarchitecture Haswell et Broadwell |- ! !! Port d'émission 1 !! Port d'émission 2 !! Port d'émission 3 !! Port d'émission 4 !! Port d'émission 5 !! Port d'émission 6 |- ! rowspan="3" | µops entières/mémoire | ALU entière || ALU entière || ALU entière || ALU entière || ALU entière || ALU entière |- | Branchements || ''Barrel shifter'' || Branchements || ''Barrel shifter'' || Branchements || ''Barrel shifter'' |- | || Multiplieur entier || || Multiplieur entier || || Multiplieur entier |} ==Les processeurs x86 d'AMD== Les architectures Intel ont évolué progressivement, sans grandes cassure. Il y a une continuité presque ininterrompue entre l'architecture du Pentium 2 et les architectures modernes. Intel a fait des améliorations mineures à chaque nouvelle micro-architecture, si on omet le passage à un renommage à banc de registre physique et l'ajout du cache de micro-opération. A l'opposé, les architectures AMD ont eu de nombreuses cassures dans la continuité où AMD a revu sa copie de fond en comble. Étudier ces architectures demande de voir trois choses séparément : le ''front-end'' qui regroupe l'unité de chargement et les décodeurs, le ''back-end'' qui gère l'exécution dans le désordre et les unités de calcul, et le sous-système mémoire avec les caches et la ''Load Store Queue''. Leur étude sera plus ou moins séparée dans ce qui suit, pour chaque classe d'architecture. ===La première génération de CPU AMD : les architectures K5, K6, K7, K8 et K10=== La première génération de processeurs AMD est celle des architectures K5, K6, K7, K8 et K10. Il n'y a pas de K9, qui a été abandonné en cours de développement. Les processeurs K5 et K6 portent ce nom au niveau commercial. Par contre, les processeurs d'architecture K7 sont aussi connus sous le nom d''''AMD Athlon''', les AMD K8 sont connus sous le nom d''''AMD Athlon 64''', et les architecture K10 sont appelées les '''AMD Phenom'''. Comme le nom l'indique, l'architecture K8 a introduit le 64 bits chez les processeurs AMD. Elles ont une architecture assez similaire pour ce qui est du chargement et des caches. Toutes disposent d'au minimum un cache L1 d'instruction et d'un cache L1 de données. Le K5 n'avait que ces caches, mais un cache L2 a été ajouté avec le K7, puis un L3 avec le K10. L'AMD K5 avait une TLB unique, mais les processeurs suivants avaient une TLB pour le L1 d'instruction et une autre pour le L1 de données. Idem pour le cache L2, avec deux TLB : une pour les données, une pour les instructions. Les caches L1/L2 sont de type exclusifs, à savoir que les données dans le L1 ne sont pas recopiées dans le L2. Le cache L2 est précisément un cache de victime, qui mémorise les données/instructions, évincées des caches L1 lors du remplacement des lignes de cache. L'introduction du cache L2 a entrainé l'ajout de deux TLB de second niveau : une L2 TLB pour les données et une autre pour les instructions. Les architectures K8 et K10 ont ajouté un cache L3, avec un accès indirect à travers l'interface avec le bus. : L'AMD K7 originel, aussi appelée Athlon classique, n'avait pas de cache L2, mais celui-ci était placé sur la carte mère et fonctionnait à une fréquence moitié moindre de celle du CPU. L'Athlon Thunderbird, puis l'Athlon XP, ont intégré le cache L2 dans le processeur. {|class="wikitable" |- ! Architecture AMD ! colspan="5" | Caches |- | rowspan="2" | K5 | L1 instruction || L1 données || colspan="3" | |- | colspan="2" | TLB unique || colspan="3" | |- | colspan="4" | |- | rowspan="2" | K6 | L1 instruction || L1 données || colspan="3" | L2 unifié |- | TLB L1 instruction || TLB L1 données || colspan="3" | |- | colspan="6" | |- | rowspan="2" | K7, K8 | L1 instruction || L1 données || colspan="2" | L2 unifié || |- | TLB L1 instruction || TLB L1 données || TLB L2 instruction || TLB L2 données || |- | colspan="6" | |- | rowspan="2" | K10 | L1 instruction || L1 données || colspan="2" | L2 unifié || L3 |- | TLB L1 instruction || TLB L1 données || TLB L2 instruction || TLB L2 données || |} Fait important, les architectures K5 à K10 utilisent la technique du '''prédécodage''', où les instructions sont partiellement décodées avant d'entrer dans le cache d'instruction. Le prédécodage facilite grandement le travail des décodeurs d'instruction proprement dit. Par contre, le prédécodage prend de la place dans le cache L1 d'instruction, une partie de sa capacité est utilisé pour mémoriser les informations prédécodées. C'est donc un compromis entre taille du cache et taille/rapidité des décodeurs d'instruction. Sur les architectures K5 et K6, le prédécodage précise, pour chaque octet, si c'est le début ou la fin d'une instruction, si c'est un octet d'opcode, en combien de micro-opérations sera décodée l'instruction, etc. A partir de l'AMD K7, le prédécodage reconnait les branchements inconditionnels. Lorsqu'un branchement inconditionnel est pré-décodé, le pré-décodage tient compte du branchement et continue le pré-décodage des instructions à partir de la destination du branchement. Le système de prédécodage est abandonnée à partir de l'architecture Bulldozer, qui suit l'architecture K10. La prédiction de branchement de ces CPU tire partie de ce système de pré-décodage, à savoir que les prédictions de branchement sont partiellement mémorisées dans les lignes de cache du L1 d'instruction. Par exemple, l'AMD K5 se passe de ''Branch Target Buffer'' grâce à cela. Si une ligne de cache contient un branchement, elle mémorise l'adresse de destination de ce branchement, en plus des bits de pré-décodage. Si il y a plusieurs branchements dans une ligne de cache, c'est l'adresse de destination du premier branchement pris dans cette ligne de cache qui est mémorisée. Un défaut de cette approche est que si le branchement n'est pas dans le L1 d'instruction, aucune prédiction de branchement ne peut être faite et le préchargement ne peut pas fonctionner. C'est une limitation que n'ont pas les BTB découplées du cache L1 : elles peuvent prédire un branchement qui a été évincé dans le L2 ou le L3, tant que l'entrée associée est dans le BTB. Les prédictions peuvent même servir à précharger les instructions utiles. [[File:Comparaison du chargement de l'AMD K5 et K6.png|centre|vignette|upright=2|Comparaison du chargement de l'AMD K5 et K6]] Au niveau du décodage, on trouve de nombreuses différences entre les premières architectures AMD. L'AMD K5 contient 4 décodeurs hybrides, afin de décoder 4 instructions par cycles. Le K5 a quatre décodeurs simples couplés à 4 décodeurs complexes avec chacun un accès au micro-code. Une instruction peut donc passer par a donc deux voies de décodage : un décodage rapide et simple pour les instructions simples, un décodage lent et passant par le microcode pour les instructions complexes. Pour décoder 4 instructions, les deux voies sont dupliquées en 4 exemplaires, ce qui a un cout en circuits non-négligeable. L'AMD K6 utilise moins de décodeurs et ne peut que décoder deux instructions à la fois maximum. Par contre, il fournit en sortie 4 micro-opérations. Il intègre pour cela deux décodeurs simples, un décodeur complexe et un décodeur micro-codé. Un décodeur simple transforme une instruction simple en une ou deux micro-opérations. Il est possible d'utiliser les deux décodeurs simples en même temps, afin de fournir 4 micro-opérations en sortie du décodeur. Les deux autres décodent une instruction complexe en 1 à 4 micro-opérations. Si jamais la ou les deux instructions sont décodées en 1, 2 ou 3 micro-opérations, les micro-opérations manquantes pour atteindre 4 sont remplies par des NOPs. Pour le K7 et au-delà, le processeur dispose de décodeurs séparées pour les instructions micro-codées de celles qui ne le sont pas. Le processeur peut décoder jusqu’à 3 instructions par cycle. Le décodage d'une instruction microcodée ne peut pas se faire en parallèle du décodage non-microcodé. C'est soit le décodeur microcodé qui est utilisé, soit les décodeurs câblés, pas les deux en même temps. Le décodage d'une instruction prend 4 cycles. Les instructions non-microcodées sont décodées en une seule micro-opération, à un détail près : le CPU optimise la prise en charge des instructions ''load-up''. La différence entre le K6 et le K7 s'explique par des optimisations des instructions ''load-up''. Sur le K6, les instructions ''load-up'' sont décodées en deux micro-opération : la lecture en RAM, l'opération proprement dite. Mais sur le K7, une instruction ''load-up'' est décodée en une seule micro-opération. En conséquence, les décodeurs simples sont fortement simplifiés et le décodeur complexe disparait au profit d'un microcode unique. [[File:Décodage sur le K5 et le K5.png|centre|vignette|upright=3|Décodage sur le K5 et le K5]] ====Les micro-architectures K5 et K6 d'AMD==== Les deux premières architectures étaient les architectures K5 et K6, l'architecture K6 ayant été déclinée en quatre versions, nommées K6-1, K6-2, et K-3, avec une version K6-3 bis. Elles sont regroupées ensemble car elles ont beaucoup de points communs. Par exemple, tout ce qui a trait au chargement et au cache était similaire, de même que les unités de calcul. Les deux architectures avaient n'avaient pas de cache L2 et devaient se contenter d'un cache L1 d'instruction et d'un cache L1 de données. L'AMD K5 incorpore une TLB unique, alors que le K6 utilise des TLB séparées pour le cache d'instruction et le cache de données. Une différence entre l'architecture K5 et K6 est que la première utilise des caches normaux, alors que la seconde utilise des ''sector caches''. Les deux architectures disposaient des unités de calcul suivantes : deux ALU entières, une FPU, deux unités LOAD/STORE pour les accès mémoire, une unité de branchement et une ou plusieurs unités SIMD. Une organisation classique, donc. Pour les unités entières, il y avait deux ALU simples, un ''barrel shifter'' et un diviseur. Il n'y a pas d'erreur, le processeur incorpore un circuit diviseur, mais pas de circuit multiplieur. La raison est que la multiplication est réalisée par la FPU ! En effet, le multiplieur flottant de la FPU intègre un multiplieur entier pour multiplier les mantisses, qui est utilisé pour les multiplications entières. La même technique a été utilisée sur l'Atom, comme vu plus haut. Le tout était alimenté par deux ports d'émission, appelés ports X et Y. Sur l'architecture K5, le ''barrel shifter'' et le diviseur sont des ports différents. {|class="wikitable" |+ AMD K5 |- ! Port X ! Port Y |- | ALU simple | ALU simple |- | ''Barrel Shifter'' | Diviseur |} Sur l'architecture K6, le ''barrel shifter'' et le diviseur sont sur le même port. {|class="wikitable" |+ AMD K6 |- ! Port X ! Port Y |- | ALU simple | ALU simple |- | | ''Barrel Shifter'' |- | | Diviseur |} Niveau unités mémoire, le K5 avait deux unités LOAD/STORE, chacune capable de faire lecture et écriture. Par contre, la ''store queue'' n'a qu'un seul port d'entrée, ce qui fait que le processeur peut seulement accepter une écriture par cycle. Le processeur peut donc émettre soit deux lectures simultanées, soit une lecture accompagnée d'une écriture. Impossible d'émettre deux écritures simultanées, ce qui est de toute façon très rare. L'architecture K6 utilise quant à elle une unité LOAD pour les lectures et une unité STORE pour les écritures. Ce qui permet de faire une lecture et une écriture par cycle, pas autre chose. Niveau unités SIMD, l'architecture K7 n'avait qu'une seule unité SIMD, placée sur le port d'émission X. L'architecture K8 ajouta une seconde unité SIMD, sur l'autre port d'émission entier. De plus, trois ALU SIMD ont été ajoutées : un décaleur MMX, une unité 3DNow!, une unité mixte MMX/3DNow. Elles sont reliées aux deux ports d'émission entier X et Y ! Elles ne sont pas représentées ci-dessous, par souci de simplicité. [[File:Unité de calcul des processeurs AMD K5 et K6.png|centre|vignette|upright=2|Unité de calcul des processeurs AMD K5 et K6. les unités sur la même colonnes sont reliées au même port d'émission.]] Si les unités de calcul et le chargement sont globalement les mêmes, les deux architectures se différencient sur l'exécution dans le désordre. L'AMD K5 utilise du renommage de registre dans le ROB avec des stations de réservation. Par contre, l'AMD K6 utilise un ''scheduler'' centralisée. De plus, son renommage de registre se fait avec un banc de registre physique. L'architecture AMD K5 utilisait de deux stations de réservation par unité de calcul, sauf pour les deux unités mémoire partageaient une station de réservation unique (deux fois plus grande). Les stations de réservation sont cependant mal nommées, vu que ce sont en réalité des mémoire FIFO. Une micro-opération n'est émise que si elle est la plus ancienne dans la FIFO/station de réservation. Le renommage de registres se faisait dans le tampon de ré-ordonnancement, il n'y avait pas encore de banc de registre physique. Le tampon de ré-ordonnancement faisait seulement 16 instructions. [[File:AMD K5.jpg|centre|vignette|upright=3|AMDK5 Diagramme.]] L'architecture K6 remplace les stations de réservations par un ''scheduler'' centralisée. Les 4 micro-opérations renommées sont écrites dans le ''scheduler'' par groupe de 4, NOP de ''padding'' inclus. le ''scheduler'' centralisé contient 24 micro-opérations, groupées en 6 groupes de 4 micro-opérations, avec potentiellement des NOP dedans suivant le résultat du décodage. L'avantage est que l'implémentation de le ''scheduler'' est simple. le ''scheduler'' centralisée permettait d'émettre 6 micro-opérations en même temps (une par unité de calcul/mémoire). Le renommage de registres se faisait dans le tampon de ré-ordonnancement, il n'y avait pas encore de banc de registre physique. Le processeur utilisait un renommage avec un banc de registre physique. Le banc de registre physique pour les entiers contenait 48 registres, dont 24 étaient des registres architecturaux et 24 étaient des registres renommés. Sur les 24 registres architecturaux, 16 avaient une fonction de ''scratchpad'' que les ''datasheets'' d'AMD ne détaillent pas, les 8 restants étaient les registres généraux EAX, EBX, etc. [[File:AMD K6 Little foot & Modl 6.png|centre|vignette|upright=3|AMD K6 original.]] ====Les micro-architectures K7, K8 et K10 d'AMD==== Les micro-architectures suivantes sont les architectures K7, K8 et K10. Les architectures K7, K8 et K10 sont assez similaires. La différence principale entre le K7 et le K8 est le support du 64 bits. Les apports du K10 sont la présence d'un cache L3, d'une unité de calcul supplémentaire et d'améliorations de la prédiction de branchement. La taille de certains caches a été augmentée, de même que la largeur de certaines interconnexions/bus. L'architecture K7 des processeurs Athlon utilisait le renommage de registre, mais seulement pour les registres flottants, pas pour les registres entiers. Le ranommeg des registres flottants étaient réalisé via un banc de registres physique, ne contenant que des registres flottants. Les architectures K8 et K10 utilisent le renommage de registres pour tous les registres, entiers comme flottants. Par contre, le renommage de registre n'est pas réalisé de la même manière pour les registres entiers et flottants. Les registres entiers sont renommés dans le tampon de ré-ordonnancement, comme c'était le cas sur les architectures Intel avant le Pentium 4. Par contre, les registres flottants sont renommés grâce à un banc de registre physique. Le K8 est donc un processeur au renommage hybride, qui utilise les deux solutions de renommage principales. A partir du K7, le CPU optimise la prise en charge des instructions ''load-up''. Les instructions ''load-op'' sont appelées des macro-opérations dans la terminologie d'AMD, et aussi d'Intel. L'idée est que les instructions ''load-up'' sont décodées en micro-opérations intermédiaires. Elles sont propagées dans le pipeline comme étant une seule micro-opération, jusqu'à l'étage d'émission. Lors de l'émission, les instructions ''load-up'' sont scindées en deux micro-opérations : la lecture de l'opérande, puis l'opération proprement dite. Faire ainsi économise des ressources et optimise le remplissage du tampon de ré-ordonnancement, des ''schedulers''s, des stations de réservation, etc. Le tampon de réordonnancement est combiné avec divers circuits en charge de l'exécution dans le désordre, dans ce qui s'appelle l'''instruction control unit''. Il contient de 72 à, 84 instructions, qui sont regroupées en groupes de 3. Là encore, comme pour le K5 et le K6, le tampon de réordonnancement tient compte de la sortie des décodeurs. Les décodeurs fournissent toujours trois micro-opérations par cycle, quitte à remplir les vides par des NOP. Le tampon de réordonnancement reçoit les micro-opérations, NOP inclus, par groupes de 3, et est structuré autour de ces triplets de micro-opération, y compris en interne. Pour ce qui est de l'unité mémoire, elle est précédée par une file de µops mémoire, qui émet les accès mémoire dans l'ordre du programme. Elle est souvent qualifiée de ''Load-Store Queue'', mais ce n'est pas la terminologie que nous utilisons dans ce cours. La file de micro-opération lire/écrire 64 bits par cycle depuis le cache L1, ce qui fait un seul accès au cache par cycle. La file de µops mémoire est appelée la ''Pre-Cache Queue''. Si au vu de son nom, vous avez deviné qu'il y avait une ''Post-Cache Queue''. Elle mémorise les lectures/écritures émises, mais qui ont levé un défaut de cache L1. Elle ne fait pas partie de la file de µops mémoire proprement dite. Les architectures K7, K8 et K10 ont des unités de calcul très similaires. Concrètement, il y a trois ALU entières, trois unités de calcul d'adresse, et une FPU. Le processeur incorpore, aussi un multiplieur entier, relié sur le port d'émission de la première ALU. La FPU regroupe un additionneur flottant, un multiplieur flottant, et une troisième unité LOAD/STORE pour les lectures/écritures pour les nombres flottants. L'architecture K8 ajoute une unité de manipulation de bit, la K10 un diviseur entier. [[File:Unité de calcul des processeurs AMD K7, K8 et K10.png|centre|vignette|upright=2|Unité de calcul des processeurs AMD K7, K8 et K10]] La manière d'alimenter les ALU en micro-opérations varie un petit peu entre les architectures K7, K8 et K10. Il y a cependant quelques constantes entre les trois. La première est qu'il y a un ''scheduler'' séparée pour les flottants, de 36 à 42 entrées, avec renommage de registre. le ''scheduler'' flottante a trois ports d'émission : un pour l'additionneur flottant, un autre pour le multiplieur, et un troisième pour la troisième unité flottante qui s'occupe du reste. La seconde est que chaque ALU entière est couplée avec une unité de calcul d'adresse. Par contre, la méthode de couplage varie d'un processeur à l'autre. : Les stations de réservation sont nommées des ''schedulers'' dans les schémas qui suivent. La micro-architecture K7 avait deux ''schedulers'' : une pour les opérations flottantes, une autre pour les instructions entières et les accès mémoire. le ''scheduler'' entière était reliée à 3 ALU entières et à 3 AGU. Elle pouvait émettre trois micro-opérations en même temps : trois micro-opérations entières, trois micro-opérations mémoire. Les AGU étaient reliées à la file de µops mémoire mentionnée plus haut, ce qui permet d'émettre trois µops mémoire par cycle. Par contre, la file de µops mémoire ne pouvait exécuter qu'une lecture de 64 bits ou une écriture de 64 bits. En clair, trois micro-opérations mémoire peuvent être émises par cycle, cela entraine trois calculs d'adresse simultanés, mais les trois lectures/écritures sont mises en attente dans la file de µops mémoire. Elles s'exécutent alors l'une après l'autre. le ''scheduler'' entière contenait 5 à 6 groupes de 3 macro-opérations. Vous noterez que j'ai parlé de macro-opérations et pas de micro-opérations, car les instructions ''load-up'' sont considérées comme une seule "micro-opération" dans le ''scheduler'' entière. Et cela se marie bien avec un ''scheduler'' unique partagée entre pipeline entier et pipeline mémoire. Une macro-opération était scindée en deux micro-opérations : une micro-opération mémoire et une micro-opération entière. Il est donc avantageux de regrouper unités mémoire et unités entières au même ''scheduler'' pour ce faire. [[File:AMD K7.png|centre|vignette|upright=3|AMD K7]] Sur les architectures K8 et K10, la station de réservation unique de 15 micro-opérations est remplacée par trois stations de réservations, de 8 micro-opérations chacune pour le K8, de 10 pour le K10. Chaque station de réservation entière alimente une unité de calcul entière et une unité de calcul d'adresse. l'unité de calcul d'adresse est reliée à la file de µops mémoire, qui n’exécute toujours qu'un seul accès mémoire par cycle. Le multiplieur est relié à la première station de réservation, sur le même port d'émission que l'ALU. [[File:AMD Husky microarchitecture.png|centre|vignette|upright=3|AMD Husky micro-architecture]] La micro-architecture K10 a été déclinée en plusieurs versions, nommées Grayhound, Grayhound+ et Husky, Husky étant une architecture gravée en 32 nm dédiée aux processeurs A-3000. L'architecture Grayhound a plus de cache et un ROB plus grand, la Husky est quand à elle un peu plus différente. Elle n'a pas de cache L3, contrairement aux autres architectures K10, ce qui simplifie fortement son sous-système mémoire. Par contre, les ''schedulers''s/stations de réservation et le ROB sont plus grands, pareil pour les files dans l'unité mémoire. Une ALU pour les divisions entières a aussi été ajoutée. Pour résumer, les architectures K7, K8 et K10 séparent les pipelines entiers et flottants : trois pipelines entiers avec chacun son unité de calcul, et un pipeline flottant avec plusieurs unités de calcul. Les raisons à cela sont assez diverses. Disons que dupliquer des ALU entières simples prend peu de transistors, là où les gros circuits comme le multiplieur ou la FPU ne sont pas dupliqués. Et cela a un autre avantage : le renommage, ''dispatch'' et l'émission sont plus simples. Les pipelines entiers ont une exécution dans le désordre peu complexe, grâce au grand nombre d'unités de calcul, ce qui fait que le pipeline entier est de seulement 15 cycles au total (chargement et décodage inclus). A l'opposé, la FPU est alimentée par une exécution dans le désordre très complexe, avec banc de registre physique et beaucoup de ressources, mais au prix d'un pipeline flottant plus long de 3 cycles, soit 18 cycles au total. ===La micro-architecture Bulldozer et ses dérivés=== Viennent ensuite les '''micro-architectures Bulldozer''', avec trois révisions ultérieures nommées Piledriver, Steamroller et Excavator. Un détail très important de Bulldozer est que de nombreux circuits sont partagés entre deux cœurs, à un point qui mérite de nombreuses explications. Les processeurs Bulldozer peuvent exécuter deux programmes "en même temps", sur deux cœurs partiellement fusionnés. Cette technique de partage d'unités de calcul entre coeurs s'appelle le '''cluster multithreading''', ou encore les '''architectures à cœurs conjoints''' (''Conjoined Core Architectures''). Les deux cœurs sont séparés pour ce qui est du chemin de données, du ''back-end''. Ils disposent de deux bancs de registres généraux et les ALU entières sont dupliquées. Toute la logique d'exécution dans le désordre est aussi dupliquée, avec deux ROBs, des stations de réservations séparées, etc. L'unité mémoire est aussi dupliquée, chaque cœur dispose de ses propres ''load queue'' et ''store queue'', ainsi de que son propre cache L1 de données. En clair, les chemins de données sont totalement séparés, sauf sur deux points : la FPU et les unités SIMD. La FPU est partagée entre deux coeurs, les unités SIMD sont aussi dans ce cas. Le partage de la FPU permet d'éviter de dupliquer trop de circuits et donc d'économiser des transistors. Le problème est que ce partage est source de dépendances structurelles, ce qui peut entraîner des pertes de performances. Par contre, le ''front-end'' est presque totalement partagé entre deux cœurs. Il n'y a qu'un seul cache d'instruction pour les deux cœurs, la TLB du cache d'instruction est unique, l'unité de prédiction de branchement est partagée entre deux cœurs, les décodeurs d'instruction aussi sont partagés, même la file de µops ! Les seules unités qui sont dupliquées sont la file d'instruction et l'unité de renommage, présentes en deux exemplaires. Concrètement, les deux programmes ont accès au cache à tour de rôle. Un programme a accès au cache à un instant t, mais le cycle suivant pourra être alloué à l'autre programme. Une unité décide de quel programme peut charger ses données, idem pour le décodage. [[File:AMD Bulldozer microarchitecture.png|centre|vignette|upright=3|Microarchitecture Bulldozer d'AMD.]] Au-delà de ce partage entre cœurs, Bulldozer a eu un changement assez important : les stations de réservation sont passées de stations de réservation très décentralisées à une station de réservation unique (pour les µops entières/mémoire), d'environ 40 entrées. L’implémentation de la station de réservation a aussi changée. Car 40 entrées, c'est beaucoup pour l'époque. Elle subit quelques simplifications pour la rendre plus rapide et plus économe en transistors. Les autres processeurs de l'époque utilisaient une station de réservation qui détectait à chaque instant quelle était l'instruction la plus ancienne, qui soit prête pour l’exécution. Mais Bulldozer n'utilisait pas cette technique. A la place, il mémorisait la place de l'instruction la plus ancienne gra^ce à une ''ancestry table''. Et l'instruction la plus ancienne est privilégiée sur toute les autres. Mais si elle n'est pas prête à s'exécuter, la station de réservation choisit une instruction suivant sa position dans la station de réservation (qui reste une mémoire RAM/associative, ne l'oublions pas). Bulldozer utilise aussi les optimisations du contournement et du banc de registre, vues dans le chapitre sur les CPU superscalaires. Le banc de registres généraux est dupliqué, afin de garder des bancs de registres avec peu de ports de lecture/écriture. Chaque banc de registre généraux a 4 ports de lecture et deux d'écriture, ce qui permet d'alimenter 2 ALU entières. En tout, cela permet d'alimenter 4 ALU entières, avec 8 ports de lecture et 4 d'écriture. Le tout alimente 2 ALU entières, et 2 AGUs/unités mémoire. Vu que la FPU est partagée entre deux programmes, sa station de réservation a une taille doublée comparé à la normale. Jugez plutôt : 60 entrées pour la station de réservation, là où les microarchitectures concurrentes d'Intel (''Sandy bridge'') utilisait une station de réservation de 54 entrées pour toutes les instructions entières/flottante/mémoire ! Idem pour le banc de registres flottants, qui n'a pas moins de 160 registres flottants ! Pour ce qui est des instructions SIMD, Bulldozer supporte l'extension AVX, qui fait des calculs du des registres de 256 bits, découpés en entiers/flottants de 64 bits, 32 bits, 16 bits, 8 bits, etc. L'unité SIMD ne gére cependant que des calculs sur 128 bits. Les instructions AVX sont donc découpées en deux µops, chacune traitant la moitié d'un registre SIMD. La performance n'est donc pas améliorée par rapport au SSE. Par contre, les unités SIMD gérent nativement l'opération FMA (une multiplication suivie d'une addition). {|class="wikitable" |- |+ Bulldozer |- ! Station de réservation 1 !! Station de réservation 2 !! Station de réservation 3 !! Station de réservation 4 |- | FMA - 128 bits || FMA - 128 bits || ALU - 128 bits || ALU - 128 bits |- | FMA opérandes entiers - 128 bits || Suffle et permutations || || FSTORE (x87) |} La révision Steamroller sépara le ''front-end'' en deux voies distinctes, une par ''thread''. Concrètement, le processeur se contente maintenant de partager la FPU et les unités SIMD entre deux coeurs, pas plus. Pour cela, elle ajouta un second décodeur d'instruction, une seconde file de micro-opération et une seconde unité de renommage de registres, afin d'améliorer les performances. Niveaux optimisations mineures, les stations de réservation ont été augmentées, elles peuvent mémoriser plus de micro-opérations, idem pour les bancs de registre et les files de lecture/écriture. Un cache de micro-opérations a été ajouté, de même que des optimisations quant au renommage de registre. Des ALU ont aussi été ajoutées, des FPU retirées. [[File:AMD excavator microarchitecture.png|centre|vignette|upright=3|Microarchitecture Excavator d'AMD.]] ===Les micro-architectures ZEN d'AMD=== Les micro-architectures suivantes sont les '''architectures ZEN 1/2/3/4'''. Elles se ressemblent beaucoup, le cœur de l'architecture reste plus ou moins le même. En passant à la suivante, le nombre de registre virtuel augmente, le ''branch target buffer'' augmente en taille, le ROB et les files d'attente grossissent, les caches de micro-opération aussi, les caches grossissent, etc. Une optimisation intéressante est l'ajout d'un cache de micro-opération, qui améliore grandement les performances du ''front-end'', notamment pour les boucles. La micro-architecture Zen 1 est illustrée ci-dessous. Comme on le voit, les registres flottants ont une unité de renommage séparée de celle pour les entiers, mais les deux utilisent du renommage à banc de registre physique. Il y a par contre une différence au niveau des ''schedulers'', notées ''scheduler'' dans le schéma. Les µops flottantes utilisent une station de réservation unique, alors qu'il y a une station de réservation par ALU entière. La raison de ce choix est que les opérations flottantes ont un nombre de cycle plus élevé, sans compter que les codes flottants mélangent bien additions et multiplication. [[File:Zen microarchitecture.svg|centre|vignette|upright=3|Micro-architecture Zen 1 d'AMD.]] La micro-architecture Zen 5 se distingue fortement des 4 microarchitectures précédentes. Premièrement, elle passe à une station de réservation centralisée pour les µops entières, une seconde pour els µops mémoire, et une troisième pour les µops SIMD/flottantes. Le retour à une station de réservation aussi peu décentralisée n'avait pas été vu depuis la microarchitecture Bulldozer. Une autre différence est qu'elle utilise un décodeur ''clustered'', tel que vu dans le chapitre sur les processeurs superscalaires, dans la section "Le décodage superscalaire large". ==La microarchitecture Netburst du Pentium 4== Dans cette section, nous allons voir l'architecture du processeur Pentium 4, qu'on a volontairement laissée de côté précédemment. Pourquoi un tel saut dans le temps ? Parce que le Pentium est complément à part des autres architectures Intel. Le Pentium 4 a représenté une rupture en termes de microarchitecture, qui a été un échec tellement retentissant que les processeurs suivants sont repartis sur la base du Pentium 3. Il introduisait de nombreuses nouveautés architecturales qui étaient très innovantes. Par exemple, il introduisait le renommage avec un banc de registre physique, qui a été utilisé sur tous les processeurs Intel suivants. Mais la plupart de ces innovations étaient en réalité de fausses bonnes idées, ou du moins des idées difficiles à exploiter. Par exemple, le système de pipeline à ''replay'' n'a été utilisé que sur le Pentium 4 et aucun autre processeur ne l'a implémenté. ===Un focus sur la fréquence d'horloge=== La microarchitecture du Pentium 4 a été déclinée en plusieurs versions, dont les finesses de gravure n'étaient pas les mêmes. La microarchitecture Netburst, utilisée sur le Pentium 4, utilisait un pipeline à 20 étage, augmenté à 32 sur une révision ultérieure. Il a existé quatre révisions de l'architecture : Willamette (180 nm), Northwood (130 nm), Prescott (90 nm) et Cedar Mill (65 nm). Un point important est que le Pentium 4 était prévu pour fonctionner à haute fréquence. Ses 1,5 GHz étaient impressionnants pour l'époque, les autres processeurs tournant à une fréquence proche du GigaHertzs. Pour cela, la solution retenue par Intel a été un pipeline très long, avec beaucoup d'étages. Le Pentium 4 a été décliné en plusieurs versions assez proches, chacune avec sa propre finesse de gravure qui n'ont pas toute le même pipeline. Les micro-architectures ''Willamette'' et ''Northwood'' avaient un pipeline de 20 étages, alors que les autres processeurs de l'époque avaient entre 10 et 15 étages maximum. Les micro-architectures ''Prescott'' et ''Cedar Mill'' étaient une refonte qui a fait grimper le nombre d'étages à 31 ! Du jamais vu, il s'agit d'un record pour un processeur commercial. Un pipeline aussi long permet d'exécuter beaucoup d’instructions en même temps, chacune dans un étage, mais aussi d'atteindre de hautes fréquences facilement. Le problème est qu'un pipeline avec autant d'étages a beaucoup de problèmes. Un point important est que la prédiction de branchement est cruciale. Pour rappel, la pénalité en cas de mauvaise prédiction dépend du nombre d'étages avant que le branchement soit résolu. Et les branchements sont résolus soit en fin de décodage, soit dans l'unité de calcul. C'est à dire au milieu du pipeline, soit en fin de pipeline. La pénalité en cas de mauvaise prédiction de branchement était énorme sur le Pentium 4, elle atteignait facilement 30 cycles Pour compenser, le Pentium 4 avait une prédiction de branchement très performante, pour l'époque. J'insiste sur le pour l'époque. Il utilisait un prédicteur qu'on a déjà abordé dans le chapitre sur la prédiction de branchement, précisément un prédicteur adaptatif à deux niveaux avec un historique global de 16 bits. Il avait aussi un ''Branch Target Buffer'' de 4096 entrées. Mais surtout, il intégrait une sorte de précurseur du cache de micro-opération, appelé le cache de traces, qui est détaillé dans la section suivante. ===Le cache de trace du Pentium 4=== Les décodeurs du Pentium 4 ne font pas décoder les instructions, ils mémorisent le résultat dans un cache de micro-opération un peu particulier, appelé le '''cache de trace'''. Une ligne de cache peut mémoriser 6 micro-opérations, ce qui peu sembler peu mais a été repris sur les micro-architectures suivantes. Mais le cache de trace a une grande différence avec un cache de micro-opération normal. Un cache de micro-opération normal mémorise une instruction par ligne de cache. Une instruction est décodée en plusieurs micro-instructions, qui sont enregistrées dans une ligne de cache. Si l'instruction n'utilise par les 6 micro-opérations disponibles, le reste de la ligne de cache n'est pas utilisé. Mais le Pentium 4 optimise le tout de manière ce à ce que ne soit pas le cas. Sur le Pentium 4, la contrainte du "une instruction par ligne de cache" est abandonnée. Une ligne de cache mémorise 6 micro-opérations consécutives, qui peuvent appartenir à plusieurs instructions. Par exemple, si le décodeur décode 4 instructions consécutives en 6 micro-opérations au total, alors le tout prendra une seule ligne de cache sur le Pentium 4. Et les 4 instructions consécutives n'ont même pas à être consécutives en mémoire : il peut y avoir des branchements pris entre ces instructions ! {|class="wikitable" |+ Cache de trace |- ! Ligne de cache | ADD || SUB || ADD || MOV || MUL || ''shift'' |- ! Ligne de cache | colspan="3" | ADD ''load-up'' || MUL || colspan="2" | Branch if Equal |- ! Ligne de cache | XOR || colspan="4" | POP || SUB |- ! ... | colspan="6" | ... |} Pour expliquer cela plus concrètement, nous allons devoir introduire les concepts de trace et de bloc de base. Un '''bloc de base''' (''basic block'') est une suite d'instructions sans branchement, qui est séparé par deux branchements. Le début d'un bloc de base est la destination d'un branchement, un bloc de base se termine avec un branchement. Une '''trace''' est formée en concaténant plusieurs blocs de base. Pour donner un exemple, regardez le code illustré ci-contre. Il est composé d'un bloc de base A, suivi par un bloc de base B, qui peut faire appel soit au bloc C, soit un bloc D. Un tel code peut donner deux traces : ABC ou ABD. La trace exécutée dépend du résultat du branchement qui choisit entre C et D. Le cache de trace mémorise des traces de 6 micro-opérations consécutives. Les traces sont formées en sortie des décodeurs d'instruction, par de subtiles opérations mélangeant mémorisation, décalage et concaténation. Les circuits qui construisent les traces ne sont pas connus, mais ils doivent certainement être très compliqués. toujours est-il qu'un cache de trace peut mémoriser des traces différentes, même si leur début est le même. Par exemple, prenons deux traces, composées des blocs de base A, B, C et D. La première trace est la trace ABC, la seconde est la trace ABD. Les deux traces auront chacune une ligne de cache dédiée. Une trace est réutilisable quand le premier bloc de base est identique et que les prédictions de branchement restent identiques. Pour vérifier cela, le tag du cache de traces contient l'adresse du premier bloc de base, la position des branchements dans la trace et le résultat des prédictions utilisées pour construire la trace. Le résultat des prédictions de branchement de la trace est stocké sous la forme d'une suite de bits : si la trace contient n branchements, le n-ième bit vaut 1 si ce branchement a été pris, et 0 sinon. Même chose pour la position des branchements dans la trace : le bit numéro n indique si la n-ième instruction de la trace est un branchement : si c'est le cas, il vaut 1, et 0 sinon. Si la trace est réutilisée par la suite, elle est lue depuis le cache de traces. Pour savoir si une trace est réutilisable, l'unité de chargement envoie le ''program counter'' au cache de traces, l'unité de prédiction de branchement fournit le reste des informations. Si on a un succès de cache de traces, et la trace est envoyée directement au décodeur. Sinon, la trace est chargée depuis le cache d'instructions et assemblée. Il faut signaler que le cache de trace avait sa propre unité de prédiction de branchement séparée de l'unité de prédiction de branchement normale. [[File:TraceCache.png|centre|vignette|upright=2|Cache de traces.]] Le cache de traces réduisait la longueur du pipeline en cas de succès de cache de trace. Quand les instructions étaient lues depuis le cache de trace, les étages avant le cache de trace ne sont pas utilisés, tout se passe comme s'ils étaient retirés du pipeline. C'est la même chose avec le cache de micro-opération des processeurs modernes, mais l'idée n'existait pas encore à l'époque. Le cache de trace mémorise des traces décodées, ce qui fait qu'un succès de cache de trace contournait non seulement le cache d'instruction, mais aussi les décodeurs. Le temps d'accès au cache de trace pouvait être assez élevé, même s'il était comparable au temps d'accès du cache d'instruction. Le cache de traces a depuis été remplacé par une alternative bien plus intéressante, le cache de micro-opérations, plus flexible et plus performant. Comparé à un cache de trace, la contrainte "une instruction par ligne de cache" simplifie grandement l'implémentation d'un cache de micro-opération. Ne parlons pas de la détection des succès de cache, qui demande d'utiliser les prédictions de branchement. Mais le vrai problème avec le cache de trace est tout autre. Il arrive souvent qu'une micro-opération soit présente dans plusieurs lignes de cache en raison du processus de construction des traces, chose impossible avec un cache de micro-opération. Et c'est un problème, qui réduit la capacité effective du cache de trace. Alors certes, une ligne de cache est plus remplie que sur un cache de micro-opération, on est certain que les 6 micro-opération par ligne de cache sont remplies. Mais la redondance réduit grandement cet avantage. ===L'exécution dans le désordre et le chemin de données du P4=== Le renommage de registres se fait avec un banc de registres physiques avec une table d'alias. Le Pentium 4 avait une exécution dans le désordre très limitée, basée sur la présence de deux files de micro-opération : une pour les accès mémoire, une autre pour les autres instructions. La seconde file regroupait opérations entières et flottantes, elles n'étaient pas séparées. Avec ces deux files, les instructions mémoire étaient exécutées dans l'ordre du programme, les instructions arithmétiques s'exécutaient aussi dans l'ordre du programme, mais une instruction arithmétique pouvait passer avant une instruction mémoire et inversement. L'avantage est que cela permettait de faire des lectures en avance, c'était une forme limitée de lecture non-bloquantes. Il s'agit bel et bien de deux files d'instructions, pas de ''schedulers'' ni de stations de réservation. Le Pentium 4 est le seul processeur commercial qui a utilisé des files de micro-opération séparées, tous les autres utilisent des ''schedulers'' : centralisées pour Intel, décentralisées pour AMD (en général). Le Pentium 2 et 3, bien qu'antérieurs, utilisait une station de réservation unique. Cela peut sembler être un retour en arrière, mais les files d'instructions sont bien plus larges : de 42 micro-opérations pour le Pentium 3, on passe à 120 micro-opérations pour le Pentium 4. Et vu la longueur du pipeline, qui fait qu'il y a plus d'instructions en vol, c'était une nécessité. Mais cela n'aurait pas été possible en utilisant des stations de réservation, pour des raisons de consommation électrique et/ou de budget en transistors, ce qui fait que passer à une file de micro-opération été la solution retenue. Pour les accès mémoire, le Pentium 4 utilisait donc une file de µops mémoire unique, couplée à une file d'écriture (non-représentée sur les schémas qui suivent). La file d'écriture du Pentium 4 était de 24 écritures maximum et gérait le ''Store-to-load forwarding''. Le processeur pouvait émettre une lecture et une écriture à chaque cycle. Il y avait un port d'émission pour les lectures et un autre pour les écritures, tous deux ayant chacun leur propre unité de calcul d'adresse. Le processeur contenait 3 ALU entières, 2 unités de calcul d'adresse et une FPU. La FPU était complétée par une unité pour faire des copies entre registres flottants, des opérations MOV. Pour les AGU, il y en avait une dédiée aux lectures, une autre pour les écritures. Le tout était relié aux ports d'émissions comme suit : [[File:Ports d'émission du Pentium 4.png|centre|vignette|upright=2.5|Ports d'émission du Pentium 4]] Le processeur utilisait deux réseaux de contournement séparés : un pour les opérations flottantes, un pour les opérations entières. Le réseau de contournement pour les opérations entières est aussi relié aux unités de calcul d'adresse. Jusque là, rien de surprenant, le chemin de données du processeur est assez classique. [[File:Architettura Pentium 4.png|centre|vignette|upright=3|Microarchitecture du Pentium 4.]] ===Les unités de calcul entières du Pentium 4=== Sur le Pentium 4, les ALU entières étaient cadencées à une fréquence double de celle du processeur. Les ALU entières pouvaient exécuter deux micro-opérations par cycle, ce qui fait que les ports d'émissions reliés aux ALU devaient eux aussi fonctionner à double fréquence. Pour faire la différence entre les deux fréquences, nous parlerons de fréquence/cycle processeur et de fréquence/cycle de l'ALU. Précisons que seules les ALU entières étaient à double fréquence, pas le multiplieur, pas le ''barrel shifter''. Pour simplifier, nous allons parler d'additionneur plutôt que de l'ALU entière, ce qui sera plus proche de la réalité. Et l'implémentation de l'additionneur du Pentium 4 était très innovante. L'additionneur pouvait exécuter deux additions par cycle, même si les deux additions ont une dépendance. Mais n'allez pas croire que l'implémentation était intuitive, avec un additionneur 32 bit basique très rapide. Non seulement l'additionneur fonctionnait à double fréquence, mais il était aussi pipeliné, avec un système de contournement interne ! Les additionneurs étaient pipelinées, d'une manière très simple. Une addition 32 bits était découpée en trois étapes : deux additions de 16 bits, une dernière étape pour mettre à jour le registre d'état. Pour cela, chaque additionneur était composé de deux additionneur 16 bits chacune, placées l'une après l'autre, avec un registre de pipeline entre les deux. L'additionneur prenait deux cycles d'horloge pour faire son travail : le premier cycle calculait les 16 bits de poids faible, le second calculait les 16 bits de poids fort lors du second cycle. Le tout est appelé '''addition étagée''' (''staggered add'') dans la documentation Intel. Une addition se fait donc en deux étapes, sauf que c'est compensé par le fait que l'additionneur fonctionnait à une fréquence double de celle du processeur ! Le résultat de ce fonctionnement franchement bizarre, est que les 16 bits de poids faible étaient calculés en une moitié de cycle processeur, alors que l'opération complète prenait un cycle. Deux additions consécutives s'exécutaient donc en 1 cycle et demi, alors qu'on aurait cru au premier abord que cela prendrait seulement un cycle. Si on fait les calculs, on s'apercoit que le rythme de croisière est cependant proche de 2 additions par cycle, bien qu'inférieur. 3 additions consécutives se font en deux cycles, 5 additions en 3 cycles, 7 en 4 cycles, etc. Et le Pentium 4 ajoutait un système de contournement interne à l'ALU. En clair, si une addition utilise le résultat de l'addition précédente, les deux peuvent s'exécuter en un cycle d'horloge et demi. Les 16 bits de poids faible de la première addition sont disponibles après un cycle ALU, ce qui permet de démarrer le calcul de la seconde addition au cycle suivant. ===Le ''replay pipeline''=== Le processeur est un processeur triple émission : il peut charger et décoder 3 µops par cycle, le ROB peut terminer 3 µops par cycle, etc. Pourtant, les ports d'émission peuvent émettre 6 instructions par cycle : 4 ports, dont deux à double fréquence. Une telle différence s'explique par l'usage d'un ''replay pipeline'', dont nous avons déjà parlé dans ce cours. Pour rappel, le Pentium 4 suppose que les lectures font tous un succès de cache L1. Si une opération arithmétique utilise la donnée lue comme opérande, le processeur l'émet immédiatement, l'opérande sera disponible une fois l'opération en entrée de l'ALU entière. Mais s'il s'est trompé, le processeur ré-exécute l'instruction après un temps d'attente de quelques cycles, pour se caler sur la latence du cache L2. Et si il y a un défaut de cache L2, l’instruction attend encore. Cela demande de ré-exécuter des instructions émises à tord, ce qui fait que le processeur doit avoir la capacité d'exécution pour. Ce pourquoi le processeur peut émettre 6 µops dans les unités de calcul : 3 µops normales et 3 µops ré-exécutées. ==Les microarchitectures x86 de Cyrix et Via== Les processeurs x86 grand public sont actuellement conçus et commercialisé par deux acteurs : Intel et AMD. Il faut dire que le jeu d'instruction x86 demande une licence pour être utilisée, qu'Intel et AMD refusent de dsitribuer à leurs concurrents, sauf en de très rares occasions. Cependant, il y a eu dans le passé un troisième acteur, qui a reussit à acquérir les droits de la licence x86 : Cyrix, qui a ensuite été racheté par National Semiconductor, lui-même acquis par Via. ===Les architectures compatibles 386 et 486 de Cyrix=== Cyrix a produits plusieurs CPUs et même des co-processeurs x87, avant d'être racheté. Sa carrière commence avec le Cyrix FasMath, un co-processeur arithmétique pour calculs flottants, compatible avec le x87 d'Intel. Il a ensuite produits plusieurs clones du processeur 386 d'Intel, nommés 486SLC et 486DLC. Une dénomination assez trompeuse, vous en conviendrez, mais qui n'est heureusement pas passée inaperçue et leur a valu de nombreuses critiques. Néanmoins, leurs processeurs étaient plus performants que le 386 de base, ce qui fait qu'ils étaient des upgrades corrects pour les PC avec un 386 (les cartes mères compatibles avec le i386 n’étaient pas compatibles avec le i486). Le 486SRX2 et le 486DRX2, sortis plus tard, étaient des versions avec une fréquence encore plus élevée, ce qui augmentait leurs performances. Cyrix récidiva avec le 5x86, un processeur offrant des performances s'approchant du Pentium, mais pour la plateforme 486. Le processeur supportait seulement les instructions du 486, pas les instructions ajoutées sur le Pentium. Son bus était similaire à celui du 486. Mais sa microarchitecture se rapprochait du Pentium, bien que n'étant pas aussi complexe. Il y avait une file d'instruction capable de mettre en attente 3 instructions, un cache unifié, une unité de prédiction de branchement. Malheureusement, la prédiction de branchements avait été désactivée en raisons de bugs matériels qui faisaient crasher le processeur. Niveau ALU, mais il y avait une FPU, une ALU entière et une unité mémoire. Mais il n'y avait pas de double émission. [[File:Cy5x86 arch (cropped).png|centre|vignette|upright=2.5|Cy5x86 arch (cropped).]] ===Le Cyrix 6x86 : une architecture superscalaire avancée=== Le '''Cyrix 6x86''' est là où la superscalarité apparait dans la gamme Cyrix. Le processeur était non pas une upgrade pour des cartes mères existantes, mais un concurrent direct du Pentium. C'était un processeur à double émission, avec exécution dans le désordre et renommage de registre. L'organisation de ses caches est assez originale. Il avait un cache principal de 16 kibioctets, qui mémorisait à la fois données et instructions, couplé à un cache d'instruction de 256 octets. En termes modernes, on dirait qu'il disposait d'un cache L2, couplé à un cache L1 d'instructions, mais sans cache L1 pour les données. Le cache unifié/L2 était un cache double port. Le cache d'instruction était totalement associatif. [[File:Cy6x86 arch.png|centre|vignette|upright=2.5|Cy6x86 microarchitecture.]] Le processeur supportait une double émission bien plus complète que celle du Pentium. Il disposait de deux pipelines entiers, nommés X et Y. Le pipeline X était le seul à pouvoir exécuter branchements et opérations flottantes, c'était le seul connecté à la FPU. Par contre, il était possible d'émettre un branchement ou une opération flottante dans le pipeline X, tout en émettant une seconde instruction dans le pipeline Y. Ce que le Pentium ne pouvait pas faire. Certaines instructions ne pouvaient cependant pas être appariées avec une autre : les multiplications/divisions, les ''string instruction'', les ''far jumps'', les accès aux entrées-sorties, et des instructions systèmes. La FPU pouvait exécuter des instructions en parallèle de l'ALU entière. Elle avait une file de µops de 4 µops flottantes. Elle avait aussi sa propre ''Store queue'', spécifiquement dédiée aux écritures flottantes, séparée de la ''Store Queue'' pour les écritures "normales", celles des registres généraux. Cette séparation est possible du fit que les registres flottants et généraux sont séparés sur le jeu d'instruction x86. [[File:Cyrix 6x86 arch.svg|centre|vignette|upright=2.5|Cy6x86 microarchitecture.]] Le Cyrix 6x86 avait de nombreux avantages sur le Pentium. Il intégrait notamment du renommage de registres pour les registres entiers, ainsi que le contournement, ce que ne faisait pas le Pentium. Et il pouvait faire de la double émission entière-flottante, alors que le Pentium ne pouvait pas émettre de seconde µop en parallèle avec une opération flottante. Tout cela le rendait bien plus performant que le Pentium, sur le papier. Sauf que sa FPU était peu performante, proche de celle du 5x86. Les concepteurs du processeur avaient mis le paquet sur les opérations entières, en délaissant les opérations flottantes. Les applications développées pour le Pentium, qui répartissaient au mieux leurs calculs entre FPU et ALU entière, marchaient donc moins bien sur le 6x86. Le successeur du 6x86, le '''Cyrix Jalapeno''', était un concurrent du Pentium 2/3. Son pipeline passait de 7 à 11 étages, ce qui permettait des augmentation de fréquence importante. Son cache était quadruplé en taille et passait à 8 voies. Et pour ce qui de la superscalarité, il était maintenant capable d'émettre deux µops flottantes par cycle : une partait dans l'additionneur flottant, l'autre dans un multiplieur flottant. ===Les processeurs de marque Via=== Après deux rachats, la licence x86 de Cyrix est passée dans les main de Via. Via avait racheté Cyrix, mais aussi Centaur, un autre concepteur de processeur. Via produisit plusieurs processeurs x86, basés sur des design provenant non pas de Cyrix, mais de Centaur, pour leur microarchitecture. Le premier processeur de cette lignée, le mal-nommé Cyrix III, a d'ailleurs été renommé en C3, parce qu'il n'avait aucun lien avec les microarchitectures de Cyrix et n'utilisait pas leurs technologies. Les '''processeurs Via C3''' et '''Via C7''' étaient des processeurs 32 bits. Ils étaient prévus pour des ordinateurs portables et ciblainet une faible consommation d'énergie, plutôt que des hautes performances. Ils n'avaient pas d'exécution dans le désordre, mais utilisaient une superscalarité limitée à la double émission. Le C3 regroupe en réalité deux microarchitecture semblables. Les modèles Samuel 2 et Ezra utilisaient la première version de la microarchitecture, alors que les processeurs Nehemiah avaient une version améliorée de celle-ci. Le pipeline passait de 12 à 16 étages, sa FPU est améliorée, les extensions SIMD sont revues (passage au SSE, abandon du 3DNow!). Les processeurs C7 utilisent cette même microarchitecture, bien qu'améliorée sur quelques détails. [[File:VIA Nano Architecture Blockdiagram.jpg|vignette|upright=1.5|VIA Nano Architecture.]] Par la suite, Via sortit le '''Via Nano''' en 2008 . C'était le premier CPU 64 bits de la marque. Il avait tout d'un design moderne, avec exécution dans le désordre, prédiction de branchement complexe, hiérarchie de cache classique, préchargement, etc. Il implémentait la superscalarité en triple émission. Pour cela, son ''front-end'' chargeait 16 octets par cycle, qui étaient accumulés dans une file d'instruction. Trois décodeurs lisaient les instructions dans cette file, puis envoyaient trois µops dans une file de µops de taille inconnue. Le renommage de registre pouvait lui aussi renommer trois µops par cycle. Niveaux unités, il avait deux ALU entières, une unité LOAD, une unité STORE, deux unités SIMD (une pour les additions SIMD, une pour les multiplications SIMD). Chaque unité avait sa propre file de µops, qui faisait entre 8 et 12 entrées. Les unités LOAD et STORE avaient chacune leur propre file de µops, il n'y avait pas de file de µops partagée entre les deux. L'unité LOAD alimentait une ''load queue'' de 16 lectures, alors que l'unité STORE alimentait une ''store queue'' de 16 écritures. Les unités de calcul sont décrites dans le tableau ci-dessous : {|class="wikitable" |- ! !! ALU 1 !! ALU 2 !! FPU/SIMD 1 !! FPU/SIMD 2 !! LOAD !! STORE |- ! File de µops | 12 entrées || 11 entrées || 8 entrées || 24 entrées || 8 entrées || 8 à 13 entrées, selon les sources |- ! rowspan="5" | Opérations | Opérations entières de base || Opérations entières de base || || || LOAD || STORE |- | Décalages et rotations || Multiplication entière 32 bits || Multiplication entière 64 bits || || || |- | CMOV || CMOV || Division entière 64 bits || Division entière 64 bits || || |- | ''Add With Carry'' || Branchements || Division flottante || || || |- | || || SIMD opérations entières + FMUL 128 bits || SIMD opérations entières + FADD 128 bits || || |} Les processeurs qui ont suivis sont des processeurs commercialisés uniquement en Chine, à destination du marché chinois et subventionnés (si ce n'est plus), par l'administration chinoise.Le peu d'informations qui sont disponibles dessus sont disponibles sur le substack ''Chips and cheese'', qui a notamment quelques articles sur les processeurs Longsoon. Pour une histoire complète et une review en profondeur des architectures de Via, je conseille les articles du blog ''Chips and cheese'' : * [https://chipsandcheese.com/p/the-weird-and-wacky-world-of-via-the-3rd-player-in-the-modern-x86-market The Weird and Wacky World of VIA, the 3rd player in the “Modern” x86 market] * [https://chipsandcheese.com/p/the-weird-and-wacky-world-of-via-part-2-zhaoxins-not-quite-electric-boogaloo The Weird and Wacky World of VIA Part 2: Zhaoxin’s not quite Electric Boogaloo] * [https://chipsandcheese.com/p/zhaoxin-part-3-a-sort-of-anti-climax Zhaoxin Part 3: A Sort of Anti-Climax] * [https://chipsandcheese.com/p/via-part-4-a-deep-dive-into-centaurs-last-cpu-core-cns VIA Part 4 – A Deep Dive into Centaur’s Last CPU Core: CNS] * [https://chipsandcheese.com/p/examining-centaur-chas-die-and-implementation-goals Examining Centaur CHA’s Die and Implementation Goals] <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les processeurs superscalaires | prevText=Les processeurs superscalaires | next=Les processeurs VLIW et EPIC | nextText=Les processeurs VLIW et EPIC }} </noinclude> jr542ps0xaqwqhg8je7dbp0a2t43b2m 773638 773637 2026-09-29T21:20:29Z Mewtow 31375 773638 wikitext text/x-wiki Dans ce chapitre, nous allons étudier des exemples de processeurs x86, ceux présents dans nos PC. Nous n'allons pas voir les anciens processeurs comme le 286, le 386 ou le 486. Nous allons commencer avec le Pentium 1, et les processeurs commerciaux qui ont suivis. Tous les processeurs que nous allons voir dans ce chapitre sont des processeurs superscalaires. De fait, ce n'est pas pour rien si ce chapitre se situe après le chapitre sur les processeurs superscalaires. Par contre, nous allons voir que certains n'ont pas d'exécution dans le désordre, car elle est arrivée après la superscalarité. Le jeu d'instruction x86 pose quelques problèmes pour la superscalarité, car c'est un jeu d'instruction CISC, avec tous les défauts que ça implique. Un jeu d'instruction CISC a en effet de nombreuses propriétés qui collent mal avec l'émission multiple, avec la '''superscalarité'''. Il y en a plusieurs, certaines impactent le chargement des instructions, d'autres leur décodage, d'autres l'exécution, etc. Premièrement, les instructions sont de longueur variable, entre 1 et 15 octets, ce qui complique leur chargement et leur décodage. En pratique, les processeurs chargent un bloc de 32 à 64 octets, et découpent celui-ci en plusieurs instructions. La conséquence est que l'usage d'instructions trop longues peut poser problème. Imaginez qu'un processeur charge un bloc de 16 octets et que celui-ci ne contienne qu'une seule instruction : on ne profite pas de la superscalarité. Deuxièmement, une partie des instructions est microcodée, faute de mieux. Et cela pose de sérieux challenges pour l'implémentation des décodeurs. Dupliquer le microcode demanderait trop de transistors, ce qui fait que ce n'est pas fait. À la place, il n'y a qu'un seul microcode, ce qui fait que l'on ne peut pas décoder plusieurs instructions microcodées en même temps. Il est cependant possible de profiter de la superscalarité, en décodant une instruction microcodée en parallèle d'autres instructions non-microcodées. Et heureusement, ce cas est de loin le plus fréquent, il est rare que plusieurs instructions microcodées se suivent.' Troisièmement, la présence d'instructions ''load-up'', qui lisent un opérande en mémoire, peut poser problème, mais est aussi source d'optimisations assez intéressantes. En théorie, une instruction ''load-op'' est décodée en deux micro-opération : une pour lire d'opérande en RAM, l'autre pour faire l'opération arithmétique. Sauf que les processeurs x86 modernes optimisent la gestion des instructions ''load-up''. Par exemple, les premiers processeurs Atom géraient des micro-opérations de type ''load-up'', directement dans le chemin de données ! D'autres processeurs utilisent la technique de la '''micro-fusion''' pour retarder le décodage réel des instructions ''load-up'' assez loin dans le pipeline. Avec eux, une instruction ''load-op'' est décodée en une seule "macro-opération", qui est propagée dans le pipeline, pour être scindée en deux micro-opérations un peu avant les ALU et l'unité mémoire. L'avantage est qu'une macro-opération ne prend qu'une seule entrée dans le tampon de ré-ordonnancement, le ''scheduler'', la file de micro-opération, et les autres structures similaires. Il faut cependant noter qu'avoir des instructions complexes peut avoir des avantages sur les processeurs superscalaires à exécution dans le désordre. Les avantages sont liés au fait que certaines instructions complexes peuvent être implémentées avec des circuits dédiés, plutot qu'avec une suite de µops ou d'instructions. Les performances sont alors meilleures car une grosse instruction complexe devient une seule µops, ce qui aide le renommage de registres, prend moins de place dans le ROB ou les stations de réservation, etc. : Pour avoir une petite idée des avantages et inconvénients, je conseille la lecture de cet articles de blog : [https://chipsandcheese.com/p/why-x86-doesnt-need-to-die Why x86 Doesn’t Need to Die]. Il s'agit d'une réponse à cet autre article, plus court : [https://hackaday.com/2024/03/21/why-x86-needs-to-die/ Why X86 Needs To Die]. ==Introduction : généralités et historique== Avant de voir les processeurs dans un ordre chronologique, il est bon de faire quelques généralités, histoire de bien cadrer ce qui va suivre. Les architectures Intel et AMD se classent en deux types : une classe de microarchitectures pour la haute performance, une classe de microarchitectures moins performante mais plus économe. La première est utilisée sur les PC fixes et parfois sur les serveurs, les processeurs pour ''desktop'' et serveur pouvant être différents. Les microarchitectures pour serveurs sont souvent des variantes des microarchitectures pour ''desktop''. Les serveurs ont surtout besoin d'exécuter un grand nombre d programmes/processus en même temps, ce qui fait qu'elles ont besoin d'un grand nombre de cœurs moins de cœurs performants individuellement. Pour les applications ''desktop'', c'est l'inverse : elles ont besoin de cœurs performants, quitte à en avoir moins. Pour la seconde catégorie, parler de microarchitecture basse consommation serait peu-être un peu exagéré, car elles ne visent pas non les smartphones et autres appareils embarqué. Mais elles le sont suffisamment pour entrer dans un ordinateur portable, où l'autonomie de la batterie est très importante. Dan ce chapitre, nous allons parler exclusivement des processeurs haute performance, les microarchitectures "basse consommation" seront pour le prochain chapitre. ===Les différences et points communs entre µarchs d'Intel et d'AMD=== Les microarchitectures Intel et AMD ne sont pas très différentes quand on regarde de loin. Elles ont évoluées dans la même direction, avec une introduction précoce de la superscalarité, puis de l'exécution dans le désordre, du renommage de registre, de la prédiction de branchement, d'un cache de µops, etc. Néanmoins, il y a des différences entre les deux qui relèvent de la tendance générale, avec de nombreuses exceptions : * Intel préfère utiliser un ''scheduler'' centralisé, alors qu'AMD préfère des stations des ''schedulers'' décentralisés. * AMD sépare les unités flottantes/SIMD des unités entières, elles ont des ports d'émission bien séparés. Intel, en comparaison, préfère mettre une ALU et une unité FPU/SIMD sur le même port d'émission. Mais il s'agit là de tendance, avec de nombreuses exceptions. Par exemple, les microarchitectures K6 et Bulldozer d'AMD utilisaient une station de réservation centralisé. De même, les micraorchitectures récentes d'Intel tendent de plus en plus à scinder le ''scheduler''s, de plus en plus avec le temps. Le fait est qu'elle a dû grossir avec le temps, au point de devoir être scindée tellement elle prenait de circuits. La microarchitecture Skylake l'a scindée en une station de réservation pour les µops mémoire et une autre pour le reste. La microarchitecture ''Sunny Cove'' a ensuite scindée la station de réservation mémoire en deux : une pour les lectures et une pour les écritures. Dans ce chapitre, nous ne parlerons pas des unités de prédiction de branchement, ni de la hiérarchie des caches. Et les raisons sont différentes entre les eux. Les unités de prédiction de branchement ont été discutées dans le chapitre sur la prédiction de branchement. De plus, de nombreux processeurs différents utilisent des unités de prédiction de branchement qui ont des algorithmes similaires. Mais la raison principale est que l'unité de prédiction de branchement est complétement détachée du reste du pipeline, cache d'instruction excepté sur certaines microarchitectures. N'importe quelle unité de branchement peut s'adapter à n'importe quel pipeline/microarchitecture, tant que ses ''itmings'' et délais en cycles d'horloge tiennent la route. Il en est plus ou moins de même pour la hiérarchie de caches. Me système mémoire est assez indépendant du reste de la microarchitecture. Dans ce qui va suivre, vous allez rapidement remarquer quelque chose d'assez évident. Les processeurs x86 ont en quelque sorte deux "pipelines" séparés, assez différents les unes des autres, qui ont évolués en parallèle. D'un côté, il y a le "pipeline" entier/mémoire, qui exécute les opérations entières et les µops mémoire. Il regroupe des ALU entières, des AGU (unité de calcul d'adresse) et les unités mémoire LOAD/STORE. Il communique directement avec la ''Load/Store Queue'', car c'est là dedans que se font les calculs d'adresse. A l'opposé, les calculs flottants sont réalisés dans des pipelines séparés, sauf sur quelques processeurs qui font exception, comme les microarchitectures Core. Nous verrons pourquoi dans la section suivante. Pour ce qui est des accès mémoire, les microarchitectures Intel et AMD ont évolué différemment. Intel a suivi cette progression : * Le Pentium 1 utilisait une unité mémoire intégrée dans le pipeline entier. * Le Pentium 3 a séparé l'unité mémoire du pipeline entier, mais ne restait capable que d'émettre un accès mémoire par cycle. * La microarchitectures Core a ajouté la possibilité de faire deux émissions mémoire simultanées : une lecture avec une écriture. * Par la suite, de nouveaux ports de lectures ont été rajoutés. ===Un aparté sur la FPU des processeurs x86=== Les processeurs x86 oint acquis une FPU assez rapidement dans l'histoire. Les processeurs 286 et 386 n'avaient pas de FPU, mais pouvaient faire appel à un coprocesseur spécialisé dans les calculs flottants : le '''coprocesseur x87'''. Le coprocesseur x87 intégrait 8 registres flottants et supportait 8quelques instructions flottante, comme FADD pour l'addition, FSUB pour la soustraction, FMUL pour la multiplication, FDIV pour la division, etc. Le coprocesseur x87 a été intégré dans le processeur assez rapidement, dès le 486. Pour cela, le 486 intégrait une FPU et les 8 registres flottants. Les instructions FADD, SUB, FMUL, et quelques autres, ont aussi été ajoutées au jeu d'instruction de base du 486. Elles formaient une '''extension du jeu d'instruction x86''', à savoir des paquets d'instructions qui n'étaient pas dans le jeu d’instruction de base, mais qui ont été rajoutés par la suite et sont devenus des standards. Détail extraordinairement important : le coprocesseur x87 intégrait aussi 8 registres, avec une organisation très spéciale. Les registres n'étaient pas "adressables" avec des noms de registres, ils étaient à la place organisé en pile d'opérande. Vous vous rappelez peut-être que, dans le chapitre "les machines à pile et mémoire-mémoire", j'ai parlé des processeurs avec une pile d'opérande. Le coprocesseur x87 en était un. Et cela posait pas mal de problème pour rendre les opérations flottantes performantes. Notamment, cela posait problème pour le renommage de registres. Le fait que les registres flottants et généraux soient séparés fait qu'ils sont souvent renommés à part, dans deux unités e renommage différentes. Les registres flottants ont été les premiers à être renommés. De nombreux processeurs renommaient les registres flottants, alors que les registres généraux n'étaient pas renommés. La raison est que quand on un budget en transistor limité, on ne peut pas renommer les deux. Et autant c'est utile de renommer les registres généraux, autant la pile de registre du x87 rendait cela quasiment nécessaire pour avoir des performances convenables. un autre détail est que les optimisations du renommages sont d'abord arrivées sur le pipeline flottant, avant d'être portées sur le pipeline entier. Un exemple est celui des techniques d'élimination des MOV (''MOV elimination''), qui traitent les instructions MOV entre registres directement dans l'unité de renommage. Ou encore, les techniques avec des idiomes pour mettre à zéro un registre en le Xorant avec lui-même. Elles ont été utilisées d'abord sur les registres flottants/SIMD, avant d'arriver sur les registres généraux. Quelques processeurs les utilsaient pour les registres flottants, mais pas les registres généraux. Il en est de même avec le renommage dans le ROB versus à banc de registre physique. Quelques CPU renommaient les registres flottants avec un renommage à banc de registre physique, avec que le pipeline entier utilisait encore le renommage dans le ROB. Les processeurs Athlon et Phenom d'AMD étaient dans ce cas, par exemple. Chez Intel, le renommage à banc de registre physique est apparu sur le Pentium 4 et a été appliqué sur tous les registres. En général, la FPU est précédée par une station de réservation unique (ou par un ''scheduler'' sur certains CPU). Il y a souvent un port d'émission pour l'additionneur flottant et un autre pour le multiplieurs, sauf pour les tout premiers modèles d'Intel et AMD. Il y aussi souvent un port pour les instructions FSTORE, les écritures flottantes. Les ports en question servent à transmettre les données à écrire vers l'unité mémoire, ainsi que l'adresse mémoire associée. {|class="wikitable" |+ Station de réservation flottante |- ! Station de réservation 1 !! Station de réservation 2 !! Station de réservation 3 |- | FADD (additionneur flottant) || FMUL (multiplication flottante || FSTORE |} ===Un aparté sur les instructions SIMD des processeurs x86=== L'extension flottante x87 est resté la norme pendant une bonne décennie, sur les CPU 32 bits. Mais par la suite, les choses ont changées avec l'introduction des '''instructions SIMD'''. Je ne vais pas rentrer dans le détail, un chapitre ultérieur détaillera les instructions SIMD. Mais je dois cependant parler des bases de ces instructions, car elles ont remplacé les instructions flottantes progressivement. Mais avant toute chose, un petit historique,pour vous faire comprendre le vocabulaire utilisé dans ce qui suit. Les premières instructions SIMD ont été introduites en 1996, sur le Pentium MMX. Les instructions en question étaient regroupées dans une '''extension x86''' (un ajout au jeu d'instruction de base), appelé le MMX. Il ne contenait que des instructions SIMD pour des opérandes entiers. Mais par la suite, les extensions '''''Streaming SIMD Extensions''''' (SSE) ont ajouté des opérations flottantes. Les ''Streaming SIMD Extensions'', qu'on va abrévier SSE dans ce qui suit, ont été déclinées en plusieurs versions : SSE1, SSE2, SEE3, SSE4, et quelques intermédiaires. Puis, vint le '''AVX''' (''Advanced Vector eXtensions''). Les instructions SIMD regroupent plusieurs opérations identiques en une seule instruction, la seule contrainte étant que les opérandes soient différentes. Par exemple, une instruction d'addition SIMD regroupe quatre additions séparées, chacun travaillant sur des opérandes différentes. [[File:Instructions SIMD.png|centre|vignette|upright=3|Instructions SIMD]] J'ai donné l'exemple d'une addition SIMD qui regroupe quatre additions flottantes, travaillant chacune sur ses opérandes rien qu'à elle. Les opérandes en question ne sont pas lues depuis les registres généraux ou flottants. A la place, les instructions utilisent un banc de registre dédié, qui contient des registres assez larges. Les instructions SIMD utilisent donc des '''registres SIMD''', qui mémorisent des paquets d'opérandes. Par exemple, l'extension SSE a ajouté 16 registres XMM, de 128 bits chacun. un registre de 128 bits peut mémoriser : 2 entiers/flottants 64 bits, 4 entiers/flottants 32 bits, 8 entiers 16 bits, 16 entiers 8 bits. [[File:Vector register.png|centre|vignette|upright=2|Contenu d'un vecteur en fonction du type de données utilisé.]] L'AVX, quant à elle, donne accès à 16 registres de 256 bits chacun. Pour faire des économies de circuits, ils ont été fusionnés avec les registres XMM du SSE. Les 128 bits de poids faible de ces registres ne sont autre que les registres du SSE. [[File:AVX registers.svg|centre|vignette|upright=1.5|Registres AVX.]] Si je parle de ces instructions et registres SIMD, c'est parce qu'ils ont remplacé les instructions/registres flottants d'antan. Le x87 a disparu, les instructions SIMD font office d'instructions flottantes. Le remplacement a eu lieu avec le passage au 64 bits. Les raisons à cela sont multiples, mais la principale est que le x87 était très mal fait, avec une architecture obsolète. Une annexe en parle en détail, mais le x87 utilisait une pile de registre totalement inhabituelle, que les compilateurs ne pouvaient pas utiliser convenablement. Aussi, lors du passage au 64 bits, Intel et AMD en ont profité pour se débarrasser du x87 et le remplacer par quelque chose de plus moderne. Vu que les extensions SIMD faisaient déjà des calculs flottants, elles l'ont remplacé. Et même dans le processeur, dans sa microarchitecture, le remplacement a été total. Le processeur intègre une ou plusieurs unités de calcul spécialisées dans les instructions SIMD. Et elles remplacent la FPU, totalement. Typiquement, il y a au minimum : * une unité SIMD spécialisée dans les additions entières ; * une unité SIMD spécialisée dans les multiplications entières ; * une unité SIMD spécialisée dans les additions flottantes ; * une unité SIMD spécialisée dans les multiplications flottantes. * éventuellement une unité SIMD annexe pour les autres instructions SIMD, et elles sont nombreuses. Les unités SIMD étaient parfois mutualisées avec la FPU, c'est à dire que la FPU x87 était en réalité une sous-partie de l'unité SIMD. Après tout, l'unité SIMD contient plusieurs additionneurs flottants 32/64 bits, idem pour les multiplieurs flottants. Alors autant en profiter pour leur faire faire des calculs flottants normaux, ceux de la FPU x87. ==Les processeurs x86 d'Intel== Nous allons voir les processeurs Intel à part des processeurs AMD. La raison à cela est que les architectures Intel et AMD ont progressivement évolué, chacune se basant sur la précédente et l'améliorant. Il n'y a pas eu de cassure entre microarchitectures AMD, qui sont chacune la suite de la précédente. Il est donc préférable de voir les architectures AMD dans l'ordre chronologique. Par contre, Intel a eu une gigantesque cassure, avec le processeur Pentium 4. Son architecture se démarquait fortement du Pentium 3, mais elle n'a pas convaincu et a été abandonnée avec les processeurs suivants. Ce qui fait nous verrons l'architecture du Pentium 4 à part. Nous allons commencer avec les processeurs Intel. N'y voyez pas du favoritisme derrière ce choix, la justification est toute autre. Si je commence par Intel, c'est pour commencer avec les Pentium 1 et 2, qui sont superscalaires, mais sans exécution dans le désordre. L'absence d'exécution dans le désordre les rend bien plus simples à étudier que les autres, ce qui en fait un bon point de départ pour ce chapitre. Les autres processeurs x86 sont tous avec à exécution dans le désordre, à une exception qu'on verra dans le chapitre suivant. AMD n'a pas produit de processeurs ''in-order'', tous les processeurs produits par AMD intègrent l'exécution dans le désordre. Le Pentium 1 et 2 utilisaient la même architecture, qu'on détaillera dans ce qui suit. Les seules différences importantes étaient la fréquence, le cache, et quelques détails dans le genre. Le Pentium 3 était une nouvelle microarchitecture qui ajoutait l'exécution dans le désordre. Un an et demi plus tard, le Pentium 4 est sorti et a été un échec. Ses performances étaient peu convaincantes face au Pentium 3, et sa consommation énergétique était très importante. La conséquence est que le Pentium 4 et le Pentium 3 ont survécu pendant un long moment, beaucoup de monde préférait acheter un Pentium 3. Intel a alors amélioré les microarchitectures du Pentium 3 et du 4, indépendamment, pendant environ 7 ans. La microarchitecture du Pentium 3 a subit plusieurs micro-évolutions, chacune avec une finesse de gravure différente, afin de satisfaire les consomateurs. Les premeirs Pentium 3 avaient une finesse de gravure de 250 nm, elle a chuté à 65 sur les derniers modèles. L'architecture du Pentium 4 a fait la même chose, pour tenter de corriger ses problèmes de performance et de consommation d'énergie. Les premiers Pentium 4 avaient uen finesse de gravure de 180 nm, elle a elle aussi chutée à 65 sur les derniers modèles. Après l'échec du Pentium 4, les ingénieurs d'Intel ont repris l'architecture P6 et l'ont améliorée fortement, pour donner l'architecture Core. Les micro-processeurs suivants ont fait évoluer cette architecture progressivement, au point où elle ne ressemble plus à l'originale. L'architecture Core a laissé la place à l'architecture Nehalem, puis Sandy Bridge, puis Haswell, puis Skylake, puis Ice Lake, et Golden Cove. Il s'agit de la lignée principale, partant du Pentium 3 et continuant jusqu'à nos jours. Ces microarchitectures ont suivi un motif assez simple, appelé modèle '''tick-tock'''. Chaque microarchitecture était déclinée en deux versions, la seconde ayant une finesse de gravure réduite. En parallèle, Intel a travaillé sur des processeurs basse performance et basse consommation, avec une microarchitecture très différente. Les processeurs Atom de microarchitecture Bonnel, pour être ensuite remplacés par les microarchitectures Silvermont, puis Goldmont et Gracemont. Ces microarchitectures ont évolué en parallèle de la lignée principale, il s'agit d'une lignée secondaire. Le tout est résumé dans ce schéma ci-dessous. [[File:IntelProcessorRoadmap-4v.svg|centre|vignette|upright=2.5|Roadmap des processeurs Intel, qui servira de structure pour la suite du chapitre]] De nos jours, les processeurs Intel utilisent les deux types de micro-architectures en même temps. Les CPU Intel modernes disposent de deux types de coeurs : les coeurs P et le coeurs E. Leur nom signifie "Performance" et "Efficient", qui trahissent leur but. Les coeurs P utilisent la microarchitecture de la lignée principale, qui est conçue pour la performance. Les coeurs E, quant à eux, utilisent les micro-architectures basse consommation de la lignée secondaire. Ceci étant dit, commençons par le commencement, avec le Pentium 1. ===Le Pentium 1/MMX : la double émission entière avec deux pipelines=== Le processeur Pentium d'Intel avait un pipeline de 5 étages : un étage de chargement/prédiction de branchement, deux étages de décodage, un étage d'exécution et un dernier étage pour l'écriture dans les registres. Le Pentium 1 était un processeur double émission, intégrant deux pipelines nommés U et V. Chose importante, les deux pipelines n'étaient pas identiques. Le pipeline U pouvait exécuter toutes les instructions, mais le pipeline V était beaucoup plus limité. Par exemple, seul le pipeline U peut faire des calculs flottants, le pipeline V ne fait que des calculs entiers et des branchements. Les deux pipelines disposaient d'une unité de calcul entière, identique dans les deux pipelines. Mais le pipeline U incorporait un circuit multiplieur/diviseur et d'un ''barrel shifter''. L'unité flottante était sur le port d'émission du pipeline U, idem pour l'unité de calcul vectoriel MMX sur le Pentium MMX. Les deux pipelines avaient chacun une unité de calcul d'adresse, mais ils n'étaient pas identiques : celle du pipeline V ne gérait que l’instruction LEA, celle du pipeline U gérait tous les calculs d'adresse. {|class="wikitable" |- ! Pipeline U ! Pipeline V |- | ALU entière | ALU entière |- | Multiplieur/diviseur | |- | ''Barrel Shifter'' | |- | AGU complexe | AGU simple (opération LEA) |- | FPU | |- | Unité SIMD | |} Les deux pipelines géraient les opérations bit à bit, les additions, les soustractions et les comparaisons. Les autres instructions ne sont exécutables que dans le pipeline U. Pour être plus précis, les deux pipelines supportaient les instructions suivantes, ce qui fait qu'on pouvait en faire deux en même temps : * Les instructions arithmétiques INC, DEC, ADD, SUB ; * l'instruction de comparaison CMP ; * les instructions bit à bit AND, OR, XOR ; * l'instruction de calcul d'adresse LEA ; * l'instruction MOV (dépend du mode d'adressage) ; * les instructions de gestion de la pile PUSH et POP (dépend du mode d'adressage) ; * l'instruction NOP, qui ne fait rien. Il faut noter qu'il y a cependant quelques restrictions, beaucoup de paires d'instructions sont interdites. La plupart interdisent au pipeline V de faire quoique ce soit quand une opération particulière est émise dans le pipeline U. Par exemple, si le pipeline U exécute une multiplication ou une division, le processeur ne peut pas exécuter une opération dans le pipeline V. Et c'est pareil avec les branchements : si un branchement est émis dans le pipeline U, l'instruction suivant le branchement n'est pas émise dans le pipeline V, pour éliminer les dépendances de contrôle. De même, si le pipeline U exécute une opération flottante, le pipeline V ne pourra rien exécuter. La seule exception est l'instruction FCXH, qui échange deux registres flottants. [[File:Intel Pentium arch.svg|centre|vignette|upright=2.5|Microarchitecture de l'Intel Pentium MMX. On voit que certaines unités de calcul sont dupliquées.]] Un choix assez intéressant a été fait pour le cache de données. Nous avions vu dans le chapitre sur les CPU superscalaires que la superscalarité a un impact sur l'unité mémoire. Il y a alors deux implémentations. La première ne fait rien, l'unité mémoire ne change pas, et le processeur ne peut pas faire deux accès mémoire simultanés. La seconde duplique l'unité mémoire et les ports de lecture/écriture du cache, ce qui autorise des accès mémoire simultanés. Le Pentium 1 utilise une solution intermédiaire. Les ingénieurs d'Intel étaient partis à la base sur un cache totalement double port, pour obtenir des performances maximales. Mais diverses simulations et observations les ont fait changer d'avis. Les simulations ont montré qu'il est "rare" que les deux pipelines aient besoin de lire/écrire dans le cache en même temps. Et ils ont optimisé le cache de donnée pour en tenir compte. Le cache de données est partiellement multiport : simple port sur certains aspects, double port sur d'autres. Le cache est un cache splité, à savoir que les données et les ''tags'' sont séparés dans des mémoires séparées. La mémoire pour les ''tags'' est multiport, ce qui permet d'interroger les ''tags'' du cache deux fois par cycle. Un port est relié au pipeline u, un autre au pipeline V. Mais pour les données, le cache n'a qu'un seul port pour lire/écrire des données. Impossible donc de lire deux données en même temps, pour alimenter les deux pipelines. Il utilise cependant 8 banques permet d'accélérer des accès mémoire proches dans le temps, mais dans des cycles d'horloge différents. Entre les deux mémoires, il y a un circuit qui détecte les conflits, à savoir les situations où les deux pipelines accèdent en même temps au cache. S'ils veulent lire/écrire une donnée dans le même cycle, ce qui est impossible avec un seul port, le pipeline U a la priorité et le pipeline V attend le cycle suivant. Le circuit détecte aussi les conflits de banque, à savoir quand un pipeline accède à une banque en cours d'accès par l'autre pipeline (on rappelle qu'un accès au cache prend plusieurs cycles). Le circuit détecte aussi certaines dépendances mémoires, à savoir des accès consécutifs à la même adresse. : La TLB du processeur est aussi totalement double port. ===La microarchitecture P6 (Pentium 3) : l'exécution dans le désordre=== Le Pentium 3 utilisait la '''microarchitecture P6''', qui a été dérivée dans de nombreuses variantes, dont les finesses de gravure n'étaient pas les mêmes. Il introduit une exécution dans le désordre simple, avec un ''scheduler'' centralisé, avec renommage dans le désordre dans le ROB (tampon de ré-ordonnancement), commandé par une table d'alias. C'était un processeur triple émission, soit une instruction de plus que la double émission du Pentium 1. [[File:P6 func diag.png|centre|vignette|upright=2|P6 func diag]] Le pipeline passe de 5 étage sur le Pentium à 14 - 12 étages, dont le détail est le suivant : * Prédiction de branchement, deux cycles ; * Chargement des instructions, trois cycles ; * Décodage de l'instruction, deux cycles ; * Renommage de registre, un cycle ; * Copie des opérandes dans le tampon de ré-ordonnancement (lié au renommage de registre dans le ROB) ; * Dispath dans ou depuis la station de réservation. * Exécution de l'instruction ; * Écriture du résultat dans le ROB ; * Écriture dans le banc de registre physique. Les instructions sont chargées par blocs de 16 octets, avec un système de fusion de blocs pour gérer les instructions à cheval sur deux blocs. Lors d'un branchement, deux blocs doivent être chargés si l'instruction de destination n'est pas alignée sur 16 octets et cela cause un délai de un cycle d'horloge. Le décodage des instructions x86 était géré par plusieurs décodeurs. Il y avait trois décodeurs : deux décodeurs simples, et un décodeur complexe. Les décodeurs simples décodaient les instructions les plus fréquentes, mais aussi les plus simples, qui étaient décodées en une seule micro-opération. Les instructions CISC complexes étaient gérées uniquement par le décodeur complexe, basé sur un microcode, qui pouvait fournir jusqu'à 4 micro-opérations par cycle. Le tout est résumé avec la règle 4-1-1. La toute première instruction chargée depuis la file d'instruction va dans le premier décodeur simple. Si jamais le décodeur ne peut pas décoder l'instruction, l'instruction est redirigée dans un autre décodeur, avec un délai d'un cycle d'horloge. Les stations de réservations étaient regroupées dans une structure centralisé, en sortie de l'unité de renommage. Elles avaient 4 ports d'émission. En réalité, 5 dont deux pour les écritures (un pour l'adresse à transmettre, un pour la donnée). Le tout avait une répartition moitié-moitié pour les calculs et les accès mémoire. Chaque port d'émission pour les calculs était relié à une ALU et une FPU/unité SIMD. Le tableau suivant résume tout. Vous remarquerez la présence de plusieurs additionneurs flottants. Le premier exécute les opérations x87, l'autre les opérations SIMD. Les opérations SIMD se font sur des registres de 128 bits, mais elles sont en réalité cassées en deux µops, chacune travaillant sur 64 bits. {|class="wikitable" |+ Pentium 3 |- ! !! Port d'émission 1 !! Port d'émission 2 !! Port d'émission 3 !! Port d'émission 4 !! Port d'émission 5 |- ! rowspan="3" | µops entières | ALU entière || ALU entière || LOAD || STORE adresse || STORE donnée |- | LEA || ALU SIMD MMX || || || |- | Multiplieur entier || || || || |- ! rowspan="3" | µops flottantes | x87 FADD || FADD 64 bits (SIMD) || || |- | FMUL (x87 et 64 bits) || || || |- | FDIV || || || |} Les premiers Pentium 3 n'avaient pas de cache L2 dans le processeur, celui-ci était sur la carte mère. Mais il a été intégré dans le processeur sur la seconde version du Pentium 3, la version Coppermine. Le Pentium 3 a servi de base aux microarchitectures d'Intel qui ont suivi. Les changements à chaque nouvelle génération sont assez mineurs : la prédiction de branchement est améliorée, la taille des stations de réservation et du ROB augmente, idem avec les autres structures liées à l'exécution dans le désordre. Les processeurs Intel ont conservé un ''scheduler'' centralisé, alors qu'AMD utilise une autre méthode, comme nous allons le voir dans ce qui suit. Les seuls changements notables sont est le passage à un renommage dans le ROB à un renommage à banc de registre physique, ainsi que l'introduction du cache de micro-opération. Et ce sont des modifications qu'AMD a aussi faites, celle-ci étant clairement une bonne idée pour toutes les micro-architectures avec un budget en transistor suffisant. Il est intéressant de garder cela en tête, car une bonne partie des améliorations de chaque micro-architecture proviendra de là. ===La microarchitecture Core : désambiguïsation mémoire, macro-fusion, ''stack engine'', ''Fetch Input Queue''=== La '''microarchitecture Core''' fait suite au Pentium 4, mais reprend en fait beaucoup d’éléments du Pentium 2 et 3. Elle utilise la station de réservation unique avec renommage dans le ROB, provenant du Pentium 2/3. A part ça, les améliorations sont assez diverses : un cache L2, l'arrivé de la désambiguïsation mémoire, une ''Fetch Input Queue'' et un ''stack engine'' primitif. Le processeur introduit aussi la macro-fusion qui fusionne une instruction de test et le branchement qui suit en une seule micro-opération. beaucoup d'optimisations importantes, donc. [[Image:Intel Core2 arch.svg|centre|vignette|upright=2|Intel Core microarchitecture]] Il y a quelques modifications au niveau de l'unité de chargement. La file d'instruction a toujours ce système de fusion de blocs, sauf que les branchements ne causent plus de délai d'un cycle lors du chargement. La file d'instruction est suivie par un circuit de prédécodage qui détermine la taille des instructions et leurs frontières, avant de mémoriser le tout dans une file de 40 instructions. La station de réservation dispose de 5 ports d'émission, dont un pour les lectures et un pour les écritures. Les deux sont reliées à une ''Load/Store Queue'', appelée ''Memory Ordering Buffer'', elle-même reliée au cache de données par un port de lecture et un port d'écriture. Les ports de lecture/écriture du cache font 128 bits, pour gérer naturellement les instructions LOAD/STORE dans les registres SIMD. Les trois ports restants sont chacun reliés à des ALU entières et des unités flottantes/SIMD (pour l'extension SSE). Le multiplieur entier est relié au second port d'émission. L'additionneur flottant SIMD/SSE est connecté au port 1, le multiplieur/diviseur flottant SIMD/SSE est connecté au port 0, une unité SIMD annexe est connectée sur chaque port. {|class="wikitable" |+ Microarchitecture Core (Penryn et Merom) |- ! !! Port d'émission 1 !! Port d'émission 2 !! Port d'émission 3 !! Port d'émission 4 !! Port d'émission 5 |- ! rowspan="3 | µops entières/mémoire | ALU entière || ALU entière || ALU entière || LOAD || STORE |- | ''Barrel shifter'' || Multiplieur entier || ''Barrel shifter'' || || |- |- | || || ALU branchements || || |- ! rowspan="3 | µops flottantes et SIMD | FMUL et FDIV || FADD || || |- | ALU SIMD entière (128 bits) || ALU SIMD entière (128 bits) || ALU SIMD entière (128 bits) || || |- | || MUL SIMD entière (128 bits) || || || |} Le résultat que le processeur peut émettre un mix d'opérations flottantes et entière assez varié, avec un mix allant de trois opérations entières à trois opérations flottantes, avec tous les intermédiaires. Le fait de mettre les ALU SIMD sur des ports différents permet d'émettre une addition et une multiplication flottante/SIMD simultanément. ===La microarchitecture Nehalem : un vrai ''Loop Stream Detector''=== Les microarchitectures '''Nehalem''' et '''Westmere''' n'introduisent pas d'optimisation majeure. A la rigueur, ils introduisent une prédiction de branchement à deux niveaux, et une macro-fusion plus complète. Les unités de calcul sont assez semblables, de même que leur répartition sur les ports d'émission. Elle a introduit cependant un vrai ''Loop Stream Detector'' (LSD). Pour rappel, le LSD qui permet d'exécuter les boucles directement depuis la file de µops. Le LSD reconnait les petites boucles, qui tiennent dans la file de µops, et lit les µops adéquates depuis celle-ci. Les instructions de la boucle n'ont donc pas à être chargée et décodées. La microarchitecture Core avait une sorte de pseudo-''Loop Stream Detector'', mais il était localisé dans la file d'instruction. Il était donc moins performant. Ce pseudo-''Loop Stream Detector'' permettait de ne pas charger les instruction x86, mais elles devaient quand même être décodées et passer par la file de µops. Avec Nehalem, ce n'est plus le cas. [[File:Intel Nehalem arch.svg|centre|vignette|upright=2.5|Intel Nehalem.]] ===La microarchitecture Sandy Bridge : le cache de µops=== Les microarchitectures '''Sandy Bridge''' and '''Ivy Bridge''' ont introduit le renommage à banc de registre physique et l'ajout d'un cache de micro-opérations. L'ajout du cache de micro-opérations est une optimisation particulièrement rentable, particulièrement pour le complexe jeu d’instruction x86. Avec ce cache, les décodeurs servent surtout à alimenter le cache de micro-opérations, parfois décoder des instructions en-dehors de boucles, pas plus. Intel a d'ailleurs reflété ce fait dans sa terminologie. Intel distingue deux voies de chargement : le ''legacy pipeline'' et le cache de micro-opérations. L'unité de chargement et les décodeurs sont regroupés dans la voie du ''legacy pipeline''. Sur les processeurs modernes, les décodeurs ne servent que pour 10 à 20% des micro-opérations exécutées, le reste est lu depuis le cache de µops. Cependant, Sandy Bridge a un cache de µops assez limité, qui ne permet pas d’atteindre ces chiffres. De nombreuses instructions ne peuvent pas être mémorisées dans le cache de µops, les limitations quand à son utilisation sont assez importantes. Par exemple, le processeur ne consulte pas le cache de µops à chaque cycle, il ne démarre son utilisation qu'après un branchement (donc une boucle potentielle) et cesse de l'utiliser au premier défaut de cache (dans le cache de µops). Le cache de micro-opérations est complété avec un ''Loop Stream Detector'', placé après le cache en question. Les décodeurs et le cache de micro-opérations alimentent une file de micro-opérations, située juste avant l'étage de renommage de registres. La file de micro-opérations sert en quelque sorte de tampon entre l'étage de "décodage" et celui de renommage. Le ''Loop Stream Detector'' utilise cette file de micro-opérations comme d'un cache lorsqu'une boucle est détectée. Les micro-opérations de la boucle sont lue depuis la file de micro-opérations, pour être envoyée au renommeur de registres. L'avantage est que le cache de micro-opérations et/ou les décodeurs sont mis en pause et clock-gatés lorsqu'une boucle s'exécute, ce qui réduit la consommation du processeur. Le ''Loop Stream Detector'' et le cache de micro-opération ont globalement le même effet : désactiver tout ce qui est avant, le ''Loop Stream Detector'' appliquant cette méthode au cache de micro-opération lui-même. Pour le reste, ''Sandy Bridge'' n'innove pas trop. Les unités d'exécution sont globalement les mêmes, leur répartition sur les port est peu changée. LA seule différence intéressante est que ''Sandy Bridge'' n'a plus une unité mémoire dédiée aux LOAD et une aux STORE. Elle en a deux qui peuvent faire indifféremment LOAD et STORE. Le processeur peut donc émettre deux LOAD simultanément, ce qui entraine un gain en performance appréciable. ===Les microarchitectures Haswell et Broadwell=== Les architectures '''Haswell''' et '''Broadwell''' ont ajouté quelques unités de calcul, élargit la sortie du cache de micro-opérations. Un port d'émission pour opération entières a été ajouté, de même qu'un port pour les accès mémoire. Le processeur passe donc à 8 ports d'émission, ce qui permet d'émettre jusqu'à 8 micro-opérations, à condition que le cache de micro-opération suive. Pour le reste, le processeur est similaire aux architectures précédentes, si ce n'est que certaines structures grossissent. {|class="wikitable" |+ Microarchitecture Haswell et Broadwell |- ! !! Port d'émission 1 !! Port d'émission 2 !! Port d'émission 3 !! Port d'émission 4 !! Port d'émission 5 !! Port d'émission 6 |- ! rowspan="3" | µops entières/mémoire | ALU entière || ALU entière || ALU entière || ALU entière || LOAD/STORE || LOAD/STORE |- | ''Barrel shifter'' || Manipulation de bits || ''Barrel shifter'' || Manipulation de bits || || |- | || Multiplieur entier || ALU branchements || || || |- ! rowspan="4" | µops flottantes et SIMD | SIMD bit à bit (256 bits) || SIMD bit à bit (256 bits) || SIMD bit à bit (256 bits) || || || |- | || ALU SIMD entière (256 bits) || ALU SIMD entière (256 bits) || || || |- | FMUL + FMA (256 bits) || FMUL + FMA (256 bits) || || || || |- | FDIV || FADD || || || || |} ===La microarchitecture Skylake : la fin de la station de réservation centralisé=== L'architecture '''Skylake''' a eu une longévité hors du commun, avec près de 6 ans d’utilisation ininterrompue. Elle a été la concurrentes des microarchitectures Zen 1, Zen 2 et Zen 3 d'AMD. La microarchitecture ''Skylake'' est une microarchitecture capable de décoder/renommer 4 instructions par cycle, elle peut émettre 6 µops par cycle grâce au cache de µops. Elle a été déclinée en plusieurs microarchitectures légèrement différentes les unes des autres, nommés '''''Kaby Lake''''', '''''Coffee Lake''''', '''''Comet Lake'''''. Un changement extrêmement important concerne la station de réservation centralisé, qui ne l'est plus sur Skylake. Elle est scindée en deux stations de réservations : une pour les µops mémoire, et une autre pour le reste. Mien de rien, c'est à ce moment que la tendance "Intel = station de réservation centralisé " a commencée à s'adoucir. Intel est longtemps resté sur cette organisation avec un '''''Math Scheduler''''' d'un côté, et un '''''MEM scheduler''''' de l'autre. Pour le reste, les améliorations sont mineures. A la rigueur, l'unité de renommage de registre ajoute des optimisations comme l'élimination des MOV, les idiomes liés aux opérations avec zéro, etc. ===La microarchitecture ''Sunny Cove'' : la station de réservation mémoire est scindée=== Après Skylake, les microarchitecture d'Intel ont changé de dénomination. Elles sont maintenant nommées non pas avec des noms de lacs, mais ont un nom qui finit par Cove : ''Sunny Cove'', ''Golden Cove'', etc. La seule exception à cette règle est la microarchitecture '''''Palm Cove''''' était un ''die shrink'' de Skylake, ce qui fait qu'elle est à part de celles qui vont suivre, qui sont vraiment des microarchitectures différentes. La microarchitecture qui suit immédiatement skylake était la microarchitecture '''''Sunny Cove'''''. La microarchitecture''Sunny Cove'' suit la tendance entamée avec Skylake de casser la station de réservation principale en plusieurs stations de réservations plus petites. Cette fois-ci c'est la station de réservation pour les µops mémoire qui est scindée en deux une pour les lectures et une pour les écritures. La microarchitecture ''Sunny Cove'' passe de quadruple émission à la pentuple émission. Précisément, l'unité de renommage de registres est maintenant capable de renommer 5 µops par cycle. De plus, l'unité de renommage devient plus performante. Ses capacités de ''MOV elimination'' ont été améliorées, et elle devient capable de reconnaitre certains idiomes, comme celui qui met à zéro un registre en le XORant avec lui-même. ''Sunny Cove'' était au départ prévue pour les PC ''desktop'', mais sa production a eu de nombreux problèmes. Elle était censée être produite avec une technologie de gravure 10nm d'Intel lui-même, qui a cependant eu de nombreux problèmes de production. Au final, ''Sunny Cove'' et ses variantes n'ont existées que dans des CPU mobile, basse performance et basse consommation. Elle a été déclinée en deux versions : '''''Willow Cove''''' a un cache retravaillé, alors que '''''Cypress Cove''''' est l'équivalent de ''Sunny Cove'' mais repassé à une technologie de gravure de 14nm. Les deux microarchitecture ont été utilisées sur les plateformes dites '''''Ice Lake''''' et '''''Tiger Lake'''''. ===La microarchitecture ''Golden Cove'' : un ''Fetch'' doublé=== La microarchitecture '''Golden Cove''' a suivi ''Sunny Cove''. Les microarchitectures suivantes, ''Redwood Cove'' et ''Raptor Cove'', sont des modifications mineures de ''Golden Cove''. ''Golden Cove'' altère les décodeurs et l'unité de chargement. Sur toutes les générations précédentes, on reste sur une unité de chargement qui charge 16 octets à la fois. Une telle stagnation sur les unités de chargement et de décodage s'explique encore une fois par la présence du cache de micro-opération fait que ce n'est pas trop un problème. Tout ce qui précède le cache de micro-opérations n'a pas de raison d'évoluer, car ce cache est très puissant. Mais cela change avec ''Golden Cove''. Golden Cove double la taille du chargement qui passe à 32 octets. Le processeur peut décoder 6 instructions par cycle, et en émettre 6 à destination des ''schedulers''s. Il s'agit donc de processeurs superscalaires très larges, ce qui est la norme de nos jours et le restera pendant longtemps. ''Golden Cove'' conserve les trois ''schedulers'' séparées de ''Sunny Cove'', savoir : pour les instructions entières/flottantes, pour les lectures, pour les écritures. [[File:Golden Cove.png|centre|vignette|upright=3|Golden Cove]] Niveau unités de calcul, peu de changements avec ''Sunny Cove'', si ce n'est une ALU entière en plus. {|class="wikitable" |- ! Port d'émission n°1 !! Port d'émission n°2 !! Port d'émission n°3 !! Port d'émission n°4 !! Port d'émission n°5 |- | ALU entière || ALU entière || ALU entière || ALU entière || ALU entière |- | ''Barrel shifter'' || Multiplieur || Multiplieur || ''Barrel shifter'' || |- | Branchements || Diviseur || || Branchements || |} ===La microarchitecture ''Lion Cove'' : la scission du ''math scheduler''=== La microarchitecture '''''Lion Cove''''' poursuit la tendance à scinder la station de réservation. La station de réservation pour les opérations entières/flottantes est maintenant scindée en deux : une pour les µops entières, une autre pour les µops SIMD/flottantes. Une autre modification, très liée à la précédente, est que le renommage de registre est lui aussi scindé. Les registres SIMD/flottants sont maintenant renommé indépendamment des registres généraux/entiers. Les raisons sont certainement que cela simplifie grandement la conception du processeur, en séparant les pipelines entiers et SIMD, surtout que les opérations entières et SIMD sont forts différentes : instructions 2-opérandes d'un côté, 2 à 3-opérandes pour le SIMD ; présence de techniques de ''masking'' pour le SIMD, mais pas pour les opérations entières, etc. Pour le reste, le processeur de 6 à 8 voies d'émission, et l'unité de chargement peut maintenant charger 48 octets, au lieu de 32 auparavant. Des ALU entières et SIMD ont été rajoutés. L'unité d'émission pour les opérations entières dispose de 6 ports d'émission, alors que celle pour les opérations SIMD n'en a que 4. {|class="wikitable" |+ Microarchitecture Haswell et Broadwell |- ! !! Port d'émission 1 !! Port d'émission 2 !! Port d'émission 3 !! Port d'émission 4 !! Port d'émission 5 !! Port d'émission 6 |- ! rowspan="3" | µops entières/mémoire | ALU entière || ALU entière || ALU entière || ALU entière || ALU entière || ALU entière |- | Branchements || ''Barrel shifter'' || Branchements || ''Barrel shifter'' || Branchements || ''Barrel shifter'' |- | || Multiplieur entier || || Multiplieur entier || || Multiplieur entier |} ==Les processeurs x86 d'AMD== Les architectures Intel ont évolué progressivement, sans grandes cassure. Il y a une continuité presque ininterrompue entre l'architecture du Pentium 2 et les architectures modernes. Intel a fait des améliorations mineures à chaque nouvelle micro-architecture, si on omet le passage à un renommage à banc de registre physique et l'ajout du cache de micro-opération. A l'opposé, les architectures AMD ont eu de nombreuses cassures dans la continuité où AMD a revu sa copie de fond en comble. Étudier ces architectures demande de voir trois choses séparément : le ''front-end'' qui regroupe l'unité de chargement et les décodeurs, le ''back-end'' qui gère l'exécution dans le désordre et les unités de calcul, et le sous-système mémoire avec les caches et la ''Load Store Queue''. Leur étude sera plus ou moins séparée dans ce qui suit, pour chaque classe d'architecture. ===La première génération de CPU AMD : les architectures K5, K6, K7, K8 et K10=== La première génération de processeurs AMD est celle des architectures K5, K6, K7, K8 et K10. Il n'y a pas de K9, qui a été abandonné en cours de développement. Les processeurs K5 et K6 portent ce nom au niveau commercial. Par contre, les processeurs d'architecture K7 sont aussi connus sous le nom d''''AMD Athlon''', les AMD K8 sont connus sous le nom d''''AMD Athlon 64''', et les architecture K10 sont appelées les '''AMD Phenom'''. Comme le nom l'indique, l'architecture K8 a introduit le 64 bits chez les processeurs AMD. Elles ont une architecture assez similaire pour ce qui est du chargement et des caches. Toutes disposent d'au minimum un cache L1 d'instruction et d'un cache L1 de données. Le K5 n'avait que ces caches, mais un cache L2 a été ajouté avec le K7, puis un L3 avec le K10. L'AMD K5 avait une TLB unique, mais les processeurs suivants avaient une TLB pour le L1 d'instruction et une autre pour le L1 de données. Idem pour le cache L2, avec deux TLB : une pour les données, une pour les instructions. Les caches L1/L2 sont de type exclusifs, à savoir que les données dans le L1 ne sont pas recopiées dans le L2. Le cache L2 est précisément un cache de victime, qui mémorise les données/instructions, évincées des caches L1 lors du remplacement des lignes de cache. L'introduction du cache L2 a entrainé l'ajout de deux TLB de second niveau : une L2 TLB pour les données et une autre pour les instructions. Les architectures K8 et K10 ont ajouté un cache L3, avec un accès indirect à travers l'interface avec le bus. : L'AMD K7 originel, aussi appelée Athlon classique, n'avait pas de cache L2, mais celui-ci était placé sur la carte mère et fonctionnait à une fréquence moitié moindre de celle du CPU. L'Athlon Thunderbird, puis l'Athlon XP, ont intégré le cache L2 dans le processeur. {|class="wikitable" |- ! Architecture AMD ! colspan="5" | Caches |- | rowspan="2" | K5 | L1 instruction || L1 données || colspan="3" | |- | colspan="2" | TLB unique || colspan="3" | |- | colspan="4" | |- | rowspan="2" | K6 | L1 instruction || L1 données || colspan="3" | L2 unifié |- | TLB L1 instruction || TLB L1 données || colspan="3" | |- | colspan="6" | |- | rowspan="2" | K7, K8 | L1 instruction || L1 données || colspan="2" | L2 unifié || |- | TLB L1 instruction || TLB L1 données || TLB L2 instruction || TLB L2 données || |- | colspan="6" | |- | rowspan="2" | K10 | L1 instruction || L1 données || colspan="2" | L2 unifié || L3 |- | TLB L1 instruction || TLB L1 données || TLB L2 instruction || TLB L2 données || |} Fait important, les architectures K5 à K10 utilisent la technique du '''prédécodage''', où les instructions sont partiellement décodées avant d'entrer dans le cache d'instruction. Le prédécodage facilite grandement le travail des décodeurs d'instruction proprement dit. Par contre, le prédécodage prend de la place dans le cache L1 d'instruction, une partie de sa capacité est utilisé pour mémoriser les informations prédécodées. C'est donc un compromis entre taille du cache et taille/rapidité des décodeurs d'instruction. Sur les architectures K5 et K6, le prédécodage précise, pour chaque octet, si c'est le début ou la fin d'une instruction, si c'est un octet d'opcode, en combien de micro-opérations sera décodée l'instruction, etc. A partir de l'AMD K7, le prédécodage reconnait les branchements inconditionnels. Lorsqu'un branchement inconditionnel est pré-décodé, le pré-décodage tient compte du branchement et continue le pré-décodage des instructions à partir de la destination du branchement. Le système de prédécodage est abandonnée à partir de l'architecture Bulldozer, qui suit l'architecture K10. La prédiction de branchement de ces CPU tire partie de ce système de pré-décodage, à savoir que les prédictions de branchement sont partiellement mémorisées dans les lignes de cache du L1 d'instruction. Par exemple, l'AMD K5 se passe de ''Branch Target Buffer'' grâce à cela. Si une ligne de cache contient un branchement, elle mémorise l'adresse de destination de ce branchement, en plus des bits de pré-décodage. Si il y a plusieurs branchements dans une ligne de cache, c'est l'adresse de destination du premier branchement pris dans cette ligne de cache qui est mémorisée. Un défaut de cette approche est que si le branchement n'est pas dans le L1 d'instruction, aucune prédiction de branchement ne peut être faite et le préchargement ne peut pas fonctionner. C'est une limitation que n'ont pas les BTB découplées du cache L1 : elles peuvent prédire un branchement qui a été évincé dans le L2 ou le L3, tant que l'entrée associée est dans le BTB. Les prédictions peuvent même servir à précharger les instructions utiles. [[File:Comparaison du chargement de l'AMD K5 et K6.png|centre|vignette|upright=2|Comparaison du chargement de l'AMD K5 et K6]] Au niveau du décodage, on trouve de nombreuses différences entre les premières architectures AMD. L'AMD K5 contient 4 décodeurs hybrides, afin de décoder 4 instructions par cycles. Le K5 a quatre décodeurs simples couplés à 4 décodeurs complexes avec chacun un accès au micro-code. Une instruction peut donc passer par a donc deux voies de décodage : un décodage rapide et simple pour les instructions simples, un décodage lent et passant par le microcode pour les instructions complexes. Pour décoder 4 instructions, les deux voies sont dupliquées en 4 exemplaires, ce qui a un cout en circuits non-négligeable. L'AMD K6 utilise moins de décodeurs et ne peut que décoder deux instructions à la fois maximum. Par contre, il fournit en sortie 4 micro-opérations. Il intègre pour cela deux décodeurs simples, un décodeur complexe et un décodeur micro-codé. Un décodeur simple transforme une instruction simple en une ou deux micro-opérations. Il est possible d'utiliser les deux décodeurs simples en même temps, afin de fournir 4 micro-opérations en sortie du décodeur. Les deux autres décodent une instruction complexe en 1 à 4 micro-opérations. Si jamais la ou les deux instructions sont décodées en 1, 2 ou 3 micro-opérations, les micro-opérations manquantes pour atteindre 4 sont remplies par des NOPs. Pour le K7 et au-delà, le processeur dispose de décodeurs séparées pour les instructions micro-codées de celles qui ne le sont pas. Le processeur peut décoder jusqu’à 3 instructions par cycle. Le décodage d'une instruction microcodée ne peut pas se faire en parallèle du décodage non-microcodé. C'est soit le décodeur microcodé qui est utilisé, soit les décodeurs câblés, pas les deux en même temps. Le décodage d'une instruction prend 4 cycles. Les instructions non-microcodées sont décodées en une seule micro-opération, à un détail près : le CPU optimise la prise en charge des instructions ''load-up''. La différence entre le K6 et le K7 s'explique par des optimisations des instructions ''load-up''. Sur le K6, les instructions ''load-up'' sont décodées en deux micro-opération : la lecture en RAM, l'opération proprement dite. Mais sur le K7, une instruction ''load-up'' est décodée en une seule micro-opération. En conséquence, les décodeurs simples sont fortement simplifiés et le décodeur complexe disparait au profit d'un microcode unique. [[File:Décodage sur le K5 et le K5.png|centre|vignette|upright=3|Décodage sur le K5 et le K5]] ====Les micro-architectures K5 et K6 d'AMD==== Les deux premières architectures étaient les architectures K5 et K6, l'architecture K6 ayant été déclinée en quatre versions, nommées K6-1, K6-2, et K-3, avec une version K6-3 bis. Elles sont regroupées ensemble car elles ont beaucoup de points communs. Par exemple, tout ce qui a trait au chargement et au cache était similaire, de même que les unités de calcul. Les deux architectures avaient n'avaient pas de cache L2 et devaient se contenter d'un cache L1 d'instruction et d'un cache L1 de données. L'AMD K5 incorpore une TLB unique, alors que le K6 utilise des TLB séparées pour le cache d'instruction et le cache de données. Une différence entre l'architecture K5 et K6 est que la première utilise des caches normaux, alors que la seconde utilise des ''sector caches''. Les deux architectures disposaient des unités de calcul suivantes : deux ALU entières, une FPU, deux unités LOAD/STORE pour les accès mémoire, une unité de branchement et une ou plusieurs unités SIMD. Une organisation classique, donc. Pour les unités entières, il y avait deux ALU simples, un ''barrel shifter'' et un diviseur. Il n'y a pas d'erreur, le processeur incorpore un circuit diviseur, mais pas de circuit multiplieur. La raison est que la multiplication est réalisée par la FPU ! En effet, le multiplieur flottant de la FPU intègre un multiplieur entier pour multiplier les mantisses, qui est utilisé pour les multiplications entières. La même technique a été utilisée sur l'Atom, comme vu plus haut. Le tout était alimenté par deux ports d'émission, appelés ports X et Y. Sur l'architecture K5, le ''barrel shifter'' et le diviseur sont des ports différents. {|class="wikitable" |+ AMD K5 |- ! Port X ! Port Y |- | ALU simple | ALU simple |- | ''Barrel Shifter'' | Diviseur |} Sur l'architecture K6, le ''barrel shifter'' et le diviseur sont sur le même port. {|class="wikitable" |+ AMD K6 |- ! Port X ! Port Y |- | ALU simple | ALU simple |- | | ''Barrel Shifter'' |- | | Diviseur |} Niveau unités mémoire, le K5 avait deux unités LOAD/STORE, chacune capable de faire lecture et écriture. Par contre, la ''store queue'' n'a qu'un seul port d'entrée, ce qui fait que le processeur peut seulement accepter une écriture par cycle. Le processeur peut donc émettre soit deux lectures simultanées, soit une lecture accompagnée d'une écriture. Impossible d'émettre deux écritures simultanées, ce qui est de toute façon très rare. L'architecture K6 utilise quant à elle une unité LOAD pour les lectures et une unité STORE pour les écritures. Ce qui permet de faire une lecture et une écriture par cycle, pas autre chose. Niveau unités SIMD, l'architecture K7 n'avait qu'une seule unité SIMD, placée sur le port d'émission X. L'architecture K8 ajouta une seconde unité SIMD, sur l'autre port d'émission entier. De plus, trois ALU SIMD ont été ajoutées : un décaleur MMX, une unité 3DNow!, une unité mixte MMX/3DNow. Elles sont reliées aux deux ports d'émission entier X et Y ! Elles ne sont pas représentées ci-dessous, par souci de simplicité. [[File:Unité de calcul des processeurs AMD K5 et K6.png|centre|vignette|upright=2|Unité de calcul des processeurs AMD K5 et K6. les unités sur la même colonnes sont reliées au même port d'émission.]] Si les unités de calcul et le chargement sont globalement les mêmes, les deux architectures se différencient sur l'exécution dans le désordre. L'AMD K5 utilise du renommage de registre dans le ROB avec des stations de réservation. Par contre, l'AMD K6 utilise un ''scheduler'' centralisé. De plus, son renommage de registre se fait avec un banc de registre physique. L'architecture AMD K5 utilisait de deux stations de réservation par unité de calcul, sauf pour les deux unités mémoire partageaient une station de réservation unique (deux fois plus grande). Les stations de réservation sont cependant mal nommées, vu que ce sont en réalité des mémoire FIFO. Une micro-opération n'est émise que si elle est la plus ancienne dans la FIFO/station de réservation. Le renommage de registres se faisait dans le tampon de ré-ordonnancement, il n'y avait pas encore de banc de registre physique. Le tampon de ré-ordonnancement faisait seulement 16 instructions. [[File:AMD K5.jpg|centre|vignette|upright=3|AMDK5 Diagramme.]] L'architecture K6 remplace les stations de réservations par un ''scheduler'' centralisé. Les 4 micro-opérations renommées sont écrites dans le ''scheduler'' par groupe de 4, NOP de ''padding'' inclus. le ''scheduler'' centralisé contient 24 micro-opérations, groupées en 6 groupes de 4 micro-opérations, avec potentiellement des NOP dedans suivant le résultat du décodage. L'avantage est que l'implémentation de le ''scheduler'' est simple. le ''scheduler'' centralisé permettait d'émettre 6 micro-opérations en même temps (une par unité de calcul/mémoire). Le renommage de registres se faisait dans le tampon de ré-ordonnancement, il n'y avait pas encore de banc de registre physique. Le processeur utilisait un renommage avec un banc de registre physique. Le banc de registre physique pour les entiers contenait 48 registres, dont 24 étaient des registres architecturaux et 24 étaient des registres renommés. Sur les 24 registres architecturaux, 16 avaient une fonction de ''scratchpad'' que les ''datasheets'' d'AMD ne détaillent pas, les 8 restants étaient les registres généraux EAX, EBX, etc. [[File:AMD K6 Little foot & Modl 6.png|centre|vignette|upright=3|AMD K6 original.]] ====Les micro-architectures K7, K8 et K10 d'AMD==== Les micro-architectures suivantes sont les architectures K7, K8 et K10. Les architectures K7, K8 et K10 sont assez similaires. La différence principale entre le K7 et le K8 est le support du 64 bits. Les apports du K10 sont la présence d'un cache L3, d'une unité de calcul supplémentaire et d'améliorations de la prédiction de branchement. La taille de certains caches a été augmentée, de même que la largeur de certaines interconnexions/bus. L'architecture K7 des processeurs Athlon utilisait le renommage de registre, mais seulement pour les registres flottants, pas pour les registres entiers. Le ranommeg des registres flottants étaient réalisé via un banc de registres physique, ne contenant que des registres flottants. Les architectures K8 et K10 utilisent le renommage de registres pour tous les registres, entiers comme flottants. Par contre, le renommage de registre n'est pas réalisé de la même manière pour les registres entiers et flottants. Les registres entiers sont renommés dans le tampon de ré-ordonnancement, comme c'était le cas sur les architectures Intel avant le Pentium 4. Par contre, les registres flottants sont renommés grâce à un banc de registre physique. Le K8 est donc un processeur au renommage hybride, qui utilise les deux solutions de renommage principales. A partir du K7, le CPU optimise la prise en charge des instructions ''load-up''. Les instructions ''load-op'' sont appelées des macro-opérations dans la terminologie d'AMD, et aussi d'Intel. L'idée est que les instructions ''load-up'' sont décodées en micro-opérations intermédiaires. Elles sont propagées dans le pipeline comme étant une seule micro-opération, jusqu'à l'étage d'émission. Lors de l'émission, les instructions ''load-up'' sont scindées en deux micro-opérations : la lecture de l'opérande, puis l'opération proprement dite. Faire ainsi économise des ressources et optimise le remplissage du tampon de ré-ordonnancement, des ''schedulers''s, des stations de réservation, etc. Le tampon de réordonnancement est combiné avec divers circuits en charge de l'exécution dans le désordre, dans ce qui s'appelle l'''instruction control unit''. Il contient de 72 à, 84 instructions, qui sont regroupées en groupes de 3. Là encore, comme pour le K5 et le K6, le tampon de réordonnancement tient compte de la sortie des décodeurs. Les décodeurs fournissent toujours trois micro-opérations par cycle, quitte à remplir les vides par des NOP. Le tampon de réordonnancement reçoit les micro-opérations, NOP inclus, par groupes de 3, et est structuré autour de ces triplets de micro-opération, y compris en interne. Pour ce qui est de l'unité mémoire, elle est précédée par une file de µops mémoire, qui émet les accès mémoire dans l'ordre du programme. Elle est souvent qualifiée de ''Load-Store Queue'', mais ce n'est pas la terminologie que nous utilisons dans ce cours. La file de micro-opération lire/écrire 64 bits par cycle depuis le cache L1, ce qui fait un seul accès au cache par cycle. La file de µops mémoire est appelée la ''Pre-Cache Queue''. Si au vu de son nom, vous avez deviné qu'il y avait une ''Post-Cache Queue''. Elle mémorise les lectures/écritures émises, mais qui ont levé un défaut de cache L1. Elle ne fait pas partie de la file de µops mémoire proprement dite. Les architectures K7, K8 et K10 ont des unités de calcul très similaires. Concrètement, il y a trois ALU entières, trois unités de calcul d'adresse, et une FPU. Le processeur incorpore, aussi un multiplieur entier, relié sur le port d'émission de la première ALU. La FPU regroupe un additionneur flottant, un multiplieur flottant, et une troisième unité LOAD/STORE pour les lectures/écritures pour les nombres flottants. L'architecture K8 ajoute une unité de manipulation de bit, la K10 un diviseur entier. [[File:Unité de calcul des processeurs AMD K7, K8 et K10.png|centre|vignette|upright=2|Unité de calcul des processeurs AMD K7, K8 et K10]] La manière d'alimenter les ALU en micro-opérations varie un petit peu entre les architectures K7, K8 et K10. Il y a cependant quelques constantes entre les trois. La première est qu'il y a un ''scheduler'' séparée pour les flottants, de 36 à 42 entrées, avec renommage de registre. le ''scheduler'' flottante a trois ports d'émission : un pour l'additionneur flottant, un autre pour le multiplieur, et un troisième pour la troisième unité flottante qui s'occupe du reste. La seconde est que chaque ALU entière est couplée avec une unité de calcul d'adresse. Par contre, la méthode de couplage varie d'un processeur à l'autre. : Les stations de réservation sont nommées des ''schedulers'' dans les schémas qui suivent. La micro-architecture K7 avait deux ''schedulers'' : une pour les opérations flottantes, une autre pour les instructions entières et les accès mémoire. le ''scheduler'' entière était reliée à 3 ALU entières et à 3 AGU. Elle pouvait émettre trois micro-opérations en même temps : trois micro-opérations entières, trois micro-opérations mémoire. Les AGU étaient reliées à la file de µops mémoire mentionnée plus haut, ce qui permet d'émettre trois µops mémoire par cycle. Par contre, la file de µops mémoire ne pouvait exécuter qu'une lecture de 64 bits ou une écriture de 64 bits. En clair, trois micro-opérations mémoire peuvent être émises par cycle, cela entraine trois calculs d'adresse simultanés, mais les trois lectures/écritures sont mises en attente dans la file de µops mémoire. Elles s'exécutent alors l'une après l'autre. le ''scheduler'' entière contenait 5 à 6 groupes de 3 macro-opérations. Vous noterez que j'ai parlé de macro-opérations et pas de micro-opérations, car les instructions ''load-up'' sont considérées comme une seule "micro-opération" dans le ''scheduler'' entière. Et cela se marie bien avec un ''scheduler'' unique partagée entre pipeline entier et pipeline mémoire. Une macro-opération était scindée en deux micro-opérations : une micro-opération mémoire et une micro-opération entière. Il est donc avantageux de regrouper unités mémoire et unités entières au même ''scheduler'' pour ce faire. [[File:AMD K7.png|centre|vignette|upright=3|AMD K7]] Sur les architectures K8 et K10, la station de réservation unique de 15 micro-opérations est remplacée par trois stations de réservations, de 8 micro-opérations chacune pour le K8, de 10 pour le K10. Chaque station de réservation entière alimente une unité de calcul entière et une unité de calcul d'adresse. l'unité de calcul d'adresse est reliée à la file de µops mémoire, qui n’exécute toujours qu'un seul accès mémoire par cycle. Le multiplieur est relié à la première station de réservation, sur le même port d'émission que l'ALU. [[File:AMD Husky microarchitecture.png|centre|vignette|upright=3|AMD Husky micro-architecture]] La micro-architecture K10 a été déclinée en plusieurs versions, nommées Grayhound, Grayhound+ et Husky, Husky étant une architecture gravée en 32 nm dédiée aux processeurs A-3000. L'architecture Grayhound a plus de cache et un ROB plus grand, la Husky est quand à elle un peu plus différente. Elle n'a pas de cache L3, contrairement aux autres architectures K10, ce qui simplifie fortement son sous-système mémoire. Par contre, les ''schedulers''s/stations de réservation et le ROB sont plus grands, pareil pour les files dans l'unité mémoire. Une ALU pour les divisions entières a aussi été ajoutée. Pour résumer, les architectures K7, K8 et K10 séparent les pipelines entiers et flottants : trois pipelines entiers avec chacun son unité de calcul, et un pipeline flottant avec plusieurs unités de calcul. Les raisons à cela sont assez diverses. Disons que dupliquer des ALU entières simples prend peu de transistors, là où les gros circuits comme le multiplieur ou la FPU ne sont pas dupliqués. Et cela a un autre avantage : le renommage, ''dispatch'' et l'émission sont plus simples. Les pipelines entiers ont une exécution dans le désordre peu complexe, grâce au grand nombre d'unités de calcul, ce qui fait que le pipeline entier est de seulement 15 cycles au total (chargement et décodage inclus). A l'opposé, la FPU est alimentée par une exécution dans le désordre très complexe, avec banc de registre physique et beaucoup de ressources, mais au prix d'un pipeline flottant plus long de 3 cycles, soit 18 cycles au total. ===La micro-architecture Bulldozer et ses dérivés=== Viennent ensuite les '''micro-architectures Bulldozer''', avec trois révisions ultérieures nommées Piledriver, Steamroller et Excavator. Un détail très important de Bulldozer est que de nombreux circuits sont partagés entre deux cœurs, à un point qui mérite de nombreuses explications. Les processeurs Bulldozer peuvent exécuter deux programmes "en même temps", sur deux cœurs partiellement fusionnés. Cette technique de partage d'unités de calcul entre coeurs s'appelle le '''cluster multithreading''', ou encore les '''architectures à cœurs conjoints''' (''Conjoined Core Architectures''). Les deux cœurs sont séparés pour ce qui est du chemin de données, du ''back-end''. Ils disposent de deux bancs de registres généraux et les ALU entières sont dupliquées. Toute la logique d'exécution dans le désordre est aussi dupliquée, avec deux ROBs, des stations de réservations séparées, etc. L'unité mémoire est aussi dupliquée, chaque cœur dispose de ses propres ''load queue'' et ''store queue'', ainsi de que son propre cache L1 de données. En clair, les chemins de données sont totalement séparés, sauf sur deux points : la FPU et les unités SIMD. La FPU est partagée entre deux coeurs, les unités SIMD sont aussi dans ce cas. Le partage de la FPU permet d'éviter de dupliquer trop de circuits et donc d'économiser des transistors. Le problème est que ce partage est source de dépendances structurelles, ce qui peut entraîner des pertes de performances. Par contre, le ''front-end'' est presque totalement partagé entre deux cœurs. Il n'y a qu'un seul cache d'instruction pour les deux cœurs, la TLB du cache d'instruction est unique, l'unité de prédiction de branchement est partagée entre deux cœurs, les décodeurs d'instruction aussi sont partagés, même la file de µops ! Les seules unités qui sont dupliquées sont la file d'instruction et l'unité de renommage, présentes en deux exemplaires. Concrètement, les deux programmes ont accès au cache à tour de rôle. Un programme a accès au cache à un instant t, mais le cycle suivant pourra être alloué à l'autre programme. Une unité décide de quel programme peut charger ses données, idem pour le décodage. [[File:AMD Bulldozer microarchitecture.png|centre|vignette|upright=3|Microarchitecture Bulldozer d'AMD.]] Au-delà de ce partage entre cœurs, Bulldozer a eu un changement assez important : les stations de réservation sont passées de stations de réservation très décentralisés à une station de réservation unique (pour les µops entières/mémoire), d'environ 40 entrées. L’implémentation de la station de réservation a aussi changée. Car 40 entrées, c'est beaucoup pour l'époque. Elle subit quelques simplifications pour la rendre plus rapide et plus économe en transistors. Les autres processeurs de l'époque utilisaient une station de réservation qui détectait à chaque instant quelle était l'instruction la plus ancienne, qui soit prête pour l’exécution. Mais Bulldozer n'utilisait pas cette technique. A la place, il mémorisait la place de l'instruction la plus ancienne gra^ce à une ''ancestry table''. Et l'instruction la plus ancienne est privilégiée sur toute les autres. Mais si elle n'est pas prête à s'exécuter, la station de réservation choisit une instruction suivant sa position dans la station de réservation (qui reste une mémoire RAM/associative, ne l'oublions pas). Bulldozer utilise aussi les optimisations du contournement et du banc de registre, vues dans le chapitre sur les CPU superscalaires. Le banc de registres généraux est dupliqué, afin de garder des bancs de registres avec peu de ports de lecture/écriture. Chaque banc de registre généraux a 4 ports de lecture et deux d'écriture, ce qui permet d'alimenter 2 ALU entières. En tout, cela permet d'alimenter 4 ALU entières, avec 8 ports de lecture et 4 d'écriture. Le tout alimente 2 ALU entières, et 2 AGUs/unités mémoire. Vu que la FPU est partagée entre deux programmes, sa station de réservation a une taille doublée comparé à la normale. Jugez plutôt : 60 entrées pour la station de réservation, là où les microarchitectures concurrentes d'Intel (''Sandy bridge'') utilisait une station de réservation de 54 entrées pour toutes les instructions entières/flottante/mémoire ! Idem pour le banc de registres flottants, qui n'a pas moins de 160 registres flottants ! Pour ce qui est des instructions SIMD, Bulldozer supporte l'extension AVX, qui fait des calculs du des registres de 256 bits, découpés en entiers/flottants de 64 bits, 32 bits, 16 bits, 8 bits, etc. L'unité SIMD ne gére cependant que des calculs sur 128 bits. Les instructions AVX sont donc découpées en deux µops, chacune traitant la moitié d'un registre SIMD. La performance n'est donc pas améliorée par rapport au SSE. Par contre, les unités SIMD gérent nativement l'opération FMA (une multiplication suivie d'une addition). {|class="wikitable" |- |+ Bulldozer |- ! Station de réservation 1 !! Station de réservation 2 !! Station de réservation 3 !! Station de réservation 4 |- | FMA - 128 bits || FMA - 128 bits || ALU - 128 bits || ALU - 128 bits |- | FMA opérandes entiers - 128 bits || Suffle et permutations || || FSTORE (x87) |} La révision Steamroller sépara le ''front-end'' en deux voies distinctes, une par ''thread''. Concrètement, le processeur se contente maintenant de partager la FPU et les unités SIMD entre deux coeurs, pas plus. Pour cela, elle ajouta un second décodeur d'instruction, une seconde file de micro-opération et une seconde unité de renommage de registres, afin d'améliorer les performances. Niveaux optimisations mineures, les stations de réservation ont été augmentées, elles peuvent mémoriser plus de micro-opérations, idem pour les bancs de registre et les files de lecture/écriture. Un cache de micro-opérations a été ajouté, de même que des optimisations quant au renommage de registre. Des ALU ont aussi été ajoutées, des FPU retirées. [[File:AMD excavator microarchitecture.png|centre|vignette|upright=3|Microarchitecture Excavator d'AMD.]] ===Les micro-architectures ZEN d'AMD=== Les micro-architectures suivantes sont les '''architectures ZEN 1/2/3/4'''. Elles se ressemblent beaucoup, le cœur de l'architecture reste plus ou moins le même. En passant à la suivante, le nombre de registre virtuel augmente, le ''branch target buffer'' augmente en taille, le ROB et les files d'attente grossissent, les caches de micro-opération aussi, les caches grossissent, etc. Une optimisation intéressante est l'ajout d'un cache de micro-opération, qui améliore grandement les performances du ''front-end'', notamment pour les boucles. La micro-architecture Zen 1 est illustrée ci-dessous. Comme on le voit, les registres flottants ont une unité de renommage séparée de celle pour les entiers, mais les deux utilisent du renommage à banc de registre physique. Il y a par contre une différence au niveau des ''schedulers'', notées ''scheduler'' dans le schéma. Les µops flottantes utilisent une station de réservation unique, alors qu'il y a une station de réservation par ALU entière. La raison de ce choix est que les opérations flottantes ont un nombre de cycle plus élevé, sans compter que les codes flottants mélangent bien additions et multiplication. [[File:Zen microarchitecture.svg|centre|vignette|upright=3|Micro-architecture Zen 1 d'AMD.]] La micro-architecture Zen 5 se distingue fortement des 4 microarchitectures précédentes. Premièrement, elle passe à une station de réservation centralisé pour les µops entières, une seconde pour els µops mémoire, et une troisième pour les µops SIMD/flottantes. Le retour à une station de réservation aussi peu décentralisé n'avait pas été vu depuis la microarchitecture Bulldozer. Une autre différence est qu'elle utilise un décodeur ''clustered'', tel que vu dans le chapitre sur les processeurs superscalaires, dans la section "Le décodage superscalaire large". ==La microarchitecture Netburst du Pentium 4== Dans cette section, nous allons voir l'architecture du processeur Pentium 4, qu'on a volontairement laissée de côté précédemment. Pourquoi un tel saut dans le temps ? Parce que le Pentium est complément à part des autres architectures Intel. Le Pentium 4 a représenté une rupture en termes de microarchitecture, qui a été un échec tellement retentissant que les processeurs suivants sont repartis sur la base du Pentium 3. Il introduisait de nombreuses nouveautés architecturales qui étaient très innovantes. Par exemple, il introduisait le renommage avec un banc de registre physique, qui a été utilisé sur tous les processeurs Intel suivants. Mais la plupart de ces innovations étaient en réalité de fausses bonnes idées, ou du moins des idées difficiles à exploiter. Par exemple, le système de pipeline à ''replay'' n'a été utilisé que sur le Pentium 4 et aucun autre processeur ne l'a implémenté. ===Un focus sur la fréquence d'horloge=== La microarchitecture du Pentium 4 a été déclinée en plusieurs versions, dont les finesses de gravure n'étaient pas les mêmes. La microarchitecture Netburst, utilisée sur le Pentium 4, utilisait un pipeline à 20 étage, augmenté à 32 sur une révision ultérieure. Il a existé quatre révisions de l'architecture : Willamette (180 nm), Northwood (130 nm), Prescott (90 nm) et Cedar Mill (65 nm). Un point important est que le Pentium 4 était prévu pour fonctionner à haute fréquence. Ses 1,5 GHz étaient impressionnants pour l'époque, les autres processeurs tournant à une fréquence proche du GigaHertzs. Pour cela, la solution retenue par Intel a été un pipeline très long, avec beaucoup d'étages. Le Pentium 4 a été décliné en plusieurs versions assez proches, chacune avec sa propre finesse de gravure qui n'ont pas toute le même pipeline. Les micro-architectures ''Willamette'' et ''Northwood'' avaient un pipeline de 20 étages, alors que les autres processeurs de l'époque avaient entre 10 et 15 étages maximum. Les micro-architectures ''Prescott'' et ''Cedar Mill'' étaient une refonte qui a fait grimper le nombre d'étages à 31 ! Du jamais vu, il s'agit d'un record pour un processeur commercial. Un pipeline aussi long permet d'exécuter beaucoup d’instructions en même temps, chacune dans un étage, mais aussi d'atteindre de hautes fréquences facilement. Le problème est qu'un pipeline avec autant d'étages a beaucoup de problèmes. Un point important est que la prédiction de branchement est cruciale. Pour rappel, la pénalité en cas de mauvaise prédiction dépend du nombre d'étages avant que le branchement soit résolu. Et les branchements sont résolus soit en fin de décodage, soit dans l'unité de calcul. C'est à dire au milieu du pipeline, soit en fin de pipeline. La pénalité en cas de mauvaise prédiction de branchement était énorme sur le Pentium 4, elle atteignait facilement 30 cycles Pour compenser, le Pentium 4 avait une prédiction de branchement très performante, pour l'époque. J'insiste sur le pour l'époque. Il utilisait un prédicteur qu'on a déjà abordé dans le chapitre sur la prédiction de branchement, précisément un prédicteur adaptatif à deux niveaux avec un historique global de 16 bits. Il avait aussi un ''Branch Target Buffer'' de 4096 entrées. Mais surtout, il intégrait une sorte de précurseur du cache de micro-opération, appelé le cache de traces, qui est détaillé dans la section suivante. ===Le cache de trace du Pentium 4=== Les décodeurs du Pentium 4 ne font pas décoder les instructions, ils mémorisent le résultat dans un cache de micro-opération un peu particulier, appelé le '''cache de trace'''. Une ligne de cache peut mémoriser 6 micro-opérations, ce qui peu sembler peu mais a été repris sur les micro-architectures suivantes. Mais le cache de trace a une grande différence avec un cache de micro-opération normal. Un cache de micro-opération normal mémorise une instruction par ligne de cache. Une instruction est décodée en plusieurs micro-instructions, qui sont enregistrées dans une ligne de cache. Si l'instruction n'utilise par les 6 micro-opérations disponibles, le reste de la ligne de cache n'est pas utilisé. Mais le Pentium 4 optimise le tout de manière ce à ce que ne soit pas le cas. Sur le Pentium 4, la contrainte du "une instruction par ligne de cache" est abandonnée. Une ligne de cache mémorise 6 micro-opérations consécutives, qui peuvent appartenir à plusieurs instructions. Par exemple, si le décodeur décode 4 instructions consécutives en 6 micro-opérations au total, alors le tout prendra une seule ligne de cache sur le Pentium 4. Et les 4 instructions consécutives n'ont même pas à être consécutives en mémoire : il peut y avoir des branchements pris entre ces instructions ! {|class="wikitable" |+ Cache de trace |- ! Ligne de cache | ADD || SUB || ADD || MOV || MUL || ''shift'' |- ! Ligne de cache | colspan="3" | ADD ''load-up'' || MUL || colspan="2" | Branch if Equal |- ! Ligne de cache | XOR || colspan="4" | POP || SUB |- ! ... | colspan="6" | ... |} Pour expliquer cela plus concrètement, nous allons devoir introduire les concepts de trace et de bloc de base. Un '''bloc de base''' (''basic block'') est une suite d'instructions sans branchement, qui est séparé par deux branchements. Le début d'un bloc de base est la destination d'un branchement, un bloc de base se termine avec un branchement. Une '''trace''' est formée en concaténant plusieurs blocs de base. Pour donner un exemple, regardez le code illustré ci-contre. Il est composé d'un bloc de base A, suivi par un bloc de base B, qui peut faire appel soit au bloc C, soit un bloc D. Un tel code peut donner deux traces : ABC ou ABD. La trace exécutée dépend du résultat du branchement qui choisit entre C et D. Le cache de trace mémorise des traces de 6 micro-opérations consécutives. Les traces sont formées en sortie des décodeurs d'instruction, par de subtiles opérations mélangeant mémorisation, décalage et concaténation. Les circuits qui construisent les traces ne sont pas connus, mais ils doivent certainement être très compliqués. toujours est-il qu'un cache de trace peut mémoriser des traces différentes, même si leur début est le même. Par exemple, prenons deux traces, composées des blocs de base A, B, C et D. La première trace est la trace ABC, la seconde est la trace ABD. Les deux traces auront chacune une ligne de cache dédiée. Une trace est réutilisable quand le premier bloc de base est identique et que les prédictions de branchement restent identiques. Pour vérifier cela, le tag du cache de traces contient l'adresse du premier bloc de base, la position des branchements dans la trace et le résultat des prédictions utilisées pour construire la trace. Le résultat des prédictions de branchement de la trace est stocké sous la forme d'une suite de bits : si la trace contient n branchements, le n-ième bit vaut 1 si ce branchement a été pris, et 0 sinon. Même chose pour la position des branchements dans la trace : le bit numéro n indique si la n-ième instruction de la trace est un branchement : si c'est le cas, il vaut 1, et 0 sinon. Si la trace est réutilisée par la suite, elle est lue depuis le cache de traces. Pour savoir si une trace est réutilisable, l'unité de chargement envoie le ''program counter'' au cache de traces, l'unité de prédiction de branchement fournit le reste des informations. Si on a un succès de cache de traces, et la trace est envoyée directement au décodeur. Sinon, la trace est chargée depuis le cache d'instructions et assemblée. Il faut signaler que le cache de trace avait sa propre unité de prédiction de branchement séparée de l'unité de prédiction de branchement normale. [[File:TraceCache.png|centre|vignette|upright=2|Cache de traces.]] Le cache de traces réduisait la longueur du pipeline en cas de succès de cache de trace. Quand les instructions étaient lues depuis le cache de trace, les étages avant le cache de trace ne sont pas utilisés, tout se passe comme s'ils étaient retirés du pipeline. C'est la même chose avec le cache de micro-opération des processeurs modernes, mais l'idée n'existait pas encore à l'époque. Le cache de trace mémorise des traces décodées, ce qui fait qu'un succès de cache de trace contournait non seulement le cache d'instruction, mais aussi les décodeurs. Le temps d'accès au cache de trace pouvait être assez élevé, même s'il était comparable au temps d'accès du cache d'instruction. Le cache de traces a depuis été remplacé par une alternative bien plus intéressante, le cache de micro-opérations, plus flexible et plus performant. Comparé à un cache de trace, la contrainte "une instruction par ligne de cache" simplifie grandement l'implémentation d'un cache de micro-opération. Ne parlons pas de la détection des succès de cache, qui demande d'utiliser les prédictions de branchement. Mais le vrai problème avec le cache de trace est tout autre. Il arrive souvent qu'une micro-opération soit présente dans plusieurs lignes de cache en raison du processus de construction des traces, chose impossible avec un cache de micro-opération. Et c'est un problème, qui réduit la capacité effective du cache de trace. Alors certes, une ligne de cache est plus remplie que sur un cache de micro-opération, on est certain que les 6 micro-opération par ligne de cache sont remplies. Mais la redondance réduit grandement cet avantage. ===L'exécution dans le désordre et le chemin de données du P4=== Le renommage de registres se fait avec un banc de registres physiques avec une table d'alias. Le Pentium 4 avait une exécution dans le désordre très limitée, basée sur la présence de deux files de micro-opération : une pour les accès mémoire, une autre pour les autres instructions. La seconde file regroupait opérations entières et flottantes, elles n'étaient pas séparées. Avec ces deux files, les instructions mémoire étaient exécutées dans l'ordre du programme, les instructions arithmétiques s'exécutaient aussi dans l'ordre du programme, mais une instruction arithmétique pouvait passer avant une instruction mémoire et inversement. L'avantage est que cela permettait de faire des lectures en avance, c'était une forme limitée de lecture non-bloquantes. Il s'agit bel et bien de deux files d'instructions, pas de ''schedulers'' ni de stations de réservation. Le Pentium 4 est le seul processeur commercial qui a utilisé des files de micro-opération séparées, tous les autres utilisent des ''schedulers'' : centralisés pour Intel, décentralisés pour AMD (en général). Le Pentium 2 et 3, bien qu'antérieurs, utilisait une station de réservation unique. Cela peut sembler être un retour en arrière, mais les files d'instructions sont bien plus larges : de 42 micro-opérations pour le Pentium 3, on passe à 120 micro-opérations pour le Pentium 4. Et vu la longueur du pipeline, qui fait qu'il y a plus d'instructions en vol, c'était une nécessité. Mais cela n'aurait pas été possible en utilisant des stations de réservation, pour des raisons de consommation électrique et/ou de budget en transistors, ce qui fait que passer à une file de micro-opération été la solution retenue. Pour les accès mémoire, le Pentium 4 utilisait donc une file de µops mémoire unique, couplée à une file d'écriture (non-représentée sur les schémas qui suivent). La file d'écriture du Pentium 4 était de 24 écritures maximum et gérait le ''Store-to-load forwarding''. Le processeur pouvait émettre une lecture et une écriture à chaque cycle. Il y avait un port d'émission pour les lectures et un autre pour les écritures, tous deux ayant chacun leur propre unité de calcul d'adresse. Le processeur contenait 3 ALU entières, 2 unités de calcul d'adresse et une FPU. La FPU était complétée par une unité pour faire des copies entre registres flottants, des opérations MOV. Pour les AGU, il y en avait une dédiée aux lectures, une autre pour les écritures. Le tout était relié aux ports d'émissions comme suit : [[File:Ports d'émission du Pentium 4.png|centre|vignette|upright=2.5|Ports d'émission du Pentium 4]] Le processeur utilisait deux réseaux de contournement séparés : un pour les opérations flottantes, un pour les opérations entières. Le réseau de contournement pour les opérations entières est aussi relié aux unités de calcul d'adresse. Jusque là, rien de surprenant, le chemin de données du processeur est assez classique. [[File:Architettura Pentium 4.png|centre|vignette|upright=3|Microarchitecture du Pentium 4.]] ===Les unités de calcul entières du Pentium 4=== Sur le Pentium 4, les ALU entières étaient cadencées à une fréquence double de celle du processeur. Les ALU entières pouvaient exécuter deux micro-opérations par cycle, ce qui fait que les ports d'émissions reliés aux ALU devaient eux aussi fonctionner à double fréquence. Pour faire la différence entre les deux fréquences, nous parlerons de fréquence/cycle processeur et de fréquence/cycle de l'ALU. Précisons que seules les ALU entières étaient à double fréquence, pas le multiplieur, pas le ''barrel shifter''. Pour simplifier, nous allons parler d'additionneur plutôt que de l'ALU entière, ce qui sera plus proche de la réalité. Et l'implémentation de l'additionneur du Pentium 4 était très innovante. L'additionneur pouvait exécuter deux additions par cycle, même si les deux additions ont une dépendance. Mais n'allez pas croire que l'implémentation était intuitive, avec un additionneur 32 bit basique très rapide. Non seulement l'additionneur fonctionnait à double fréquence, mais il était aussi pipeliné, avec un système de contournement interne ! Les additionneurs étaient pipelinées, d'une manière très simple. Une addition 32 bits était découpée en trois étapes : deux additions de 16 bits, une dernière étape pour mettre à jour le registre d'état. Pour cela, chaque additionneur était composé de deux additionneur 16 bits chacune, placées l'une après l'autre, avec un registre de pipeline entre les deux. L'additionneur prenait deux cycles d'horloge pour faire son travail : le premier cycle calculait les 16 bits de poids faible, le second calculait les 16 bits de poids fort lors du second cycle. Le tout est appelé '''addition étagée''' (''staggered add'') dans la documentation Intel. Une addition se fait donc en deux étapes, sauf que c'est compensé par le fait que l'additionneur fonctionnait à une fréquence double de celle du processeur ! Le résultat de ce fonctionnement franchement bizarre, est que les 16 bits de poids faible étaient calculés en une moitié de cycle processeur, alors que l'opération complète prenait un cycle. Deux additions consécutives s'exécutaient donc en 1 cycle et demi, alors qu'on aurait cru au premier abord que cela prendrait seulement un cycle. Si on fait les calculs, on s'apercoit que le rythme de croisière est cependant proche de 2 additions par cycle, bien qu'inférieur. 3 additions consécutives se font en deux cycles, 5 additions en 3 cycles, 7 en 4 cycles, etc. Et le Pentium 4 ajoutait un système de contournement interne à l'ALU. En clair, si une addition utilise le résultat de l'addition précédente, les deux peuvent s'exécuter en un cycle d'horloge et demi. Les 16 bits de poids faible de la première addition sont disponibles après un cycle ALU, ce qui permet de démarrer le calcul de la seconde addition au cycle suivant. ===Le ''replay pipeline''=== Le processeur est un processeur triple émission : il peut charger et décoder 3 µops par cycle, le ROB peut terminer 3 µops par cycle, etc. Pourtant, les ports d'émission peuvent émettre 6 instructions par cycle : 4 ports, dont deux à double fréquence. Une telle différence s'explique par l'usage d'un ''replay pipeline'', dont nous avons déjà parlé dans ce cours. Pour rappel, le Pentium 4 suppose que les lectures font tous un succès de cache L1. Si une opération arithmétique utilise la donnée lue comme opérande, le processeur l'émet immédiatement, l'opérande sera disponible une fois l'opération en entrée de l'ALU entière. Mais s'il s'est trompé, le processeur ré-exécute l'instruction après un temps d'attente de quelques cycles, pour se caler sur la latence du cache L2. Et si il y a un défaut de cache L2, l’instruction attend encore. Cela demande de ré-exécuter des instructions émises à tord, ce qui fait que le processeur doit avoir la capacité d'exécution pour. Ce pourquoi le processeur peut émettre 6 µops dans les unités de calcul : 3 µops normales et 3 µops ré-exécutées. ==Les microarchitectures x86 de Cyrix et Via== Les processeurs x86 grand public sont actuellement conçus et commercialisé par deux acteurs : Intel et AMD. Il faut dire que le jeu d'instruction x86 demande une licence pour être utilisée, qu'Intel et AMD refusent de dsitribuer à leurs concurrents, sauf en de très rares occasions. Cependant, il y a eu dans le passé un troisième acteur, qui a reussit à acquérir les droits de la licence x86 : Cyrix, qui a ensuite été racheté par National Semiconductor, lui-même acquis par Via. ===Les architectures compatibles 386 et 486 de Cyrix=== Cyrix a produits plusieurs CPUs et même des co-processeurs x87, avant d'être racheté. Sa carrière commence avec le Cyrix FasMath, un co-processeur arithmétique pour calculs flottants, compatible avec le x87 d'Intel. Il a ensuite produits plusieurs clones du processeur 386 d'Intel, nommés 486SLC et 486DLC. Une dénomination assez trompeuse, vous en conviendrez, mais qui n'est heureusement pas passée inaperçue et leur a valu de nombreuses critiques. Néanmoins, leurs processeurs étaient plus performants que le 386 de base, ce qui fait qu'ils étaient des upgrades corrects pour les PC avec un 386 (les cartes mères compatibles avec le i386 n’étaient pas compatibles avec le i486). Le 486SRX2 et le 486DRX2, sortis plus tard, étaient des versions avec une fréquence encore plus élevée, ce qui augmentait leurs performances. Cyrix récidiva avec le 5x86, un processeur offrant des performances s'approchant du Pentium, mais pour la plateforme 486. Le processeur supportait seulement les instructions du 486, pas les instructions ajoutées sur le Pentium. Son bus était similaire à celui du 486. Mais sa microarchitecture se rapprochait du Pentium, bien que n'étant pas aussi complexe. Il y avait une file d'instruction capable de mettre en attente 3 instructions, un cache unifié, une unité de prédiction de branchement. Malheureusement, la prédiction de branchements avait été désactivée en raisons de bugs matériels qui faisaient crasher le processeur. Niveau ALU, mais il y avait une FPU, une ALU entière et une unité mémoire. Mais il n'y avait pas de double émission. [[File:Cy5x86 arch (cropped).png|centre|vignette|upright=2.5|Cy5x86 arch (cropped).]] ===Le Cyrix 6x86 : une architecture superscalaire avancée=== Le '''Cyrix 6x86''' est là où la superscalarité apparait dans la gamme Cyrix. Le processeur était non pas une upgrade pour des cartes mères existantes, mais un concurrent direct du Pentium. C'était un processeur à double émission, avec exécution dans le désordre et renommage de registre. L'organisation de ses caches est assez originale. Il avait un cache principal de 16 kibioctets, qui mémorisait à la fois données et instructions, couplé à un cache d'instruction de 256 octets. En termes modernes, on dirait qu'il disposait d'un cache L2, couplé à un cache L1 d'instructions, mais sans cache L1 pour les données. Le cache unifié/L2 était un cache double port. Le cache d'instruction était totalement associatif. [[File:Cy6x86 arch.png|centre|vignette|upright=2.5|Cy6x86 microarchitecture.]] Le processeur supportait une double émission bien plus complète que celle du Pentium. Il disposait de deux pipelines entiers, nommés X et Y. Le pipeline X était le seul à pouvoir exécuter branchements et opérations flottantes, c'était le seul connecté à la FPU. Par contre, il était possible d'émettre un branchement ou une opération flottante dans le pipeline X, tout en émettant une seconde instruction dans le pipeline Y. Ce que le Pentium ne pouvait pas faire. Certaines instructions ne pouvaient cependant pas être appariées avec une autre : les multiplications/divisions, les ''string instruction'', les ''far jumps'', les accès aux entrées-sorties, et des instructions systèmes. La FPU pouvait exécuter des instructions en parallèle de l'ALU entière. Elle avait une file de µops de 4 µops flottantes. Elle avait aussi sa propre ''Store queue'', spécifiquement dédiée aux écritures flottantes, séparée de la ''Store Queue'' pour les écritures "normales", celles des registres généraux. Cette séparation est possible du fit que les registres flottants et généraux sont séparés sur le jeu d'instruction x86. [[File:Cyrix 6x86 arch.svg|centre|vignette|upright=2.5|Cy6x86 microarchitecture.]] Le Cyrix 6x86 avait de nombreux avantages sur le Pentium. Il intégrait notamment du renommage de registres pour les registres entiers, ainsi que le contournement, ce que ne faisait pas le Pentium. Et il pouvait faire de la double émission entière-flottante, alors que le Pentium ne pouvait pas émettre de seconde µop en parallèle avec une opération flottante. Tout cela le rendait bien plus performant que le Pentium, sur le papier. Sauf que sa FPU était peu performante, proche de celle du 5x86. Les concepteurs du processeur avaient mis le paquet sur les opérations entières, en délaissant les opérations flottantes. Les applications développées pour le Pentium, qui répartissaient au mieux leurs calculs entre FPU et ALU entière, marchaient donc moins bien sur le 6x86. Le successeur du 6x86, le '''Cyrix Jalapeno''', était un concurrent du Pentium 2/3. Son pipeline passait de 7 à 11 étages, ce qui permettait des augmentation de fréquence importante. Son cache était quadruplé en taille et passait à 8 voies. Et pour ce qui de la superscalarité, il était maintenant capable d'émettre deux µops flottantes par cycle : une partait dans l'additionneur flottant, l'autre dans un multiplieur flottant. ===Les processeurs de marque Via=== Après deux rachats, la licence x86 de Cyrix est passée dans les main de Via. Via avait racheté Cyrix, mais aussi Centaur, un autre concepteur de processeur. Via produisit plusieurs processeurs x86, basés sur des design provenant non pas de Cyrix, mais de Centaur, pour leur microarchitecture. Le premier processeur de cette lignée, le mal-nommé Cyrix III, a d'ailleurs été renommé en C3, parce qu'il n'avait aucun lien avec les microarchitectures de Cyrix et n'utilisait pas leurs technologies. Les '''processeurs Via C3''' et '''Via C7''' étaient des processeurs 32 bits. Ils étaient prévus pour des ordinateurs portables et ciblainet une faible consommation d'énergie, plutôt que des hautes performances. Ils n'avaient pas d'exécution dans le désordre, mais utilisaient une superscalarité limitée à la double émission. Le C3 regroupe en réalité deux microarchitecture semblables. Les modèles Samuel 2 et Ezra utilisaient la première version de la microarchitecture, alors que les processeurs Nehemiah avaient une version améliorée de celle-ci. Le pipeline passait de 12 à 16 étages, sa FPU est améliorée, les extensions SIMD sont revues (passage au SSE, abandon du 3DNow!). Les processeurs C7 utilisent cette même microarchitecture, bien qu'améliorée sur quelques détails. [[File:VIA Nano Architecture Blockdiagram.jpg|vignette|upright=1.5|VIA Nano Architecture.]] Par la suite, Via sortit le '''Via Nano''' en 2008 . C'était le premier CPU 64 bits de la marque. Il avait tout d'un design moderne, avec exécution dans le désordre, prédiction de branchement complexe, hiérarchie de cache classique, préchargement, etc. Il implémentait la superscalarité en triple émission. Pour cela, son ''front-end'' chargeait 16 octets par cycle, qui étaient accumulés dans une file d'instruction. Trois décodeurs lisaient les instructions dans cette file, puis envoyaient trois µops dans une file de µops de taille inconnue. Le renommage de registre pouvait lui aussi renommer trois µops par cycle. Niveaux unités, il avait deux ALU entières, une unité LOAD, une unité STORE, deux unités SIMD (une pour les additions SIMD, une pour les multiplications SIMD). Chaque unité avait sa propre file de µops, qui faisait entre 8 et 12 entrées. Les unités LOAD et STORE avaient chacune leur propre file de µops, il n'y avait pas de file de µops partagée entre les deux. L'unité LOAD alimentait une ''load queue'' de 16 lectures, alors que l'unité STORE alimentait une ''store queue'' de 16 écritures. Les unités de calcul sont décrites dans le tableau ci-dessous : {|class="wikitable" |- ! !! ALU 1 !! ALU 2 !! FPU/SIMD 1 !! FPU/SIMD 2 !! LOAD !! STORE |- ! File de µops | 12 entrées || 11 entrées || 8 entrées || 24 entrées || 8 entrées || 8 à 13 entrées, selon les sources |- ! rowspan="5" | Opérations | Opérations entières de base || Opérations entières de base || || || LOAD || STORE |- | Décalages et rotations || Multiplication entière 32 bits || Multiplication entière 64 bits || || || |- | CMOV || CMOV || Division entière 64 bits || Division entière 64 bits || || |- | ''Add With Carry'' || Branchements || Division flottante || || || |- | || || SIMD opérations entières + FMUL 128 bits || SIMD opérations entières + FADD 128 bits || || |} Les processeurs qui ont suivis sont des processeurs commercialisés uniquement en Chine, à destination du marché chinois et subventionnés (si ce n'est plus), par l'administration chinoise.Le peu d'informations qui sont disponibles dessus sont disponibles sur le substack ''Chips and cheese'', qui a notamment quelques articles sur les processeurs Longsoon. Pour une histoire complète et une review en profondeur des architectures de Via, je conseille les articles du blog ''Chips and cheese'' : * [https://chipsandcheese.com/p/the-weird-and-wacky-world-of-via-the-3rd-player-in-the-modern-x86-market The Weird and Wacky World of VIA, the 3rd player in the “Modern” x86 market] * [https://chipsandcheese.com/p/the-weird-and-wacky-world-of-via-part-2-zhaoxins-not-quite-electric-boogaloo The Weird and Wacky World of VIA Part 2: Zhaoxin’s not quite Electric Boogaloo] * [https://chipsandcheese.com/p/zhaoxin-part-3-a-sort-of-anti-climax Zhaoxin Part 3: A Sort of Anti-Climax] * [https://chipsandcheese.com/p/via-part-4-a-deep-dive-into-centaurs-last-cpu-core-cns VIA Part 4 – A Deep Dive into Centaur’s Last CPU Core: CNS] * [https://chipsandcheese.com/p/examining-centaur-chas-die-and-implementation-goals Examining Centaur CHA’s Die and Implementation Goals] <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les processeurs superscalaires | prevText=Les processeurs superscalaires | next=Les processeurs VLIW et EPIC | nextText=Les processeurs VLIW et EPIC }} </noinclude> q7jx7w0beg5sxs9xsp8gkoi2v9g69ao Fonctionnement d'un ordinateur/Les microarchitectures pour le x86 : basse consommation 0 84530 773679 773538 2026-09-29T23:04:30Z Mewtow 31375 773679 wikitext text/x-wiki Le chapitre précédent étudiait les processeurs x86 destinés aux PC fixe, au ''gaming'', aux serveurs, bref : à ce tout ce qui demande de la performance avant tout. De telles processeurs sont appelés des processeurs haute performance. Mais divers processeurs x86 visent eux, non pas la performance, mais surtout une consommation d'énergie réduite. Ils sont destinés aux PC portables, essentiellement. Cela ne veut pas dire qu'ils ne sont pas performants, mais qu'ils font un compromis différent : moins de performance, moins de consommation. ==Les microarchitectures basse consommation== Et qui dit basse consommation dit souvent : microarchitectures adaptées. Alors certes, certains modèles basse consommation utilisent les microarchitectures du chapitre précédent, et retirent des coeurs ou du cache. C'est une possibilité, mais elle n'est pas systématique. De nombreux processeurs basse consommation utilisent une microarchitecture adaptée, prévue pour consommer moins. Les microarchitectures de ce genre seront appelées, dans ce chapitre, des '''microarchitectures basse consommation'''. ===Les sources d'économie dans le cas général=== Les microarchitectures basse consommation font des économies à divers endroits. Des économies sur l'exécution dans le désordre : ROB plus petit, ''schedulers'' plus petits, ''store queue'' plus petites. Des économies sur les unités : moins d'ALU, moins de FPU, unités SIMD plus petites, moins d'unité mémoire, une seule unité de branchement, etc. Le banc de registre peut avoir moins de ports, ce qui entraine l'apparition de contraintes d’appariement. Et bien d'autres. Les toutes premières microarchitectures basse consommation se débarrassaient de l’exécution dans le désordre. Les processeurs basse consommation ARM faisaient cela, de même que les processeurs MIPS ou autres destinés à l'embarqué. Chez Intel, les premiers processeurs Atom d'Intel n'utilisaient pas l'exécution dans le désordre, ce qui fait qu'il aura droit à sa propre section dédiée. Mais la loi de Moore a changé la donne avec le temps. Même pour de la basse consommation, l'exécution dans le désordre est utilisée. Le gain en performance est tellement important que le ratio performance/consommation est amélioré. Quitte à gagner 50% de performances avec une consommation augmentée de 30%, autant en profiter, quitte à faire des économies ailleurs. Niveau prédiction de branchements, ils tendent à ne pas faire trop d'économie. La simple présence d'un pipeline rend la prédiction de branchement nécessaire, et l'exécution dans le désordre la rend encore plus importante. De fait, la prédiction de branchement évite du 'gaspillage", ce qui fait qu'elle améliore aussi bien les performances que la consommation d'énergie, si elle est correctement calibrée. Annuler des instructions exécutées à tord, c'est avant tout gaspiller de l'électricité pour rien. ===Les microarchitectures basse consommation d'Intel=== La première microarchitecture basse consommation d'Intel était celle des processeurs Atom, une gamme de processeurs basse consommation séparée des processeurs pour ''desktop''. Les processeurs Atom ont utilisé plusieurs microarchitectures succesives. La microarchitecture ''Bonnell'' et son ''die shrink'' ''Saltwell'' a été la première. C'était une microarchitecture sans exécution dans le désordre. Les microarchitectures qui suivent sont, dans l'ordre chronologique et en 2026 : ''Silvermont'', ''Goldmont'', ''Tremont'' et ''Gracemont''. Elles utilisent toutes l'exécution dans le désordre. Outre les processeurs Atom, Intel utilise aussi ces microarchitectures basse consommation dans ses processeurs pour ''desktop''. De nos jours, les processeurs Intel utilisent les deux types de micro-architectures en même temps. Les CPU Intel modernes disposent de deux types de coeurs : les coeurs P et le coeurs E. Leur nom signifie "Performance" et "Efficient", qui trahissent leur but. Les coeurs P utilisent la microarchitecture de la lignée principale, qui est conçue pour la performance. Les coeurs E, quant à eux, utilisent les micro-architectures basse consommation de la lignée secondaire. LA technique est aussi utilisée par les processeurs ARM et quelques autres marques. Un autre détail est que les microarchitecture basse consommation ne mettent pas le paquet sur les instructions SIMD. Elles se contentent d'utiliser des unités de calcul 128 bits. Pour l'AVX, qui utilise des registres de 256 bits, ,voire 512, les calculs sont fait en deux fois. La conséquence est qu'une instruction SIMD de type SSE ou AVX, est décodée en deux micro-opérations 128 bits. ==Les processeurs Atom d'Intel, de microarchitecture Bonnell== L'architecture de l'Atom première génération est assez simple. Son pipeline faisait 16 étages, ce qui est beaucoup. C'est un processeur 32 bits, ce qui aura son importance dans ce qui suit. Il était conçu pour être un processeur basse consommation, donc peu puissant. En conséquence, il n'a pas d'exécution dans le désordre, même s'il est superscalaire. C'était la norme à l'époque pour les processeurs basse consommation, que de faire sans exécution dans le désordre. De nos jours, les choses ont bien changée, même les processeurs basse consommation ont exécution dans le désordre, superscalarité et renommage de registres. ===Le ''front-end'' de l'Atom=== Le cache d'instruction permet de lire 8 octets par cycle, qui sont placés dans une file d'instruction, elle-même suivie par deux décodeurs. Le fait que les décodeurs lisent les instructions depuis une file d'instruction fait que les deux instructions décodées ne sont pas forcément consécutives en mémoire RAM. Par exemple, l'Atom peut décoder un branchement prédit comme pris, suivi par l'instruction de destination du branchement. Les deux instructions ont été chargées dans la file d'instruction et sont consécutifs dedans, alors qu'elles ne sont pas consécutives en mémoire RAM. Sur l'Atom, la majorité des instructions x86 sont décodées en une seule micro-opération, y compris les instructions ''load-up''. Le microcode n'est utilisé que pour une extrême minorité d'instructions et est à part des deux décodeurs précédents. L'avantage est que cela permet d'utiliser au mieux la file de micro-opération, qui est de petite taille. Mais surtout, cela permet de grandement réduire la consommation du processeur, au détriment de ses performances. Pour avoir un décodage rapide, malgré des instructions complexes, le processeur recourt à la technique du pré-décodage, qui prédécode les instructions lors de leur chargement dans le cache d'instruction. Le prédécodage lui-même prend deux cycles, là où une lecture dans le L1 d'instruction en prend 3. les défauts de cache d'instruction sont donc plus longs de deux cycles. Mais l'avantage du prédécodage est que la consommation d'énergie est diminuée. Prenez une instruction exécutée plusieurs fois, dans une boucle. Au lieu de décoder intégralement une instruction à chaque fois qu'on l'exécute, on la prédécode une fois, seul le reste du décodage est fait à chaque exécution. D'où un gain d'énergie assez intéressant. Les caches de micro-opération, qui sont capables d'exécuter une optimisation similaire, n'existaient pas encore à cette époque. ===Le chemin de données de l'Atom=== Les deux décodeurs alimentent une file de micro-opérations de petite taille : 32 µops maximum, 16 par ''thread'' si le ''multithreading'' matériel est activé. La file de micro-opérations a deux ports d'émission, ce qui permet d'émettre au maximum 2 µops par cycle. Les conditions pour cela sont cependant drastiques. Les deux instructions ne doivent pas avoir de dépendances de registres, à quelques exceptions près liées au registre d'état. Le multithreading matériel doit aussi être désactivé. Les deux instructions doivent aller chacun dans un port différent, et cela tient en compte du fait que les deux ports sont reliés à des unités de calcul fort différentes. Le tout est illustré ci-dessous. Les deux ports ont chacun une ALU simple dédiée, capable de faire des additions/soustractions, des opérations bit à bit et des copies entre registres. Mais ils ont aussi des opérations qui leur sont spécifiques. La séparation entre les deux pipelines est assez complexe. Il ne s'agit pas du cas simple avec un pipeline entier et un pipeline flottant séparés. En réalité, il y a deux pipelines, chacun capables de faire des opérations entières et flottantes, mais pas les mêmes opérations. Le premier port permet d’exécuter des opérations entières simples, une addition flottante, des comparaisons/branchements, ou une instruction de calcul d'adresse LEA. Le second port/pipeline est, quant à lui, conçu pour exécuter les instruction ''load-up'' nativement, en une seule micro-opération. Il contient toute la machinerie pour faire les accès mémoire, notamment des unités de calcul d'adresse et un cache L1 de données. A la suite du cache, se trouvent une ALU entière simple, un ''barrel shifter'', et un circuit multiplieur/diviseur. Le circuit multiplieur/diviseur est utilisé à la fois pour les opérations flottantes et entières. [[File:Intel Atom Microarchitecture.png|centre|vignette|upright=2.5|Intel Atom Microarchitecture]] Cette organisation difficile à comprendre est en réalité très efficace, très économe en circuit, tout en gardant une performance intéressante. Les instructions simples, ADD/SUB/bitwise sont supportées dans les deux pipelines. Il faut dire que ce sont des opérations courantes qu'il vaut mieux optimiser au mieux. Le processeur peut donc émettre deux opérations simples et fréquentes en même temps, ce qui augmente les performances. Les opérations plus complexes, à savoir les multiplications/divisions/décalages/rotations/manipulations de bit sont supportées dans un seul pipeline. La raison est qu'il est rare que de telles opérations soient consécutives, et qu'il n'est donc pas utile d'optimiser pour cette situation. Si les deux pipelines devaient supporter ces opérations, cela demanderait de dupliquer les circuits multiplieurs/diviseur, ce qui aurait un cout en circuit important pour un gain en performance assez faible. ===Le système d'exceptions flottantes de l'Atom=== Le processeur étant sans exécution dans le désordre, ses instructions doivent écrire dans les registres dans l'ordre du programme. En conséquence, certaines instructions doivent être retardées, leur émission doit attendre que les conditions soient adéquates. Et cela pose problème avec les opérations flottantes, vu qu'elles prennent pas mal de cycles pour s'exécuter. Imaginez qu'une instruction flottante de 10 cycles soit suivie par une instruction entière. En théorie, on doit retarder l'émission de l'instruction entière de 9 cycles pour éviter tout problèmes. Le cout en performance est donc assez important. En théorie, les instructions entières et flottantes écrivant dans des registres séparés, ce qui fait que l'on pourrait exécuter instructions entières et flottantes dans le désordre. Sauf pour les instructions de copie entre registres entier et flottants, mais laissons-les de côté. Le problème est qu'une instruction flottante peut parfois lever une exception, par exemple en cas de division par zéro, ou pour certains calculs précis. Si une exception est levée, alors l'instruction flottante est annulée, de même que toutes les instructions qui suivent, y compris les opérations entières. Ce n'est pas un problème si le processeur gère nativement les exceptions précises, par exemple avec un tampon de ré-ordonnancement. Mais l'Atom étant un processeur sans exécution dans le désordre, les instructions entières devraient être mises en attente tant qu'une instruction flottante est en cours d'exécution. Heureusement, l'Atom d'Intel a trouvé une parade. La technique, appelée ''Safe Instruction Recognition'' par Intel, est décrite dans le brevet US00525721.6A. L'idée est de tester les opérandes flottantes, pour détecter les combinaisons d'opérandes à problème, dont l'addition/multiplication peut lever une exception. Si des opérandes à problème sont détectées, on stoppe l'émission de nouvelles instructions en parallèle de l'instruction flottante et l'unité d'émission émet des bulles de pipeline tant que l'instruction flottante est en cours. Sinon, l'émission multiple fonctionne. La technique permet ainsi de ne pas écrire dans les registres entiers/flottants dans l'ordre du programme : une instruction entière peut être autorisée à s'exécuter même si elle écrit dans un registre entier avant qu'une instruction flottante délivre son résultat. ==Les microarchitectures de Silvermont à Crestmont== Les microarchitectures qui font suite à l'architecture Bonnell sont, dans l'ordre chronologique : Silvermont, Goldmont, Tremont, Gracemont et Crestmont. Elles utilisent toute l'exécution dans le désordre, avec renommage de registres. Elles sont aussi superscalaires, avec une progression chronologique de la triple vers la pentuple émission, voire au-delà. Les différentes microarchitecture sont toutes superscalaires, avec une progression chronologique de la triple vers la pentuple émission, voire au-delà. Il faut noter que la microarchitecture Tremont pouvait décoder six instructions par cycles, mais émettre seulement 4 µops par cycle. Idem avec Gracemont , qui était limitée à 5 µops par cyle, là encore à cause de l’unité de renommage. {|class="wikitable" |- ! Processeur !! Chargement !! Décodage !! Renommage |- ! Silvermont | 16 octets par cycle || 2 instructions par cycle || 2 µops par cycle |- ! Goldmont | 16 octets par cycle || 3 instructions/cycle || 2 µops par cycle |- ! Tremont | 32 octets par cycle || 6 instructions/cycle || 4 µops par cycle |- ! Gracemont | 32 octets par cycle || 6 instructions/cycle || 5 µops par cycle |- ! Crestmont | 6 octets par cycle || 6 instructions par cycle || 6 µops par cycle |} Les microarchitectures Tremont, Gracemont et Crestmont sont des processeurs superscalaires assez larges, avec exécution dans le désordre, ce qui est assez étonnant pour de la basse consommation, mais qui est devenu la norme depuis longtemps, grâce à la loi de Moore. Néanmoins, cela vient avec des optimisations pour réduire le cout en circuit/énergie. Et ces optimisations sont intéressantes à étudier. Par contre, certaines implémentations de l’exécution dans le désordre sont plus consommatrices que d'autres. Et cela permet de faire le lien avec le chapitre précédent. Dans le chapitre précédent, j'ai dit que les processeurs Intel utilisaient une station de réservation centralisée, alors qu'AMD préférait la décentraliser à l'excès. AMD pousse le bouchon jusqu'à avoir une station de réservation par unité, que ce soit les ALU, les FPU, les unités mémoire, et même les unités de branchement. Il se trouve que la solution d'AMD est nettement meilleure. L'utilisation de '''stations de réservations décentralisées''' est une première optimisation. Et quand je dis décentralisé, c'est au point où chaque ALU entière a sa propre station de réservation. Cela réduit les performances par rapport à une station de réservation centralisée, ou un moins un système moins décentralisé, mais entraine un gain en consommation d'électricité non négligeable. Une seconde optimisation est que les stations de réservation pour les opérations flottantes sont séparées des autres. Il n'y a pas, comme sur les microarchitectures Intel, de ports d'émission qui partagent ue ALU et une FPU, voire une ALU et une unité SIMD. La raison est que si le programme exécuté n'utilise pas d'instructions SIMD, les circuits associés peuvent être ''clock gatés'', voire éteints. Les stations de réservation SIMD ou Flottante, les registres SIMD/flottants, les FPU, les unités SIMD : tout cela est simplement mis en veille. Le gain en termes de consommation est alors assez important, surtout avec les instructions SIMD. Une troisième optimisation est liée aux FPU, et précisément aux stations de réservation associées. Ou plutôt devrais-je dire : la station de réservation flottante. Car si les ALU entières ont chacune leur propre station de réservation, les FPU et les unités SIMD tendent à avoir une seule station de réservation, partagée entre toutes les FPUs. La raison à cela est que cela convient mieux aux opérations flottantes. Elles ont une durée plus longue, attendent plus longtemps dans les stations de réservation, etc. bref, des détails techniques qui font que c'est mieux ainsi. Une dernière optimisation, liée à la précédente, est l'usage de '''files d'instructions pour les opérations mémoire'''. Si ces processeurs utilisent des stations de réservation pour les opérations entières, ce n'est pas le cas pour les opérations mémoire. Les accès mémoire sont donc exécutés dans l'ordre, contrairement aux autres opérations. Il arrive aussi que ce soit la même chose, mais pour les opérations flottantes, encore que ce soit plus rare. . Les performances mémoire sont donc un peu réduites, mais le gain en termes d'énergie en vaut la peine. Une particularité de ces microarchitectures est l'absence du cache de micro-opérations. Pourtant, un tel cache devrait être une source d'économies d'énergie. Lire des µops dans ce cache évite d'avoir à accéder au cache d’instruction, décoder des instructions, etc. Sans doute que le cout en circuit est plus faible, et que ce gain en circuit est considéré comme plus important que les économies d'énergie et les gains en performances qui vont avec. ===Les unités fonctionnelles et l'exécution dans le désordre=== Pour ce qui est de l'exécution dans le désordre, il faut préciser que Silvermont et Goldmont n'utilisent pas le même mécanisme de renommage de registre. Silvermont fait le renommage dans le ROB, avec un banc de registre architectural et un banc de registres renommés. L'avantage est que cette implémentation est économe en circuits, même si elle entraine des déplacements de données et des copies entre registres réguliers. Elle permet notamment de réduire le nombre de ports du banc de registre, en répartissant ceux-ci sur le banc de registre architectural et renommés. Goldmont passe à un renommage avec un banc de registre physique unique. Silvermont a deux ALU entières, un ''barrel shifter'', un multiplieur entier, une unité mémoire unique, un additionneur flottant et un multiplier flottant. Le tout est repartit sur 5 pseudo-ports d'émission, en réalité 5 stations de réservation de 8 entrées, chacune connectée à quelques unités de calcul. Le tout est organisé comme suit {|class="wikitable" |+ Silvermont |- ! Station de réservation 1 !! Station de réservation 2 !! Station de réservation 3 !! Station de réservation 4 !! Station de réservation 5 |- | 8 entrées || 8 entrées || 6 entrées || 8 entrées || 8 entrées |- | colspan="5" | |- | ALU entière || ALU entière || LOAD/STORE || FADD || FMUL |- | ''Barrel shfiter'' || Multiplieur entier || || ALU SIMD entière (128bits) || ALU SIMD entière (128bits) |- | || Branchements || || |} Goldmont fait les modifications suivantes : il rajoute une ALU entière, les stations de réservations augmentent en taille, il fusionne les stations de réservation pour les unités flottantes. De plus, l'ALU pour les branchements reçoit sa propre réservation de station. L'avantage est que cela permet d'exécuter les branchements en priorité, et dont de savoir s'ils sont pris ou pas en avance, et à quelle adresse brancher cas échant. Le plus tôt ces informations sont connues, au mieux la prédiction de branchement fonctionne bien, au mieux on peut annuler les instructions chargées à tord. {|class="wikitable" |- |+ Goldmont |- ! Station de réservation 1 !! Station de réservation 2 !! Station de réservation 3 !! Station de réservation 4 !! Station de réservation 5 !! Station de réservation 6 !! Station de réservation 7 !! Station de réservation 8 |- | 10 entrées || 10 entrées || 10 entrées || 8 entrées || colspan="2" | 13 entrées || colspan="2" | 27 entrées |- | colspan="8" | |- | ALU entière || ALU entière || ALU entière || Branchements || LOAD || STORE || FADD || FMUL |- | ''Barrel shfiter'' || Multiplieur entier || || || || || ALU SIMD entière (128bits) || ALU SIMD entière + MUL SIMD entière (128bits) |} Les microarchitectures suivantes ont plus d'unités de calcul. {|class="wikitable" |- |+ Tremont |- ! Station de réservation 1 !! Station de réservation 2 !! Station de réservation 3 !! Station de réservation 4 !! Station de réservation 5 !! Station de réservation 6 !! Station de réservation 7 !! Station de réservation 8 !! Station de réservation 9 !! Station de réservation 10 |- | 12 entrées || 12 entrées || 7 entrées || 17 entrées || colspan="2" | 13 entrées || 14 entrées || 13 entrées || colspan="2" | 24 entrées |- | colspan="8" | |- | ALU entière || ALU entière || ALU entière || Branchements || LOAD || LOAD || STORE || FSTORE (écriture) || ALU SIMD (128 bits) || ALU SIMD (128 bits) |- | ''Barrel shfiter'' || Multiplieur entier || || || || || SIMD FMUL (128bits) || SIMD FADD (128bits) |- | || || || || || || FDIV || |} {|class="wikitable" |- |+ Gracemont |- ! RS !! RS !! RS !! RS !! RS !! RS !! RS !! RS !! RS !! RS !! RS !! RS !! RS !! RS !! RS |- | 15 entrées || 16 entrées || 16 entrées || 15 entrées || colspan="2" | 42 entrées | colspan="4" | 22 entrées | 13 entrées || colspan="2" | 24 entrées |- | ALU || ALU || ALU || ALU || Branch || Branch | LOAD || LOAD || STORE || STORE | FSTORE (écriture) || FSTORE (écriture) || ALU SIMD (128 bits) || ALU SIMD (128 bits) || ALU SIMD (128 bits) |- | || MUL entier || MUL entier || || || | || || || | SIMD FMA (128bits) || SIMD FMA (128bits) |- | || DIV entier || DIV entier || || || | || || || | SIMD FADD (128bits) || SIMD FADD (128bits) |- | || LEA || Manipulation de bits || || || | || || || | SIMD FMUL (128bits) || SIMD FMUL (128bits) |} ===L'unité mémoire et la FPU des CPU Intel basse consommation=== Silvermont et Goldmont se limitent à une simple unité mémoire, qui a cependant deux ports séparés pour Goldmont. L'économie en circuit est conséquente, car ils se débrouillent avec une ''load queue'' et une ''Store queue'', toutes deux simple port (si on omet le port pour le ''store to load forwarding''). De même, le cache L1 peut se débrouiller avec seulement une implémentation naturelle, à savoir un port de lecture et un d'écriture (le cache est naturellement double port, vu que les entrées de lecture et d'écriture sont séparées sur les cellules de SRAM). Pas besoin d'utiliser de structures matérielle avec un port de plus que de nature, ce qui est un énorme avantage en termes d'économie de circuits et de consommation énergétique. C'est sur les microarchitecture suivantes que démarrent les hostilités. Tremont ajoute un second port pour émettre une lecture, Gracemont ajoute un second port pour les écritures en plus (4 ports au total). Crestmont uant à elle, dispose de trois ports d'émission pour les lectures et de deux ports d'émission pour les écritures. De plus, la file de µops mémoire est scindée en deux : une file de µops mémoire, suivie par une station de réservation de petite taille. Les µops mémoire sont accumulées dans la file de µop quand les stations de réservation sont pleines, histoire de ne pas bloquer l'émission en cas de défaut de cache un peu trop prolongé. Prenons une µop mémoire qui est tout juste ''dispatch'' : l'unité de ''dispatch'' regarde si il y a de la place dans la station de réservation. Si c'est le cas, elle envoie la µop mémoire à la station de réservation. Sinon, elle l'envoie dans la file de µops mémoire. Tremont utilise une file de µops de 21 entrées, alors que la station de réservation en fait 13, ce qui fait un total de 34 entrées. Les performances sont moindres comparé à une station de réservation de 34 entrées, car les µops dans la file de µops mémoire ne peuvent pas être émises tant qu'elles n'ont pas atteint les stations de réservations, même si les conditions sont remplies en matière d'opérandes pour qu'elles puissent passer devant. Mais le gain en circuits est conséquent, de même que l'économie d'énergie, pour une perte de performance plus que tolérable. Les opérations flottantes étant assez longues, Gracemont utilise le même système pour les opérations flottantes. Une file de µops précède deux stations de réservation. La première accumule des opérations flottantes, destinées à être exécutées dans la FPU (de type SIMD). La file de µops fait 56 entrées, alors que la station de réservation en a 35. Une seconde station de réservation de 18 entrées met en attente les écritures flottantes, à savoir les écritures qui écrivent un flottant simple ou double précision en mémoire RAM. Le schéma ci-dessous illustre ce qu'il en est sur l'architecture Crestmont. On voit que les files pour µops flottantes et mémoire sont de type ''non-scheduling'', ce qui veut dire que ce sont de simples files d'instruction. [[File:Crestmont.png|centre|vignette|upright=3|Crestmont]] ===Le ''front-end'' : un changement après Silvermont et Goldmont=== Le ''front-end'' commence avec le cache d'instruction et la file d'instruction. Le cache d'instruction est un cache simple port, capable de lire 16 octets consécutifs par cycle. Ces 16 octets peuvent contenir un nombre variable d'instructions, de 16 instructions maximum à une seule (une instruction x86 fait entre 1 et 16 octets). Sur l'architecture Silvermont, la file d'instruction peut mémoriser maximum 6 blocs de 16 octets, elle a donc une capacité de 6 blocs. La file d'instruction est suivie par plusieurs décodeurs simples et un microcode. L'architecture Silvermont n'a que deux décodeurs simples, alors que Goldmont en a 3. Le décodage d'une instruction prend trois cycles d'horloge, le décodage est évidemment pipeliné. Il faut noter que les instructions ''load-op'' sont décodées en une seule µop, ils utilisent la technique de la micro-fusion. Ils alimentent une file de µops, capable de mémoriser 32 µops sur Silvermont. {|class="wikitable" |- ! !! Silvermont !! Goldmont |- ! Chargement | colspan="2" | 16 octets par cycle |- ! File d'instruction | 6 blocs, donc 6* 16 octets || |- ! Decodage | Deux instructions par cycle || Trois instructions par cycle |- ! File de µops | 32 µops || |} En remplacement du cache de µops, ces microarchitectures, depuis Tremont, utilisent un ''front-end'' tel que décrit dans le chapitre sur les processeurs superscalaires, dans la section "''Les optimisations des processeurs superscalaires larges''". Faisons un rapide rappel, avec une remise en contexte "historique". Goldmont était une microarchitecture triple émission, avec trois décodeurs simples (et un microcode). La microarchitecture suivante, Tremont, souhaitait augmenter la largeur du processeur. Idéalement, il aurait fallu recréer le ''front-end'' pour pouvoir charger 4 à 5 instructions simultanément, et surtout les décoder. Mais ce n'est pas ce qui a été fait. A la place, elles ont décidées de dupliquer les décodeurs, et de les coller ensemble en utilisant l'unité de prédiction de branchement. Il y a donc 6 décodeurs, qui sont organisés en deux paquets de trois, en deux ''clusters''. Et cette organisation en ''cluster'' est primordiale pour comprendre la suite. Le processeur ne charge pas 6 instructions consécutives, mais 2 blocs de 3 instructions. Les deux blocs ne sont donc pas consécutifs en mémoire RAM, bien au contraire : ils sont séparés par des branchements. Le premier bloc est chargé normalement, mais le second bloc est décidé par la prédiction de branchement. La conséquence est qu'en absence de branchements, le processeur ne peut que charger/décoder 3 instructions consécutives, pas 6. Pour charger deux blocs non-consécutifs, le cache d'instruction est un cache double port. Notons que ces ''clusters'' ont leur propre file d'instruction, et leur propre file de µops ! Il y a donc deux files de µops en sortie des deux ''clusters'' de décodeurs. L'unité de renommage choisit à chaque cycle quelle file de µops utiliser, suivant leur remplissage ou d'autres informations. Sur Tremont, l'unité de renommage peut renommer 4 µops, même si le processeur peut décoder 6 instructions en parallèle dans le meilleur des cas. Mais ce n'est pas un problème énorme, car le processeur n'atteint pas toujours les 6 µops par cycle. Il oscille entre 3 et 6 µops par cycle, parfois moins si les conditions ne sont pas réunies. Les files de µops découplent décodeurs et unités de renommages, histoire de fluidifier le trafic. [[File:Front-end découplé de la microarchitecture Tremont.png|centre|vignette|upright=3|Front-end découplé de la microarchitecture Tremont.]] La microarchitecture '''Gracemont''' peut décoder deux paquets de 3 instructions chaque. Elle envoie ensuite 5 µops à l'unité d'émission, qui sont distribuées dans deux pipelines : un pipeline flottant/SIMD et un pipeline entier. Et le pipeline entier peut émettre 4 µops entières, deux lectures, deux écritures et deux branchements ! Pire que ça, le ''barrel shifter'' et le multiplieur/diviseur sont dupliqués en deux exemplaires ! [[File:Gracemont.png|centre|vignette|upright=3|Gracemont]] <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Les microarchitectures pour le x86 : haute performance | prevText=Les microarchitectures pour le x86 : haute performance | next=Les processeurs VLIW et EPIC | nextText=Les processeurs VLIW et EPIC }} </noinclude> shbk8ycame0tq2ty7d2xs2vr4dr4uog Mathc complexes/09y 0 84536 773702 773557 2026-09-30T11:06:26Z Xhungab 23827 773702 wikitext text/x-wiki [[Catégorie:Mathc complexes (livre)]] [[Mathc complexes/a277#Le fichier principal :| Application]] Installer et compiler ce fichier dans votre répertoire de travail. {{Fichier|c04b.c|largeur=70%|info=|icon=Crystal128-source-c.svg}} <syntaxhighlight lang="c"> /* ------------------------------------ */ /* Save as : c04b.c */ /* ------------------------------------ */ #include "w_a.h" /* ------------------------------------ */ #include "f.h" /* ------------------------------------ */ int main(void) { double dft4[R4*(C4*C2)] = { 1,0, 1,0, 1,0, 1,0, 1,0, f(1,4).r,f(1,4).i, f(2,4).r,f(2,4).i, f(3,4).r,f(3,4).i, 1,0, f(2,4).r,f(2,4).i, f(4,4).r,f(4,4).i, f(6,4).r,f(6,4).i, 1,0, f(3,4).r,f(3,4).i, f(6,4).r,f(6,4).i, f(9,4).r,f(9,4).i }; double Ts[R4*(C1*C2)] = { +2,0, +4,0, -1,0, +3,0 }; double **DFT4 = ca_A_mZ(dft4, i_mZ(R4,C4)); double **cDFT4 = conj_mZ(DFT4, i_mZ(R4,C4)); double **cDFT4div4 = smul_mZ(1/4.,cDFT4, i_mZ(R4,C4)); double **s = ca_A_mZ(Ts, i_mZ(R4,C1)); double **S = i_mZ(R4,C1) ; clrscrn(); printf(" DFT4 : "); p_mZ(DFT4,S4,P3,S3,P3,C6); printf(" s : "); p_mZ(s,S4,P3,S3,P3,C6); mul_mZ(DFT4,s,S); printf(" S = DFT4 * s : "); p_mZ(S,S4,P3,S3,P3,C6); stop(); clrscrn(); printf(" s : "); p_mZ(m0_mZ(s),S4,P0,S3,P0,C6); printf(" 1/4 cDFT4 : "); p_mZ(cDFT4div4,S4,P3,S3,P3,C6); mul_mZ(cDFT4div4,S,s); printf(" s = 1/4 cDFT4 * S : "); p_mZ(s,S4,P3,S3,P3,C6); stop(); f_mZ(DFT4); f_mZ(cDFT4); f_mZ(cDFT4div4); f_mZ(s); f_mZ(S); return 0; } /* ------------------------------------ */ /* ------------------------------------ */ </syntaxhighlight> '''Exemple de sortie écran :''' <syntaxhighlight lang="C"> DFT4 : +1.000+0.000i +1.000+0.000i +1.000+0.000i +1.000+0.000i +1.000+0.000i -0.000-1.000i -1.000+0.000i +0.000+1.000i +1.000+0.000i -1.000+0.000i +1.000-0.000i -1.000+0.000i +1.000+0.000i +0.000+1.000i -1.000+0.000i -0.000-1.000i s : +2.000+0.000i +4.000+0.000i -1.000+0.000i +3.000+0.000i S = DFT4 * s : +8.000+0.000i +3.000-1.000i -6.000+0.000i +3.000+1.000i Press return to continue. </syntaxhighlight> {{AutoCat}} ac6enhb1rjgtm37lgvvt3fkpcf9xt8p Mathc complexes/09z 0 84537 773705 773566 2026-09-30T11:14:01Z Xhungab 23827 773705 wikitext text/x-wiki [[Catégorie:Mathc complexes (livre)]] [[Mathc complexes/a277#Le fichier principal :| Application]] Installer et compiler ce fichier dans votre répertoire de travail. {{Fichier|c0nb.c|largeur=70%|info=|icon=Crystal128-source-c.svg}} <syntaxhighlight lang="c"> /* ------------------------------------ */ /* Save as : c0nb.c */ /* ------------------------------------ */ #define CR 4. /* ------------------------------------ */ #include "w_a.h" /* ------------------------------------ */ #include "f.h" #include "dft.h" /* ------------------------------------ */ int main(void) { time_t t; srand(time(&t)); double Ts[R4*(C1*C2)] = { +2,0, +4,0, -1,0, +3,0 }; double **DFT = dft_mZ( i_mZ(CR,CR),CR); double **cDFT = conj_mZ(DFT, i_mZ(CR,CR) ); double **cDFTdivN = smul_mZ(1./CR,cDFT, i_mZ(CR,CR) ); double **s = ca_A_mZ(Ts, i_mZ(CR,C1) ); double **S = i_mZ(CR,C1) ; clrscrn(); printf(" DFT :"); p_mZ(DFT, S8,P3, S8,P3, C4); printf(" s :"); p_mZ(s,S8,P3,S8,P3,C4); mul_mZ(DFT,s,S); printf(" S = DFT * s"); p_mZ(S,S8,P3,S8,P3,C4); stop(); clrscrn(); printf(" 1/%.0f cDFT :",CR); p_mZ(cDFTdivN,S8,P3,S8,P3,C4); mul_mZ(cDFTdivN,S,s); printf(" s = 1/%.0f cDFT * S :",CR); p_mZ(s, S8,P3, S8,P3, C4); stop(); f_mZ(DFT); f_mZ(cDFT); f_mZ(cDFTdivN); f_mZ(s); f_mZ(S); return 0; } /* ------------------------------------ */ /* ------------------------------------ */ </syntaxhighlight> '''Exemple de sortie écran : ''' <syntaxhighlight lang="C"> DFT : +1.000 +0.000i +1.000 +0.000i +1.000 +0.000i +1.000 +0.000i +1.000 +0.000i -0.000 -1.000i -1.000 +0.000i +0.000 +1.000i +1.000 +0.000i -1.000 +0.000i +1.000 -0.000i -1.000 +0.000i +1.000 +0.000i +0.000 +1.000i -1.000 +0.000i -0.000 -1.000i s : +2.000 +0.000i +4.000 +0.000i -1.000 +0.000i +3.000 +0.000i S = DFT * s +8.000 +0.000i +3.000 -1.000i -6.000 +0.000i +3.000 +1.000i Press return to continue. </syntaxhighlight> {{AutoCat}} 5vp65dwgkqm6idxiwr4udxs0vyl76xw 773710 773705 2026-09-30T11:52:23Z Xhungab 23827 773710 wikitext text/x-wiki [[Catégorie:Mathc complexes (livre)]] [[Mathc complexes/a277#Le fichier principal :| Application]] Installer et compiler ce fichier dans votre répertoire de travail. {{Fichier|c0nb.c|largeur=70%|info=|icon=Crystal128-source-c.svg}} <syntaxhighlight lang="c"> /* ------------------------------------ */ /* Save as : c0nb.c */ /* ------------------------------------ */ #define RC 4. #define TsCR RC4 /* ------------------------------------ */ #include "w_a.h" /* ------------------------------------ */ #include "f.h" #include "dft.h" /* ------------------------------------ */ int main(void) { time_t t; srand(time(&t)); double Ts[TsCR*(C1*C2)] = { +2,0, +4,0, -1,0, +3,0 }; double **DFT = dft_mZ( i_mZ(RC,RC),RC); double **cDFT = conj_mZ(DFT, i_mZ(RC,RC) ); double **cDFTdivN = smul_mZ(1./RC,cDFT, i_mZ(RC,RC) ); double **s = ca_A_mZ(Ts, i_mZ(RC,C1) ); double **S = i_mZ(RC,C1) ; clrscrn(); printf(" DFT :"); p_mZ(DFT, S8,P3, S8,P3, C4); printf(" s :"); p_mZ(s,S8,P3,S8,P3,C4); mul_mZ(DFT,s,S); printf(" S = DFT * s"); p_mZ(S,S8,P3,S8,P3,C4); stop(); clrscrn(); printf(" 1/%.0f cDFT :",RC); p_mZ(cDFTdivN,S8,P3,S8,P3,C4); mul_mZ(cDFTdivN,S,s); printf(" s = 1/%.0f cDFT * S :",RC); p_mZ(s, S8,P3, S8,P3, C4); stop(); f_mZ(DFT); f_mZ(cDFT); f_mZ(cDFTdivN); f_mZ(s); f_mZ(S); return 0; } /* ------------------------------------ */ /* ------------------------------------ */ </syntaxhighlight> '''Exemple de sortie écran : ''' <syntaxhighlight lang="C"> DFT : +1.000 +0.000i +1.000 +0.000i +1.000 +0.000i +1.000 +0.000i +1.000 +0.000i -0.000 -1.000i -1.000 +0.000i +0.000 +1.000i +1.000 +0.000i -1.000 +0.000i +1.000 -0.000i -1.000 +0.000i +1.000 +0.000i +0.000 +1.000i -1.000 +0.000i -0.000 -1.000i s : +2.000 +0.000i +4.000 +0.000i -1.000 +0.000i +3.000 +0.000i S = DFT * s +8.000 +0.000i +3.000 -1.000i -6.000 +0.000i +3.000 +1.000i Press return to continue. </syntaxhighlight> {{AutoCat}} e9n7iilz4h768xcifr8elt5z3gvs8x5 773711 773710 2026-09-30T11:53:34Z Xhungab 23827 773711 wikitext text/x-wiki [[Catégorie:Mathc complexes (livre)]] [[Mathc complexes/a277#Le fichier principal :| Application]] Installer et compiler ce fichier dans votre répertoire de travail. {{Fichier|c0nb.c|largeur=70%|info=|icon=Crystal128-source-c.svg}} <syntaxhighlight lang="c"> /* ------------------------------------ */ /* Save as : c0nb.c */ /* ------------------------------------ */ #define RC 4. #define TsRC RC4 /* ------------------------------------ */ #include "w_a.h" /* ------------------------------------ */ #include "f.h" #include "dft.h" /* ------------------------------------ */ int main(void) { time_t t; srand(time(&t)); double Ts[TsRC*(C1*C2)] = { +2,0, +4,0, -1,0, +3,0 }; double **DFT = dft_mZ( i_mZ(RC,RC),RC); double **cDFT = conj_mZ(DFT, i_mZ(RC,RC) ); double **cDFTdivN = smul_mZ(1./RC,cDFT, i_mZ(RC,RC) ); double **s = ca_A_mZ(Ts, i_mZ(RC,C1) ); double **S = i_mZ(RC,C1) ; clrscrn(); printf(" DFT :"); p_mZ(DFT, S8,P3, S8,P3, C4); printf(" s :"); p_mZ(s,S8,P3,S8,P3,C4); mul_mZ(DFT,s,S); printf(" S = DFT * s"); p_mZ(S,S8,P3,S8,P3,C4); stop(); clrscrn(); printf(" 1/%.0f cDFT :",RC); p_mZ(cDFTdivN,S8,P3,S8,P3,C4); mul_mZ(cDFTdivN,S,s); printf(" s = 1/%.0f cDFT * S :",RC); p_mZ(s, S8,P3, S8,P3, C4); stop(); f_mZ(DFT); f_mZ(cDFT); f_mZ(cDFTdivN); f_mZ(s); f_mZ(S); return 0; } /* ------------------------------------ */ /* ------------------------------------ */ </syntaxhighlight> '''Exemple de sortie écran : ''' <syntaxhighlight lang="C"> DFT : +1.000 +0.000i +1.000 +0.000i +1.000 +0.000i +1.000 +0.000i +1.000 +0.000i -0.000 -1.000i -1.000 +0.000i +0.000 +1.000i +1.000 +0.000i -1.000 +0.000i +1.000 -0.000i -1.000 +0.000i +1.000 +0.000i +0.000 +1.000i -1.000 +0.000i -0.000 -1.000i s : +2.000 +0.000i +4.000 +0.000i -1.000 +0.000i +3.000 +0.000i S = DFT * s +8.000 +0.000i +3.000 -1.000i -6.000 +0.000i +3.000 +1.000i Press return to continue. </syntaxhighlight> {{AutoCat}} i0fjhcelbwlkfogr7otkucifm4bvikz Fonctionnement d'un ordinateur/Les schedulers larges et leurs optimisations 0 84538 773614 2026-09-29T20:46:53Z Mewtow 31375 Page créée avec « Nous venons de parler de l'exécution dans le désordre pendant deux chapitres. Les chapitres précédents vous ont laissé penser qu'un processeur avec exécution dans le désordre était assez simple : on remplace le file de µops par un fenêtre d’instruction, on ajoute éventuellement un unité de renommage de registres, et voilà ! Et en effet, l'implémentation la plus simple de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralis... » 773614 wikitext text/x-wiki Nous venons de parler de l'exécution dans le désordre pendant deux chapitres. Les chapitres précédents vous ont laissé penser qu'un processeur avec exécution dans le désordre était assez simple : on remplace le file de µops par un fenêtre d’instruction, on ajoute éventuellement un unité de renommage de registres, et voilà ! Et en effet, l'implémentation la plus simple de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Mais dans la réalité, les processeurs modernes n'utilisent pas un ''scheduler'' unique. Les processeurs modernes ont besoin de ''scheduler'' très grands, avec un grand nombre d'entrées. Or, nous avons vu qu'un ''scheduler'' est un sorte de mémoire associative très complexe, avec un grand nombre de comparateurs. Et cela pose problème quand le ''scheduler'' doit mémoriser un grand nombre de µops. Le cout en transistors d'un ''scheduler'' n'est pas proportionnel au nombre de µops qu'elle peut mémoriser. Par exemple, si je compare un ''scheduler'' de 32 entrées (32 µops max), elle n'utilise pas deux fois plus transistors qu'un fenêtre de 16 entrées. Le cout en circuit n'est pas deux fois plus élevé, mais est approximativement 4 fois plus élevé. Le cout est presque quadratique, à savoir qu'il est proportionnel au carré du nombre d'entrées. Et il en est de même avec le performance. Dès qu'on dépasse la centaine de µops, un ''scheduler'' centralisé n'est pas très pratique. Il consomme beaucoup de transistors, chauffe beaucoup, n'est pas très rapide. La solution est alors de scinder un gros ''scheduler'' en plusieurs ''schedulers'' plus petits. Reste à voir comment faire. Dans les grandes lignes, il existe dans les grandes lignes 4 grandes techniques d'exécution dans le désordre. Elles peuvent se clesser sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! ''scheduler'' |- ! un seule | ''Scoreboard'' | ''scheduler'' centralisée |- ! Plusieurs | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | ''scheduler'' décentralisé |} ==Les ''schedulers'' décentralisés== Il est possible de scinder le ''scheduler'' en un ''scheduler'' pour les µops mémoire (simplifiée en un file de µops clessique), et un autre pour les autres µops. Sachez qu'il est possible d'aller plus loin, par exemple en séparant le ''scheduler'' en un fenêtre spécialisée dans les µops flottantes et un autre pour les µops entières. Et ce n'est là qu'un exemple parmi de nombreuses autres possibilités. Pour faire le différence avec un ''scheduler'' unique, nous allons parler de ''scheduler'' centralisée s'il n'y en a qu'un, de '''''scheduler'' décentralisée''' s'il y en a plusieurs. Il est possible d'associer chaque ''scheduler'' à un type précis de µops. Par exemple, avec un ''scheduler'' pour les µops de calcul entières, un autre pour les µops flottantes, un autre pour les µops mémoire. Il s'agit d'un choix simple et efficace, mais quelques processeurs font autrement, pour répondre à des contraintes très diverses. [[File:Processeur avec des fenêtres d'instruction décentralisées.png|centre|vignette|upright=2|Processeur avec des fenêtres d'instruction décentralisées]] Reste à scinder le ''scheduler'' pour trier les µops suivant leur type. Si le processeur exécute les accès mémoire dans l'ordre, le méthode le plus simple utilise un ''scheduler'' pour les opérations flottantes et un autre pour les autres µops (µops entières et parfois mémoire avec). L'avantage est que cele simplifie grandement le processeur. Les flottants sont gérés à part des entiers. Ils ont leurs propres registres, des FPU séparées des ALU entières, bref : le séparation est complète. Utiliser un ''scheduler'' séparée va dans ce sens. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Il est possible de faire pareil sur les processeurs avec exécution dans le désordre des accès mémoire. Par exemple : les processeurs Intel de microarchitecture Skyleke utilisent un ''scheduler'' pour les opérations entières/flottantes, et un ''scheduler'' séparée pour les µops mémoire. Un avantage est que les deux fenêtres d'instructions sont plus spécialisées, ce qui entraine des économies de circuit. Les opérations entières/flottantes ont besoin de deux registres pour les opérandes et d'un autre résultat, alors que les µops mémoire n'ont besoin que de deux registres maximum. En utilisant un ''scheduler'' unique, chaque entrée doit mémoriser l'opcode et trois registres, dont un est inutilisé pour les µops mémoire et les branchements. En utilisant des fenêtres d’instructions séparées, celle pour les µops entières/flottantes a trois registres par entrée, contre seulement deux registres par entrée pour celle des µops mémoire. Un cas extrême est celui où chaque ALU/FPU a sa propre ''scheduler''. Nous parlerons alors de '''fenêtres d'instruction totalement décentralisées'''. Par exemple, il y a un ''scheduler'' pour l'ALU entière, un autre pour le multiplieur entier, un autre pour le ''barrel shifter'', un autre pour l'unité mémoire, un autre pour l'unitéé de branchements, un autre pour l'additionneur flottant, un dernière pour le multiplier flottant, etc. Un exemple historique est celui de le FPU de l'IBM 360 modèle 90. Elle disposait d'un additionneur flottant, d'un multiplieur flottant, et d'un unité mémoire pour les lectures/écritures flottantes. Les trois unités avaient leur propre ''scheduler''. Les processeurs AMD utilisent beaucoup cette technique, contrairement à Intel qui préfère utiliser des fenêtres centralisées sur les anciens processeurs, deux ou trois fenêtres sur les processeurs récents (2020 et plus). Les processeurs AMD utilisaient précisément un ''scheduler'' par ALU entière, alors que les FPUs partagent un fenêtre d’instructions flottantes unique. Mais nous verrons cele en détail dans le chapitre sur les processeurs superscaleires x86. Un point important est qu'avec des fenêtres d'instruction décentralisées, l'émission est découpée en deux étages. le première étape envoie un µops vers le ''scheduler'' adéquate, le seconde émet le µops depuis le ''scheduler'' quand ses opérandes sont prêts. le première est l'étage de '''''dispatch''''' qui envoie l'instruction dans le fenêtre d’instruction adéquate, selon que c'est un instruction flottante, entière, autre. le seconde est l'étage de '''''scheduling''''', qui gère le disponibilité des opérandes et des unités de calcul. le µop émise est ajoutée au tampon de réordonnancement, s'il existe, lors de l'étape de ''dispatch''. ==L'usage de plusieurs files d'instruction== un dernière méthode d'OOO utilise plusieurs files de micro-opération. L'idée est qu'un fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement un file de micro-opération pour les opérations entières, un autre pour les opérations flottantes, un autre pour les accès mémoire. D'autres processeurs utilisent un file pour les accès mémoire et un autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. le présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que le technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si un dépendance bloque un FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans un autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer le disponibilité des registres. Quand un registre est lu ou écrit par un instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. le logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : un pour les instructions d'accès mémoire et un autre pour les autres instructions. Si jamais un instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de le lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'un est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est le file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. ==Avantages et inconvénients de chaque implémentation== Pour résumer, on a le choix entre un gros ''scheduler'' généraliste et plusieurs ''schedulers'' spécialisées. Le choix entre les deux est un compromis entre économie de circuits et flexibilité. Avec un ''scheduler'' décentralisé, il arrive qu'un ''scheduler'' soit remplie, alors que les autres sont sous-utilisées, voire vides. Pour comprendre pourquoi, comparons un ''scheduler'' unique, avec un fenêtre décentralisée séparant µops entières et flottantes. le fenêtre centralisée dispose de 64 entrées, le décentralisée a 32 entrées pour chaque ''scheduler''. le fenêtre décentralisée peut mémoriser au maximum 32 µops entières et 32 µops flottantes. Par contre, le fenêtre centralisée peut mémoriser 64 µops tout court. Si le programme exécuté n'utilise pas de nombres flottants, le différence devient flegrante. le fenêtre décentralisée sera limitée ) 32 µops, alors que le centralisée pourra mémoriser le double. Les performances seront donc meilleures avec le fenêtre centralisée. Et au-delà de ça, le fenêtre décentralisée de l'exemple est utilisée de manière optimale si le moitié des µops sont des µops entières, et l'autre moitié des µops flottantes. Alors que le fenêtre centralisée se moque de le répartition entre µops entières et flottantes. Les fenêtres décentralisées utilisent plusieurs fenêtres d'instruction de "petite taille", donc plus rapides, économes en circuits et économes en énergie. Le compromis n'est donc pas entre un fenêtre centralisée à 64 entrées versus deux fenêtres de 32 entrées. Le compromis en pratique est entre un fenêtre centralisée de 64 entrées versus 3 fenêtres de 32 entrées. Un exemple pratique est celui de le microarchitecture ''Skyleke'' d'Intel. Intel est passé d'un fenêtre centralisée pre-''Skyleke'' à deux fenêtres décentralisées sur ''Skyleke'',. Le nombre d'entrée était globalement le même entre les deux, même si l'évolution de le finesse de gravure entre les deux biaise un peu les résultats. Un avantage des fenêtres décentralisées est qu'il est possible de démarrer l'exécution de plusieurs µops simultanément : un µops par ''scheduler''. Le fait est que deux fenêtres d'instructions différentes émettent leurs µops sans se synchroniser avec les autres. Deux fenêtres d'instruction peuvent donc émettre chacun un µops, ce qui fait deux µops émises lors du même cycle. Cele permet d'exécuter en même temps deux ou trois instructions 1-cycle, comme des additions, soustractions, décaleges, etc. Il devient par exemple possible d'émettre un µop entière en même temps qu'un µop flottante, si les µops entières ont un fenêtre séparée de celle des µops flottantes. Il est maintenant temps de voir en quoi sont faites les fenêtres d’instruction, qu'elles soient centralisées ou décentralisées. Nous allons aussi voir quelle est le logique d'émission associée. pp5loyrg3q1227kt1xri18tmhyifdvd 773630 773614 2026-09-29T21:08:38Z Mewtow 31375 /* Avantages et inconvénients de chaque implémentation */ 773630 wikitext text/x-wiki Nous venons de parler de l'exécution dans le désordre pendant deux chapitres. Les chapitres précédents vous ont laissé penser qu'un processeur avec exécution dans le désordre était assez simple : on remplace le file de µops par un fenêtre d’instruction, on ajoute éventuellement un unité de renommage de registres, et voilà ! Et en effet, l'implémentation la plus simple de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Mais dans la réalité, les processeurs modernes n'utilisent pas un ''scheduler'' unique. Les processeurs modernes ont besoin de ''scheduler'' très grands, avec un grand nombre d'entrées. Or, nous avons vu qu'un ''scheduler'' est un sorte de mémoire associative très complexe, avec un grand nombre de comparateurs. Et cela pose problème quand le ''scheduler'' doit mémoriser un grand nombre de µops. Le cout en transistors d'un ''scheduler'' n'est pas proportionnel au nombre de µops qu'elle peut mémoriser. Par exemple, si je compare un ''scheduler'' de 32 entrées (32 µops max), elle n'utilise pas deux fois plus transistors qu'un fenêtre de 16 entrées. Le cout en circuit n'est pas deux fois plus élevé, mais est approximativement 4 fois plus élevé. Le cout est presque quadratique, à savoir qu'il est proportionnel au carré du nombre d'entrées. Et il en est de même avec le performance. Dès qu'on dépasse la centaine de µops, un ''scheduler'' centralisé n'est pas très pratique. Il consomme beaucoup de transistors, chauffe beaucoup, n'est pas très rapide. La solution est alors de scinder un gros ''scheduler'' en plusieurs ''schedulers'' plus petits. Reste à voir comment faire. Dans les grandes lignes, il existe dans les grandes lignes 4 grandes techniques d'exécution dans le désordre. Elles peuvent se clesser sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! ''scheduler'' |- ! un seule | ''Scoreboard'' | ''scheduler'' centralisée |- ! Plusieurs | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | ''scheduler'' décentralisé |} ==Les ''schedulers'' décentralisés== Il est possible de scinder le ''scheduler'' en un ''scheduler'' pour les µops mémoire (simplifiée en un file de µops clessique), et un autre pour les autres µops. Sachez qu'il est possible d'aller plus loin, par exemple en séparant le ''scheduler'' en un fenêtre spécialisée dans les µops flottantes et un autre pour les µops entières. Et ce n'est là qu'un exemple parmi de nombreuses autres possibilités. Pour faire le différence avec un ''scheduler'' unique, nous allons parler de ''scheduler'' centralisée s'il n'y en a qu'un, de '''''scheduler'' décentralisée''' s'il y en a plusieurs. Il est possible d'associer chaque ''scheduler'' à un type précis de µops. Par exemple, avec un ''scheduler'' pour les µops de calcul entières, un autre pour les µops flottantes, un autre pour les µops mémoire. Il s'agit d'un choix simple et efficace, mais quelques processeurs font autrement, pour répondre à des contraintes très diverses. [[File:Processeur avec des fenêtres d'instruction décentralisées.png|centre|vignette|upright=2|Processeur avec des fenêtres d'instruction décentralisées]] Reste à scinder le ''scheduler'' pour trier les µops suivant leur type. Si le processeur exécute les accès mémoire dans l'ordre, le méthode le plus simple utilise un ''scheduler'' pour les opérations flottantes et un autre pour les autres µops (µops entières et parfois mémoire avec). L'avantage est que cele simplifie grandement le processeur. Les flottants sont gérés à part des entiers. Ils ont leurs propres registres, des FPU séparées des ALU entières, bref : le séparation est complète. Utiliser un ''scheduler'' séparée va dans ce sens. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Il est possible de faire pareil sur les processeurs avec exécution dans le désordre des accès mémoire. Par exemple : les processeurs Intel de microarchitecture Skyleke utilisent un ''scheduler'' pour les opérations entières/flottantes, et un ''scheduler'' séparée pour les µops mémoire. Un avantage est que les deux fenêtres d'instructions sont plus spécialisées, ce qui entraine des économies de circuit. Les opérations entières/flottantes ont besoin de deux registres pour les opérandes et d'un autre résultat, alors que les µops mémoire n'ont besoin que de deux registres maximum. En utilisant un ''scheduler'' unique, chaque entrée doit mémoriser l'opcode et trois registres, dont un est inutilisé pour les µops mémoire et les branchements. En utilisant des fenêtres d’instructions séparées, celle pour les µops entières/flottantes a trois registres par entrée, contre seulement deux registres par entrée pour celle des µops mémoire. Un cas extrême est celui où chaque ALU/FPU a sa propre ''scheduler''. Nous parlerons alors de '''fenêtres d'instruction totalement décentralisées'''. Par exemple, il y a un ''scheduler'' pour l'ALU entière, un autre pour le multiplieur entier, un autre pour le ''barrel shifter'', un autre pour l'unité mémoire, un autre pour l'unitéé de branchements, un autre pour l'additionneur flottant, un dernière pour le multiplier flottant, etc. Un exemple historique est celui de le FPU de l'IBM 360 modèle 90. Elle disposait d'un additionneur flottant, d'un multiplieur flottant, et d'un unité mémoire pour les lectures/écritures flottantes. Les trois unités avaient leur propre ''scheduler''. Les processeurs AMD utilisent beaucoup cette technique, contrairement à Intel qui préfère utiliser des fenêtres centralisées sur les anciens processeurs, deux ou trois fenêtres sur les processeurs récents (2020 et plus). Les processeurs AMD utilisaient précisément un ''scheduler'' par ALU entière, alors que les FPUs partagent un fenêtre d’instructions flottantes unique. Mais nous verrons cele en détail dans le chapitre sur les processeurs superscaleires x86. Un point important est qu'avec des fenêtres d'instruction décentralisées, l'émission est découpée en deux étages. le première étape envoie un µops vers le ''scheduler'' adéquate, le seconde émet le µops depuis le ''scheduler'' quand ses opérandes sont prêts. le première est l'étage de '''''dispatch''''' qui envoie l'instruction dans le fenêtre d’instruction adéquate, selon que c'est un instruction flottante, entière, autre. le seconde est l'étage de '''''scheduling''''', qui gère le disponibilité des opérandes et des unités de calcul. le µop émise est ajoutée au tampon de réordonnancement, s'il existe, lors de l'étape de ''dispatch''. ==L'usage de plusieurs files d'instruction== un dernière méthode d'OOO utilise plusieurs files de micro-opération. L'idée est qu'un fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement un file de micro-opération pour les opérations entières, un autre pour les opérations flottantes, un autre pour les accès mémoire. D'autres processeurs utilisent un file pour les accès mémoire et un autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. le présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que le technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si un dépendance bloque un FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans un autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer le disponibilité des registres. Quand un registre est lu ou écrit par un instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. le logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : un pour les instructions d'accès mémoire et un autre pour les autres instructions. Si jamais un instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de le lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'un est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est le file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. ==Avantages et inconvénients de chaque implémentation== Pour résumer, on a le choix entre un gros ''scheduler'' généraliste et plusieurs ''schedulers'' spécialisées. Le choix entre les deux est un compromis entre économie de circuits et flexibilité. Avec un ''scheduler'' décentralisé, il arrive qu'un ''scheduler'' soit remplie, alors que les autres sont sous-utilisées, voire vides. Pour comprendre pourquoi, comparons un ''scheduler'' unique, avec un fenêtre décentralisée séparant µops entières et flottantes. le fenêtre centralisée dispose de 64 entrées, le décentralisée a 32 entrées pour chaque ''scheduler''. le fenêtre décentralisée peut mémoriser au maximum 32 µops entières et 32 µops flottantes. Par contre, le fenêtre centralisée peut mémoriser 64 µops tout court. Si le programme exécuté n'utilise pas de nombres flottants, le différence devient flegrante. le fenêtre décentralisée sera limitée ) 32 µops, alors que le centralisée pourra mémoriser le double. Les performances seront donc meilleures avec le fenêtre centralisée. Et au-delà de ça, le fenêtre décentralisée de l'exemple est utilisée de manière optimale si le moitié des µops sont des µops entières, et l'autre moitié des µops flottantes. Alors que le fenêtre centralisée se moque de le répartition entre µops entières et flottantes. Les fenêtres décentralisées utilisent plusieurs fenêtres d'instruction de "petite taille", donc plus rapides, économes en circuits et économes en énergie. Le compromis n'est donc pas entre un fenêtre centralisée à 64 entrées versus deux fenêtres de 32 entrées. Le compromis en pratique est entre un fenêtre centralisée de 64 entrées versus 3 fenêtres de 32 entrées. Un exemple pratique est celui de le microarchitecture ''Skyleke'' d'Intel. Intel est passé d'un fenêtre centralisée pre-''Skyleke'' à deux fenêtres décentralisées sur ''Skyleke'',. Le nombre d'entrée était globalement le même entre les deux, même si l'évolution de le finesse de gravure entre les deux biaise un peu les résultats. Un avantage des fenêtres décentralisées est qu'il est possible de démarrer l'exécution de plusieurs µops simultanément : un µops par ''scheduler''. Le fait est que deux fenêtres d'instructions différentes émettent leurs µops sans se synchroniser avec les autres. Deux fenêtres d'instruction peuvent donc émettre chacun un µops, ce qui fait deux µops émises lors du même cycle. Cele permet d'exécuter en même temps deux ou trois instructions 1-cycle, comme des additions, soustractions, décaleges, etc. Il devient par exemple possible d'émettre un µop entière en même temps qu'un µop flottante, si les µops entières ont un fenêtre séparée de celle des µops flottantes. Il est maintenant temps de voir en quoi sont faites les fenêtres d’instruction, qu'elles soient centralisées ou décentralisées. Nous allons aussi voir quelle est le logique d'émission associée. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Le scoreboarding et l'algorithme de Tomasulo | prevText=Le scoreboarding et l'algorithme de Tomasulo | next=La désambiguïsation mémoire | nextText=La désambiguïsation mémoire }} </noinclude> qu15ab92uy8equgqs762h2fcpqa1p0g 773640 773630 2026-09-29T21:25:40Z Mewtow 31375 773640 wikitext text/x-wiki Nous venons de parler de l'exécution dans le désordre pendant deux chapitres. Les chapitres précédents vous ont laissé penser qu'un processeur avec exécution dans le désordre était assez simple : on remplace le file de µops par un fenêtre d’instruction, on ajoute éventuellement un unité de renommage de registres, et voilà ! Et en effet, l'implémentation la plus simple de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Mais dans la réalité, les processeurs modernes n'utilisent pas un ''scheduler'' unique. Les processeurs modernes ont besoin de ''scheduler'' très grands, avec un grand nombre d'entrées. Or, nous avons vu qu'un ''scheduler'' est un sorte de mémoire associative très complexe, avec un grand nombre de comparateurs. Et cela pose problème quand le ''scheduler'' doit mémoriser un grand nombre de µops. Le cout en transistors d'un ''scheduler'' n'est pas proportionnel au nombre de µops qu'elle peut mémoriser. Par exemple, si je compare un ''scheduler'' de 32 entrées (32 µops max), elle n'utilise pas deux fois plus transistors qu'un fenêtre de 16 entrées. Le cout en circuit n'est pas deux fois plus élevé, mais est approximativement 4 fois plus élevé. Le cout est presque quadratique, à savoir qu'il est proportionnel au carré du nombre d'entrées. Et il en est de même avec le performance. Dès qu'on dépasse la centaine de µops, un ''scheduler'' centralisé n'est pas très pratique. Il consomme beaucoup de transistors, chauffe beaucoup, n'est pas très rapide. La solution est alors de scinder un gros ''scheduler'' en plusieurs ''schedulers'' plus petits. Reste à voir comment faire. ==Les ''schedulers'' décentralisés== Il est possible de scinder le ''scheduler'' en un ''scheduler'' pour les µops mémoire (simplifiée en un file de µops clessique), et un autre pour les autres µops. Sachez qu'il est possible d'aller plus loin, par exemple en séparant le ''scheduler'' en un fenêtre spécialisée dans les µops flottantes et un autre pour les µops entières. Et ce n'est là qu'un exemple parmi de nombreuses autres possibilités. Pour faire le différence avec un ''scheduler'' unique, nous allons parler de ''scheduler'' centralisée s'il n'y en a qu'un, de '''''scheduler'' décentralisée''' s'il y en a plusieurs. Il est possible d'associer chaque ''scheduler'' à un type précis de µops. Par exemple, avec un ''scheduler'' pour les µops de calcul entières, un autre pour les µops flottantes, un autre pour les µops mémoire. Il s'agit d'un choix simple et efficace, mais quelques processeurs font autrement, pour répondre à des contraintes très diverses. [[File:Processeur avec des fenêtres d'instruction décentralisées.png|centre|vignette|upright=2|Processeur avec des fenêtres d'instruction décentralisées]] Reste à scinder le ''scheduler'' pour trier les µops suivant leur type. Si le processeur exécute les accès mémoire dans l'ordre, le méthode le plus simple utilise un ''scheduler'' pour les opérations flottantes et un autre pour les autres µops (µops entières et parfois mémoire avec). L'avantage est que cele simplifie grandement le processeur. Les flottants sont gérés à part des entiers. Ils ont leurs propres registres, des FPU séparées des ALU entières, bref : le séparation est complète. Utiliser un ''scheduler'' séparée va dans ce sens. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Il est possible de faire pareil sur les processeurs avec exécution dans le désordre des accès mémoire. Par exemple : les processeurs Intel de microarchitecture Skyleke utilisent un ''scheduler'' pour les opérations entières/flottantes, et un ''scheduler'' séparée pour les µops mémoire. Un avantage est que les deux fenêtres d'instructions sont plus spécialisées, ce qui entraine des économies de circuit. Les opérations entières/flottantes ont besoin de deux registres pour les opérandes et d'un autre résultat, alors que les µops mémoire n'ont besoin que de deux registres maximum. En utilisant un ''scheduler'' unique, chaque entrée doit mémoriser l'opcode et trois registres, dont un est inutilisé pour les µops mémoire et les branchements. En utilisant des fenêtres d’instructions séparées, celle pour les µops entières/flottantes a trois registres par entrée, contre seulement deux registres par entrée pour celle des µops mémoire. Un cas extrême est celui où chaque ALU/FPU a sa propre ''scheduler''. Nous parlerons alors de '''fenêtres d'instruction totalement décentralisées'''. Par exemple, il y a un ''scheduler'' pour l'ALU entière, un autre pour le multiplieur entier, un autre pour le ''barrel shifter'', un autre pour l'unité mémoire, un autre pour l'unitéé de branchements, un autre pour l'additionneur flottant, un dernière pour le multiplier flottant, etc. Un exemple historique est celui de le FPU de l'IBM 360 modèle 90. Elle disposait d'un additionneur flottant, d'un multiplieur flottant, et d'un unité mémoire pour les lectures/écritures flottantes. Les trois unités avaient leur propre ''scheduler''. Les processeurs AMD utilisent beaucoup cette technique, contrairement à Intel qui préfère utiliser des fenêtres centralisées sur les anciens processeurs, deux ou trois fenêtres sur les processeurs récents (2020 et plus). Les processeurs AMD utilisaient précisément un ''scheduler'' par ALU entière, alors que les FPUs partagent un fenêtre d’instructions flottantes unique. Mais nous verrons cele en détail dans le chapitre sur les processeurs superscaleires x86. Un point important est qu'avec des fenêtres d'instruction décentralisées, l'émission est découpée en deux étages. le première étape envoie un µops vers le ''scheduler'' adéquate, le seconde émet le µops depuis le ''scheduler'' quand ses opérandes sont prêts. le première est l'étage de '''''dispatch''''' qui envoie l'instruction dans le fenêtre d’instruction adéquate, selon que c'est un instruction flottante, entière, autre. le seconde est l'étage de '''''scheduling''''', qui gère le disponibilité des opérandes et des unités de calcul. le µop émise est ajoutée au tampon de réordonnancement, s'il existe, lors de l'étape de ''dispatch''. ==L'usage de plusieurs files d'instruction== un dernière méthode d'OOO utilise plusieurs files de micro-opération. L'idée est qu'un fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement un file de micro-opération pour les opérations entières, un autre pour les opérations flottantes, un autre pour les accès mémoire. D'autres processeurs utilisent un file pour les accès mémoire et un autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. le présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que le technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si un dépendance bloque un FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans un autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer le disponibilité des registres. Quand un registre est lu ou écrit par un instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. le logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : un pour les instructions d'accès mémoire et un autre pour les autres instructions. Si jamais un instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de le lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'un est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est le file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. ==Avantages et inconvénients de chaque implémentation== Pour résumer, on a le choix entre un gros ''scheduler'' généraliste et plusieurs ''schedulers'' spécialisées. Le choix entre les deux est un compromis entre économie de circuits et flexibilité. Avec un ''scheduler'' décentralisé, il arrive qu'un ''scheduler'' soit remplie, alors que les autres sont sous-utilisées, voire vides. Pour comprendre pourquoi, comparons un ''scheduler'' unique, avec un fenêtre décentralisée séparant µops entières et flottantes. le fenêtre centralisée dispose de 64 entrées, le décentralisée a 32 entrées pour chaque ''scheduler''. le fenêtre décentralisée peut mémoriser au maximum 32 µops entières et 32 µops flottantes. Par contre, le fenêtre centralisée peut mémoriser 64 µops tout court. Si le programme exécuté n'utilise pas de nombres flottants, le différence devient flegrante. le fenêtre décentralisée sera limitée ) 32 µops, alors que le centralisée pourra mémoriser le double. Les performances seront donc meilleures avec le fenêtre centralisée. Et au-delà de ça, le fenêtre décentralisée de l'exemple est utilisée de manière optimale si le moitié des µops sont des µops entières, et l'autre moitié des µops flottantes. Alors que le fenêtre centralisée se moque de le répartition entre µops entières et flottantes. Les fenêtres décentralisées utilisent plusieurs fenêtres d'instruction de "petite taille", donc plus rapides, économes en circuits et économes en énergie. Le compromis n'est donc pas entre un fenêtre centralisée à 64 entrées versus deux fenêtres de 32 entrées. Le compromis en pratique est entre un fenêtre centralisée de 64 entrées versus 3 fenêtres de 32 entrées. Un exemple pratique est celui de le microarchitecture ''Skyleke'' d'Intel. Intel est passé d'un fenêtre centralisée pre-''Skyleke'' à deux fenêtres décentralisées sur ''Skyleke'',. Le nombre d'entrée était globalement le même entre les deux, même si l'évolution de le finesse de gravure entre les deux biaise un peu les résultats. Un avantage des fenêtres décentralisées est qu'il est possible de démarrer l'exécution de plusieurs µops simultanément : un µops par ''scheduler''. Le fait est que deux fenêtres d'instructions différentes émettent leurs µops sans se synchroniser avec les autres. Deux fenêtres d'instruction peuvent donc émettre chacun un µops, ce qui fait deux µops émises lors du même cycle. Cele permet d'exécuter en même temps deux ou trois instructions 1-cycle, comme des additions, soustractions, décaleges, etc. Il devient par exemple possible d'émettre un µop entière en même temps qu'un µop flottante, si les µops entières ont un fenêtre séparée de celle des µops flottantes. Dans les grandes lignes, il existe dans les grandes lignes 4 grandes techniques d'exécution dans le désordre. Elles peuvent se clesser sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! ''scheduler'' |- ! un seule | ''Scoreboard'' | ''scheduler'' centralisée |- ! Plusieurs | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | ''scheduler'' décentralisé |} <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Le scoreboarding et l'algorithme de Tomasulo | prevText=Le scoreboarding et l'algorithme de Tomasulo | next=La désambiguïsation mémoire | nextText=La désambiguïsation mémoire }} </noinclude> 7k99nr59dg7b4unamsgp07vl2axev6a 773641 773640 2026-09-29T21:27:33Z Mewtow 31375 773641 wikitext text/x-wiki Nous venons de parler de l'exécution dans le désordre pendant deux chapitres. Les chapitres précédents vous ont laissé penser qu'un processeur avec exécution dans le désordre était assez simple : on remplace le file de µops par un fenêtre d’instruction, on ajoute éventuellement un unité de renommage de registres, et voilà ! Et en effet, l'implémentation la plus simple de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Mais dans la réalité, les processeurs modernes n'utilisent pas un ''scheduler'' unique. Les processeurs modernes ont besoin de ''scheduler'' très grands, avec un grand nombre d'entrées. Or, nous avons vu qu'un ''scheduler'' est un sorte de mémoire associative très complexe, avec un grand nombre de comparateurs. Et cela pose problème quand le ''scheduler'' doit mémoriser un grand nombre de µops. Le cout en transistors d'un ''scheduler'' n'est pas proportionnel au nombre de µops qu'elle peut mémoriser. Par exemple, si je compare un ''scheduler'' de 32 entrées (32 µops max), elle n'utilise pas deux fois plus transistors qu'un fenêtre de 16 entrées. Le cout en circuit n'est pas deux fois plus élevé, mais est approximativement 4 fois plus élevé. Le cout est presque quadratique, à savoir qu'il est proportionnel au carré du nombre d'entrées. Et il en est de même avec le performance. Dès qu'on dépasse la centaine de µops, un ''scheduler'' centralisé n'est pas très pratique. Il consomme beaucoup de transistors, chauffe beaucoup, n'est pas très rapide. ==Les ''schedulers'' décentralisés== La solution est de scinder un gros ''scheduler'' en plusieurs ''schedulers'' plus petits. La scission doit se faire en tenant compte du reste du processeur. En effet, il faut relier les ''schedulers'' aux unités de calcul, ainsi qu'à l'unité mémoire, et cela ne peut pas se faire n'importe comment. Reste à voir comment faire. Il est possible de scinder le ''scheduler'' en un ''scheduler'' pour les µops mémoire (simplifiée en un file de µops clessique), et un autre pour les autres µops. Sachez qu'il est possible d'aller plus loin, par exemple en séparant le ''scheduler'' en un fenêtre spécialisée dans les µops flottantes et un autre pour les µops entières. Et ce n'est là qu'un exemple parmi de nombreuses autres possibilités. Pour faire le différence avec un ''scheduler'' unique, nous allons parler de ''scheduler'' centralisée s'il n'y en a qu'un, de '''''scheduler'' décentralisée''' s'il y en a plusieurs. Il est possible d'associer chaque ''scheduler'' à un type précis de µops. Par exemple, avec un ''scheduler'' pour les µops de calcul entières, un autre pour les µops flottantes, un autre pour les µops mémoire. Il s'agit d'un choix simple et efficace, mais quelques processeurs font autrement, pour répondre à des contraintes très diverses. [[File:Processeur avec des fenêtres d'instruction décentralisées.png|centre|vignette|upright=2|Processeur avec des fenêtres d'instruction décentralisées]] Reste à scinder le ''scheduler'' pour trier les µops suivant leur type. Si le processeur exécute les accès mémoire dans l'ordre, le méthode le plus simple utilise un ''scheduler'' pour les opérations flottantes et un autre pour les autres µops (µops entières et parfois mémoire avec). L'avantage est que cele simplifie grandement le processeur. Les flottants sont gérés à part des entiers. Ils ont leurs propres registres, des FPU séparées des ALU entières, bref : le séparation est complète. Utiliser un ''scheduler'' séparée va dans ce sens. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Il est possible de faire pareil sur les processeurs avec exécution dans le désordre des accès mémoire. Par exemple : les processeurs Intel de microarchitecture Skyleke utilisent un ''scheduler'' pour les opérations entières/flottantes, et un ''scheduler'' séparée pour les µops mémoire. Un avantage est que les deux fenêtres d'instructions sont plus spécialisées, ce qui entraine des économies de circuit. Les opérations entières/flottantes ont besoin de deux registres pour les opérandes et d'un autre résultat, alors que les µops mémoire n'ont besoin que de deux registres maximum. En utilisant un ''scheduler'' unique, chaque entrée doit mémoriser l'opcode et trois registres, dont un est inutilisé pour les µops mémoire et les branchements. En utilisant des fenêtres d’instructions séparées, celle pour les µops entières/flottantes a trois registres par entrée, contre seulement deux registres par entrée pour celle des µops mémoire. Un cas extrême est celui où chaque ALU/FPU a sa propre ''scheduler''. Nous parlerons alors de '''fenêtres d'instruction totalement décentralisées'''. Par exemple, il y a un ''scheduler'' pour l'ALU entière, un autre pour le multiplieur entier, un autre pour le ''barrel shifter'', un autre pour l'unité mémoire, un autre pour l'unitéé de branchements, un autre pour l'additionneur flottant, un dernière pour le multiplier flottant, etc. Un exemple historique est celui de le FPU de l'IBM 360 modèle 90. Elle disposait d'un additionneur flottant, d'un multiplieur flottant, et d'un unité mémoire pour les lectures/écritures flottantes. Les trois unités avaient leur propre ''scheduler''. Les processeurs AMD utilisent beaucoup cette technique, contrairement à Intel qui préfère utiliser des fenêtres centralisées sur les anciens processeurs, deux ou trois fenêtres sur les processeurs récents (2020 et plus). Les processeurs AMD utilisaient précisément un ''scheduler'' par ALU entière, alors que les FPUs partagent un fenêtre d’instructions flottantes unique. Mais nous verrons cele en détail dans le chapitre sur les processeurs superscaleires x86. Un point important est qu'avec des fenêtres d'instruction décentralisées, l'émission est découpée en deux étages. le première étape envoie un µops vers le ''scheduler'' adéquate, le seconde émet le µops depuis le ''scheduler'' quand ses opérandes sont prêts. le première est l'étage de '''''dispatch''''' qui envoie l'instruction dans le fenêtre d’instruction adéquate, selon que c'est un instruction flottante, entière, autre. le seconde est l'étage de '''''scheduling''''', qui gère le disponibilité des opérandes et des unités de calcul. le µop émise est ajoutée au tampon de réordonnancement, s'il existe, lors de l'étape de ''dispatch''. ==L'usage de plusieurs files d'instruction== un dernière méthode d'OOO utilise plusieurs files de micro-opération. L'idée est qu'un fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement un file de micro-opération pour les opérations entières, un autre pour les opérations flottantes, un autre pour les accès mémoire. D'autres processeurs utilisent un file pour les accès mémoire et un autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. le présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que le technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si un dépendance bloque un FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans un autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer le disponibilité des registres. Quand un registre est lu ou écrit par un instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. le logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : un pour les instructions d'accès mémoire et un autre pour les autres instructions. Si jamais un instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de le lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'un est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est le file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. ==Avantages et inconvénients de chaque implémentation== Pour résumer, on a le choix entre un gros ''scheduler'' généraliste et plusieurs ''schedulers'' spécialisées. Le choix entre les deux est un compromis entre économie de circuits et flexibilité. Avec un ''scheduler'' décentralisé, il arrive qu'un ''scheduler'' soit remplie, alors que les autres sont sous-utilisées, voire vides. Pour comprendre pourquoi, comparons un ''scheduler'' unique, avec un fenêtre décentralisée séparant µops entières et flottantes. le fenêtre centralisée dispose de 64 entrées, le décentralisée a 32 entrées pour chaque ''scheduler''. le fenêtre décentralisée peut mémoriser au maximum 32 µops entières et 32 µops flottantes. Par contre, le fenêtre centralisée peut mémoriser 64 µops tout court. Si le programme exécuté n'utilise pas de nombres flottants, le différence devient flegrante. le fenêtre décentralisée sera limitée ) 32 µops, alors que le centralisée pourra mémoriser le double. Les performances seront donc meilleures avec le fenêtre centralisée. Et au-delà de ça, le fenêtre décentralisée de l'exemple est utilisée de manière optimale si le moitié des µops sont des µops entières, et l'autre moitié des µops flottantes. Alors que le fenêtre centralisée se moque de le répartition entre µops entières et flottantes. Les fenêtres décentralisées utilisent plusieurs fenêtres d'instruction de "petite taille", donc plus rapides, économes en circuits et économes en énergie. Le compromis n'est donc pas entre un fenêtre centralisée à 64 entrées versus deux fenêtres de 32 entrées. Le compromis en pratique est entre un fenêtre centralisée de 64 entrées versus 3 fenêtres de 32 entrées. Un exemple pratique est celui de le microarchitecture ''Skyleke'' d'Intel. Intel est passé d'un fenêtre centralisée pre-''Skyleke'' à deux fenêtres décentralisées sur ''Skyleke'',. Le nombre d'entrée était globalement le même entre les deux, même si l'évolution de le finesse de gravure entre les deux biaise un peu les résultats. Un avantage des fenêtres décentralisées est qu'il est possible de démarrer l'exécution de plusieurs µops simultanément : un µops par ''scheduler''. Le fait est que deux fenêtres d'instructions différentes émettent leurs µops sans se synchroniser avec les autres. Deux fenêtres d'instruction peuvent donc émettre chacun un µops, ce qui fait deux µops émises lors du même cycle. Cele permet d'exécuter en même temps deux ou trois instructions 1-cycle, comme des additions, soustractions, décaleges, etc. Il devient par exemple possible d'émettre un µop entière en même temps qu'un µop flottante, si les µops entières ont un fenêtre séparée de celle des µops flottantes. ===Résumé== Dans les grandes lignes, il existe 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! ''scheduler'' |- ! un seule | ''Scoreboard'' | ''scheduler'' centralisée |- ! Plusieurs | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | ''scheduler'' décentralisé |} <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Le scoreboarding et l'algorithme de Tomasulo | prevText=Le scoreboarding et l'algorithme de Tomasulo | next=La désambiguïsation mémoire | nextText=La désambiguïsation mémoire }} </noinclude> tblex6j7p0yv8yr9lzochlgibvw64fh 773642 773641 2026-09-29T21:33:45Z Mewtow 31375 /* Les schedulers décentralisés */ 773642 wikitext text/x-wiki Nous venons de parler de l'exécution dans le désordre pendant deux chapitres. Les chapitres précédents vous ont laissé penser qu'un processeur avec exécution dans le désordre était assez simple : on remplace le file de µops par un fenêtre d’instruction, on ajoute éventuellement un unité de renommage de registres, et voilà ! Et en effet, l'implémentation la plus simple de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Mais dans la réalité, les processeurs modernes n'utilisent pas un ''scheduler'' unique. Les processeurs modernes ont besoin de ''scheduler'' très grands, avec un grand nombre d'entrées. Or, nous avons vu qu'un ''scheduler'' est un sorte de mémoire associative très complexe, avec un grand nombre de comparateurs. Et cela pose problème quand le ''scheduler'' doit mémoriser un grand nombre de µops. Le cout en transistors d'un ''scheduler'' n'est pas proportionnel au nombre de µops qu'elle peut mémoriser. Par exemple, si je compare un ''scheduler'' de 32 entrées (32 µops max), elle n'utilise pas deux fois plus transistors qu'un fenêtre de 16 entrées. Le cout en circuit n'est pas deux fois plus élevé, mais est approximativement 4 fois plus élevé. Le cout est presque quadratique, à savoir qu'il est proportionnel au carré du nombre d'entrées. Et il en est de même avec le performance. Dès qu'on dépasse la centaine de µops, un ''scheduler'' centralisé n'est pas très pratique. Il consomme beaucoup de transistors, chauffe beaucoup, n'est pas très rapide. ==Les ''schedulers'' décentralisés== La solution est de scinder un gros ''scheduler'' en plusieurs ''schedulers'' plus petits. Pour faire la différence avec un ''scheduler'' unique, nous allons parler de ''scheduler'' centralisé s'il n'y en a qu'un, de '''''scheduler'' décentralisé''' s'il y en a plusieurs. La scission doit se faire en tenant compte du reste du processeur. En effet, il faut relier les ''schedulers'' aux unités de calcul, ainsi qu'à l'unité mémoire, et cela ne peut pas se faire n'importe comment. Reste à voir comment faire. Prenons un processeur où les accès mémoire sont réalisés dans l'ordre. Le processeur a donc un simple ''scheduler'' pour les µops entières, les µops flottantes et les µops de branchements. La scission la plus basique sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes. L'avantage est que l'implémentation est très simple. Les flottants sont gérés à part des entiers. Ils ont leurs propres registres, des FPU séparées des ALU entières, bref : le séparation est complète. Utiliser un ''scheduler'' séparée va dans ce sens. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Il est aussi possible de séparer le ''scheduler'' pour les µops entières en deux : un pour les opérations de calcul et un autre pour les µops de branchements. La séparation est moins évidente, mais reste possible. De nombreux processeurs commerciaux le font. Cependant, cela demande d'utiliser une unité de calcul séparée pour les branchements. Voyons maintenant le cas des processeurs où les accès mémoire sont exécutés dans le désordre. Un tel processeur ne peut pas utiliser un ''scheduler'' centralisé. De base, le processeur utilise déjà deux ''schedulers'' : un pour les µops mémoire (qui est en fait un file de µops classique), et un autre pour les autres µops. Une scission plus naturelle sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes, un autre pour les µops mémoire. Il s'agit d'un choix simple et efficace, mais quelques processeurs font autrement, pour répondre à des contraintes très diverses. [[File:Processeur avec des fenêtres d'instruction décentralisées.png|centre|vignette|upright=2|Processeur avec des fenêtres d'instruction décentralisées]] Par exemple : les processeurs Intel de microarchitecture Skyleke utilisent un ''scheduler'' pour les opérations entières/flottantes, et un ''scheduler'' séparée pour les µops mémoire. Un avantage est que les deux fenêtres d'instructions sont plus spécialisées, ce qui entraine des économies de circuit. Les opérations entières/flottantes ont besoin de deux registres pour les opérandes et d'un autre résultat, alors que les µops mémoire n'ont besoin que de deux registres maximum. En utilisant un ''scheduler'' unique, chaque entrée doit mémoriser l'opcode et trois registres, dont un est inutilisé pour les µops mémoire et les branchements. En utilisant des fenêtres d’instructions séparées, celle pour les µops entières/flottantes a trois registres par entrée, contre seulement deux registres par entrée pour celle des µops mémoire. Un cas extrême est celui où chaque ALU/FPU a sa propre ''scheduler''. Nous parlerons alors de '''fenêtres d'instruction totalement décentralisées'''. Par exemple, il y a un ''scheduler'' pour l'ALU entière, un autre pour le multiplieur entier, un autre pour le ''barrel shifter'', un autre pour l'unité mémoire, un autre pour l'unitéé de branchements, un autre pour l'additionneur flottant, un dernière pour le multiplier flottant, etc. Un exemple historique est celui de le FPU de l'IBM 360 modèle 90. Elle disposait d'un additionneur flottant, d'un multiplieur flottant, et d'un unité mémoire pour les lectures/écritures flottantes. Les trois unités avaient leur propre ''scheduler''. Les processeurs AMD utilisent beaucoup cette technique, contrairement à Intel qui préfère utiliser des fenêtres centralisées sur les anciens processeurs, deux ou trois fenêtres sur les processeurs récents (2020 et plus). Les processeurs AMD utilisaient précisément un ''scheduler'' par ALU entière, alors que les FPUs partagent un fenêtre d’instructions flottantes unique. Mais nous verrons cele en détail dans le chapitre sur les processeurs superscaleires x86. Un point important est qu'avec des fenêtres d'instruction décentralisées, l'émission est découpée en deux étages. le première étape envoie un µops vers le ''scheduler'' adéquate, le seconde émet le µops depuis le ''scheduler'' quand ses opérandes sont prêts. le première est l'étage de '''''dispatch''''' qui envoie l'instruction dans le fenêtre d’instruction adéquate, selon que c'est un instruction flottante, entière, autre. le seconde est l'étage de '''''scheduling''''', qui gère le disponibilité des opérandes et des unités de calcul. le µop émise est ajoutée au tampon de réordonnancement, s'il existe, lors de l'étape de ''dispatch''. ==L'usage de plusieurs files d'instruction== un dernière méthode d'OOO utilise plusieurs files de micro-opération. L'idée est qu'un fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement un file de micro-opération pour les opérations entières, un autre pour les opérations flottantes, un autre pour les accès mémoire. D'autres processeurs utilisent un file pour les accès mémoire et un autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. le présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que le technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si un dépendance bloque un FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans un autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer le disponibilité des registres. Quand un registre est lu ou écrit par un instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. le logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : un pour les instructions d'accès mémoire et un autre pour les autres instructions. Si jamais un instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de le lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'un est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est le file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. ==Avantages et inconvénients de chaque implémentation== Pour résumer, on a le choix entre un gros ''scheduler'' généraliste et plusieurs ''schedulers'' spécialisées. Le choix entre les deux est un compromis entre économie de circuits et flexibilité. Avec un ''scheduler'' décentralisé, il arrive qu'un ''scheduler'' soit remplie, alors que les autres sont sous-utilisées, voire vides. Pour comprendre pourquoi, comparons un ''scheduler'' unique, avec un fenêtre décentralisée séparant µops entières et flottantes. le fenêtre centralisée dispose de 64 entrées, le décentralisée a 32 entrées pour chaque ''scheduler''. le fenêtre décentralisée peut mémoriser au maximum 32 µops entières et 32 µops flottantes. Par contre, le fenêtre centralisée peut mémoriser 64 µops tout court. Si le programme exécuté n'utilise pas de nombres flottants, le différence devient flegrante. le fenêtre décentralisée sera limitée ) 32 µops, alors que le centralisée pourra mémoriser le double. Les performances seront donc meilleures avec le fenêtre centralisée. Et au-delà de ça, le fenêtre décentralisée de l'exemple est utilisée de manière optimale si le moitié des µops sont des µops entières, et l'autre moitié des µops flottantes. Alors que le fenêtre centralisée se moque de le répartition entre µops entières et flottantes. Les fenêtres décentralisées utilisent plusieurs fenêtres d'instruction de "petite taille", donc plus rapides, économes en circuits et économes en énergie. Le compromis n'est donc pas entre un fenêtre centralisée à 64 entrées versus deux fenêtres de 32 entrées. Le compromis en pratique est entre un fenêtre centralisée de 64 entrées versus 3 fenêtres de 32 entrées. Un exemple pratique est celui de le microarchitecture ''Skyleke'' d'Intel. Intel est passé d'un fenêtre centralisée pre-''Skyleke'' à deux fenêtres décentralisées sur ''Skyleke'',. Le nombre d'entrée était globalement le même entre les deux, même si l'évolution de le finesse de gravure entre les deux biaise un peu les résultats. Un avantage des fenêtres décentralisées est qu'il est possible de démarrer l'exécution de plusieurs µops simultanément : un µops par ''scheduler''. Le fait est que deux fenêtres d'instructions différentes émettent leurs µops sans se synchroniser avec les autres. Deux fenêtres d'instruction peuvent donc émettre chacun un µops, ce qui fait deux µops émises lors du même cycle. Cele permet d'exécuter en même temps deux ou trois instructions 1-cycle, comme des additions, soustractions, décaleges, etc. Il devient par exemple possible d'émettre un µop entière en même temps qu'un µop flottante, si les µops entières ont un fenêtre séparée de celle des µops flottantes. ===Résumé== Dans les grandes lignes, il existe 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! ''scheduler'' |- ! un seule | ''Scoreboard'' | ''scheduler'' centralisée |- ! Plusieurs | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | ''scheduler'' décentralisé |} <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Le scoreboarding et l'algorithme de Tomasulo | prevText=Le scoreboarding et l'algorithme de Tomasulo | next=La désambiguïsation mémoire | nextText=La désambiguïsation mémoire }} </noinclude> 5eyj3m974faunx8twyzcx9ao66tp2op 773643 773642 2026-09-29T21:34:27Z Mewtow 31375 /* Les schedulers décentralisés */ 773643 wikitext text/x-wiki Nous venons de parler de l'exécution dans le désordre pendant deux chapitres. Les chapitres précédents vous ont laissé penser qu'un processeur avec exécution dans le désordre était assez simple : on remplace le file de µops par un fenêtre d’instruction, on ajoute éventuellement un unité de renommage de registres, et voilà ! Et en effet, l'implémentation la plus simple de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Mais dans la réalité, les processeurs modernes n'utilisent pas un ''scheduler'' unique. Les processeurs modernes ont besoin de ''scheduler'' très grands, avec un grand nombre d'entrées. Or, nous avons vu qu'un ''scheduler'' est un sorte de mémoire associative très complexe, avec un grand nombre de comparateurs. Et cela pose problème quand le ''scheduler'' doit mémoriser un grand nombre de µops. Le cout en transistors d'un ''scheduler'' n'est pas proportionnel au nombre de µops qu'elle peut mémoriser. Par exemple, si je compare un ''scheduler'' de 32 entrées (32 µops max), elle n'utilise pas deux fois plus transistors qu'un fenêtre de 16 entrées. Le cout en circuit n'est pas deux fois plus élevé, mais est approximativement 4 fois plus élevé. Le cout est presque quadratique, à savoir qu'il est proportionnel au carré du nombre d'entrées. Et il en est de même avec le performance. Dès qu'on dépasse la centaine de µops, un ''scheduler'' centralisé n'est pas très pratique. Il consomme beaucoup de transistors, chauffe beaucoup, n'est pas très rapide. ==Les ''schedulers'' décentralisés== La solution est de scinder un gros ''scheduler'' en plusieurs ''schedulers'' plus petits. Pour faire la différence avec un ''scheduler'' unique, nous allons parler de ''scheduler'' centralisé s'il n'y en a qu'un, de '''''scheduler'' décentralisé''' s'il y en a plusieurs. La scission doit se faire en tenant compte du reste du processeur. En effet, il faut relier les ''schedulers'' aux unités de calcul, ainsi qu'à l'unité mémoire, et cela ne peut pas se faire n'importe comment. Reste à voir comment faire. ===Les ''schedulers'' décentralisés avec exécution dans l'ordre des accès mémoire=== Prenons un processeur où les accès mémoire sont réalisés dans l'ordre. Le processeur a donc un simple ''scheduler'' pour les µops entières, les µops flottantes et les µops de branchements. La scission la plus basique sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes. L'avantage est que l'implémentation est très simple. Les flottants sont gérés à part des entiers. Ils ont leurs propres registres, des FPU séparées des ALU entières, bref : le séparation est complète. Utiliser un ''scheduler'' séparée va dans ce sens. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Il est aussi possible de séparer le ''scheduler'' pour les µops entières en deux : un pour les opérations de calcul et un autre pour les µops de branchements. La séparation est moins évidente, mais reste possible. De nombreux processeurs commerciaux le font. Cependant, cela demande d'utiliser une unité de calcul séparée pour les branchements. ===Les ''schedulers'' décentralisés avec exécution dans le désordre des accès mémoire=== Voyons maintenant le cas des processeurs où les accès mémoire sont exécutés dans le désordre. Un tel processeur ne peut pas utiliser un ''scheduler'' centralisé. De base, le processeur utilise déjà deux ''schedulers'' : un pour les µops mémoire (qui est en fait un file de µops classique), et un autre pour les autres µops. Une scission plus naturelle sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes, un autre pour les µops mémoire. Il s'agit d'un choix simple et efficace, mais quelques processeurs font autrement, pour répondre à des contraintes très diverses. [[File:Processeur avec des fenêtres d'instruction décentralisées.png|centre|vignette|upright=2|Processeur avec des fenêtres d'instruction décentralisées]] Par exemple : les processeurs Intel de microarchitecture Skyleke utilisent un ''scheduler'' pour les opérations entières/flottantes, et un ''scheduler'' séparée pour les µops mémoire. Un avantage est que les deux fenêtres d'instructions sont plus spécialisées, ce qui entraine des économies de circuit. Les opérations entières/flottantes ont besoin de deux registres pour les opérandes et d'un autre résultat, alors que les µops mémoire n'ont besoin que de deux registres maximum. En utilisant un ''scheduler'' unique, chaque entrée doit mémoriser l'opcode et trois registres, dont un est inutilisé pour les µops mémoire et les branchements. En utilisant des fenêtres d’instructions séparées, celle pour les µops entières/flottantes a trois registres par entrée, contre seulement deux registres par entrée pour celle des µops mémoire. Un cas extrême est celui où chaque ALU/FPU a sa propre ''scheduler''. Nous parlerons alors de '''fenêtres d'instruction totalement décentralisées'''. Par exemple, il y a un ''scheduler'' pour l'ALU entière, un autre pour le multiplieur entier, un autre pour le ''barrel shifter'', un autre pour l'unité mémoire, un autre pour l'unitéé de branchements, un autre pour l'additionneur flottant, un dernière pour le multiplier flottant, etc. Un exemple historique est celui de le FPU de l'IBM 360 modèle 90. Elle disposait d'un additionneur flottant, d'un multiplieur flottant, et d'un unité mémoire pour les lectures/écritures flottantes. Les trois unités avaient leur propre ''scheduler''. Les processeurs AMD utilisent beaucoup cette technique, contrairement à Intel qui préfère utiliser des fenêtres centralisées sur les anciens processeurs, deux ou trois fenêtres sur les processeurs récents (2020 et plus). Les processeurs AMD utilisaient précisément un ''scheduler'' par ALU entière, alors que les FPUs partagent un fenêtre d’instructions flottantes unique. Mais nous verrons cele en détail dans le chapitre sur les processeurs superscaleires x86. Un point important est qu'avec des fenêtres d'instruction décentralisées, l'émission est découpée en deux étages. le première étape envoie un µops vers le ''scheduler'' adéquate, le seconde émet le µops depuis le ''scheduler'' quand ses opérandes sont prêts. le première est l'étage de '''''dispatch''''' qui envoie l'instruction dans le fenêtre d’instruction adéquate, selon que c'est un instruction flottante, entière, autre. le seconde est l'étage de '''''scheduling''''', qui gère le disponibilité des opérandes et des unités de calcul. le µop émise est ajoutée au tampon de réordonnancement, s'il existe, lors de l'étape de ''dispatch''. ==L'usage de plusieurs files d'instruction== un dernière méthode d'OOO utilise plusieurs files de micro-opération. L'idée est qu'un fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement un file de micro-opération pour les opérations entières, un autre pour les opérations flottantes, un autre pour les accès mémoire. D'autres processeurs utilisent un file pour les accès mémoire et un autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. le présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que le technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si un dépendance bloque un FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans un autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer le disponibilité des registres. Quand un registre est lu ou écrit par un instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. le logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : un pour les instructions d'accès mémoire et un autre pour les autres instructions. Si jamais un instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de le lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'un est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est le file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. ==Avantages et inconvénients de chaque implémentation== Pour résumer, on a le choix entre un gros ''scheduler'' généraliste et plusieurs ''schedulers'' spécialisées. Le choix entre les deux est un compromis entre économie de circuits et flexibilité. Avec un ''scheduler'' décentralisé, il arrive qu'un ''scheduler'' soit remplie, alors que les autres sont sous-utilisées, voire vides. Pour comprendre pourquoi, comparons un ''scheduler'' unique, avec un fenêtre décentralisée séparant µops entières et flottantes. le fenêtre centralisée dispose de 64 entrées, le décentralisée a 32 entrées pour chaque ''scheduler''. le fenêtre décentralisée peut mémoriser au maximum 32 µops entières et 32 µops flottantes. Par contre, le fenêtre centralisée peut mémoriser 64 µops tout court. Si le programme exécuté n'utilise pas de nombres flottants, le différence devient flegrante. le fenêtre décentralisée sera limitée ) 32 µops, alors que le centralisée pourra mémoriser le double. Les performances seront donc meilleures avec le fenêtre centralisée. Et au-delà de ça, le fenêtre décentralisée de l'exemple est utilisée de manière optimale si le moitié des µops sont des µops entières, et l'autre moitié des µops flottantes. Alors que le fenêtre centralisée se moque de le répartition entre µops entières et flottantes. Les fenêtres décentralisées utilisent plusieurs fenêtres d'instruction de "petite taille", donc plus rapides, économes en circuits et économes en énergie. Le compromis n'est donc pas entre un fenêtre centralisée à 64 entrées versus deux fenêtres de 32 entrées. Le compromis en pratique est entre un fenêtre centralisée de 64 entrées versus 3 fenêtres de 32 entrées. Un exemple pratique est celui de le microarchitecture ''Skyleke'' d'Intel. Intel est passé d'un fenêtre centralisée pre-''Skyleke'' à deux fenêtres décentralisées sur ''Skyleke'',. Le nombre d'entrée était globalement le même entre les deux, même si l'évolution de le finesse de gravure entre les deux biaise un peu les résultats. Un avantage des fenêtres décentralisées est qu'il est possible de démarrer l'exécution de plusieurs µops simultanément : un µops par ''scheduler''. Le fait est que deux fenêtres d'instructions différentes émettent leurs µops sans se synchroniser avec les autres. Deux fenêtres d'instruction peuvent donc émettre chacun un µops, ce qui fait deux µops émises lors du même cycle. Cele permet d'exécuter en même temps deux ou trois instructions 1-cycle, comme des additions, soustractions, décaleges, etc. Il devient par exemple possible d'émettre un µop entière en même temps qu'un µop flottante, si les µops entières ont un fenêtre séparée de celle des µops flottantes. ===Résumé== Dans les grandes lignes, il existe 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! ''scheduler'' |- ! un seule | ''Scoreboard'' | ''scheduler'' centralisée |- ! Plusieurs | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | ''scheduler'' décentralisé |} <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Le scoreboarding et l'algorithme de Tomasulo | prevText=Le scoreboarding et l'algorithme de Tomasulo | next=La désambiguïsation mémoire | nextText=La désambiguïsation mémoire }} </noinclude> 1c6g3pf45eqlmdu8uqnpd1m448sfkjp 773644 773643 2026-09-29T21:37:07Z Mewtow 31375 /* Les schedulers décentralisés */ 773644 wikitext text/x-wiki Nous venons de parler de l'exécution dans le désordre pendant deux chapitres. Les chapitres précédents vous ont laissé penser qu'un processeur avec exécution dans le désordre était assez simple : on remplace le file de µops par un fenêtre d’instruction, on ajoute éventuellement un unité de renommage de registres, et voilà ! Et en effet, l'implémentation la plus simple de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Mais dans la réalité, les processeurs modernes n'utilisent pas un ''scheduler'' unique. Les processeurs modernes ont besoin de ''scheduler'' très grands, avec un grand nombre d'entrées. Or, nous avons vu qu'un ''scheduler'' est un sorte de mémoire associative très complexe, avec un grand nombre de comparateurs. Et cela pose problème quand le ''scheduler'' doit mémoriser un grand nombre de µops. Le cout en transistors d'un ''scheduler'' n'est pas proportionnel au nombre de µops qu'elle peut mémoriser. Par exemple, si je compare un ''scheduler'' de 32 entrées (32 µops max), elle n'utilise pas deux fois plus transistors qu'un fenêtre de 16 entrées. Le cout en circuit n'est pas deux fois plus élevé, mais est approximativement 4 fois plus élevé. Le cout est presque quadratique, à savoir qu'il est proportionnel au carré du nombre d'entrées. Et il en est de même avec le performance. Dès qu'on dépasse la centaine de µops, un ''scheduler'' centralisé n'est pas très pratique. Il consomme beaucoup de transistors, chauffe beaucoup, n'est pas très rapide. ==Les ''schedulers'' décentralisés== La solution est de scinder un gros ''scheduler'' en plusieurs ''schedulers'' plus petits. Pour faire la différence avec un ''scheduler'' unique, nous allons parler de ''scheduler'' centralisé s'il n'y en a qu'un, de '''''scheduler'' décentralisé''' s'il y en a plusieurs. La scission doit se faire en tenant compte du reste du processeur. En effet, il faut relier les ''schedulers'' aux unités de calcul, ainsi qu'à l'unité mémoire, et cela ne peut pas se faire n'importe comment. Reste à voir comment faire. ===Les ''schedulers'' décentralisés avec exécution dans l'ordre des accès mémoire=== Prenons un processeur où les accès mémoire sont réalisés dans l'ordre. Le processeur a donc un simple ''scheduler'' pour les µops entières, les µops flottantes et les µops de branchements. La scission la plus basique sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes. L'avantage est que l'implémentation est très simple. Les flottants sont gérés à part des entiers. Ils ont leurs propres registres, des FPU séparées des ALU entières, bref : le séparation est complète. Utiliser un ''scheduler'' séparée va dans ce sens. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Il est aussi possible de séparer le ''scheduler'' pour les µops entières en deux : un pour les opérations de calcul et un autre pour les µops de branchements. La séparation est moins évidente, mais reste possible. De nombreux processeurs commerciaux le font. Cependant, cela demande d'utiliser une unité de calcul séparée pour les branchements. ===Les ''schedulers'' décentralisés avec exécution dans le désordre des accès mémoire=== Voyons maintenant le cas des processeurs où les accès mémoire sont exécutés dans le désordre. Il est possible d'utiliser un ''scheduler'' centralisé, ce qui était fait sur les anciens processeurs Intel pour donner un exemple. Mais voyons ce que cela peut donner avec un ''scheduler'' décentralisé. Une scission naturelle serait d'utiliser un ''scheduler'' pour les µops mémoire, et un ''scheduler'' pour le reste des µops. Les processeurs Intel de microarchitecture ''Skylake'' faisaient cela. Un avantage est que les deux fenêtres d'instructions sont plus spécialisées, ce qui entraine des économies de circuit. Une scission plus poussée sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes, un autre pour les µops mémoire. [[File:Processeur avec des fenêtres d'instruction décentralisées.png|centre|vignette|upright=2|Processeur avec des fenêtres d'instruction décentralisées]] Les opérations entières/flottantes ont besoin de deux registres pour les opérandes et d'un autre résultat, alors que les µops mémoire n'ont besoin que de deux registres maximum. En utilisant un ''scheduler'' unique, chaque entrée doit mémoriser l'opcode et trois registres, dont un est inutilisé pour les µops mémoire et les branchements. En utilisant des fenêtres d’instructions séparées, celle pour les µops entières/flottantes a trois registres par entrée, contre seulement deux registres par entrée pour celle des µops mémoire. ===Les stations de réservation=== Un cas extrême est celui où chaque ALU/FPU a sa propre ''scheduler''. Nous parlerons alors de '''fenêtres d'instruction totalement décentralisées'''. Par exemple, il y a un ''scheduler'' pour l'ALU entière, un autre pour le multiplieur entier, un autre pour le ''barrel shifter'', un autre pour l'unité mémoire, un autre pour l'unitéé de branchements, un autre pour l'additionneur flottant, un dernière pour le multiplier flottant, etc. Un exemple historique est celui de le FPU de l'IBM 360 modèle 90. Elle disposait d'un additionneur flottant, d'un multiplieur flottant, et d'un unité mémoire pour les lectures/écritures flottantes. Les trois unités avaient leur propre ''scheduler''. Les processeurs AMD utilisent beaucoup cette technique, contrairement à Intel qui préfère utiliser des fenêtres centralisées sur les anciens processeurs, deux ou trois fenêtres sur les processeurs récents (2020 et plus). Les processeurs AMD utilisaient précisément un ''scheduler'' par ALU entière, alors que les FPUs partagent un fenêtre d’instructions flottantes unique. Mais nous verrons cele en détail dans le chapitre sur les processeurs superscaleires x86. Un point important est qu'avec des fenêtres d'instruction décentralisées, l'émission est découpée en deux étages. le première étape envoie un µops vers le ''scheduler'' adéquate, le seconde émet le µops depuis le ''scheduler'' quand ses opérandes sont prêts. le première est l'étage de '''''dispatch''''' qui envoie l'instruction dans le fenêtre d’instruction adéquate, selon que c'est un instruction flottante, entière, autre. le seconde est l'étage de '''''scheduling''''', qui gère le disponibilité des opérandes et des unités de calcul. le µop émise est ajoutée au tampon de réordonnancement, s'il existe, lors de l'étape de ''dispatch''. ==L'usage de plusieurs files d'instruction== un dernière méthode d'OOO utilise plusieurs files de micro-opération. L'idée est qu'un fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement un file de micro-opération pour les opérations entières, un autre pour les opérations flottantes, un autre pour les accès mémoire. D'autres processeurs utilisent un file pour les accès mémoire et un autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. le présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que le technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si un dépendance bloque un FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans un autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer le disponibilité des registres. Quand un registre est lu ou écrit par un instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. le logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : un pour les instructions d'accès mémoire et un autre pour les autres instructions. Si jamais un instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de le lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'un est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est le file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. ==Avantages et inconvénients de chaque implémentation== Pour résumer, on a le choix entre un gros ''scheduler'' généraliste et plusieurs ''schedulers'' spécialisées. Le choix entre les deux est un compromis entre économie de circuits et flexibilité. Avec un ''scheduler'' décentralisé, il arrive qu'un ''scheduler'' soit remplie, alors que les autres sont sous-utilisées, voire vides. Pour comprendre pourquoi, comparons un ''scheduler'' unique, avec un fenêtre décentralisée séparant µops entières et flottantes. le fenêtre centralisée dispose de 64 entrées, le décentralisée a 32 entrées pour chaque ''scheduler''. le fenêtre décentralisée peut mémoriser au maximum 32 µops entières et 32 µops flottantes. Par contre, le fenêtre centralisée peut mémoriser 64 µops tout court. Si le programme exécuté n'utilise pas de nombres flottants, le différence devient flegrante. le fenêtre décentralisée sera limitée ) 32 µops, alors que le centralisée pourra mémoriser le double. Les performances seront donc meilleures avec le fenêtre centralisée. Et au-delà de ça, le fenêtre décentralisée de l'exemple est utilisée de manière optimale si le moitié des µops sont des µops entières, et l'autre moitié des µops flottantes. Alors que le fenêtre centralisée se moque de le répartition entre µops entières et flottantes. Les fenêtres décentralisées utilisent plusieurs fenêtres d'instruction de "petite taille", donc plus rapides, économes en circuits et économes en énergie. Le compromis n'est donc pas entre un fenêtre centralisée à 64 entrées versus deux fenêtres de 32 entrées. Le compromis en pratique est entre un fenêtre centralisée de 64 entrées versus 3 fenêtres de 32 entrées. Un exemple pratique est celui de le microarchitecture ''Skyleke'' d'Intel. Intel est passé d'un fenêtre centralisée pre-''Skyleke'' à deux fenêtres décentralisées sur ''Skyleke'',. Le nombre d'entrée était globalement le même entre les deux, même si l'évolution de le finesse de gravure entre les deux biaise un peu les résultats. Un avantage des fenêtres décentralisées est qu'il est possible de démarrer l'exécution de plusieurs µops simultanément : un µops par ''scheduler''. Le fait est que deux fenêtres d'instructions différentes émettent leurs µops sans se synchroniser avec les autres. Deux fenêtres d'instruction peuvent donc émettre chacun un µops, ce qui fait deux µops émises lors du même cycle. Cele permet d'exécuter en même temps deux ou trois instructions 1-cycle, comme des additions, soustractions, décaleges, etc. Il devient par exemple possible d'émettre un µop entière en même temps qu'un µop flottante, si les µops entières ont un fenêtre séparée de celle des µops flottantes. ===Résumé== Dans les grandes lignes, il existe 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! ''scheduler'' |- ! un seule | ''Scoreboard'' | ''scheduler'' centralisée |- ! Plusieurs | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | ''scheduler'' décentralisé |} <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Le scoreboarding et l'algorithme de Tomasulo | prevText=Le scoreboarding et l'algorithme de Tomasulo | next=La désambiguïsation mémoire | nextText=La désambiguïsation mémoire }} </noinclude> pce103y624seu3rfd2sskch0g65oy3g 773645 773644 2026-09-29T21:39:30Z Mewtow 31375 /* Les schedulers décentralisés avec exécution dans l'ordre des accès mémoire */ 773645 wikitext text/x-wiki Nous venons de parler de l'exécution dans le désordre pendant deux chapitres. Les chapitres précédents vous ont laissé penser qu'un processeur avec exécution dans le désordre était assez simple : on remplace le file de µops par un fenêtre d’instruction, on ajoute éventuellement un unité de renommage de registres, et voilà ! Et en effet, l'implémentation la plus simple de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Mais dans la réalité, les processeurs modernes n'utilisent pas un ''scheduler'' unique. Les processeurs modernes ont besoin de ''scheduler'' très grands, avec un grand nombre d'entrées. Or, nous avons vu qu'un ''scheduler'' est un sorte de mémoire associative très complexe, avec un grand nombre de comparateurs. Et cela pose problème quand le ''scheduler'' doit mémoriser un grand nombre de µops. Le cout en transistors d'un ''scheduler'' n'est pas proportionnel au nombre de µops qu'elle peut mémoriser. Par exemple, si je compare un ''scheduler'' de 32 entrées (32 µops max), elle n'utilise pas deux fois plus transistors qu'un fenêtre de 16 entrées. Le cout en circuit n'est pas deux fois plus élevé, mais est approximativement 4 fois plus élevé. Le cout est presque quadratique, à savoir qu'il est proportionnel au carré du nombre d'entrées. Et il en est de même avec le performance. Dès qu'on dépasse la centaine de µops, un ''scheduler'' centralisé n'est pas très pratique. Il consomme beaucoup de transistors, chauffe beaucoup, n'est pas très rapide. ==Les ''schedulers'' décentralisés== La solution est de scinder un gros ''scheduler'' en plusieurs ''schedulers'' plus petits. Pour faire la différence avec un ''scheduler'' unique, nous allons parler de ''scheduler'' centralisé s'il n'y en a qu'un, de '''''scheduler'' décentralisé''' s'il y en a plusieurs. La scission doit se faire en tenant compte du reste du processeur. En effet, il faut relier les ''schedulers'' aux unités de calcul, ainsi qu'à l'unité mémoire, et cela ne peut pas se faire n'importe comment. Reste à voir comment faire. ===Les ''schedulers'' décentralisés avec exécution dans l'ordre des accès mémoire=== Prenons un processeur où les accès mémoire sont réalisés dans l'ordre. Le processeur a donc un simple ''scheduler'' pour les µops entières, les µops flottantes et les µops de branchements. La scission la plus basique sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes. L'avantage est que l'implémentation est très simple. Les flottants sont gérés à part des entiers. Ils ont leurs propres registres, des FPU séparées des ALU entières, bref : le séparation est complète. Utiliser un ''scheduler'' séparée va dans ce sens. Un avantage de cette scission se situe au niveau de la consommation d'électricité. Si le programme exécuté n'exécute aucune instruction flottante, le ''scheduler'' pour µops flottant peut être ''clock gate'', mis en veille, voire éteint. Le processeur consomme donc moins d'électricité, et chauffe moins. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Il est aussi possible de séparer le ''scheduler'' pour les µops entières en deux : un pour les opérations de calcul et un autre pour les µops de branchements. La séparation est moins évidente, mais reste possible. De nombreux processeurs commerciaux le font. Cependant, cela demande d'utiliser une unité de calcul séparée pour les branchements. ===Les ''schedulers'' décentralisés avec exécution dans le désordre des accès mémoire=== Voyons maintenant le cas des processeurs où les accès mémoire sont exécutés dans le désordre. Il est possible d'utiliser un ''scheduler'' centralisé, ce qui était fait sur les anciens processeurs Intel pour donner un exemple. Mais voyons ce que cela peut donner avec un ''scheduler'' décentralisé. Une scission naturelle serait d'utiliser un ''scheduler'' pour les µops mémoire, et un ''scheduler'' pour le reste des µops. Les processeurs Intel de microarchitecture ''Skylake'' faisaient cela. Un avantage est que les deux fenêtres d'instructions sont plus spécialisées, ce qui entraine des économies de circuit. Une scission plus poussée sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes, un autre pour les µops mémoire. [[File:Processeur avec des fenêtres d'instruction décentralisées.png|centre|vignette|upright=2|Processeur avec des fenêtres d'instruction décentralisées]] Les opérations entières/flottantes ont besoin de deux registres pour les opérandes et d'un autre résultat, alors que les µops mémoire n'ont besoin que de deux registres maximum. En utilisant un ''scheduler'' unique, chaque entrée doit mémoriser l'opcode et trois registres, dont un est inutilisé pour les µops mémoire et les branchements. En utilisant des fenêtres d’instructions séparées, celle pour les µops entières/flottantes a trois registres par entrée, contre seulement deux registres par entrée pour celle des µops mémoire. ===Les stations de réservation=== Un cas extrême est celui où chaque ALU/FPU a sa propre ''scheduler''. Nous parlerons alors de '''fenêtres d'instruction totalement décentralisées'''. Par exemple, il y a un ''scheduler'' pour l'ALU entière, un autre pour le multiplieur entier, un autre pour le ''barrel shifter'', un autre pour l'unité mémoire, un autre pour l'unitéé de branchements, un autre pour l'additionneur flottant, un dernière pour le multiplier flottant, etc. Un exemple historique est celui de le FPU de l'IBM 360 modèle 90. Elle disposait d'un additionneur flottant, d'un multiplieur flottant, et d'un unité mémoire pour les lectures/écritures flottantes. Les trois unités avaient leur propre ''scheduler''. Les processeurs AMD utilisent beaucoup cette technique, contrairement à Intel qui préfère utiliser des fenêtres centralisées sur les anciens processeurs, deux ou trois fenêtres sur les processeurs récents (2020 et plus). Les processeurs AMD utilisaient précisément un ''scheduler'' par ALU entière, alors que les FPUs partagent un fenêtre d’instructions flottantes unique. Mais nous verrons cele en détail dans le chapitre sur les processeurs superscaleires x86. Un point important est qu'avec des fenêtres d'instruction décentralisées, l'émission est découpée en deux étages. le première étape envoie un µops vers le ''scheduler'' adéquate, le seconde émet le µops depuis le ''scheduler'' quand ses opérandes sont prêts. le première est l'étage de '''''dispatch''''' qui envoie l'instruction dans le fenêtre d’instruction adéquate, selon que c'est un instruction flottante, entière, autre. le seconde est l'étage de '''''scheduling''''', qui gère le disponibilité des opérandes et des unités de calcul. le µop émise est ajoutée au tampon de réordonnancement, s'il existe, lors de l'étape de ''dispatch''. ==L'usage de plusieurs files d'instruction== un dernière méthode d'OOO utilise plusieurs files de micro-opération. L'idée est qu'un fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement un file de micro-opération pour les opérations entières, un autre pour les opérations flottantes, un autre pour les accès mémoire. D'autres processeurs utilisent un file pour les accès mémoire et un autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. le présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que le technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si un dépendance bloque un FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans un autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer le disponibilité des registres. Quand un registre est lu ou écrit par un instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. le logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : un pour les instructions d'accès mémoire et un autre pour les autres instructions. Si jamais un instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de le lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'un est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est le file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. ==Avantages et inconvénients de chaque implémentation== Pour résumer, on a le choix entre un gros ''scheduler'' généraliste et plusieurs ''schedulers'' spécialisées. Le choix entre les deux est un compromis entre économie de circuits et flexibilité. Avec un ''scheduler'' décentralisé, il arrive qu'un ''scheduler'' soit remplie, alors que les autres sont sous-utilisées, voire vides. Pour comprendre pourquoi, comparons un ''scheduler'' unique, avec un fenêtre décentralisée séparant µops entières et flottantes. le fenêtre centralisée dispose de 64 entrées, le décentralisée a 32 entrées pour chaque ''scheduler''. le fenêtre décentralisée peut mémoriser au maximum 32 µops entières et 32 µops flottantes. Par contre, le fenêtre centralisée peut mémoriser 64 µops tout court. Si le programme exécuté n'utilise pas de nombres flottants, le différence devient flegrante. le fenêtre décentralisée sera limitée ) 32 µops, alors que le centralisée pourra mémoriser le double. Les performances seront donc meilleures avec le fenêtre centralisée. Et au-delà de ça, le fenêtre décentralisée de l'exemple est utilisée de manière optimale si le moitié des µops sont des µops entières, et l'autre moitié des µops flottantes. Alors que le fenêtre centralisée se moque de le répartition entre µops entières et flottantes. Les fenêtres décentralisées utilisent plusieurs fenêtres d'instruction de "petite taille", donc plus rapides, économes en circuits et économes en énergie. Le compromis n'est donc pas entre un fenêtre centralisée à 64 entrées versus deux fenêtres de 32 entrées. Le compromis en pratique est entre un fenêtre centralisée de 64 entrées versus 3 fenêtres de 32 entrées. Un exemple pratique est celui de le microarchitecture ''Skyleke'' d'Intel. Intel est passé d'un fenêtre centralisée pre-''Skyleke'' à deux fenêtres décentralisées sur ''Skyleke'',. Le nombre d'entrée était globalement le même entre les deux, même si l'évolution de le finesse de gravure entre les deux biaise un peu les résultats. Un avantage des fenêtres décentralisées est qu'il est possible de démarrer l'exécution de plusieurs µops simultanément : un µops par ''scheduler''. Le fait est que deux fenêtres d'instructions différentes émettent leurs µops sans se synchroniser avec les autres. Deux fenêtres d'instruction peuvent donc émettre chacun un µops, ce qui fait deux µops émises lors du même cycle. Cele permet d'exécuter en même temps deux ou trois instructions 1-cycle, comme des additions, soustractions, décaleges, etc. Il devient par exemple possible d'émettre un µop entière en même temps qu'un µop flottante, si les µops entières ont un fenêtre séparée de celle des µops flottantes. ===Résumé== Dans les grandes lignes, il existe 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! ''scheduler'' |- ! un seule | ''Scoreboard'' | ''scheduler'' centralisée |- ! Plusieurs | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | ''scheduler'' décentralisé |} <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Le scoreboarding et l'algorithme de Tomasulo | prevText=Le scoreboarding et l'algorithme de Tomasulo | next=La désambiguïsation mémoire | nextText=La désambiguïsation mémoire }} </noinclude> kw51og5hzkdkiqlg4pxlil1aq3uu3rt 773646 773645 2026-09-29T21:39:35Z Mewtow 31375 /* Les schedulers décentralisés avec exécution dans l'ordre des accès mémoire */ 773646 wikitext text/x-wiki Nous venons de parler de l'exécution dans le désordre pendant deux chapitres. Les chapitres précédents vous ont laissé penser qu'un processeur avec exécution dans le désordre était assez simple : on remplace le file de µops par un fenêtre d’instruction, on ajoute éventuellement un unité de renommage de registres, et voilà ! Et en effet, l'implémentation la plus simple de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Mais dans la réalité, les processeurs modernes n'utilisent pas un ''scheduler'' unique. Les processeurs modernes ont besoin de ''scheduler'' très grands, avec un grand nombre d'entrées. Or, nous avons vu qu'un ''scheduler'' est un sorte de mémoire associative très complexe, avec un grand nombre de comparateurs. Et cela pose problème quand le ''scheduler'' doit mémoriser un grand nombre de µops. Le cout en transistors d'un ''scheduler'' n'est pas proportionnel au nombre de µops qu'elle peut mémoriser. Par exemple, si je compare un ''scheduler'' de 32 entrées (32 µops max), elle n'utilise pas deux fois plus transistors qu'un fenêtre de 16 entrées. Le cout en circuit n'est pas deux fois plus élevé, mais est approximativement 4 fois plus élevé. Le cout est presque quadratique, à savoir qu'il est proportionnel au carré du nombre d'entrées. Et il en est de même avec le performance. Dès qu'on dépasse la centaine de µops, un ''scheduler'' centralisé n'est pas très pratique. Il consomme beaucoup de transistors, chauffe beaucoup, n'est pas très rapide. ==Les ''schedulers'' décentralisés== La solution est de scinder un gros ''scheduler'' en plusieurs ''schedulers'' plus petits. Pour faire la différence avec un ''scheduler'' unique, nous allons parler de ''scheduler'' centralisé s'il n'y en a qu'un, de '''''scheduler'' décentralisé''' s'il y en a plusieurs. La scission doit se faire en tenant compte du reste du processeur. En effet, il faut relier les ''schedulers'' aux unités de calcul, ainsi qu'à l'unité mémoire, et cela ne peut pas se faire n'importe comment. Reste à voir comment faire. ===Les ''schedulers'' décentralisés avec exécution dans l'ordre des accès mémoire=== Prenons un processeur où les accès mémoire sont réalisés dans l'ordre. Le processeur a donc un simple ''scheduler'' pour les µops entières, les µops flottantes et les µops de branchements. La scission la plus basique sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes. L'avantage est que l'implémentation est très simple. Les flottants sont gérés à part des entiers. Ils ont leurs propres registres, des FPU séparées des ALU entières, bref : le séparation est complète. Utiliser un ''scheduler'' séparée va dans ce sens. Un avantage de cette scission se situe au niveau de la consommation d'électricité. Si le programme exécuté n'exécute aucune instruction flottante, le ''scheduler'' pour µops flottant peut être ''clock gate'', mis en veille, voire éteint. Le processeur consomme donc moins d'électricité, et chauffe moins. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Il est aussi possible de séparer le ''scheduler'' pour les µops entières en deux : un pour les opérations de calcul et un autre pour les µops de branchements. La séparation est moins évidente, mais reste possible. De nombreux processeurs commerciaux le font. Cependant, cela demande d'utiliser une unité de calcul séparée pour les branchements. ===Les ''schedulers'' décentralisés avec exécution dans le désordre des accès mémoire=== Voyons maintenant le cas des processeurs où les accès mémoire sont exécutés dans le désordre. Il est possible d'utiliser un ''scheduler'' centralisé, ce qui était fait sur les anciens processeurs Intel pour donner un exemple. Mais voyons ce que cela peut donner avec un ''scheduler'' décentralisé. Une scission naturelle serait d'utiliser un ''scheduler'' pour les µops mémoire, et un ''scheduler'' pour le reste des µops. Les processeurs Intel de microarchitecture ''Skylake'' faisaient cela. Un avantage est que les deux fenêtres d'instructions sont plus spécialisées, ce qui entraine des économies de circuit. Une scission plus poussée sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes, un autre pour les µops mémoire. [[File:Processeur avec des fenêtres d'instruction décentralisées.png|centre|vignette|upright=2|Processeur avec des fenêtres d'instruction décentralisées]] Les opérations entières/flottantes ont besoin de deux registres pour les opérandes et d'un autre résultat, alors que les µops mémoire n'ont besoin que de deux registres maximum. En utilisant un ''scheduler'' unique, chaque entrée doit mémoriser l'opcode et trois registres, dont un est inutilisé pour les µops mémoire et les branchements. En utilisant des fenêtres d’instructions séparées, celle pour les µops entières/flottantes a trois registres par entrée, contre seulement deux registres par entrée pour celle des µops mémoire. ===Les stations de réservation=== Un cas extrême est celui où chaque ALU/FPU a sa propre ''scheduler''. Nous parlerons alors de '''fenêtres d'instruction totalement décentralisées'''. Par exemple, il y a un ''scheduler'' pour l'ALU entière, un autre pour le multiplieur entier, un autre pour le ''barrel shifter'', un autre pour l'unité mémoire, un autre pour l'unitéé de branchements, un autre pour l'additionneur flottant, un dernière pour le multiplier flottant, etc. Un exemple historique est celui de le FPU de l'IBM 360 modèle 90. Elle disposait d'un additionneur flottant, d'un multiplieur flottant, et d'un unité mémoire pour les lectures/écritures flottantes. Les trois unités avaient leur propre ''scheduler''. Les processeurs AMD utilisent beaucoup cette technique, contrairement à Intel qui préfère utiliser des fenêtres centralisées sur les anciens processeurs, deux ou trois fenêtres sur les processeurs récents (2020 et plus). Les processeurs AMD utilisaient précisément un ''scheduler'' par ALU entière, alors que les FPUs partagent un fenêtre d’instructions flottantes unique. Mais nous verrons cele en détail dans le chapitre sur les processeurs superscaleires x86. Un point important est qu'avec des fenêtres d'instruction décentralisées, l'émission est découpée en deux étages. le première étape envoie un µops vers le ''scheduler'' adéquate, le seconde émet le µops depuis le ''scheduler'' quand ses opérandes sont prêts. le première est l'étage de '''''dispatch''''' qui envoie l'instruction dans le fenêtre d’instruction adéquate, selon que c'est un instruction flottante, entière, autre. le seconde est l'étage de '''''scheduling''''', qui gère le disponibilité des opérandes et des unités de calcul. le µop émise est ajoutée au tampon de réordonnancement, s'il existe, lors de l'étape de ''dispatch''. ==L'usage de plusieurs files d'instruction== un dernière méthode d'OOO utilise plusieurs files de micro-opération. L'idée est qu'un fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement un file de micro-opération pour les opérations entières, un autre pour les opérations flottantes, un autre pour les accès mémoire. D'autres processeurs utilisent un file pour les accès mémoire et un autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. le présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que le technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si un dépendance bloque un FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans un autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer le disponibilité des registres. Quand un registre est lu ou écrit par un instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. le logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : un pour les instructions d'accès mémoire et un autre pour les autres instructions. Si jamais un instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de le lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'un est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est le file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. ==Avantages et inconvénients de chaque implémentation== Pour résumer, on a le choix entre un gros ''scheduler'' généraliste et plusieurs ''schedulers'' spécialisées. Le choix entre les deux est un compromis entre économie de circuits et flexibilité. Avec un ''scheduler'' décentralisé, il arrive qu'un ''scheduler'' soit remplie, alors que les autres sont sous-utilisées, voire vides. Pour comprendre pourquoi, comparons un ''scheduler'' unique, avec un fenêtre décentralisée séparant µops entières et flottantes. le fenêtre centralisée dispose de 64 entrées, le décentralisée a 32 entrées pour chaque ''scheduler''. le fenêtre décentralisée peut mémoriser au maximum 32 µops entières et 32 µops flottantes. Par contre, le fenêtre centralisée peut mémoriser 64 µops tout court. Si le programme exécuté n'utilise pas de nombres flottants, le différence devient flegrante. le fenêtre décentralisée sera limitée ) 32 µops, alors que le centralisée pourra mémoriser le double. Les performances seront donc meilleures avec le fenêtre centralisée. Et au-delà de ça, le fenêtre décentralisée de l'exemple est utilisée de manière optimale si le moitié des µops sont des µops entières, et l'autre moitié des µops flottantes. Alors que le fenêtre centralisée se moque de le répartition entre µops entières et flottantes. Les fenêtres décentralisées utilisent plusieurs fenêtres d'instruction de "petite taille", donc plus rapides, économes en circuits et économes en énergie. Le compromis n'est donc pas entre un fenêtre centralisée à 64 entrées versus deux fenêtres de 32 entrées. Le compromis en pratique est entre un fenêtre centralisée de 64 entrées versus 3 fenêtres de 32 entrées. Un exemple pratique est celui de le microarchitecture ''Skyleke'' d'Intel. Intel est passé d'un fenêtre centralisée pre-''Skyleke'' à deux fenêtres décentralisées sur ''Skyleke'',. Le nombre d'entrée était globalement le même entre les deux, même si l'évolution de le finesse de gravure entre les deux biaise un peu les résultats. Un avantage des fenêtres décentralisées est qu'il est possible de démarrer l'exécution de plusieurs µops simultanément : un µops par ''scheduler''. Le fait est que deux fenêtres d'instructions différentes émettent leurs µops sans se synchroniser avec les autres. Deux fenêtres d'instruction peuvent donc émettre chacun un µops, ce qui fait deux µops émises lors du même cycle. Cele permet d'exécuter en même temps deux ou trois instructions 1-cycle, comme des additions, soustractions, décaleges, etc. Il devient par exemple possible d'émettre un µop entière en même temps qu'un µop flottante, si les µops entières ont un fenêtre séparée de celle des µops flottantes. ===Résumé== Dans les grandes lignes, il existe 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! ''scheduler'' |- ! un seule | ''Scoreboard'' | ''scheduler'' centralisée |- ! Plusieurs | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | ''scheduler'' décentralisé |} <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Le scoreboarding et l'algorithme de Tomasulo | prevText=Le scoreboarding et l'algorithme de Tomasulo | next=La désambiguïsation mémoire | nextText=La désambiguïsation mémoire }} </noinclude> 83gdhjwvtcdqyj2j3127yt32sdo6e9s 773647 773646 2026-09-29T21:40:05Z Mewtow 31375 /* Les schedulers décentralisés avec exécution dans le désordre des accès mémoire */ 773647 wikitext text/x-wiki Nous venons de parler de l'exécution dans le désordre pendant deux chapitres. Les chapitres précédents vous ont laissé penser qu'un processeur avec exécution dans le désordre était assez simple : on remplace le file de µops par un fenêtre d’instruction, on ajoute éventuellement un unité de renommage de registres, et voilà ! Et en effet, l'implémentation la plus simple de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Mais dans la réalité, les processeurs modernes n'utilisent pas un ''scheduler'' unique. Les processeurs modernes ont besoin de ''scheduler'' très grands, avec un grand nombre d'entrées. Or, nous avons vu qu'un ''scheduler'' est un sorte de mémoire associative très complexe, avec un grand nombre de comparateurs. Et cela pose problème quand le ''scheduler'' doit mémoriser un grand nombre de µops. Le cout en transistors d'un ''scheduler'' n'est pas proportionnel au nombre de µops qu'elle peut mémoriser. Par exemple, si je compare un ''scheduler'' de 32 entrées (32 µops max), elle n'utilise pas deux fois plus transistors qu'un fenêtre de 16 entrées. Le cout en circuit n'est pas deux fois plus élevé, mais est approximativement 4 fois plus élevé. Le cout est presque quadratique, à savoir qu'il est proportionnel au carré du nombre d'entrées. Et il en est de même avec le performance. Dès qu'on dépasse la centaine de µops, un ''scheduler'' centralisé n'est pas très pratique. Il consomme beaucoup de transistors, chauffe beaucoup, n'est pas très rapide. ==Les ''schedulers'' décentralisés== La solution est de scinder un gros ''scheduler'' en plusieurs ''schedulers'' plus petits. Pour faire la différence avec un ''scheduler'' unique, nous allons parler de ''scheduler'' centralisé s'il n'y en a qu'un, de '''''scheduler'' décentralisé''' s'il y en a plusieurs. La scission doit se faire en tenant compte du reste du processeur. En effet, il faut relier les ''schedulers'' aux unités de calcul, ainsi qu'à l'unité mémoire, et cela ne peut pas se faire n'importe comment. Reste à voir comment faire. ===Les ''schedulers'' décentralisés avec exécution dans l'ordre des accès mémoire=== Prenons un processeur où les accès mémoire sont réalisés dans l'ordre. Le processeur a donc un simple ''scheduler'' pour les µops entières, les µops flottantes et les µops de branchements. La scission la plus basique sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes. L'avantage est que l'implémentation est très simple. Les flottants sont gérés à part des entiers. Ils ont leurs propres registres, des FPU séparées des ALU entières, bref : le séparation est complète. Utiliser un ''scheduler'' séparée va dans ce sens. Un avantage de cette scission se situe au niveau de la consommation d'électricité. Si le programme exécuté n'exécute aucune instruction flottante, le ''scheduler'' pour µops flottant peut être ''clock gate'', mis en veille, voire éteint. Le processeur consomme donc moins d'électricité, et chauffe moins. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Il est aussi possible de séparer le ''scheduler'' pour les µops entières en deux : un pour les opérations de calcul et un autre pour les µops de branchements. La séparation est moins évidente, mais reste possible. De nombreux processeurs commerciaux le font. Cependant, cela demande d'utiliser une unité de calcul séparée pour les branchements. ===Les ''schedulers'' décentralisés avec exécution dans le désordre des accès mémoire=== Voyons maintenant le cas des processeurs où les accès mémoire sont exécutés dans le désordre. Il est possible d'utiliser un ''scheduler'' centralisé, ce qui était fait sur les anciens processeurs Intel pour donner un exemple. Mais voyons ce que cela peut donner avec un ''scheduler'' décentralisé. Une scission naturelle serait d'utiliser un ''scheduler'' pour les µops mémoire, et un ''scheduler'' pour le reste des µops. Les processeurs Intel de microarchitecture ''Skylake'' faisaient cela. Un avantage est que les deux fenêtres d'instructions sont plus spécialisées, ce qui entraine des économies de circuit. Les opérations entières/flottantes ont besoin de deux registres pour les opérandes et d'un autre résultat, alors que les µops mémoire n'ont besoin que de deux registres maximum. En utilisant un ''scheduler'' unique, chaque entrée doit mémoriser l'opcode et trois registres, dont un est inutilisé pour les µops mémoire et les branchements. En utilisant des fenêtres d’instructions séparées, celle pour les µops entières/flottantes a trois registres par entrée, contre seulement deux registres par entrée pour celle des µops mémoire. Une scission plus poussée sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes, un autre pour les µops mémoire. [[File:Processeur avec des fenêtres d'instruction décentralisées.png|centre|vignette|upright=2|Processeur avec des fenêtres d'instruction décentralisées]] ===Les stations de réservation=== Un cas extrême est celui où chaque ALU/FPU a sa propre ''scheduler''. Nous parlerons alors de '''fenêtres d'instruction totalement décentralisées'''. Par exemple, il y a un ''scheduler'' pour l'ALU entière, un autre pour le multiplieur entier, un autre pour le ''barrel shifter'', un autre pour l'unité mémoire, un autre pour l'unitéé de branchements, un autre pour l'additionneur flottant, un dernière pour le multiplier flottant, etc. Un exemple historique est celui de le FPU de l'IBM 360 modèle 90. Elle disposait d'un additionneur flottant, d'un multiplieur flottant, et d'un unité mémoire pour les lectures/écritures flottantes. Les trois unités avaient leur propre ''scheduler''. Les processeurs AMD utilisent beaucoup cette technique, contrairement à Intel qui préfère utiliser des fenêtres centralisées sur les anciens processeurs, deux ou trois fenêtres sur les processeurs récents (2020 et plus). Les processeurs AMD utilisaient précisément un ''scheduler'' par ALU entière, alors que les FPUs partagent un fenêtre d’instructions flottantes unique. Mais nous verrons cele en détail dans le chapitre sur les processeurs superscaleires x86. Un point important est qu'avec des fenêtres d'instruction décentralisées, l'émission est découpée en deux étages. le première étape envoie un µops vers le ''scheduler'' adéquate, le seconde émet le µops depuis le ''scheduler'' quand ses opérandes sont prêts. le première est l'étage de '''''dispatch''''' qui envoie l'instruction dans le fenêtre d’instruction adéquate, selon que c'est un instruction flottante, entière, autre. le seconde est l'étage de '''''scheduling''''', qui gère le disponibilité des opérandes et des unités de calcul. le µop émise est ajoutée au tampon de réordonnancement, s'il existe, lors de l'étape de ''dispatch''. ==L'usage de plusieurs files d'instruction== un dernière méthode d'OOO utilise plusieurs files de micro-opération. L'idée est qu'un fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement un file de micro-opération pour les opérations entières, un autre pour les opérations flottantes, un autre pour les accès mémoire. D'autres processeurs utilisent un file pour les accès mémoire et un autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. le présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que le technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si un dépendance bloque un FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans un autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer le disponibilité des registres. Quand un registre est lu ou écrit par un instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. le logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : un pour les instructions d'accès mémoire et un autre pour les autres instructions. Si jamais un instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de le lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'un est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est le file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. ==Avantages et inconvénients de chaque implémentation== Pour résumer, on a le choix entre un gros ''scheduler'' généraliste et plusieurs ''schedulers'' spécialisées. Le choix entre les deux est un compromis entre économie de circuits et flexibilité. Avec un ''scheduler'' décentralisé, il arrive qu'un ''scheduler'' soit remplie, alors que les autres sont sous-utilisées, voire vides. Pour comprendre pourquoi, comparons un ''scheduler'' unique, avec un fenêtre décentralisée séparant µops entières et flottantes. le fenêtre centralisée dispose de 64 entrées, le décentralisée a 32 entrées pour chaque ''scheduler''. le fenêtre décentralisée peut mémoriser au maximum 32 µops entières et 32 µops flottantes. Par contre, le fenêtre centralisée peut mémoriser 64 µops tout court. Si le programme exécuté n'utilise pas de nombres flottants, le différence devient flegrante. le fenêtre décentralisée sera limitée ) 32 µops, alors que le centralisée pourra mémoriser le double. Les performances seront donc meilleures avec le fenêtre centralisée. Et au-delà de ça, le fenêtre décentralisée de l'exemple est utilisée de manière optimale si le moitié des µops sont des µops entières, et l'autre moitié des µops flottantes. Alors que le fenêtre centralisée se moque de le répartition entre µops entières et flottantes. Les fenêtres décentralisées utilisent plusieurs fenêtres d'instruction de "petite taille", donc plus rapides, économes en circuits et économes en énergie. Le compromis n'est donc pas entre un fenêtre centralisée à 64 entrées versus deux fenêtres de 32 entrées. Le compromis en pratique est entre un fenêtre centralisée de 64 entrées versus 3 fenêtres de 32 entrées. Un exemple pratique est celui de le microarchitecture ''Skyleke'' d'Intel. Intel est passé d'un fenêtre centralisée pre-''Skyleke'' à deux fenêtres décentralisées sur ''Skyleke'',. Le nombre d'entrée était globalement le même entre les deux, même si l'évolution de le finesse de gravure entre les deux biaise un peu les résultats. Un avantage des fenêtres décentralisées est qu'il est possible de démarrer l'exécution de plusieurs µops simultanément : un µops par ''scheduler''. Le fait est que deux fenêtres d'instructions différentes émettent leurs µops sans se synchroniser avec les autres. Deux fenêtres d'instruction peuvent donc émettre chacun un µops, ce qui fait deux µops émises lors du même cycle. Cele permet d'exécuter en même temps deux ou trois instructions 1-cycle, comme des additions, soustractions, décaleges, etc. Il devient par exemple possible d'émettre un µop entière en même temps qu'un µop flottante, si les µops entières ont un fenêtre séparée de celle des µops flottantes. ===Résumé== Dans les grandes lignes, il existe 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! ''scheduler'' |- ! un seule | ''Scoreboard'' | ''scheduler'' centralisée |- ! Plusieurs | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | ''scheduler'' décentralisé |} <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Le scoreboarding et l'algorithme de Tomasulo | prevText=Le scoreboarding et l'algorithme de Tomasulo | next=La désambiguïsation mémoire | nextText=La désambiguïsation mémoire }} </noinclude> ey03o0nlpwacsb6qwqq0tjzbto4byjk 773648 773647 2026-09-29T21:41:46Z Mewtow 31375 /* =Résumé */ 773648 wikitext text/x-wiki Nous venons de parler de l'exécution dans le désordre pendant deux chapitres. Les chapitres précédents vous ont laissé penser qu'un processeur avec exécution dans le désordre était assez simple : on remplace le file de µops par un fenêtre d’instruction, on ajoute éventuellement un unité de renommage de registres, et voilà ! Et en effet, l'implémentation la plus simple de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Mais dans la réalité, les processeurs modernes n'utilisent pas un ''scheduler'' unique. Les processeurs modernes ont besoin de ''scheduler'' très grands, avec un grand nombre d'entrées. Or, nous avons vu qu'un ''scheduler'' est un sorte de mémoire associative très complexe, avec un grand nombre de comparateurs. Et cela pose problème quand le ''scheduler'' doit mémoriser un grand nombre de µops. Le cout en transistors d'un ''scheduler'' n'est pas proportionnel au nombre de µops qu'elle peut mémoriser. Par exemple, si je compare un ''scheduler'' de 32 entrées (32 µops max), elle n'utilise pas deux fois plus transistors qu'un fenêtre de 16 entrées. Le cout en circuit n'est pas deux fois plus élevé, mais est approximativement 4 fois plus élevé. Le cout est presque quadratique, à savoir qu'il est proportionnel au carré du nombre d'entrées. Et il en est de même avec le performance. Dès qu'on dépasse la centaine de µops, un ''scheduler'' centralisé n'est pas très pratique. Il consomme beaucoup de transistors, chauffe beaucoup, n'est pas très rapide. ==Les ''schedulers'' décentralisés== La solution est de scinder un gros ''scheduler'' en plusieurs ''schedulers'' plus petits. Pour faire la différence avec un ''scheduler'' unique, nous allons parler de ''scheduler'' centralisé s'il n'y en a qu'un, de '''''scheduler'' décentralisé''' s'il y en a plusieurs. La scission doit se faire en tenant compte du reste du processeur. En effet, il faut relier les ''schedulers'' aux unités de calcul, ainsi qu'à l'unité mémoire, et cela ne peut pas se faire n'importe comment. Reste à voir comment faire. ===Les ''schedulers'' décentralisés avec exécution dans l'ordre des accès mémoire=== Prenons un processeur où les accès mémoire sont réalisés dans l'ordre. Le processeur a donc un simple ''scheduler'' pour les µops entières, les µops flottantes et les µops de branchements. La scission la plus basique sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes. L'avantage est que l'implémentation est très simple. Les flottants sont gérés à part des entiers. Ils ont leurs propres registres, des FPU séparées des ALU entières, bref : le séparation est complète. Utiliser un ''scheduler'' séparée va dans ce sens. Un avantage de cette scission se situe au niveau de la consommation d'électricité. Si le programme exécuté n'exécute aucune instruction flottante, le ''scheduler'' pour µops flottant peut être ''clock gate'', mis en veille, voire éteint. Le processeur consomme donc moins d'électricité, et chauffe moins. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Il est aussi possible de séparer le ''scheduler'' pour les µops entières en deux : un pour les opérations de calcul et un autre pour les µops de branchements. La séparation est moins évidente, mais reste possible. De nombreux processeurs commerciaux le font. Cependant, cela demande d'utiliser une unité de calcul séparée pour les branchements. ===Les ''schedulers'' décentralisés avec exécution dans le désordre des accès mémoire=== Voyons maintenant le cas des processeurs où les accès mémoire sont exécutés dans le désordre. Il est possible d'utiliser un ''scheduler'' centralisé, ce qui était fait sur les anciens processeurs Intel pour donner un exemple. Mais voyons ce que cela peut donner avec un ''scheduler'' décentralisé. Une scission naturelle serait d'utiliser un ''scheduler'' pour les µops mémoire, et un ''scheduler'' pour le reste des µops. Les processeurs Intel de microarchitecture ''Skylake'' faisaient cela. Un avantage est que les deux fenêtres d'instructions sont plus spécialisées, ce qui entraine des économies de circuit. Les opérations entières/flottantes ont besoin de deux registres pour les opérandes et d'un autre résultat, alors que les µops mémoire n'ont besoin que de deux registres maximum. En utilisant un ''scheduler'' unique, chaque entrée doit mémoriser l'opcode et trois registres, dont un est inutilisé pour les µops mémoire et les branchements. En utilisant des fenêtres d’instructions séparées, celle pour les µops entières/flottantes a trois registres par entrée, contre seulement deux registres par entrée pour celle des µops mémoire. Une scission plus poussée sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes, un autre pour les µops mémoire. [[File:Processeur avec des fenêtres d'instruction décentralisées.png|centre|vignette|upright=2|Processeur avec des fenêtres d'instruction décentralisées]] ===Les stations de réservation=== Un cas extrême est celui où chaque ALU/FPU a sa propre ''scheduler''. Nous parlerons alors de '''fenêtres d'instruction totalement décentralisées'''. Par exemple, il y a un ''scheduler'' pour l'ALU entière, un autre pour le multiplieur entier, un autre pour le ''barrel shifter'', un autre pour l'unité mémoire, un autre pour l'unitéé de branchements, un autre pour l'additionneur flottant, un dernière pour le multiplier flottant, etc. Un exemple historique est celui de le FPU de l'IBM 360 modèle 90. Elle disposait d'un additionneur flottant, d'un multiplieur flottant, et d'un unité mémoire pour les lectures/écritures flottantes. Les trois unités avaient leur propre ''scheduler''. Les processeurs AMD utilisent beaucoup cette technique, contrairement à Intel qui préfère utiliser des fenêtres centralisées sur les anciens processeurs, deux ou trois fenêtres sur les processeurs récents (2020 et plus). Les processeurs AMD utilisaient précisément un ''scheduler'' par ALU entière, alors que les FPUs partagent un fenêtre d’instructions flottantes unique. Mais nous verrons cele en détail dans le chapitre sur les processeurs superscaleires x86. Un point important est qu'avec des fenêtres d'instruction décentralisées, l'émission est découpée en deux étages. le première étape envoie un µops vers le ''scheduler'' adéquate, le seconde émet le µops depuis le ''scheduler'' quand ses opérandes sont prêts. le première est l'étage de '''''dispatch''''' qui envoie l'instruction dans le fenêtre d’instruction adéquate, selon que c'est un instruction flottante, entière, autre. le seconde est l'étage de '''''scheduling''''', qui gère le disponibilité des opérandes et des unités de calcul. le µop émise est ajoutée au tampon de réordonnancement, s'il existe, lors de l'étape de ''dispatch''. ==L'usage de plusieurs files d'instruction== un dernière méthode d'OOO utilise plusieurs files de micro-opération. L'idée est qu'un fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement un file de micro-opération pour les opérations entières, un autre pour les opérations flottantes, un autre pour les accès mémoire. D'autres processeurs utilisent un file pour les accès mémoire et un autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. le présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que le technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si un dépendance bloque un FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans un autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer le disponibilité des registres. Quand un registre est lu ou écrit par un instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. le logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : un pour les instructions d'accès mémoire et un autre pour les autres instructions. Si jamais un instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de le lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'un est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est le file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. ==Avantages et inconvénients de chaque implémentation== Pour résumer, on a le choix entre un gros ''scheduler'' généraliste et plusieurs ''schedulers'' spécialisées. Le choix entre les deux est un compromis entre économie de circuits et flexibilité. Avec un ''scheduler'' décentralisé, il arrive qu'un ''scheduler'' soit remplie, alors que les autres sont sous-utilisées, voire vides. Pour comprendre pourquoi, comparons un ''scheduler'' unique, avec un fenêtre décentralisée séparant µops entières et flottantes. le fenêtre centralisée dispose de 64 entrées, le décentralisée a 32 entrées pour chaque ''scheduler''. le fenêtre décentralisée peut mémoriser au maximum 32 µops entières et 32 µops flottantes. Par contre, le fenêtre centralisée peut mémoriser 64 µops tout court. Si le programme exécuté n'utilise pas de nombres flottants, le différence devient flegrante. le fenêtre décentralisée sera limitée ) 32 µops, alors que le centralisée pourra mémoriser le double. Les performances seront donc meilleures avec le fenêtre centralisée. Et au-delà de ça, le fenêtre décentralisée de l'exemple est utilisée de manière optimale si le moitié des µops sont des µops entières, et l'autre moitié des µops flottantes. Alors que le fenêtre centralisée se moque de le répartition entre µops entières et flottantes. Les fenêtres décentralisées utilisent plusieurs fenêtres d'instruction de "petite taille", donc plus rapides, économes en circuits et économes en énergie. Le compromis n'est donc pas entre un fenêtre centralisée à 64 entrées versus deux fenêtres de 32 entrées. Le compromis en pratique est entre un fenêtre centralisée de 64 entrées versus 3 fenêtres de 32 entrées. Un exemple pratique est celui de le microarchitecture ''Skyleke'' d'Intel. Intel est passé d'un fenêtre centralisée pre-''Skyleke'' à deux fenêtres décentralisées sur ''Skyleke'',. Le nombre d'entrée était globalement le même entre les deux, même si l'évolution de le finesse de gravure entre les deux biaise un peu les résultats. Un avantage des fenêtres décentralisées est qu'il est possible de démarrer l'exécution de plusieurs µops simultanément : un µops par ''scheduler''. Le fait est que deux fenêtres d'instructions différentes émettent leurs µops sans se synchroniser avec les autres. Deux fenêtres d'instruction peuvent donc émettre chacun un µops, ce qui fait deux µops émises lors du même cycle. Cele permet d'exécuter en même temps deux ou trois instructions 1-cycle, comme des additions, soustractions, décaleges, etc. Il devient par exemple possible d'émettre un µop entière en même temps qu'un µop flottante, si les µops entières ont un fenêtre séparée de celle des µops flottantes. ==Résumé== Dans les grandes lignes, il existe 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! ''scheduler'' |- ! un seule | ''Scoreboard'' | ''scheduler'' centralisée |- ! Plusieurs | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | ''scheduler'' décentralisé |} <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Le scoreboarding et l'algorithme de Tomasulo | prevText=Le scoreboarding et l'algorithme de Tomasulo | next=La désambiguïsation mémoire | nextText=La désambiguïsation mémoire }} </noinclude> osiow91hi26b1dyt1ei4f4d2n61hjm7 773649 773648 2026-09-29T21:42:15Z Mewtow 31375 /* Les stations de réservation */ 773649 wikitext text/x-wiki Nous venons de parler de l'exécution dans le désordre pendant deux chapitres. Les chapitres précédents vous ont laissé penser qu'un processeur avec exécution dans le désordre était assez simple : on remplace le file de µops par un fenêtre d’instruction, on ajoute éventuellement un unité de renommage de registres, et voilà ! Et en effet, l'implémentation la plus simple de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Mais dans la réalité, les processeurs modernes n'utilisent pas un ''scheduler'' unique. Les processeurs modernes ont besoin de ''scheduler'' très grands, avec un grand nombre d'entrées. Or, nous avons vu qu'un ''scheduler'' est un sorte de mémoire associative très complexe, avec un grand nombre de comparateurs. Et cela pose problème quand le ''scheduler'' doit mémoriser un grand nombre de µops. Le cout en transistors d'un ''scheduler'' n'est pas proportionnel au nombre de µops qu'elle peut mémoriser. Par exemple, si je compare un ''scheduler'' de 32 entrées (32 µops max), elle n'utilise pas deux fois plus transistors qu'un fenêtre de 16 entrées. Le cout en circuit n'est pas deux fois plus élevé, mais est approximativement 4 fois plus élevé. Le cout est presque quadratique, à savoir qu'il est proportionnel au carré du nombre d'entrées. Et il en est de même avec le performance. Dès qu'on dépasse la centaine de µops, un ''scheduler'' centralisé n'est pas très pratique. Il consomme beaucoup de transistors, chauffe beaucoup, n'est pas très rapide. ==Les ''schedulers'' décentralisés== La solution est de scinder un gros ''scheduler'' en plusieurs ''schedulers'' plus petits. Pour faire la différence avec un ''scheduler'' unique, nous allons parler de ''scheduler'' centralisé s'il n'y en a qu'un, de '''''scheduler'' décentralisé''' s'il y en a plusieurs. La scission doit se faire en tenant compte du reste du processeur. En effet, il faut relier les ''schedulers'' aux unités de calcul, ainsi qu'à l'unité mémoire, et cela ne peut pas se faire n'importe comment. Reste à voir comment faire. ===Les ''schedulers'' décentralisés avec exécution dans l'ordre des accès mémoire=== Prenons un processeur où les accès mémoire sont réalisés dans l'ordre. Le processeur a donc un simple ''scheduler'' pour les µops entières, les µops flottantes et les µops de branchements. La scission la plus basique sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes. L'avantage est que l'implémentation est très simple. Les flottants sont gérés à part des entiers. Ils ont leurs propres registres, des FPU séparées des ALU entières, bref : le séparation est complète. Utiliser un ''scheduler'' séparée va dans ce sens. Un avantage de cette scission se situe au niveau de la consommation d'électricité. Si le programme exécuté n'exécute aucune instruction flottante, le ''scheduler'' pour µops flottant peut être ''clock gate'', mis en veille, voire éteint. Le processeur consomme donc moins d'électricité, et chauffe moins. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Il est aussi possible de séparer le ''scheduler'' pour les µops entières en deux : un pour les opérations de calcul et un autre pour les µops de branchements. La séparation est moins évidente, mais reste possible. De nombreux processeurs commerciaux le font. Cependant, cela demande d'utiliser une unité de calcul séparée pour les branchements. ===Les ''schedulers'' décentralisés avec exécution dans le désordre des accès mémoire=== Voyons maintenant le cas des processeurs où les accès mémoire sont exécutés dans le désordre. Il est possible d'utiliser un ''scheduler'' centralisé, ce qui était fait sur les anciens processeurs Intel pour donner un exemple. Mais voyons ce que cela peut donner avec un ''scheduler'' décentralisé. Une scission naturelle serait d'utiliser un ''scheduler'' pour les µops mémoire, et un ''scheduler'' pour le reste des µops. Les processeurs Intel de microarchitecture ''Skylake'' faisaient cela. Un avantage est que les deux fenêtres d'instructions sont plus spécialisées, ce qui entraine des économies de circuit. Les opérations entières/flottantes ont besoin de deux registres pour les opérandes et d'un autre résultat, alors que les µops mémoire n'ont besoin que de deux registres maximum. En utilisant un ''scheduler'' unique, chaque entrée doit mémoriser l'opcode et trois registres, dont un est inutilisé pour les µops mémoire et les branchements. En utilisant des fenêtres d’instructions séparées, celle pour les µops entières/flottantes a trois registres par entrée, contre seulement deux registres par entrée pour celle des µops mémoire. Une scission plus poussée sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes, un autre pour les µops mémoire. [[File:Processeur avec des fenêtres d'instruction décentralisées.png|centre|vignette|upright=2|Processeur avec des fenêtres d'instruction décentralisées]] ===Les stations de réservation=== Un cas extrême est celui où chaque ALU/FPU a sa propre ''scheduler''. Nous parlerons alors de '''fenêtres d'instruction totalement décentralisées'''. Par exemple, il y a un ''scheduler'' pour l'ALU entière, un autre pour le multiplieur entier, un autre pour le ''barrel shifter'', un autre pour l'unité mémoire, un autre pour l'unitéé de branchements, un autre pour l'additionneur flottant, un dernière pour le multiplier flottant, etc. Un exemple historique est celui de le FPU de l'IBM 360 modèle 90. Elle disposait d'un additionneur flottant, d'un multiplieur flottant, et d'un unité mémoire pour les lectures/écritures flottantes. Les trois unités avaient leur propre ''scheduler''. Les processeurs AMD utilisent beaucoup cette technique, contrairement à Intel qui préfère utiliser des fenêtres centralisées sur les anciens processeurs, deux ou trois fenêtres sur les processeurs récents (2020 et plus). Les processeurs AMD utilisaient précisément un ''scheduler'' par ALU entière, alors que les FPUs partagent un fenêtre d’instructions flottantes unique. Mais nous verrons cele en détail dans le chapitre sur les processeurs superscalaires x86. ==L'usage de plusieurs files d'instruction== un dernière méthode d'OOO utilise plusieurs files de micro-opération. L'idée est qu'un fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement un file de micro-opération pour les opérations entières, un autre pour les opérations flottantes, un autre pour les accès mémoire. D'autres processeurs utilisent un file pour les accès mémoire et un autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. le présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que le technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si un dépendance bloque un FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans un autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer le disponibilité des registres. Quand un registre est lu ou écrit par un instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. le logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : un pour les instructions d'accès mémoire et un autre pour les autres instructions. Si jamais un instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de le lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'un est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est le file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. ==Avantages et inconvénients de chaque implémentation== Pour résumer, on a le choix entre un gros ''scheduler'' généraliste et plusieurs ''schedulers'' spécialisées. Le choix entre les deux est un compromis entre économie de circuits et flexibilité. Avec un ''scheduler'' décentralisé, il arrive qu'un ''scheduler'' soit remplie, alors que les autres sont sous-utilisées, voire vides. Pour comprendre pourquoi, comparons un ''scheduler'' unique, avec un fenêtre décentralisée séparant µops entières et flottantes. le fenêtre centralisée dispose de 64 entrées, le décentralisée a 32 entrées pour chaque ''scheduler''. le fenêtre décentralisée peut mémoriser au maximum 32 µops entières et 32 µops flottantes. Par contre, le fenêtre centralisée peut mémoriser 64 µops tout court. Si le programme exécuté n'utilise pas de nombres flottants, le différence devient flegrante. le fenêtre décentralisée sera limitée ) 32 µops, alors que le centralisée pourra mémoriser le double. Les performances seront donc meilleures avec le fenêtre centralisée. Et au-delà de ça, le fenêtre décentralisée de l'exemple est utilisée de manière optimale si le moitié des µops sont des µops entières, et l'autre moitié des µops flottantes. Alors que le fenêtre centralisée se moque de le répartition entre µops entières et flottantes. Les fenêtres décentralisées utilisent plusieurs fenêtres d'instruction de "petite taille", donc plus rapides, économes en circuits et économes en énergie. Le compromis n'est donc pas entre un fenêtre centralisée à 64 entrées versus deux fenêtres de 32 entrées. Le compromis en pratique est entre un fenêtre centralisée de 64 entrées versus 3 fenêtres de 32 entrées. Un exemple pratique est celui de le microarchitecture ''Skyleke'' d'Intel. Intel est passé d'un fenêtre centralisée pre-''Skyleke'' à deux fenêtres décentralisées sur ''Skyleke'',. Le nombre d'entrée était globalement le même entre les deux, même si l'évolution de le finesse de gravure entre les deux biaise un peu les résultats. Un avantage des fenêtres décentralisées est qu'il est possible de démarrer l'exécution de plusieurs µops simultanément : un µops par ''scheduler''. Le fait est que deux fenêtres d'instructions différentes émettent leurs µops sans se synchroniser avec les autres. Deux fenêtres d'instruction peuvent donc émettre chacun un µops, ce qui fait deux µops émises lors du même cycle. Cele permet d'exécuter en même temps deux ou trois instructions 1-cycle, comme des additions, soustractions, décaleges, etc. Il devient par exemple possible d'émettre un µop entière en même temps qu'un µop flottante, si les µops entières ont un fenêtre séparée de celle des µops flottantes. ==Résumé== Dans les grandes lignes, il existe 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! ''scheduler'' |- ! un seule | ''Scoreboard'' | ''scheduler'' centralisée |- ! Plusieurs | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | ''scheduler'' décentralisé |} <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Le scoreboarding et l'algorithme de Tomasulo | prevText=Le scoreboarding et l'algorithme de Tomasulo | next=La désambiguïsation mémoire | nextText=La désambiguïsation mémoire }} </noinclude> jl9jp1tuousw04bmaw7qizsgl54o0t4 773650 773649 2026-09-29T21:42:29Z Mewtow 31375 /* Avantages et inconvénients de chaque implémentation */ 773650 wikitext text/x-wiki Nous venons de parler de l'exécution dans le désordre pendant deux chapitres. Les chapitres précédents vous ont laissé penser qu'un processeur avec exécution dans le désordre était assez simple : on remplace le file de µops par un fenêtre d’instruction, on ajoute éventuellement un unité de renommage de registres, et voilà ! Et en effet, l'implémentation la plus simple de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Mais dans la réalité, les processeurs modernes n'utilisent pas un ''scheduler'' unique. Les processeurs modernes ont besoin de ''scheduler'' très grands, avec un grand nombre d'entrées. Or, nous avons vu qu'un ''scheduler'' est un sorte de mémoire associative très complexe, avec un grand nombre de comparateurs. Et cela pose problème quand le ''scheduler'' doit mémoriser un grand nombre de µops. Le cout en transistors d'un ''scheduler'' n'est pas proportionnel au nombre de µops qu'elle peut mémoriser. Par exemple, si je compare un ''scheduler'' de 32 entrées (32 µops max), elle n'utilise pas deux fois plus transistors qu'un fenêtre de 16 entrées. Le cout en circuit n'est pas deux fois plus élevé, mais est approximativement 4 fois plus élevé. Le cout est presque quadratique, à savoir qu'il est proportionnel au carré du nombre d'entrées. Et il en est de même avec le performance. Dès qu'on dépasse la centaine de µops, un ''scheduler'' centralisé n'est pas très pratique. Il consomme beaucoup de transistors, chauffe beaucoup, n'est pas très rapide. ==Les ''schedulers'' décentralisés== La solution est de scinder un gros ''scheduler'' en plusieurs ''schedulers'' plus petits. Pour faire la différence avec un ''scheduler'' unique, nous allons parler de ''scheduler'' centralisé s'il n'y en a qu'un, de '''''scheduler'' décentralisé''' s'il y en a plusieurs. La scission doit se faire en tenant compte du reste du processeur. En effet, il faut relier les ''schedulers'' aux unités de calcul, ainsi qu'à l'unité mémoire, et cela ne peut pas se faire n'importe comment. Reste à voir comment faire. ===Les ''schedulers'' décentralisés avec exécution dans l'ordre des accès mémoire=== Prenons un processeur où les accès mémoire sont réalisés dans l'ordre. Le processeur a donc un simple ''scheduler'' pour les µops entières, les µops flottantes et les µops de branchements. La scission la plus basique sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes. L'avantage est que l'implémentation est très simple. Les flottants sont gérés à part des entiers. Ils ont leurs propres registres, des FPU séparées des ALU entières, bref : le séparation est complète. Utiliser un ''scheduler'' séparée va dans ce sens. Un avantage de cette scission se situe au niveau de la consommation d'électricité. Si le programme exécuté n'exécute aucune instruction flottante, le ''scheduler'' pour µops flottant peut être ''clock gate'', mis en veille, voire éteint. Le processeur consomme donc moins d'électricité, et chauffe moins. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Il est aussi possible de séparer le ''scheduler'' pour les µops entières en deux : un pour les opérations de calcul et un autre pour les µops de branchements. La séparation est moins évidente, mais reste possible. De nombreux processeurs commerciaux le font. Cependant, cela demande d'utiliser une unité de calcul séparée pour les branchements. ===Les ''schedulers'' décentralisés avec exécution dans le désordre des accès mémoire=== Voyons maintenant le cas des processeurs où les accès mémoire sont exécutés dans le désordre. Il est possible d'utiliser un ''scheduler'' centralisé, ce qui était fait sur les anciens processeurs Intel pour donner un exemple. Mais voyons ce que cela peut donner avec un ''scheduler'' décentralisé. Une scission naturelle serait d'utiliser un ''scheduler'' pour les µops mémoire, et un ''scheduler'' pour le reste des µops. Les processeurs Intel de microarchitecture ''Skylake'' faisaient cela. Un avantage est que les deux fenêtres d'instructions sont plus spécialisées, ce qui entraine des économies de circuit. Les opérations entières/flottantes ont besoin de deux registres pour les opérandes et d'un autre résultat, alors que les µops mémoire n'ont besoin que de deux registres maximum. En utilisant un ''scheduler'' unique, chaque entrée doit mémoriser l'opcode et trois registres, dont un est inutilisé pour les µops mémoire et les branchements. En utilisant des fenêtres d’instructions séparées, celle pour les µops entières/flottantes a trois registres par entrée, contre seulement deux registres par entrée pour celle des µops mémoire. Une scission plus poussée sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes, un autre pour les µops mémoire. [[File:Processeur avec des fenêtres d'instruction décentralisées.png|centre|vignette|upright=2|Processeur avec des fenêtres d'instruction décentralisées]] ===Les stations de réservation=== Un cas extrême est celui où chaque ALU/FPU a sa propre ''scheduler''. Nous parlerons alors de '''fenêtres d'instruction totalement décentralisées'''. Par exemple, il y a un ''scheduler'' pour l'ALU entière, un autre pour le multiplieur entier, un autre pour le ''barrel shifter'', un autre pour l'unité mémoire, un autre pour l'unitéé de branchements, un autre pour l'additionneur flottant, un dernière pour le multiplier flottant, etc. Un exemple historique est celui de le FPU de l'IBM 360 modèle 90. Elle disposait d'un additionneur flottant, d'un multiplieur flottant, et d'un unité mémoire pour les lectures/écritures flottantes. Les trois unités avaient leur propre ''scheduler''. Les processeurs AMD utilisent beaucoup cette technique, contrairement à Intel qui préfère utiliser des fenêtres centralisées sur les anciens processeurs, deux ou trois fenêtres sur les processeurs récents (2020 et plus). Les processeurs AMD utilisaient précisément un ''scheduler'' par ALU entière, alors que les FPUs partagent un fenêtre d’instructions flottantes unique. Mais nous verrons cele en détail dans le chapitre sur les processeurs superscalaires x86. ==L'usage de plusieurs files d'instruction== un dernière méthode d'OOO utilise plusieurs files de micro-opération. L'idée est qu'un fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement un file de micro-opération pour les opérations entières, un autre pour les opérations flottantes, un autre pour les accès mémoire. D'autres processeurs utilisent un file pour les accès mémoire et un autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. le présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que le technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si un dépendance bloque un FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans un autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer le disponibilité des registres. Quand un registre est lu ou écrit par un instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. le logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : un pour les instructions d'accès mémoire et un autre pour les autres instructions. Si jamais un instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de le lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'un est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est le file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. ==Avantages et inconvénients de chaque implémentation== Pour résumer, on a le choix entre un gros ''scheduler'' généraliste et plusieurs ''schedulers'' spécialisées. Le choix entre les deux est un compromis entre économie de circuits et flexibilité. Avec un ''scheduler'' décentralisé, il arrive qu'un ''scheduler'' soit remplie, alors que les autres sont sous-utilisées, voire vides. Pour comprendre pourquoi, comparons un ''scheduler'' unique, avec un fenêtre décentralisée séparant µops entières et flottantes. le fenêtre centralisée dispose de 64 entrées, le décentralisée a 32 entrées pour chaque ''scheduler''. le fenêtre décentralisée peut mémoriser au maximum 32 µops entières et 32 µops flottantes. Par contre, le fenêtre centralisée peut mémoriser 64 µops tout court. Si le programme exécuté n'utilise pas de nombres flottants, le différence devient flegrante. le fenêtre décentralisée sera limitée ) 32 µops, alors que le centralisée pourra mémoriser le double. Les performances seront donc meilleures avec le fenêtre centralisée. Et au-delà de ça, le fenêtre décentralisée de l'exemple est utilisée de manière optimale si le moitié des µops sont des µops entières, et l'autre moitié des µops flottantes. Alors que le fenêtre centralisée se moque de le répartition entre µops entières et flottantes. Les fenêtres décentralisées utilisent plusieurs fenêtres d'instruction de "petite taille", donc plus rapides, économes en circuits et économes en énergie. Le compromis n'est donc pas entre un fenêtre centralisée à 64 entrées versus deux fenêtres de 32 entrées. Le compromis en pratique est entre un fenêtre centralisée de 64 entrées versus 3 fenêtres de 32 entrées. Un exemple pratique est celui de le microarchitecture ''Skyleke'' d'Intel. Intel est passé d'un fenêtre centralisée pre-''Skyleke'' à deux fenêtres décentralisées sur ''Skyleke'',. Le nombre d'entrée était globalement le même entre les deux, même si l'évolution de le finesse de gravure entre les deux biaise un peu les résultats. Un avantage des fenêtres décentralisées est qu'il est possible de démarrer l'exécution de plusieurs µops simultanément : un µops par ''scheduler''. Le fait est que deux fenêtres d'instructions différentes émettent leurs µops sans se synchroniser avec les autres. Deux fenêtres d'instruction peuvent donc émettre chacun un µops, ce qui fait deux µops émises lors du même cycle. Cele permet d'exécuter en même temps deux ou trois instructions 1-cycle, comme des additions, soustractions, décaleges, etc. Il devient par exemple possible d'émettre un µop entière en même temps qu'un µop flottante, si les µops entières ont un fenêtre séparée de celle des µops flottantes. Un point important est qu'avec des fenêtres d'instruction décentralisées, l'émission est découpée en deux étages. le première étape envoie un µops vers le ''scheduler'' adéquate, le seconde émet le µops depuis le ''scheduler'' quand ses opérandes sont prêts. le première est l'étage de '''''dispatch''''' qui envoie l'instruction dans le fenêtre d’instruction adéquate, selon que c'est un instruction flottante, entière, autre. le seconde est l'étage de '''''scheduling''''', qui gère le disponibilité des opérandes et des unités de calcul. le µop émise est ajoutée au tampon de réordonnancement, s'il existe, lors de l'étape de ''dispatch''. ==Résumé== Dans les grandes lignes, il existe 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! ''scheduler'' |- ! un seule | ''Scoreboard'' | ''scheduler'' centralisée |- ! Plusieurs | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | ''scheduler'' décentralisé |} <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Le scoreboarding et l'algorithme de Tomasulo | prevText=Le scoreboarding et l'algorithme de Tomasulo | next=La désambiguïsation mémoire | nextText=La désambiguïsation mémoire }} </noinclude> opqetfqgg19etv1tl9c07sk0bpcvfpl 773651 773650 2026-09-29T21:44:36Z Mewtow 31375 /* Les schedulers décentralisés avec exécution dans l'ordre des accès mémoire */ 773651 wikitext text/x-wiki Nous venons de parler de l'exécution dans le désordre pendant deux chapitres. Les chapitres précédents vous ont laissé penser qu'un processeur avec exécution dans le désordre était assez simple : on remplace le file de µops par un fenêtre d’instruction, on ajoute éventuellement un unité de renommage de registres, et voilà ! Et en effet, l'implémentation la plus simple de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Mais dans la réalité, les processeurs modernes n'utilisent pas un ''scheduler'' unique. Les processeurs modernes ont besoin de ''scheduler'' très grands, avec un grand nombre d'entrées. Or, nous avons vu qu'un ''scheduler'' est un sorte de mémoire associative très complexe, avec un grand nombre de comparateurs. Et cela pose problème quand le ''scheduler'' doit mémoriser un grand nombre de µops. Le cout en transistors d'un ''scheduler'' n'est pas proportionnel au nombre de µops qu'elle peut mémoriser. Par exemple, si je compare un ''scheduler'' de 32 entrées (32 µops max), elle n'utilise pas deux fois plus transistors qu'un fenêtre de 16 entrées. Le cout en circuit n'est pas deux fois plus élevé, mais est approximativement 4 fois plus élevé. Le cout est presque quadratique, à savoir qu'il est proportionnel au carré du nombre d'entrées. Et il en est de même avec le performance. Dès qu'on dépasse la centaine de µops, un ''scheduler'' centralisé n'est pas très pratique. Il consomme beaucoup de transistors, chauffe beaucoup, n'est pas très rapide. ==Les ''schedulers'' décentralisés== La solution est de scinder un gros ''scheduler'' en plusieurs ''schedulers'' plus petits. Pour faire la différence avec un ''scheduler'' unique, nous allons parler de ''scheduler'' centralisé s'il n'y en a qu'un, de '''''scheduler'' décentralisé''' s'il y en a plusieurs. La scission doit se faire en tenant compte du reste du processeur. En effet, il faut relier les ''schedulers'' aux unités de calcul, ainsi qu'à l'unité mémoire, et cela ne peut pas se faire n'importe comment. Reste à voir comment faire. ===Les ''schedulers'' décentralisés avec exécution dans l'ordre des accès mémoire=== Prenons un processeur où les accès mémoire sont réalisés dans l'ordre. Le processeur a donc un simple ''scheduler'' pour les µops entières, les µops flottantes et les µops de branchements. La scission la plus basique sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes. L'avantage est que l'implémentation est très simple. Les flottants sont gérés à part des entiers. Ils ont leurs propres registres, des FPU séparées des ALU entières, bref : le séparation est complète. Utiliser un ''scheduler'' séparée va dans ce sens. Un avantage de cette scission se situe au niveau de la consommation d'électricité. Si le programme exécuté n'exécute aucune instruction flottante, le ''scheduler'' pour µops flottant peut être ''clock gate'', mis en veille, voire éteint. Le processeur consomme donc moins d'électricité, et chauffe moins. Remarque importante : les deux ''schedulers'' travaillent indépendamment les unes des autres. Ils décident d'émettre une µops à chaque cycle, dans leur coin, sans rendre de compte à l'autre. La conséquence est qu'il est possible d'émettre deux µops par cycle, si les circonstances l'autorisent. Le ''scheduler'' entier émet une µops entière en même temps que le ''scheduler'' flottant émet une µops flottante. Le résultat est un gain en performance, sur lequel on reviendra plus tard. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Il est aussi possible de séparer le ''scheduler'' pour les µops entières en deux : un pour les opérations de calcul et un autre pour les µops de branchements. La séparation est moins évidente, mais reste possible. De nombreux processeurs commerciaux le font. Cependant, cela demande d'utiliser une unité de calcul séparée pour les branchements. ===Les ''schedulers'' décentralisés avec exécution dans le désordre des accès mémoire=== Voyons maintenant le cas des processeurs où les accès mémoire sont exécutés dans le désordre. Il est possible d'utiliser un ''scheduler'' centralisé, ce qui était fait sur les anciens processeurs Intel pour donner un exemple. Mais voyons ce que cela peut donner avec un ''scheduler'' décentralisé. Une scission naturelle serait d'utiliser un ''scheduler'' pour les µops mémoire, et un ''scheduler'' pour le reste des µops. Les processeurs Intel de microarchitecture ''Skylake'' faisaient cela. Un avantage est que les deux fenêtres d'instructions sont plus spécialisées, ce qui entraine des économies de circuit. Les opérations entières/flottantes ont besoin de deux registres pour les opérandes et d'un autre résultat, alors que les µops mémoire n'ont besoin que de deux registres maximum. En utilisant un ''scheduler'' unique, chaque entrée doit mémoriser l'opcode et trois registres, dont un est inutilisé pour les µops mémoire et les branchements. En utilisant des fenêtres d’instructions séparées, celle pour les µops entières/flottantes a trois registres par entrée, contre seulement deux registres par entrée pour celle des µops mémoire. Une scission plus poussée sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes, un autre pour les µops mémoire. [[File:Processeur avec des fenêtres d'instruction décentralisées.png|centre|vignette|upright=2|Processeur avec des fenêtres d'instruction décentralisées]] ===Les stations de réservation=== Un cas extrême est celui où chaque ALU/FPU a sa propre ''scheduler''. Nous parlerons alors de '''fenêtres d'instruction totalement décentralisées'''. Par exemple, il y a un ''scheduler'' pour l'ALU entière, un autre pour le multiplieur entier, un autre pour le ''barrel shifter'', un autre pour l'unité mémoire, un autre pour l'unitéé de branchements, un autre pour l'additionneur flottant, un dernière pour le multiplier flottant, etc. Un exemple historique est celui de le FPU de l'IBM 360 modèle 90. Elle disposait d'un additionneur flottant, d'un multiplieur flottant, et d'un unité mémoire pour les lectures/écritures flottantes. Les trois unités avaient leur propre ''scheduler''. Les processeurs AMD utilisent beaucoup cette technique, contrairement à Intel qui préfère utiliser des fenêtres centralisées sur les anciens processeurs, deux ou trois fenêtres sur les processeurs récents (2020 et plus). Les processeurs AMD utilisaient précisément un ''scheduler'' par ALU entière, alors que les FPUs partagent un fenêtre d’instructions flottantes unique. Mais nous verrons cele en détail dans le chapitre sur les processeurs superscalaires x86. ==L'usage de plusieurs files d'instruction== un dernière méthode d'OOO utilise plusieurs files de micro-opération. L'idée est qu'un fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement un file de micro-opération pour les opérations entières, un autre pour les opérations flottantes, un autre pour les accès mémoire. D'autres processeurs utilisent un file pour les accès mémoire et un autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. le présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que le technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si un dépendance bloque un FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans un autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer le disponibilité des registres. Quand un registre est lu ou écrit par un instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. le logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : un pour les instructions d'accès mémoire et un autre pour les autres instructions. Si jamais un instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de le lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'un est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est le file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. ==Avantages et inconvénients de chaque implémentation== Pour résumer, on a le choix entre un gros ''scheduler'' généraliste et plusieurs ''schedulers'' spécialisées. Le choix entre les deux est un compromis entre économie de circuits et flexibilité. Avec un ''scheduler'' décentralisé, il arrive qu'un ''scheduler'' soit remplie, alors que les autres sont sous-utilisées, voire vides. Pour comprendre pourquoi, comparons un ''scheduler'' unique, avec un fenêtre décentralisée séparant µops entières et flottantes. le fenêtre centralisée dispose de 64 entrées, le décentralisée a 32 entrées pour chaque ''scheduler''. le fenêtre décentralisée peut mémoriser au maximum 32 µops entières et 32 µops flottantes. Par contre, le fenêtre centralisée peut mémoriser 64 µops tout court. Si le programme exécuté n'utilise pas de nombres flottants, le différence devient flegrante. le fenêtre décentralisée sera limitée ) 32 µops, alors que le centralisée pourra mémoriser le double. Les performances seront donc meilleures avec le fenêtre centralisée. Et au-delà de ça, le fenêtre décentralisée de l'exemple est utilisée de manière optimale si le moitié des µops sont des µops entières, et l'autre moitié des µops flottantes. Alors que le fenêtre centralisée se moque de le répartition entre µops entières et flottantes. Les fenêtres décentralisées utilisent plusieurs fenêtres d'instruction de "petite taille", donc plus rapides, économes en circuits et économes en énergie. Le compromis n'est donc pas entre un fenêtre centralisée à 64 entrées versus deux fenêtres de 32 entrées. Le compromis en pratique est entre un fenêtre centralisée de 64 entrées versus 3 fenêtres de 32 entrées. Un exemple pratique est celui de le microarchitecture ''Skyleke'' d'Intel. Intel est passé d'un fenêtre centralisée pre-''Skyleke'' à deux fenêtres décentralisées sur ''Skyleke'',. Le nombre d'entrée était globalement le même entre les deux, même si l'évolution de le finesse de gravure entre les deux biaise un peu les résultats. Un avantage des fenêtres décentralisées est qu'il est possible de démarrer l'exécution de plusieurs µops simultanément : un µops par ''scheduler''. Le fait est que deux fenêtres d'instructions différentes émettent leurs µops sans se synchroniser avec les autres. Deux fenêtres d'instruction peuvent donc émettre chacun un µops, ce qui fait deux µops émises lors du même cycle. Cele permet d'exécuter en même temps deux ou trois instructions 1-cycle, comme des additions, soustractions, décaleges, etc. Il devient par exemple possible d'émettre un µop entière en même temps qu'un µop flottante, si les µops entières ont un fenêtre séparée de celle des µops flottantes. Un point important est qu'avec des fenêtres d'instruction décentralisées, l'émission est découpée en deux étages. le première étape envoie un µops vers le ''scheduler'' adéquate, le seconde émet le µops depuis le ''scheduler'' quand ses opérandes sont prêts. le première est l'étage de '''''dispatch''''' qui envoie l'instruction dans le fenêtre d’instruction adéquate, selon que c'est un instruction flottante, entière, autre. le seconde est l'étage de '''''scheduling''''', qui gère le disponibilité des opérandes et des unités de calcul. le µop émise est ajoutée au tampon de réordonnancement, s'il existe, lors de l'étape de ''dispatch''. ==Résumé== Dans les grandes lignes, il existe 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! ''scheduler'' |- ! un seule | ''Scoreboard'' | ''scheduler'' centralisée |- ! Plusieurs | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | ''scheduler'' décentralisé |} <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Le scoreboarding et l'algorithme de Tomasulo | prevText=Le scoreboarding et l'algorithme de Tomasulo | next=La désambiguïsation mémoire | nextText=La désambiguïsation mémoire }} </noinclude> oetqr9x60gnt4wxdlncm4q86pkjywxx 773652 773651 2026-09-29T21:46:57Z Mewtow 31375 /* Les schedulers décentralisés avec exécution dans le désordre des accès mémoire */ 773652 wikitext text/x-wiki Nous venons de parler de l'exécution dans le désordre pendant deux chapitres. Les chapitres précédents vous ont laissé penser qu'un processeur avec exécution dans le désordre était assez simple : on remplace le file de µops par un fenêtre d’instruction, on ajoute éventuellement un unité de renommage de registres, et voilà ! Et en effet, l'implémentation la plus simple de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Mais dans la réalité, les processeurs modernes n'utilisent pas un ''scheduler'' unique. Les processeurs modernes ont besoin de ''scheduler'' très grands, avec un grand nombre d'entrées. Or, nous avons vu qu'un ''scheduler'' est un sorte de mémoire associative très complexe, avec un grand nombre de comparateurs. Et cela pose problème quand le ''scheduler'' doit mémoriser un grand nombre de µops. Le cout en transistors d'un ''scheduler'' n'est pas proportionnel au nombre de µops qu'elle peut mémoriser. Par exemple, si je compare un ''scheduler'' de 32 entrées (32 µops max), elle n'utilise pas deux fois plus transistors qu'un fenêtre de 16 entrées. Le cout en circuit n'est pas deux fois plus élevé, mais est approximativement 4 fois plus élevé. Le cout est presque quadratique, à savoir qu'il est proportionnel au carré du nombre d'entrées. Et il en est de même avec le performance. Dès qu'on dépasse la centaine de µops, un ''scheduler'' centralisé n'est pas très pratique. Il consomme beaucoup de transistors, chauffe beaucoup, n'est pas très rapide. ==Les ''schedulers'' décentralisés== La solution est de scinder un gros ''scheduler'' en plusieurs ''schedulers'' plus petits. Pour faire la différence avec un ''scheduler'' unique, nous allons parler de ''scheduler'' centralisé s'il n'y en a qu'un, de '''''scheduler'' décentralisé''' s'il y en a plusieurs. La scission doit se faire en tenant compte du reste du processeur. En effet, il faut relier les ''schedulers'' aux unités de calcul, ainsi qu'à l'unité mémoire, et cela ne peut pas se faire n'importe comment. Reste à voir comment faire. ===Les ''schedulers'' décentralisés avec exécution dans l'ordre des accès mémoire=== Prenons un processeur où les accès mémoire sont réalisés dans l'ordre. Le processeur a donc un simple ''scheduler'' pour les µops entières, les µops flottantes et les µops de branchements. La scission la plus basique sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes. L'avantage est que l'implémentation est très simple. Les flottants sont gérés à part des entiers. Ils ont leurs propres registres, des FPU séparées des ALU entières, bref : le séparation est complète. Utiliser un ''scheduler'' séparée va dans ce sens. Un avantage de cette scission se situe au niveau de la consommation d'électricité. Si le programme exécuté n'exécute aucune instruction flottante, le ''scheduler'' pour µops flottant peut être ''clock gate'', mis en veille, voire éteint. Le processeur consomme donc moins d'électricité, et chauffe moins. Remarque importante : les deux ''schedulers'' travaillent indépendamment les unes des autres. Ils décident d'émettre une µops à chaque cycle, dans leur coin, sans rendre de compte à l'autre. La conséquence est qu'il est possible d'émettre deux µops par cycle, si les circonstances l'autorisent. Le ''scheduler'' entier émet une µops entière en même temps que le ''scheduler'' flottant émet une µops flottante. Le résultat est un gain en performance, sur lequel on reviendra plus tard. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Il est aussi possible de séparer le ''scheduler'' pour les µops entières en deux : un pour les opérations de calcul et un autre pour les µops de branchements. La séparation est moins évidente, mais reste possible. De nombreux processeurs commerciaux le font. Cependant, cela demande d'utiliser une unité de calcul séparée pour les branchements. ===Les ''schedulers'' décentralisés avec exécution dans le désordre des accès mémoire=== Voyons maintenant le cas des processeurs où les accès mémoire sont exécutés dans le désordre. Il est possible d'utiliser un ''scheduler'' centralisé, ce qui était fait sur les anciens processeurs Intel pour donner un exemple. Mais voyons ce que cela peut donner avec un ''scheduler'' décentralisé. Une scission naturelle serait d'utiliser un ''scheduler'' pour les µops mémoire, et un ''scheduler'' pour le reste des µops. Les processeurs Intel de microarchitecture ''Skylake'' faisaient cela. Un avantage est que les deux fenêtres d'instructions sont plus spécialisées, ce qui entraine des économies de circuit. Les opérations entières/flottantes ont besoin de deux registres pour les opérandes et d'un autre résultat, alors que les µops mémoire n'ont besoin que de deux registres maximum. En utilisant un ''scheduler'' unique, chaque entrée doit mémoriser l'opcode et trois registres, dont un est inutilisé pour les µops mémoire et les branchements. En utilisant des fenêtres d’instructions séparées, celle pour les µops entières/flottantes a trois registres par entrée, contre seulement deux registres par entrée pour celle des µops mémoire. Un autre avantage est que cela permet d'émettre une µops mémoire et une autre µops lors du même cycle. Si les circonstances le permettent, le processeur peut émettre une µops entière dans une ALU entière, et une µops mémoire dans l'unité mémoire. Le gain en performance est substantiel. Précisons que les processeurs avec exécution dans le désordre peuvent exécuter une instruction arithmétique en parallèle d'un accès mémoire. Mais les deux ne démarrent pas au même cycle : on émet d'abord l'accès mémoire, puis les instructions de calcul suivent au cycle suivant. Là, les deux démarrent au même cycle. Une scission plus poussée sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes, un autre pour les µops mémoire. [[File:Processeur avec des fenêtres d'instruction décentralisées.png|centre|vignette|upright=2|Processeur avec des fenêtres d'instruction décentralisées]] ===Les stations de réservation=== Un cas extrême est celui où chaque ALU/FPU a sa propre ''scheduler''. Nous parlerons alors de '''fenêtres d'instruction totalement décentralisées'''. Par exemple, il y a un ''scheduler'' pour l'ALU entière, un autre pour le multiplieur entier, un autre pour le ''barrel shifter'', un autre pour l'unité mémoire, un autre pour l'unitéé de branchements, un autre pour l'additionneur flottant, un dernière pour le multiplier flottant, etc. Un exemple historique est celui de le FPU de l'IBM 360 modèle 90. Elle disposait d'un additionneur flottant, d'un multiplieur flottant, et d'un unité mémoire pour les lectures/écritures flottantes. Les trois unités avaient leur propre ''scheduler''. Les processeurs AMD utilisent beaucoup cette technique, contrairement à Intel qui préfère utiliser des fenêtres centralisées sur les anciens processeurs, deux ou trois fenêtres sur les processeurs récents (2020 et plus). Les processeurs AMD utilisaient précisément un ''scheduler'' par ALU entière, alors que les FPUs partagent un fenêtre d’instructions flottantes unique. Mais nous verrons cele en détail dans le chapitre sur les processeurs superscalaires x86. ==L'usage de plusieurs files d'instruction== un dernière méthode d'OOO utilise plusieurs files de micro-opération. L'idée est qu'un fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement un file de micro-opération pour les opérations entières, un autre pour les opérations flottantes, un autre pour les accès mémoire. D'autres processeurs utilisent un file pour les accès mémoire et un autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. le présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que le technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si un dépendance bloque un FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans un autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer le disponibilité des registres. Quand un registre est lu ou écrit par un instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. le logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : un pour les instructions d'accès mémoire et un autre pour les autres instructions. Si jamais un instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de le lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'un est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est le file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. ==Avantages et inconvénients de chaque implémentation== Pour résumer, on a le choix entre un gros ''scheduler'' généraliste et plusieurs ''schedulers'' spécialisées. Le choix entre les deux est un compromis entre économie de circuits et flexibilité. Avec un ''scheduler'' décentralisé, il arrive qu'un ''scheduler'' soit remplie, alors que les autres sont sous-utilisées, voire vides. Pour comprendre pourquoi, comparons un ''scheduler'' unique, avec un fenêtre décentralisée séparant µops entières et flottantes. le fenêtre centralisée dispose de 64 entrées, le décentralisée a 32 entrées pour chaque ''scheduler''. le fenêtre décentralisée peut mémoriser au maximum 32 µops entières et 32 µops flottantes. Par contre, le fenêtre centralisée peut mémoriser 64 µops tout court. Si le programme exécuté n'utilise pas de nombres flottants, le différence devient flegrante. le fenêtre décentralisée sera limitée ) 32 µops, alors que le centralisée pourra mémoriser le double. Les performances seront donc meilleures avec le fenêtre centralisée. Et au-delà de ça, le fenêtre décentralisée de l'exemple est utilisée de manière optimale si le moitié des µops sont des µops entières, et l'autre moitié des µops flottantes. Alors que le fenêtre centralisée se moque de le répartition entre µops entières et flottantes. Les fenêtres décentralisées utilisent plusieurs fenêtres d'instruction de "petite taille", donc plus rapides, économes en circuits et économes en énergie. Le compromis n'est donc pas entre un fenêtre centralisée à 64 entrées versus deux fenêtres de 32 entrées. Le compromis en pratique est entre un fenêtre centralisée de 64 entrées versus 3 fenêtres de 32 entrées. Un exemple pratique est celui de le microarchitecture ''Skyleke'' d'Intel. Intel est passé d'un fenêtre centralisée pre-''Skyleke'' à deux fenêtres décentralisées sur ''Skyleke'',. Le nombre d'entrée était globalement le même entre les deux, même si l'évolution de le finesse de gravure entre les deux biaise un peu les résultats. Un avantage des fenêtres décentralisées est qu'il est possible de démarrer l'exécution de plusieurs µops simultanément : un µops par ''scheduler''. Le fait est que deux fenêtres d'instructions différentes émettent leurs µops sans se synchroniser avec les autres. Deux fenêtres d'instruction peuvent donc émettre chacun un µops, ce qui fait deux µops émises lors du même cycle. Cele permet d'exécuter en même temps deux ou trois instructions 1-cycle, comme des additions, soustractions, décaleges, etc. Il devient par exemple possible d'émettre un µop entière en même temps qu'un µop flottante, si les µops entières ont un fenêtre séparée de celle des µops flottantes. Un point important est qu'avec des fenêtres d'instruction décentralisées, l'émission est découpée en deux étages. le première étape envoie un µops vers le ''scheduler'' adéquate, le seconde émet le µops depuis le ''scheduler'' quand ses opérandes sont prêts. le première est l'étage de '''''dispatch''''' qui envoie l'instruction dans le fenêtre d’instruction adéquate, selon que c'est un instruction flottante, entière, autre. le seconde est l'étage de '''''scheduling''''', qui gère le disponibilité des opérandes et des unités de calcul. le µop émise est ajoutée au tampon de réordonnancement, s'il existe, lors de l'étape de ''dispatch''. ==Résumé== Dans les grandes lignes, il existe 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! ''scheduler'' |- ! un seule | ''Scoreboard'' | ''scheduler'' centralisée |- ! Plusieurs | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | ''scheduler'' décentralisé |} <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Le scoreboarding et l'algorithme de Tomasulo | prevText=Le scoreboarding et l'algorithme de Tomasulo | next=La désambiguïsation mémoire | nextText=La désambiguïsation mémoire }} </noinclude> f6dtis97jtz9javz3msn24b7vwk3xcd 773653 773652 2026-09-29T21:47:25Z Mewtow 31375 /* Les schedulers décentralisés avec exécution dans l'ordre des accès mémoire */ 773653 wikitext text/x-wiki Nous venons de parler de l'exécution dans le désordre pendant deux chapitres. Les chapitres précédents vous ont laissé penser qu'un processeur avec exécution dans le désordre était assez simple : on remplace le file de µops par un fenêtre d’instruction, on ajoute éventuellement un unité de renommage de registres, et voilà ! Et en effet, l'implémentation la plus simple de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Mais dans la réalité, les processeurs modernes n'utilisent pas un ''scheduler'' unique. Les processeurs modernes ont besoin de ''scheduler'' très grands, avec un grand nombre d'entrées. Or, nous avons vu qu'un ''scheduler'' est un sorte de mémoire associative très complexe, avec un grand nombre de comparateurs. Et cela pose problème quand le ''scheduler'' doit mémoriser un grand nombre de µops. Le cout en transistors d'un ''scheduler'' n'est pas proportionnel au nombre de µops qu'elle peut mémoriser. Par exemple, si je compare un ''scheduler'' de 32 entrées (32 µops max), elle n'utilise pas deux fois plus transistors qu'un fenêtre de 16 entrées. Le cout en circuit n'est pas deux fois plus élevé, mais est approximativement 4 fois plus élevé. Le cout est presque quadratique, à savoir qu'il est proportionnel au carré du nombre d'entrées. Et il en est de même avec le performance. Dès qu'on dépasse la centaine de µops, un ''scheduler'' centralisé n'est pas très pratique. Il consomme beaucoup de transistors, chauffe beaucoup, n'est pas très rapide. ==Les ''schedulers'' décentralisés== La solution est de scinder un gros ''scheduler'' en plusieurs ''schedulers'' plus petits. Pour faire la différence avec un ''scheduler'' unique, nous allons parler de ''scheduler'' centralisé s'il n'y en a qu'un, de '''''scheduler'' décentralisé''' s'il y en a plusieurs. La scission doit se faire en tenant compte du reste du processeur. En effet, il faut relier les ''schedulers'' aux unités de calcul, ainsi qu'à l'unité mémoire, et cela ne peut pas se faire n'importe comment. Reste à voir comment faire. ===Les ''schedulers'' décentralisés avec exécution dans l'ordre des accès mémoire=== Prenons un processeur où les accès mémoire sont réalisés dans l'ordre. Le processeur a donc un simple ''scheduler'' pour les µops entières, les µops flottantes et les µops de branchements. La scission la plus basique sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes. L'avantage est que l'implémentation est très simple. Les flottants sont gérés à part des entiers. Ils ont leurs propres registres, des FPU séparées des ALU entières, bref : le séparation est complète. Utiliser un ''scheduler'' séparée va dans ce sens. Un avantage de cette scission se situe au niveau de la consommation d'électricité. Si le programme exécuté n'exécute aucune instruction flottante, le ''scheduler'' pour µops flottant peut être ''clock gate'', mis en veille, voire éteint. Le processeur consomme donc moins d'électricité, et chauffe moins. Remarque importante : les deux ''schedulers'' travaillent indépendamment les unes des autres. Ils décident d'émettre une µops à chaque cycle, dans leur coin, sans rendre de compte à l'autre. La conséquence est qu'il est possible d'émettre deux µops par cycle, si les circonstances l'autorisent. Le ''scheduler'' entier émet une µops entière en même temps que le ''scheduler'' flottant émet une µops flottante. Les deux µops démarrent au même cycle, on n'émet pas l'une après l'autre. Le résultat est un gain en performance, sur lequel on reviendra plus tard. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Il est aussi possible de séparer le ''scheduler'' pour les µops entières en deux : un pour les opérations de calcul et un autre pour les µops de branchements. La séparation est moins évidente, mais reste possible. De nombreux processeurs commerciaux le font. Cependant, cela demande d'utiliser une unité de calcul séparée pour les branchements. ===Les ''schedulers'' décentralisés avec exécution dans le désordre des accès mémoire=== Voyons maintenant le cas des processeurs où les accès mémoire sont exécutés dans le désordre. Il est possible d'utiliser un ''scheduler'' centralisé, ce qui était fait sur les anciens processeurs Intel pour donner un exemple. Mais voyons ce que cela peut donner avec un ''scheduler'' décentralisé. Une scission naturelle serait d'utiliser un ''scheduler'' pour les µops mémoire, et un ''scheduler'' pour le reste des µops. Les processeurs Intel de microarchitecture ''Skylake'' faisaient cela. Un avantage est que les deux fenêtres d'instructions sont plus spécialisées, ce qui entraine des économies de circuit. Les opérations entières/flottantes ont besoin de deux registres pour les opérandes et d'un autre résultat, alors que les µops mémoire n'ont besoin que de deux registres maximum. En utilisant un ''scheduler'' unique, chaque entrée doit mémoriser l'opcode et trois registres, dont un est inutilisé pour les µops mémoire et les branchements. En utilisant des fenêtres d’instructions séparées, celle pour les µops entières/flottantes a trois registres par entrée, contre seulement deux registres par entrée pour celle des µops mémoire. Un autre avantage est que cela permet d'émettre une µops mémoire et une autre µops lors du même cycle. Si les circonstances le permettent, le processeur peut émettre une µops entière dans une ALU entière, et une µops mémoire dans l'unité mémoire. Le gain en performance est substantiel. Précisons que les processeurs avec exécution dans le désordre peuvent exécuter une instruction arithmétique en parallèle d'un accès mémoire. Mais les deux ne démarrent pas au même cycle : on émet d'abord l'accès mémoire, puis les instructions de calcul suivent au cycle suivant. Là, les deux démarrent au même cycle. Une scission plus poussée sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes, un autre pour les µops mémoire. [[File:Processeur avec des fenêtres d'instruction décentralisées.png|centre|vignette|upright=2|Processeur avec des fenêtres d'instruction décentralisées]] ===Les stations de réservation=== Un cas extrême est celui où chaque ALU/FPU a sa propre ''scheduler''. Nous parlerons alors de '''fenêtres d'instruction totalement décentralisées'''. Par exemple, il y a un ''scheduler'' pour l'ALU entière, un autre pour le multiplieur entier, un autre pour le ''barrel shifter'', un autre pour l'unité mémoire, un autre pour l'unitéé de branchements, un autre pour l'additionneur flottant, un dernière pour le multiplier flottant, etc. Un exemple historique est celui de le FPU de l'IBM 360 modèle 90. Elle disposait d'un additionneur flottant, d'un multiplieur flottant, et d'un unité mémoire pour les lectures/écritures flottantes. Les trois unités avaient leur propre ''scheduler''. Les processeurs AMD utilisent beaucoup cette technique, contrairement à Intel qui préfère utiliser des fenêtres centralisées sur les anciens processeurs, deux ou trois fenêtres sur les processeurs récents (2020 et plus). Les processeurs AMD utilisaient précisément un ''scheduler'' par ALU entière, alors que les FPUs partagent un fenêtre d’instructions flottantes unique. Mais nous verrons cele en détail dans le chapitre sur les processeurs superscalaires x86. ==L'usage de plusieurs files d'instruction== un dernière méthode d'OOO utilise plusieurs files de micro-opération. L'idée est qu'un fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement un file de micro-opération pour les opérations entières, un autre pour les opérations flottantes, un autre pour les accès mémoire. D'autres processeurs utilisent un file pour les accès mémoire et un autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. le présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que le technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si un dépendance bloque un FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans un autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer le disponibilité des registres. Quand un registre est lu ou écrit par un instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. le logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : un pour les instructions d'accès mémoire et un autre pour les autres instructions. Si jamais un instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de le lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'un est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est le file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. ==Avantages et inconvénients de chaque implémentation== Pour résumer, on a le choix entre un gros ''scheduler'' généraliste et plusieurs ''schedulers'' spécialisées. Le choix entre les deux est un compromis entre économie de circuits et flexibilité. Avec un ''scheduler'' décentralisé, il arrive qu'un ''scheduler'' soit remplie, alors que les autres sont sous-utilisées, voire vides. Pour comprendre pourquoi, comparons un ''scheduler'' unique, avec un fenêtre décentralisée séparant µops entières et flottantes. le fenêtre centralisée dispose de 64 entrées, le décentralisée a 32 entrées pour chaque ''scheduler''. le fenêtre décentralisée peut mémoriser au maximum 32 µops entières et 32 µops flottantes. Par contre, le fenêtre centralisée peut mémoriser 64 µops tout court. Si le programme exécuté n'utilise pas de nombres flottants, le différence devient flegrante. le fenêtre décentralisée sera limitée ) 32 µops, alors que le centralisée pourra mémoriser le double. Les performances seront donc meilleures avec le fenêtre centralisée. Et au-delà de ça, le fenêtre décentralisée de l'exemple est utilisée de manière optimale si le moitié des µops sont des µops entières, et l'autre moitié des µops flottantes. Alors que le fenêtre centralisée se moque de le répartition entre µops entières et flottantes. Les fenêtres décentralisées utilisent plusieurs fenêtres d'instruction de "petite taille", donc plus rapides, économes en circuits et économes en énergie. Le compromis n'est donc pas entre un fenêtre centralisée à 64 entrées versus deux fenêtres de 32 entrées. Le compromis en pratique est entre un fenêtre centralisée de 64 entrées versus 3 fenêtres de 32 entrées. Un exemple pratique est celui de le microarchitecture ''Skyleke'' d'Intel. Intel est passé d'un fenêtre centralisée pre-''Skyleke'' à deux fenêtres décentralisées sur ''Skyleke'',. Le nombre d'entrée était globalement le même entre les deux, même si l'évolution de le finesse de gravure entre les deux biaise un peu les résultats. Un avantage des fenêtres décentralisées est qu'il est possible de démarrer l'exécution de plusieurs µops simultanément : un µops par ''scheduler''. Le fait est que deux fenêtres d'instructions différentes émettent leurs µops sans se synchroniser avec les autres. Deux fenêtres d'instruction peuvent donc émettre chacun un µops, ce qui fait deux µops émises lors du même cycle. Cele permet d'exécuter en même temps deux ou trois instructions 1-cycle, comme des additions, soustractions, décaleges, etc. Il devient par exemple possible d'émettre un µop entière en même temps qu'un µop flottante, si les µops entières ont un fenêtre séparée de celle des µops flottantes. Un point important est qu'avec des fenêtres d'instruction décentralisées, l'émission est découpée en deux étages. le première étape envoie un µops vers le ''scheduler'' adéquate, le seconde émet le µops depuis le ''scheduler'' quand ses opérandes sont prêts. le première est l'étage de '''''dispatch''''' qui envoie l'instruction dans le fenêtre d’instruction adéquate, selon que c'est un instruction flottante, entière, autre. le seconde est l'étage de '''''scheduling''''', qui gère le disponibilité des opérandes et des unités de calcul. le µop émise est ajoutée au tampon de réordonnancement, s'il existe, lors de l'étape de ''dispatch''. ==Résumé== Dans les grandes lignes, il existe 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! ''scheduler'' |- ! un seule | ''Scoreboard'' | ''scheduler'' centralisée |- ! Plusieurs | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | ''scheduler'' décentralisé |} <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Le scoreboarding et l'algorithme de Tomasulo | prevText=Le scoreboarding et l'algorithme de Tomasulo | next=La désambiguïsation mémoire | nextText=La désambiguïsation mémoire }} </noinclude> pb404ffhx8k5jvyg7mq4mfz183k0e8b 773654 773653 2026-09-29T21:52:14Z Mewtow 31375 /* Les stations de réservation */ 773654 wikitext text/x-wiki Nous venons de parler de l'exécution dans le désordre pendant deux chapitres. Les chapitres précédents vous ont laissé penser qu'un processeur avec exécution dans le désordre était assez simple : on remplace le file de µops par un fenêtre d’instruction, on ajoute éventuellement un unité de renommage de registres, et voilà ! Et en effet, l'implémentation la plus simple de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Mais dans la réalité, les processeurs modernes n'utilisent pas un ''scheduler'' unique. Les processeurs modernes ont besoin de ''scheduler'' très grands, avec un grand nombre d'entrées. Or, nous avons vu qu'un ''scheduler'' est un sorte de mémoire associative très complexe, avec un grand nombre de comparateurs. Et cela pose problème quand le ''scheduler'' doit mémoriser un grand nombre de µops. Le cout en transistors d'un ''scheduler'' n'est pas proportionnel au nombre de µops qu'elle peut mémoriser. Par exemple, si je compare un ''scheduler'' de 32 entrées (32 µops max), elle n'utilise pas deux fois plus transistors qu'un fenêtre de 16 entrées. Le cout en circuit n'est pas deux fois plus élevé, mais est approximativement 4 fois plus élevé. Le cout est presque quadratique, à savoir qu'il est proportionnel au carré du nombre d'entrées. Et il en est de même avec le performance. Dès qu'on dépasse la centaine de µops, un ''scheduler'' centralisé n'est pas très pratique. Il consomme beaucoup de transistors, chauffe beaucoup, n'est pas très rapide. ==Les ''schedulers'' décentralisés== La solution est de scinder un gros ''scheduler'' en plusieurs ''schedulers'' plus petits. Pour faire la différence avec un ''scheduler'' unique, nous allons parler de ''scheduler'' centralisé s'il n'y en a qu'un, de '''''scheduler'' décentralisé''' s'il y en a plusieurs. La scission doit se faire en tenant compte du reste du processeur. En effet, il faut relier les ''schedulers'' aux unités de calcul, ainsi qu'à l'unité mémoire, et cela ne peut pas se faire n'importe comment. Reste à voir comment faire. ===Les ''schedulers'' décentralisés avec exécution dans l'ordre des accès mémoire=== Prenons un processeur où les accès mémoire sont réalisés dans l'ordre. Le processeur a donc un simple ''scheduler'' pour les µops entières, les µops flottantes et les µops de branchements. La scission la plus basique sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes. L'avantage est que l'implémentation est très simple. Les flottants sont gérés à part des entiers. Ils ont leurs propres registres, des FPU séparées des ALU entières, bref : le séparation est complète. Utiliser un ''scheduler'' séparée va dans ce sens. Un avantage de cette scission se situe au niveau de la consommation d'électricité. Si le programme exécuté n'exécute aucune instruction flottante, le ''scheduler'' pour µops flottant peut être ''clock gate'', mis en veille, voire éteint. Le processeur consomme donc moins d'électricité, et chauffe moins. Remarque importante : les deux ''schedulers'' travaillent indépendamment les unes des autres. Ils décident d'émettre une µops à chaque cycle, dans leur coin, sans rendre de compte à l'autre. La conséquence est qu'il est possible d'émettre deux µops par cycle, si les circonstances l'autorisent. Le ''scheduler'' entier émet une µops entière en même temps que le ''scheduler'' flottant émet une µops flottante. Les deux µops démarrent au même cycle, on n'émet pas l'une après l'autre. Le résultat est un gain en performance, sur lequel on reviendra plus tard. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Il est aussi possible de séparer le ''scheduler'' pour les µops entières en deux : un pour les opérations de calcul et un autre pour les µops de branchements. La séparation est moins évidente, mais reste possible. De nombreux processeurs commerciaux le font. Cependant, cela demande d'utiliser une unité de calcul séparée pour les branchements. ===Les ''schedulers'' décentralisés avec exécution dans le désordre des accès mémoire=== Voyons maintenant le cas des processeurs où les accès mémoire sont exécutés dans le désordre. Il est possible d'utiliser un ''scheduler'' centralisé, ce qui était fait sur les anciens processeurs Intel pour donner un exemple. Mais voyons ce que cela peut donner avec un ''scheduler'' décentralisé. Une scission naturelle serait d'utiliser un ''scheduler'' pour les µops mémoire, et un ''scheduler'' pour le reste des µops. Les processeurs Intel de microarchitecture ''Skylake'' faisaient cela. Un avantage est que les deux fenêtres d'instructions sont plus spécialisées, ce qui entraine des économies de circuit. Les opérations entières/flottantes ont besoin de deux registres pour les opérandes et d'un autre résultat, alors que les µops mémoire n'ont besoin que de deux registres maximum. En utilisant un ''scheduler'' unique, chaque entrée doit mémoriser l'opcode et trois registres, dont un est inutilisé pour les µops mémoire et les branchements. En utilisant des fenêtres d’instructions séparées, celle pour les µops entières/flottantes a trois registres par entrée, contre seulement deux registres par entrée pour celle des µops mémoire. Un autre avantage est que cela permet d'émettre une µops mémoire et une autre µops lors du même cycle. Si les circonstances le permettent, le processeur peut émettre une µops entière dans une ALU entière, et une µops mémoire dans l'unité mémoire. Le gain en performance est substantiel. Précisons que les processeurs avec exécution dans le désordre peuvent exécuter une instruction arithmétique en parallèle d'un accès mémoire. Mais les deux ne démarrent pas au même cycle : on émet d'abord l'accès mémoire, puis les instructions de calcul suivent au cycle suivant. Là, les deux démarrent au même cycle. Une scission plus poussée sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes, un autre pour les µops mémoire. [[File:Processeur avec des fenêtres d'instruction décentralisées.png|centre|vignette|upright=2|Processeur avec des fenêtres d'instruction décentralisées]] ===Les stations de réservation=== Un cas extrême est celui où chaque ALU/FPU a sa propre ''scheduler''. Par exemple, il y a un ''scheduler'' pour l'ALU entière, un autre pour le multiplieur entier, un autre pour le ''barrel shifter'', un autre pour l'unité mémoire, un autre pour l'unité de branchements, un autre pour l'additionneur flottant, un autre pour le multiplier flottant, etc. Un exemple historique est celui de le FPU de l'IBM 360 modèle 90, qui avait un additionneur flottant, un multiplieur flottant, et une unité mémoire pour les lectures/écritures flottantes. Les trois unités avaient leur propre ''scheduler''. Un exemple aussi extrême n'est pas si rare. Les processeurs AMD utilisent beaucoup cette technique, pour les ALU entières, à quelques nuances près. A l'opposé, Intel préfère utiliser des ''schedulers'' centralisés sur les anciens processeurs, deux ou trois ''schedulers'' sur les processeurs récents (2020 et plus). Les processeurs AMD utilisaient précisément un ''scheduler'' par ALU entière, alors que les FPUs partagent un fenêtre d’instructions flottantes unique. Mais nous verrons cela en détail dans le chapitre sur les processeurs superscalaires x86. Toujours est-il qu'un cas aussi unique porte un nom. Les ''schedulers'' reliés à une seule ALU (entière ou flottante) sont appelés des '''stations de réservation'''. Le terme a été introduit dans l'article de Tomasulo, qui décrivait justement la FPU de l'IBM 360, mentionnée plus haut. Mais dans ce cours, le terme décrit des ''schedulers'' qui mémorisent les opérandes des instructions, pas seulement les noms de registres associés. ==L'usage de plusieurs files d'instruction== un dernière méthode d'OOO utilise plusieurs files de micro-opération. L'idée est qu'un fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement un file de micro-opération pour les opérations entières, un autre pour les opérations flottantes, un autre pour les accès mémoire. D'autres processeurs utilisent un file pour les accès mémoire et un autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. le présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que le technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si un dépendance bloque un FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans un autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer le disponibilité des registres. Quand un registre est lu ou écrit par un instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. le logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : un pour les instructions d'accès mémoire et un autre pour les autres instructions. Si jamais un instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de le lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'un est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est le file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. ==Avantages et inconvénients de chaque implémentation== Pour résumer, on a le choix entre un gros ''scheduler'' généraliste et plusieurs ''schedulers'' spécialisées. Le choix entre les deux est un compromis entre économie de circuits et flexibilité. Avec un ''scheduler'' décentralisé, il arrive qu'un ''scheduler'' soit remplie, alors que les autres sont sous-utilisées, voire vides. Pour comprendre pourquoi, comparons un ''scheduler'' unique, avec un fenêtre décentralisée séparant µops entières et flottantes. le fenêtre centralisée dispose de 64 entrées, le décentralisée a 32 entrées pour chaque ''scheduler''. le fenêtre décentralisée peut mémoriser au maximum 32 µops entières et 32 µops flottantes. Par contre, le fenêtre centralisée peut mémoriser 64 µops tout court. Si le programme exécuté n'utilise pas de nombres flottants, le différence devient flegrante. le fenêtre décentralisée sera limitée ) 32 µops, alors que le centralisée pourra mémoriser le double. Les performances seront donc meilleures avec le fenêtre centralisée. Et au-delà de ça, le fenêtre décentralisée de l'exemple est utilisée de manière optimale si le moitié des µops sont des µops entières, et l'autre moitié des µops flottantes. Alors que le fenêtre centralisée se moque de le répartition entre µops entières et flottantes. Les fenêtres décentralisées utilisent plusieurs fenêtres d'instruction de "petite taille", donc plus rapides, économes en circuits et économes en énergie. Le compromis n'est donc pas entre un fenêtre centralisée à 64 entrées versus deux fenêtres de 32 entrées. Le compromis en pratique est entre un fenêtre centralisée de 64 entrées versus 3 fenêtres de 32 entrées. Un exemple pratique est celui de le microarchitecture ''Skyleke'' d'Intel. Intel est passé d'un fenêtre centralisée pre-''Skyleke'' à deux fenêtres décentralisées sur ''Skyleke'',. Le nombre d'entrée était globalement le même entre les deux, même si l'évolution de le finesse de gravure entre les deux biaise un peu les résultats. Un avantage des fenêtres décentralisées est qu'il est possible de démarrer l'exécution de plusieurs µops simultanément : un µops par ''scheduler''. Le fait est que deux fenêtres d'instructions différentes émettent leurs µops sans se synchroniser avec les autres. Deux fenêtres d'instruction peuvent donc émettre chacun un µops, ce qui fait deux µops émises lors du même cycle. Cele permet d'exécuter en même temps deux ou trois instructions 1-cycle, comme des additions, soustractions, décaleges, etc. Il devient par exemple possible d'émettre un µop entière en même temps qu'un µop flottante, si les µops entières ont un fenêtre séparée de celle des µops flottantes. Un point important est qu'avec des fenêtres d'instruction décentralisées, l'émission est découpée en deux étages. le première étape envoie un µops vers le ''scheduler'' adéquate, le seconde émet le µops depuis le ''scheduler'' quand ses opérandes sont prêts. le première est l'étage de '''''dispatch''''' qui envoie l'instruction dans le fenêtre d’instruction adéquate, selon que c'est un instruction flottante, entière, autre. le seconde est l'étage de '''''scheduling''''', qui gère le disponibilité des opérandes et des unités de calcul. le µop émise est ajoutée au tampon de réordonnancement, s'il existe, lors de l'étape de ''dispatch''. ==Résumé== Dans les grandes lignes, il existe 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! ''scheduler'' |- ! un seule | ''Scoreboard'' | ''scheduler'' centralisée |- ! Plusieurs | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | ''scheduler'' décentralisé |} <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Le scoreboarding et l'algorithme de Tomasulo | prevText=Le scoreboarding et l'algorithme de Tomasulo | next=La désambiguïsation mémoire | nextText=La désambiguïsation mémoire }} </noinclude> 3gzu9vh9cxcq77hki1rpadmyh3nh1ru 773655 773654 2026-09-29T21:53:27Z Mewtow 31375 /* L'usage de plusieurs files d'instruction */ 773655 wikitext text/x-wiki Nous venons de parler de l'exécution dans le désordre pendant deux chapitres. Les chapitres précédents vous ont laissé penser qu'un processeur avec exécution dans le désordre était assez simple : on remplace le file de µops par un fenêtre d’instruction, on ajoute éventuellement un unité de renommage de registres, et voilà ! Et en effet, l'implémentation la plus simple de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Mais dans la réalité, les processeurs modernes n'utilisent pas un ''scheduler'' unique. Les processeurs modernes ont besoin de ''scheduler'' très grands, avec un grand nombre d'entrées. Or, nous avons vu qu'un ''scheduler'' est un sorte de mémoire associative très complexe, avec un grand nombre de comparateurs. Et cela pose problème quand le ''scheduler'' doit mémoriser un grand nombre de µops. Le cout en transistors d'un ''scheduler'' n'est pas proportionnel au nombre de µops qu'elle peut mémoriser. Par exemple, si je compare un ''scheduler'' de 32 entrées (32 µops max), elle n'utilise pas deux fois plus transistors qu'un fenêtre de 16 entrées. Le cout en circuit n'est pas deux fois plus élevé, mais est approximativement 4 fois plus élevé. Le cout est presque quadratique, à savoir qu'il est proportionnel au carré du nombre d'entrées. Et il en est de même avec le performance. Dès qu'on dépasse la centaine de µops, un ''scheduler'' centralisé n'est pas très pratique. Il consomme beaucoup de transistors, chauffe beaucoup, n'est pas très rapide. ==Les ''schedulers'' décentralisés== La solution est de scinder un gros ''scheduler'' en plusieurs ''schedulers'' plus petits. Pour faire la différence avec un ''scheduler'' unique, nous allons parler de ''scheduler'' centralisé s'il n'y en a qu'un, de '''''scheduler'' décentralisé''' s'il y en a plusieurs. La scission doit se faire en tenant compte du reste du processeur. En effet, il faut relier les ''schedulers'' aux unités de calcul, ainsi qu'à l'unité mémoire, et cela ne peut pas se faire n'importe comment. Reste à voir comment faire. ===Les ''schedulers'' décentralisés avec exécution dans l'ordre des accès mémoire=== Prenons un processeur où les accès mémoire sont réalisés dans l'ordre. Le processeur a donc un simple ''scheduler'' pour les µops entières, les µops flottantes et les µops de branchements. La scission la plus basique sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes. L'avantage est que l'implémentation est très simple. Les flottants sont gérés à part des entiers. Ils ont leurs propres registres, des FPU séparées des ALU entières, bref : le séparation est complète. Utiliser un ''scheduler'' séparée va dans ce sens. Un avantage de cette scission se situe au niveau de la consommation d'électricité. Si le programme exécuté n'exécute aucune instruction flottante, le ''scheduler'' pour µops flottant peut être ''clock gate'', mis en veille, voire éteint. Le processeur consomme donc moins d'électricité, et chauffe moins. Remarque importante : les deux ''schedulers'' travaillent indépendamment les unes des autres. Ils décident d'émettre une µops à chaque cycle, dans leur coin, sans rendre de compte à l'autre. La conséquence est qu'il est possible d'émettre deux µops par cycle, si les circonstances l'autorisent. Le ''scheduler'' entier émet une µops entière en même temps que le ''scheduler'' flottant émet une µops flottante. Les deux µops démarrent au même cycle, on n'émet pas l'une après l'autre. Le résultat est un gain en performance, sur lequel on reviendra plus tard. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Il est aussi possible de séparer le ''scheduler'' pour les µops entières en deux : un pour les opérations de calcul et un autre pour les µops de branchements. La séparation est moins évidente, mais reste possible. De nombreux processeurs commerciaux le font. Cependant, cela demande d'utiliser une unité de calcul séparée pour les branchements. ===Les ''schedulers'' décentralisés avec exécution dans le désordre des accès mémoire=== Voyons maintenant le cas des processeurs où les accès mémoire sont exécutés dans le désordre. Il est possible d'utiliser un ''scheduler'' centralisé, ce qui était fait sur les anciens processeurs Intel pour donner un exemple. Mais voyons ce que cela peut donner avec un ''scheduler'' décentralisé. Une scission naturelle serait d'utiliser un ''scheduler'' pour les µops mémoire, et un ''scheduler'' pour le reste des µops. Les processeurs Intel de microarchitecture ''Skylake'' faisaient cela. Un avantage est que les deux fenêtres d'instructions sont plus spécialisées, ce qui entraine des économies de circuit. Les opérations entières/flottantes ont besoin de deux registres pour les opérandes et d'un autre résultat, alors que les µops mémoire n'ont besoin que de deux registres maximum. En utilisant un ''scheduler'' unique, chaque entrée doit mémoriser l'opcode et trois registres, dont un est inutilisé pour les µops mémoire et les branchements. En utilisant des fenêtres d’instructions séparées, celle pour les µops entières/flottantes a trois registres par entrée, contre seulement deux registres par entrée pour celle des µops mémoire. Un autre avantage est que cela permet d'émettre une µops mémoire et une autre µops lors du même cycle. Si les circonstances le permettent, le processeur peut émettre une µops entière dans une ALU entière, et une µops mémoire dans l'unité mémoire. Le gain en performance est substantiel. Précisons que les processeurs avec exécution dans le désordre peuvent exécuter une instruction arithmétique en parallèle d'un accès mémoire. Mais les deux ne démarrent pas au même cycle : on émet d'abord l'accès mémoire, puis les instructions de calcul suivent au cycle suivant. Là, les deux démarrent au même cycle. Une scission plus poussée sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes, un autre pour les µops mémoire. [[File:Processeur avec des fenêtres d'instruction décentralisées.png|centre|vignette|upright=2|Processeur avec des fenêtres d'instruction décentralisées]] ===Les stations de réservation=== Un cas extrême est celui où chaque ALU/FPU a sa propre ''scheduler''. Par exemple, il y a un ''scheduler'' pour l'ALU entière, un autre pour le multiplieur entier, un autre pour le ''barrel shifter'', un autre pour l'unité mémoire, un autre pour l'unité de branchements, un autre pour l'additionneur flottant, un autre pour le multiplier flottant, etc. Un exemple historique est celui de le FPU de l'IBM 360 modèle 90, qui avait un additionneur flottant, un multiplieur flottant, et une unité mémoire pour les lectures/écritures flottantes. Les trois unités avaient leur propre ''scheduler''. Un exemple aussi extrême n'est pas si rare. Les processeurs AMD utilisent beaucoup cette technique, pour les ALU entières, à quelques nuances près. A l'opposé, Intel préfère utiliser des ''schedulers'' centralisés sur les anciens processeurs, deux ou trois ''schedulers'' sur les processeurs récents (2020 et plus). Les processeurs AMD utilisaient précisément un ''scheduler'' par ALU entière, alors que les FPUs partagent un fenêtre d’instructions flottantes unique. Mais nous verrons cela en détail dans le chapitre sur les processeurs superscalaires x86. Toujours est-il qu'un cas aussi unique porte un nom. Les ''schedulers'' reliés à une seule ALU (entière ou flottante) sont appelés des '''stations de réservation'''. Le terme a été introduit dans l'article de Tomasulo, qui décrivait justement la FPU de l'IBM 360, mentionnée plus haut. Mais dans ce cours, le terme décrit des ''schedulers'' qui mémorisent les opérandes des instructions, pas seulement les noms de registres associés. ===L'usage de plusieurs files d'instruction=== Utiliser plusieurs ''schedulers'' séparés est une bonne méthode pour économiser des circuits. Mais il est possible d'aller encore plus loin, en remplaçant les ''schedulers'' par des files de micro-opérations. L'idée est qu'un fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement un file de micro-opération pour les opérations entières, un autre pour les opérations flottantes, un autre pour les accès mémoire. D'autres processeurs utilisent un file pour les accès mémoire et un autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. le présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que le technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si un dépendance bloque un FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans un autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer le disponibilité des registres. Quand un registre est lu ou écrit par un instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. le logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : un pour les instructions d'accès mémoire et un autre pour les autres instructions. Si jamais un instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de le lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'un est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est le file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. ==Avantages et inconvénients de chaque implémentation== Pour résumer, on a le choix entre un gros ''scheduler'' généraliste et plusieurs ''schedulers'' spécialisées. Le choix entre les deux est un compromis entre économie de circuits et flexibilité. Avec un ''scheduler'' décentralisé, il arrive qu'un ''scheduler'' soit remplie, alors que les autres sont sous-utilisées, voire vides. Pour comprendre pourquoi, comparons un ''scheduler'' unique, avec un fenêtre décentralisée séparant µops entières et flottantes. le fenêtre centralisée dispose de 64 entrées, le décentralisée a 32 entrées pour chaque ''scheduler''. le fenêtre décentralisée peut mémoriser au maximum 32 µops entières et 32 µops flottantes. Par contre, le fenêtre centralisée peut mémoriser 64 µops tout court. Si le programme exécuté n'utilise pas de nombres flottants, le différence devient flegrante. le fenêtre décentralisée sera limitée ) 32 µops, alors que le centralisée pourra mémoriser le double. Les performances seront donc meilleures avec le fenêtre centralisée. Et au-delà de ça, le fenêtre décentralisée de l'exemple est utilisée de manière optimale si le moitié des µops sont des µops entières, et l'autre moitié des µops flottantes. Alors que le fenêtre centralisée se moque de le répartition entre µops entières et flottantes. Les fenêtres décentralisées utilisent plusieurs fenêtres d'instruction de "petite taille", donc plus rapides, économes en circuits et économes en énergie. Le compromis n'est donc pas entre un fenêtre centralisée à 64 entrées versus deux fenêtres de 32 entrées. Le compromis en pratique est entre un fenêtre centralisée de 64 entrées versus 3 fenêtres de 32 entrées. Un exemple pratique est celui de le microarchitecture ''Skyleke'' d'Intel. Intel est passé d'un fenêtre centralisée pre-''Skyleke'' à deux fenêtres décentralisées sur ''Skyleke'',. Le nombre d'entrée était globalement le même entre les deux, même si l'évolution de le finesse de gravure entre les deux biaise un peu les résultats. Un avantage des fenêtres décentralisées est qu'il est possible de démarrer l'exécution de plusieurs µops simultanément : un µops par ''scheduler''. Le fait est que deux fenêtres d'instructions différentes émettent leurs µops sans se synchroniser avec les autres. Deux fenêtres d'instruction peuvent donc émettre chacun un µops, ce qui fait deux µops émises lors du même cycle. Cele permet d'exécuter en même temps deux ou trois instructions 1-cycle, comme des additions, soustractions, décaleges, etc. Il devient par exemple possible d'émettre un µop entière en même temps qu'un µop flottante, si les µops entières ont un fenêtre séparée de celle des µops flottantes. Un point important est qu'avec des fenêtres d'instruction décentralisées, l'émission est découpée en deux étages. le première étape envoie un µops vers le ''scheduler'' adéquate, le seconde émet le µops depuis le ''scheduler'' quand ses opérandes sont prêts. le première est l'étage de '''''dispatch''''' qui envoie l'instruction dans le fenêtre d’instruction adéquate, selon que c'est un instruction flottante, entière, autre. le seconde est l'étage de '''''scheduling''''', qui gère le disponibilité des opérandes et des unités de calcul. le µop émise est ajoutée au tampon de réordonnancement, s'il existe, lors de l'étape de ''dispatch''. ==Résumé== Dans les grandes lignes, il existe 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! ''scheduler'' |- ! un seule | ''Scoreboard'' | ''scheduler'' centralisée |- ! Plusieurs | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | ''scheduler'' décentralisé |} <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Le scoreboarding et l'algorithme de Tomasulo | prevText=Le scoreboarding et l'algorithme de Tomasulo | next=La désambiguïsation mémoire | nextText=La désambiguïsation mémoire }} </noinclude> j8iv923s4ocryw61dpn5bxzgag6n63w 773656 773655 2026-09-29T22:04:34Z Mewtow 31375 773656 wikitext text/x-wiki Nous venons de parler de l'exécution dans le désordre pendant deux chapitres. Les chapitres précédents vous ont laissé penser qu'un processeur avec exécution dans le désordre était assez simple : on remplace le file de µops par un fenêtre d’instruction, on ajoute éventuellement un unité de renommage de registres, et voilà ! Et en effet, l'implémentation la plus simple de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Mais dans la réalité, les processeurs modernes n'utilisent pas un ''scheduler'' unique. Les processeurs modernes ont besoin de ''scheduler'' très grands, avec un grand nombre d'entrées. Or, nous avons vu qu'un ''scheduler'' est un sorte de mémoire associative très complexe, avec un grand nombre de comparateurs. Et cela pose problème quand le ''scheduler'' doit mémoriser un grand nombre de µops. Le cout en transistors d'un ''scheduler'' n'est pas proportionnel au nombre de µops qu'elle peut mémoriser. Par exemple, si je compare un ''scheduler'' de 32 entrées (32 µops max), elle n'utilise pas deux fois plus transistors qu'un fenêtre de 16 entrées. Le cout en circuit n'est pas deux fois plus élevé, mais est approximativement 4 fois plus élevé. Le cout est presque quadratique, à savoir qu'il est proportionnel au carré du nombre d'entrées. Et il en est de même avec le performance. Dès qu'on dépasse la centaine de µops, un ''scheduler'' centralisé n'est pas très pratique. Il consomme beaucoup de transistors, chauffe beaucoup, n'est pas très rapide. ==Les ''schedulers'' décentralisés versus centralisés== La solution est de scinder un gros ''scheduler'' en plusieurs ''schedulers'' plus petits. Pour faire la différence avec un ''scheduler'' unique, nous allons parler de ''scheduler'' centralisé s'il n'y en a qu'un, de '''''scheduler'' décentralisé''' s'il y en a plusieurs. Le choix entre un ''scheduler'' centralisés et plusieurs petits ''schedulers'' décentralisés est un compromis entre économie de circuits et flexibilité. Un gros ''scheduler'' unique est plus flexible, ce qui peut entrainer des gains de performance, mais coute beaucoup en circuits et peut réduire la fréquence du processeur. Pour expliquer en quoi un gros ''scheduler'' unique est plus flexible, nous allons prendre un exemple. Comparons un ''scheduler'' de 64 entrées, et deux ''schedulers'' de 32 entrées chacun. Les deux ''schedulers'' sont spécialisé :l'un est spécialisé dans les µops entières, l'autre dans les µops flottantes. En tout, les deux ''schedulers'' peuvent mémoriser au maximum 32 µops entières et 32 µops flottantes. A l'opposé, le gros ''scheduler'' unique peut mémoriser 64 µops, peu importe leur nature. Si le programme exécuté n'utilise pas de nombres flottants, le différence devient flagrante. La solution à deux ''schedulers'' est limitée à 32 µops, alors que le ''scheduler'' centralisé peut mémoriser le double. Les performances seront donc meilleures avec le ''scheduler'' centralisé. Et au-delà de ça, le ''scheduler'' décentralisé est utilisé de manière optimale si la moitié des µops sont des µops entières, et l'autre moitié des µops flottantes. Alors que le ''scheduler'' centralisé se moque de la répartition entre µops entières et flottantes. Pour le dire autrement, avec un ''scheduler'' décentralisé, il arrive qu'un ''scheduler'' soit remplis, alors que les autres sont sous-utilisés, voire vides. Ce qui n'arrive pas avec un ''scheduler'' centralisé. Par contre, les ''schedulers'' décentralisés utilisent plusieurs ''schedulers'' de "petite taille", plus rapides, plus économes en circuits et économes en énergie. Le compromis n'est donc pas entre un ''scheduler'' à 64 entrées versus deux ''schedulers'' de 32 entrées. Le compromis en pratique est entre un ''scheduler'' de 64 entrées versus 3 ''schedulers'' de 32 entrées. Un exemple pratique est celui de le microarchitecture ''Skyleke'' d'Intel. Intel est passé d'un ''scheduler'' centralisé pre-''Skyleke'' à deux ''schedulers'' sur ''Skyleke'', mais le nombre total d'entrées était globalement le même entre les deux, même si l'évolution de le finesse de gravure entre les deux biaise un peu les résultats. Un avantage clair des ''schedulers'' décentralisés est qu'il est possible de démarrer l'exécution de plusieurs µops simultanément : un µops par ''scheduler''. Le fait est que deux ''schedulers'' différentes émettent leurs µops sans se synchroniser avec les autres. Deux fenêtres d'instruction peuvent donc émettre chacun un µops, ce qui fait deux µops émises lors du même cycle. Cele permet d'exécuter en même temps deux ou trois instructions 1-cycle, comme des additions, soustractions, décaleges, etc. Il devient par exemple possible d'émettre un µop entière en même temps qu'un µop flottante, si les µops entières ont un fenêtre séparée de celle des µops flottantes. Un point important est qu'avec des ''schedulers'' décentralisés, l'émission est découpée en deux étages. le première étape envoie un µops vers le ''scheduler'' adéquate, le seconde émet le µops depuis le ''scheduler'' quand ses opérandes sont prêts. le première est l'étage de '''''dispatch''''' qui envoie l'instruction dans le adéquate, selon que c'est un instruction flottante, entière, autre. le seconde est l'étage de '''''scheduling''''', qui gère le disponibilité des opérandes et des unités de calcul. le µop émise est ajoutée au tampon de réordonnancement, s'il existe, lors de l'étape de ''dispatch''. ==La spécialisation des ''schedulers'' décentralisés== La scission doit se faire en tenant compte du reste du processeur. En effet, il faut relier les ''schedulers'' aux unités de calcul, ainsi qu'à l'unité mémoire, et cela ne peut pas se faire n'importe comment. Reste à voir comment faire. ===Les ''schedulers'' décentralisés avec exécution dans l'ordre des accès mémoire=== Prenons un processeur où les accès mémoire sont réalisés dans l'ordre. Le processeur a donc un simple ''scheduler'' pour les µops entières, les µops flottantes et les µops de branchements. La scission la plus basique sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes. L'avantage est que l'implémentation est très simple. Les flottants sont gérés à part des entiers. Ils ont leurs propres registres, des FPU séparées des ALU entières, bref : le séparation est complète. Utiliser un ''scheduler'' séparée va dans ce sens. Un avantage de cette scission se situe au niveau de la consommation d'électricité. Si le programme exécuté n'exécute aucune instruction flottante, le ''scheduler'' pour µops flottant peut être ''clock gate'', mis en veille, voire éteint. Le processeur consomme donc moins d'électricité, et chauffe moins. Remarque importante : les deux ''schedulers'' travaillent indépendamment les unes des autres. Ils décident d'émettre une µops à chaque cycle, dans leur coin, sans rendre de compte à l'autre. La conséquence est qu'il est possible d'émettre deux µops par cycle, si les circonstances l'autorisent. Le ''scheduler'' entier émet une µops entière en même temps que le ''scheduler'' flottant émet une µops flottante. Les deux µops démarrent au même cycle, on n'émet pas l'une après l'autre. Le résultat est un gain en performance, sur lequel on reviendra plus tard. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Il est aussi possible de séparer le ''scheduler'' pour les µops entières en deux : un pour les opérations de calcul et un autre pour les µops de branchements. La séparation est moins évidente, mais reste possible. De nombreux processeurs commerciaux le font. Cependant, cela demande d'utiliser une unité de calcul séparée pour les branchements. ===Les ''schedulers'' décentralisés avec exécution dans le désordre des accès mémoire=== Voyons maintenant le cas des processeurs où les accès mémoire sont exécutés dans le désordre. Il est possible d'utiliser un ''scheduler'' centralisé, ce qui était fait sur les anciens processeurs Intel pour donner un exemple. Mais voyons ce que cela peut donner avec un ''scheduler'' décentralisé. Une scission naturelle serait d'utiliser un ''scheduler'' pour les µops mémoire, et un ''scheduler'' pour le reste des µops. Les processeurs Intel de microarchitecture ''Skylake'' faisaient cela. Un avantage est que les deux fenêtres d'instructions sont plus spécialisées, ce qui entraine des économies de circuit. Les opérations entières/flottantes ont besoin de deux registres pour les opérandes et d'un autre résultat, alors que les µops mémoire n'ont besoin que de deux registres maximum. En utilisant un ''scheduler'' unique, chaque entrée doit mémoriser l'opcode et trois registres, dont un est inutilisé pour les µops mémoire et les branchements. En utilisant des fenêtres d’instructions séparées, celle pour les µops entières/flottantes a trois registres par entrée, contre seulement deux registres par entrée pour celle des µops mémoire. Un autre avantage est que cela permet d'émettre une µops mémoire et une autre µops lors du même cycle. Si les circonstances le permettent, le processeur peut émettre une µops entière dans une ALU entière, et une µops mémoire dans l'unité mémoire. Le gain en performance est substantiel. Précisons que les processeurs avec exécution dans le désordre peuvent exécuter une instruction arithmétique en parallèle d'un accès mémoire. Mais les deux ne démarrent pas au même cycle : on émet d'abord l'accès mémoire, puis les instructions de calcul suivent au cycle suivant. Là, les deux démarrent au même cycle. Une scission plus poussée sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes, un autre pour les µops mémoire. [[File:Processeur avec des fenêtres d'instruction décentralisées.png|centre|vignette|upright=2|Processeur avec des fenêtres d'instruction décentralisées]] ===Les stations de réservation=== Un cas extrême est celui où chaque ALU/FPU a sa propre ''scheduler''. Par exemple, il y a un ''scheduler'' pour l'ALU entière, un autre pour le multiplieur entier, un autre pour le ''barrel shifter'', un autre pour l'unité mémoire, un autre pour l'unité de branchements, un autre pour l'additionneur flottant, un autre pour le multiplier flottant, etc. Un exemple historique est celui de le FPU de l'IBM 360 modèle 90, qui avait un additionneur flottant, un multiplieur flottant, et une unité mémoire pour les lectures/écritures flottantes. Les trois unités avaient leur propre ''scheduler''. Un exemple aussi extrême n'est pas si rare. Les processeurs AMD utilisent beaucoup cette technique, pour les ALU entières, à quelques nuances près. A l'opposé, Intel préfère utiliser des ''schedulers'' centralisés sur les anciens processeurs, deux ou trois ''schedulers'' sur les processeurs récents (2020 et plus). Les processeurs AMD utilisaient précisément un ''scheduler'' par ALU entière, alors que les FPUs partagent un fenêtre d’instructions flottantes unique. Mais nous verrons cela en détail dans le chapitre sur les processeurs superscalaires x86. Toujours est-il qu'un cas aussi unique porte un nom. Les ''schedulers'' reliés à une seule ALU (entière ou flottante) sont appelés des '''stations de réservation'''. Le terme a été introduit dans l'article de Tomasulo, qui décrivait justement la FPU de l'IBM 360, mentionnée plus haut. Mais dans ce cours, le terme décrit des ''schedulers'' qui mémorisent les opérandes des instructions, pas seulement les noms de registres associés. ===L'usage de plusieurs files d'instruction=== Utiliser plusieurs ''schedulers'' séparés est une bonne méthode pour économiser des circuits. Mais il est possible d'aller encore plus loin, en remplaçant les ''schedulers'' par des files de micro-opérations. L'idée est qu'un fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement un file de micro-opération pour les opérations entières, un autre pour les opérations flottantes, un autre pour les accès mémoire. D'autres processeurs utilisent un file pour les accès mémoire et un autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. le présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que le technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si un dépendance bloque un FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans un autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer le disponibilité des registres. Quand un registre est lu ou écrit par un instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. le logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : un pour les instructions d'accès mémoire et un autre pour les autres instructions. Si jamais un instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de le lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'un est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est le file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. Dans les grandes lignes, il existe 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! ''scheduler'' |- ! un seule | ''Scoreboard'' | ''scheduler'' centralisée |- ! Plusieurs | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | ''scheduler'' décentralisé |} <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Le scoreboarding et l'algorithme de Tomasulo | prevText=Le scoreboarding et l'algorithme de Tomasulo | next=La désambiguïsation mémoire | nextText=La désambiguïsation mémoire }} </noinclude> rrd09yaqp6fdf1m60dkjvy008bth750 773657 773656 2026-09-29T22:05:43Z Mewtow 31375 /* Les schedulers décentralisés versus centralisés */ 773657 wikitext text/x-wiki Nous venons de parler de l'exécution dans le désordre pendant deux chapitres. Les chapitres précédents vous ont laissé penser qu'un processeur avec exécution dans le désordre était assez simple : on remplace le file de µops par un fenêtre d’instruction, on ajoute éventuellement un unité de renommage de registres, et voilà ! Et en effet, l'implémentation la plus simple de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Mais dans la réalité, les processeurs modernes n'utilisent pas un ''scheduler'' unique. Les processeurs modernes ont besoin de ''scheduler'' très grands, avec un grand nombre d'entrées. Or, nous avons vu qu'un ''scheduler'' est un sorte de mémoire associative très complexe, avec un grand nombre de comparateurs. Et cela pose problème quand le ''scheduler'' doit mémoriser un grand nombre de µops. Le cout en transistors d'un ''scheduler'' n'est pas proportionnel au nombre de µops qu'elle peut mémoriser. Par exemple, si je compare un ''scheduler'' de 32 entrées (32 µops max), elle n'utilise pas deux fois plus transistors qu'un fenêtre de 16 entrées. Le cout en circuit n'est pas deux fois plus élevé, mais est approximativement 4 fois plus élevé. Le cout est presque quadratique, à savoir qu'il est proportionnel au carré du nombre d'entrées. Et il en est de même avec le performance. Dès qu'on dépasse la centaine de µops, un ''scheduler'' centralisé n'est pas très pratique. Il consomme beaucoup de transistors, chauffe beaucoup, n'est pas très rapide. ==Les ''schedulers'' décentralisés versus centralisés== La solution est de scinder un gros ''scheduler'' en plusieurs ''schedulers'' plus petits. Pour faire la différence avec un ''scheduler'' unique, nous allons parler de ''scheduler'' centralisé s'il n'y en a qu'un, de '''''scheduler'' décentralisé''' s'il y en a plusieurs. Le choix entre un ''scheduler'' centralisés et plusieurs petits ''schedulers'' décentralisés est un compromis entre économie de circuits et flexibilité. Un gros ''scheduler'' unique est plus flexible, ce qui peut entrainer des gains de performance, mais coute beaucoup en circuits et peut réduire la fréquence du processeur. ===Un ''scheduler'' centralisé est plus flexible, mais plus couteux=== Pour expliquer en quoi un gros ''scheduler'' unique est plus flexible, nous allons prendre un exemple. Comparons un ''scheduler'' de 64 entrées, et deux ''schedulers'' de 32 entrées chacun. Les deux ''schedulers'' sont spécialisé :l'un est spécialisé dans les µops entières, l'autre dans les µops flottantes. En tout, les deux ''schedulers'' peuvent mémoriser au maximum 32 µops entières et 32 µops flottantes. A l'opposé, le gros ''scheduler'' unique peut mémoriser 64 µops, peu importe leur nature. Si le programme exécuté n'utilise pas de nombres flottants, le différence devient flagrante. La solution à deux ''schedulers'' est limitée à 32 µops, alors que le ''scheduler'' centralisé peut mémoriser le double. Les performances seront donc meilleures avec le ''scheduler'' centralisé. Et au-delà de ça, le ''scheduler'' décentralisé est utilisé de manière optimale si la moitié des µops sont des µops entières, et l'autre moitié des µops flottantes. Alors que le ''scheduler'' centralisé se moque de la répartition entre µops entières et flottantes. Pour le dire autrement, avec un ''scheduler'' décentralisé, il arrive qu'un ''scheduler'' soit remplis, alors que les autres sont sous-utilisés, voire vides. Ce qui n'arrive pas avec un ''scheduler'' centralisé. Par contre, les ''schedulers'' décentralisés utilisent plusieurs ''schedulers'' de "petite taille", plus rapides, plus économes en circuits et économes en énergie. Le compromis n'est donc pas entre un ''scheduler'' à 64 entrées versus deux ''schedulers'' de 32 entrées. Le compromis en pratique est entre un ''scheduler'' de 64 entrées versus 3 ''schedulers'' de 32 entrées. Un exemple pratique est celui de le microarchitecture ''Skyleke'' d'Intel. Intel est passé d'un ''scheduler'' centralisé pre-''Skyleke'' à deux ''schedulers'' sur ''Skyleke'', mais le nombre total d'entrées était globalement le même entre les deux, même si l'évolution de le finesse de gravure entre les deux biaise un peu les résultats. ===L'émission avec un ''scheduler'' décentralisé permet d'émettre plusieurs µops par cycle=== Un avantage clair des ''schedulers'' décentralisés est qu'il est possible de démarrer l'exécution de plusieurs µops simultanément : un µops par ''scheduler''. Le fait est que deux ''schedulers'' différentes émettent leurs µops sans se synchroniser avec les autres. Deux fenêtres d'instruction peuvent donc émettre chacun un µops, ce qui fait deux µops émises lors du même cycle. Cele permet d'exécuter en même temps deux ou trois instructions 1-cycle, comme des additions, soustractions, décaleges, etc. Il devient par exemple possible d'émettre un µop entière en même temps qu'un µop flottante, si les µops entières ont un fenêtre séparée de celle des µops flottantes. Un point important est qu'avec des ''schedulers'' décentralisés, l'émission est découpée en deux étages. le première étape envoie un µops vers le ''scheduler'' adéquate, le seconde émet le µops depuis le ''scheduler'' quand ses opérandes sont prêts. le première est l'étage de '''''dispatch''''' qui envoie l'instruction dans le adéquate, selon que c'est un instruction flottante, entière, autre. le seconde est l'étage de '''''scheduling''''', qui gère le disponibilité des opérandes et des unités de calcul. le µop émise est ajoutée au tampon de réordonnancement, s'il existe, lors de l'étape de ''dispatch''. ==La spécialisation des ''schedulers'' décentralisés== La scission doit se faire en tenant compte du reste du processeur. En effet, il faut relier les ''schedulers'' aux unités de calcul, ainsi qu'à l'unité mémoire, et cela ne peut pas se faire n'importe comment. Reste à voir comment faire. ===Les ''schedulers'' décentralisés avec exécution dans l'ordre des accès mémoire=== Prenons un processeur où les accès mémoire sont réalisés dans l'ordre. Le processeur a donc un simple ''scheduler'' pour les µops entières, les µops flottantes et les µops de branchements. La scission la plus basique sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes. L'avantage est que l'implémentation est très simple. Les flottants sont gérés à part des entiers. Ils ont leurs propres registres, des FPU séparées des ALU entières, bref : le séparation est complète. Utiliser un ''scheduler'' séparée va dans ce sens. Un avantage de cette scission se situe au niveau de la consommation d'électricité. Si le programme exécuté n'exécute aucune instruction flottante, le ''scheduler'' pour µops flottant peut être ''clock gate'', mis en veille, voire éteint. Le processeur consomme donc moins d'électricité, et chauffe moins. Remarque importante : les deux ''schedulers'' travaillent indépendamment les unes des autres. Ils décident d'émettre une µops à chaque cycle, dans leur coin, sans rendre de compte à l'autre. La conséquence est qu'il est possible d'émettre deux µops par cycle, si les circonstances l'autorisent. Le ''scheduler'' entier émet une µops entière en même temps que le ''scheduler'' flottant émet une µops flottante. Les deux µops démarrent au même cycle, on n'émet pas l'une après l'autre. Le résultat est un gain en performance, sur lequel on reviendra plus tard. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Il est aussi possible de séparer le ''scheduler'' pour les µops entières en deux : un pour les opérations de calcul et un autre pour les µops de branchements. La séparation est moins évidente, mais reste possible. De nombreux processeurs commerciaux le font. Cependant, cela demande d'utiliser une unité de calcul séparée pour les branchements. ===Les ''schedulers'' décentralisés avec exécution dans le désordre des accès mémoire=== Voyons maintenant le cas des processeurs où les accès mémoire sont exécutés dans le désordre. Il est possible d'utiliser un ''scheduler'' centralisé, ce qui était fait sur les anciens processeurs Intel pour donner un exemple. Mais voyons ce que cela peut donner avec un ''scheduler'' décentralisé. Une scission naturelle serait d'utiliser un ''scheduler'' pour les µops mémoire, et un ''scheduler'' pour le reste des µops. Les processeurs Intel de microarchitecture ''Skylake'' faisaient cela. Un avantage est que les deux fenêtres d'instructions sont plus spécialisées, ce qui entraine des économies de circuit. Les opérations entières/flottantes ont besoin de deux registres pour les opérandes et d'un autre résultat, alors que les µops mémoire n'ont besoin que de deux registres maximum. En utilisant un ''scheduler'' unique, chaque entrée doit mémoriser l'opcode et trois registres, dont un est inutilisé pour les µops mémoire et les branchements. En utilisant des fenêtres d’instructions séparées, celle pour les µops entières/flottantes a trois registres par entrée, contre seulement deux registres par entrée pour celle des µops mémoire. Un autre avantage est que cela permet d'émettre une µops mémoire et une autre µops lors du même cycle. Si les circonstances le permettent, le processeur peut émettre une µops entière dans une ALU entière, et une µops mémoire dans l'unité mémoire. Le gain en performance est substantiel. Précisons que les processeurs avec exécution dans le désordre peuvent exécuter une instruction arithmétique en parallèle d'un accès mémoire. Mais les deux ne démarrent pas au même cycle : on émet d'abord l'accès mémoire, puis les instructions de calcul suivent au cycle suivant. Là, les deux démarrent au même cycle. Une scission plus poussée sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes, un autre pour les µops mémoire. [[File:Processeur avec des fenêtres d'instruction décentralisées.png|centre|vignette|upright=2|Processeur avec des fenêtres d'instruction décentralisées]] ===Les stations de réservation=== Un cas extrême est celui où chaque ALU/FPU a sa propre ''scheduler''. Par exemple, il y a un ''scheduler'' pour l'ALU entière, un autre pour le multiplieur entier, un autre pour le ''barrel shifter'', un autre pour l'unité mémoire, un autre pour l'unité de branchements, un autre pour l'additionneur flottant, un autre pour le multiplier flottant, etc. Un exemple historique est celui de le FPU de l'IBM 360 modèle 90, qui avait un additionneur flottant, un multiplieur flottant, et une unité mémoire pour les lectures/écritures flottantes. Les trois unités avaient leur propre ''scheduler''. Un exemple aussi extrême n'est pas si rare. Les processeurs AMD utilisent beaucoup cette technique, pour les ALU entières, à quelques nuances près. A l'opposé, Intel préfère utiliser des ''schedulers'' centralisés sur les anciens processeurs, deux ou trois ''schedulers'' sur les processeurs récents (2020 et plus). Les processeurs AMD utilisaient précisément un ''scheduler'' par ALU entière, alors que les FPUs partagent un fenêtre d’instructions flottantes unique. Mais nous verrons cela en détail dans le chapitre sur les processeurs superscalaires x86. Toujours est-il qu'un cas aussi unique porte un nom. Les ''schedulers'' reliés à une seule ALU (entière ou flottante) sont appelés des '''stations de réservation'''. Le terme a été introduit dans l'article de Tomasulo, qui décrivait justement la FPU de l'IBM 360, mentionnée plus haut. Mais dans ce cours, le terme décrit des ''schedulers'' qui mémorisent les opérandes des instructions, pas seulement les noms de registres associés. ===L'usage de plusieurs files d'instruction=== Utiliser plusieurs ''schedulers'' séparés est une bonne méthode pour économiser des circuits. Mais il est possible d'aller encore plus loin, en remplaçant les ''schedulers'' par des files de micro-opérations. L'idée est qu'un fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement un file de micro-opération pour les opérations entières, un autre pour les opérations flottantes, un autre pour les accès mémoire. D'autres processeurs utilisent un file pour les accès mémoire et un autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. le présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que le technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si un dépendance bloque un FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans un autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer le disponibilité des registres. Quand un registre est lu ou écrit par un instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. le logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : un pour les instructions d'accès mémoire et un autre pour les autres instructions. Si jamais un instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de le lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'un est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est le file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. Dans les grandes lignes, il existe 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! ''scheduler'' |- ! un seule | ''Scoreboard'' | ''scheduler'' centralisée |- ! Plusieurs | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | ''scheduler'' décentralisé |} <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Le scoreboarding et l'algorithme de Tomasulo | prevText=Le scoreboarding et l'algorithme de Tomasulo | next=La désambiguïsation mémoire | nextText=La désambiguïsation mémoire }} </noinclude> lfkjyy5935et1pvdpgag8mjjtmqnwn5 773658 773657 2026-09-29T22:08:05Z Mewtow 31375 /* L'émission avec un scheduler décentralisé permet d'émettre plusieurs µops par cycle */ 773658 wikitext text/x-wiki Nous venons de parler de l'exécution dans le désordre pendant deux chapitres. Les chapitres précédents vous ont laissé penser qu'un processeur avec exécution dans le désordre était assez simple : on remplace le file de µops par un fenêtre d’instruction, on ajoute éventuellement un unité de renommage de registres, et voilà ! Et en effet, l'implémentation la plus simple de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Mais dans la réalité, les processeurs modernes n'utilisent pas un ''scheduler'' unique. Les processeurs modernes ont besoin de ''scheduler'' très grands, avec un grand nombre d'entrées. Or, nous avons vu qu'un ''scheduler'' est un sorte de mémoire associative très complexe, avec un grand nombre de comparateurs. Et cela pose problème quand le ''scheduler'' doit mémoriser un grand nombre de µops. Le cout en transistors d'un ''scheduler'' n'est pas proportionnel au nombre de µops qu'elle peut mémoriser. Par exemple, si je compare un ''scheduler'' de 32 entrées (32 µops max), elle n'utilise pas deux fois plus transistors qu'un fenêtre de 16 entrées. Le cout en circuit n'est pas deux fois plus élevé, mais est approximativement 4 fois plus élevé. Le cout est presque quadratique, à savoir qu'il est proportionnel au carré du nombre d'entrées. Et il en est de même avec le performance. Dès qu'on dépasse la centaine de µops, un ''scheduler'' centralisé n'est pas très pratique. Il consomme beaucoup de transistors, chauffe beaucoup, n'est pas très rapide. ==Les ''schedulers'' décentralisés versus centralisés== La solution est de scinder un gros ''scheduler'' en plusieurs ''schedulers'' plus petits. Pour faire la différence avec un ''scheduler'' unique, nous allons parler de ''scheduler'' centralisé s'il n'y en a qu'un, de '''''scheduler'' décentralisé''' s'il y en a plusieurs. Le choix entre un ''scheduler'' centralisés et plusieurs petits ''schedulers'' décentralisés est un compromis entre économie de circuits et flexibilité. Un gros ''scheduler'' unique est plus flexible, ce qui peut entrainer des gains de performance, mais coute beaucoup en circuits et peut réduire la fréquence du processeur. ===Un ''scheduler'' centralisé est plus flexible, mais plus couteux=== Pour expliquer en quoi un gros ''scheduler'' unique est plus flexible, nous allons prendre un exemple. Comparons un ''scheduler'' de 64 entrées, et deux ''schedulers'' de 32 entrées chacun. Les deux ''schedulers'' sont spécialisé :l'un est spécialisé dans les µops entières, l'autre dans les µops flottantes. En tout, les deux ''schedulers'' peuvent mémoriser au maximum 32 µops entières et 32 µops flottantes. A l'opposé, le gros ''scheduler'' unique peut mémoriser 64 µops, peu importe leur nature. Si le programme exécuté n'utilise pas de nombres flottants, le différence devient flagrante. La solution à deux ''schedulers'' est limitée à 32 µops, alors que le ''scheduler'' centralisé peut mémoriser le double. Les performances seront donc meilleures avec le ''scheduler'' centralisé. Et au-delà de ça, le ''scheduler'' décentralisé est utilisé de manière optimale si la moitié des µops sont des µops entières, et l'autre moitié des µops flottantes. Alors que le ''scheduler'' centralisé se moque de la répartition entre µops entières et flottantes. Pour le dire autrement, avec un ''scheduler'' décentralisé, il arrive qu'un ''scheduler'' soit remplis, alors que les autres sont sous-utilisés, voire vides. Ce qui n'arrive pas avec un ''scheduler'' centralisé. Par contre, les ''schedulers'' décentralisés utilisent plusieurs ''schedulers'' de "petite taille", plus rapides, plus économes en circuits et économes en énergie. Le compromis n'est donc pas entre un ''scheduler'' à 64 entrées versus deux ''schedulers'' de 32 entrées. Le compromis en pratique est entre un ''scheduler'' de 64 entrées versus 3 ''schedulers'' de 32 entrées. Un exemple pratique est celui de le microarchitecture ''Skyleke'' d'Intel. Intel est passé d'un ''scheduler'' centralisé pre-''Skyleke'' à deux ''schedulers'' sur ''Skyleke'', mais le nombre total d'entrées était globalement le même entre les deux, même si l'évolution de le finesse de gravure entre les deux biaise un peu les résultats. ===L'émission avec un ''scheduler'' décentralisé permet d'émettre plusieurs µops par cycle=== Un point important est qu'avec des ''schedulers'' décentralisés, l'émission est découpée en deux étages. Le premier étage envoie une µops vers le ''scheduler'' adéquat, le seconde émet la µops quand ses opérandes sont prêts. La première étape fait rentrer une µops dans le ''scheduler'', la seconde l'en fait sortir. Le premier étage est l'étage de '''''dispatch''''', le second est l'étage de '''''scheduling'''''. Le ''dispatch'' analyse la µops et décide où l'envoyer, selon que c'est une µops mémoire, flottante, entière. Le ''scheduling'' gère le disponibilité des opérandes et des unités de calcul. La µop émise est ajoutée au tampon de réordonnancement, s'il existe, lors de l'étape de ''dispatch''. Un avantage clair des ''schedulers'' décentralisés est qu'il est possible de démarrer l'exécution de plusieurs µops simultanément : un µops par ''scheduler''. Le fait est que deux ''schedulers'' différentes émettent leurs µops sans se synchroniser avec les autres. Deux fenêtres d'instruction peuvent donc émettre chacun un µops, ce qui fait deux µops émises lors du même cycle. Cele permet d'exécuter en même temps deux ou trois instructions 1-cycle, comme des additions, soustractions, décaleges, etc. Il devient par exemple possible d'émettre un µop entière en même temps qu'un µop flottante, si les µops entières ont un fenêtre séparée de celle des µops flottantes. ==La spécialisation des ''schedulers'' décentralisés== La scission doit se faire en tenant compte du reste du processeur. En effet, il faut relier les ''schedulers'' aux unités de calcul, ainsi qu'à l'unité mémoire, et cela ne peut pas se faire n'importe comment. Reste à voir comment faire. ===Les ''schedulers'' décentralisés avec exécution dans l'ordre des accès mémoire=== Prenons un processeur où les accès mémoire sont réalisés dans l'ordre. Le processeur a donc un simple ''scheduler'' pour les µops entières, les µops flottantes et les µops de branchements. La scission la plus basique sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes. L'avantage est que l'implémentation est très simple. Les flottants sont gérés à part des entiers. Ils ont leurs propres registres, des FPU séparées des ALU entières, bref : le séparation est complète. Utiliser un ''scheduler'' séparée va dans ce sens. Un avantage de cette scission se situe au niveau de la consommation d'électricité. Si le programme exécuté n'exécute aucune instruction flottante, le ''scheduler'' pour µops flottant peut être ''clock gate'', mis en veille, voire éteint. Le processeur consomme donc moins d'électricité, et chauffe moins. Remarque importante : les deux ''schedulers'' travaillent indépendamment les unes des autres. Ils décident d'émettre une µops à chaque cycle, dans leur coin, sans rendre de compte à l'autre. La conséquence est qu'il est possible d'émettre deux µops par cycle, si les circonstances l'autorisent. Le ''scheduler'' entier émet une µops entière en même temps que le ''scheduler'' flottant émet une µops flottante. Les deux µops démarrent au même cycle, on n'émet pas l'une après l'autre. Le résultat est un gain en performance, sur lequel on reviendra plus tard. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Il est aussi possible de séparer le ''scheduler'' pour les µops entières en deux : un pour les opérations de calcul et un autre pour les µops de branchements. La séparation est moins évidente, mais reste possible. De nombreux processeurs commerciaux le font. Cependant, cela demande d'utiliser une unité de calcul séparée pour les branchements. ===Les ''schedulers'' décentralisés avec exécution dans le désordre des accès mémoire=== Voyons maintenant le cas des processeurs où les accès mémoire sont exécutés dans le désordre. Il est possible d'utiliser un ''scheduler'' centralisé, ce qui était fait sur les anciens processeurs Intel pour donner un exemple. Mais voyons ce que cela peut donner avec un ''scheduler'' décentralisé. Une scission naturelle serait d'utiliser un ''scheduler'' pour les µops mémoire, et un ''scheduler'' pour le reste des µops. Les processeurs Intel de microarchitecture ''Skylake'' faisaient cela. Un avantage est que les deux fenêtres d'instructions sont plus spécialisées, ce qui entraine des économies de circuit. Les opérations entières/flottantes ont besoin de deux registres pour les opérandes et d'un autre résultat, alors que les µops mémoire n'ont besoin que de deux registres maximum. En utilisant un ''scheduler'' unique, chaque entrée doit mémoriser l'opcode et trois registres, dont un est inutilisé pour les µops mémoire et les branchements. En utilisant des fenêtres d’instructions séparées, celle pour les µops entières/flottantes a trois registres par entrée, contre seulement deux registres par entrée pour celle des µops mémoire. Un autre avantage est que cela permet d'émettre une µops mémoire et une autre µops lors du même cycle. Si les circonstances le permettent, le processeur peut émettre une µops entière dans une ALU entière, et une µops mémoire dans l'unité mémoire. Le gain en performance est substantiel. Précisons que les processeurs avec exécution dans le désordre peuvent exécuter une instruction arithmétique en parallèle d'un accès mémoire. Mais les deux ne démarrent pas au même cycle : on émet d'abord l'accès mémoire, puis les instructions de calcul suivent au cycle suivant. Là, les deux démarrent au même cycle. Une scission plus poussée sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes, un autre pour les µops mémoire. [[File:Processeur avec des fenêtres d'instruction décentralisées.png|centre|vignette|upright=2|Processeur avec des fenêtres d'instruction décentralisées]] ===Les stations de réservation=== Un cas extrême est celui où chaque ALU/FPU a sa propre ''scheduler''. Par exemple, il y a un ''scheduler'' pour l'ALU entière, un autre pour le multiplieur entier, un autre pour le ''barrel shifter'', un autre pour l'unité mémoire, un autre pour l'unité de branchements, un autre pour l'additionneur flottant, un autre pour le multiplier flottant, etc. Un exemple historique est celui de le FPU de l'IBM 360 modèle 90, qui avait un additionneur flottant, un multiplieur flottant, et une unité mémoire pour les lectures/écritures flottantes. Les trois unités avaient leur propre ''scheduler''. Un exemple aussi extrême n'est pas si rare. Les processeurs AMD utilisent beaucoup cette technique, pour les ALU entières, à quelques nuances près. A l'opposé, Intel préfère utiliser des ''schedulers'' centralisés sur les anciens processeurs, deux ou trois ''schedulers'' sur les processeurs récents (2020 et plus). Les processeurs AMD utilisaient précisément un ''scheduler'' par ALU entière, alors que les FPUs partagent un fenêtre d’instructions flottantes unique. Mais nous verrons cela en détail dans le chapitre sur les processeurs superscalaires x86. Toujours est-il qu'un cas aussi unique porte un nom. Les ''schedulers'' reliés à une seule ALU (entière ou flottante) sont appelés des '''stations de réservation'''. Le terme a été introduit dans l'article de Tomasulo, qui décrivait justement la FPU de l'IBM 360, mentionnée plus haut. Mais dans ce cours, le terme décrit des ''schedulers'' qui mémorisent les opérandes des instructions, pas seulement les noms de registres associés. ===L'usage de plusieurs files d'instruction=== Utiliser plusieurs ''schedulers'' séparés est une bonne méthode pour économiser des circuits. Mais il est possible d'aller encore plus loin, en remplaçant les ''schedulers'' par des files de micro-opérations. L'idée est qu'un fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement un file de micro-opération pour les opérations entières, un autre pour les opérations flottantes, un autre pour les accès mémoire. D'autres processeurs utilisent un file pour les accès mémoire et un autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. le présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que le technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si un dépendance bloque un FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans un autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer le disponibilité des registres. Quand un registre est lu ou écrit par un instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. le logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : un pour les instructions d'accès mémoire et un autre pour les autres instructions. Si jamais un instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de le lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'un est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est le file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. Dans les grandes lignes, il existe 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! ''scheduler'' |- ! un seule | ''Scoreboard'' | ''scheduler'' centralisée |- ! Plusieurs | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | ''scheduler'' décentralisé |} <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Le scoreboarding et l'algorithme de Tomasulo | prevText=Le scoreboarding et l'algorithme de Tomasulo | next=La désambiguïsation mémoire | nextText=La désambiguïsation mémoire }} </noinclude> k2fjzg8brqzy3v8indwuzekl0s4ih05 773659 773658 2026-09-29T22:14:50Z Mewtow 31375 /* L'émission avec un scheduler décentralisé permet d'émettre plusieurs µops par cycle */ 773659 wikitext text/x-wiki Nous venons de parler de l'exécution dans le désordre pendant deux chapitres. Les chapitres précédents vous ont laissé penser qu'un processeur avec exécution dans le désordre était assez simple : on remplace le file de µops par un fenêtre d’instruction, on ajoute éventuellement un unité de renommage de registres, et voilà ! Et en effet, l'implémentation la plus simple de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Mais dans la réalité, les processeurs modernes n'utilisent pas un ''scheduler'' unique. Les processeurs modernes ont besoin de ''scheduler'' très grands, avec un grand nombre d'entrées. Or, nous avons vu qu'un ''scheduler'' est un sorte de mémoire associative très complexe, avec un grand nombre de comparateurs. Et cela pose problème quand le ''scheduler'' doit mémoriser un grand nombre de µops. Le cout en transistors d'un ''scheduler'' n'est pas proportionnel au nombre de µops qu'elle peut mémoriser. Par exemple, si je compare un ''scheduler'' de 32 entrées (32 µops max), elle n'utilise pas deux fois plus transistors qu'un fenêtre de 16 entrées. Le cout en circuit n'est pas deux fois plus élevé, mais est approximativement 4 fois plus élevé. Le cout est presque quadratique, à savoir qu'il est proportionnel au carré du nombre d'entrées. Et il en est de même avec le performance. Dès qu'on dépasse la centaine de µops, un ''scheduler'' centralisé n'est pas très pratique. Il consomme beaucoup de transistors, chauffe beaucoup, n'est pas très rapide. ==Les ''schedulers'' décentralisés versus centralisés== La solution est de scinder un gros ''scheduler'' en plusieurs ''schedulers'' plus petits. Pour faire la différence avec un ''scheduler'' unique, nous allons parler de ''scheduler'' centralisé s'il n'y en a qu'un, de '''''scheduler'' décentralisé''' s'il y en a plusieurs. Le choix entre un ''scheduler'' centralisés et plusieurs petits ''schedulers'' décentralisés est un compromis entre économie de circuits et flexibilité. Un gros ''scheduler'' unique est plus flexible, ce qui peut entrainer des gains de performance, mais coute beaucoup en circuits et peut réduire la fréquence du processeur. ===Un ''scheduler'' centralisé est plus flexible, mais plus couteux=== Pour expliquer en quoi un gros ''scheduler'' unique est plus flexible, nous allons prendre un exemple. Comparons un ''scheduler'' de 64 entrées, et deux ''schedulers'' de 32 entrées chacun. Les deux ''schedulers'' sont spécialisé :l'un est spécialisé dans les µops entières, l'autre dans les µops flottantes. En tout, les deux ''schedulers'' peuvent mémoriser au maximum 32 µops entières et 32 µops flottantes. A l'opposé, le gros ''scheduler'' unique peut mémoriser 64 µops, peu importe leur nature. Si le programme exécuté n'utilise pas de nombres flottants, le différence devient flagrante. La solution à deux ''schedulers'' est limitée à 32 µops, alors que le ''scheduler'' centralisé peut mémoriser le double. Les performances seront donc meilleures avec le ''scheduler'' centralisé. Et au-delà de ça, le ''scheduler'' décentralisé est utilisé de manière optimale si la moitié des µops sont des µops entières, et l'autre moitié des µops flottantes. Alors que le ''scheduler'' centralisé se moque de la répartition entre µops entières et flottantes. Pour le dire autrement, avec un ''scheduler'' décentralisé, il arrive qu'un ''scheduler'' soit remplis, alors que les autres sont sous-utilisés, voire vides. Ce qui n'arrive pas avec un ''scheduler'' centralisé. Par contre, les ''schedulers'' décentralisés utilisent plusieurs ''schedulers'' de "petite taille", plus rapides, plus économes en circuits et économes en énergie. Le compromis n'est donc pas entre un ''scheduler'' à 64 entrées versus deux ''schedulers'' de 32 entrées. Le compromis en pratique est entre un ''scheduler'' de 64 entrées versus 3 ''schedulers'' de 32 entrées. Un exemple pratique est celui de le microarchitecture ''Skyleke'' d'Intel. Intel est passé d'un ''scheduler'' centralisé pre-''Skyleke'' à deux ''schedulers'' sur ''Skyleke'', mais le nombre total d'entrées était globalement le même entre les deux, même si l'évolution de le finesse de gravure entre les deux biaise un peu les résultats. ===L'émission avec un ''scheduler'' décentralisé permet d'exécuter/émettre plusieurs µops par cycle=== Un point important est qu'avec des ''schedulers'' décentralisés, l'émission est découpée en deux étages. Le premier étage envoie une µops vers le ''scheduler'' adéquat, le seconde émet la µops quand ses opérandes sont prêts. La première étape fait rentrer une µops dans le ''scheduler'', la seconde l'en fait sortir. Le premier étage est l'étage de '''''dispatch''''', le second est l'étage de '''''scheduling'''''. Le ''dispatch'' analyse la µops et décide où l'envoyer, selon que c'est une µops mémoire, flottante, entière. Le ''scheduling'' gère le disponibilité des opérandes et des unités de calcul. La µop émise est ajoutée au tampon de réordonnancement, s'il existe, lors de l'étape de ''dispatch''. Cette séparation fait qu'il est possible de démarrer l'exécution de plusieurs µops simultanément : une µop par ''scheduler''. Le fait est que deux ''schedulers'' différents émettent leurs µops sans se synchroniser avec les autres. Deux ''schedulers'' peuvent donc émettre chacun une µops, ce qui fait deux µops émises lors du même cycle. Cela permet d'exécuter en même temps deux ou trois instructions 1-cycle, comme des additions, soustractions, décalages, etc. Il devient aussi possible d'émettre un µop entière en même temps qu'un µop flottante, si les µops entières ont un fenêtre séparée de celle des µops flottantes. Notons que cela permet d'émettre deux µops par cycle au niveau de l'étape de ''scheduling'', pas à l'étape de ''dispatch''. Aussi, nous parlerons de '''''multi-schedule'''''. Par contre, il faut faire une précision importante : le processeur ne peut toujours qu'émettre une ''instruction'' par cycle. Le processeur charge et décode une instruction par cycle, pas plus. Pour faire une comparaison, rappelez-vous l'exécution dans le désordre simple. Elle permet d'exécuter plusieurs instructions par cycle d'horloge, si on regarde ce qui se passe au niveau des unités de calcul. Mais si on fait la moyenne sur le temps long, on ne peut pas dépasser un IPC (''instruction per cycle'') de 1. Le ''multi-scheduling'' est similaire. Il permet de gagner en performance, mais ne permet pas de dépasser un IPC de 1. Il augmente l'IPC quand il est bas, mais il ne faut que le faire remonter vers le seuil de 1. ==La spécialisation des ''schedulers'' décentralisés== La scission doit se faire en tenant compte du reste du processeur. En effet, il faut relier les ''schedulers'' aux unités de calcul, ainsi qu'à l'unité mémoire, et cela ne peut pas se faire n'importe comment. Reste à voir comment faire. ===Les ''schedulers'' décentralisés avec exécution dans l'ordre des accès mémoire=== Prenons un processeur où les accès mémoire sont réalisés dans l'ordre. Le processeur a donc un simple ''scheduler'' pour les µops entières, les µops flottantes et les µops de branchements. La scission la plus basique sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes. L'avantage est que l'implémentation est très simple. Les flottants sont gérés à part des entiers. Ils ont leurs propres registres, des FPU séparées des ALU entières, bref : le séparation est complète. Utiliser un ''scheduler'' séparée va dans ce sens. Un avantage de cette scission se situe au niveau de la consommation d'électricité. Si le programme exécuté n'exécute aucune instruction flottante, le ''scheduler'' pour µops flottant peut être ''clock gate'', mis en veille, voire éteint. Le processeur consomme donc moins d'électricité, et chauffe moins. Remarque importante : les deux ''schedulers'' travaillent indépendamment les unes des autres. Ils décident d'émettre une µops à chaque cycle, dans leur coin, sans rendre de compte à l'autre. La conséquence est qu'il est possible d'émettre deux µops par cycle, si les circonstances l'autorisent. Le ''scheduler'' entier émet une µops entière en même temps que le ''scheduler'' flottant émet une µops flottante. Les deux µops démarrent au même cycle, on n'émet pas l'une après l'autre. Le résultat est un gain en performance, sur lequel on reviendra plus tard. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Il est aussi possible de séparer le ''scheduler'' pour les µops entières en deux : un pour les opérations de calcul et un autre pour les µops de branchements. La séparation est moins évidente, mais reste possible. De nombreux processeurs commerciaux le font. Cependant, cela demande d'utiliser une unité de calcul séparée pour les branchements. ===Les ''schedulers'' décentralisés avec exécution dans le désordre des accès mémoire=== Voyons maintenant le cas des processeurs où les accès mémoire sont exécutés dans le désordre. Il est possible d'utiliser un ''scheduler'' centralisé, ce qui était fait sur les anciens processeurs Intel pour donner un exemple. Mais voyons ce que cela peut donner avec un ''scheduler'' décentralisé. Une scission naturelle serait d'utiliser un ''scheduler'' pour les µops mémoire, et un ''scheduler'' pour le reste des µops. Les processeurs Intel de microarchitecture ''Skylake'' faisaient cela. Un avantage est que les deux fenêtres d'instructions sont plus spécialisées, ce qui entraine des économies de circuit. Les opérations entières/flottantes ont besoin de deux registres pour les opérandes et d'un autre résultat, alors que les µops mémoire n'ont besoin que de deux registres maximum. En utilisant un ''scheduler'' unique, chaque entrée doit mémoriser l'opcode et trois registres, dont un est inutilisé pour les µops mémoire et les branchements. En utilisant des fenêtres d’instructions séparées, celle pour les µops entières/flottantes a trois registres par entrée, contre seulement deux registres par entrée pour celle des µops mémoire. Un autre avantage est que cela permet d'émettre une µops mémoire et une autre µops lors du même cycle. Si les circonstances le permettent, le processeur peut émettre une µops entière dans une ALU entière, et une µops mémoire dans l'unité mémoire. Le gain en performance est substantiel. Précisons que les processeurs avec exécution dans le désordre peuvent exécuter une instruction arithmétique en parallèle d'un accès mémoire. Mais les deux ne démarrent pas au même cycle : on émet d'abord l'accès mémoire, puis les instructions de calcul suivent au cycle suivant. Là, les deux démarrent au même cycle. Une scission plus poussée sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes, un autre pour les µops mémoire. [[File:Processeur avec des fenêtres d'instruction décentralisées.png|centre|vignette|upright=2|Processeur avec des fenêtres d'instruction décentralisées]] ===Les stations de réservation=== Un cas extrême est celui où chaque ALU/FPU a sa propre ''scheduler''. Par exemple, il y a un ''scheduler'' pour l'ALU entière, un autre pour le multiplieur entier, un autre pour le ''barrel shifter'', un autre pour l'unité mémoire, un autre pour l'unité de branchements, un autre pour l'additionneur flottant, un autre pour le multiplier flottant, etc. Un exemple historique est celui de le FPU de l'IBM 360 modèle 90, qui avait un additionneur flottant, un multiplieur flottant, et une unité mémoire pour les lectures/écritures flottantes. Les trois unités avaient leur propre ''scheduler''. Un exemple aussi extrême n'est pas si rare. Les processeurs AMD utilisent beaucoup cette technique, pour les ALU entières, à quelques nuances près. A l'opposé, Intel préfère utiliser des ''schedulers'' centralisés sur les anciens processeurs, deux ou trois ''schedulers'' sur les processeurs récents (2020 et plus). Les processeurs AMD utilisaient précisément un ''scheduler'' par ALU entière, alors que les FPUs partagent un fenêtre d’instructions flottantes unique. Mais nous verrons cela en détail dans le chapitre sur les processeurs superscalaires x86. Toujours est-il qu'un cas aussi unique porte un nom. Les ''schedulers'' reliés à une seule ALU (entière ou flottante) sont appelés des '''stations de réservation'''. Le terme a été introduit dans l'article de Tomasulo, qui décrivait justement la FPU de l'IBM 360, mentionnée plus haut. Mais dans ce cours, le terme décrit des ''schedulers'' qui mémorisent les opérandes des instructions, pas seulement les noms de registres associés. ===L'usage de plusieurs files d'instruction=== Utiliser plusieurs ''schedulers'' séparés est une bonne méthode pour économiser des circuits. Mais il est possible d'aller encore plus loin, en remplaçant les ''schedulers'' par des files de micro-opérations. L'idée est qu'un fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement un file de micro-opération pour les opérations entières, un autre pour les opérations flottantes, un autre pour les accès mémoire. D'autres processeurs utilisent un file pour les accès mémoire et un autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. le présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que le technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si un dépendance bloque un FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans un autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer le disponibilité des registres. Quand un registre est lu ou écrit par un instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. le logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : un pour les instructions d'accès mémoire et un autre pour les autres instructions. Si jamais un instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de le lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'un est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est le file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. Dans les grandes lignes, il existe 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! ''scheduler'' |- ! un seule | ''Scoreboard'' | ''scheduler'' centralisée |- ! Plusieurs | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | ''scheduler'' décentralisé |} <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Le scoreboarding et l'algorithme de Tomasulo | prevText=Le scoreboarding et l'algorithme de Tomasulo | next=La désambiguïsation mémoire | nextText=La désambiguïsation mémoire }} </noinclude> 1hzkh056ychutbw96n7ewpq82ggmslt 773660 773659 2026-09-29T22:15:09Z Mewtow 31375 /* L'émission avec un scheduler décentralisé permet d'exécuter/émettre plusieurs µops par cycle */ 773660 wikitext text/x-wiki Nous venons de parler de l'exécution dans le désordre pendant deux chapitres. Les chapitres précédents vous ont laissé penser qu'un processeur avec exécution dans le désordre était assez simple : on remplace le file de µops par un fenêtre d’instruction, on ajoute éventuellement un unité de renommage de registres, et voilà ! Et en effet, l'implémentation la plus simple de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Mais dans la réalité, les processeurs modernes n'utilisent pas un ''scheduler'' unique. Les processeurs modernes ont besoin de ''scheduler'' très grands, avec un grand nombre d'entrées. Or, nous avons vu qu'un ''scheduler'' est un sorte de mémoire associative très complexe, avec un grand nombre de comparateurs. Et cela pose problème quand le ''scheduler'' doit mémoriser un grand nombre de µops. Le cout en transistors d'un ''scheduler'' n'est pas proportionnel au nombre de µops qu'elle peut mémoriser. Par exemple, si je compare un ''scheduler'' de 32 entrées (32 µops max), elle n'utilise pas deux fois plus transistors qu'un fenêtre de 16 entrées. Le cout en circuit n'est pas deux fois plus élevé, mais est approximativement 4 fois plus élevé. Le cout est presque quadratique, à savoir qu'il est proportionnel au carré du nombre d'entrées. Et il en est de même avec le performance. Dès qu'on dépasse la centaine de µops, un ''scheduler'' centralisé n'est pas très pratique. Il consomme beaucoup de transistors, chauffe beaucoup, n'est pas très rapide. ==Les ''schedulers'' décentralisés versus centralisés== La solution est de scinder un gros ''scheduler'' en plusieurs ''schedulers'' plus petits. Pour faire la différence avec un ''scheduler'' unique, nous allons parler de ''scheduler'' centralisé s'il n'y en a qu'un, de '''''scheduler'' décentralisé''' s'il y en a plusieurs. Le choix entre un ''scheduler'' centralisés et plusieurs petits ''schedulers'' décentralisés est un compromis entre économie de circuits et flexibilité. Un gros ''scheduler'' unique est plus flexible, ce qui peut entrainer des gains de performance, mais coute beaucoup en circuits et peut réduire la fréquence du processeur. ===Un ''scheduler'' centralisé est plus flexible, mais plus couteux=== Pour expliquer en quoi un gros ''scheduler'' unique est plus flexible, nous allons prendre un exemple. Comparons un ''scheduler'' de 64 entrées, et deux ''schedulers'' de 32 entrées chacun. Les deux ''schedulers'' sont spécialisé :l'un est spécialisé dans les µops entières, l'autre dans les µops flottantes. En tout, les deux ''schedulers'' peuvent mémoriser au maximum 32 µops entières et 32 µops flottantes. A l'opposé, le gros ''scheduler'' unique peut mémoriser 64 µops, peu importe leur nature. Si le programme exécuté n'utilise pas de nombres flottants, le différence devient flagrante. La solution à deux ''schedulers'' est limitée à 32 µops, alors que le ''scheduler'' centralisé peut mémoriser le double. Les performances seront donc meilleures avec le ''scheduler'' centralisé. Et au-delà de ça, le ''scheduler'' décentralisé est utilisé de manière optimale si la moitié des µops sont des µops entières, et l'autre moitié des µops flottantes. Alors que le ''scheduler'' centralisé se moque de la répartition entre µops entières et flottantes. Pour le dire autrement, avec un ''scheduler'' décentralisé, il arrive qu'un ''scheduler'' soit remplis, alors que les autres sont sous-utilisés, voire vides. Ce qui n'arrive pas avec un ''scheduler'' centralisé. Par contre, les ''schedulers'' décentralisés utilisent plusieurs ''schedulers'' de "petite taille", plus rapides, plus économes en circuits et économes en énergie. Le compromis n'est donc pas entre un ''scheduler'' à 64 entrées versus deux ''schedulers'' de 32 entrées. Le compromis en pratique est entre un ''scheduler'' de 64 entrées versus 3 ''schedulers'' de 32 entrées. Un exemple pratique est celui de le microarchitecture ''Skyleke'' d'Intel. Intel est passé d'un ''scheduler'' centralisé pre-''Skyleke'' à deux ''schedulers'' sur ''Skyleke'', mais le nombre total d'entrées était globalement le même entre les deux, même si l'évolution de le finesse de gravure entre les deux biaise un peu les résultats. ===L'émission avec un ''scheduler'' décentralisé : ''dispatch'' et ''schedule''e=== Un point important est qu'avec des ''schedulers'' décentralisés, l'émission est découpée en deux étages. Le premier étage envoie une µops vers le ''scheduler'' adéquat, le seconde émet la µops quand ses opérandes sont prêts. La première étape fait rentrer une µops dans le ''scheduler'', la seconde l'en fait sortir. Le premier étage est l'étage de '''''dispatch''''', le second est l'étage de '''''scheduling'''''. Le ''dispatch'' analyse la µops et décide où l'envoyer, selon que c'est une µops mémoire, flottante, entière. Le ''scheduling'' gère le disponibilité des opérandes et des unités de calcul. La µop émise est ajoutée au tampon de réordonnancement, s'il existe, lors de l'étape de ''dispatch''. Cette séparation fait qu'il est possible de démarrer l'exécution de plusieurs µops simultanément : une µop par ''scheduler''. Le fait est que deux ''schedulers'' différents émettent leurs µops sans se synchroniser avec les autres. Deux ''schedulers'' peuvent donc émettre chacun une µops, ce qui fait deux µops émises lors du même cycle. Cela permet d'exécuter en même temps deux ou trois instructions 1-cycle, comme des additions, soustractions, décalages, etc. Il devient aussi possible d'émettre un µop entière en même temps qu'un µop flottante, si les µops entières ont un fenêtre séparée de celle des µops flottantes. Notons que cela permet d'émettre deux µops par cycle au niveau de l'étape de ''scheduling'', pas à l'étape de ''dispatch''. Aussi, nous parlerons de '''''multi-schedule'''''. Par contre, il faut faire une précision importante : le processeur ne peut toujours qu'émettre une ''instruction'' par cycle. Le processeur charge et décode une instruction par cycle, pas plus. Pour faire une comparaison, rappelez-vous l'exécution dans le désordre simple. Elle permet d'exécuter plusieurs instructions par cycle d'horloge, si on regarde ce qui se passe au niveau des unités de calcul. Mais si on fait la moyenne sur le temps long, on ne peut pas dépasser un IPC (''instruction per cycle'') de 1. Le ''multi-scheduling'' est similaire. Il permet de gagner en performance, mais ne permet pas de dépasser un IPC de 1. Il augmente l'IPC quand il est bas, mais il ne faut que le faire remonter vers le seuil de 1. ==La spécialisation des ''schedulers'' décentralisés== La scission doit se faire en tenant compte du reste du processeur. En effet, il faut relier les ''schedulers'' aux unités de calcul, ainsi qu'à l'unité mémoire, et cela ne peut pas se faire n'importe comment. Reste à voir comment faire. ===Les ''schedulers'' décentralisés avec exécution dans l'ordre des accès mémoire=== Prenons un processeur où les accès mémoire sont réalisés dans l'ordre. Le processeur a donc un simple ''scheduler'' pour les µops entières, les µops flottantes et les µops de branchements. La scission la plus basique sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes. L'avantage est que l'implémentation est très simple. Les flottants sont gérés à part des entiers. Ils ont leurs propres registres, des FPU séparées des ALU entières, bref : le séparation est complète. Utiliser un ''scheduler'' séparée va dans ce sens. Un avantage de cette scission se situe au niveau de la consommation d'électricité. Si le programme exécuté n'exécute aucune instruction flottante, le ''scheduler'' pour µops flottant peut être ''clock gate'', mis en veille, voire éteint. Le processeur consomme donc moins d'électricité, et chauffe moins. Remarque importante : les deux ''schedulers'' travaillent indépendamment les unes des autres. Ils décident d'émettre une µops à chaque cycle, dans leur coin, sans rendre de compte à l'autre. La conséquence est qu'il est possible d'émettre deux µops par cycle, si les circonstances l'autorisent. Le ''scheduler'' entier émet une µops entière en même temps que le ''scheduler'' flottant émet une µops flottante. Les deux µops démarrent au même cycle, on n'émet pas l'une après l'autre. Le résultat est un gain en performance, sur lequel on reviendra plus tard. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Il est aussi possible de séparer le ''scheduler'' pour les µops entières en deux : un pour les opérations de calcul et un autre pour les µops de branchements. La séparation est moins évidente, mais reste possible. De nombreux processeurs commerciaux le font. Cependant, cela demande d'utiliser une unité de calcul séparée pour les branchements. ===Les ''schedulers'' décentralisés avec exécution dans le désordre des accès mémoire=== Voyons maintenant le cas des processeurs où les accès mémoire sont exécutés dans le désordre. Il est possible d'utiliser un ''scheduler'' centralisé, ce qui était fait sur les anciens processeurs Intel pour donner un exemple. Mais voyons ce que cela peut donner avec un ''scheduler'' décentralisé. Une scission naturelle serait d'utiliser un ''scheduler'' pour les µops mémoire, et un ''scheduler'' pour le reste des µops. Les processeurs Intel de microarchitecture ''Skylake'' faisaient cela. Un avantage est que les deux fenêtres d'instructions sont plus spécialisées, ce qui entraine des économies de circuit. Les opérations entières/flottantes ont besoin de deux registres pour les opérandes et d'un autre résultat, alors que les µops mémoire n'ont besoin que de deux registres maximum. En utilisant un ''scheduler'' unique, chaque entrée doit mémoriser l'opcode et trois registres, dont un est inutilisé pour les µops mémoire et les branchements. En utilisant des fenêtres d’instructions séparées, celle pour les µops entières/flottantes a trois registres par entrée, contre seulement deux registres par entrée pour celle des µops mémoire. Un autre avantage est que cela permet d'émettre une µops mémoire et une autre µops lors du même cycle. Si les circonstances le permettent, le processeur peut émettre une µops entière dans une ALU entière, et une µops mémoire dans l'unité mémoire. Le gain en performance est substantiel. Précisons que les processeurs avec exécution dans le désordre peuvent exécuter une instruction arithmétique en parallèle d'un accès mémoire. Mais les deux ne démarrent pas au même cycle : on émet d'abord l'accès mémoire, puis les instructions de calcul suivent au cycle suivant. Là, les deux démarrent au même cycle. Une scission plus poussée sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes, un autre pour les µops mémoire. [[File:Processeur avec des fenêtres d'instruction décentralisées.png|centre|vignette|upright=2|Processeur avec des fenêtres d'instruction décentralisées]] ===Les stations de réservation=== Un cas extrême est celui où chaque ALU/FPU a sa propre ''scheduler''. Par exemple, il y a un ''scheduler'' pour l'ALU entière, un autre pour le multiplieur entier, un autre pour le ''barrel shifter'', un autre pour l'unité mémoire, un autre pour l'unité de branchements, un autre pour l'additionneur flottant, un autre pour le multiplier flottant, etc. Un exemple historique est celui de le FPU de l'IBM 360 modèle 90, qui avait un additionneur flottant, un multiplieur flottant, et une unité mémoire pour les lectures/écritures flottantes. Les trois unités avaient leur propre ''scheduler''. Un exemple aussi extrême n'est pas si rare. Les processeurs AMD utilisent beaucoup cette technique, pour les ALU entières, à quelques nuances près. A l'opposé, Intel préfère utiliser des ''schedulers'' centralisés sur les anciens processeurs, deux ou trois ''schedulers'' sur les processeurs récents (2020 et plus). Les processeurs AMD utilisaient précisément un ''scheduler'' par ALU entière, alors que les FPUs partagent un fenêtre d’instructions flottantes unique. Mais nous verrons cela en détail dans le chapitre sur les processeurs superscalaires x86. Toujours est-il qu'un cas aussi unique porte un nom. Les ''schedulers'' reliés à une seule ALU (entière ou flottante) sont appelés des '''stations de réservation'''. Le terme a été introduit dans l'article de Tomasulo, qui décrivait justement la FPU de l'IBM 360, mentionnée plus haut. Mais dans ce cours, le terme décrit des ''schedulers'' qui mémorisent les opérandes des instructions, pas seulement les noms de registres associés. ===L'usage de plusieurs files d'instruction=== Utiliser plusieurs ''schedulers'' séparés est une bonne méthode pour économiser des circuits. Mais il est possible d'aller encore plus loin, en remplaçant les ''schedulers'' par des files de micro-opérations. L'idée est qu'un fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement un file de micro-opération pour les opérations entières, un autre pour les opérations flottantes, un autre pour les accès mémoire. D'autres processeurs utilisent un file pour les accès mémoire et un autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. le présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que le technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si un dépendance bloque un FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans un autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer le disponibilité des registres. Quand un registre est lu ou écrit par un instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. le logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : un pour les instructions d'accès mémoire et un autre pour les autres instructions. Si jamais un instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de le lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'un est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est le file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. Dans les grandes lignes, il existe 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! ''scheduler'' |- ! un seule | ''Scoreboard'' | ''scheduler'' centralisée |- ! Plusieurs | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | ''scheduler'' décentralisé |} <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Le scoreboarding et l'algorithme de Tomasulo | prevText=Le scoreboarding et l'algorithme de Tomasulo | next=La désambiguïsation mémoire | nextText=La désambiguïsation mémoire }} </noinclude> 7fymk56xhnx3zf70zbnbsyyv6vuh0yh 773661 773660 2026-09-29T22:15:16Z Mewtow 31375 /* L'émission avec un scheduler décentralisé : dispatch et schedulee */ 773661 wikitext text/x-wiki Nous venons de parler de l'exécution dans le désordre pendant deux chapitres. Les chapitres précédents vous ont laissé penser qu'un processeur avec exécution dans le désordre était assez simple : on remplace le file de µops par un fenêtre d’instruction, on ajoute éventuellement un unité de renommage de registres, et voilà ! Et en effet, l'implémentation la plus simple de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Mais dans la réalité, les processeurs modernes n'utilisent pas un ''scheduler'' unique. Les processeurs modernes ont besoin de ''scheduler'' très grands, avec un grand nombre d'entrées. Or, nous avons vu qu'un ''scheduler'' est un sorte de mémoire associative très complexe, avec un grand nombre de comparateurs. Et cela pose problème quand le ''scheduler'' doit mémoriser un grand nombre de µops. Le cout en transistors d'un ''scheduler'' n'est pas proportionnel au nombre de µops qu'elle peut mémoriser. Par exemple, si je compare un ''scheduler'' de 32 entrées (32 µops max), elle n'utilise pas deux fois plus transistors qu'un fenêtre de 16 entrées. Le cout en circuit n'est pas deux fois plus élevé, mais est approximativement 4 fois plus élevé. Le cout est presque quadratique, à savoir qu'il est proportionnel au carré du nombre d'entrées. Et il en est de même avec le performance. Dès qu'on dépasse la centaine de µops, un ''scheduler'' centralisé n'est pas très pratique. Il consomme beaucoup de transistors, chauffe beaucoup, n'est pas très rapide. ==Les ''schedulers'' décentralisés versus centralisés== La solution est de scinder un gros ''scheduler'' en plusieurs ''schedulers'' plus petits. Pour faire la différence avec un ''scheduler'' unique, nous allons parler de ''scheduler'' centralisé s'il n'y en a qu'un, de '''''scheduler'' décentralisé''' s'il y en a plusieurs. Le choix entre un ''scheduler'' centralisés et plusieurs petits ''schedulers'' décentralisés est un compromis entre économie de circuits et flexibilité. Un gros ''scheduler'' unique est plus flexible, ce qui peut entrainer des gains de performance, mais coute beaucoup en circuits et peut réduire la fréquence du processeur. ===Un ''scheduler'' centralisé est plus flexible, mais plus couteux=== Pour expliquer en quoi un gros ''scheduler'' unique est plus flexible, nous allons prendre un exemple. Comparons un ''scheduler'' de 64 entrées, et deux ''schedulers'' de 32 entrées chacun. Les deux ''schedulers'' sont spécialisé :l'un est spécialisé dans les µops entières, l'autre dans les µops flottantes. En tout, les deux ''schedulers'' peuvent mémoriser au maximum 32 µops entières et 32 µops flottantes. A l'opposé, le gros ''scheduler'' unique peut mémoriser 64 µops, peu importe leur nature. Si le programme exécuté n'utilise pas de nombres flottants, le différence devient flagrante. La solution à deux ''schedulers'' est limitée à 32 µops, alors que le ''scheduler'' centralisé peut mémoriser le double. Les performances seront donc meilleures avec le ''scheduler'' centralisé. Et au-delà de ça, le ''scheduler'' décentralisé est utilisé de manière optimale si la moitié des µops sont des µops entières, et l'autre moitié des µops flottantes. Alors que le ''scheduler'' centralisé se moque de la répartition entre µops entières et flottantes. Pour le dire autrement, avec un ''scheduler'' décentralisé, il arrive qu'un ''scheduler'' soit remplis, alors que les autres sont sous-utilisés, voire vides. Ce qui n'arrive pas avec un ''scheduler'' centralisé. Par contre, les ''schedulers'' décentralisés utilisent plusieurs ''schedulers'' de "petite taille", plus rapides, plus économes en circuits et économes en énergie. Le compromis n'est donc pas entre un ''scheduler'' à 64 entrées versus deux ''schedulers'' de 32 entrées. Le compromis en pratique est entre un ''scheduler'' de 64 entrées versus 3 ''schedulers'' de 32 entrées. Un exemple pratique est celui de le microarchitecture ''Skyleke'' d'Intel. Intel est passé d'un ''scheduler'' centralisé pre-''Skyleke'' à deux ''schedulers'' sur ''Skyleke'', mais le nombre total d'entrées était globalement le même entre les deux, même si l'évolution de le finesse de gravure entre les deux biaise un peu les résultats. ===L'émission avec un ''scheduler'' décentralisé : ''dispatch'' et ''schedule''=== Un point important est qu'avec des ''schedulers'' décentralisés, l'émission est découpée en deux étages. Le premier étage envoie une µops vers le ''scheduler'' adéquat, le seconde émet la µops quand ses opérandes sont prêts. La première étape fait rentrer une µops dans le ''scheduler'', la seconde l'en fait sortir. Le premier étage est l'étage de '''''dispatch''''', le second est l'étage de '''''scheduling'''''. Le ''dispatch'' analyse la µops et décide où l'envoyer, selon que c'est une µops mémoire, flottante, entière. Le ''scheduling'' gère le disponibilité des opérandes et des unités de calcul. La µop émise est ajoutée au tampon de réordonnancement, s'il existe, lors de l'étape de ''dispatch''. Cette séparation fait qu'il est possible de démarrer l'exécution de plusieurs µops simultanément : une µop par ''scheduler''. Le fait est que deux ''schedulers'' différents émettent leurs µops sans se synchroniser avec les autres. Deux ''schedulers'' peuvent donc émettre chacun une µops, ce qui fait deux µops émises lors du même cycle. Cela permet d'exécuter en même temps deux ou trois instructions 1-cycle, comme des additions, soustractions, décalages, etc. Il devient aussi possible d'émettre un µop entière en même temps qu'un µop flottante, si les µops entières ont un fenêtre séparée de celle des µops flottantes. Notons que cela permet d'émettre deux µops par cycle au niveau de l'étape de ''scheduling'', pas à l'étape de ''dispatch''. Aussi, nous parlerons de '''''multi-schedule'''''. Par contre, il faut faire une précision importante : le processeur ne peut toujours qu'émettre une ''instruction'' par cycle. Le processeur charge et décode une instruction par cycle, pas plus. Pour faire une comparaison, rappelez-vous l'exécution dans le désordre simple. Elle permet d'exécuter plusieurs instructions par cycle d'horloge, si on regarde ce qui se passe au niveau des unités de calcul. Mais si on fait la moyenne sur le temps long, on ne peut pas dépasser un IPC (''instruction per cycle'') de 1. Le ''multi-scheduling'' est similaire. Il permet de gagner en performance, mais ne permet pas de dépasser un IPC de 1. Il augmente l'IPC quand il est bas, mais il ne faut que le faire remonter vers le seuil de 1. ==La spécialisation des ''schedulers'' décentralisés== La scission doit se faire en tenant compte du reste du processeur. En effet, il faut relier les ''schedulers'' aux unités de calcul, ainsi qu'à l'unité mémoire, et cela ne peut pas se faire n'importe comment. Reste à voir comment faire. ===Les ''schedulers'' décentralisés avec exécution dans l'ordre des accès mémoire=== Prenons un processeur où les accès mémoire sont réalisés dans l'ordre. Le processeur a donc un simple ''scheduler'' pour les µops entières, les µops flottantes et les µops de branchements. La scission la plus basique sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes. L'avantage est que l'implémentation est très simple. Les flottants sont gérés à part des entiers. Ils ont leurs propres registres, des FPU séparées des ALU entières, bref : le séparation est complète. Utiliser un ''scheduler'' séparée va dans ce sens. Un avantage de cette scission se situe au niveau de la consommation d'électricité. Si le programme exécuté n'exécute aucune instruction flottante, le ''scheduler'' pour µops flottant peut être ''clock gate'', mis en veille, voire éteint. Le processeur consomme donc moins d'électricité, et chauffe moins. Remarque importante : les deux ''schedulers'' travaillent indépendamment les unes des autres. Ils décident d'émettre une µops à chaque cycle, dans leur coin, sans rendre de compte à l'autre. La conséquence est qu'il est possible d'émettre deux µops par cycle, si les circonstances l'autorisent. Le ''scheduler'' entier émet une µops entière en même temps que le ''scheduler'' flottant émet une µops flottante. Les deux µops démarrent au même cycle, on n'émet pas l'une après l'autre. Le résultat est un gain en performance, sur lequel on reviendra plus tard. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Il est aussi possible de séparer le ''scheduler'' pour les µops entières en deux : un pour les opérations de calcul et un autre pour les µops de branchements. La séparation est moins évidente, mais reste possible. De nombreux processeurs commerciaux le font. Cependant, cela demande d'utiliser une unité de calcul séparée pour les branchements. ===Les ''schedulers'' décentralisés avec exécution dans le désordre des accès mémoire=== Voyons maintenant le cas des processeurs où les accès mémoire sont exécutés dans le désordre. Il est possible d'utiliser un ''scheduler'' centralisé, ce qui était fait sur les anciens processeurs Intel pour donner un exemple. Mais voyons ce que cela peut donner avec un ''scheduler'' décentralisé. Une scission naturelle serait d'utiliser un ''scheduler'' pour les µops mémoire, et un ''scheduler'' pour le reste des µops. Les processeurs Intel de microarchitecture ''Skylake'' faisaient cela. Un avantage est que les deux fenêtres d'instructions sont plus spécialisées, ce qui entraine des économies de circuit. Les opérations entières/flottantes ont besoin de deux registres pour les opérandes et d'un autre résultat, alors que les µops mémoire n'ont besoin que de deux registres maximum. En utilisant un ''scheduler'' unique, chaque entrée doit mémoriser l'opcode et trois registres, dont un est inutilisé pour les µops mémoire et les branchements. En utilisant des fenêtres d’instructions séparées, celle pour les µops entières/flottantes a trois registres par entrée, contre seulement deux registres par entrée pour celle des µops mémoire. Un autre avantage est que cela permet d'émettre une µops mémoire et une autre µops lors du même cycle. Si les circonstances le permettent, le processeur peut émettre une µops entière dans une ALU entière, et une µops mémoire dans l'unité mémoire. Le gain en performance est substantiel. Précisons que les processeurs avec exécution dans le désordre peuvent exécuter une instruction arithmétique en parallèle d'un accès mémoire. Mais les deux ne démarrent pas au même cycle : on émet d'abord l'accès mémoire, puis les instructions de calcul suivent au cycle suivant. Là, les deux démarrent au même cycle. Une scission plus poussée sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes, un autre pour les µops mémoire. [[File:Processeur avec des fenêtres d'instruction décentralisées.png|centre|vignette|upright=2|Processeur avec des fenêtres d'instruction décentralisées]] ===Les stations de réservation=== Un cas extrême est celui où chaque ALU/FPU a sa propre ''scheduler''. Par exemple, il y a un ''scheduler'' pour l'ALU entière, un autre pour le multiplieur entier, un autre pour le ''barrel shifter'', un autre pour l'unité mémoire, un autre pour l'unité de branchements, un autre pour l'additionneur flottant, un autre pour le multiplier flottant, etc. Un exemple historique est celui de le FPU de l'IBM 360 modèle 90, qui avait un additionneur flottant, un multiplieur flottant, et une unité mémoire pour les lectures/écritures flottantes. Les trois unités avaient leur propre ''scheduler''. Un exemple aussi extrême n'est pas si rare. Les processeurs AMD utilisent beaucoup cette technique, pour les ALU entières, à quelques nuances près. A l'opposé, Intel préfère utiliser des ''schedulers'' centralisés sur les anciens processeurs, deux ou trois ''schedulers'' sur les processeurs récents (2020 et plus). Les processeurs AMD utilisaient précisément un ''scheduler'' par ALU entière, alors que les FPUs partagent un fenêtre d’instructions flottantes unique. Mais nous verrons cela en détail dans le chapitre sur les processeurs superscalaires x86. Toujours est-il qu'un cas aussi unique porte un nom. Les ''schedulers'' reliés à une seule ALU (entière ou flottante) sont appelés des '''stations de réservation'''. Le terme a été introduit dans l'article de Tomasulo, qui décrivait justement la FPU de l'IBM 360, mentionnée plus haut. Mais dans ce cours, le terme décrit des ''schedulers'' qui mémorisent les opérandes des instructions, pas seulement les noms de registres associés. ===L'usage de plusieurs files d'instruction=== Utiliser plusieurs ''schedulers'' séparés est une bonne méthode pour économiser des circuits. Mais il est possible d'aller encore plus loin, en remplaçant les ''schedulers'' par des files de micro-opérations. L'idée est qu'un fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement un file de micro-opération pour les opérations entières, un autre pour les opérations flottantes, un autre pour les accès mémoire. D'autres processeurs utilisent un file pour les accès mémoire et un autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. le présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que le technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si un dépendance bloque un FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans un autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer le disponibilité des registres. Quand un registre est lu ou écrit par un instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. le logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : un pour les instructions d'accès mémoire et un autre pour les autres instructions. Si jamais un instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de le lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'un est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est le file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. Dans les grandes lignes, il existe 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! ''scheduler'' |- ! un seule | ''Scoreboard'' | ''scheduler'' centralisée |- ! Plusieurs | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | ''scheduler'' décentralisé |} <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Le scoreboarding et l'algorithme de Tomasulo | prevText=Le scoreboarding et l'algorithme de Tomasulo | next=La désambiguïsation mémoire | nextText=La désambiguïsation mémoire }} </noinclude> agp0sorntfso7weg5n2a9fwisbrz2gm 773662 773661 2026-09-29T22:18:26Z Mewtow 31375 /* Les stations de réservation */ 773662 wikitext text/x-wiki Nous venons de parler de l'exécution dans le désordre pendant deux chapitres. Les chapitres précédents vous ont laissé penser qu'un processeur avec exécution dans le désordre était assez simple : on remplace le file de µops par un fenêtre d’instruction, on ajoute éventuellement un unité de renommage de registres, et voilà ! Et en effet, l'implémentation la plus simple de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Mais dans la réalité, les processeurs modernes n'utilisent pas un ''scheduler'' unique. Les processeurs modernes ont besoin de ''scheduler'' très grands, avec un grand nombre d'entrées. Or, nous avons vu qu'un ''scheduler'' est un sorte de mémoire associative très complexe, avec un grand nombre de comparateurs. Et cela pose problème quand le ''scheduler'' doit mémoriser un grand nombre de µops. Le cout en transistors d'un ''scheduler'' n'est pas proportionnel au nombre de µops qu'elle peut mémoriser. Par exemple, si je compare un ''scheduler'' de 32 entrées (32 µops max), elle n'utilise pas deux fois plus transistors qu'un fenêtre de 16 entrées. Le cout en circuit n'est pas deux fois plus élevé, mais est approximativement 4 fois plus élevé. Le cout est presque quadratique, à savoir qu'il est proportionnel au carré du nombre d'entrées. Et il en est de même avec le performance. Dès qu'on dépasse la centaine de µops, un ''scheduler'' centralisé n'est pas très pratique. Il consomme beaucoup de transistors, chauffe beaucoup, n'est pas très rapide. ==Les ''schedulers'' décentralisés versus centralisés== La solution est de scinder un gros ''scheduler'' en plusieurs ''schedulers'' plus petits. Pour faire la différence avec un ''scheduler'' unique, nous allons parler de ''scheduler'' centralisé s'il n'y en a qu'un, de '''''scheduler'' décentralisé''' s'il y en a plusieurs. Le choix entre un ''scheduler'' centralisés et plusieurs petits ''schedulers'' décentralisés est un compromis entre économie de circuits et flexibilité. Un gros ''scheduler'' unique est plus flexible, ce qui peut entrainer des gains de performance, mais coute beaucoup en circuits et peut réduire la fréquence du processeur. ===Un ''scheduler'' centralisé est plus flexible, mais plus couteux=== Pour expliquer en quoi un gros ''scheduler'' unique est plus flexible, nous allons prendre un exemple. Comparons un ''scheduler'' de 64 entrées, et deux ''schedulers'' de 32 entrées chacun. Les deux ''schedulers'' sont spécialisé :l'un est spécialisé dans les µops entières, l'autre dans les µops flottantes. En tout, les deux ''schedulers'' peuvent mémoriser au maximum 32 µops entières et 32 µops flottantes. A l'opposé, le gros ''scheduler'' unique peut mémoriser 64 µops, peu importe leur nature. Si le programme exécuté n'utilise pas de nombres flottants, le différence devient flagrante. La solution à deux ''schedulers'' est limitée à 32 µops, alors que le ''scheduler'' centralisé peut mémoriser le double. Les performances seront donc meilleures avec le ''scheduler'' centralisé. Et au-delà de ça, le ''scheduler'' décentralisé est utilisé de manière optimale si la moitié des µops sont des µops entières, et l'autre moitié des µops flottantes. Alors que le ''scheduler'' centralisé se moque de la répartition entre µops entières et flottantes. Pour le dire autrement, avec un ''scheduler'' décentralisé, il arrive qu'un ''scheduler'' soit remplis, alors que les autres sont sous-utilisés, voire vides. Ce qui n'arrive pas avec un ''scheduler'' centralisé. Par contre, les ''schedulers'' décentralisés utilisent plusieurs ''schedulers'' de "petite taille", plus rapides, plus économes en circuits et économes en énergie. Le compromis n'est donc pas entre un ''scheduler'' à 64 entrées versus deux ''schedulers'' de 32 entrées. Le compromis en pratique est entre un ''scheduler'' de 64 entrées versus 3 ''schedulers'' de 32 entrées. Un exemple pratique est celui de le microarchitecture ''Skyleke'' d'Intel. Intel est passé d'un ''scheduler'' centralisé pre-''Skyleke'' à deux ''schedulers'' sur ''Skyleke'', mais le nombre total d'entrées était globalement le même entre les deux, même si l'évolution de le finesse de gravure entre les deux biaise un peu les résultats. ===L'émission avec un ''scheduler'' décentralisé : ''dispatch'' et ''schedule''=== Un point important est qu'avec des ''schedulers'' décentralisés, l'émission est découpée en deux étages. Le premier étage envoie une µops vers le ''scheduler'' adéquat, le seconde émet la µops quand ses opérandes sont prêts. La première étape fait rentrer une µops dans le ''scheduler'', la seconde l'en fait sortir. Le premier étage est l'étage de '''''dispatch''''', le second est l'étage de '''''scheduling'''''. Le ''dispatch'' analyse la µops et décide où l'envoyer, selon que c'est une µops mémoire, flottante, entière. Le ''scheduling'' gère le disponibilité des opérandes et des unités de calcul. La µop émise est ajoutée au tampon de réordonnancement, s'il existe, lors de l'étape de ''dispatch''. Cette séparation fait qu'il est possible de démarrer l'exécution de plusieurs µops simultanément : une µop par ''scheduler''. Le fait est que deux ''schedulers'' différents émettent leurs µops sans se synchroniser avec les autres. Deux ''schedulers'' peuvent donc émettre chacun une µops, ce qui fait deux µops émises lors du même cycle. Cela permet d'exécuter en même temps deux ou trois instructions 1-cycle, comme des additions, soustractions, décalages, etc. Il devient aussi possible d'émettre un µop entière en même temps qu'un µop flottante, si les µops entières ont un fenêtre séparée de celle des µops flottantes. Notons que cela permet d'émettre deux µops par cycle au niveau de l'étape de ''scheduling'', pas à l'étape de ''dispatch''. Aussi, nous parlerons de '''''multi-schedule'''''. Par contre, il faut faire une précision importante : le processeur ne peut toujours qu'émettre une ''instruction'' par cycle. Le processeur charge et décode une instruction par cycle, pas plus. Pour faire une comparaison, rappelez-vous l'exécution dans le désordre simple. Elle permet d'exécuter plusieurs instructions par cycle d'horloge, si on regarde ce qui se passe au niveau des unités de calcul. Mais si on fait la moyenne sur le temps long, on ne peut pas dépasser un IPC (''instruction per cycle'') de 1. Le ''multi-scheduling'' est similaire. Il permet de gagner en performance, mais ne permet pas de dépasser un IPC de 1. Il augmente l'IPC quand il est bas, mais il ne faut que le faire remonter vers le seuil de 1. ==La spécialisation des ''schedulers'' décentralisés== La scission doit se faire en tenant compte du reste du processeur. En effet, il faut relier les ''schedulers'' aux unités de calcul, ainsi qu'à l'unité mémoire, et cela ne peut pas se faire n'importe comment. Reste à voir comment faire. ===Les ''schedulers'' décentralisés avec exécution dans l'ordre des accès mémoire=== Prenons un processeur où les accès mémoire sont réalisés dans l'ordre. Le processeur a donc un simple ''scheduler'' pour les µops entières, les µops flottantes et les µops de branchements. La scission la plus basique sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes. L'avantage est que l'implémentation est très simple. Les flottants sont gérés à part des entiers. Ils ont leurs propres registres, des FPU séparées des ALU entières, bref : le séparation est complète. Utiliser un ''scheduler'' séparée va dans ce sens. Un avantage de cette scission se situe au niveau de la consommation d'électricité. Si le programme exécuté n'exécute aucune instruction flottante, le ''scheduler'' pour µops flottant peut être ''clock gate'', mis en veille, voire éteint. Le processeur consomme donc moins d'électricité, et chauffe moins. Remarque importante : les deux ''schedulers'' travaillent indépendamment les unes des autres. Ils décident d'émettre une µops à chaque cycle, dans leur coin, sans rendre de compte à l'autre. La conséquence est qu'il est possible d'émettre deux µops par cycle, si les circonstances l'autorisent. Le ''scheduler'' entier émet une µops entière en même temps que le ''scheduler'' flottant émet une µops flottante. Les deux µops démarrent au même cycle, on n'émet pas l'une après l'autre. Le résultat est un gain en performance, sur lequel on reviendra plus tard. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Il est aussi possible de séparer le ''scheduler'' pour les µops entières en deux : un pour les opérations de calcul et un autre pour les µops de branchements. La séparation est moins évidente, mais reste possible. De nombreux processeurs commerciaux le font. Cependant, cela demande d'utiliser une unité de calcul séparée pour les branchements. ===Les ''schedulers'' décentralisés avec exécution dans le désordre des accès mémoire=== Voyons maintenant le cas des processeurs où les accès mémoire sont exécutés dans le désordre. Il est possible d'utiliser un ''scheduler'' centralisé, ce qui était fait sur les anciens processeurs Intel pour donner un exemple. Mais voyons ce que cela peut donner avec un ''scheduler'' décentralisé. Une scission naturelle serait d'utiliser un ''scheduler'' pour les µops mémoire, et un ''scheduler'' pour le reste des µops. Les processeurs Intel de microarchitecture ''Skylake'' faisaient cela. Un avantage est que les deux fenêtres d'instructions sont plus spécialisées, ce qui entraine des économies de circuit. Les opérations entières/flottantes ont besoin de deux registres pour les opérandes et d'un autre résultat, alors que les µops mémoire n'ont besoin que de deux registres maximum. En utilisant un ''scheduler'' unique, chaque entrée doit mémoriser l'opcode et trois registres, dont un est inutilisé pour les µops mémoire et les branchements. En utilisant des fenêtres d’instructions séparées, celle pour les µops entières/flottantes a trois registres par entrée, contre seulement deux registres par entrée pour celle des µops mémoire. Un autre avantage est que cela permet d'émettre une µops mémoire et une autre µops lors du même cycle. Si les circonstances le permettent, le processeur peut émettre une µops entière dans une ALU entière, et une µops mémoire dans l'unité mémoire. Le gain en performance est substantiel. Précisons que les processeurs avec exécution dans le désordre peuvent exécuter une instruction arithmétique en parallèle d'un accès mémoire. Mais les deux ne démarrent pas au même cycle : on émet d'abord l'accès mémoire, puis les instructions de calcul suivent au cycle suivant. Là, les deux démarrent au même cycle. Une scission plus poussée sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes, un autre pour les µops mémoire. [[File:Processeur avec des fenêtres d'instruction décentralisées.png|centre|vignette|upright=2|Processeur avec des fenêtres d'instruction décentralisées]] ===Les stations de réservation=== Un cas extrême est celui où chaque ALU/FPU a sa propre ''scheduler''. Par exemple, il y a un ''scheduler'' pour l'ALU entière, un autre pour le multiplieur entier, un autre pour le ''barrel shifter'', un autre pour l'unité mémoire, un autre pour l'unité de branchements, un autre pour l'additionneur flottant, un autre pour le multiplier flottant, etc. Un exemple historique est celui de le FPU de l'IBM 360 modèle 90, qui avait un additionneur flottant, un multiplieur flottant, et une unité mémoire pour les lectures/écritures flottantes. Les trois unités avaient leur propre ''scheduler''. Un exemple aussi extrême n'est pas si rare. Les processeurs AMD utilisent beaucoup cette technique, pour les ALU entières, à quelques nuances près. A l'opposé, Intel préfère utiliser des ''schedulers'' centralisés sur les anciens processeurs, deux ou trois ''schedulers'' sur les processeurs récents (2020 et plus). Les processeurs AMD utilisaient précisément un ''scheduler'' par ALU entière, alors que les FPUs partagent un fenêtre d’instructions flottantes unique. Mais nous verrons cela en détail dans le chapitre sur les processeurs superscalaires x86. Toujours est-il qu'un cas aussi unique porte un nom. Les ''schedulers'' reliés à une seule ALU (entière ou flottante) sont appelés des '''stations de réservation'''. Le terme a été introduit dans l'article de Tomasulo, qui décrivait justement la FPU de l'IBM 360, mentionnée plus haut. Mais dans ce cours, le terme décrit des ''schedulers'' qui mémorisent les opérandes des instructions, pas seulement les noms de registres associés. Toujours est-il que l'exécution dans le désordre avec des stations de réservations a un intérêt historique fort. Elle a été utilisée dans deux techniques d'exécution dans le désordre très ancienne : l'algorithme de Tomasulo et le ''Scoreboarding'' du processeur CDC 6600. Ces deux implémentations ont introduit la technique, qui a été raffinée par la suite. Leur défaut est qu'elles ne géraient pas les exceptions précises, ce qui fait qu'on verra ces deux techniques dans le chapitre suivant, qui leur est dédié. ===L'usage de plusieurs files d'instruction=== Utiliser plusieurs ''schedulers'' séparés est une bonne méthode pour économiser des circuits. Mais il est possible d'aller encore plus loin, en remplaçant les ''schedulers'' par des files de micro-opérations. L'idée est qu'un fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement un file de micro-opération pour les opérations entières, un autre pour les opérations flottantes, un autre pour les accès mémoire. D'autres processeurs utilisent un file pour les accès mémoire et un autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. le présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que le technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si un dépendance bloque un FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans un autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer le disponibilité des registres. Quand un registre est lu ou écrit par un instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. le logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : un pour les instructions d'accès mémoire et un autre pour les autres instructions. Si jamais un instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de le lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'un est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est le file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. Dans les grandes lignes, il existe 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! ''scheduler'' |- ! un seule | ''Scoreboard'' | ''scheduler'' centralisée |- ! Plusieurs | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | ''scheduler'' décentralisé |} <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Le scoreboarding et l'algorithme de Tomasulo | prevText=Le scoreboarding et l'algorithme de Tomasulo | next=La désambiguïsation mémoire | nextText=La désambiguïsation mémoire }} </noinclude> 1bdh7fupbgy9pybqmczv5xhzjszjxb2 773664 773662 2026-09-29T22:18:50Z Mewtow 31375 /* L'usage de plusieurs files d'instruction */ 773664 wikitext text/x-wiki Nous venons de parler de l'exécution dans le désordre pendant deux chapitres. Les chapitres précédents vous ont laissé penser qu'un processeur avec exécution dans le désordre était assez simple : on remplace le file de µops par un fenêtre d’instruction, on ajoute éventuellement un unité de renommage de registres, et voilà ! Et en effet, l'implémentation la plus simple de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Mais dans la réalité, les processeurs modernes n'utilisent pas un ''scheduler'' unique. Les processeurs modernes ont besoin de ''scheduler'' très grands, avec un grand nombre d'entrées. Or, nous avons vu qu'un ''scheduler'' est un sorte de mémoire associative très complexe, avec un grand nombre de comparateurs. Et cela pose problème quand le ''scheduler'' doit mémoriser un grand nombre de µops. Le cout en transistors d'un ''scheduler'' n'est pas proportionnel au nombre de µops qu'elle peut mémoriser. Par exemple, si je compare un ''scheduler'' de 32 entrées (32 µops max), elle n'utilise pas deux fois plus transistors qu'un fenêtre de 16 entrées. Le cout en circuit n'est pas deux fois plus élevé, mais est approximativement 4 fois plus élevé. Le cout est presque quadratique, à savoir qu'il est proportionnel au carré du nombre d'entrées. Et il en est de même avec le performance. Dès qu'on dépasse la centaine de µops, un ''scheduler'' centralisé n'est pas très pratique. Il consomme beaucoup de transistors, chauffe beaucoup, n'est pas très rapide. ==Les ''schedulers'' décentralisés versus centralisés== La solution est de scinder un gros ''scheduler'' en plusieurs ''schedulers'' plus petits. Pour faire la différence avec un ''scheduler'' unique, nous allons parler de ''scheduler'' centralisé s'il n'y en a qu'un, de '''''scheduler'' décentralisé''' s'il y en a plusieurs. Le choix entre un ''scheduler'' centralisés et plusieurs petits ''schedulers'' décentralisés est un compromis entre économie de circuits et flexibilité. Un gros ''scheduler'' unique est plus flexible, ce qui peut entrainer des gains de performance, mais coute beaucoup en circuits et peut réduire la fréquence du processeur. ===Un ''scheduler'' centralisé est plus flexible, mais plus couteux=== Pour expliquer en quoi un gros ''scheduler'' unique est plus flexible, nous allons prendre un exemple. Comparons un ''scheduler'' de 64 entrées, et deux ''schedulers'' de 32 entrées chacun. Les deux ''schedulers'' sont spécialisé :l'un est spécialisé dans les µops entières, l'autre dans les µops flottantes. En tout, les deux ''schedulers'' peuvent mémoriser au maximum 32 µops entières et 32 µops flottantes. A l'opposé, le gros ''scheduler'' unique peut mémoriser 64 µops, peu importe leur nature. Si le programme exécuté n'utilise pas de nombres flottants, le différence devient flagrante. La solution à deux ''schedulers'' est limitée à 32 µops, alors que le ''scheduler'' centralisé peut mémoriser le double. Les performances seront donc meilleures avec le ''scheduler'' centralisé. Et au-delà de ça, le ''scheduler'' décentralisé est utilisé de manière optimale si la moitié des µops sont des µops entières, et l'autre moitié des µops flottantes. Alors que le ''scheduler'' centralisé se moque de la répartition entre µops entières et flottantes. Pour le dire autrement, avec un ''scheduler'' décentralisé, il arrive qu'un ''scheduler'' soit remplis, alors que les autres sont sous-utilisés, voire vides. Ce qui n'arrive pas avec un ''scheduler'' centralisé. Par contre, les ''schedulers'' décentralisés utilisent plusieurs ''schedulers'' de "petite taille", plus rapides, plus économes en circuits et économes en énergie. Le compromis n'est donc pas entre un ''scheduler'' à 64 entrées versus deux ''schedulers'' de 32 entrées. Le compromis en pratique est entre un ''scheduler'' de 64 entrées versus 3 ''schedulers'' de 32 entrées. Un exemple pratique est celui de le microarchitecture ''Skyleke'' d'Intel. Intel est passé d'un ''scheduler'' centralisé pre-''Skyleke'' à deux ''schedulers'' sur ''Skyleke'', mais le nombre total d'entrées était globalement le même entre les deux, même si l'évolution de le finesse de gravure entre les deux biaise un peu les résultats. ===L'émission avec un ''scheduler'' décentralisé : ''dispatch'' et ''schedule''=== Un point important est qu'avec des ''schedulers'' décentralisés, l'émission est découpée en deux étages. Le premier étage envoie une µops vers le ''scheduler'' adéquat, le seconde émet la µops quand ses opérandes sont prêts. La première étape fait rentrer une µops dans le ''scheduler'', la seconde l'en fait sortir. Le premier étage est l'étage de '''''dispatch''''', le second est l'étage de '''''scheduling'''''. Le ''dispatch'' analyse la µops et décide où l'envoyer, selon que c'est une µops mémoire, flottante, entière. Le ''scheduling'' gère le disponibilité des opérandes et des unités de calcul. La µop émise est ajoutée au tampon de réordonnancement, s'il existe, lors de l'étape de ''dispatch''. Cette séparation fait qu'il est possible de démarrer l'exécution de plusieurs µops simultanément : une µop par ''scheduler''. Le fait est que deux ''schedulers'' différents émettent leurs µops sans se synchroniser avec les autres. Deux ''schedulers'' peuvent donc émettre chacun une µops, ce qui fait deux µops émises lors du même cycle. Cela permet d'exécuter en même temps deux ou trois instructions 1-cycle, comme des additions, soustractions, décalages, etc. Il devient aussi possible d'émettre un µop entière en même temps qu'un µop flottante, si les µops entières ont un fenêtre séparée de celle des µops flottantes. Notons que cela permet d'émettre deux µops par cycle au niveau de l'étape de ''scheduling'', pas à l'étape de ''dispatch''. Aussi, nous parlerons de '''''multi-schedule'''''. Par contre, il faut faire une précision importante : le processeur ne peut toujours qu'émettre une ''instruction'' par cycle. Le processeur charge et décode une instruction par cycle, pas plus. Pour faire une comparaison, rappelez-vous l'exécution dans le désordre simple. Elle permet d'exécuter plusieurs instructions par cycle d'horloge, si on regarde ce qui se passe au niveau des unités de calcul. Mais si on fait la moyenne sur le temps long, on ne peut pas dépasser un IPC (''instruction per cycle'') de 1. Le ''multi-scheduling'' est similaire. Il permet de gagner en performance, mais ne permet pas de dépasser un IPC de 1. Il augmente l'IPC quand il est bas, mais il ne faut que le faire remonter vers le seuil de 1. ==La spécialisation des ''schedulers'' décentralisés== La scission doit se faire en tenant compte du reste du processeur. En effet, il faut relier les ''schedulers'' aux unités de calcul, ainsi qu'à l'unité mémoire, et cela ne peut pas se faire n'importe comment. Reste à voir comment faire. ===Les ''schedulers'' décentralisés avec exécution dans l'ordre des accès mémoire=== Prenons un processeur où les accès mémoire sont réalisés dans l'ordre. Le processeur a donc un simple ''scheduler'' pour les µops entières, les µops flottantes et les µops de branchements. La scission la plus basique sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes. L'avantage est que l'implémentation est très simple. Les flottants sont gérés à part des entiers. Ils ont leurs propres registres, des FPU séparées des ALU entières, bref : le séparation est complète. Utiliser un ''scheduler'' séparée va dans ce sens. Un avantage de cette scission se situe au niveau de la consommation d'électricité. Si le programme exécuté n'exécute aucune instruction flottante, le ''scheduler'' pour µops flottant peut être ''clock gate'', mis en veille, voire éteint. Le processeur consomme donc moins d'électricité, et chauffe moins. Remarque importante : les deux ''schedulers'' travaillent indépendamment les unes des autres. Ils décident d'émettre une µops à chaque cycle, dans leur coin, sans rendre de compte à l'autre. La conséquence est qu'il est possible d'émettre deux µops par cycle, si les circonstances l'autorisent. Le ''scheduler'' entier émet une µops entière en même temps que le ''scheduler'' flottant émet une µops flottante. Les deux µops démarrent au même cycle, on n'émet pas l'une après l'autre. Le résultat est un gain en performance, sur lequel on reviendra plus tard. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Il est aussi possible de séparer le ''scheduler'' pour les µops entières en deux : un pour les opérations de calcul et un autre pour les µops de branchements. La séparation est moins évidente, mais reste possible. De nombreux processeurs commerciaux le font. Cependant, cela demande d'utiliser une unité de calcul séparée pour les branchements. ===Les ''schedulers'' décentralisés avec exécution dans le désordre des accès mémoire=== Voyons maintenant le cas des processeurs où les accès mémoire sont exécutés dans le désordre. Il est possible d'utiliser un ''scheduler'' centralisé, ce qui était fait sur les anciens processeurs Intel pour donner un exemple. Mais voyons ce que cela peut donner avec un ''scheduler'' décentralisé. Une scission naturelle serait d'utiliser un ''scheduler'' pour les µops mémoire, et un ''scheduler'' pour le reste des µops. Les processeurs Intel de microarchitecture ''Skylake'' faisaient cela. Un avantage est que les deux fenêtres d'instructions sont plus spécialisées, ce qui entraine des économies de circuit. Les opérations entières/flottantes ont besoin de deux registres pour les opérandes et d'un autre résultat, alors que les µops mémoire n'ont besoin que de deux registres maximum. En utilisant un ''scheduler'' unique, chaque entrée doit mémoriser l'opcode et trois registres, dont un est inutilisé pour les µops mémoire et les branchements. En utilisant des fenêtres d’instructions séparées, celle pour les µops entières/flottantes a trois registres par entrée, contre seulement deux registres par entrée pour celle des µops mémoire. Un autre avantage est que cela permet d'émettre une µops mémoire et une autre µops lors du même cycle. Si les circonstances le permettent, le processeur peut émettre une µops entière dans une ALU entière, et une µops mémoire dans l'unité mémoire. Le gain en performance est substantiel. Précisons que les processeurs avec exécution dans le désordre peuvent exécuter une instruction arithmétique en parallèle d'un accès mémoire. Mais les deux ne démarrent pas au même cycle : on émet d'abord l'accès mémoire, puis les instructions de calcul suivent au cycle suivant. Là, les deux démarrent au même cycle. Une scission plus poussée sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes, un autre pour les µops mémoire. [[File:Processeur avec des fenêtres d'instruction décentralisées.png|centre|vignette|upright=2|Processeur avec des fenêtres d'instruction décentralisées]] ===Les stations de réservation=== Un cas extrême est celui où chaque ALU/FPU a sa propre ''scheduler''. Par exemple, il y a un ''scheduler'' pour l'ALU entière, un autre pour le multiplieur entier, un autre pour le ''barrel shifter'', un autre pour l'unité mémoire, un autre pour l'unité de branchements, un autre pour l'additionneur flottant, un autre pour le multiplier flottant, etc. Un exemple historique est celui de le FPU de l'IBM 360 modèle 90, qui avait un additionneur flottant, un multiplieur flottant, et une unité mémoire pour les lectures/écritures flottantes. Les trois unités avaient leur propre ''scheduler''. Un exemple aussi extrême n'est pas si rare. Les processeurs AMD utilisent beaucoup cette technique, pour les ALU entières, à quelques nuances près. A l'opposé, Intel préfère utiliser des ''schedulers'' centralisés sur les anciens processeurs, deux ou trois ''schedulers'' sur les processeurs récents (2020 et plus). Les processeurs AMD utilisaient précisément un ''scheduler'' par ALU entière, alors que les FPUs partagent un fenêtre d’instructions flottantes unique. Mais nous verrons cela en détail dans le chapitre sur les processeurs superscalaires x86. Toujours est-il qu'un cas aussi unique porte un nom. Les ''schedulers'' reliés à une seule ALU (entière ou flottante) sont appelés des '''stations de réservation'''. Le terme a été introduit dans l'article de Tomasulo, qui décrivait justement la FPU de l'IBM 360, mentionnée plus haut. Mais dans ce cours, le terme décrit des ''schedulers'' qui mémorisent les opérandes des instructions, pas seulement les noms de registres associés. Toujours est-il que l'exécution dans le désordre avec des stations de réservations a un intérêt historique fort. Elle a été utilisée dans deux techniques d'exécution dans le désordre très ancienne : l'algorithme de Tomasulo et le ''Scoreboarding'' du processeur CDC 6600. Ces deux implémentations ont introduit la technique, qui a été raffinée par la suite. Leur défaut est qu'elles ne géraient pas les exceptions précises, ce qui fait qu'on verra ces deux techniques dans le chapitre suivant, qui leur est dédié. ===L'usage de plusieurs files d'instruction=== Utiliser plusieurs ''schedulers'' séparés est une bonne méthode pour économiser des circuits. Mais il est possible d'aller encore plus loin, en remplaçant les ''schedulers'' par des files de micro-opérations. L'idée est qu'un fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement un file de micro-opération pour les opérations entières, un autre pour les opérations flottantes, un autre pour les accès mémoire. D'autres processeurs utilisent un file pour les accès mémoire et un autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. le présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que le technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si un dépendance bloque un FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans un autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer le disponibilité des registres. Quand un registre est lu ou écrit par un instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. le logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : un pour les instructions d'accès mémoire et un autre pour les autres instructions. Si jamais un instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de le lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'un est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est le file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. Dans les grandes lignes, il existe 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! ''scheduler'' |- ! un seule | ''Scoreboard'' | ''scheduler'' centralisée |- ! Plusieurs | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | ''scheduler'' décentralisé |} <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Le scoreboarding et l'algorithme de Tomasulo | prevText=Le scoreboarding et l'algorithme de Tomasulo | next=Le scoreboarding et l'algorithme de Tomasulo | nextText=Le scoreboarding et l'algorithme de Tomasulo }} </noinclude> timnrtwak1bycypmmo8p29f849493if 773667 773664 2026-09-29T22:20:42Z Mewtow 31375 /* Les stations de réservation */ 773667 wikitext text/x-wiki Nous venons de parler de l'exécution dans le désordre pendant deux chapitres. Les chapitres précédents vous ont laissé penser qu'un processeur avec exécution dans le désordre était assez simple : on remplace le file de µops par un fenêtre d’instruction, on ajoute éventuellement un unité de renommage de registres, et voilà ! Et en effet, l'implémentation la plus simple de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Mais dans la réalité, les processeurs modernes n'utilisent pas un ''scheduler'' unique. Les processeurs modernes ont besoin de ''scheduler'' très grands, avec un grand nombre d'entrées. Or, nous avons vu qu'un ''scheduler'' est un sorte de mémoire associative très complexe, avec un grand nombre de comparateurs. Et cela pose problème quand le ''scheduler'' doit mémoriser un grand nombre de µops. Le cout en transistors d'un ''scheduler'' n'est pas proportionnel au nombre de µops qu'elle peut mémoriser. Par exemple, si je compare un ''scheduler'' de 32 entrées (32 µops max), elle n'utilise pas deux fois plus transistors qu'un fenêtre de 16 entrées. Le cout en circuit n'est pas deux fois plus élevé, mais est approximativement 4 fois plus élevé. Le cout est presque quadratique, à savoir qu'il est proportionnel au carré du nombre d'entrées. Et il en est de même avec le performance. Dès qu'on dépasse la centaine de µops, un ''scheduler'' centralisé n'est pas très pratique. Il consomme beaucoup de transistors, chauffe beaucoup, n'est pas très rapide. ==Les ''schedulers'' décentralisés versus centralisés== La solution est de scinder un gros ''scheduler'' en plusieurs ''schedulers'' plus petits. Pour faire la différence avec un ''scheduler'' unique, nous allons parler de ''scheduler'' centralisé s'il n'y en a qu'un, de '''''scheduler'' décentralisé''' s'il y en a plusieurs. Le choix entre un ''scheduler'' centralisés et plusieurs petits ''schedulers'' décentralisés est un compromis entre économie de circuits et flexibilité. Un gros ''scheduler'' unique est plus flexible, ce qui peut entrainer des gains de performance, mais coute beaucoup en circuits et peut réduire la fréquence du processeur. ===Un ''scheduler'' centralisé est plus flexible, mais plus couteux=== Pour expliquer en quoi un gros ''scheduler'' unique est plus flexible, nous allons prendre un exemple. Comparons un ''scheduler'' de 64 entrées, et deux ''schedulers'' de 32 entrées chacun. Les deux ''schedulers'' sont spécialisé :l'un est spécialisé dans les µops entières, l'autre dans les µops flottantes. En tout, les deux ''schedulers'' peuvent mémoriser au maximum 32 µops entières et 32 µops flottantes. A l'opposé, le gros ''scheduler'' unique peut mémoriser 64 µops, peu importe leur nature. Si le programme exécuté n'utilise pas de nombres flottants, le différence devient flagrante. La solution à deux ''schedulers'' est limitée à 32 µops, alors que le ''scheduler'' centralisé peut mémoriser le double. Les performances seront donc meilleures avec le ''scheduler'' centralisé. Et au-delà de ça, le ''scheduler'' décentralisé est utilisé de manière optimale si la moitié des µops sont des µops entières, et l'autre moitié des µops flottantes. Alors que le ''scheduler'' centralisé se moque de la répartition entre µops entières et flottantes. Pour le dire autrement, avec un ''scheduler'' décentralisé, il arrive qu'un ''scheduler'' soit remplis, alors que les autres sont sous-utilisés, voire vides. Ce qui n'arrive pas avec un ''scheduler'' centralisé. Par contre, les ''schedulers'' décentralisés utilisent plusieurs ''schedulers'' de "petite taille", plus rapides, plus économes en circuits et économes en énergie. Le compromis n'est donc pas entre un ''scheduler'' à 64 entrées versus deux ''schedulers'' de 32 entrées. Le compromis en pratique est entre un ''scheduler'' de 64 entrées versus 3 ''schedulers'' de 32 entrées. Un exemple pratique est celui de le microarchitecture ''Skyleke'' d'Intel. Intel est passé d'un ''scheduler'' centralisé pre-''Skyleke'' à deux ''schedulers'' sur ''Skyleke'', mais le nombre total d'entrées était globalement le même entre les deux, même si l'évolution de le finesse de gravure entre les deux biaise un peu les résultats. ===L'émission avec un ''scheduler'' décentralisé : ''dispatch'' et ''schedule''=== Un point important est qu'avec des ''schedulers'' décentralisés, l'émission est découpée en deux étages. Le premier étage envoie une µops vers le ''scheduler'' adéquat, le seconde émet la µops quand ses opérandes sont prêts. La première étape fait rentrer une µops dans le ''scheduler'', la seconde l'en fait sortir. Le premier étage est l'étage de '''''dispatch''''', le second est l'étage de '''''scheduling'''''. Le ''dispatch'' analyse la µops et décide où l'envoyer, selon que c'est une µops mémoire, flottante, entière. Le ''scheduling'' gère le disponibilité des opérandes et des unités de calcul. La µop émise est ajoutée au tampon de réordonnancement, s'il existe, lors de l'étape de ''dispatch''. Cette séparation fait qu'il est possible de démarrer l'exécution de plusieurs µops simultanément : une µop par ''scheduler''. Le fait est que deux ''schedulers'' différents émettent leurs µops sans se synchroniser avec les autres. Deux ''schedulers'' peuvent donc émettre chacun une µops, ce qui fait deux µops émises lors du même cycle. Cela permet d'exécuter en même temps deux ou trois instructions 1-cycle, comme des additions, soustractions, décalages, etc. Il devient aussi possible d'émettre un µop entière en même temps qu'un µop flottante, si les µops entières ont un fenêtre séparée de celle des µops flottantes. Notons que cela permet d'émettre deux µops par cycle au niveau de l'étape de ''scheduling'', pas à l'étape de ''dispatch''. Aussi, nous parlerons de '''''multi-schedule'''''. Par contre, il faut faire une précision importante : le processeur ne peut toujours qu'émettre une ''instruction'' par cycle. Le processeur charge et décode une instruction par cycle, pas plus. Pour faire une comparaison, rappelez-vous l'exécution dans le désordre simple. Elle permet d'exécuter plusieurs instructions par cycle d'horloge, si on regarde ce qui se passe au niveau des unités de calcul. Mais si on fait la moyenne sur le temps long, on ne peut pas dépasser un IPC (''instruction per cycle'') de 1. Le ''multi-scheduling'' est similaire. Il permet de gagner en performance, mais ne permet pas de dépasser un IPC de 1. Il augmente l'IPC quand il est bas, mais il ne faut que le faire remonter vers le seuil de 1. ==La spécialisation des ''schedulers'' décentralisés== La scission doit se faire en tenant compte du reste du processeur. En effet, il faut relier les ''schedulers'' aux unités de calcul, ainsi qu'à l'unité mémoire, et cela ne peut pas se faire n'importe comment. Reste à voir comment faire. ===Les ''schedulers'' décentralisés avec exécution dans l'ordre des accès mémoire=== Prenons un processeur où les accès mémoire sont réalisés dans l'ordre. Le processeur a donc un simple ''scheduler'' pour les µops entières, les µops flottantes et les µops de branchements. La scission la plus basique sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes. L'avantage est que l'implémentation est très simple. Les flottants sont gérés à part des entiers. Ils ont leurs propres registres, des FPU séparées des ALU entières, bref : le séparation est complète. Utiliser un ''scheduler'' séparée va dans ce sens. Un avantage de cette scission se situe au niveau de la consommation d'électricité. Si le programme exécuté n'exécute aucune instruction flottante, le ''scheduler'' pour µops flottant peut être ''clock gate'', mis en veille, voire éteint. Le processeur consomme donc moins d'électricité, et chauffe moins. Remarque importante : les deux ''schedulers'' travaillent indépendamment les unes des autres. Ils décident d'émettre une µops à chaque cycle, dans leur coin, sans rendre de compte à l'autre. La conséquence est qu'il est possible d'émettre deux µops par cycle, si les circonstances l'autorisent. Le ''scheduler'' entier émet une µops entière en même temps que le ''scheduler'' flottant émet une µops flottante. Les deux µops démarrent au même cycle, on n'émet pas l'une après l'autre. Le résultat est un gain en performance, sur lequel on reviendra plus tard. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Il est aussi possible de séparer le ''scheduler'' pour les µops entières en deux : un pour les opérations de calcul et un autre pour les µops de branchements. La séparation est moins évidente, mais reste possible. De nombreux processeurs commerciaux le font. Cependant, cela demande d'utiliser une unité de calcul séparée pour les branchements. ===Les ''schedulers'' décentralisés avec exécution dans le désordre des accès mémoire=== Voyons maintenant le cas des processeurs où les accès mémoire sont exécutés dans le désordre. Il est possible d'utiliser un ''scheduler'' centralisé, ce qui était fait sur les anciens processeurs Intel pour donner un exemple. Mais voyons ce que cela peut donner avec un ''scheduler'' décentralisé. Une scission naturelle serait d'utiliser un ''scheduler'' pour les µops mémoire, et un ''scheduler'' pour le reste des µops. Les processeurs Intel de microarchitecture ''Skylake'' faisaient cela. Un avantage est que les deux fenêtres d'instructions sont plus spécialisées, ce qui entraine des économies de circuit. Les opérations entières/flottantes ont besoin de deux registres pour les opérandes et d'un autre résultat, alors que les µops mémoire n'ont besoin que de deux registres maximum. En utilisant un ''scheduler'' unique, chaque entrée doit mémoriser l'opcode et trois registres, dont un est inutilisé pour les µops mémoire et les branchements. En utilisant des fenêtres d’instructions séparées, celle pour les µops entières/flottantes a trois registres par entrée, contre seulement deux registres par entrée pour celle des µops mémoire. Un autre avantage est que cela permet d'émettre une µops mémoire et une autre µops lors du même cycle. Si les circonstances le permettent, le processeur peut émettre une µops entière dans une ALU entière, et une µops mémoire dans l'unité mémoire. Le gain en performance est substantiel. Précisons que les processeurs avec exécution dans le désordre peuvent exécuter une instruction arithmétique en parallèle d'un accès mémoire. Mais les deux ne démarrent pas au même cycle : on émet d'abord l'accès mémoire, puis les instructions de calcul suivent au cycle suivant. Là, les deux démarrent au même cycle. Une scission plus poussée sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes, un autre pour les µops mémoire. [[File:Processeur avec des fenêtres d'instruction décentralisées.png|centre|vignette|upright=2|Processeur avec des fenêtres d'instruction décentralisées]] ===Les stations de réservation=== Un cas extrême est celui où chaque ALU/FPU a sa propre ''scheduler''. Par exemple, il y a un ''scheduler'' pour l'ALU entière, un autre pour le multiplieur entier, un autre pour le ''barrel shifter'', un autre pour l'unité mémoire, un autre pour l'unité de branchements, un autre pour l'additionneur flottant, un autre pour le multiplier flottant, etc. Un exemple historique est celui de le FPU de l'IBM 360 modèle 90, qui avait un additionneur flottant, un multiplieur flottant, et une unité mémoire pour les lectures/écritures flottantes. Les trois unités avaient leur propre ''scheduler''. Un exemple aussi extrême n'est pas si rare. Les processeurs AMD utilisent beaucoup cette technique, pour les ALU entières, à quelques nuances près. A l'opposé, Intel préfère utiliser des ''schedulers'' centralisés sur les anciens processeurs, deux ou trois ''schedulers'' sur les processeurs récents (2020 et plus). Les processeurs AMD utilisaient précisément un ''scheduler'' par ALU entière, alors que les FPUs partagent un fenêtre d’instructions flottantes unique. Mais nous verrons cela en détail dans le chapitre sur les processeurs superscalaires x86. Toujours est-il qu'un cas aussi unique porte un nom. Les ''schedulers'' reliés à une seule ALU (entière ou flottante) sont appelés des '''stations de réservation'''. Le terme a été introduit dans l'article de Tomasulo, qui décrivait justement la FPU de l'IBM 360, mentionnée plus haut. Mais dans ce cours, le terme décrit des ''schedulers'' qui mémorisent les opérandes des instructions, pas seulement les noms de registres associés. [[File:Contournement avec des stations de réservation.png|centre|vignette|upright=2.5|Stations de réservation]] Toujours est-il que l'exécution dans le désordre avec des stations de réservations a un intérêt historique fort. Elle a été utilisée dans deux techniques d'exécution dans le désordre très ancienne : l'algorithme de Tomasulo et le ''Scoreboarding'' du processeur CDC 6600. Ces deux implémentations ont introduit la technique, qui a été raffinée par la suite. Leur défaut est qu'elles ne géraient pas les exceptions précises, ce qui fait qu'on verra ces deux techniques dans le chapitre suivant, qui leur est dédié. ===L'usage de plusieurs files d'instruction=== Utiliser plusieurs ''schedulers'' séparés est une bonne méthode pour économiser des circuits. Mais il est possible d'aller encore plus loin, en remplaçant les ''schedulers'' par des files de micro-opérations. L'idée est qu'un fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement un file de micro-opération pour les opérations entières, un autre pour les opérations flottantes, un autre pour les accès mémoire. D'autres processeurs utilisent un file pour les accès mémoire et un autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. le présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que le technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si un dépendance bloque un FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans un autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer le disponibilité des registres. Quand un registre est lu ou écrit par un instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. le logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : un pour les instructions d'accès mémoire et un autre pour les autres instructions. Si jamais un instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de le lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'un est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est le file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. Dans les grandes lignes, il existe 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! ''scheduler'' |- ! un seule | ''Scoreboard'' | ''scheduler'' centralisée |- ! Plusieurs | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | ''scheduler'' décentralisé |} <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Le scoreboarding et l'algorithme de Tomasulo | prevText=Le scoreboarding et l'algorithme de Tomasulo | next=Le scoreboarding et l'algorithme de Tomasulo | nextText=Le scoreboarding et l'algorithme de Tomasulo }} </noinclude> n2qosrx2xj10spmnwxnvslab66ve7is 773668 773667 2026-09-29T22:20:59Z Mewtow 31375 /* Les stations de réservation */ 773668 wikitext text/x-wiki Nous venons de parler de l'exécution dans le désordre pendant deux chapitres. Les chapitres précédents vous ont laissé penser qu'un processeur avec exécution dans le désordre était assez simple : on remplace le file de µops par un fenêtre d’instruction, on ajoute éventuellement un unité de renommage de registres, et voilà ! Et en effet, l'implémentation la plus simple de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Mais dans la réalité, les processeurs modernes n'utilisent pas un ''scheduler'' unique. Les processeurs modernes ont besoin de ''scheduler'' très grands, avec un grand nombre d'entrées. Or, nous avons vu qu'un ''scheduler'' est un sorte de mémoire associative très complexe, avec un grand nombre de comparateurs. Et cela pose problème quand le ''scheduler'' doit mémoriser un grand nombre de µops. Le cout en transistors d'un ''scheduler'' n'est pas proportionnel au nombre de µops qu'elle peut mémoriser. Par exemple, si je compare un ''scheduler'' de 32 entrées (32 µops max), elle n'utilise pas deux fois plus transistors qu'un fenêtre de 16 entrées. Le cout en circuit n'est pas deux fois plus élevé, mais est approximativement 4 fois plus élevé. Le cout est presque quadratique, à savoir qu'il est proportionnel au carré du nombre d'entrées. Et il en est de même avec le performance. Dès qu'on dépasse la centaine de µops, un ''scheduler'' centralisé n'est pas très pratique. Il consomme beaucoup de transistors, chauffe beaucoup, n'est pas très rapide. ==Les ''schedulers'' décentralisés versus centralisés== La solution est de scinder un gros ''scheduler'' en plusieurs ''schedulers'' plus petits. Pour faire la différence avec un ''scheduler'' unique, nous allons parler de ''scheduler'' centralisé s'il n'y en a qu'un, de '''''scheduler'' décentralisé''' s'il y en a plusieurs. Le choix entre un ''scheduler'' centralisés et plusieurs petits ''schedulers'' décentralisés est un compromis entre économie de circuits et flexibilité. Un gros ''scheduler'' unique est plus flexible, ce qui peut entrainer des gains de performance, mais coute beaucoup en circuits et peut réduire la fréquence du processeur. ===Un ''scheduler'' centralisé est plus flexible, mais plus couteux=== Pour expliquer en quoi un gros ''scheduler'' unique est plus flexible, nous allons prendre un exemple. Comparons un ''scheduler'' de 64 entrées, et deux ''schedulers'' de 32 entrées chacun. Les deux ''schedulers'' sont spécialisé :l'un est spécialisé dans les µops entières, l'autre dans les µops flottantes. En tout, les deux ''schedulers'' peuvent mémoriser au maximum 32 µops entières et 32 µops flottantes. A l'opposé, le gros ''scheduler'' unique peut mémoriser 64 µops, peu importe leur nature. Si le programme exécuté n'utilise pas de nombres flottants, le différence devient flagrante. La solution à deux ''schedulers'' est limitée à 32 µops, alors que le ''scheduler'' centralisé peut mémoriser le double. Les performances seront donc meilleures avec le ''scheduler'' centralisé. Et au-delà de ça, le ''scheduler'' décentralisé est utilisé de manière optimale si la moitié des µops sont des µops entières, et l'autre moitié des µops flottantes. Alors que le ''scheduler'' centralisé se moque de la répartition entre µops entières et flottantes. Pour le dire autrement, avec un ''scheduler'' décentralisé, il arrive qu'un ''scheduler'' soit remplis, alors que les autres sont sous-utilisés, voire vides. Ce qui n'arrive pas avec un ''scheduler'' centralisé. Par contre, les ''schedulers'' décentralisés utilisent plusieurs ''schedulers'' de "petite taille", plus rapides, plus économes en circuits et économes en énergie. Le compromis n'est donc pas entre un ''scheduler'' à 64 entrées versus deux ''schedulers'' de 32 entrées. Le compromis en pratique est entre un ''scheduler'' de 64 entrées versus 3 ''schedulers'' de 32 entrées. Un exemple pratique est celui de le microarchitecture ''Skyleke'' d'Intel. Intel est passé d'un ''scheduler'' centralisé pre-''Skyleke'' à deux ''schedulers'' sur ''Skyleke'', mais le nombre total d'entrées était globalement le même entre les deux, même si l'évolution de le finesse de gravure entre les deux biaise un peu les résultats. ===L'émission avec un ''scheduler'' décentralisé : ''dispatch'' et ''schedule''=== Un point important est qu'avec des ''schedulers'' décentralisés, l'émission est découpée en deux étages. Le premier étage envoie une µops vers le ''scheduler'' adéquat, le seconde émet la µops quand ses opérandes sont prêts. La première étape fait rentrer une µops dans le ''scheduler'', la seconde l'en fait sortir. Le premier étage est l'étage de '''''dispatch''''', le second est l'étage de '''''scheduling'''''. Le ''dispatch'' analyse la µops et décide où l'envoyer, selon que c'est une µops mémoire, flottante, entière. Le ''scheduling'' gère le disponibilité des opérandes et des unités de calcul. La µop émise est ajoutée au tampon de réordonnancement, s'il existe, lors de l'étape de ''dispatch''. Cette séparation fait qu'il est possible de démarrer l'exécution de plusieurs µops simultanément : une µop par ''scheduler''. Le fait est que deux ''schedulers'' différents émettent leurs µops sans se synchroniser avec les autres. Deux ''schedulers'' peuvent donc émettre chacun une µops, ce qui fait deux µops émises lors du même cycle. Cela permet d'exécuter en même temps deux ou trois instructions 1-cycle, comme des additions, soustractions, décalages, etc. Il devient aussi possible d'émettre un µop entière en même temps qu'un µop flottante, si les µops entières ont un fenêtre séparée de celle des µops flottantes. Notons que cela permet d'émettre deux µops par cycle au niveau de l'étape de ''scheduling'', pas à l'étape de ''dispatch''. Aussi, nous parlerons de '''''multi-schedule'''''. Par contre, il faut faire une précision importante : le processeur ne peut toujours qu'émettre une ''instruction'' par cycle. Le processeur charge et décode une instruction par cycle, pas plus. Pour faire une comparaison, rappelez-vous l'exécution dans le désordre simple. Elle permet d'exécuter plusieurs instructions par cycle d'horloge, si on regarde ce qui se passe au niveau des unités de calcul. Mais si on fait la moyenne sur le temps long, on ne peut pas dépasser un IPC (''instruction per cycle'') de 1. Le ''multi-scheduling'' est similaire. Il permet de gagner en performance, mais ne permet pas de dépasser un IPC de 1. Il augmente l'IPC quand il est bas, mais il ne faut que le faire remonter vers le seuil de 1. ==La spécialisation des ''schedulers'' décentralisés== La scission doit se faire en tenant compte du reste du processeur. En effet, il faut relier les ''schedulers'' aux unités de calcul, ainsi qu'à l'unité mémoire, et cela ne peut pas se faire n'importe comment. Reste à voir comment faire. ===Les ''schedulers'' décentralisés avec exécution dans l'ordre des accès mémoire=== Prenons un processeur où les accès mémoire sont réalisés dans l'ordre. Le processeur a donc un simple ''scheduler'' pour les µops entières, les µops flottantes et les µops de branchements. La scission la plus basique sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes. L'avantage est que l'implémentation est très simple. Les flottants sont gérés à part des entiers. Ils ont leurs propres registres, des FPU séparées des ALU entières, bref : le séparation est complète. Utiliser un ''scheduler'' séparée va dans ce sens. Un avantage de cette scission se situe au niveau de la consommation d'électricité. Si le programme exécuté n'exécute aucune instruction flottante, le ''scheduler'' pour µops flottant peut être ''clock gate'', mis en veille, voire éteint. Le processeur consomme donc moins d'électricité, et chauffe moins. Remarque importante : les deux ''schedulers'' travaillent indépendamment les unes des autres. Ils décident d'émettre une µops à chaque cycle, dans leur coin, sans rendre de compte à l'autre. La conséquence est qu'il est possible d'émettre deux µops par cycle, si les circonstances l'autorisent. Le ''scheduler'' entier émet une µops entière en même temps que le ''scheduler'' flottant émet une µops flottante. Les deux µops démarrent au même cycle, on n'émet pas l'une après l'autre. Le résultat est un gain en performance, sur lequel on reviendra plus tard. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Il est aussi possible de séparer le ''scheduler'' pour les µops entières en deux : un pour les opérations de calcul et un autre pour les µops de branchements. La séparation est moins évidente, mais reste possible. De nombreux processeurs commerciaux le font. Cependant, cela demande d'utiliser une unité de calcul séparée pour les branchements. ===Les ''schedulers'' décentralisés avec exécution dans le désordre des accès mémoire=== Voyons maintenant le cas des processeurs où les accès mémoire sont exécutés dans le désordre. Il est possible d'utiliser un ''scheduler'' centralisé, ce qui était fait sur les anciens processeurs Intel pour donner un exemple. Mais voyons ce que cela peut donner avec un ''scheduler'' décentralisé. Une scission naturelle serait d'utiliser un ''scheduler'' pour les µops mémoire, et un ''scheduler'' pour le reste des µops. Les processeurs Intel de microarchitecture ''Skylake'' faisaient cela. Un avantage est que les deux fenêtres d'instructions sont plus spécialisées, ce qui entraine des économies de circuit. Les opérations entières/flottantes ont besoin de deux registres pour les opérandes et d'un autre résultat, alors que les µops mémoire n'ont besoin que de deux registres maximum. En utilisant un ''scheduler'' unique, chaque entrée doit mémoriser l'opcode et trois registres, dont un est inutilisé pour les µops mémoire et les branchements. En utilisant des fenêtres d’instructions séparées, celle pour les µops entières/flottantes a trois registres par entrée, contre seulement deux registres par entrée pour celle des µops mémoire. Un autre avantage est que cela permet d'émettre une µops mémoire et une autre µops lors du même cycle. Si les circonstances le permettent, le processeur peut émettre une µops entière dans une ALU entière, et une µops mémoire dans l'unité mémoire. Le gain en performance est substantiel. Précisons que les processeurs avec exécution dans le désordre peuvent exécuter une instruction arithmétique en parallèle d'un accès mémoire. Mais les deux ne démarrent pas au même cycle : on émet d'abord l'accès mémoire, puis les instructions de calcul suivent au cycle suivant. Là, les deux démarrent au même cycle. Une scission plus poussée sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes, un autre pour les µops mémoire. [[File:Processeur avec des fenêtres d'instruction décentralisées.png|centre|vignette|upright=2|Processeur avec des fenêtres d'instruction décentralisées]] ===Les stations de réservation=== Un cas extrême est celui où chaque ALU/FPU a sa propre ''scheduler''. Par exemple, il y a un ''scheduler'' pour l'ALU entière, un autre pour le multiplieur entier, un autre pour le ''barrel shifter'', un autre pour l'unité mémoire, un autre pour l'unité de branchements, un autre pour l'additionneur flottant, un autre pour le multiplier flottant, etc. Un exemple historique est celui de le FPU de l'IBM 360 modèle 90, qui avait un additionneur flottant, un multiplieur flottant, et une unité mémoire pour les lectures/écritures flottantes. Les trois unités avaient leur propre ''scheduler''. Un exemple aussi extrême n'est pas si rare. Les processeurs AMD utilisent beaucoup cette technique, pour les ALU entières, à quelques nuances près. A l'opposé, Intel préfère utiliser des ''schedulers'' centralisés sur les anciens processeurs, deux ou trois ''schedulers'' sur les processeurs récents (2020 et plus). Les processeurs AMD utilisaient précisément un ''scheduler'' par ALU entière, alors que les FPUs partagent un fenêtre d’instructions flottantes unique. Mais nous verrons cela en détail dans le chapitre sur les processeurs superscalaires x86. Toujours est-il qu'un cas aussi unique porte un nom. Les ''schedulers'' reliés à une seule ALU (entière ou flottante) sont appelés des '''stations de réservation''', ''Reservation Stations'' en anglais. Le terme a été introduit dans l'article de Tomasulo, qui décrivait justement la FPU de l'IBM 360, mentionnée plus haut. Mais dans ce cours, le terme décrit des ''schedulers'' qui mémorisent les opérandes des instructions, pas seulement les noms de registres associés. [[File:Contournement avec des stations de réservation.png|centre|vignette|upright=2.5|Stations de réservation]] Toujours est-il que l'exécution dans le désordre avec des stations de réservations a un intérêt historique fort. Elle a été utilisée dans deux techniques d'exécution dans le désordre très ancienne : l'algorithme de Tomasulo et le ''Scoreboarding'' du processeur CDC 6600. Ces deux implémentations ont introduit la technique, qui a été raffinée par la suite. Leur défaut est qu'elles ne géraient pas les exceptions précises, ce qui fait qu'on verra ces deux techniques dans le chapitre suivant, qui leur est dédié. ===L'usage de plusieurs files d'instruction=== Utiliser plusieurs ''schedulers'' séparés est une bonne méthode pour économiser des circuits. Mais il est possible d'aller encore plus loin, en remplaçant les ''schedulers'' par des files de micro-opérations. L'idée est qu'un fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement un file de micro-opération pour les opérations entières, un autre pour les opérations flottantes, un autre pour les accès mémoire. D'autres processeurs utilisent un file pour les accès mémoire et un autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. le présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que le technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si un dépendance bloque un FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans un autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer le disponibilité des registres. Quand un registre est lu ou écrit par un instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. le logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : un pour les instructions d'accès mémoire et un autre pour les autres instructions. Si jamais un instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de le lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'un est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est le file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. Dans les grandes lignes, il existe 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! ''scheduler'' |- ! un seule | ''Scoreboard'' | ''scheduler'' centralisée |- ! Plusieurs | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | ''scheduler'' décentralisé |} <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Le scoreboarding et l'algorithme de Tomasulo | prevText=Le scoreboarding et l'algorithme de Tomasulo | next=Le scoreboarding et l'algorithme de Tomasulo | nextText=Le scoreboarding et l'algorithme de Tomasulo }} </noinclude> r0t30l1zrlotqme3pfzia8s5itr4pe0 773669 773668 2026-09-29T22:22:44Z Mewtow 31375 /* Les schedulers décentralisés avec exécution dans l'ordre des accès mémoire */ 773669 wikitext text/x-wiki Nous venons de parler de l'exécution dans le désordre pendant deux chapitres. Les chapitres précédents vous ont laissé penser qu'un processeur avec exécution dans le désordre était assez simple : on remplace le file de µops par un fenêtre d’instruction, on ajoute éventuellement un unité de renommage de registres, et voilà ! Et en effet, l'implémentation la plus simple de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Mais dans la réalité, les processeurs modernes n'utilisent pas un ''scheduler'' unique. Les processeurs modernes ont besoin de ''scheduler'' très grands, avec un grand nombre d'entrées. Or, nous avons vu qu'un ''scheduler'' est un sorte de mémoire associative très complexe, avec un grand nombre de comparateurs. Et cela pose problème quand le ''scheduler'' doit mémoriser un grand nombre de µops. Le cout en transistors d'un ''scheduler'' n'est pas proportionnel au nombre de µops qu'elle peut mémoriser. Par exemple, si je compare un ''scheduler'' de 32 entrées (32 µops max), elle n'utilise pas deux fois plus transistors qu'un fenêtre de 16 entrées. Le cout en circuit n'est pas deux fois plus élevé, mais est approximativement 4 fois plus élevé. Le cout est presque quadratique, à savoir qu'il est proportionnel au carré du nombre d'entrées. Et il en est de même avec le performance. Dès qu'on dépasse la centaine de µops, un ''scheduler'' centralisé n'est pas très pratique. Il consomme beaucoup de transistors, chauffe beaucoup, n'est pas très rapide. ==Les ''schedulers'' décentralisés versus centralisés== La solution est de scinder un gros ''scheduler'' en plusieurs ''schedulers'' plus petits. Pour faire la différence avec un ''scheduler'' unique, nous allons parler de ''scheduler'' centralisé s'il n'y en a qu'un, de '''''scheduler'' décentralisé''' s'il y en a plusieurs. Le choix entre un ''scheduler'' centralisés et plusieurs petits ''schedulers'' décentralisés est un compromis entre économie de circuits et flexibilité. Un gros ''scheduler'' unique est plus flexible, ce qui peut entrainer des gains de performance, mais coute beaucoup en circuits et peut réduire la fréquence du processeur. ===Un ''scheduler'' centralisé est plus flexible, mais plus couteux=== Pour expliquer en quoi un gros ''scheduler'' unique est plus flexible, nous allons prendre un exemple. Comparons un ''scheduler'' de 64 entrées, et deux ''schedulers'' de 32 entrées chacun. Les deux ''schedulers'' sont spécialisé :l'un est spécialisé dans les µops entières, l'autre dans les µops flottantes. En tout, les deux ''schedulers'' peuvent mémoriser au maximum 32 µops entières et 32 µops flottantes. A l'opposé, le gros ''scheduler'' unique peut mémoriser 64 µops, peu importe leur nature. Si le programme exécuté n'utilise pas de nombres flottants, le différence devient flagrante. La solution à deux ''schedulers'' est limitée à 32 µops, alors que le ''scheduler'' centralisé peut mémoriser le double. Les performances seront donc meilleures avec le ''scheduler'' centralisé. Et au-delà de ça, le ''scheduler'' décentralisé est utilisé de manière optimale si la moitié des µops sont des µops entières, et l'autre moitié des µops flottantes. Alors que le ''scheduler'' centralisé se moque de la répartition entre µops entières et flottantes. Pour le dire autrement, avec un ''scheduler'' décentralisé, il arrive qu'un ''scheduler'' soit remplis, alors que les autres sont sous-utilisés, voire vides. Ce qui n'arrive pas avec un ''scheduler'' centralisé. Par contre, les ''schedulers'' décentralisés utilisent plusieurs ''schedulers'' de "petite taille", plus rapides, plus économes en circuits et économes en énergie. Le compromis n'est donc pas entre un ''scheduler'' à 64 entrées versus deux ''schedulers'' de 32 entrées. Le compromis en pratique est entre un ''scheduler'' de 64 entrées versus 3 ''schedulers'' de 32 entrées. Un exemple pratique est celui de le microarchitecture ''Skyleke'' d'Intel. Intel est passé d'un ''scheduler'' centralisé pre-''Skyleke'' à deux ''schedulers'' sur ''Skyleke'', mais le nombre total d'entrées était globalement le même entre les deux, même si l'évolution de le finesse de gravure entre les deux biaise un peu les résultats. ===L'émission avec un ''scheduler'' décentralisé : ''dispatch'' et ''schedule''=== Un point important est qu'avec des ''schedulers'' décentralisés, l'émission est découpée en deux étages. Le premier étage envoie une µops vers le ''scheduler'' adéquat, le seconde émet la µops quand ses opérandes sont prêts. La première étape fait rentrer une µops dans le ''scheduler'', la seconde l'en fait sortir. Le premier étage est l'étage de '''''dispatch''''', le second est l'étage de '''''scheduling'''''. Le ''dispatch'' analyse la µops et décide où l'envoyer, selon que c'est une µops mémoire, flottante, entière. Le ''scheduling'' gère le disponibilité des opérandes et des unités de calcul. La µop émise est ajoutée au tampon de réordonnancement, s'il existe, lors de l'étape de ''dispatch''. Cette séparation fait qu'il est possible de démarrer l'exécution de plusieurs µops simultanément : une µop par ''scheduler''. Le fait est que deux ''schedulers'' différents émettent leurs µops sans se synchroniser avec les autres. Deux ''schedulers'' peuvent donc émettre chacun une µops, ce qui fait deux µops émises lors du même cycle. Cela permet d'exécuter en même temps deux ou trois instructions 1-cycle, comme des additions, soustractions, décalages, etc. Il devient aussi possible d'émettre un µop entière en même temps qu'un µop flottante, si les µops entières ont un fenêtre séparée de celle des µops flottantes. Notons que cela permet d'émettre deux µops par cycle au niveau de l'étape de ''scheduling'', pas à l'étape de ''dispatch''. Aussi, nous parlerons de '''''multi-schedule'''''. Par contre, il faut faire une précision importante : le processeur ne peut toujours qu'émettre une ''instruction'' par cycle. Le processeur charge et décode une instruction par cycle, pas plus. Pour faire une comparaison, rappelez-vous l'exécution dans le désordre simple. Elle permet d'exécuter plusieurs instructions par cycle d'horloge, si on regarde ce qui se passe au niveau des unités de calcul. Mais si on fait la moyenne sur le temps long, on ne peut pas dépasser un IPC (''instruction per cycle'') de 1. Le ''multi-scheduling'' est similaire. Il permet de gagner en performance, mais ne permet pas de dépasser un IPC de 1. Il augmente l'IPC quand il est bas, mais il ne faut que le faire remonter vers le seuil de 1. ==La spécialisation des ''schedulers'' décentralisés== La scission doit se faire en tenant compte du reste du processeur. En effet, il faut relier les ''schedulers'' aux unités de calcul, ainsi qu'à l'unité mémoire, et cela ne peut pas se faire n'importe comment. Reste à voir comment faire. ===Les ''schedulers'' décentralisés avec exécution dans l'ordre des accès mémoire=== Prenons un processeur où les accès mémoire sont réalisés dans l'ordre. Le processeur a donc un simple ''scheduler'' pour les µops entières, les µops flottantes et les µops de branchements. La scission la plus basique sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes. L'avantage est que l'implémentation est très simple. Les flottants sont gérés à part des entiers. Ils ont leurs propres registres, des FPU séparées des ALU entières, bref : le séparation est complète. Utiliser un ''scheduler'' séparée va dans ce sens. Un avantage de cette scission se situe au niveau de la consommation d'électricité. Si le programme exécuté n'exécute aucune instruction flottante, le ''scheduler'' pour µops flottant peut être ''clock gate'', mis en veille, voire éteint. Le processeur consomme donc moins d'électricité, et chauffe moins. Un autre avantage de cette séparation est qu'elle permet de renommer les registres flottants et entiers séparément. Non pas que ce soit impossible avec un ''scheduler'' unique, mais c'est beaucoup plus compliqué et rarement fait. En séparant ''scheduler'' entier et ''scheduler'' flottant, les deux peuvent être précédés de deux unités de renommage séparées. Remarque importante : les deux ''schedulers'' travaillent indépendamment les unes des autres. Ils décident d'émettre une µops à chaque cycle, dans leur coin, sans rendre de compte à l'autre. La conséquence est qu'il est possible d'émettre deux µops par cycle, si les circonstances l'autorisent. Le ''scheduler'' entier émet une µops entière en même temps que le ''scheduler'' flottant émet une µops flottante. Les deux µops démarrent au même cycle, on n'émet pas l'une après l'autre. Le résultat est un gain en performance, sur lequel on reviendra plus tard. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Il est aussi possible de séparer le ''scheduler'' pour les µops entières en deux : un pour les opérations de calcul et un autre pour les µops de branchements. La séparation est moins évidente, mais reste possible. De nombreux processeurs commerciaux le font. Cependant, cela demande d'utiliser une unité de calcul séparée pour les branchements. ===Les ''schedulers'' décentralisés avec exécution dans le désordre des accès mémoire=== Voyons maintenant le cas des processeurs où les accès mémoire sont exécutés dans le désordre. Il est possible d'utiliser un ''scheduler'' centralisé, ce qui était fait sur les anciens processeurs Intel pour donner un exemple. Mais voyons ce que cela peut donner avec un ''scheduler'' décentralisé. Une scission naturelle serait d'utiliser un ''scheduler'' pour les µops mémoire, et un ''scheduler'' pour le reste des µops. Les processeurs Intel de microarchitecture ''Skylake'' faisaient cela. Un avantage est que les deux fenêtres d'instructions sont plus spécialisées, ce qui entraine des économies de circuit. Les opérations entières/flottantes ont besoin de deux registres pour les opérandes et d'un autre résultat, alors que les µops mémoire n'ont besoin que de deux registres maximum. En utilisant un ''scheduler'' unique, chaque entrée doit mémoriser l'opcode et trois registres, dont un est inutilisé pour les µops mémoire et les branchements. En utilisant des fenêtres d’instructions séparées, celle pour les µops entières/flottantes a trois registres par entrée, contre seulement deux registres par entrée pour celle des µops mémoire. Un autre avantage est que cela permet d'émettre une µops mémoire et une autre µops lors du même cycle. Si les circonstances le permettent, le processeur peut émettre une µops entière dans une ALU entière, et une µops mémoire dans l'unité mémoire. Le gain en performance est substantiel. Précisons que les processeurs avec exécution dans le désordre peuvent exécuter une instruction arithmétique en parallèle d'un accès mémoire. Mais les deux ne démarrent pas au même cycle : on émet d'abord l'accès mémoire, puis les instructions de calcul suivent au cycle suivant. Là, les deux démarrent au même cycle. Une scission plus poussée sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes, un autre pour les µops mémoire. [[File:Processeur avec des fenêtres d'instruction décentralisées.png|centre|vignette|upright=2|Processeur avec des fenêtres d'instruction décentralisées]] ===Les stations de réservation=== Un cas extrême est celui où chaque ALU/FPU a sa propre ''scheduler''. Par exemple, il y a un ''scheduler'' pour l'ALU entière, un autre pour le multiplieur entier, un autre pour le ''barrel shifter'', un autre pour l'unité mémoire, un autre pour l'unité de branchements, un autre pour l'additionneur flottant, un autre pour le multiplier flottant, etc. Un exemple historique est celui de le FPU de l'IBM 360 modèle 90, qui avait un additionneur flottant, un multiplieur flottant, et une unité mémoire pour les lectures/écritures flottantes. Les trois unités avaient leur propre ''scheduler''. Un exemple aussi extrême n'est pas si rare. Les processeurs AMD utilisent beaucoup cette technique, pour les ALU entières, à quelques nuances près. A l'opposé, Intel préfère utiliser des ''schedulers'' centralisés sur les anciens processeurs, deux ou trois ''schedulers'' sur les processeurs récents (2020 et plus). Les processeurs AMD utilisaient précisément un ''scheduler'' par ALU entière, alors que les FPUs partagent un fenêtre d’instructions flottantes unique. Mais nous verrons cela en détail dans le chapitre sur les processeurs superscalaires x86. Toujours est-il qu'un cas aussi unique porte un nom. Les ''schedulers'' reliés à une seule ALU (entière ou flottante) sont appelés des '''stations de réservation''', ''Reservation Stations'' en anglais. Le terme a été introduit dans l'article de Tomasulo, qui décrivait justement la FPU de l'IBM 360, mentionnée plus haut. Mais dans ce cours, le terme décrit des ''schedulers'' qui mémorisent les opérandes des instructions, pas seulement les noms de registres associés. [[File:Contournement avec des stations de réservation.png|centre|vignette|upright=2.5|Stations de réservation]] Toujours est-il que l'exécution dans le désordre avec des stations de réservations a un intérêt historique fort. Elle a été utilisée dans deux techniques d'exécution dans le désordre très ancienne : l'algorithme de Tomasulo et le ''Scoreboarding'' du processeur CDC 6600. Ces deux implémentations ont introduit la technique, qui a été raffinée par la suite. Leur défaut est qu'elles ne géraient pas les exceptions précises, ce qui fait qu'on verra ces deux techniques dans le chapitre suivant, qui leur est dédié. ===L'usage de plusieurs files d'instruction=== Utiliser plusieurs ''schedulers'' séparés est une bonne méthode pour économiser des circuits. Mais il est possible d'aller encore plus loin, en remplaçant les ''schedulers'' par des files de micro-opérations. L'idée est qu'un fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement un file de micro-opération pour les opérations entières, un autre pour les opérations flottantes, un autre pour les accès mémoire. D'autres processeurs utilisent un file pour les accès mémoire et un autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. le présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que le technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si un dépendance bloque un FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans un autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer le disponibilité des registres. Quand un registre est lu ou écrit par un instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. le logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : un pour les instructions d'accès mémoire et un autre pour les autres instructions. Si jamais un instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de le lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'un est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est le file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. Dans les grandes lignes, il existe 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! ''scheduler'' |- ! un seule | ''Scoreboard'' | ''scheduler'' centralisée |- ! Plusieurs | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | ''scheduler'' décentralisé |} <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Le scoreboarding et l'algorithme de Tomasulo | prevText=Le scoreboarding et l'algorithme de Tomasulo | next=Le scoreboarding et l'algorithme de Tomasulo | nextText=Le scoreboarding et l'algorithme de Tomasulo }} </noinclude> ohgvg9fj34cxvzf0tnkexaf6ofsbd3k 773672 773669 2026-09-29T22:34:30Z Mewtow 31375 /* Les schedulers décentralisés avec exécution dans le désordre des accès mémoire */ 773672 wikitext text/x-wiki Nous venons de parler de l'exécution dans le désordre pendant deux chapitres. Les chapitres précédents vous ont laissé penser qu'un processeur avec exécution dans le désordre était assez simple : on remplace le file de µops par un fenêtre d’instruction, on ajoute éventuellement un unité de renommage de registres, et voilà ! Et en effet, l'implémentation la plus simple de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Mais dans la réalité, les processeurs modernes n'utilisent pas un ''scheduler'' unique. Les processeurs modernes ont besoin de ''scheduler'' très grands, avec un grand nombre d'entrées. Or, nous avons vu qu'un ''scheduler'' est un sorte de mémoire associative très complexe, avec un grand nombre de comparateurs. Et cela pose problème quand le ''scheduler'' doit mémoriser un grand nombre de µops. Le cout en transistors d'un ''scheduler'' n'est pas proportionnel au nombre de µops qu'elle peut mémoriser. Par exemple, si je compare un ''scheduler'' de 32 entrées (32 µops max), elle n'utilise pas deux fois plus transistors qu'un fenêtre de 16 entrées. Le cout en circuit n'est pas deux fois plus élevé, mais est approximativement 4 fois plus élevé. Le cout est presque quadratique, à savoir qu'il est proportionnel au carré du nombre d'entrées. Et il en est de même avec le performance. Dès qu'on dépasse la centaine de µops, un ''scheduler'' centralisé n'est pas très pratique. Il consomme beaucoup de transistors, chauffe beaucoup, n'est pas très rapide. ==Les ''schedulers'' décentralisés versus centralisés== La solution est de scinder un gros ''scheduler'' en plusieurs ''schedulers'' plus petits. Pour faire la différence avec un ''scheduler'' unique, nous allons parler de ''scheduler'' centralisé s'il n'y en a qu'un, de '''''scheduler'' décentralisé''' s'il y en a plusieurs. Le choix entre un ''scheduler'' centralisés et plusieurs petits ''schedulers'' décentralisés est un compromis entre économie de circuits et flexibilité. Un gros ''scheduler'' unique est plus flexible, ce qui peut entrainer des gains de performance, mais coute beaucoup en circuits et peut réduire la fréquence du processeur. ===Un ''scheduler'' centralisé est plus flexible, mais plus couteux=== Pour expliquer en quoi un gros ''scheduler'' unique est plus flexible, nous allons prendre un exemple. Comparons un ''scheduler'' de 64 entrées, et deux ''schedulers'' de 32 entrées chacun. Les deux ''schedulers'' sont spécialisé :l'un est spécialisé dans les µops entières, l'autre dans les µops flottantes. En tout, les deux ''schedulers'' peuvent mémoriser au maximum 32 µops entières et 32 µops flottantes. A l'opposé, le gros ''scheduler'' unique peut mémoriser 64 µops, peu importe leur nature. Si le programme exécuté n'utilise pas de nombres flottants, le différence devient flagrante. La solution à deux ''schedulers'' est limitée à 32 µops, alors que le ''scheduler'' centralisé peut mémoriser le double. Les performances seront donc meilleures avec le ''scheduler'' centralisé. Et au-delà de ça, le ''scheduler'' décentralisé est utilisé de manière optimale si la moitié des µops sont des µops entières, et l'autre moitié des µops flottantes. Alors que le ''scheduler'' centralisé se moque de la répartition entre µops entières et flottantes. Pour le dire autrement, avec un ''scheduler'' décentralisé, il arrive qu'un ''scheduler'' soit remplis, alors que les autres sont sous-utilisés, voire vides. Ce qui n'arrive pas avec un ''scheduler'' centralisé. Par contre, les ''schedulers'' décentralisés utilisent plusieurs ''schedulers'' de "petite taille", plus rapides, plus économes en circuits et économes en énergie. Le compromis n'est donc pas entre un ''scheduler'' à 64 entrées versus deux ''schedulers'' de 32 entrées. Le compromis en pratique est entre un ''scheduler'' de 64 entrées versus 3 ''schedulers'' de 32 entrées. Un exemple pratique est celui de le microarchitecture ''Skyleke'' d'Intel. Intel est passé d'un ''scheduler'' centralisé pre-''Skyleke'' à deux ''schedulers'' sur ''Skyleke'', mais le nombre total d'entrées était globalement le même entre les deux, même si l'évolution de le finesse de gravure entre les deux biaise un peu les résultats. ===L'émission avec un ''scheduler'' décentralisé : ''dispatch'' et ''schedule''=== Un point important est qu'avec des ''schedulers'' décentralisés, l'émission est découpée en deux étages. Le premier étage envoie une µops vers le ''scheduler'' adéquat, le seconde émet la µops quand ses opérandes sont prêts. La première étape fait rentrer une µops dans le ''scheduler'', la seconde l'en fait sortir. Le premier étage est l'étage de '''''dispatch''''', le second est l'étage de '''''scheduling'''''. Le ''dispatch'' analyse la µops et décide où l'envoyer, selon que c'est une µops mémoire, flottante, entière. Le ''scheduling'' gère le disponibilité des opérandes et des unités de calcul. La µop émise est ajoutée au tampon de réordonnancement, s'il existe, lors de l'étape de ''dispatch''. Cette séparation fait qu'il est possible de démarrer l'exécution de plusieurs µops simultanément : une µop par ''scheduler''. Le fait est que deux ''schedulers'' différents émettent leurs µops sans se synchroniser avec les autres. Deux ''schedulers'' peuvent donc émettre chacun une µops, ce qui fait deux µops émises lors du même cycle. Cela permet d'exécuter en même temps deux ou trois instructions 1-cycle, comme des additions, soustractions, décalages, etc. Il devient aussi possible d'émettre un µop entière en même temps qu'un µop flottante, si les µops entières ont un fenêtre séparée de celle des µops flottantes. Notons que cela permet d'émettre deux µops par cycle au niveau de l'étape de ''scheduling'', pas à l'étape de ''dispatch''. Aussi, nous parlerons de '''''multi-schedule'''''. Par contre, il faut faire une précision importante : le processeur ne peut toujours qu'émettre une ''instruction'' par cycle. Le processeur charge et décode une instruction par cycle, pas plus. Pour faire une comparaison, rappelez-vous l'exécution dans le désordre simple. Elle permet d'exécuter plusieurs instructions par cycle d'horloge, si on regarde ce qui se passe au niveau des unités de calcul. Mais si on fait la moyenne sur le temps long, on ne peut pas dépasser un IPC (''instruction per cycle'') de 1. Le ''multi-scheduling'' est similaire. Il permet de gagner en performance, mais ne permet pas de dépasser un IPC de 1. Il augmente l'IPC quand il est bas, mais il ne faut que le faire remonter vers le seuil de 1. ==La spécialisation des ''schedulers'' décentralisés== La scission doit se faire en tenant compte du reste du processeur. En effet, il faut relier les ''schedulers'' aux unités de calcul, ainsi qu'à l'unité mémoire, et cela ne peut pas se faire n'importe comment. Reste à voir comment faire. ===Les ''schedulers'' décentralisés avec exécution dans l'ordre des accès mémoire=== Prenons un processeur où les accès mémoire sont réalisés dans l'ordre. Le processeur a donc un simple ''scheduler'' pour les µops entières, les µops flottantes et les µops de branchements. La scission la plus basique sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes. L'avantage est que l'implémentation est très simple. Les flottants sont gérés à part des entiers. Ils ont leurs propres registres, des FPU séparées des ALU entières, bref : le séparation est complète. Utiliser un ''scheduler'' séparée va dans ce sens. Un avantage de cette scission se situe au niveau de la consommation d'électricité. Si le programme exécuté n'exécute aucune instruction flottante, le ''scheduler'' pour µops flottant peut être ''clock gate'', mis en veille, voire éteint. Le processeur consomme donc moins d'électricité, et chauffe moins. Un autre avantage de cette séparation est qu'elle permet de renommer les registres flottants et entiers séparément. Non pas que ce soit impossible avec un ''scheduler'' unique, mais c'est beaucoup plus compliqué et rarement fait. En séparant ''scheduler'' entier et ''scheduler'' flottant, les deux peuvent être précédés de deux unités de renommage séparées. Remarque importante : les deux ''schedulers'' travaillent indépendamment les unes des autres. Ils décident d'émettre une µops à chaque cycle, dans leur coin, sans rendre de compte à l'autre. La conséquence est qu'il est possible d'émettre deux µops par cycle, si les circonstances l'autorisent. Le ''scheduler'' entier émet une µops entière en même temps que le ''scheduler'' flottant émet une µops flottante. Les deux µops démarrent au même cycle, on n'émet pas l'une après l'autre. Le résultat est un gain en performance, sur lequel on reviendra plus tard. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Il est aussi possible de séparer le ''scheduler'' pour les µops entières en deux : un pour les opérations de calcul et un autre pour les µops de branchements. La séparation est moins évidente, mais reste possible. De nombreux processeurs commerciaux le font. Cependant, cela demande d'utiliser une unité de calcul séparée pour les branchements. ===Les ''schedulers'' spécialisés pour les µops mémoire=== Voyons maintenant le cas des processeurs où les accès mémoire sont exécutés dans le désordre. Il est possible d'utiliser un ''scheduler'' centralisé, ce qui était fait sur les anciens processeurs Intel pour donner un exemple. Mais voyons ce que cela peut donner avec un ''scheduler'' décentralisé. Une scission naturelle serait d'utiliser un ''scheduler'' pour les µops mémoire, et un ''scheduler'' pour le reste des µops. Les processeurs Intel de microarchitecture ''Skylake'' faisaient cela. Un avantage est que les deux fenêtres d'instructions sont plus spécialisées, ce qui entraine des économies de circuit. Les opérations entières/flottantes ont besoin de deux registres pour les opérandes et d'un autre résultat, alors que les µops mémoire n'ont besoin que de deux registres maximum. En utilisant un ''scheduler'' unique, chaque entrée doit mémoriser l'opcode et trois registres, dont un est inutilisé pour les µops mémoire et les branchements. En utilisant des fenêtres d’instructions séparées, celle pour les µops entières/flottantes a trois registres par entrée, contre seulement deux registres par entrée pour celle des µops mémoire. Un autre avantage est que cela permet d'émettre une µops mémoire et une autre µops lors du même cycle. Si les circonstances le permettent, le processeur peut émettre une µops entière dans une ALU entière, et une µops mémoire dans l'unité mémoire. Le gain en performance est substantiel. Précisons que les processeurs avec exécution dans le désordre peuvent exécuter une instruction arithmétique en parallèle d'un accès mémoire. Mais les deux ne démarrent pas au même cycle : on émet d'abord l'accès mémoire, puis les instructions de calcul suivent au cycle suivant. Là, les deux démarrent au même cycle. Une scission plus poussée sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes, un autre pour les µops mémoire. [[File:Processeur avec des fenêtres d'instruction décentralisées.png|centre|vignette|upright=2|Processeur avec des fenêtres d'instruction décentralisées]] ===Les stations de réservation=== Un cas extrême est celui où chaque ALU/FPU a sa propre ''scheduler''. Par exemple, il y a un ''scheduler'' pour l'ALU entière, un autre pour le multiplieur entier, un autre pour le ''barrel shifter'', un autre pour l'unité mémoire, un autre pour l'unité de branchements, un autre pour l'additionneur flottant, un autre pour le multiplier flottant, etc. Un exemple historique est celui de le FPU de l'IBM 360 modèle 90, qui avait un additionneur flottant, un multiplieur flottant, et une unité mémoire pour les lectures/écritures flottantes. Les trois unités avaient leur propre ''scheduler''. Un exemple aussi extrême n'est pas si rare. Les processeurs AMD utilisent beaucoup cette technique, pour les ALU entières, à quelques nuances près. A l'opposé, Intel préfère utiliser des ''schedulers'' centralisés sur les anciens processeurs, deux ou trois ''schedulers'' sur les processeurs récents (2020 et plus). Les processeurs AMD utilisaient précisément un ''scheduler'' par ALU entière, alors que les FPUs partagent un fenêtre d’instructions flottantes unique. Mais nous verrons cela en détail dans le chapitre sur les processeurs superscalaires x86. Toujours est-il qu'un cas aussi unique porte un nom. Les ''schedulers'' reliés à une seule ALU (entière ou flottante) sont appelés des '''stations de réservation''', ''Reservation Stations'' en anglais. Le terme a été introduit dans l'article de Tomasulo, qui décrivait justement la FPU de l'IBM 360, mentionnée plus haut. Mais dans ce cours, le terme décrit des ''schedulers'' qui mémorisent les opérandes des instructions, pas seulement les noms de registres associés. [[File:Contournement avec des stations de réservation.png|centre|vignette|upright=2.5|Stations de réservation]] Toujours est-il que l'exécution dans le désordre avec des stations de réservations a un intérêt historique fort. Elle a été utilisée dans deux techniques d'exécution dans le désordre très ancienne : l'algorithme de Tomasulo et le ''Scoreboarding'' du processeur CDC 6600. Ces deux implémentations ont introduit la technique, qui a été raffinée par la suite. Leur défaut est qu'elles ne géraient pas les exceptions précises, ce qui fait qu'on verra ces deux techniques dans le chapitre suivant, qui leur est dédié. ===L'usage de plusieurs files d'instruction=== Utiliser plusieurs ''schedulers'' séparés est une bonne méthode pour économiser des circuits. Mais il est possible d'aller encore plus loin, en remplaçant les ''schedulers'' par des files de micro-opérations. L'idée est qu'un fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement un file de micro-opération pour les opérations entières, un autre pour les opérations flottantes, un autre pour les accès mémoire. D'autres processeurs utilisent un file pour les accès mémoire et un autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. le présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que le technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si un dépendance bloque un FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans un autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer le disponibilité des registres. Quand un registre est lu ou écrit par un instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. le logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : un pour les instructions d'accès mémoire et un autre pour les autres instructions. Si jamais un instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de le lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'un est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est le file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. Dans les grandes lignes, il existe 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! ''scheduler'' |- ! un seule | ''Scoreboard'' | ''scheduler'' centralisée |- ! Plusieurs | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | ''scheduler'' décentralisé |} <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Le scoreboarding et l'algorithme de Tomasulo | prevText=Le scoreboarding et l'algorithme de Tomasulo | next=Le scoreboarding et l'algorithme de Tomasulo | nextText=Le scoreboarding et l'algorithme de Tomasulo }} </noinclude> 1704uro0080qdd8gw2jrsrg8hhbefcy 773673 773672 2026-09-29T22:37:48Z Mewtow 31375 /* Les schedulers décentralisés avec exécution dans l'ordre des accès mémoire */ 773673 wikitext text/x-wiki Nous venons de parler de l'exécution dans le désordre pendant deux chapitres. Les chapitres précédents vous ont laissé penser qu'un processeur avec exécution dans le désordre était assez simple : on remplace le file de µops par un fenêtre d’instruction, on ajoute éventuellement un unité de renommage de registres, et voilà ! Et en effet, l'implémentation la plus simple de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Mais dans la réalité, les processeurs modernes n'utilisent pas un ''scheduler'' unique. Les processeurs modernes ont besoin de ''scheduler'' très grands, avec un grand nombre d'entrées. Or, nous avons vu qu'un ''scheduler'' est un sorte de mémoire associative très complexe, avec un grand nombre de comparateurs. Et cela pose problème quand le ''scheduler'' doit mémoriser un grand nombre de µops. Le cout en transistors d'un ''scheduler'' n'est pas proportionnel au nombre de µops qu'elle peut mémoriser. Par exemple, si je compare un ''scheduler'' de 32 entrées (32 µops max), elle n'utilise pas deux fois plus transistors qu'un fenêtre de 16 entrées. Le cout en circuit n'est pas deux fois plus élevé, mais est approximativement 4 fois plus élevé. Le cout est presque quadratique, à savoir qu'il est proportionnel au carré du nombre d'entrées. Et il en est de même avec le performance. Dès qu'on dépasse la centaine de µops, un ''scheduler'' centralisé n'est pas très pratique. Il consomme beaucoup de transistors, chauffe beaucoup, n'est pas très rapide. ==Les ''schedulers'' décentralisés versus centralisés== La solution est de scinder un gros ''scheduler'' en plusieurs ''schedulers'' plus petits. Pour faire la différence avec un ''scheduler'' unique, nous allons parler de ''scheduler'' centralisé s'il n'y en a qu'un, de '''''scheduler'' décentralisé''' s'il y en a plusieurs. Le choix entre un ''scheduler'' centralisés et plusieurs petits ''schedulers'' décentralisés est un compromis entre économie de circuits et flexibilité. Un gros ''scheduler'' unique est plus flexible, ce qui peut entrainer des gains de performance, mais coute beaucoup en circuits et peut réduire la fréquence du processeur. ===Un ''scheduler'' centralisé est plus flexible, mais plus couteux=== Pour expliquer en quoi un gros ''scheduler'' unique est plus flexible, nous allons prendre un exemple. Comparons un ''scheduler'' de 64 entrées, et deux ''schedulers'' de 32 entrées chacun. Les deux ''schedulers'' sont spécialisé :l'un est spécialisé dans les µops entières, l'autre dans les µops flottantes. En tout, les deux ''schedulers'' peuvent mémoriser au maximum 32 µops entières et 32 µops flottantes. A l'opposé, le gros ''scheduler'' unique peut mémoriser 64 µops, peu importe leur nature. Si le programme exécuté n'utilise pas de nombres flottants, le différence devient flagrante. La solution à deux ''schedulers'' est limitée à 32 µops, alors que le ''scheduler'' centralisé peut mémoriser le double. Les performances seront donc meilleures avec le ''scheduler'' centralisé. Et au-delà de ça, le ''scheduler'' décentralisé est utilisé de manière optimale si la moitié des µops sont des µops entières, et l'autre moitié des µops flottantes. Alors que le ''scheduler'' centralisé se moque de la répartition entre µops entières et flottantes. Pour le dire autrement, avec un ''scheduler'' décentralisé, il arrive qu'un ''scheduler'' soit remplis, alors que les autres sont sous-utilisés, voire vides. Ce qui n'arrive pas avec un ''scheduler'' centralisé. Par contre, les ''schedulers'' décentralisés utilisent plusieurs ''schedulers'' de "petite taille", plus rapides, plus économes en circuits et économes en énergie. Le compromis n'est donc pas entre un ''scheduler'' à 64 entrées versus deux ''schedulers'' de 32 entrées. Le compromis en pratique est entre un ''scheduler'' de 64 entrées versus 3 ''schedulers'' de 32 entrées. Un exemple pratique est celui de le microarchitecture ''Skyleke'' d'Intel. Intel est passé d'un ''scheduler'' centralisé pre-''Skyleke'' à deux ''schedulers'' sur ''Skyleke'', mais le nombre total d'entrées était globalement le même entre les deux, même si l'évolution de le finesse de gravure entre les deux biaise un peu les résultats. ===L'émission avec un ''scheduler'' décentralisé : ''dispatch'' et ''schedule''=== Un point important est qu'avec des ''schedulers'' décentralisés, l'émission est découpée en deux étages. Le premier étage envoie une µops vers le ''scheduler'' adéquat, le seconde émet la µops quand ses opérandes sont prêts. La première étape fait rentrer une µops dans le ''scheduler'', la seconde l'en fait sortir. Le premier étage est l'étage de '''''dispatch''''', le second est l'étage de '''''scheduling'''''. Le ''dispatch'' analyse la µops et décide où l'envoyer, selon que c'est une µops mémoire, flottante, entière. Le ''scheduling'' gère le disponibilité des opérandes et des unités de calcul. La µop émise est ajoutée au tampon de réordonnancement, s'il existe, lors de l'étape de ''dispatch''. Cette séparation fait qu'il est possible de démarrer l'exécution de plusieurs µops simultanément : une µop par ''scheduler''. Le fait est que deux ''schedulers'' différents émettent leurs µops sans se synchroniser avec les autres. Deux ''schedulers'' peuvent donc émettre chacun une µops, ce qui fait deux µops émises lors du même cycle. Cela permet d'exécuter en même temps deux ou trois instructions 1-cycle, comme des additions, soustractions, décalages, etc. Il devient aussi possible d'émettre un µop entière en même temps qu'un µop flottante, si les µops entières ont un fenêtre séparée de celle des µops flottantes. Notons que cela permet d'émettre deux µops par cycle au niveau de l'étape de ''scheduling'', pas à l'étape de ''dispatch''. Aussi, nous parlerons de '''''multi-schedule'''''. Par contre, il faut faire une précision importante : le processeur ne peut toujours qu'émettre une ''instruction'' par cycle. Le processeur charge et décode une instruction par cycle, pas plus. Pour faire une comparaison, rappelez-vous l'exécution dans le désordre simple. Elle permet d'exécuter plusieurs instructions par cycle d'horloge, si on regarde ce qui se passe au niveau des unités de calcul. Mais si on fait la moyenne sur le temps long, on ne peut pas dépasser un IPC (''instruction per cycle'') de 1. Le ''multi-scheduling'' est similaire. Il permet de gagner en performance, mais ne permet pas de dépasser un IPC de 1. Il augmente l'IPC quand il est bas, mais il ne faut que le faire remonter vers le seuil de 1. ==La spécialisation des ''schedulers'' décentralisés== La scission doit se faire en tenant compte du reste du processeur. En effet, il faut relier les ''schedulers'' aux unités de calcul, ainsi qu'à l'unité mémoire, et cela ne peut pas se faire n'importe comment. Reste à voir comment faire. ===Les ''schedulers'' spécialisés pour les µops flottantes=== Prenons un processeur où les accès mémoire sont réalisés dans l'ordre. Le processeur a donc un simple ''scheduler'' pour les µops entières, les µops flottantes et les µops de branchements. La scission la plus basique sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes. Il est aussi possible de séparer le ''scheduler'' pour les µops entières en deux : un pour les opérations de calcul et un autre pour les µops de branchements. La séparation est moins évidente, mais reste possible. Pour le moment, concentrons-nous sur la séparation du ''scheduler'' flottant et du ''scheduler entier''. L'avantage est que l'implémentation est très simple. Les flottants sont gérés à part des entiers. Ils ont leurs propres registres, des FPU séparées des ALU entières, bref : le séparation est complète. Utiliser un ''scheduler'' séparée va dans ce sens. Un avantage de cette scission se situe au niveau de la consommation d'électricité. Si le programme exécuté n'exécute aucune instruction flottante, le ''scheduler'' pour µops flottant peut être ''clock gate'', mis en veille, voire éteint. Le processeur consomme donc moins d'électricité, et chauffe moins. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Remarque importante : les deux ''schedulers'' travaillent indépendamment les unes des autres. Ils décident d'émettre une µops à chaque cycle, dans leur coin, sans rendre de compte à l'autre. La conséquence est qu'il est possible d'émettre deux µops par cycle, si les circonstances l'autorisent. Le ''scheduler'' entier émet une µops entière en même temps que le ''scheduler'' flottant émet une µops flottante. Les deux µops démarrent au même cycle, on n'émet pas l'une après l'autre. Le résultat est un gain en performance, sur lequel on reviendra plus tard. Un avantage de cette séparation est qu'elle permet de renommer les registres flottants et entiers séparément. Non pas que ce soit impossible avec un ''scheduler'' unique, mais c'est beaucoup plus compliqué et rarement fait. En séparant ''scheduler'' entier et ''scheduler'' flottant, les deux peuvent être précédés de deux unités de renommage séparées. Et à vrai dire, on peut même aller plus loin, en n'autorisant l'exécution dans le désordre que pour les opérations flottantes, ou au contraire que pour les opérations entières. La toute première implémentation de l'exécution dans le désordre, sur l'IBM 360, en est un bon exemple. La FPU de ce processeur était précédée par un ''scheduler'', mais les ALu entières n'étaient précédés que par une file de µops basique, sans exécution dans le désordre. ===Les ''schedulers'' spécialisés pour les µops mémoire=== Voyons maintenant le cas des processeurs où les accès mémoire sont exécutés dans le désordre. Il est possible d'utiliser un ''scheduler'' centralisé, ce qui était fait sur les anciens processeurs Intel pour donner un exemple. Mais voyons ce que cela peut donner avec un ''scheduler'' décentralisé. Une scission naturelle serait d'utiliser un ''scheduler'' pour les µops mémoire, et un ''scheduler'' pour le reste des µops. Les processeurs Intel de microarchitecture ''Skylake'' faisaient cela. Un avantage est que les deux fenêtres d'instructions sont plus spécialisées, ce qui entraine des économies de circuit. Les opérations entières/flottantes ont besoin de deux registres pour les opérandes et d'un autre résultat, alors que les µops mémoire n'ont besoin que de deux registres maximum. En utilisant un ''scheduler'' unique, chaque entrée doit mémoriser l'opcode et trois registres, dont un est inutilisé pour les µops mémoire et les branchements. En utilisant des fenêtres d’instructions séparées, celle pour les µops entières/flottantes a trois registres par entrée, contre seulement deux registres par entrée pour celle des µops mémoire. Un autre avantage est que cela permet d'émettre une µops mémoire et une autre µops lors du même cycle. Si les circonstances le permettent, le processeur peut émettre une µops entière dans une ALU entière, et une µops mémoire dans l'unité mémoire. Le gain en performance est substantiel. Précisons que les processeurs avec exécution dans le désordre peuvent exécuter une instruction arithmétique en parallèle d'un accès mémoire. Mais les deux ne démarrent pas au même cycle : on émet d'abord l'accès mémoire, puis les instructions de calcul suivent au cycle suivant. Là, les deux démarrent au même cycle. Une scission plus poussée sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes, un autre pour les µops mémoire. [[File:Processeur avec des fenêtres d'instruction décentralisées.png|centre|vignette|upright=2|Processeur avec des fenêtres d'instruction décentralisées]] ===Les stations de réservation=== Un cas extrême est celui où chaque ALU/FPU a sa propre ''scheduler''. Par exemple, il y a un ''scheduler'' pour l'ALU entière, un autre pour le multiplieur entier, un autre pour le ''barrel shifter'', un autre pour l'unité mémoire, un autre pour l'unité de branchements, un autre pour l'additionneur flottant, un autre pour le multiplier flottant, etc. Un exemple historique est celui de le FPU de l'IBM 360 modèle 90, qui avait un additionneur flottant, un multiplieur flottant, et une unité mémoire pour les lectures/écritures flottantes. Les trois unités avaient leur propre ''scheduler''. Un exemple aussi extrême n'est pas si rare. Les processeurs AMD utilisent beaucoup cette technique, pour les ALU entières, à quelques nuances près. A l'opposé, Intel préfère utiliser des ''schedulers'' centralisés sur les anciens processeurs, deux ou trois ''schedulers'' sur les processeurs récents (2020 et plus). Les processeurs AMD utilisaient précisément un ''scheduler'' par ALU entière, alors que les FPUs partagent un fenêtre d’instructions flottantes unique. Mais nous verrons cela en détail dans le chapitre sur les processeurs superscalaires x86. Toujours est-il qu'un cas aussi unique porte un nom. Les ''schedulers'' reliés à une seule ALU (entière ou flottante) sont appelés des '''stations de réservation''', ''Reservation Stations'' en anglais. Le terme a été introduit dans l'article de Tomasulo, qui décrivait justement la FPU de l'IBM 360, mentionnée plus haut. Mais dans ce cours, le terme décrit des ''schedulers'' qui mémorisent les opérandes des instructions, pas seulement les noms de registres associés. [[File:Contournement avec des stations de réservation.png|centre|vignette|upright=2.5|Stations de réservation]] Toujours est-il que l'exécution dans le désordre avec des stations de réservations a un intérêt historique fort. Elle a été utilisée dans deux techniques d'exécution dans le désordre très ancienne : l'algorithme de Tomasulo et le ''Scoreboarding'' du processeur CDC 6600. Ces deux implémentations ont introduit la technique, qui a été raffinée par la suite. Leur défaut est qu'elles ne géraient pas les exceptions précises, ce qui fait qu'on verra ces deux techniques dans le chapitre suivant, qui leur est dédié. ===L'usage de plusieurs files d'instruction=== Utiliser plusieurs ''schedulers'' séparés est une bonne méthode pour économiser des circuits. Mais il est possible d'aller encore plus loin, en remplaçant les ''schedulers'' par des files de micro-opérations. L'idée est qu'un fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement un file de micro-opération pour les opérations entières, un autre pour les opérations flottantes, un autre pour les accès mémoire. D'autres processeurs utilisent un file pour les accès mémoire et un autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. le présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que le technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si un dépendance bloque un FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans un autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer le disponibilité des registres. Quand un registre est lu ou écrit par un instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. le logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : un pour les instructions d'accès mémoire et un autre pour les autres instructions. Si jamais un instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de le lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'un est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est le file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. Dans les grandes lignes, il existe 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! ''scheduler'' |- ! un seule | ''Scoreboard'' | ''scheduler'' centralisée |- ! Plusieurs | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | ''scheduler'' décentralisé |} <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Le scoreboarding et l'algorithme de Tomasulo | prevText=Le scoreboarding et l'algorithme de Tomasulo | next=Le scoreboarding et l'algorithme de Tomasulo | nextText=Le scoreboarding et l'algorithme de Tomasulo }} </noinclude> gav4jjeuy33y304c5oqs4nzitsc1nd9 773674 773673 2026-09-29T22:40:18Z Mewtow 31375 773674 wikitext text/x-wiki Nous venons de parler de l'exécution dans le désordre pendant deux chapitres. Les chapitres précédents vous ont laissé penser qu'un processeur avec exécution dans le désordre était assez simple : on remplace le file de µops par un fenêtre d’instruction, on ajoute éventuellement un unité de renommage de registres, et voilà ! Et en effet, l'implémentation la plus simple de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Mais dans la réalité, les processeurs modernes n'utilisent pas un ''scheduler'' unique. Les processeurs modernes ont besoin de ''scheduler'' très grands, avec un grand nombre d'entrées. Or, nous avons vu qu'un ''scheduler'' est un sorte de mémoire associative très complexe, avec un grand nombre de comparateurs. Et cela pose problème quand le ''scheduler'' doit mémoriser un grand nombre de µops. Le cout en transistors d'un ''scheduler'' n'est pas proportionnel au nombre de µops qu'elle peut mémoriser. Par exemple, si je compare un ''scheduler'' de 32 entrées (32 µops max), elle n'utilise pas deux fois plus transistors qu'un fenêtre de 16 entrées. Le cout en circuit n'est pas deux fois plus élevé, mais est approximativement 4 fois plus élevé. Le cout est presque quadratique, à savoir qu'il est proportionnel au carré du nombre d'entrées. Et il en est de même avec le performance. Dès qu'on dépasse la centaine de µops, un ''scheduler'' centralisé n'est pas très pratique. Il consomme beaucoup de transistors, chauffe beaucoup, n'est pas très rapide. La solution est de scinder un gros ''scheduler'' en plusieurs ''schedulers'' plus petits. Pour faire la différence avec un ''scheduler'' unique, nous allons parler de ''scheduler'' centralisé s'il n'y en a qu'un, de '''''scheduler'' décentralisé''' s'il y en a plusieurs. ==La spécialisation des ''schedulers'' décentralisés== La scission du ''scheduler'' doit idéalement se faire en tenant compte du reste du processeur. En effet, il faut relier les ''schedulers'' aux unités de calcul, ainsi qu'à l'unité mémoire, et cela ne peut pas se faire n'importe comment. Reste à voir comment faire. Précisons d'or et déjà que la scission dépend de si le processeur supporte l'exécution dans le désordre des accès mémoire. Si le processeur accepte de faire les accès mémoire dans le désordre, alors la scission sera différente. ===Les ''schedulers'' spécialisés pour les µops flottantes=== Prenons un processeur où les accès mémoire sont réalisés dans l'ordre. Le processeur a donc un simple ''scheduler'' pour les µops entières, les µops flottantes et les µops de branchements. La scission la plus basique sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes. Il est aussi possible de séparer le ''scheduler'' pour les µops entières en deux : un pour les opérations de calcul et un autre pour les µops de branchements. La séparation est moins évidente, mais reste possible. Pour le moment, concentrons-nous sur la séparation du ''scheduler'' flottant et du ''scheduler entier''. L'avantage est que l'implémentation est très simple. Les flottants sont gérés à part des entiers. Ils ont leurs propres registres, des FPU séparées des ALU entières, bref : le séparation est complète. Utiliser un ''scheduler'' séparée va dans ce sens. Un avantage de cette scission se situe au niveau de la consommation d'électricité. Si le programme exécuté n'exécute aucune instruction flottante, le ''scheduler'' pour µops flottant peut être ''clock gate'', mis en veille, voire éteint. Le processeur consomme donc moins d'électricité, et chauffe moins. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Remarque importante : les deux ''schedulers'' travaillent indépendamment les unes des autres. Ils décident d'émettre une µops à chaque cycle, dans leur coin, sans rendre de compte à l'autre. La conséquence est qu'il est possible d'émettre deux µops par cycle, si les circonstances l'autorisent. Le ''scheduler'' entier émet une µops entière en même temps que le ''scheduler'' flottant émet une µops flottante. Les deux µops démarrent au même cycle, on n'émet pas l'une après l'autre. Le résultat est un gain en performance, sur lequel on reviendra plus tard. Un avantage de cette séparation est qu'elle permet de renommer les registres flottants et entiers séparément. Non pas que ce soit impossible avec un ''scheduler'' unique, mais c'est beaucoup plus compliqué et rarement fait. En séparant ''scheduler'' entier et ''scheduler'' flottant, les deux peuvent être précédés de deux unités de renommage séparées. Et à vrai dire, on peut même aller plus loin, en n'autorisant l'exécution dans le désordre que pour les opérations flottantes, ou au contraire que pour les opérations entières. La toute première implémentation de l'exécution dans le désordre, sur l'IBM 360, en est un bon exemple. La FPU de ce processeur était précédée par un ''scheduler'', mais les ALu entières n'étaient précédés que par une file de µops basique, sans exécution dans le désordre. ===Les ''schedulers'' spécialisés pour les µops mémoire=== Voyons maintenant le cas des processeurs où les accès mémoire sont exécutés dans le désordre. Il est possible d'utiliser un ''scheduler'' centralisé, ce qui était fait sur les anciens processeurs Intel pour donner un exemple. Mais voyons ce que cela peut donner avec un ''scheduler'' décentralisé. Une scission naturelle serait d'utiliser un ''scheduler'' pour les µops mémoire, et un ''scheduler'' pour le reste des µops. Les processeurs Intel de microarchitecture ''Skylake'' faisaient cela. Un avantage est que les deux fenêtres d'instructions sont plus spécialisées, ce qui entraine des économies de circuit. Les opérations entières/flottantes ont besoin de deux registres pour les opérandes et d'un autre résultat, alors que les µops mémoire n'ont besoin que de deux registres maximum. En utilisant un ''scheduler'' unique, chaque entrée doit mémoriser l'opcode et trois registres, dont un est inutilisé pour les µops mémoire et les branchements. En utilisant des fenêtres d’instructions séparées, celle pour les µops entières/flottantes a trois registres par entrée, contre seulement deux registres par entrée pour celle des µops mémoire. Un autre avantage est que cela permet d'émettre une µops mémoire et une autre µops lors du même cycle. Si les circonstances le permettent, le processeur peut émettre une µops entière dans une ALU entière, et une µops mémoire dans l'unité mémoire. Le gain en performance est substantiel. Précisons que les processeurs avec exécution dans le désordre peuvent exécuter une instruction arithmétique en parallèle d'un accès mémoire. Mais les deux ne démarrent pas au même cycle : on émet d'abord l'accès mémoire, puis les instructions de calcul suivent au cycle suivant. Là, les deux démarrent au même cycle. Une scission plus poussée sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes, un autre pour les µops mémoire. [[File:Processeur avec des fenêtres d'instruction décentralisées.png|centre|vignette|upright=2|Processeur avec des fenêtres d'instruction décentralisées]] ===Les stations de réservation=== Un cas extrême est celui où chaque ALU/FPU a sa propre ''scheduler''. Par exemple, il y a un ''scheduler'' pour l'ALU entière, un autre pour le multiplieur entier, un autre pour le ''barrel shifter'', un autre pour l'unité mémoire, un autre pour l'unité de branchements, un autre pour l'additionneur flottant, un autre pour le multiplier flottant, etc. Un exemple historique est celui de le FPU de l'IBM 360 modèle 90, qui avait un additionneur flottant, un multiplieur flottant, et une unité mémoire pour les lectures/écritures flottantes. Les trois unités avaient leur propre ''scheduler''. Un exemple aussi extrême n'est pas si rare. Les processeurs AMD utilisent beaucoup cette technique, pour les ALU entières, à quelques nuances près. A l'opposé, Intel préfère utiliser des ''schedulers'' centralisés sur les anciens processeurs, deux ou trois ''schedulers'' sur les processeurs récents (2020 et plus). Les processeurs AMD utilisaient précisément un ''scheduler'' par ALU entière, alors que les FPUs partagent un fenêtre d’instructions flottantes unique. Mais nous verrons cela en détail dans le chapitre sur les processeurs superscalaires x86. Toujours est-il qu'un cas aussi unique porte un nom. Les ''schedulers'' reliés à une seule ALU (entière ou flottante) sont appelés des '''stations de réservation''', ''Reservation Stations'' en anglais. Le terme a été introduit dans l'article de Tomasulo, qui décrivait justement la FPU de l'IBM 360, mentionnée plus haut. Mais dans ce cours, le terme décrit des ''schedulers'' qui mémorisent les opérandes des instructions, pas seulement les noms de registres associés. [[File:Contournement avec des stations de réservation.png|centre|vignette|upright=2.5|Stations de réservation]] Toujours est-il que l'exécution dans le désordre avec des stations de réservations a un intérêt historique fort. Elle a été utilisée dans deux techniques d'exécution dans le désordre très ancienne : l'algorithme de Tomasulo et le ''Scoreboarding'' du processeur CDC 6600. Ces deux implémentations ont introduit la technique, qui a été raffinée par la suite. Leur défaut est qu'elles ne géraient pas les exceptions précises, ce qui fait qu'on verra ces deux techniques dans le chapitre suivant, qui leur est dédié. ===L'usage de plusieurs files d'instruction=== Utiliser plusieurs ''schedulers'' séparés est une bonne méthode pour économiser des circuits. Mais il est possible d'aller encore plus loin, en remplaçant les ''schedulers'' par des files de micro-opérations. L'idée est qu'un fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement un file de micro-opération pour les opérations entières, un autre pour les opérations flottantes, un autre pour les accès mémoire. D'autres processeurs utilisent un file pour les accès mémoire et un autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. le présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que le technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si un dépendance bloque un FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans un autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer le disponibilité des registres. Quand un registre est lu ou écrit par un instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. le logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : un pour les instructions d'accès mémoire et un autre pour les autres instructions. Si jamais un instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de le lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'un est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est le file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. Dans les grandes lignes, il existe 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! ''scheduler'' |- ! un seule | ''Scoreboard'' | ''scheduler'' centralisée |- ! Plusieurs | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | ''scheduler'' décentralisé |} ==Les ''schedulers'' décentralisés versus centralisés== Le choix entre un ''scheduler'' centralisés et plusieurs petits ''schedulers'' décentralisés est un compromis entre économie de circuits et flexibilité. Un gros ''scheduler'' unique est plus flexible, ce qui peut entrainer des gains de performance, mais coute beaucoup en circuits et peut réduire la fréquence du processeur. ===Un ''scheduler'' centralisé est plus flexible, mais plus couteux=== Pour expliquer en quoi un gros ''scheduler'' unique est plus flexible, nous allons prendre un exemple. Comparons un ''scheduler'' de 64 entrées, et deux ''schedulers'' de 32 entrées chacun. Les deux ''schedulers'' sont spécialisé :l'un est spécialisé dans les µops entières, l'autre dans les µops flottantes. En tout, les deux ''schedulers'' peuvent mémoriser au maximum 32 µops entières et 32 µops flottantes. A l'opposé, le gros ''scheduler'' unique peut mémoriser 64 µops, peu importe leur nature. Si le programme exécuté n'utilise pas de nombres flottants, le différence devient flagrante. La solution à deux ''schedulers'' est limitée à 32 µops, alors que le ''scheduler'' centralisé peut mémoriser le double. Les performances seront donc meilleures avec le ''scheduler'' centralisé. Et au-delà de ça, le ''scheduler'' décentralisé est utilisé de manière optimale si la moitié des µops sont des µops entières, et l'autre moitié des µops flottantes. Alors que le ''scheduler'' centralisé se moque de la répartition entre µops entières et flottantes. Pour le dire autrement, avec un ''scheduler'' décentralisé, il arrive qu'un ''scheduler'' soit remplis, alors que les autres sont sous-utilisés, voire vides. Ce qui n'arrive pas avec un ''scheduler'' centralisé. Par contre, les ''schedulers'' décentralisés utilisent plusieurs ''schedulers'' de "petite taille", plus rapides, plus économes en circuits et économes en énergie. Le compromis n'est donc pas entre un ''scheduler'' à 64 entrées versus deux ''schedulers'' de 32 entrées. Le compromis en pratique est entre un ''scheduler'' de 64 entrées versus 3 ''schedulers'' de 32 entrées. Un exemple pratique est celui de le microarchitecture ''Skyleke'' d'Intel. Intel est passé d'un ''scheduler'' centralisé pre-''Skyleke'' à deux ''schedulers'' sur ''Skyleke'', mais le nombre total d'entrées était globalement le même entre les deux, même si l'évolution de le finesse de gravure entre les deux biaise un peu les résultats. ===L'émission avec un ''scheduler'' décentralisé : ''dispatch'' et ''schedule''=== Un point important est qu'avec des ''schedulers'' décentralisés, l'émission est découpée en deux étages. Le premier étage envoie une µops vers le ''scheduler'' adéquat, le seconde émet la µops quand ses opérandes sont prêts. La première étape fait rentrer une µops dans le ''scheduler'', la seconde l'en fait sortir. Le premier étage est l'étage de '''''dispatch''''', le second est l'étage de '''''scheduling'''''. Le ''dispatch'' analyse la µops et décide où l'envoyer, selon que c'est une µops mémoire, flottante, entière. Le ''scheduling'' gère le disponibilité des opérandes et des unités de calcul. La µop émise est ajoutée au tampon de réordonnancement, s'il existe, lors de l'étape de ''dispatch''. Cette séparation fait qu'il est possible de démarrer l'exécution de plusieurs µops simultanément : une µop par ''scheduler''. Le fait est que deux ''schedulers'' différents émettent leurs µops sans se synchroniser avec les autres. Deux ''schedulers'' peuvent donc émettre chacun une µops, ce qui fait deux µops émises lors du même cycle. Cela permet d'exécuter en même temps deux ou trois instructions 1-cycle, comme des additions, soustractions, décalages, etc. Il devient aussi possible d'émettre un µop entière en même temps qu'un µop flottante, si les µops entières ont un fenêtre séparée de celle des µops flottantes. Notons que cela permet d'émettre deux µops par cycle au niveau de l'étape de ''scheduling'', pas à l'étape de ''dispatch''. Aussi, nous parlerons de '''''multi-schedule'''''. Par contre, il faut faire une précision importante : le processeur ne peut toujours qu'émettre une ''instruction'' par cycle. Le processeur charge et décode une instruction par cycle, pas plus. Pour faire une comparaison, rappelez-vous l'exécution dans le désordre simple. Elle permet d'exécuter plusieurs instructions par cycle d'horloge, si on regarde ce qui se passe au niveau des unités de calcul. Mais si on fait la moyenne sur le temps long, on ne peut pas dépasser un IPC (''instruction per cycle'') de 1. Le ''multi-scheduling'' est similaire. Il permet de gagner en performance, mais ne permet pas de dépasser un IPC de 1. Il augmente l'IPC quand il est bas, mais il ne faut que le faire remonter vers le seuil de 1. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Le scoreboarding et l'algorithme de Tomasulo | prevText=Le scoreboarding et l'algorithme de Tomasulo | next=Le scoreboarding et l'algorithme de Tomasulo | nextText=Le scoreboarding et l'algorithme de Tomasulo }} </noinclude> 1w3sqkm0btifebrwrznee7ghusdipsw 773680 773674 2026-09-29T23:06:57Z Mewtow 31375 773680 wikitext text/x-wiki Nous venons de parler de l'exécution dans le désordre pendant deux chapitres. Les chapitres précédents vous ont laissé penser qu'un processeur avec exécution dans le désordre était assez simple : on remplace le file de µops par un fenêtre d’instruction, on ajoute éventuellement un unité de renommage de registres, et voilà ! Et en effet, l'implémentation la plus simple de l'OOO utilise un ''scheduler'' unique, appelée un '''''scheduler'' centralisé'''. Mais dans la réalité, les processeurs modernes n'utilisent pas un ''scheduler'' unique. Les processeurs modernes ont besoin de ''scheduler'' très grands, avec un grand nombre d'entrées. Or, nous avons vu qu'un ''scheduler'' est un sorte de mémoire associative très complexe, avec un grand nombre de comparateurs. Et cela pose problème quand le ''scheduler'' doit mémoriser un grand nombre de µops. Le cout en transistors d'un ''scheduler'' n'est pas proportionnel au nombre de µops qu'elle peut mémoriser. Par exemple, si je compare un ''scheduler'' de 32 entrées (32 µops max), elle n'utilise pas deux fois plus transistors qu'un fenêtre de 16 entrées. Le cout en circuit n'est pas deux fois plus élevé, mais est approximativement 4 fois plus élevé. Le cout est presque quadratique, à savoir qu'il est proportionnel au carré du nombre d'entrées. Et il en est de même avec le performance. Dès qu'on dépasse la centaine de µops, un ''scheduler'' centralisé n'est pas très pratique. Il consomme beaucoup de transistors, chauffe beaucoup, n'est pas très rapide. La solution est de scinder un gros ''scheduler'' en plusieurs ''schedulers'' plus petits. Pour faire la différence avec un ''scheduler'' unique, nous allons parler de ''scheduler'' centralisé s'il n'y en a qu'un, de '''''scheduler'' décentralisé''' s'il y en a plusieurs. ==La spécialisation des ''schedulers'' décentralisés== La scission du ''scheduler'' doit idéalement se faire en tenant compte du reste du processeur. En effet, il faut relier les ''schedulers'' aux unités de calcul, ainsi qu'à l'unité mémoire, et cela ne peut pas se faire n'importe comment. Reste à voir comment faire. Précisons d'or et déjà que la scission dépend de si le processeur supporte l'exécution dans le désordre des accès mémoire. Si le processeur accepte de faire les accès mémoire dans le désordre, alors la scission sera différente. ===Les ''schedulers'' spécialisés pour les µops flottantes=== Prenons un processeur où les accès mémoire sont réalisés dans l'ordre. Le processeur a donc un simple ''scheduler'' pour les µops entières, les µops flottantes et les µops de branchements. La scission la plus basique sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes. Il est aussi possible de séparer le ''scheduler'' pour les µops entières en deux : un pour les opérations de calcul et un autre pour les µops de branchements. La séparation est moins évidente, mais reste possible. Pour le moment, concentrons-nous sur la séparation du ''scheduler'' flottant et du ''scheduler entier''. L'avantage est que l'implémentation est très simple. Les flottants sont gérés à part des entiers. Ils ont leurs propres registres, des FPU séparées des ALU entières, bref : le séparation est complète. Utiliser un ''scheduler'' séparée va dans ce sens. Un avantage de cette scission se situe au niveau de la consommation d'électricité. Si le programme exécuté n'exécute aucune instruction flottante, le ''scheduler'' pour µops flottant peut être ''clock gate'', mis en veille, voire éteint. Le processeur consomme donc moins d'électricité, et chauffe moins. [[File:Processeur avec plusieurs fenêtres d'instruction.png|centre|vignette|upright=2.5|Processeur avec plusieurs fenêtres d'instruction.]] Remarque importante : les deux ''schedulers'' travaillent indépendamment les unes des autres. Ils décident d'émettre une µops à chaque cycle, dans leur coin, sans rendre de compte à l'autre. La conséquence est qu'il est possible d'émettre deux µops par cycle, si les circonstances l'autorisent. Le ''scheduler'' entier émet une µops entière en même temps que le ''scheduler'' flottant émet une µops flottante. Les deux µops démarrent au même cycle, on n'émet pas l'une après l'autre. Le résultat est un gain en performance, sur lequel on reviendra plus tard. Un avantage de cette séparation est qu'elle permet de renommer les registres flottants et entiers séparément. Non pas que ce soit impossible avec un ''scheduler'' unique, mais c'est beaucoup plus compliqué et rarement fait. En séparant ''scheduler'' entier et ''scheduler'' flottant, les deux peuvent être précédés de deux unités de renommage séparées. Et à vrai dire, on peut même aller plus loin, en n'autorisant l'exécution dans le désordre que pour les opérations flottantes, ou au contraire que pour les opérations entières. La toute première implémentation de l'exécution dans le désordre, sur l'IBM 360, en est un bon exemple. La FPU de ce processeur était précédée par un ''scheduler'', mais les ALu entières n'étaient précédés que par une file de µops basique, sans exécution dans le désordre. ===Les ''schedulers'' spécialisés pour les µops mémoire=== Voyons maintenant le cas des processeurs où les accès mémoire sont exécutés dans le désordre. Il est possible d'utiliser un ''scheduler'' centralisé, ce qui était fait sur les anciens processeurs Intel pour donner un exemple. Mais voyons ce que cela peut donner avec un ''scheduler'' décentralisé. Une scission naturelle serait d'utiliser un ''scheduler'' pour les µops mémoire, et un ''scheduler'' pour le reste des µops. Les processeurs Intel de microarchitecture ''Skylake'' faisaient cela. Un avantage est que les deux fenêtres d'instructions sont plus spécialisées, ce qui entraine des économies de circuit. Les opérations entières/flottantes ont besoin de deux registres pour les opérandes et d'un autre résultat, alors que les µops mémoire n'ont besoin que de deux registres maximum. En utilisant un ''scheduler'' unique, chaque entrée doit mémoriser l'opcode et trois registres, dont un est inutilisé pour les µops mémoire et les branchements. En utilisant des fenêtres d’instructions séparées, celle pour les µops entières/flottantes a trois registres par entrée, contre seulement deux registres par entrée pour celle des µops mémoire. Un autre avantage est que cela permet d'émettre une µops mémoire et une autre µops lors du même cycle. Si les circonstances le permettent, le processeur peut émettre une µops entière dans une ALU entière, et une µops mémoire dans l'unité mémoire. Le gain en performance est substantiel. Précisons que les processeurs avec exécution dans le désordre peuvent exécuter une instruction arithmétique en parallèle d'un accès mémoire. Mais les deux ne démarrent pas au même cycle : on émet d'abord l'accès mémoire, puis les instructions de calcul suivent au cycle suivant. Là, les deux démarrent au même cycle. Une scission plus poussée sépare un ''scheduler'' pour les µops de calcul entières, d'un ''scheduler'' pour les µops flottantes, un autre pour les µops mémoire. [[File:Processeur avec des fenêtres d'instruction décentralisées.png|centre|vignette|upright=2|Processeur avec des fenêtres d'instruction décentralisées]] ===Les stations de réservation=== Un cas extrême est celui où chaque ALU/FPU a sa propre ''scheduler''. Par exemple, il y a un ''scheduler'' pour l'ALU entière, un autre pour le multiplieur entier, un autre pour le ''barrel shifter'', un autre pour l'unité mémoire, un autre pour l'unité de branchements, un autre pour l'additionneur flottant, un autre pour le multiplier flottant, etc. Un exemple historique est celui de le FPU de l'IBM 360 modèle 90, qui avait un additionneur flottant, un multiplieur flottant, et une unité mémoire pour les lectures/écritures flottantes. Les trois unités avaient leur propre ''scheduler''. Un exemple aussi extrême n'est pas si rare. Les processeurs AMD utilisent beaucoup cette technique, pour les ALU entières, à quelques nuances près. A l'opposé, Intel préfère utiliser des ''schedulers'' centralisés sur les anciens processeurs, deux ou trois ''schedulers'' sur les processeurs récents (2020 et plus). Les processeurs AMD utilisaient précisément un ''scheduler'' par ALU entière, alors que les FPUs partagent un fenêtre d’instructions flottantes unique. Mais nous verrons cela en détail dans le chapitre sur les processeurs superscalaires x86. Toujours est-il qu'un cas aussi unique porte un nom. Les ''schedulers'' reliés à une seule ALU (entière ou flottante) sont appelés des '''stations de réservation''', ''Reservation Stations'' en anglais. Le terme a été introduit dans l'article de Tomasulo, qui décrivait justement la FPU de l'IBM 360, mentionnée plus haut. Mais dans ce cours, le terme décrit des ''schedulers'' qui mémorisent les opérandes des instructions, pas seulement les noms de registres associés. [[File:Contournement avec des stations de réservation.png|centre|vignette|upright=2.5|Stations de réservation]] Toujours est-il que l'exécution dans le désordre avec des stations de réservations a un intérêt historique fort. Elle a été utilisée dans deux techniques d'exécution dans le désordre très ancienne : l'algorithme de Tomasulo et le ''Scoreboarding'' du processeur CDC 6600. Ces deux implémentations ont introduit la technique, qui a été raffinée par la suite. Leur défaut est qu'elles ne géraient pas les exceptions précises, ce qui fait qu'on verra ces deux techniques dans le chapitre suivant, qui leur est dédié. ===L'usage de plusieurs files d'instruction=== Utiliser plusieurs ''schedulers'' séparés est une bonne méthode pour économiser des circuits. Mais il est possible d'aller encore plus loin, en remplaçant les ''schedulers'' par des files de micro-opérations. L'idée est qu'un fois décodée, les instructions sont accumulées dans des files de micro-opération différentes. Il y a typiquement un file de micro-opération pour les opérations entières, un autre pour les opérations flottantes, un autre pour les accès mémoire. D'autres processeurs utilisent un file pour les accès mémoire et un autre pour les autres instructions, comme le faisait le Pentium 4 d'Intel. Les files de micro-opération sont des mémoires FIFO, ce qui fait qu'elles conservent l'ordre des instructions. Et chaque FIFO est couplée à un ''scoreboard'' qui vérifie les dépendances à chaque cycle. le présence de ''scoreboard'' nous dit que l'intérêt n'est pas un mécanisme d'émission plus compliqué, mais que le technique se repose sur le fait d'avoir plusieurs files de micro-opération. L'intérêt d'avoir plusieurs FIFOs est que si un dépendance bloque un FIFO, les autres peuvent continuer d'émettre des instructions. Les files de micro-opération émettent leurs instructions de manière indépendante, ou presque. Elles ne savent pas si telle instruction dans un autre file doit passer avant ou après l'instruction qu'elles émettent. Par contre, les unités d'émission communiquent entre eux pour gérer le disponibilité des registres. Quand un registre est lu ou écrit par un instruction, les autres files d'instruction doivent être prévenues et mettre à jour leurs unités d'émission. le logique d'émission est donc plus complexe que prévu. Le processeur Pentium 4 avait deux FIFOs séparées : un pour les instructions d'accès mémoire et un autre pour les autres instructions. Si jamais un instruction mémoire bloquait le pipeline, l'autre FIFO pouvait continuer à exécuter des instructions entières indépendante de le lecture bloquée. Les FIFOs sont simples à implémenter et ont un cout en circuit modéré. Par contre, le gain en performances est assez limité avec cette méthode, surtout comparé aux méthodes qui vont suivre. Le problème est qu'il est facile de se retrouver avec toutes les files de micro-opération bloquées. Quand l'un est bloquée, les autres tendent à se vider rapidement, particulièrement quand c'est le file pour les accès mémoire qui se bloque. Les techniques qui vont suivre font totalement disparaitre ce genre de blocage. Dans les grandes lignes, il existe 4 grandes techniques d'exécution dans le désordre. Elles peuvent se classer sur deux critères : est-ce que les instructions sont émises dans l'ordre, et combien il y a de files de micro-opération. {|class="wikitable" |- ! ! File de µops normale ! ''scheduler'' |- ! un seule | ''Scoreboard'' | ''scheduler'' centralisée |- ! Plusieurs | Plusieurs FIFOs, plusieurs ''Scoreboard'' indépendants | ''scheduler'' décentralisé |} ==Les ''schedulers'' décentralisés versus centralisés== Le choix entre un ''scheduler'' centralisés et plusieurs petits ''schedulers'' décentralisés est un compromis entre économie de circuits et flexibilité. Un gros ''scheduler'' unique est plus flexible, ce qui peut entrainer des gains de performance, mais coute beaucoup en circuits et peut réduire la fréquence du processeur. ===Un ''scheduler'' centralisé est plus flexible, mais plus couteux=== Pour expliquer en quoi un gros ''scheduler'' unique est plus flexible, nous allons prendre un exemple. Comparons un ''scheduler'' de 64 entrées, et deux ''schedulers'' de 32 entrées chacun. Les deux ''schedulers'' sont spécialisé :l'un est spécialisé dans les µops entières, l'autre dans les µops flottantes. En tout, les deux ''schedulers'' peuvent mémoriser au maximum 32 µops entières et 32 µops flottantes. A l'opposé, le gros ''scheduler'' unique peut mémoriser 64 µops, peu importe leur nature. Si le programme exécuté n'utilise pas de nombres flottants, le différence devient flagrante. La solution à deux ''schedulers'' est limitée à 32 µops, alors que le ''scheduler'' centralisé peut mémoriser le double. Les performances seront donc meilleures avec le ''scheduler'' centralisé. Et au-delà de ça, le ''scheduler'' décentralisé est utilisé de manière optimale si la moitié des µops sont des µops entières, et l'autre moitié des µops flottantes. Alors que le ''scheduler'' centralisé se moque de la répartition entre µops entières et flottantes. Pour le dire autrement, avec un ''scheduler'' décentralisé, il arrive qu'un ''scheduler'' soit remplis, alors que les autres sont sous-utilisés, voire vides. Ce qui n'arrive pas avec un ''scheduler'' centralisé. Par contre, les ''schedulers'' décentralisés utilisent plusieurs ''schedulers'' de "petite taille", plus rapides, plus économes en circuits et économes en énergie. Le compromis n'est donc pas entre un ''scheduler'' à 64 entrées versus deux ''schedulers'' de 32 entrées. Le compromis en pratique est entre un ''scheduler'' de 64 entrées versus 3 ''schedulers'' de 32 entrées. Un exemple pratique est celui de le microarchitecture ''Skyleke'' d'Intel. Intel est passé d'un ''scheduler'' centralisé pre-''Skyleke'' à deux ''schedulers'' sur ''Skyleke'', mais le nombre total d'entrées était globalement le même entre les deux, même si l'évolution de le finesse de gravure entre les deux biaise un peu les résultats. ===L'émission avec un ''scheduler'' décentralisé : ''dispatch'' et ''schedule''=== Un point important est qu'avec des ''schedulers'' décentralisés, l'émission est découpée en deux étages. Le premier étage envoie une µops vers le ''scheduler'' adéquat, le seconde émet la µops quand ses opérandes sont prêts. La première étape fait rentrer une µops dans le ''scheduler'', la seconde l'en fait sortir. Le premier étage est l'étage de '''''dispatch''''', le second est l'étage de '''''scheduling'''''. Le ''dispatch'' analyse la µops et décide où l'envoyer, selon que c'est une µops mémoire, flottante, entière. Le ''scheduling'' gère le disponibilité des opérandes et des unités de calcul. La µop émise est ajoutée au tampon de réordonnancement, s'il existe, lors de l'étape de ''dispatch''. Cette séparation fait qu'il est possible de démarrer l'exécution de plusieurs µops simultanément : une µop par ''scheduler''. Le fait est que deux ''schedulers'' différents émettent leurs µops sans se synchroniser avec les autres. Deux ''schedulers'' peuvent donc émettre chacun une µops, ce qui fait deux µops émises lors du même cycle. Cela permet d'exécuter en même temps deux ou trois instructions 1-cycle, comme des additions, soustractions, décalages, etc. Il devient aussi possible d'émettre un µop entière en même temps qu'un µop flottante, si les µops entières ont un fenêtre séparée de celle des µops flottantes. Notons que cela permet d'émettre deux µops par cycle au niveau de l'étape de ''scheduling'', pas à l'étape de ''dispatch''. Aussi, nous parlerons de '''''multi-schedule'''''. Par contre, il faut faire une précision importante : le processeur ne peut toujours qu'émettre une ''instruction'' par cycle. Le processeur charge et décode une instruction par cycle, pas plus. Pour faire une comparaison, rappelez-vous l'exécution dans le désordre simple. Elle permet d'exécuter plusieurs instructions par cycle d'horloge, si on regarde ce qui se passe au niveau des unités de calcul. Mais si on fait la moyenne sur le temps long, on ne peut pas dépasser un IPC (''instruction per cycle'') de 1. Le ''multi-scheduling'' est similaire. Il permet de gagner en performance, mais ne permet pas de dépasser un IPC de 1. Il augmente l'IPC quand il est bas, mais il ne faut que le faire remonter vers le seuil de 1. <noinclude> {{NavChapitre | book=Fonctionnement d'un ordinateur | prev=Le scoreboarding et l'algorithme de Tomasulo | prevText=Le scoreboarding et l'algorithme de Tomasulo | next=Le scoreboarding et l'algorithme de Tomasulo | nextText=Le scoreboarding et l'algorithme de Tomasulo }} </noinclude> a3ftumjivq83bfnq4kvtw8evpl80smo Mathc complexes/0a0 0 84539 773703 2026-09-30T11:08:15Z Xhungab 23827 news 773703 wikitext text/x-wiki [[Catégorie:Mathc complexes (livre)]] [[Mathc complexes/a277#Le fichier principal :| Application]] Installer et compiler ce fichier dans votre répertoire de travail. {{Fichier|c04c.c|largeur=70%|info=|icon=Crystal128-source-c.svg}} <syntaxhighlight lang="c"> /* ------------------------------------ */ /* Save as : c04c.c */ /* ------------------------------------ */ #include "w_a.h" /* ------------------------------------ */ #include "f.h" /* ------------------------------------ */ int main(void) { double dft4[R4*(C4*C2)] = { 1,0, 1,0, 1,0, 1,0, 1,0, f(1,4).r,f(1,4).i, f(2,4).r,f(2,4).i, f(3,4).r,f(3,4).i, 1,0, f(2,4).r,f(2,4).i, f(4,4).r,f(4,4).i, f(6,4).r,f(6,4).i, 1,0, f(3,4).r,f(3,4).i, f(6,4).r,f(6,4).i, f(9,4).r,f(9,4).i }; double Ts[R4*(C1*C2)] = { +1,0, +2,-1, -0,-1, -1,+2 }; double **DFT4 = ca_A_mZ(dft4, i_mZ(R4,C4)); double **cDFT4 = conj_mZ(DFT4, i_mZ(R4,C4)); double **cDFT4div4 = smul_mZ(1/4.,cDFT4, i_mZ(R4,C4)); double **s = ca_A_mZ(Ts, i_mZ(R4,C1)); double **S = i_mZ(R4,C1) ; clrscrn(); printf(" DFT4 : "); p_mZ(DFT4,S4,P3,S3,P3,C6); printf(" s : "); p_mZ(s,S4,P3,S3,P3,C6); mul_mZ(DFT4,s,S); printf(" S = DFT4 * s : "); p_mZ(S,S4,P3,S3,P3,C6); stop(); clrscrn(); printf(" s : "); p_mZ(m0_mZ(s),S4,P0,S3,P0,C6); printf(" 1/4 cDFT4 : "); p_mZ(cDFT4div4,S4,P3,S3,P3,C6); mul_mZ(cDFT4div4,S,s); printf(" s = 1/4 cDFT4 * S : "); p_mZ(s,S4,P3,S3,P3,C6); stop(); f_mZ(DFT4); f_mZ(cDFT4); f_mZ(cDFT4div4); f_mZ(s); f_mZ(S); return 0; } /* ------------------------------------ */ /* ------------------------------------ */ </syntaxhighlight> '''Exemple de sortie écran :''' <syntaxhighlight lang="C"> DFT4 : +1.000+0.000i +1.000+0.000i +1.000+0.000i +1.000+0.000i +1.000+0.000i -0.000-1.000i -1.000+0.000i +0.000+1.000i +1.000+0.000i -1.000+0.000i +1.000-0.000i -1.000+0.000i +1.000+0.000i +0.000+1.000i -1.000+0.000i -0.000-1.000i s : +1.000+0.000i +2.000-1.000i +0.000-1.000i -1.000+2.000i S = DFT4 * s : +2.000+0.000i -2.000-2.000i +0.000-2.000i +4.000+4.000i Press return to continue. </syntaxhighlight> {{AutoCat}} 6pslywa4bhzsh1t58969l2pzpc16rrf Mathc complexes/0a1 0 84540 773706 2026-09-30T11:15:58Z Xhungab 23827 news 773706 wikitext text/x-wiki [[Catégorie:Mathc complexes (livre)]] [[Mathc complexes/a277#Le fichier principal :| Application]] Installer et compiler ce fichier dans votre répertoire de travail. {{Fichier|c0nc.c|largeur=70%|info=|icon=Crystal128-source-c.svg}} <syntaxhighlight lang="c"> /* ------------------------------------ */ /* Save as : c0nc.c */ /* ------------------------------------ */ #define CR 4. /* ------------------------------------ */ #include "w_a.h" /* ------------------------------------ */ #include "f.h" #include "dft.h" /* ------------------------------------ */ int main(void) { time_t t; srand(time(&t)); double Ts[R4*(C1*C2)] = { +1,0, +2,-1, -0,-1, -1,+2 }; double **DFT = dft_mZ( i_mZ(CR,CR),CR); double **cDFT = conj_mZ(DFT, i_mZ(CR,CR) ); double **cDFTdivN = smul_mZ(1./CR,cDFT, i_mZ(CR,CR) ); double **s = ca_A_mZ(Ts, i_mZ(CR,C1) ); double **S = i_mZ(CR,C1) ; clrscrn(); printf(" DFT :"); p_mZ(DFT, S8,P3, S8,P3, C4); printf(" s :"); p_mZ(s,S8,P3,S8,P3,C4); mul_mZ(DFT,s,S); printf(" S = DFT * s"); p_mZ(S,S8,P3,S8,P3,C4); stop(); clrscrn(); printf(" 1/%.0f cDFT :",CR); p_mZ(cDFTdivN,S8,P3,S8,P3,C4); mul_mZ(cDFTdivN,S,s); printf(" s = 1/%.0f cDFT * S :",CR); p_mZ(s, S8,P3, S8,P3, C4); stop(); f_mZ(DFT); f_mZ(cDFT); f_mZ(cDFTdivN); f_mZ(s); f_mZ(S); return 0; } /* ------------------------------------ */ /* ------------------------------------ */ </syntaxhighlight> '''Exemple de sortie écran : ''' <syntaxhighlight lang="C"> DFT : +1.000 +0.000i +1.000 +0.000i +1.000 +0.000i +1.000 +0.000i +1.000 +0.000i -0.000 -1.000i -1.000 +0.000i +0.000 +1.000i +1.000 +0.000i -1.000 +0.000i +1.000 -0.000i -1.000 +0.000i +1.000 +0.000i +0.000 +1.000i -1.000 +0.000i -0.000 -1.000i s : +1.000 +0.000i +2.000 -1.000i +0.000 -1.000i -1.000 +2.000i S = DFT * s +2.000 +0.000i -2.000 -2.000i +0.000 -2.000i +4.000 +4.000i Press return to continue. </syntaxhighlight> {{AutoCat}} 92mp1khl6gvz2qsewo6hooi39l4yg4a 773712 773706 2026-09-30T11:54:07Z Xhungab 23827 773712 wikitext text/x-wiki [[Catégorie:Mathc complexes (livre)]] [[Mathc complexes/a277#Le fichier principal :| Application]] Installer et compiler ce fichier dans votre répertoire de travail. {{Fichier|c0nc.c|largeur=70%|info=|icon=Crystal128-source-c.svg}} <syntaxhighlight lang="c"> /* ------------------------------------ */ /* Save as : c0nc.c */ /* ------------------------------------ */ #define RC 4. #define TsRC RC4 /* ------------------------------------ */ #include "w_a.h" /* ------------------------------------ */ #include "f.h" #include "dft.h" /* ------------------------------------ */ int main(void) { time_t t; srand(time(&t)); double Ts[TsRC*(C1*C2)] = { +1,0, +2,-1, -0,-1, -1,+2 }; double **DFT = dft_mZ( i_mZ(RC,RC),RC); double **cDFT = conj_mZ(DFT, i_mZ(RC,RC) ); double **cDFTdivN = smul_mZ(1./RC,cDFT, i_mZ(RC,RC) ); double **s = ca_A_mZ(Ts, i_mZ(RC,C1) ); double **S = i_mZ(RC,C1) ; clrscrn(); printf(" DFT :"); p_mZ(DFT, S8,P3, S8,P3, C4); printf(" s :"); p_mZ(s,S8,P3,S8,P3,C4); mul_mZ(DFT,s,S); printf(" S = DFT * s"); p_mZ(S,S8,P3,S8,P3,C4); stop(); clrscrn(); printf(" 1/%.0f cDFT :",RC); p_mZ(cDFTdivN,S8,P3,S8,P3,C4); mul_mZ(cDFTdivN,S,s); printf(" s = 1/%.0f cDFT * S :",RC); p_mZ(s, S8,P3, S8,P3, C4); stop(); f_mZ(DFT); f_mZ(cDFT); f_mZ(cDFTdivN); f_mZ(s); f_mZ(S); return 0; } /* ------------------------------------ */ /* ------------------------------------ */ </syntaxhighlight> '''Exemple de sortie écran : ''' <syntaxhighlight lang="C"> DFT : +1.000 +0.000i +1.000 +0.000i +1.000 +0.000i +1.000 +0.000i +1.000 +0.000i -0.000 -1.000i -1.000 +0.000i +0.000 +1.000i +1.000 +0.000i -1.000 +0.000i +1.000 -0.000i -1.000 +0.000i +1.000 +0.000i +0.000 +1.000i -1.000 +0.000i -0.000 -1.000i s : +1.000 +0.000i +2.000 -1.000i +0.000 -1.000i -1.000 +2.000i S = DFT * s +2.000 +0.000i -2.000 -2.000i +0.000 -2.000i +4.000 +4.000i Press return to continue. </syntaxhighlight> {{AutoCat}} 1mgy2xujt1e919c2s2ycnfs3uy1p86m